From 44f29bf758c66cd4ebe717766474e9aca75e7354 Mon Sep 17 00:00:00 2001 From: Neil Brommer Date: Sat, 16 Dec 2017 14:25:50 -0800 Subject: [PATCH] Add current project --- .gitignore | 3 + README.md | 18 +- css/multiTable.css | 55 ++++ css/prism.css | 139 +++++++++ dbTools.php | 13 + documentation.html | 413 +++++++++++++++++++++++++ favicon.ico | Bin 0 -> 5558 bytes index.html | 362 ++++++++++++++++++++++ js/docs.js | 174 +++++++++++ js/main.js | 739 +++++++++++++++++++++++++++++++++++++++++++++ lang.php | 284 +++++++++++++++++ resource.php | 238 +++++++++++++++ snippet.php | 250 +++++++++++++++ tables.png | Bin 0 -> 78491 bytes tables.xml | 1 + 15 files changed, 2688 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 css/multiTable.css create mode 100644 css/prism.css create mode 100644 dbTools.php create mode 100644 documentation.html create mode 100644 favicon.ico create mode 100644 index.html create mode 100644 js/docs.js create mode 100644 js/main.js create mode 100644 lang.php create mode 100644 resource.php create mode 100644 snippet.php create mode 100644 tables.png create mode 100644 tables.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c01b39a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +lib/ +info.php diff --git a/README.md b/README.md index ed3c5de..cdb7678 100644 --- a/README.md +++ b/README.md @@ -1 +1,17 @@ -SnippetManager +# Snippet Manager + +An instance of this site is hosted at [snippets.neilbrommer.com](https://snippets.neilbrommer.com) + +A tool for keeping pieces of useful code and programming resources. + +Includes a RESTful API and a web client. + +There is currently no login system; all data is public. + +## Libraries + +[JQuery](https://jquery.com/) + +[Popper.js](https://popper.js.org/) + +[Bootstrap](https://getbootstrap.com/) diff --git a/css/multiTable.css b/css/multiTable.css new file mode 100644 index 0000000..eb7cc72 --- /dev/null +++ b/css/multiTable.css @@ -0,0 +1,55 @@ +.navbar { + margin-top: 20px; + margin-bottom: 20px; +} + +html { + padding-bottom: 50px; +} + +pre { + tab-size: 4; + -moz-tab-size: 4; + background-color: rgb(245, 245, 245); + padding: 10px; +} + +.langList { + margin-bottom: 5px; +} + +.addSection { + margin-top: 15px; +} + +.snippetBody { + font-family: monospace; +} + +.requiredField { + color: red; +} + +#successAlert { + display: none; +} + +.card-header { + padding-top: 7px; + padding-bottom: 7px; +} + +.langSelect { + width: 100%; +} + +#tablesImg { + width: 100%; +} + +.resultsContainer { + white-space: pre-wrap; + background-color: rgb(245, 245, 245); + max-height: 600px; + margin-bottom: 0px; +} diff --git a/css/prism.css b/css/prism.css new file mode 100644 index 0000000..e0dd385 --- /dev/null +++ b/css/prism.css @@ -0,0 +1,139 @@ +/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+abap+actionscript+ada+apacheconf+apl+applescript+c+asciidoc+aspnet+autohotkey+autoit+bash+basic+batch+bison+brainfuck+bro+cpp+csharp+arduino+coffeescript+ruby+css-extras+d+dart+django+diff+docker+eiffel+elixir+erlang+fsharp+flow+fortran+gherkin+git+glsl+go+graphql+groovy+haml+handlebars+haskell+haxe+http+icon+inform7+ini+j+java+jolie+json+julia+keyman+kotlin+latex+less+livescript+lolcode+lua+makefile+markdown+matlab+mel+mizar+monkey+n4js+nasm+nginx+nim+nix+nsis+objectivec+ocaml+opencl+oz+parigp+parser+pascal+perl+php+php-extras+powershell+processing+prolog+properties+protobuf+pug+puppet+pure+python+q+qore+r+jsx+renpy+reason+rest+rip+roboconf+crystal+rust+sas+sass+scss+scala+scheme+smalltalk+smarty+sql+stylus+swift+tcl+textile+twig+typescript+vbnet+verilog+vhdl+vim+wiki+xojo+yaml */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, pre[class*="language-"] ::selection, +code[class*="language-"]::selection, code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + diff --git a/dbTools.php b/dbTools.php new file mode 100644 index 0000000..487e14f --- /dev/null +++ b/dbTools.php @@ -0,0 +1,13 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + return new PDO($dsn, $user, $pass, $opt); +} +?> diff --git a/documentation.html b/documentation.html new file mode 100644 index 0000000..d6e9953 --- /dev/null +++ b/documentation.html @@ -0,0 +1,413 @@ + + + + + + + + + + + Documentation - Multi-Table Service + + + + + + + + + + +
+ + +

