Add current project
This commit is contained in:
		
							parent
							
								
									61df06fa4e
								
							
						
					
					
						commit
						44f29bf758
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| .vscode/ | ||||
| lib/ | ||||
| info.php | ||||
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								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/) | ||||
|  |  | |||
							
								
								
									
										55
									
								
								css/multiTable.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								css/multiTable.css
									
									
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										139
									
								
								css/prism.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								css/prism.css
									
									
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										13
									
								
								dbTools.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								dbTools.php
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| <?php | ||||
| function buildPDO() { | ||||
| 	include_once "info.php"; | ||||
| 
 | ||||
| 	$dsn = "mysql:host=$host;dbname=$db;charset=$charset"; | ||||
| 	$opt = [ | ||||
| 		PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, | ||||
| 		PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, | ||||
| 		PDO::ATTR_EMULATE_PREPARES   => false, | ||||
| 	]; | ||||
| 	return new PDO($dsn, $user, $pass, $opt); | ||||
| } | ||||
| ?>
 | ||||
							
								
								
									
										413
									
								
								documentation.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								documentation.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,413 @@ | |||
| <!doctype html> | ||||
| <html lang="en"> | ||||
| 
 | ||||
| <head> | ||||
| 	<meta charset="utf-8"> | ||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||||
| 	<meta name="description" content="A new tab page"> | ||||
| 	<meta name="author" content="Neil Brommer"> | ||||
| 	<link rel="icon" href="favicon.ico"> | ||||
| 
 | ||||
| 	<title>Documentation - Multi-Table Service</title> | ||||
| 
 | ||||
| 	<!-- Bootstrap core CSS --> | ||||
| 	<link href="lib/bootstrap/css/bootstrap.min.css" rel="stylesheet"> | ||||
| 
 | ||||
| 	<!-- Custom styles --> | ||||
| 	<link href="css/multiTable.css" rel="stylesheet"> | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
| 
 | ||||
| 	<div id="wrapper" class="container"> | ||||
| 		<nav class="navbar rounded navbar-expand-md navbar-dark bg-dark mb-4"> | ||||
| 			<a class="navbar-brand" href="#">Snippets</a> | ||||
| 			<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" | ||||
| 			 aria-expanded="false" aria-label="Toggle navigation"> | ||||
| 				<span class="navbar-toggler-icon"></span> | ||||
| 			</button> | ||||
| 			<div class="collapse navbar-collapse" id="navbarCollapse"> | ||||
| 				<ul class="navbar-nav mr-auto"> | ||||
| 					<li> | ||||
| 						<a class="nav-link" href="index.html">Web Client</a> | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<a class="nav-link active" href="documentation.html">API</a> | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 				<form class="form-inline mt-2 mt-md-0"> | ||||
| 				</form> | ||||
| 			</div> | ||||
| 		</nav> | ||||
| 
 | ||||
| 		<h1>About</h1> | ||||
| 		<p> | ||||
| 			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. | ||||
| 		</p> | ||||
| 
 | ||||
| 		<p>Features I plan to add to the backend:</p> | ||||
| 		<ul> | ||||
| 			<li>A login system</li> | ||||
| 			<li>Add a column for snippets to indicate the language the snippet is written in</li> | ||||
| 			<li>Search</li> | ||||
| 		</ul> | ||||
| 
 | ||||
| 		<p>Features I plan to add to the web client:</p> | ||||
| 		<ul> | ||||
| 			<li>Syntax highlighting via <a href="http://prismjs.com/" target="_blamk">Prism</a></li> | ||||
| 			<li>When a single language is selected, show all related snippets and resources</li> | ||||
| 			<li>Deep linking</li> | ||||
| 		</ul> | ||||
| 
 | ||||
| 		<hr> | ||||
| 
 | ||||
| 		<h1>Tables</h1> | ||||
| 		<p>There are three main tables:</p> | ||||
| 		<ul> | ||||
| 			<li>language</li> | ||||
| 			<li>snippet</li> | ||||
| 			<li>resource</li> | ||||
| 		</ul> | ||||
| 
 | ||||
| 		<p>And three tables used to link these tables together:</p> | ||||
| 		<ul> | ||||
| 			<li>langLang</li> | ||||
| 			<li>langSnippet</li> | ||||
| 			<li>langResource</li> | ||||
| 		</ul> | ||||
| 
 | ||||
| 		<img id="tablesImg" src="tables.png" class="img-fluid rounded my-3 p-2 border"> | ||||
| 
 | ||||
| 		<p>Each of the three main tables has a corresponding API endpoint  (off of the base URL webdev.neilbrommer.com/multiTable/):</p> | ||||
| 		<ul> | ||||
| 			<li>lang.php</li> | ||||
| 			<li>snippet.php</li> | ||||
| 			<li>resource.php</li> | ||||
| 		</ul> | ||||
| 
 | ||||
| 		<hr> | ||||
| 
 | ||||
| 		<h1>API</h1> | ||||
| 		<p> | ||||
| 			Each of the endpoints is off of the base URL of <u>https://webdev.neilbrommer.com/multiTable/</u>. | ||||
| 			SSL is required. | ||||
| 		</p> | ||||
| 		<p>Arguments that are <u>underlined</u> are optional.</p> | ||||
| 
 | ||||
| 		<h3 class="mt-5">lang.php</h3> | ||||
| 		<p>For managing the list of languages.</p> | ||||
| 
 | ||||
| 		<div class="row border mb-4 rounded"> | ||||
| 			<form id="languageForm" class="py-3 col-md-4"> | ||||
| 				<p>webdev.neilbrommer.com<wbr>/multiTable<wbr>/lang.php</p> | ||||
| 				<div class="form-group"> | ||||
| 					<select id="languageType" class="custom-select"> | ||||
| 						<option value="GET" selected>GET</option> | ||||
| 						<option value="POST">POST</option> | ||||
| 						<option value="PUT">PUT</option> | ||||
| 						<option value="DELETE">DELETE</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="languageLangID">langID</label> | ||||
| 					<input id="languageLangID" type="number" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="languageLangName">langName</label> | ||||
| 					<input id="languageLangName" type="text" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="languageLangDesc">langDescription</label> | ||||
| 					<input id="languageLangDesc" type="text" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="languageAssocLang">associatedLang</label> | ||||
| 					<input id="languageAssocLang" type="number" class="form-control"> | ||||
| 				</div> | ||||
| 				<button id="languageSubmit" type="submit" class="btn btn-primary">Submit</button> | ||||
| 			</form> | ||||
| 			<pre class="col-md-8 p-1 resultsContainer"><code id="languageResults">Results will appear here</code></pre> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<dl> | ||||
| 			<dt>GET</dt> | ||||
| 			<dd> | ||||
| 				<p> | ||||
| 				Each of these returns a JSON object with <code>langID</code>, <code>langName</code>, <code>langDescription</code>, | ||||
| 				a list of related <code>languages</code>, a list of <code>snippets</code>, and a list of <code>resources</code>. | ||||
| 				</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						No arguments: returns all language entries. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>langID</code> (number): returns the specified language. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>POST</dt> | ||||
| 			<p>Returns the <code>langID</code> of the new entry.</p> | ||||
| 			<dd> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>langName</code> (string), <u><code>langDescription</code></u> (string), <u><code>associatedLang</code></u> | ||||
| 						(number): Creates a new language with the specified information. <code>associatedLang</code> is the | ||||
| 						<code>langID</code> of the language you want to link to the one being created. More languages can be linked later | ||||
| 						via <code>PUT</code>. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>PUT</dt> | ||||
| 			<p>Returns no data.</p> | ||||
| 			<dd> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>langID</code> (number), <u><code>langName</code></u> (string), <u><code>langDescription</code></u> | ||||
| 						(string), <u><code>associatedLang</code></u> (number): Modifies any provided fields for the language | ||||
| 						specified by the <code>langID</code>. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>DELETE</dt> | ||||
| 			<p>Returns no data.</p> | ||||
| 			<dd> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>langID</code> (number): Deletes the specified language entry, including all connections to snippets, | ||||
| 						resources, and other languages. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>langID</code> (number), <code>associatedLang</code> (number): Removes the connection between the two | ||||
| 						specified languages. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 		</dl> | ||||
| 
 | ||||
| 		<h3 class="mt-5">snippet.php</h3> | ||||
| 		<p>For managing the list of snippets.</p> | ||||
| 
 | ||||
| 		<div class="row border mb-4 rounded"> | ||||
| 			<form id="snippetForm" class="py-3 col-md-4"> | ||||
| 				<p class="wrapping">webdev.neilbrommer.com<wbr>/multiTable<wbr>/snippet.php</p> | ||||
| 				<div class="form-group"> | ||||
| 					<select id="snippetType" class="custom-select"> | ||||
| 						<option value="GET" selected>GET</option> | ||||
| 						<option value="POST">POST</option> | ||||
| 						<option value="PUT">PUT</option> | ||||
| 						<option value="DELETE">DELETE</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="snippetSnippetID">snippetID</label> | ||||
| 					<input id="snippetSnippetID" type="number" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="snippetSnippetName">snippetName</label> | ||||
| 					<input id="snippetSnippetName" type="text" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="snippetSnippetDesc">snippetDescription</label> | ||||
| 					<input id="snippetSnippetDesc" type="text" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="snippetSnippetBody">snippet</label> | ||||
| 					<textarea id="snippetSnippetBody" class="form-control"></textarea> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="snippetLangID">langID</label> | ||||
| 					<input id="snippetLangID" type="number" class="form-control"> | ||||
| 				</div> | ||||
| 				<button id="snippetSubmit" type="submit" class="btn btn-primary">Submit</button> | ||||
| 			</form> | ||||
| 			<pre class="col-md-8 p-1 resultsContainer"><code id="snippetResults">Results will appear here</code></pre> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<dl> | ||||
| 			<dt>GET</dt> | ||||
| 			<dd> | ||||
| 				<p> | ||||
| 					Each of these returns a JSON object with <code>snippetID</code>, <code>snippetName</code>, | ||||
| 					<code>snippetDescription</code>, <code>snippet</code>, and a list of related <code>languages</code>. | ||||
| 				</p> | ||||
| 
 | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						No arguments: Returns a list of all snippets. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>snippetID</code> (number): Returns the entry for the specified language. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>langID</code> (number): Returns a list of snippets related to the given language. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>POST</dt> | ||||
