diff --git a/db/mysql/create_links_table.sql b/db/mysql/create_links_table.sql new file mode 100644 index 0000000..751217f --- /dev/null +++ b/db/mysql/create_links_table.sql @@ -0,0 +1,8 @@ +CREATE table if not exists links ( + id integer primary key auto_increment, + label text not null, + url text not null, + icon text not null, + position text not null, + visibility text null, + sort integer not null default 0) diff --git a/db/mysql/create_posts_table.sql b/db/mysql/create_posts_table.sql new file mode 100644 index 0000000..2e3f623 --- /dev/null +++ b/db/mysql/create_posts_table.sql @@ -0,0 +1,9 @@ +CREATE table if not exists posts ( + id integer primary key auto_increment, + username text not null, + content text not null, + location text not null, + visibility text null, + created timestamp not null default current_timestamp, + updated timestamp not null default current_timestamp, + sort integer not null default 0) diff --git a/db/mysql/create_sessions_table.sql b/db/mysql/create_sessions_table.sql new file mode 100644 index 0000000..23748b6 --- /dev/null +++ b/db/mysql/create_sessions_table.sql @@ -0,0 +1,5 @@ +CREATE table if not exists sessions ( + id integer primary key auto_increment, + username text not null, + token text not null, + expires timestamp null) diff --git a/db/mysql/create_settings_table.sql b/db/mysql/create_settings_table.sql new file mode 100644 index 0000000..80a3931 --- /dev/null +++ b/db/mysql/create_settings_table.sql @@ -0,0 +1,4 @@ +CREATE table if not exists settings ( + id integer primary key auto_increment, + setting text not null, + value text not null) diff --git a/db/mysql/create_users_table.sql b/db/mysql/create_users_table.sql new file mode 100644 index 0000000..82f7cbd --- /dev/null +++ b/db/mysql/create_users_table.sql @@ -0,0 +1,7 @@ +CREATE table if not exists users ( + id integer primary key auto_increment, + username text not null, + hash text not null, + can_post integer not null default 0, + is_admin integer not null default 0, + created timestamp not null default current_timestamp) diff --git a/db/mysql/get_last_post.sql b/db/mysql/get_last_post.sql new file mode 100644 index 0000000..57c68ee --- /dev/null +++ b/db/mysql/get_last_post.sql @@ -0,0 +1,4 @@ +SELECT * +from posts +where + id = last_insert_id() diff --git a/db/sqlite/create_links_table.sql b/db/sqlite/create_links_table.sql new file mode 100644 index 0000000..d6be4b1 --- /dev/null +++ b/db/sqlite/create_links_table.sql @@ -0,0 +1,8 @@ +CREATE table if not exists links ( + id integer primary key autoincrement, + label text not null, + url text not null, + icon text not null, + position text not null, + visibility text null, + sort integer not null default 0) diff --git a/db/sqlite/create_posts_table.sql b/db/sqlite/create_posts_table.sql new file mode 100644 index 0000000..c031c5a --- /dev/null +++ b/db/sqlite/create_posts_table.sql @@ -0,0 +1,9 @@ +CREATE table if not exists posts ( + id integer primary key autoincrement, + username text not null, + content text not null, + location text not null, + visibility text null, + created timestamp not null default current_timestamp, + updated timestamp not null default current_timestamp, + sort integer not null default 0) diff --git a/db/sqlite/create_sessions_table.sql b/db/sqlite/create_sessions_table.sql new file mode 100644 index 0000000..d93597a --- /dev/null +++ b/db/sqlite/create_sessions_table.sql @@ -0,0 +1,5 @@ +CREATE table if not exists sessions ( + id integer primary key autoincrement, + username text not null, + token text not null, + expires timestamp null) diff --git a/db/sqlite/create_settings_table.sql b/db/sqlite/create_settings_table.sql new file mode 100644 index 0000000..e0a9139 --- /dev/null +++ b/db/sqlite/create_settings_table.sql @@ -0,0 +1,4 @@ +CREATE table if not exists settings ( + id integer primary key autoincrement, + setting text not null, + value text not null) diff --git a/db/sqlite/create_users_table.sql b/db/sqlite/create_users_table.sql new file mode 100644 index 0000000..dd608c1 --- /dev/null +++ b/db/sqlite/create_users_table.sql @@ -0,0 +1,7 @@ +CREATE table if not exists users ( + id integer primary key autoincrement, + username text not null, + hash text not null, + can_post integer not null default 0, + is_admin integer not null default 0, + created timestamp not null default current_timestamp) diff --git a/db/sqlite/get_last_post.sql b/db/sqlite/get_last_post.sql new file mode 100644 index 0000000..abbeca0 --- /dev/null +++ b/db/sqlite/get_last_post.sql @@ -0,0 +1,4 @@ +SELECT * +from posts +where + rowid = last_insert_rowid() diff --git a/files/FormValidator/FormValidator.js b/files/FormValidator/FormValidator.js new file mode 100644 index 0000000..917cbcf --- /dev/null +++ b/files/FormValidator/FormValidator.js @@ -0,0 +1,46 @@ +$(function() { + FormValidator = {}; + + FormValidator.onError = function(str) + { + alert(str); + console.log(str); + }; + + FormValidator.validate = function(callback) + { + var pass = 1; + + $("[fv-regex]").each(function(i, x) { + + if (pass == 0) + return; + + x = $(x); + + let input = x.val(); + let regex = new RegExp(x.attr("fv-regex"), "g"); + + if (!input.match(regex)) + { + x.addClass("border-danger"); + x.focus(); + x.select(); + + let warning = x.attr("fv-warning") ?? "Please correct the highlighted input and try again"; + + FormValidator.onError(warning) + + pass = 0; + return; + } + + if (pass == 1) + if (typeof callback === "function") + callback(); + + x.removeClass("border-danger"); + }); + + }; +}); diff --git a/files/SearchableInput/SearchableInput.css b/files/SearchableInput/SearchableInput.css new file mode 100644 index 0000000..a3ec784 --- /dev/null +++ b/files/SearchableInput/SearchableInput.css @@ -0,0 +1,37 @@ +div.searchable-input input +{ + width: 100%; + box-sizing: border-box; +} + +div.searchable-input div.items +{ + padding-top: 0.5em; + padding-bottom: 0.5em; + border: 1px solid #aaa; + /*border-top: 0;*/ + max-width: 100%; + max-height: 10em; + overflow-x: scroll; + overflow-y: scroll; + position: absolute; + background: #fff; + box-sizing: border-box; +} + +div.searchable-input div.item +{ + white-space: normal; + padding-left: 0.5em; + padding-right: 0.5em; + user-select: none; +} + +div.searchable-input div.item:hover +{ + /*background: #0af; + color: #fff;*/ + background: highlight; + color: highlighttext; + cursor: pointer; +} diff --git a/files/SearchableInput/SearchableInput.js b/files/SearchableInput/SearchableInput.js new file mode 100644 index 0000000..bf0e050 --- /dev/null +++ b/files/SearchableInput/SearchableInput.js @@ -0,0 +1,206 @@ +$(function() { + SearchableInput = {}; + + SearchableInput.initItems = function() + { + var items = $("div.searchable-input div.item"); + + items.each(function(i, x) { + x = $(x); + + var parent = x.parents("div.searchable-input").first(); + var input = parent.find("input").first(); + var item = x; + var itemContainer = parent.find("div.items").first(); + + if (item.is("[onclick]")) + return; + + if (!item.is("[data-value]")) + return; + + item.unbind("mousedown"); + item.bind("mousedown", function() { + input.attr("data-value", item.attr("data-value")); + input.val(item.text().trim()); + itemContainer.hide(); + }); + }); + }; + + SearchableInput.init = function() + { + $("div.searchable-input input").each(function(i, x) { + x = $(x); + + var parent = x.parents("div.searchable-input").first(); + var backgroundColor = null; + var selectColor = null; + var input = x; + var itemContainer = parent.find("div.items").first(); + var items = itemContainer.find("div.item"); + var strictSearch = parent.attr("strict-search"); + + // Get first opaque body color: + parent.parents("*").each(function(i, x) { + if (backgroundColor !== null) + return; + + x = $(x); + var color = x.css("backgroundColor"); + + if (/^rgba/.test(color)) + { + var alphaPart = parseFloat(color.split(",")[3]); + + if (isNaN(alphaPart)) + return; + + if (alphaPart > 0.9) + backgroundColor = color; + + return; + } + + if (/^rgb/.test(color)) + backgroundColor = color; + }); + + itemContainer.hide(); + + x.unbind("blur"); + x.bind("blur", function() { + setTimeout(function() { + itemContainer.hide(); + + if (input.val().trim().length < 1) + input.attr("data-value", null); + }, 10); + }); + + x.unbind("input"); + x.bind("input", function() { + + var fnOnInputCooldown = function(itemContainer) + { + var parent = itemContainer.parents("div.searchable-input").first(); + var input = parent.find("input").first(); + var items = itemContainer.find("div.item"); + var searchTermsString = input.val().toLowerCase().trim(); + var searchTerms = searchTermsString.split(" "); + + items.hide(); + + items.each(function(i, x) { + x = $(x); + + var item = x; + var pass = 1; + var itemText = item.text().toLowerCase().trim(); + + if (strictSearch) + { + if (itemText.includes(searchTermsString)) + item.show(); + return; + } + + for (var i = 0; i < searchTerms.length; i++) + { + var searchTerm = searchTerms[i]; + if (searchTerm.length < 1) + continue; + if (!itemText.includes(searchTerm)) + pass = 0; + } + + //item.hide(); + + if (pass == 1) + item.show(); + }); + }; + + + var dataSourceApi = itemContainer.attr("data-source-api"); + + if (dataSourceApi) + { + if (typeof(SearchableInput.timeout) !== "undefined") + clearTimeout(SearchableInput.timeout); + + SearchableInput.timeout = setTimeout(function() { + var searchTermsString = input.val().toLowerCase().trim(); + + console.log(dataSourceApi); + + $.get({ + url: `${dataSourceApi}?q=${searchTermsString}`, + //url: `${dataSourceApi}`, + method: "get", + success: function(data) + { + console.log(data); + itemContainer.html(""); + + for (var i = 0; i < data.length; i++) + { + var item = data[i]; + var itemElement = $("
"); + + itemElement.addClass("item"); + itemElement.attr("data-value", item.value); + itemElement.html(item.name); + + itemContainer.append(itemElement); + } + + SearchableInput.initItems(); + + fnOnInputCooldown(itemContainer); + }, + error: function(xhr, e, m) + { + console.log(e); + console.log(m); + } + }); + }, 1000); + } + + fnOnInputCooldown(itemContainer); + }); + + x.unbind("focus"); + x.bind("focus", function() { + //x.trigger("input"); + + itemContainer.css("width", parent.width() + "px"); + itemContainer.css("background", backgroundColor); + + // If data-source is a valid jQuery selector, use that container's innerHTML: + var dataSource = itemContainer.attr("data-source"); + + if (dataSource) + { + var dataSourceObject = $(dataSource); + if (dataSourceObject.length > 0) + { + itemContainer.html(dataSourceObject.first().html()); + //SearchableInput.init(); + SearchableInput.initItems(); + } + } + + itemContainer.show(); + items.show(); + input.select(); + + }); + + SearchableInput.initItems(); + }); + }; + + SearchableInput.init(); +}); diff --git a/footer.php b/footer.php index 13b9c51..1754c3f 100644 --- a/footer.php +++ b/footer.php @@ -1,5 +1,6 @@ query("SELECT * from links where position like 'footer' order by sort"); ?> @@ -9,6 +10,8 @@