About

+

+ This app keeps a set of code snippets and programming resources categorized by language/library. + Each snippet or resource can be associated with multiple languages and vice versa. +

+ +

Features I plan to add to the backend:

+ + +

Features I plan to add to the web client:

+ + +
+ +

Tables

+

There are three main tables:

+ + +

And three tables used to link these tables together:

+ + + + +

Each of the three main tables has a corresponding API endpoint (off of the base URL webdev.neilbrommer.com/multiTable/):

+ + +
+ +

API

+

+ Each of the endpoints is off of the base URL of https://webdev.neilbrommer.com/multiTable/. + SSL is required. +

+

Arguments that are underlined are optional.

+ +

lang.php

+

For managing the list of languages.

+ +
+
+

webdev.neilbrommer.com/multiTable/lang.php

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
Results will appear here
+
+ +
+
GET
+
+

+ Each of these returns a JSON object with langID, langName, langDescription, + a list of related languages, a list of snippets, and a list of resources. +

+
    +
  • + No arguments: returns all language entries. +
  • +
  • + langID (number): returns the specified language. +
  • +
+
+ +
POST
+

Returns the langID of the new entry.

+
+
    +
  • + langName (string), langDescription (string), associatedLang + (number): Creates a new language with the specified information. associatedLang is the + langID of the language you want to link to the one being created. More languages can be linked later + via PUT. +
  • +
+
+ +
PUT
+

Returns no data.

+
+
    +
  • + langID (number), langName (string), langDescription + (string), associatedLang (number): Modifies any provided fields for the language + specified by the langID. +
  • +
+
+ +
DELETE
+

Returns no data.

+
+
    +
  • + langID (number): Deletes the specified language entry, including all connections to snippets, + resources, and other languages. +
  • +
  • + langID (number), associatedLang (number): Removes the connection between the two + specified languages. +
  • +
+
+
+ +

snippet.php

+

For managing the list of snippets.

+ +
+
+

webdev.neilbrommer.com/multiTable/snippet.php

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
Results will appear here
+
+ +
+
GET
+
+

+ Each of these returns a JSON object with snippetID, snippetName, + snippetDescription, snippet, and a list of related languages. +

+ +
    +
  • + No arguments: Returns a list of all snippets. +
  • +
  • + snippetID (number): Returns the entry for the specified language. +
  • +
  • + langID (number): Returns a list of snippets related to the given language. +
  • +
+
+ +
POST
+
+

Returns the snippetID of the new snippet.

+
    +
  • + snippetName (string), langID (number), + snippetDescription (string), snippet (string): + Creates a new snippet with the given values. + + Only one language can be associated with a snippet at creation. More can be added later via + PUT. +
  • +
+
+ +
PUT
+
+

Returns nothing

+
    +
  • + snippetID (number), langID (number), + snippetName (string), snippetDescription (string), + snippet (string): Modifies the specified information. +
  • +
+
+ +
DELETE
+
+

Returns nothing

+
    +
  • + snippetID (number): Deletes the entry for the specified snippet. +
  • +
  • + snippetID (number), langID (number): Removes the connection between + the specified snippet and language. +
  • +