| 			<dd> | ||||
| 				<p>Returns the <code>snippetID</code> of the new snippet.</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>snippetName</code> (string), <u><code>langID</code></u> (number), | ||||
| 						<u><code>snippetDescription</code></u> (string), <u><code>snippet</code></u> (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 | ||||
| 						<code>PUT</code>. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>PUT</dt> | ||||
| 			<dd> | ||||
| 				<p>Returns nothing</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>snippetID</code> (number), <u><code>langID</code></u> (number), | ||||
| 						<u><code>snippetName</code></u> (string), <u><code>snippetDescription</code></u> (string), | ||||
| 						<u><code>snippet</code></u> (string): Modifies the specified information. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>DELETE</dt> | ||||
| 			<dd> | ||||
| 				<p>Returns nothing</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>snippetID</code> (number): Deletes the entry for the specified snippet. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>snippetID</code> (number), <code>langID</code> (number): Removes the connection between | ||||
| 						the specified snippet and language. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 		</dl> | ||||
| 
 | ||||
| 		<h3 class="mt-5">resource.php</h3> | ||||
| 		<p>For managing the list of resources.</p> | ||||
| 		<p> | ||||
| 			The API for resource.php is nearly identical to the one for snippet.php with <code>resourceLink</code> | ||||
| 			in place of <code>snippet</code>. | ||||
| 		</p> | ||||
| 
 | ||||
| 		<div class="row border mb-4 rounded"> | ||||
| 			<form id="resourceForm" class="py-3 col-md-4"> | ||||
| 				<p class="wrapping">webdev.neilbrommer.com<wbr>/multiTable<wbr>/resource.php</p> | ||||
| 				<div class="form-group"> | ||||
| 					<select id="resourceType" class="custom-select"> | ||||
| 						<option value="GET" selected>GET</option> | ||||
| 						<option value="POST">POST</option> | ||||
| 						<option value="PUT">PUT</option> | ||||
| 						<option value="DELETE">DELETE</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="resourceResourceID">resourceID</label> | ||||
| 					<input id="resourceResourceID" type="number" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="resourceResourceName">resourceName</label> | ||||
| 					<input id="resourceResourceName" type="text" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="resourceResourceDesc">resourceDescription</label> | ||||
| 					<input id="resourceResourceDesc" type="text" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="resourceResourceLink">resourceLink</label> | ||||
| 					<input id="resourceResourceLink" type="url" class="form-control"> | ||||
| 				</div> | ||||
| 				<div class="form-group"> | ||||
| 					<label for="resourceLangID">langID</label> | ||||
| 					<input id="resourceLangID" type="number" class="form-control"> | ||||
| 				</div> | ||||
| 				<button id="resourceSubmit" type="submit" class="btn btn-primary">Submit</button> | ||||
| 			</form> | ||||
| 			<pre class="col-md-8 p-1 resultsContainer"><code id="resourceResults">Results will appear here</code></pre> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<dl> | ||||
| 			<dt>GET</dt> | ||||
| 			<dd> | ||||
| 				<p> | ||||
| 					Returns JSON encoded resources with a <code>resourceID</code>, a <code>resourceName</code>, a | ||||
| 					<code>resourceDescription</code>, a <code>resourceLink</code>, and a list of related | ||||
| 					<code>languages</code>. | ||||
| 				</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						No arguments: Returns a list of all resource entries. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>langID</code> (number): Returns a list of resources related to the specified language. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>resourceID</code> (number): Returns the specified resource entry. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>POST</dt> | ||||
| 			<dd> | ||||
| 				<p> | ||||
| 					Returns the <code>resourceID</code> of the newly created resource. | ||||
| 				</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>resourceName</code> (string), <u><code>langID</code></u> (number), | ||||
| 						<u><code>resourceDescription</code></u> (string), and <u><code>resourceLink</code></u> (string): | ||||
| 						Creates a resource with the given information. | ||||
| 
 | ||||
| 						Only one language can be associated at creation. More can be added via <code>PUT</code>. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>PUT</dt> | ||||
| 			<dd> | ||||
| 				<p>Returns nothing.</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>resourceID</code> (number), <u><code>resourceName</code></u> (string), | ||||
| 						<u><code>langID</code></u> (number), <u><code>resourceDescription</code></u> (string), and | ||||
| 						<u><code>resourceLink</code></u> (string): Modifies the specified data for the specified | ||||
| 						resource. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 
 | ||||
| 			<dt>DELETE</dt> | ||||
| 			<dd> | ||||
| 				<p>Returns nothing.</p> | ||||
| 				<ul> | ||||
| 					<li> | ||||
| 						<code>resourceID</code> (number): Deletes the specified resource. | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<code>resourceID</code> (number), <code>langID</code> (number): Removes the connection between | ||||
| 						the specified resource and language. | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</dd> | ||||
| 		</dl> | ||||
| 
 | ||||
| 	</div> | ||||
| 
 | ||||
| 
 | ||||
| 	<!-- Bootstrap core JavaScript | ||||
|     ================================================== --> | ||||
| 	<!-- Placed at the end of the document so the pages load faster --> | ||||
| 	<script src="lib/jquery/jquery-3.2.1.min.js"></script> | ||||
| 	<script src="lib/popper/popper.js"></script> | ||||
| 	<script src="lib/bootstrap/js/bootstrap.min.js"></script> | ||||
| 
 | ||||
| 	<!-- custom JavaScript --> | ||||
| 	<script src="js/docs.js"></script> | ||||
| </body> | ||||
							
								
								
									
										
											BIN
										
									
								
								favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.4 KiB | 
							
								
								
									
										362
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,362 @@ | |||
| <!doctype html> | ||||
| <html lang="en"> | ||||
| 
 | ||||
| <head> | ||||
| 	<meta charset="utf-8"> | ||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||||
| 	<meta name="description" content="A new tab page"> | ||||
| 	<meta name="author" content="Neil Brommer"> | ||||
| 	<link rel="icon" href="favicon.ico"> | ||||
| 
 | ||||
| 	<title>Multi-Table Service</title> | ||||
| 
 | ||||
| 	<!-- Bootstrap core CSS --> | ||||
| 	<link href="lib/bootstrap/css/bootstrap.min.css" rel="stylesheet"> | ||||
| 
 | ||||
| 	<!-- Custom styles --> | ||||
| 	<link href="css/multiTable.css" rel="stylesheet"> | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
| 
 | ||||
| 	<div id="wrapper" class="container"> | ||||
| 		<nav class="navbar rounded navbar-expand-md navbar-dark bg-dark mb-4"> | ||||
| 			<a class="navbar-brand" href="#">Snippets</a> | ||||
| 			<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" | ||||
| 			 aria-expanded="false" aria-label="Toggle navigation"> | ||||
| 				<span class="navbar-toggler-icon"></span> | ||||
| 			</button> | ||||
| 			<div class="collapse navbar-collapse" id="navbarCollapse"> | ||||
| 				<ul class="navbar-nav mr-auto"> | ||||
| 					<li class="nav-item"> | ||||
| 						<a id="langLink" class="nav-link active" href="#">Languages</a> | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<a id="snippetLink" class="nav-link" href="#">Snippets</a> | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<a id="resourceLink" class="nav-link" href="#">Resources</a> | ||||
| 					</li> | ||||
| 					<li> | ||||
| 						<a class="nav-link" href="documentation.html">API</a> | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 				<form class="form-inline mt-2 mt-md-0"> | ||||
| 					<button class="btn btn-primary ml-sm-2" type="button" data-toggle="modal" data-target="#addModal">Add</button> | ||||
| 				</form> | ||||
| 			</div> | ||||
| 		</nav> | ||||
| 
 | ||||
| 		<div id="successAlert" class="alert alert-success"></div> | ||||
| 
 | ||||
| 		<div id="mainList"> | ||||
| 
 | ||||
| 		</div> | ||||
| 
 | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div id="addModal" class="modal fade" tabindex="-1" role="dialog"> | ||||
| 		<div class="modal-dialog modal-lg" role="document"> | ||||
| 			<div class="modal-content"> | ||||
| 				<div class="modal-header"> | ||||
| 					<h5 class="modal-title">Add Item</h5> | ||||
| 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
| 						<span aria-hidden="true">×</span> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 				<div class="modal-body"> | ||||
| 					<ul class="nav nav-tabs" id="tabContent"> | ||||
| 						<li class="nav-item"> | ||||
| 							<a id="addLangTab" class="nav-link active" href="#addLang" data-toggle="tab">Language</a> | ||||
| 						</li> | ||||
| 						<li class="nav-item"> | ||||
| 							<a id="addSnippetTab" class="nav-link" href="#addSnippet" data-toggle="tab">Snippet</a> | ||||
| 						</li> | ||||
| 						<li class="nav-item"> | ||||
| 							<a id="addResourceTab" class="nav-link" href="#addResource" data-toggle="tab">Resource</a> | ||||
| 						</li> | ||||
| 					</ul> | ||||
| 
 | ||||
| 					<div class="tab-content"> | ||||
| 						<div id="addLang" class="addSection tab-pane fade show active"> | ||||
| 							<form id="formAddLang"> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtLangName">Name</label> | ||||
| 									<input id="txtLangName" type="text" class="form-control addField" required> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="selectLangLangs">Languages</label> | ||||
| 									<button type="button" class="btn btn-info btn-sm float-right clearLangSelect">Clear</button> | ||||
| 									<select id="selectLangLangs" class="custom-select langSelect" multiple size="9"></select> | ||||
| 									<small class="form-text text-muted">Hold Ctrl to select multiple</small> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtLangDesc">Description</label> | ||||
| 									<textarea id="txtLangDesc" class="form-control addField"></textarea> | ||||
| 								</div> | ||||
| 							</form> | ||||
| 						</div> | ||||
| 						<div id="addSnippet" class="addSection tab-pane fade"> | ||||
| 							<form id="formAddSnippet"> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtSnippetName">Name</label> | ||||
| 									<input id="txtSnippetName" type="text" class="form-control addField" required> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="selectSnippetLangs">Languages</label> | ||||
| 									<button type="button" class="btn btn-info btn-sm float-right clearLangSelect">Clear</button> | ||||
| 									<select id="selectSnippetLangs" class="custom-select langSelect" multiple size="9"></select> | ||||
| 									<small class="form-text text-muted">Hold Ctrl to select multiple</small> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtSnippetDesc">Description</label> | ||||
| 									<textarea id="txtSnippetDesc" class="form-control addField"></textarea> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtSnippetBody">Snippet</label> | ||||
| 									<textarea id="txtSnippetBody" class="form-control addField snippetBody" rows="10" wrap="off"></textarea> | ||||
| 								</div> | ||||
| 							</form> | ||||
| 						</div> | ||||
| 						<div id="addResource" class="addSection tab-pane fade"> | ||||
| 							<form id="formAddResource"> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtResourceName">Name</label> | ||||
| 									<input id="txtResourceName" type="text" class="form-control addField" required> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="selectResourceLangs">Languages</label> | ||||
| 									<button type="button" class="btn btn-info btn-sm float-right clearLangSelect">Clear</button> | ||||
| 									<select id="selectResourceLangs" class="custom-select langSelect" multiple size="9"></select> | ||||
| 									<small class="form-text text-muted">Hold Ctrl to select multiple</small> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtResourceDesc">Description</label> | ||||
| 									<textarea id="txtResourceDesc" class="form-control addField"></textarea> | ||||
| 								</div> | ||||
| 								<div class="form-group"> | ||||
| 									<label for="txtResourceLink">Link</label> | ||||
| 									<input id="txtResourceLink" type="url" class="form-control addField"> | ||||
| 								</div> | ||||
| 							</form> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<div class="modal-footer"> | ||||
| 					<button id="btnAddItem" type="button" class="btn btn-primary">Add</button> | ||||
| 					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> | ||||
| 				</div> | ||||
| 
 | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div id="editLangModal" class="modal fade" tabindex="-1" role="dialog"> | ||||
| 		<div class="modal-dialog modal-lg" role="document"> | ||||
| 			<div class="modal-content"> | ||||
| 				<div class="modal-header"> | ||||
| 					<h5 class="modal-title">Edit Language</h5> | ||||
| 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
| 						<span aria-hidden="true">×</span> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 				<div class="modal-body"> | ||||
| 					<form id="formEditLang"> | ||||
| 						<input id="editLangID" type="hidden"> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editLangNameChk" class="custom-control-input editChk" data-for="#txtEditLangName"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Name</span> | ||||
| 							</label> | ||||
| 							<input id="txtEditLangName" type="text" class="form-control editField" disabled> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editLangLangsChk" class="custom-control-input editChk" data-for="#selectEditLangLangs"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Languages</span> | ||||
| 							</label> | ||||
| 							<button type="button" class="btn btn-info btn-sm float-right clearLangSelect">Clear</button> | ||||
| 							<select id="selectEditLangLangs" class="custom-select editField langSelect" multiple size="9" disabled></select> | ||||
| 							<small class="form-text text-muted">Hold Ctrl to select multiple</small> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editLangDescChk" class="custom-control-input editChk" data-for="#txtEditLangDesc"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Description</span> | ||||
| 							</label> | ||||
| 							<textarea id="txtEditLangDesc" class="form-control editField" disabled></textarea> | ||||
| 						</div> | ||||
| 					</form> | ||||
| 				</div> | ||||
| 				<div class="modal-footer"> | ||||
| 					<button id="btnSaveLang" type="button" class="btn btn-primary">Save</button> | ||||
| 					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div id="editSnippetModal" class="modal fade" tabindex="-1" role="dialog"> | ||||
| 		<div class="modal-dialog modal-lg" role="document"> | ||||
| 			<div class="modal-content"> | ||||
| 				<div class="modal-header"> | ||||
| 					<h5 class="modal-title">Edit Snippet</h5> | ||||
| 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
| 						<span aria-hidden="true">×</span> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 				<div class="modal-body"> | ||||
| 					<form id="formEditSnippet"> | ||||
| 						<input id="editSnippetID" type="hidden"> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editSnippetNameChk" class="custom-control-input editChk" data-for="#txtEditSnippetName"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Name</span> | ||||
| 							</label> | ||||
| 							<input id="txtEditSnippetName" type="text" class="form-control editField" disabled> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editSnippetLangsChk" class="custom-control-input editChk" data-for="#selectEditSnippetLangs"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Languages</span> | ||||
| 							</label> | ||||
| 							<button type="button" class="btn btn-info btn-sm float-right clearLangSelect">Clear</button> | ||||
| 							<select id="selectEditSnippetLangs" class="custom-select editField langSelect" multiple size="9" disabled></select> | ||||
| 							<small class="form-text text-muted">Hold Ctrl to select multiple</small> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editSnippetDescChk" class="custom-control-input editChk" data-for="#txtEditSnippetDesc"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Description</span> | ||||
| 							</label> | ||||
| 							<textarea id="txtEditSnippetDesc" class="form-control editField" disabled></textarea> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editSnippetBodyChk" class="custom-control-input editChk" data-for="#txtEditSnippetBody"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Snippet</span> | ||||
| 							</label> | ||||
| 							<textarea id="txtEditSnippetBody" class="form-control snippetBody editField" rows="10" wrap="off" disabled></textarea> | ||||
| 						</div> | ||||
| 					</form> | ||||
| 				</div> | ||||
| 				<div class="modal-footer"> | ||||
| 					<button id="btnSaveSnippet" type="button" class="btn btn-primary">Save</button> | ||||
| 					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div id="editResourceModal" class="modal fade" tabindex="-1" role="dialog"> | ||||
| 		<div class="modal-dialog modal-lg" role="document"> | ||||
| 			<div class="modal-content"> | ||||
| 				<div class="modal-header"> | ||||
| 					<h5 class="modal-title">Edit Resource</h5> | ||||
| 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
| 						<span aria-hidden="true">×</span> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 				<div class="modal-body"> | ||||
| 					<form id="formEditResource"> | ||||
| 						<input id="editResourceID" type="hidden"> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editResourceNameChk" class="custom-control-input editChk" data-for="#txtEditResourceName"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Name</span> | ||||
| 							</label> | ||||
| 							<input id="txtEditResourceName" type="text" class="form-control editField" disabled> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editResourceLangsChk" class="custom-control-input editChk" data-for="#selectEditResourceLangs"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Languages</span> | ||||
| 							</label> | ||||
| 							<button type="button" class="btn btn-info btn-sm float-right clearLangSelect">Clear</button> | ||||
| 							<select id="selectEditResourceLangs" class="custom-select editField langSelect" multiple size="9" disabled></select> | ||||
| 							<small class="form-text text-muted">Hold Ctrl to select multiple</small> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editResourceDescChk" class="custom-control-input editChk" data-for="#txtEditResourceDesc"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Description</span> | ||||
| 							</label> | ||||
| 							<textarea id="txtEditResourceDesc" class="form-control editField" disabled></textarea> | ||||
| 						</div> | ||||
| 						<div class="form-group"> | ||||
| 							<label class="custom-control custom-checkbox"> | ||||
| 								<input type="checkbox" id="editResourceLinkChk" class="custom-control-input editChk" data-for="#txtEditResourceLink"> | ||||
| 								<span class="custom-control-indicator"></span> | ||||
| 								<span class="custom-control-description">Link</span> | ||||
| 							</label> | ||||
| 							<input id="txtEditResourceLink" type="url" class="form-control editField" disabled> | ||||
| 						</div> | ||||
| 					</form> | ||||
| 				</div> | ||||
| 				<div class="modal-footer"> | ||||
| 					<button id="btnSaveResource" type="button" class="btn btn-primary">Save</button> | ||||
| 					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div id="confirmDeleteModal" class="modal fade" tabindex="-1" role="dialog"> | ||||
| 		<div class="modal-dialog" role="document"> | ||||
| 			<div class="modal-content"> | ||||
| 				<div class="modal-header"> | ||||
| 					<h5 class="modal-title">Confirm Delete</h5> | ||||
| 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
| 						<span aria-hidden="true">×</span> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 				<div class="modal-body"> | ||||
| 					<p id="deleteText">Are you sure?</p> | ||||
| 				</div> | ||||
| 				<div class="modal-footer"> | ||||
| 					<button id="btnConfirmDelete" type="button" class="btn btn-danger">Delete</button> | ||||
| 					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div id="errorModal" class="modal fade" tabindex="-1" role="dialog"> | ||||
| 		<div class="modal-dialog" role="document"> | ||||
| 			<div class="modal-content"> | ||||
| 				<div class="modal-header text-white bg-danger"> | ||||
| 					<h5 class="modal-title">Error</h5> | ||||
| 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
| 						<span aria-hidden="true">×</span> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 				<div class="modal-body"> | ||||
| 					<p id="errorText">ERROR</p> | ||||
| 				</div> | ||||
| 				<div class="modal-footer"> | ||||
| 					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 
 | ||||
| 	<!-- Bootstrap core JavaScript | ||||
|     ================================================== --> | ||||
| 	<!-- Placed at the end of the document so the pages load faster --> | ||||
| 	<script src="lib/jquery/jquery-3.2.1.min.js"></script> | ||||
| 	<script src="lib/popper/popper.js"></script> | ||||
| 	<script src="lib/bootstrap/js/bootstrap.min.js"></script> | ||||
| 	<script src="js/main.js"></script> | ||||
| 
 | ||||
| </body> | ||||
							
								
								
									
										174
									
								
								js/docs.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								js/docs.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| } | ||||
							
								
								
									
										739
									
								
								js/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										739
									
								
								js/main.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -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]; | ||||
| 		$("<option>").val(cur.langID).text(cur.langName).appendTo(selectors); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function checkBoxChange() { | ||||
| 	var me = $(this); | ||||
| 	$(me.data("for")).attr("disabled", !me.prop("checked")); | ||||
| } | ||||
| 
 | ||||
| function addNewItem() { | ||||
| 	if ($("#addLangTab").hasClass("active")) { | ||||
| 		if ($("#formAddLang")[0].checkValidity()) { | ||||
| 			var data = {}; | ||||
| 			data['langName'] = $("#txtLangName").val().trim(); | ||||
| 
 | ||||
| 			if ($("#txtLangDesc").val().trim() != "") { | ||||
| 				data['langDescription'] = $("#txtLangDesc").val().trim(); | ||||
| 			} | ||||
| 
 | ||||
| 			var langs = $("#selectLangLangs").val(); | ||||
| 
 | ||||
| 			$.ajax({ | ||||
| 				url: "lang.php", | ||||
| 				type: "POST", | ||||
| 				data: data, | ||||
| 				success: function (res) { addLangLangs(res, data['langName'], langs); }, | ||||
| 				error: displayError | ||||
| 			}); | ||||
| 		} | ||||
| 	} else if ($("#addSnippetTab").hasClass("active")) { | ||||
| 		if ($("#formAddSnippet")[0].checkValidity()) { | ||||
| 			var data = {}; | ||||
| 			data['snippetName'] = $("#txtSnippetName").val().trim(); | ||||
| 			if ($("#txtSnippetDesc").val().trim() != "") { | ||||
| 				data['snippetDescription'] = $("#txtSnippetDesc").val().trim(); | ||||
| 			} | ||||
| 			if ($("#txtSnippetBody").val().trim() != "") { | ||||
| 				data['snippet'] = $("#txtSnippetBody").val().trim(); | ||||
| 			} | ||||
| 
 | ||||
| 			var langs = $("#selectSnippetLangs").val(); | ||||
| 
 | ||||
| 			$.ajax({ | ||||
| 				url: "snippet.php", | ||||
| 				type: "POST", | ||||
| 				data: data, | ||||
| 				success: function (res) { addSnippetLangs(res, data['snippetName'], langs) }, | ||||
| 				error: displayError | ||||
| 			}); | ||||
| 		} | ||||
| 	} else { | ||||
| 		if ($("#formAddResource")[0].checkValidity()) { | ||||
| 			var data = {}; | ||||
| 			data['resourceName'] = $("#txtResourceName").val().trim(); | ||||
| 			if ($("#txtResourceDesc").val().trim() != "") { | ||||
| 				data['resourceDescription'] = $("#txtResourceDesc").val().trim(); | ||||
| 			} | ||||
| 			if ($("#txtResourceLink").val().trim() != "") { | ||||
| 				data['resourceLink'] = $("#txtResourceLink").val().trim(); | ||||
| 			} | ||||
| 
 | ||||
| 			var langs = $("#selectResourceLangs").val(); | ||||
| 
 | ||||
| 			$.ajax({ | ||||
| 				url: "resource.php", | ||||
| 				type: "POST", | ||||
| 				data: data, | ||||
| 				success: function (res) { addResourceLangs(res, data['resourceName'], langs); }, | ||||
| 				error: displayError | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addLangLangs(langID, langName, langIDList) { | ||||
| 	if (langIDList != null) { | ||||
| 		for (var i = 0; i < langIDList.length; i++) { | ||||
| 			$.ajax({ | ||||
| 				url: "lang.php", | ||||
| 				type: "PUT", | ||||
| 				data: {langID: langID, associatedLang: langIDList[i]}, | ||||
| 				error: displayError | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	successAlert("Successfully Added language: " + langName, "lang"); | ||||
| } | ||||
| 
 | ||||
| function addSnippetLangs(snippetID, snippetName, langIDList) { | ||||
| 	if (langIDList != null) { | ||||
| 		for (var i = 0; i < langIDList.length; i++) { | ||||
| 			$.ajax({ | ||||
| 				url: "snippet.php", | ||||
| 				type: "PUT", | ||||
| 				data: {snippetID: snippetID, langID: langIDList[i]}, | ||||
| 				error: displayError | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	successAlert("Successfully Added snippet: " + snippetName, "snippet"); | ||||
| } | ||||
| 
 | ||||
| function addResourceLangs(resourceID, resourceName, langIDList) { | ||||
| 	if (langIDList != null) { | ||||
| 		for (var i = 0; i < langIDList.length; i++) { | ||||
| 			$.ajax({ | ||||
| 				url: "resource.php", | ||||
| 				type: "PUT", | ||||
| 				data: {resourceID: resourceID, langID: langIDList[i]}, | ||||
| 				error: displayError | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	successAlert("Successfully Added resource: " + resourceName, "resource"); | ||||
| } | ||||
| 
 | ||||
| function successAlert(text, type) { | ||||
| 	var alert = $("#successAlert"); | ||||
| 
 | ||||
| 	if (alert.attr("display") == "none") { | ||||
| 		alert.slideUp(); | ||||
| 	} | ||||
| 
 | ||||
| 	alert.text(text).slideDown().delay(5000).slideUp(); | ||||
| 
 | ||||
| 	if (type.toLowerCase() == "lang") | ||||
| 		loadLangs(); | ||||
| 	else if (type.toLowerCase() == "snippet") | ||||
| 		loadSnippets(); | ||||
| 	else if (type.toLowerCase() == "resource") | ||||
| 		loadResources(); | ||||
| 
 | ||||
| 	$(".modal").modal('hide'); | ||||
| } | ||||
| 
 | ||||
| function loadResources() { | ||||
| 	$("#langLink").removeClass("active"); | ||||
| 	$("#snippetLink").removeClass("active"); | ||||
| 	$("#resourceLink").addClass("active"); | ||||
| 	$("#mainList").empty(); | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: "resource.php", | ||||
| 		type: "GET", | ||||
| 		success: addResourceList, | ||||
| 		error: displayError | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function addResourceList(resourceList) { | ||||
| 	var mainList = $("#mainList"); | ||||
| 	for (var i = 0; i < resourceList.length; i++) { | ||||
| 		$("<div>").attr({ "id": "resource-" + resourceList[i].resourceID }).appendTo(mainList); | ||||
| 		$.ajax({ | ||||
| 			url: "resource.php?resourceID=" + resourceList[i].resourceID, | ||||
| 			type: "GET", | ||||
| 			success: addResource, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addResource(resource) { | ||||
| 	var link = $('<a>').attr({ | ||||
| 		"id": "resource-" + resource.resourceID + "-link", | ||||
| 		"href": resource.resourceLink, | ||||
| 		"target": "_blank" | ||||
| 	}).text(resource.resourceLink); | ||||
| 	buildCard("resource", resource.resourceID, resource.resourceName, resource.languages, resource.resourceDescription, link); | ||||
| } | ||||
| 
 | ||||
| function showResource(resourceID) { | ||||
| 	deselectNav(); | ||||
| 	$("#mainList").empty(); | ||||
| 
 | ||||
| 	$("<div>").attr("id", "resource-" + resourceID).appendTo($("#mainList")); | ||||
| 	$.ajax({ | ||||
| 		url: "resource.php?resourceID=" + resourceID, | ||||
| 		type: "GET", | ||||
| 		success: function (result) { addResource(result); }, | ||||
| 		error: function (result) { displayError(result); } | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function loadSnippets() { | ||||
| 	$("#langLink").removeClass("active"); | ||||
| 	$("#snippetLink").addClass("active"); | ||||
| 	$("#resourceLink").removeClass("active"); | ||||
| 	$("#mainList").empty(); | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: "snippet.php", | ||||
| 		type: "GET", | ||||
| 		success: function (result) { addSnippets(result) }, | ||||
| 		error: function (result) { displayError(result) } | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function addSnippets(snippetList) { | ||||
| 	var mainList = $("#mainList"); | ||||
| 	for (var i = 0; i < snippetList.length; i++) { | ||||
| 		// add thesse so that everything is loaded in order regardless of async
 | ||||
| 		$("<div>").attr({ "id": "snippet-" + snippetList[i].snippetID }).appendTo(mainList); | ||||
| 		$.ajax({ | ||||
| 			url: "snippet.php?snippetID=" + snippetList[i].snippetID, | ||||
| 			type: "GET", | ||||
| 			success: function (result) { addSnippet(result) }, | ||||
| 			error: function (result) { displayError(result) } | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addSnippet(snippet) { | ||||
| 	var code = $('<pre><code>').attr("id", "snippet-" + snippet.snippetID + "-body").text(snippet.snippet); | ||||
| 	buildCard("snippet", snippet.snippetID, snippet.snippetName, snippet.languages, snippet.snippetDescription, code); | ||||
| } | ||||
| 
 | ||||
| function showSnippet(snippetID) { | ||||
| 	deselectNav(); | ||||
| 	$("#mainList").empty(); | ||||
| 	$("<div>").attr("id", "snippet-" + snippetID).appendTo($("#mainList")); | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: "snippet.php?snippetID=" + snippetID, | ||||
| 		type: "GET", | ||||
| 		success: function (result) { addSnippet(result); }, | ||||
| 		error: function (result) { displayError(result); } | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function showLang(langID) { | ||||
| 	deselectNav(); | ||||
| 	$("#mainList").empty(); | ||||
| 
 | ||||
| 	$("<div>").attr("id", "lang-" + langID).appendTo($("#mainList")); | ||||
| 	$.ajax({ | ||||
| 		url: "lang.php?langID=" + langID, | ||||
| 		type: "GET", | ||||
| 		success: function (result) { addLang(result) }, | ||||
| 		error: function (result) { displayError(result) } | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function loadLangs() { | ||||
| 	$("#langLink").addClass("active"); | ||||
| 	$("#snippetLink").removeClass("active"); | ||||
| 	$("#resourceLink").removeClass("active"); | ||||
| 	$("#mainList").empty(); | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: "lang.php", | ||||
| 		type: "GET", | ||||
| 		success: function (result) { addLangs(result) }, | ||||
| 		error: function (result) { displayError(result) } | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function addLangs(langList) { | ||||
| 	var mainList = $("#mainList"); | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$("<div>").attr({ "id": "lang-" + langList[i].langID }).appendTo(mainList); | ||||
| 		$.ajax({ | ||||
| 			url: "lang.php?langID=" + langList[i].langID, | ||||
| 			type: "GET", | ||||
| 			success: function (result) { addLang(result) }, | ||||
| 			error: function (result) { displayError(result) } | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addLang(lang) { | ||||
| 	var body = $('<div>'); | ||||
| 
 | ||||
| 	// build list of snippet links
 | ||||
| 	if (lang.snippets.length != 0) { | ||||
| 		$('<hr>').appendTo(body); | ||||
| 		$('<span>').addClass("card-text text-muted mr-3").text("Snippets:").appendTo(body); | ||||
| 
 | ||||
| 		var snippets = lang.snippets; | ||||
| 		for (var i = 0; i < snippets.length; i++) { | ||||
| 			var cur = snippets[i]; | ||||
| 			var snippetID = cur.snippetID; | ||||
| 			$("<a>").attr({ | ||||
| 				"id": "snippet-" + snippetID, | ||||
| 				"class": "card-link", | ||||
| 				"href": "#", | ||||
| 				"data-snippetID": snippetID, | ||||
| 				"onClick": "handleSnippetClicked(event, " + snippetID + ")" | ||||
| 			}).text(cur.snippetName).appendTo(body); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//build list of resource links
 | ||||
| 	if (lang.resources.length != 0) { | ||||
| 		$('<hr>').appendTo(body); | ||||
| 		$('<span>').addClass("card-text text-muted mr-3").text("Resources:").appendTo(body); | ||||
| 
 | ||||
| 		var resources = lang.resources; | ||||
| 		for (var i = 0; i < resources.length; i++) { | ||||
| 			var cur = resources[i]; | ||||
| 			var resourceID = cur.resourceID; | ||||
| 			$("<a>").attr({ | ||||
| 				"id": "resource-" + resourceID, | ||||
| 				"class": "card-link", | ||||
| 				"href": "#", | ||||
| 				"data-resourceID": resourceID, | ||||
| 				"onclick": "handleResourceClicked(event, " + resourceID + ")" | ||||
| 			}).text(cur.resourceName).appendTo(body); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	buildCard("lang", lang.langID, lang.langName, lang.languages, lang.langDescription, body); | ||||
| } | ||||
| 
 | ||||
| function buildCard(type, id, name, languageList, DescriptionText, body) { | ||||
| 	var card = $('<div>').addClass("card mb-3").attr("id", type + "-" + id + "-card"); | ||||
| 	var header = $('<div>').addClass("card-header").appendTo(card); | ||||
| 	$('<h3>').attr("id", type + "-" + id + "-name").addClass("d-inline").text(name).appendTo(header); | ||||
| 	$('<span>').attr("id", type + "-" + id + "-id").addClass("text-muted ml-3").text("#" + id).appendTo(header); | ||||
| 
 | ||||
| 	$("<button>").attr({ | ||||
| 		"type": "button", | ||||
| 		"class": "btn btn-danger float-right", | ||||
| 		"data-id": id, | ||||
| 		"data-type": type | ||||
| 	}).text("Delete").click(deleteClicked).appendTo(header); | ||||
| 
 | ||||
| 	$("<button>").attr({ | ||||
| 		"type": "button", | ||||
| 		"class": "btn btn-info float-right mr-2", | ||||
| 		"data-id": id, | ||||
| 		"data-type": type | ||||
| 	}).text("Edit").click(editClicked).appendTo(header); | ||||
| 
 | ||||
| 	var cardBody = $('<div>').addClass("card-body").appendTo(card); | ||||
| 	var langList = $("<div>").addClass("langList").appendTo(cardBody); | ||||
| 
 | ||||
| 	var langString = []; | ||||
| 	if (languageList != null && languageList.length > 0) { | ||||
| 		for (var i = 0; i < languageList.length; i++) { | ||||
| 			var cur = languageList[i]; | ||||
| 			langString[i] = cur.langID; | ||||
| 			$("<a>").attr({ | ||||
| 				"class": "card-link", | ||||
| 				"href": "#", | ||||
| 				"onClick": "handleLangClicked(event, " + cur.langID + ")" | ||||
| 			}).text(cur.langName).appendTo(langList); | ||||
| 		} | ||||
| 		card.attr("data-langs", JSON.stringify(langString)); | ||||
| 	} else { | ||||
| 		card.attr("data-langs", "[]"); | ||||
| 	} | ||||
| 
 | ||||
| 	$('<p>').attr("id", type + "-" + id + "-description").addClass("card-text").text(DescriptionText).appendTo(cardBody); | ||||
| 	cardBody.append(body); | ||||
| 
 | ||||
| 	card.append(cardBody); | ||||
| 	card.appendTo($("#" + type + "-" + id)); | ||||
| } | ||||
| 
 | ||||
| function editClicked() { | ||||
| 	var button = $(this); | ||||
| 	var type = button.data("type"); | ||||
| 	var id = button.data("id"); | ||||
| 
 | ||||
| 	$(".editChk").prop("checked", false); | ||||
| 	$(".editField").prop("disabled", true); | ||||
| 
 | ||||
| 	if (type == "lang") | ||||
| 		initEditLang(id); | ||||
| 	else if (type == "snippet") | ||||
| 		initEditSnippet(id); | ||||
| 	else | ||||
| 		initEditResource(id); | ||||
| } | ||||
| 
 | ||||
| function initEditLang(langID) { | ||||
| 	$("#editLangID").val(langID); | ||||
| 	$("#txtEditLangName").val($("#lang-" + langID + "-name").text()); | ||||
| 	$("#txtEditLangDesc").val($("#lang-" + langID + "-description").text()); | ||||
| 
 | ||||
| 	buildLangSelect(); | ||||
| 	selectList = $("#lang-" + langID + "-card").data("langs"); | ||||
| 
 | ||||
| 	$("#editLangModal").modal('show'); | ||||
| } | ||||
| 
 | ||||
| function initEditSnippet(snippetID) { | ||||
| 	$("#editSnippetID").val(snippetID); | ||||
| 	$("#txtEditSnippetName").val($("#snippet-" + snippetID + "-name").text()); | ||||
| 	$("#txtEditSnippetDesc").val($("#snippet-" + snippetID + "-description").text()); | ||||
| 	$("#txtEditSnippetBody").val($("#snippet-" + snippetID + "-body").text()); | ||||
| 
 | ||||
| 	buildLangSelect(); | ||||
| 	selectList = $("#snippet-" + snippetID + "-card").data("langs"); | ||||
| 
 | ||||
| 	$("#editSnippetModal").modal('show'); | ||||
| } | ||||
| 
 | ||||
| function initEditResource(resourceID) { | ||||
| 	$("#editResourceID").val(resourceID); | ||||
| 	$("#txtEditResourceName").val($("#resource-" + resourceID + "-name").text()); | ||||
| 	$("#txtEditResourceDesc").val($("#resource-" + resourceID + "-description").text()); | ||||
| 	$("#txtEditResourceLink").val($("#resource-" + resourceID + "-link").text()); | ||||
| 
 | ||||
| 	buildLangSelect(); | ||||
| 	selectList = $("#resource-" + resourceID + "-card").data("langs"); | ||||
| 
 | ||||
| 	$("#editResourceModal").modal('show'); | ||||
| } | ||||
| 
 | ||||
| function saveLang() { | ||||
| 	var changeName = $("#editLangNameChk").prop("checked"); | ||||
| 	var changeLang = $("#editLangLangsChk").prop("checked"); | ||||
| 	var changeDesc = $("#editLangDescChk").prop("checked"); | ||||
| 
 | ||||
| 	if (!changeName && !changeDesc && !changeLang) | ||||
| 		return; | ||||
| 
 | ||||
| 	var langID = $("#editLangID").val(); | ||||
| 	var langName = $("#txtEditLangName").val().trim(); | ||||
| 	var data = {}; | ||||
| 	data['langID'] = langID; | ||||
| 
 | ||||
| 	if (changeName && langName == "") { | ||||
| 		displayError({responseText: "Name cannot be empty"}); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (changeName && langName != "") | ||||
| 		data['langName'] = langName; | ||||
| 	if (changeDesc) | ||||
| 		data['langDescription'] = $("#txtEditLangDesc").val(); | ||||
| 
 | ||||
| 	if (changeName || changeDesc) { | ||||
| 		$.ajax({ | ||||
| 			url: "lang.php", | ||||
| 			type: "PUT", | ||||
| 			data: data, | ||||
| 			success: function () { successAlert("Successfully saved language: " + langName, "lang") }, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	if (changeLang) { | ||||
| 		var curLangsList = $("#lang-" + langID + "-card").data("langs"); | ||||
| 		var newLangsList = $("#selectEditLangLangs").val().map(function (item) { | ||||
| 			return parseInt(item, 10); | ||||
| 		}); | ||||
| 
 | ||||
| 		var langsToAdd = inANotInB(newLangsList, curLangsList); | ||||
| 		var langsToDelete = inANotInB(curLangsList, newLangsList); | ||||
| 
 | ||||
| 		addLangsLang(langID, langName, langsToAdd, langsToDelete != 0); | ||||
| 		deleteLangsLang(langID, langName, langsToDelete); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addLangsLang(langID, langName, langList, forceUpdate) { | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$.ajax({ | ||||
| 			url: "lang.php", | ||||
| 			type: "PUT", | ||||
| 			data: {langID: langID, associatedLang: langList[i]}, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	if (forceUpdate || langList.length != 0) | ||||
| 		successAlert("Successfully saved language: " + langName, "lang") | ||||
| } | ||||
| 
 | ||||
| function deleteLangsLang(langID, langName, langList) { | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$.ajax({ | ||||
| 			url: "lang.php", | ||||
| 			type: "DELETE", | ||||
| 			data: {langID: langID, associatedLang: langList[i]}, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function saveSnippet() { | ||||
| 	var changeName = $("#editSnippetNameChk").prop("checked"); | ||||
| 	var changeLang = $("#editSnippetLangsChk").prop("checked"); | ||||
| 	var changeDesc = $("#editSnippetDescChk").prop("checked"); | ||||
| 	var changeBody = $("#editSnippetBodyChk").prop("checked"); | ||||
| 
 | ||||
| 	if (!changeName && !changeLang && !changeDesc && !changeBody) | ||||
| 		return; | ||||
| 
 | ||||
| 	var snippetID = $("#editSnippetID").val(); | ||||
| 	var snippetName = $("#txtEditSnippetName").val().trim(); | ||||
| 	var data = {}; | ||||
| 	data['snippetID'] = snippetID; | ||||
| 
 | ||||
| 	if (changeName && snippetName == "") { | ||||
| 		displayError({responseText: "Name cannot be empty"}); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (changeName) | ||||
| 		data['snippetName'] = snippetName; | ||||
| 	if (changeDesc) | ||||
| 		data['snippetDescription'] = $("#txtEditSnippetDesc").val().trim(); | ||||
| 	if (changeBody) | ||||
| 		data['snippet'] = $("#txtEditSnippetBody").val().trim(); | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: "snippet.php", | ||||
| 		type: "PUT", | ||||
| 		data: data, | ||||
| 		success: function () { successAlert("Successfully saved snippet: " + snippetName, "snippet"); }, | ||||
| 		error: displayError | ||||
| 	}); | ||||
| 
 | ||||
| 
 | ||||
| 	if (changeLang) { | ||||
| 		var curLangsList = $("#snippet-" + snippetID + "-card").data("langs"); | ||||
| 		var newLangsList = $("#selectEditSnippetLangs").val().map(function (item) { | ||||
| 			return parseInt(item, 10); | ||||
| 		}); | ||||
| 
 | ||||
| 		var langsToAdd = inANotInB(newLangsList, curLangsList); | ||||
| 		addLangsSnippet(snippetID, langsToAdd); | ||||
| 
 | ||||
| 		var langsToDelete = inANotInB(curLangsList, newLangsList); | ||||
| 		deleteLangsSnippet(snippetID, langsToDelete); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addLangsSnippet(snippetID, langList) { | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$.ajax({ | ||||
| 			url: "snippet.php", | ||||
| 			type: "PUT", | ||||
| 			data: {snippetID: snippetID, langID: langList[i]}, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function deleteLangsSnippet(snippetID, langList) { | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$.ajax({ | ||||
| 			url: "snippet.php", | ||||
| 			type: "DELETE", | ||||
| 			data: {snippetID: snippetID, langID: langList[i]}, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function saveResource() { | ||||
| 	var changeName = $("#editResourceNameChk").prop("checked"); | ||||
| 	var changeLang = $("#editResourceLangsChk").prop("checked"); | ||||
| 	var changeDesc = $("#editResourceDescChk").prop("checked"); | ||||
| 	var changeLink = $("#editResourceLinkChk").prop("checked"); | ||||
| 
 | ||||
| 	if (!changeName && !changeLang && !changeDesc && !changeLink) | ||||
| 		return; | ||||
| 
 | ||||
| 	var resourceID = $("#editResourceID").val(); | ||||
| 	var resourceName = $("#txtEditResourceName").val().trim(); | ||||
| 	var data = {}; | ||||
| 	data['resourceID'] = resourceID; | ||||
| 
 | ||||
| 	if (changeName && resourceName == "") { | ||||
| 		displayError({responseText: "Name cannot be empty"}); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (changeName) | ||||
| 		data['resourceName'] = resourceName; | ||||
| 	if (changeDesc) | ||||
| 		data['resourceDescription'] = $("#txtEditResourceDesc").val().trim(); | ||||
| 	if (changeLink) | ||||
| 		data['resourceLink'] = $("#txtEditResourceLink").val().trim(); | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: "resource.php", | ||||
| 		type: "PUT", | ||||
| 		data: data, | ||||
| 		success: function () { successAlert("Successfully saved resource: " + resourceName, "resource"); }, | ||||
| 		error: displayError | ||||
| 	}); | ||||
| 
 | ||||
| 	if (changeLang) { | ||||
| 		var curLangsList = $("#resource-" + resourceID + "-card").data("langs"); | ||||
| 		var newLangsList = $("#selectEditResourceLangs").val().map(function (item) { | ||||
| 			return parseInt(item, 10); | ||||
| 		}); | ||||
| 
 | ||||
| 		var langsToAdd = inANotInB(newLangsList, curLangsList); | ||||
| 		addLangsResource(resourceID, langsToAdd); | ||||
| 
 | ||||
| 		var langsToDelete = inANotInB(curLangsList, newLangsList); | ||||
| 		deleteLangsResource(resourceID, langsToDelete); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function addLangsResource(resourceID, langList) { | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$.ajax({ | ||||
| 			url: "resource.php", | ||||
| 			type: "PUT", | ||||
| 			data: {resourceID: resourceID, langID: langList[i]}, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function deleteLangsResource(resourceID, langList) { | ||||
| 	for (var i = 0; i < langList.length; i++) { | ||||
| 		$.ajax({ | ||||
| 			url: "resource.php", | ||||
| 			type: "DELETE", | ||||
| 			data: {resourceID: resourceID, langID: langList[i]}, | ||||
| 			error: displayError | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function deleteClicked() { | ||||
| 	var button = $(this); | ||||
| 	var type = button.data("type"); | ||||
| 	var id = button.data("id"); | ||||
| 
 | ||||
| 	$("#btnConfirmDelete").off('click').click(function () { deleteItem(type, id); }); | ||||
| 	$("#confirmDeleteModal").modal('show'); | ||||
| } | ||||
| 
 | ||||
| function deleteItem(type, id) { | ||||
| 	var data = {}; | ||||
| 	data[type + "ID"] = id; | ||||
| 
 | ||||
| 	$.ajax({ | ||||
| 		url: type + ".php", | ||||
| 		type: "DELETE", | ||||
| 		data: data, | ||||
| 		success: function (res) { successAlert("Item successfully deleted", type); }, | ||||
| 		error: displayError | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function handleSnippetClicked(evt, snippetID) { | ||||
| 	evt.preventDefault(); | ||||
| 	showSnippet(snippetID); | ||||
| } | ||||
| 
 | ||||
| function handleResourceClicked(evt, resourceID) { | ||||
| 	evt.preventDefault(); | ||||
| 	showResource(resourceID); | ||||
| } | ||||
| 
 | ||||
| function handleLangClicked(evt, langID) { | ||||
| 	// TODO: show related snippets and resources
 | ||||
| 	evt.preventDefault(); | ||||
| 	showLang(langID); | ||||
| } | ||||
| 
 | ||||
| function deselectNav() { | ||||
| 	$("#langLink").removeClass("active"); | ||||
| 	$("#snippetLink").removeClass("active"); | ||||
| 	$("#resourceLink").removeClass("active"); | ||||
| } | ||||
| 
 | ||||
| function displayError(error, str) { | ||||
| 	console.log(error); | ||||
| 	$("#errorText").text(error.responseText); | ||||
| 	$("#errorModal").modal('show'); | ||||
| } | ||||
| 
 | ||||
| function inANotInB(a, b) { | ||||
| 	var list = []; | ||||
| 	for (var i = 0; i < a.length; i++) { | ||||
| 		if (b.indexOf(a[i]) == -1) | ||||
| 			list.push(a[i]); | ||||
| 	} | ||||
| 	return list; | ||||
| } | ||||
							
								
								
									
										284
									
								
								lang.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								lang.php
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,284 @@ | |||
| <?php | ||||
| // table language: langID, langName, langDescription
 | ||||
| // table langLang: langID, associatedLang
 | ||||
| include_once "dbTools.php"; | ||||
| 
 | ||||
| if ($_SERVER["REQUEST_METHOD"] == 'GET') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	if (isset(($_GET['langID'])) && isset($_GET['associatedLang'])) { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("Both langID and associatedLang are specified"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (isset($_GET['langID'])) { | ||||
| 		$id = $_GET['langID']; | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM language WHERE langID=?;"); | ||||
| 		$stmt->execute([$id]); | ||||
| 		$lang = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		if (count($lang) <= 0) { | ||||
| 			http_response_code(404); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("No such language"); | ||||
| 		} | ||||
| 
 | ||||
| 		$lang = buildLangList($pdo, $lang); | ||||
| 		$lang = buildSnippetList($pdo, $lang); | ||||
| 		$lang = buildResourceList($pdo, $lang); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($lang[0]); | ||||
| 	} elseif (isset($_GET['associatedLang'])) { | ||||
| 		$assoc = $_GET['associatedLang']; | ||||
| 		if ($assoc == '') { | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("associatedLang is given, but empty"); | ||||
| 		} | ||||
| 
 | ||||
| 		$stmt = $pdo->prepare("SELECT langID, langName, langDescription FROM language NATURAL JOIN langLang Where associatedLang=?;"); | ||||
| 		$stmt->execute([$assoc]); | ||||
| 		$langList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		$langList = buildLangList($pdo, $langList); | ||||
| 		$langList = buildSnippetList($pdo, $langList); | ||||
| 		$langList = buildResourceList($pdo, $langList); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($langList); | ||||
| 	} else { | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM language ORDER BY langID;"); | ||||
| 		$stmt->execute(); | ||||
| 		$langList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		$langList = buildLangList($pdo, $langList); | ||||
| 		$langList = buildSnippetList($pdo, $langList); | ||||
| 		$langList = buildResourceList($pdo, $langList); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($langList); | ||||
| 	} | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'POST') { | ||||
| 	if (!isset($_POST['langName']) || trim($_POST['langName']) == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("A name is required"); | ||||
| 	} | ||||
| 	$name = trim($_POST['langName']); | ||||
| 
 | ||||
| 	$pdo = buildPDO(); | ||||
| 	$stmt = $pdo->prepare("SELECT * FROM language WHERE langName=?;"); | ||||
| 	$stmt->execute([$name]); | ||||
| 	if ($stmt->rowCount() > 0) { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("A language with the given name already exists"); | ||||
| 	} | ||||
| 
 | ||||
| 	$desc = ''; | ||||
| 	if (isset($_POST['langDescription'])) { | ||||
| 		$desc = trim($_POST['langDescription']); | ||||
| 	} | ||||
| 
 | ||||
| 	$assoc = null; | ||||
| 	if (isset($_POST['associatedLang'])) { | ||||
| 		$assoc = trim($_POST['associatedLang']); | ||||
| 		if ($assoc == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Associated language is given, but empty"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	$stmt = $pdo->prepare("INSERT INTO language VALUES (NULL, ?, ?);"); | ||||
| 	$stmt->execute([$name, $desc]); | ||||
| 	$newID = $pdo->lastInsertId(); | ||||
| 
 | ||||
| 	if (isset($assoc)) { | ||||
| 		$stmt = $pdo->prepare("INSERT INTO langLang VALUES (?, ?);"); | ||||
| 		$stmt->execute([$newID, $assoc]); | ||||
| 		$stmt->execute([$assoc, $newID]); // make it two way
 | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(201); | ||||
| 	header("Content-type: text/plain; charset=utf-8"); | ||||
| 	echo $newID; | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'PUT') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	// send request as url encoded form
 | ||||
| 	$_PUT = array(); | ||||
| 	parse_str(file_get_contents("php://input"), $_PUT); | ||||
| 
 | ||||
| 	if (!isset($_PUT['langID']) || trim($_PUT['langID']) === '') { | ||||
| 		http_response_code(422); | ||||
| 		die("A langID is required"); | ||||
| 	} | ||||
| 	$id = trim($_PUT['langID']); | ||||
| 
 | ||||
| 	$name = null; | ||||
| 	if (isset($_PUT['langName']) && trim($_PUT['langName']) != '') { | ||||
| 		$name = trim($_PUT['langName']); | ||||
| 	} | ||||
| 
 | ||||
| 	$pdo = buildPDO(); | ||||
| 	$stmt = $pdo->prepare("SELECT * FROM language WHERE langName=?;"); | ||||
| 	$stmt->execute([$name]); | ||||
| 	if ($stmt->rowCount() > 0) { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("A language with the given name already exists"); | ||||
| 	} | ||||
| 
 | ||||
| 	$desc = null; | ||||
| 	if (isset($_PUT['langDescription'])) { | ||||
| 		$desc = trim($_PUT['langDescription']); | ||||
| 	} | ||||
| 
 | ||||
| 	$assoc = null; | ||||
| 	if (isset($_PUT['associatedLang'])) { | ||||
| 		$assoc = trim($_PUT['associatedLang']); | ||||
| 		if ($assoc == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Associated language is given, but empty"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (isset($name) && isset($desc)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE language SET langName=?, langDescription=? WHERE langID=?;"); | ||||
| 		$stmt->execute([$name, $desc, $id]); | ||||
| 	} elseif (isset($name)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE language SET langName=? WHERE langID=?;"); | ||||
| 		$stmt->execute([$name, $id]); | ||||
| 	} elseif (isset($desc)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE language SET langDescription=? WHERE langID=?;"); | ||||
| 		$stmt->execute([$desc, $id]); | ||||
| 	} elseif (!isset($assoc)) { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("Nothing given to update"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (isset($assoc)) { | ||||
| 		$stmt = $pdo->prepare("Select * FROM langLang WHERE langID=? AND associatedLang=?;"); | ||||
| 		$stmt->execute([$id, $assoc]); | ||||
| 
 | ||||
| 		if ($stmt->rowCount() > 0) { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("The given langID-langID connection already exists"); | ||||
| 		} | ||||
| 
 | ||||
| 		$stmt = $pdo->prepare("INSERT INTO langLang VALUES (?, ?);"); | ||||
| 		$stmt->execute([$id, $assoc]); | ||||
| 		$stmt->execute([$assoc, $id]); // make it two way
 | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(200); | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'DELETE') { | ||||
| 	// send request as url encoded form
 | ||||
| 	$_DELETE = array(); | ||||
| 	parse_str(file_get_contents("php://input"), $_DELETE); | ||||
| 
 | ||||
| 	if (!isset($_DELETE['langID']) || trim($_DELETE['langID']) == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("A langID is required"); | ||||
| 	} | ||||
| 	$id = trim($_DELETE['langID']); | ||||
| 
 | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	if (isset($_DELETE['associatedLang'])) { | ||||
| 		$assoc = trim($_DELETE['associatedLang']); | ||||
| 		if ($assoc == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Associated language is given, but empty"); | ||||
| 		} | ||||
| 
 | ||||
| 		$stmt = $pdo->prepare("DELETE FROM langLang WHERE langID=? AND associatedLang=?;"); | ||||
| 		$stmt->execute([$id, $assoc]); | ||||
| 		$stmt->execute([$assoc, $id]); | ||||
| 
 | ||||
| 		if ($stmt->rowCount() == 0) { | ||||
| 			http_response_code(404); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("No such item"); | ||||
| 		} | ||||
| 	} else { | ||||
| 		$stmt = $pdo->prepare("DELETE FROM language WHERE langID=?;"); | ||||
| 		$stmt->execute([$id]); | ||||
| 
 | ||||
| 		if ($stmt->rowCount() == 0) { | ||||
| 			http_response_code(404); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("No such item"); | ||||
| 		} | ||||
| 
 | ||||
| 		$stmt = $pdo->prepare("DELETE FROM langSnippet WHERE langID=?;"); | ||||
| 		$stmt->execute([$id]); | ||||
| 		$stmt = $pdo->prepare("DELETE FROM langResource WHERE langID=?;"); | ||||
| 		$stmt->execute([$id]); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(204); | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'OPTIONS') { | ||||
| 	header("Content-type: text/plain; charset=utf-8"); | ||||
| 	echo "Allow: GET,POST,PUT,DELETE"; | ||||
| } else { | ||||
| 	http_response_code(405); | ||||
| } | ||||
| 
 | ||||
| function buildLangList($pdo, $langList) | ||||
| { | ||||
| 	for ($i = 0; $i < count($langList); $i++) { | ||||
| 		$id = $langList[$i]['langID']; | ||||
| 
 | ||||
| 		$langList[$i]['languages'] = array(); | ||||
| 		$stmt = $pdo->prepare("SELECT langID, langName FROM langLang NATURAL JOIN language WHERE associatedLang=?"); | ||||
| 		$stmt->execute([$id]); | ||||
| 		$newList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 		for ($j = 0; $j < count($newList); $j++) { | ||||
| 			$langList[$i]['languages'][$j] = $newList[$j]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $langList; | ||||
| } | ||||
| 
 | ||||
| function buildSnippetList($pdo, $langList) | ||||
| { | ||||
| 	for ($j = 0; $j < count($langList); $j++) { | ||||
| 		$id = $langList[$j]['langID']; | ||||
| 
 | ||||
| 		$langList[$j]['snippets'] = array(); | ||||
| 		$stmt = $pdo->prepare("SELECT snippetID, snippetName FROM langSnippet NATURAL JOIN snippet WHERE langID=?;"); | ||||
| 		$stmt->execute([$id]); | ||||
| 		$snippetList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 		for ($i = 0; $i < count($snippetList); $i++) { | ||||
| 			$langList[$j]['snippets'][$i] = $snippetList[$i]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $langList; | ||||
| } | ||||
| 
 | ||||
| function buildResourceList($pdo, $langList) | ||||
| { | ||||
| 	for ($j = 0; $j < count($langList); $j++) { | ||||
| 		$id = $langList[$j]['langID']; | ||||
| 
 | ||||
| 		$langList[$j]['resources'] = array(); | ||||
| 		$stmt = $pdo->prepare("SELECT resourceID, resourceName FROM langResource NATURAL JOIN resource WHERE langID=?;"); | ||||
| 		$stmt->execute([$id]); | ||||
| 		$resourceList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 		for ($i = 0; $i < count($resourceList); $i++) { | ||||
| 			$langList[$j]['resources'][$i] = $resourceList[$i]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $langList; | ||||
| } | ||||
							
								
								
									
										238
									
								
								resource.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								resource.php
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,238 @@ | |||
| <?php | ||||
| // resourceID, resourceName, resourceDescription, resourceLink
 | ||||
| // intermediary table that relates resourceIDs to langIDs
 | ||||
| // using an intermediary allows for each snippet to be related to many languages
 | ||||
| 
 | ||||
| include_once "dbTools.php"; | ||||
| 
 | ||||
| if ($_SERVER["REQUEST_METHOD"] == 'GET') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	if (isset($_GET['resourseID']) && isset($_GET['langID'])) { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("Both resourceID and langID are specified. Only one can be given"); | ||||
| 	} else if (isset($_GET['resourceID'])) { | ||||
| 		if (trim($_GET['resourceID']) == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Empty resourceID"); | ||||
| 		} | ||||
| 
 | ||||
| 		$resourceID = $_GET['resourceID']; | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM resource WHERE resourceID=?;"); | ||||
| 		$stmt->execute([$resourceID]); | ||||
| 		$resources = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		if (count($resources) <= 0) { | ||||
| 			http_response_code(404); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("No such resource"); | ||||
| 		} | ||||
| 
 | ||||
| 		$resources = buildLangList($pdo, $resources); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($resources[0]); | ||||
| 	} elseif (isset($_GET['langID'])) { | ||||
| 		if (trim($_GET['langID']) == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Empty langID"); | ||||
| 		} | ||||
| 
 | ||||
| 		$langID = $_GET['langID']; | ||||
| 		$stmt = $pdo->prepare("SELECT DISTINCT resourceID, resourceName, resourceDescription, resourceLink FROM resource NATURAL JOIN langResource WHERE langID=? ORDER BY resourceID;"); | ||||
| 		$stmt->execute([$langID]); | ||||
| 		$resources = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		$resources = buildLangList($pdo, $resources); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($resources); | ||||
| 	} else { | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM resource ORDER BY resourceID;"); | ||||
| 		$stmt->execute(); | ||||
| 		$resources = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		$resources = buildLangList($pdo, $resources); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($resources); | ||||
| 	} | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'POST') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	if (!isset($_POST['resourceName']) || trim($_POST['resourceName']) == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("A resourceName is required"); | ||||
| 	} | ||||
| 	$name = $_POST['resourceName']; | ||||
| 
 | ||||
| 	$desc = ''; | ||||
| 	if (isset($_POST['resourceDescription'])) { | ||||
| 		$desc = trim($_POST['resourceDescription']); | ||||
| 	} | ||||
| 
 | ||||
| 	$link = ''; | ||||
| 	if (isset($_POST['resourceLink'])) { | ||||
| 		$link = trim($_POST['resourceLink']); | ||||
| 	} | ||||
| 
 | ||||
| 	$langID = NULL; | ||||
| 	if (isset($_POST['langID'])) { | ||||
| 		$langID = $_POST['langID']; | ||||
| 	} | ||||
| 
 | ||||
| 	$stmt = $pdo->prepare("INSERT INTO resource (resourceID, resourceName, resourceDescription, resourceLink) VALUES (NULL, ?, ?, ?);"); | ||||
| 	$stmt->execute([$name, $desc, $link]); | ||||
| 	$resourceID = $pdo->lastInsertId(); | ||||
| 
 | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("INSERT INTO langResource (resourceID, langID) VALUES (?, ?);"); | ||||
| 		$stmt->execute([$resourceID, $langID]); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(201); | ||||
| 	header("Content-type: text/plain; charset=utf-8"); | ||||
| 	echo $resourceID; | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'PUT') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	// send request as url encoded form
 | ||||
| 	$_PUT = array(); | ||||
| 	parse_str(file_get_contents("php://input"), $_PUT); | ||||
| 
 | ||||
| 	if (!isset($_PUT['resourceID']) && trim($_PUT['resourceID']) == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("resourceID is required"); | ||||
| 	} | ||||
| 	$resourceID = trim($_PUT['resourceID']); | ||||
| 
 | ||||
| 	$name = null; | ||||
| 	if (isset($_PUT['resourceName'])) { | ||||
| 		$name = trim($_PUT['resourceName']); | ||||
| 	} | ||||
| 
 | ||||
| 	$desc = null; | ||||
| 	if (isset($_PUT['resourceDescription'])) { | ||||
| 		$desc = trim($_PUT['resourceDescription']); | ||||
| 	} | ||||
| 
 | ||||
| 	$link = null; | ||||
| 	if (isset($_PUT['resourceLink'])) { | ||||
| 		$link = trim($_PUT['resourceLink']); | ||||
| 	} | ||||
| 
 | ||||
| 	$langID = null; | ||||
| 	if (isset($_PUT['langID'])) { | ||||
| 		$langID = trim($_PUT['langID']); | ||||
| 	} | ||||
| 	if (isset($langID) && $langID == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("langID is empty"); | ||||
| 	} | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM langResource WHERE resourceID=? AND langID=?;"); | ||||
| 		$stmt->execute([$resourceID, $langID]); | ||||
| 		if ($stmt->rowCount() > 0) { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("The given resourceID-langID connection already exists"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (isset($name)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE resource SET resourceName=? WHERE resourceID=?;"); | ||||
| 		$stmt->execute([$name, $resourceID]); | ||||
| 	} | ||||
| 	if (isset($desc)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE resource SET resourceDescription=? WHERE resourceID=?;"); | ||||
| 		$stmt->execute([$desc, $resourceID]); | ||||
| 	} | ||||
| 	if (isset($link)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE resource SET resourceLink=? WHERE resourceID=?;"); | ||||
| 		$stmt->execute([$link, $resourceID]); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("INSERT INTO langResource (resourceID, langID) VALUES (?, ?);"); | ||||
| 		$stmt->execute([$resourceID, $langID]); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(204); | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'DELETE') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	// send request as url encoded form
 | ||||
| 	$_DELETE = array(); | ||||
| 	parse_str(file_get_contents("php://input"), $_DELETE); | ||||
| 
 | ||||
| 	// can delete either the snippet itself or an association with a lang
 | ||||
| 	if (!isset($_DELETE['resourceID']) || trim($_DELETE['resourceID'])== '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("snippetID is required"); | ||||
| 	} | ||||
| 	$resourceID = trim($_DELETE['resourceID']); | ||||
| 
 | ||||
| 	$langID = null; | ||||
| 	if (isset($_DELETE['langID'])) { | ||||
| 		$langID = trim($_DELETE['langID']); | ||||
| 	} | ||||
| 	if (isset($langID) && $langID == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("langId is given, but empty"); | ||||
| 	} | ||||
| 
 | ||||
| 	$rows = null; | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("DELETE FROM langResource WHERE resourceID=? AND langID=?;"); | ||||
| 		$stmt->execute([$resourceID, $langID]); | ||||
| 		$rows = $stmt->rowCount(); | ||||
| 	} else { | ||||
| 		$stmt = $pdo->prepare("DELETE FROM resource WHERE resourceID=?;"); | ||||
| 		$stmt->execute([$resourceID]); | ||||
| 		$rows = $stmt->rowCount(); | ||||
| 		if ($rows > 0) { | ||||
| 			$stmt = $pdo->prepare("DELETE FROM langResource WHERE resourceID=?;"); | ||||
| 			$stmt->execute([$resourceID]); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ($rows == 0) { | ||||
| 		http_response_code(404); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("No such item"); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(204); | ||||
| } else if ($_SERVER["REQUEST_METHOD"] == 'OPTIONS') { | ||||
| 	header("Content-type: text/plain; charset=utf-8"); | ||||
| 	echo "Allow: GET,POST,PUT,DELETE"; | ||||
| } else { | ||||
| 	http_response_code(405); | ||||
| } | ||||
| 
 | ||||
| function buildLangList($pdo, $resources) { | ||||
| 	for ($j = 0; $j < count($resources); $j++) { | ||||
| 		$resourceID = $resources[$j]['resourceID']; | ||||
| 
 | ||||
| 		$resources[$j]['languages'] = array(); | ||||
| 		$stmt = $pdo->prepare("SELECT langID, langName FROM langResource NATURAL JOIN language WHERE resourceID=? ORDER BY langID;"); | ||||
| 		$stmt->execute([$resourceID]); | ||||
| 		$langList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 		for ($i = 0; $i < count($langList); $i++) { | ||||
| 			$resources[$j]['languages'][$i] = $langList[$i]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $resources; | ||||
| } | ||||
| ?>
 | ||||
							
								
								
									
										250
									
								
								snippet.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								snippet.php
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,250 @@ | |||
| <?php | ||||
| // table snippet: snippetID, snippetName, snippetDescription, snippet
 | ||||
| // table langSnippet: intermediary table that relates snippetIDs to langIDs
 | ||||
| // using an intermediary allows for each snippet to be related to many languages
 | ||||
| 
 | ||||
| include_once "dbTools.php"; | ||||
| 
 | ||||
| if ($_SERVER["REQUEST_METHOD"] == 'GET') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	if (isset($_GET['snippetID']) && isset($_GET['langID'])) { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("Both snippetID and langID are specified. Only one can be given"); | ||||
| 	} else if (isset($_GET['snippetID'])) { | ||||
| 		if (trim($_GET['snippetID']) == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Empty snippetID"); | ||||
| 		} | ||||
| 
 | ||||
| 		$snippetID = $_GET['snippetID']; | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM snippet WHERE snippetID=? ORDER BY snippetID;"); | ||||
| 		$stmt->execute([$snippetID]); | ||||
| 		$snippets = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		if (count($snippets) <= 0) { | ||||
| 			http_response_code(404); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("No such snippet"); | ||||
| 		} | ||||
| 
 | ||||
| 		$snippets = buildLangList($pdo, $snippets); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($snippets[0]); | ||||
| 	} elseif (isset($_GET['langID'])) { | ||||
| 		if (trim($_GET['langID']) == '') { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("Empty langID"); | ||||
| 		} | ||||
| 
 | ||||
| 		$langID = $_GET['langID']; | ||||
| 		$stmt = $pdo->prepare("SELECT DISTINCT snippetID, snippetName, snippetDescription, snippet FROM snippet NATURAL JOIN langSnippet WHERE langID=? ORDER BY snippetID;"); | ||||
| 		$stmt->execute([$langID]); | ||||
| 		$snippets = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		if (count($snippets) <= 0) { | ||||
| 			http_response_code(404); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("No snippets for the given langID"); | ||||
| 		} | ||||
| 
 | ||||
| 		$snippets = buildLangList($pdo, $snippets); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($snippets); | ||||
| 	} else { | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM snippet ORDER BY snippetID;"); | ||||
| 		$stmt->execute(); | ||||
| 		$snippets = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 
 | ||||
| 		$snippets = buildLangList($pdo, $snippets); | ||||
| 
 | ||||
| 		header("Content-type: application/json; charset=utf-8"); | ||||
| 		echo json_encode($snippets); | ||||
| 	} | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'POST') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	if (!isset($_POST['snippetName']) || trim($_POST['snippetName']) == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("A snippet name is required"); | ||||
| 	} | ||||
| 	$name = trim($_POST['snippetName']); | ||||
| 
 | ||||
| 	$desc = ''; | ||||
| 	if (isset($_POST['snippetDescription'])) { | ||||
| 		$desc = trim($_POST['snippetDescription']); | ||||
| 	} | ||||
| 
 | ||||
| 	$snippet = ''; | ||||
| 	if (isset($_POST['snippet'])) { | ||||
| 		$snippet = trim($_POST['snippet']); | ||||
| 	} | ||||
| 
 | ||||
| 	$langID = NULL; | ||||
| 	if (isset($_POST['langID'])) { | ||||
| 		$langID = $_POST['langID']; | ||||
| 	} | ||||
| 
 | ||||
| 	$stmt = $pdo->prepare("INSERT INTO snippet (snippetID, snippetName, snippetDescription, snippet) VALUES (NULL, ?, ?, ?);"); | ||||
| 	$stmt->execute([$name, $desc, $snippet]); | ||||
| 	$snippetID = $pdo->lastInsertId(); | ||||
| 
 | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("INSERT INTO langSnippet (snippetID, langID) VALUES (?, ?);"); | ||||
| 		$stmt->execute([$snippetID, $langID]); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(201); | ||||
| 	header("Content-type: application/json; charset=utf-8"); | ||||
| 	echo $snippetID; | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'PUT') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	// send request as url encoded form
 | ||||
| 	$_PUT = array(); | ||||
| 	parse_str(file_get_contents("php://input"), $_PUT); | ||||
| 
 | ||||
| 	if (!isset($_PUT['snippetID']) || trim($_PUT['snippetID']) == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("snippetID is required"); | ||||
| 	} | ||||
| 	$snippetID = trim($_PUT['snippetID']); | ||||
| 
 | ||||
| 	$name = null; | ||||
| 	if (isset($_PUT['snippetName'])) { | ||||
| 		$name = trim($_PUT['snippetName']); | ||||
| 	} | ||||
| 	if (isset($name) && $name == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("snippetName cannot be empty"); | ||||
| 	} | ||||
| 
 | ||||
| 	$desc = null; | ||||
| 	if (isset($_PUT['snippetDescription'])) { | ||||
| 		$desc = trim($_PUT['snippetDescription']); | ||||
| 	} | ||||
| 
 | ||||
| 	$body = null; | ||||
| 	if (isset($_PUT['snippet'])) { | ||||
| 		$body = trim($_PUT['snippet']); | ||||
| 	} | ||||
| 
 | ||||
| 	$langID = null; | ||||
| 	if (isset($_PUT['langID'])) { | ||||
| 		$langID = trim($_PUT['langID']); | ||||
| 	} | ||||
| 	if (isset($langID) && $langID == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("langID is empty"); | ||||
| 	} | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("SELECT * FROM langSnippet WHERE snippetID=? AND langID=?;"); | ||||
| 		$stmt->execute([$snippetID, $langID]); | ||||
| 		if ($stmt->rowCount() > 0) { | ||||
| 			http_response_code(422); | ||||
| 			header("Content-type: text/plain; charset=utf-8"); | ||||
| 			die("The given snippetID-langID connection already exists"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (isset($name)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE snippet SET snippetName=? WHERE snippetID=?;"); | ||||
| 		$stmt->execute([$name, $snippetID]); | ||||
| 	} | ||||
| 	if (isset($desc)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE snippet SET snippetDescription=? WHERE snippetID=?;"); | ||||
| 		$stmt->execute([$desc, $snippetID]); | ||||
| 	} | ||||
| 	if (isset($body)) { | ||||
| 		$stmt = $pdo->prepare("UPDATE snippet SET snippet=? WHERE snippetID=?;"); | ||||
| 		$stmt->execute([$body, $snippetID]); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("INSERT INTO langSnippet (snippetID, langID) VALUES (?, ?);"); | ||||
| 		$stmt->execute([$snippetID, $langID]); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(204); | ||||
| } elseif ($_SERVER["REQUEST_METHOD"] == 'DELETE') { | ||||
| 	$pdo = buildPDO(); | ||||
| 
 | ||||
| 	// send request as url encoded form
 | ||||
| 	$_DELETE = array(); | ||||
| 	parse_str(file_get_contents("php://input"), $_DELETE); | ||||
| 
 | ||||
| 	// can delete either the snippet itself or an association with a lang
 | ||||
| 	if (!isset($_DELETE['snippetID']) || trim($_DELETE['snippetID'])== '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("snippetID is required"); | ||||
| 	} | ||||
| 	$snippetID = trim($_DELETE['snippetID']); | ||||
| 
 | ||||
| 	$langID = null; | ||||
| 	if (isset($_DELETE['langID'])) { | ||||
| 		$langID = trim($_DELETE['langID']); | ||||
| 	} | ||||
| 	if (isset($langID) && $langID == '') { | ||||
| 		http_response_code(422); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("langId is given, but empty"); | ||||
| 	} | ||||
| 
 | ||||
| 	$rows = null; | ||||
| 	if (isset($langID)) { | ||||
| 		$stmt = $pdo->prepare("DELETE FROM langSnippet WHERE snippetID=? AND langID=?;"); | ||||
| 		$stmt->execute([$snippetID, $langID]); | ||||
| 		$rows = $stmt->rowCount(); | ||||
| 	} else { | ||||
| 		$stmt = $pdo->prepare("DELETE FROM snippet WHERE snippetID=?;"); | ||||
| 		$stmt->execute([$snippetID]); | ||||
| 		$rows = $stmt->rowCount(); | ||||
| 		if ($rows > 0) { | ||||
| 			$stmt = $pdo->prepare("DELETE FROM langSnippet WHERE snippetID=?;"); | ||||
| 			$stmt->execute([$snippetID]); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ($rows == 0) { | ||||
| 		http_response_code(404); | ||||
| 		header("Content-type: text/plain; charset=utf-8"); | ||||
| 		die("No such item"); | ||||
| 	} | ||||
| 
 | ||||
| 	http_response_code(204); | ||||
| } else if ($_SERVER["REQUEST_METHOD"] == 'OPTIONS') { | ||||
| 	header("Content-type: text/plain; charset=utf-8"); | ||||
| 	echo "Allow: GET,POST,PUT,DELETE"; | ||||
| } else { | ||||
| 	http_response_code(405); | ||||
| } | ||||
| 
 | ||||
| function buildLangList($pdo, $snippets) { | ||||
| 	for ($j = 0; $j < count($snippets); $j++) { | ||||
| 		$snippetID = $snippets[$j]['snippetID']; | ||||
| 
 | ||||
| 		$snippets[$j]['languages'] = array(); | ||||
| 		$stmt = $pdo->prepare("SELECT langID, langName FROM langSnippet NATURAL JOIN language WHERE snippetID=? ORDER BY langID;"); | ||||
| 		$stmt->execute([$snippetID]); | ||||
| 		$langList = $stmt->fetchAll(PDO::FETCH_ASSOC); | ||||
| 		for ($i = 0; $i < count($langList); $i++) { | ||||
| 			$snippets[$j]['languages'][$i] = $langList[$i]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $snippets; | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										
											BIN
										
									
								
								tables.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tables.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 77 KiB | 
							
								
								
									
										1
									
								
								tables.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tables.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| <mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/7.6.6 Chrome/58.0.3029.110 Electron/1.7.5 Safari/537.36" version="7.6.6" editor="www.draw.io" type="device"><diagram id="d667a6e1-8b29-6e91-a70b-4ec352606e5d" name="Page-1">7Vzfc6soFP5r8ridCGqSx3vb3h8z3Z07tzO7dx9tpAlbIy4hTbJ//aKCiUAam6LSpHkpHhXwnO+DA5zTAbxebL7SKJv/TmKUDMAw3gzgzQAAb+gD/ieXbEtJGAjBjOJYPLQT3OP/kHxTSFc4Rsvag4yQhOGsLpySNEVTVpNFlJJ1/bFHktRbzaIZ0gT30yjRpX/hmM1l77zJ7sY3hGdz0XToi44/RNOnGSWrVLQ3APCx+JW3F5GsSzy/nEcxWe+J4O0AXlNCWFlabK5RkutWqq1878uBu1W/KUpZkxeEWZ6jZCU+PYnS2SpXT9k/tpU6WTJKnip18J5+Xs8xQ/dZNM2fWHMkcNmcLRJ+5fFilOBZystT3hdEuUDvnOjvM6IMbfZEorNfEVkgRrf8EXHXD4XiBLA8eb3eN5OQzfcsVAkjAY1ZVfdOPbwgNGTWFtS0tUxxliHmprLAsK4sOO5SWb6mLIqWZADChLfyeZlFKS/P8vKKcqUIOa91/5abih2BPhUbaIqVynsk/JP21RX+uyLyxm/LYpj9xB/wQLbZ3ZS6zpl/L/FcWaOs85A15lGWF+mcLB5Wy9yumn3yCsQI7434dYYo5t+c20K+92Mn6oUno7o5gW8wJzCZE1gwZ9iiOX9yxinsugB7VrNxL/YcGeypqHnv+1Eaf8odFn55+3MRpdtC5xFlmhRtMPsl3+Llv3l5WNTAO/hr/6K4cxVU1rsmCaFFy3BY/PidwkdBsawveSgay3WMuRv0kh0EovaHIt7fGWI1jwLFNQ9Lt1XjoZKiJGL4ue6ZmQwk2vhBcEEbSe5AAUOg2Lj8HvHWvqukVASVijy1olILWkUFXqoPbwShSUsQOgwHCa4SNsfh5TVFCNQREjiGEE/xKeHkRIQApSKgVmQPIXKh1ANEauNPCRfzCNQUIkCHSOgYRALFkw7giRAJlYp8tSKLEJHzZocQkUDw1LHi8PjSCCL+O4DIWLHs6FSIKBVBtSJ7EIGehohcn/fiMiUp0lyFGmTMnscoqONJ1MMlX3Del+L5fxBjW+FHRitGuIhQNiczkkbJHSGZaOQw2hohxzOMLrAhdBojoqlrKDtj3dcX2xDfb5o6+rxfOFvmVpEuf0xWDwm6reQLrjCce+besNEyoJf9jfqgDAxufmurcDC2xJ0rEGijpSPcMThv/XFH33yzyp0/okXjZfJZsMfze6XPxBZ9Rs7Sx+C19EcffTvWKn0OUqcUx/hZFb2t2Ru0nFKcMUzSI01zca31c+SyuvLslstQX1icxOXaqsExN9Kw09Ufl9s6ATjG5XOkDhz3SR3fEnVUL3LoEHVCnTqgN+q0edpyYcsvqB6zdEqcoa7UVxHHDW6MXOKG6eTKFjcubnmlRqp0yw5bG3vK6sqlaWXsEnXGLVLnY2nVJ4/Vff1uV1bQEo8dXllNdB77vfHYdPJug1NUBOJcmIsY9LrHCH1bs6CzW/RSn06wR3amNfZ0PRO+6LRezhQY9ru7GLTjy7rEYpnj4ASLTXEj75nFH/5sLXa91/1OGNohs8NHBXIV6gaZQctkvsPp00W5tBM1FLDbjR1rLq2r+zpviRi2T5+2gk4u8LgAwDpxKj50Q5x2dlJcmncM4Sb9EaflcJML444H1U3ITp220dlPOobwjqYB5va502aC53siziNv6M/BkTSBV2xjTCZXY7j7+T1OR9BS9LCyDnJpOjKEffRHqbbCPt7jvr5lWo1epFW3M5XfZnjP3UtnsYqVnUmk1uxosPbhGAYl5RWajNlaIrXfViZ1gwQ245GPzGEbmDLYlEHteErbobA43RpdpbBBZZ/fPzURVo190TJq7aWw+abIi5ZBcjQR33DScDYgCSYKSE7Oc1QqajHPMWgjz7HL86NX48YUVBF25GzJxi9+/WJhBtaG5E7dKflf26yuUlzmjfR3euGNbPyDN2/nTdAlb/jl7j/2ldPT7t8iwtv/AQ==</diagram></mxfile> | ||||
		Loading…
	
		Reference in a new issue