+
+
+ +

resource.php

+

For managing the list of resources.

+

+ The API for resource.php is nearly identical to the one for snippet.php with resourceLink + in place of snippet. +

+ +
+
+

webdev.neilbrommer.com/multiTable/resource.php

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
Results will appear here
+
+ +
+
GET
+
+

+ Returns JSON encoded resources with a resourceID, a resourceName, a + resourceDescription, a resourceLink, and a list of related + languages. +

+
    +
  • + No arguments: Returns a list of all resource entries. +
  • +
  • + langID (number): Returns a list of resources related to the specified language. +
  • +
  • + resourceID (number): Returns the specified resource entry. +
  • +
+
+ +
POST
+
+

+ Returns the resourceID of the newly created resource. +

+
    +
  • + resourceName (string), langID (number), + resourceDescription (string), and resourceLink (string): + Creates a resource with the given information. + + Only one language can be associated at creation. More can be added via PUT. +
  • +
+
+ +
PUT
+
+

Returns nothing.

+
    +
  • + resourceID (number), resourceName (string), + langID (number), resourceDescription (string), and + resourceLink (string): Modifies the specified data for the specified + resource. +
  • +
+
+ +
DELETE
+
+

Returns nothing.

+
    +
  • + resourceID (number): Deletes the specified resource. +
  • +
  • + resourceID (number), langID (number): Removes the connection between + the specified resource and language. +
  • +
+
+
+ +
+ + + + + + + + + + + diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..17b809d8214f47e653e8591beba66fb54f308b3c GIT binary patch literal 5558 zcmeHLTW?HJ6h3YIfO^(xr!~`7l@?W1%$)lk9(Zs|JV;;A5G10cH`fRr+#(_(E^&!l zcqk7Pb&ER@#W}bdsHYX79b$xAr<~e`}qsC`C%KQc|Lz z4=ZgG6s1a0lyKPnUo%lr4r8naV_1R}?l?N%UpyY~LHntyD#DZunY1 zT=RG>iKpcxo|TchXn|vs{UD67GP2HBlWN8@+NrH68;3tzSE8i1&&)WVue`pliR{~z8TDHis>$e_;X7|^nMHPQB^f;pzVo~f zeRCs;`(ZM=(sk&Y8p*yDA!ASd=<@d}$k^`h1AQ&*zmvuOj&y9#$NBm%Z}}C;_*v-2 zooAQRTZo@N#LxQ7@x$xPBXuMm`NZ$zakZPpGZ$9Ve2Qa&Ej=0bG-u&iR2Cc`J z6eI?jXToSI8uQU8zarStiT1_Mo-r8v4V_<;dn`uZF$Nep`5f5Y!2VP~{BOW!f8=Cu zLDqq@&4bgxf0JGQe_lr7Rfx3ZEhB8U`;ZG>hMfE$z(wZCTGE!z8?h#c{r1fWB|c7a z8s{E?^D3T{leTQ6Zo3!u^e&n3ScC+t- z?3-mcAFvMlMnqbNxo^57Yh9|6mi6p4cGtT)IKNBADCax2-MSu?mi4fP@Xw9odp^mv z|117S&EdSmGsus!?;rJ$8@s{ZzjbPgqr*H@CymebB;$+zu(T}iRbSmq;!UZeLjw=U z?q5yBNW2a?^2V;rwO^`Ub8o%FqlpjTFf=~LscUlm&oxovt-A;2Z0mA%F5tKksOu90 zuAF&vYH<9Gjg)ww#OFFoB955fIiK)5)Z3cmZD9Xn&n$0j^{&TnOcwbS$|xV&)wd6(7?eQ|I8u! zn%p^n>rU|y90pl)e{lX}JFKfw*9Nu&T*{m-(5KeFjK}%H<9x>E`x0$&@cPs71MXFf zoegAPi#m58%*~9IT3hoSfsH!^8?`q-bI!~K8{a^`JbxFcA1n|qVeg;O+6#!^&7bGM Y--gD1_*dV8gV=WmV~=t#@Lx>*0e1%b0RR91 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..57a21e4 --- /dev/null +++ b/index.html @@ -0,0 +1,362 @@ + + + + + + + + + + + Multi-Table Service + + + + + + + + + + +
+ + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/js/docs.js b/js/docs.js new file mode 100644 index 0000000..4385fc5 --- /dev/null +++ b/js/docs.js @@ -0,0 +1,174 @@ +$(document).ready(function () { + $("#languageForm").submit(languageSubmit); + $("#snippetForm").submit(snippetSubmit); + $("#resourceForm").submit(resourceSubmit); +}); + +function languageSubmit(e) { + e.preventDefault(); + var type = $("#languageType").val(); + var data = {}; + + if (type == "GET" || type == "DELETE") { + var langID = $("#languageLangID").val(); + var assoc = $("#languageAssocLang").val(); + + if (langID != "") + data['langID'] = langID; + if (assoc != "") + data['associatedLang'] = assoc; + } else if (type == "POST") { + var langName = $("#languageLangName").val(); + var langDesc = $("#languageLangDesc").val(); + var assoc = $("#languageAssocLang").val(); + + if (langName != "") + data['langName'] = langName; + if (langDesc != "") + data['langDescription'] = langDesc; + if (assoc != "") + data['associatedLang'] = assoc; + } else { // PUT + var langID = $("#languageLangID").val(); + var langName = $("#languageLangName").val(); + var langDesc = $("#languageLangDesc").val(); + var assoc = $("#languageAssocLang").val(); + + if (langID != "") + data['langID'] = langID; + if (langName != "") + data['langName'] = langName; + if (langDesc != "") + data['langDescription'] = langDesc; + if (assoc != "") + data['associatedLang'] = assoc; + } + + makeRequest(type, "lang.php", data, $("#languageResults")); +} + +function snippetSubmit(e) { + e.preventDefault(); + var type = $("#snippetType").val(); + var data = {}; + + if (type == "GET" || type == "DELETE") { + var snippetID = $("#snippetSnippetID").val(); + var assoc = $("#snippetLangID").val(); + + if (snippetID != "") + data['snippetID'] = snippetID; + if (assoc != "") + data['langID'] = assoc; + } else if (type == "POST") { + var snippetName = $("#snippetSnippetName").val(); + var snippetDesc = $("#snippetSnippetDesc").val(); + var body = $("#snippetSnippetBody").val(); + var assoc = $("#snippetLangID").val(); + + if (snippetName != "") + data['snippetName'] = snippetName; + if (snippetDesc != "") + data['snippetDescription'] = snippetDesc; + if (body != "") + data['snippet'] = body; + if (assoc != "") + data['langID'] = assoc; + } else { // PUT + var snippetID = $("#snippetSnippetID").val(); + var snippetName = $("#snippetSnippetName").val(); + var snippetDesc = $("#snippetSnippetDesc").val(); + var body = $("#snippetSnippetBody").val(); + var assoc = $("#snippetLangID").val(); + + if (snippetID != "") + data['snippetID'] = snippetID; + if (snippetName != "") + data['snippetName'] = snippetName; + if (snippetDesc != "") + data['snippetDescription'] = snippetDesc; + if (body != "") + data['snippet'] = body; + if (assoc != "") + data['langID'] = assoc; + } + + makeRequest(type, "snippet.php", data, $("#snippetResults")); +} + +function resourceSubmit(e) { + e.preventDefault(); + var type = $("#resourceType").val(); + var data = {}; + + if (type == "GET" || type == "DELETE") { + var resourceID = $("#resourceResourceID").val(); + var assoc = $("#resourceLangID").val(); + + if (resourceID != "") + data['resourceID'] = resourceID; + if (assoc != "") + data['langID'] = assoc; + } else if (type == "POST") { + var resourceName = $("#resourceResourceName").val(); + var resourceDesc = $("#resourceResourceDesc").val(); + var link = $("#resourceResourceLink").val(); + var assoc = $("#resourceLangID").val(); + + if (resourceName != "") + data['resourceName'] = resourceName; + if (resourceDesc != "") + data['resourceDescription'] = resourceDesc; + if (link != "") + data['resourceLink'] = link; + if (assoc != "") + data['langID'] = assoc; + } else { // PUT + var resourceID = $("#resourceResourceID").val(); + var resourceName = $("#resourceResourceName").val(); + var resourceDesc = $("#resourceResourceDesc").val(); + var link = $("#resourceResourceLink").val(); + var assoc = $("#resourceLangID").val(); + + if (resourceID != "") + data['resourceID'] = resourceID; + if (resourceName != "") + data['resourceName'] = resourceName; + if (resourceDesc != "") + data['resourceDescription'] = resourceDesc; + if (link != "") + data['resourceLink'] = link; + if (assoc != "") + data['langID'] = assoc; + } + + makeRequest(type, "resource.php", data, $("#resourceResults")); +} + +function makeRequest(type, endpoint, data, resultsSection) { + $.ajax({ + url: endpoint, + type: type, + data: data, + success: function (res, status, xhr) { insertSuccess(res, xhr, resultsSection); }, + error: function (xhr, status, err) { insertError(xhr, resultsSection); } + }); +} + +function insertSuccess(results, xhr, resultsSection) { + var str = xhr.getAllResponseHeaders() + "\r\nStatus Code: " + xhr.status + " " + xhr.statusText; + if (results != null) { + if (typeof results === 'string' || results instanceof String) + str += "\r\n\r\n" + results; + else + str += "\r\n\r\n" + JSON.stringify(results, null, 4); + } + resultsSection.text(str); +} + +function insertError(xhr, resultsSection) { + var str = xhr.getAllResponseHeaders() + "\r\nStatus Code: " + xhr.status + " " + xhr.statusText; + if (xhr.responseText != null) + str += "\r\n\r\n" + xhr.responseText; + resultsSection.text(str); +} diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..7eba306 --- /dev/null +++ b/js/main.js @@ -0,0 +1,739 @@ +var selectList = []; + +$(document).ready(function () { + loadLangs(); + + $("#langLink").click(function (evt) { + evt.preventDefault(); + loadLangs(); + }); + $("#snippetLink").click(function (evt) { + evt.preventDefault(); + loadSnippets(); + }); + $("#resourceLink").click(function (evt) { + evt.preventDefault(); + loadResources(); + }); + + $("#addModal").on("show.bs.modal", function (e) { + $("#addLangTab").tab("show"); + $(".addField").val(""); + buildLangSelect(); + }); + $("#editLangModal").on("shown.bs.modal", function (e) { $(".langSelect").val(selectList); }); + $("#editSnippetModal").on("shown.bs.modal", function (e) { $(".langSelect").val(selectList); }); + $("#editResourceModal").on("shown.bs.modal", function (e) { $(".langSelect").val(selectList); }); + $("#addModal").on("shown.bs.modal", function (e) { $("#txtLangName").focus(); }); + $("#addLangTab").on("shown.bs.tab", function (e) { $("#txtLangName").focus(); }); + $("#addSnippetTab").on("shown.bs.tab", function (e) { $("#txtSnippetName").focus(); }); + $("#addResourceTab").on("shown.bs.tab", function (e) { $("#txtResourceName").focus(); }); + + $("#btnAddItem").click(addNewItem); + $("#btnSaveLang").click(saveLang); + $("#btnSaveSnippet").click(saveSnippet); + $("#btnSaveResource").click(saveResource); + $(".clearLangSelect").click(function () { $(".langSelect").val([]); }); + + $(".editChk").change(checkBoxChange); +}); + +function buildLangSelect() { + $.ajax({ + url: "lang.php", + type: "GET", + success: addSelectLangs, + error: displayError + }); +} + +function addSelectLangs(langList) { + var selectors = $(".langSelect"); + selectors.empty(); + for (var i = 0; i < langList.length; i++) { + var cur = langList[i]; + $("