From da8f4acb29bb29d9d4060f60794fb93aa79c1627 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Tue, 30 Jan 2018 16:57:13 -0500 Subject: [PATCH] Use template literals instead of mustache templates --- app/appConf/minify_config.php | 4 +- app/views/anime/details.php | 2 + app/views/header.php | 3 +- public/js/anime_collection.js | 24 +- public/js/anime_search_results.js | 27 + public/js/lib/mustache.js | 629 ------------------ public/js/manga_collection.js | 27 +- public/js/manga_search_results.js | 27 + .../templates/anime-ajax-search-results.html | 19 - .../templates/manga-ajax-search-results.html | 19 - src/API/Kitsu/Model.php | 3 - src/Model/Anime.php | 6 +- 12 files changed, 83 insertions(+), 707 deletions(-) create mode 100644 public/js/anime_search_results.js delete mode 100644 public/js/lib/mustache.js create mode 100644 public/js/manga_search_results.js delete mode 100644 public/templates/anime-ajax-search-results.html delete mode 100644 public/templates/manga-ajax-search-results.html diff --git a/app/appConf/minify_config.php b/app/appConf/minify_config.php index 44ecd993..d06dd41c 100644 --- a/app/appConf/minify_config.php +++ b/app/appConf/minify_config.php @@ -57,11 +57,11 @@ return [ 'manga_edit.js', ], 'anime_collection' => [ - 'lib/mustache.js', + 'anime_search_results.js', 'anime_collection.js', ], 'manga_collection' => [ - 'lib/mustache.js', + 'manga_search_results.js', 'manga_collection.js', ], ] diff --git a/app/views/anime/details.php b/app/views/anime/details.php index 973c377b..9e0ed3e3 100644 --- a/app/views/anime/details.php +++ b/app/views/anime/details.php @@ -17,10 +17,12 @@ Episode Count + Episode Length minutes + Age Rating diff --git a/app/views/header.php b/app/views/header.php index 04151e4a..5a95e909 100644 --- a/app/views/header.php +++ b/app/views/header.php @@ -31,7 +31,8 @@ { foreach($message as $m) { - extract($m); + $message = $m['message']; + $message_type = $m['message_type']; include 'message.php'; } } diff --git a/public/js/anime_collection.js b/public/js/anime_collection.js index a550f734..f3c115d5 100644 --- a/public/js/anime_collection.js +++ b/public/js/anime_collection.js @@ -2,31 +2,29 @@ 'use strict'; - const search = (tempHtml, query) => { + const search = (query) => { + // Show the loader _.$('.cssload-loader')[0].removeAttribute('hidden'); + + // Do the api search _.get(_.url('/anime-collection/search'), {query}, (searchResults, status) => { searchResults = JSON.parse(searchResults); + + // Hide the loader _.$('.cssload-loader')[0].setAttribute('hidden', 'hidden'); - // Give mustache a key to iterate over - searchResults = { - data: searchResults.data - }; - - Mustache.parse(tempHtml); - _.$('#series_list')[0].innerHTML = Mustache.render(tempHtml, searchResults); + // Show the results + _.$('#series_list')[0].innerHTML = render_anime_search_results(searchResults.data); }); }; - _.get('/public/templates/anime-ajax-search-results.html', (tempHtml) => { - _.on('#search', 'keyup', _.throttle(250, function(e) { - let query = encodeURIComponent(this.value); + _.on('#search', 'keyup', _.throttle(250, function() { + const query = encodeURIComponent(this.value); if (query === '') { return; } - search(tempHtml, query); + search(query); })); - }); })(AnimeClient); \ No newline at end of file diff --git a/public/js/anime_search_results.js b/public/js/anime_search_results.js new file mode 100644 index 00000000..49c8d1e5 --- /dev/null +++ b/public/js/anime_search_results.js @@ -0,0 +1,27 @@ +function render_anime_search_results (data) { + const results = []; + + data.forEach(x => { + const item = x.attributes; + const titles = item.titles.reduce((prev, current) => { + return prev + `${current}
`; + }, []); + + results.push(` + + `); + }); + + return results.join(''); +} \ No newline at end of file diff --git a/public/js/lib/mustache.js b/public/js/lib/mustache.js deleted file mode 100644 index 53ec2723..00000000 --- a/public/js/lib/mustache.js +++ /dev/null @@ -1,629 +0,0 @@ -/*! - * mustache.js - Logic-less {{mustache}} templates with JavaScript - * http://github.com/janl/mustache.js - */ - -/*global define: false Mustache: true*/ - -(function defineMustache (global, factory) { - if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') { - factory(exports); // CommonJS - } else if (typeof define === 'function' && define.amd) { - define(['exports'], factory); // AMD - } else { - global.Mustache = {}; - factory(global.Mustache); // script, wsh, asp - } -}(this, function mustacheFactory (mustache) { - - var objectToString = Object.prototype.toString; - var isArray = Array.isArray || function isArrayPolyfill (object) { - return objectToString.call(object) === '[object Array]'; - }; - - function isFunction (object) { - return typeof object === 'function'; - } - - /** - * More correct typeof string handling array - * which normally returns typeof 'object' - */ - function typeStr (obj) { - return isArray(obj) ? 'array' : typeof obj; - } - - function escapeRegExp (string) { - return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); - } - - /** - * Null safe way of checking whether or not an object, - * including its prototype, has a given property - */ - function hasProperty (obj, propName) { - return obj != null && typeof obj === 'object' && (propName in obj); - } - - // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 - // See https://github.com/janl/mustache.js/issues/189 - var regExpTest = RegExp.prototype.test; - function testRegExp (re, string) { - return regExpTest.call(re, string); - } - - var nonSpaceRe = /\S/; - function isWhitespace (string) { - return !testRegExp(nonSpaceRe, string); - } - - var entityMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/', - '`': '`', - '=': '=' - }; - - function escapeHtml (string) { - return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) { - return entityMap[s]; - }); - } - - var whiteRe = /\s*/; - var spaceRe = /\s+/; - var equalsRe = /\s*=/; - var curlyRe = /\s*\}/; - var tagRe = /#|\^|\/|>|\{|&|=|!/; - - /** - * Breaks up the given `template` string into a tree of tokens. If the `tags` - * argument is given here it must be an array with two string values: the - * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of - * course, the default is to use mustaches (i.e. mustache.tags). - * - * A token is an array with at least 4 elements. The first element is the - * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag - * did not contain a symbol (i.e. {{myValue}}) this element is "name". For - * all text that appears outside a symbol this element is "text". - * - * The second element of a token is its "value". For mustache tags this is - * whatever else was inside the tag besides the opening symbol. For text tokens - * this is the text itself. - * - * The third and fourth elements of the token are the start and end indices, - * respectively, of the token in the original template. - * - * Tokens that are the root node of a subtree contain two more elements: 1) an - * array of tokens in the subtree and 2) the index in the original template at - * which the closing tag for that section begins. - */ - function parseTemplate (template, tags) { - if (!template) - return []; - - var sections = []; // Stack to hold section tokens - var tokens = []; // Buffer to hold the tokens - var spaces = []; // Indices of whitespace tokens on the current line - var hasTag = false; // Is there a {{tag}} on the current line? - var nonSpace = false; // Is there a non-space char on the current line? - - // Strips all whitespace tokens array for the current line - // if there was a {{#tag}} on it and otherwise only space. - function stripSpace () { - if (hasTag && !nonSpace) { - while (spaces.length) - delete tokens[spaces.pop()]; - } else { - spaces = []; - } - - hasTag = false; - nonSpace = false; - } - - var openingTagRe, closingTagRe, closingCurlyRe; - function compileTags (tagsToCompile) { - if (typeof tagsToCompile === 'string') - tagsToCompile = tagsToCompile.split(spaceRe, 2); - - if (!isArray(tagsToCompile) || tagsToCompile.length !== 2) - throw new Error('Invalid tags: ' + tagsToCompile); - - openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*'); - closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1])); - closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1])); - } - - compileTags(tags || mustache.tags); - - var scanner = new Scanner(template); - - var start, type, value, chr, token, openSection; - while (!scanner.eos()) { - start = scanner.pos; - - // Match any text between tags. - value = scanner.scanUntil(openingTagRe); - - if (value) { - for (var i = 0, valueLength = value.length; i < valueLength; ++i) { - chr = value.charAt(i); - - if (isWhitespace(chr)) { - spaces.push(tokens.length); - } else { - nonSpace = true; - } - - tokens.push([ 'text', chr, start, start + 1 ]); - start += 1; - - // Check for whitespace on the current line. - if (chr === '\n') - stripSpace(); - } - } - - // Match the opening tag. - if (!scanner.scan(openingTagRe)) - break; - - hasTag = true; - - // Get the tag type. - type = scanner.scan(tagRe) || 'name'; - scanner.scan(whiteRe); - - // Get the tag value. - if (type === '=') { - value = scanner.scanUntil(equalsRe); - scanner.scan(equalsRe); - scanner.scanUntil(closingTagRe); - } else if (type === '{') { - value = scanner.scanUntil(closingCurlyRe); - scanner.scan(curlyRe); - scanner.scanUntil(closingTagRe); - type = '&'; - } else { - value = scanner.scanUntil(closingTagRe); - } - - // Match the closing tag. - if (!scanner.scan(closingTagRe)) - throw new Error('Unclosed tag at ' + scanner.pos); - - token = [ type, value, start, scanner.pos ]; - tokens.push(token); - - if (type === '#' || type === '^') { - sections.push(token); - } else if (type === '/') { - // Check section nesting. - openSection = sections.pop(); - - if (!openSection) - throw new Error('Unopened section "' + value + '" at ' + start); - - if (openSection[1] !== value) - throw new Error('Unclosed section "' + openSection[1] + '" at ' + start); - } else if (type === 'name' || type === '{' || type === '&') { - nonSpace = true; - } else if (type === '=') { - // Set the tags for the next time around. - compileTags(value); - } - } - - // Make sure there are no open sections when we're done. - openSection = sections.pop(); - - if (openSection) - throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos); - - return nestTokens(squashTokens(tokens)); - } - - /** - * Combines the values of consecutive text tokens in the given `tokens` array - * to a single token. - */ - function squashTokens (tokens) { - var squashedTokens = []; - - var token, lastToken; - for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { - token = tokens[i]; - - if (token) { - if (token[0] === 'text' && lastToken && lastToken[0] === 'text') { - lastToken[1] += token[1]; - lastToken[3] = token[3]; - } else { - squashedTokens.push(token); - lastToken = token; - } - } - } - - return squashedTokens; - } - - /** - * Forms the given array of `tokens` into a nested tree structure where - * tokens that represent a section have two additional items: 1) an array of - * all tokens that appear in that section and 2) the index in the original - * template that represents the end of that section. - */ - function nestTokens (tokens) { - var nestedTokens = []; - var collector = nestedTokens; - var sections = []; - - var token, section; - for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { - token = tokens[i]; - - switch (token[0]) { - case '#': - case '^': - collector.push(token); - sections.push(token); - collector = token[4] = []; - break; - case '/': - section = sections.pop(); - section[5] = token[2]; - collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens; - break; - default: - collector.push(token); - } - } - - return nestedTokens; - } - - /** - * A simple string scanner that is used by the template parser to find - * tokens in template strings. - */ - function Scanner (string) { - this.string = string; - this.tail = string; - this.pos = 0; - } - - /** - * Returns `true` if the tail is empty (end of string). - */ - Scanner.prototype.eos = function eos () { - return this.tail === ''; - }; - - /** - * Tries to match the given regular expression at the current position. - * Returns the matched text if it can match, the empty string otherwise. - */ - Scanner.prototype.scan = function scan (re) { - var match = this.tail.match(re); - - if (!match || match.index !== 0) - return ''; - - var string = match[0]; - - this.tail = this.tail.substring(string.length); - this.pos += string.length; - - return string; - }; - - /** - * Skips all text until the given regular expression can be matched. Returns - * the skipped string, which is the entire tail if no match can be made. - */ - Scanner.prototype.scanUntil = function scanUntil (re) { - var index = this.tail.search(re), match; - - switch (index) { - case -1: - match = this.tail; - this.tail = ''; - break; - case 0: - match = ''; - break; - default: - match = this.tail.substring(0, index); - this.tail = this.tail.substring(index); - } - - this.pos += match.length; - - return match; - }; - - /** - * Represents a rendering context by wrapping a view object and - * maintaining a reference to the parent context. - */ - function Context (view, parentContext) { - this.view = view; - this.cache = { '.': this.view }; - this.parent = parentContext; - } - - /** - * Creates a new context using the given view with this context - * as the parent. - */ - Context.prototype.push = function push (view) { - return new Context(view, this); - }; - - /** - * Returns the value of the given name in this context, traversing - * up the context hierarchy if the value is absent in this context's view. - */ - Context.prototype.lookup = function lookup (name) { - var cache = this.cache; - - var value; - if (cache.hasOwnProperty(name)) { - value = cache[name]; - } else { - var context = this, names, index, lookupHit = false; - - while (context) { - if (name.indexOf('.') > 0) { - value = context.view; - names = name.split('.'); - index = 0; - - /** - * Using the dot notion path in `name`, we descend through the - * nested objects. - * - * To be certain that the lookup has been successful, we have to - * check if the last object in the path actually has the property - * we are looking for. We store the result in `lookupHit`. - * - * This is specially necessary for when the value has been set to - * `undefined` and we want to avoid looking up parent contexts. - **/ - while (value != null && index < names.length) { - if (index === names.length - 1) - lookupHit = hasProperty(value, names[index]); - - value = value[names[index++]]; - } - } else { - value = context.view[name]; - lookupHit = hasProperty(context.view, name); - } - - if (lookupHit) - break; - - context = context.parent; - } - - cache[name] = value; - } - - if (isFunction(value)) - value = value.call(this.view); - - return value; - }; - - /** - * A Writer knows how to take a stream of tokens and render them to a - * string, given a context. It also maintains a cache of templates to - * avoid the need to parse the same template twice. - */ - function Writer () { - this.cache = {}; - } - - /** - * Clears all cached templates in this writer. - */ - Writer.prototype.clearCache = function clearCache () { - this.cache = {}; - }; - - /** - * Parses and caches the given `template` and returns the array of tokens - * that is generated from the parse. - */ - Writer.prototype.parse = function parse (template, tags) { - var cache = this.cache; - var tokens = cache[template]; - - if (tokens == null) - tokens = cache[template] = parseTemplate(template, tags); - - return tokens; - }; - - /** - * High-level method that is used to render the given `template` with - * the given `view`. - * - * The optional `partials` argument may be an object that contains the - * names and templates of partials that are used in the template. It may - * also be a function that is used to load partial templates on the fly - * that takes a single argument: the name of the partial. - */ - Writer.prototype.render = function render (template, view, partials) { - var tokens = this.parse(template); - var context = (view instanceof Context) ? view : new Context(view); - return this.renderTokens(tokens, context, partials, template); - }; - - /** - * Low-level method that renders the given array of `tokens` using - * the given `context` and `partials`. - * - * Note: The `originalTemplate` is only ever used to extract the portion - * of the original template that was contained in a higher-order section. - * If the template doesn't use higher-order sections, this argument may - * be omitted. - */ - Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate) { - var buffer = ''; - - var token, symbol, value; - for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { - value = undefined; - token = tokens[i]; - symbol = token[0]; - - if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate); - else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate); - else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate); - else if (symbol === '&') value = this.unescapedValue(token, context); - else if (symbol === 'name') value = this.escapedValue(token, context); - else if (symbol === 'text') value = this.rawValue(token); - - if (value !== undefined) - buffer += value; - } - - return buffer; - }; - - Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) { - var self = this; - var buffer = ''; - var value = context.lookup(token[1]); - - // This function is used to render an arbitrary template - // in the current context by higher-order sections. - function subRender (template) { - return self.render(template, context, partials); - } - - if (!value) return; - - if (isArray(value)) { - for (var j = 0, valueLength = value.length; j < valueLength; ++j) { - buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate); - } - } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') { - buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate); - } else if (isFunction(value)) { - if (typeof originalTemplate !== 'string') - throw new Error('Cannot use higher-order sections without the original template'); - - // Extract the portion of the original template that the section contains. - value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); - - if (value != null) - buffer += value; - } else { - buffer += this.renderTokens(token[4], context, partials, originalTemplate); - } - return buffer; - }; - - Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) { - var value = context.lookup(token[1]); - - // Use JavaScript's definition of falsy. Include empty arrays. - // See https://github.com/janl/mustache.js/issues/186 - if (!value || (isArray(value) && value.length === 0)) - return this.renderTokens(token[4], context, partials, originalTemplate); - }; - - Writer.prototype.renderPartial = function renderPartial (token, context, partials) { - if (!partials) return; - - var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; - if (value != null) - return this.renderTokens(this.parse(value), context, partials, value); - }; - - Writer.prototype.unescapedValue = function unescapedValue (token, context) { - var value = context.lookup(token[1]); - if (value != null) - return value; - }; - - Writer.prototype.escapedValue = function escapedValue (token, context) { - var value = context.lookup(token[1]); - if (value != null) - return mustache.escape(value); - }; - - Writer.prototype.rawValue = function rawValue (token) { - return token[1]; - }; - - mustache.name = 'mustache.js'; - mustache.version = '2.2.1'; - mustache.tags = [ '{{', '}}' ]; - - // All high-level mustache.* functions use this writer. - var defaultWriter = new Writer(); - - /** - * Clears all cached templates in the default writer. - */ - mustache.clearCache = function clearCache () { - return defaultWriter.clearCache(); - }; - - /** - * Parses and caches the given template in the default writer and returns the - * array of tokens it contains. Doing this ahead of time avoids the need to - * parse templates on the fly as they are rendered. - */ - mustache.parse = function parse (template, tags) { - return defaultWriter.parse(template, tags); - }; - - /** - * Renders the `template` with the given `view` and `partials` using the - * default writer. - */ - mustache.render = function render (template, view, partials) { - if (typeof template !== 'string') { - throw new TypeError('Invalid template! Template should be a "string" ' + - 'but "' + typeStr(template) + '" was given as the first ' + - 'argument for mustache#render(template, view, partials)'); - } - - return defaultWriter.render(template, view, partials); - }; - - // This is here for backwards compatibility with 0.4.x., - /*eslint-disable */ // eslint wants camel cased function name - mustache.to_html = function to_html (template, view, partials, send) { - /*eslint-enable*/ - - var result = mustache.render(template, view, partials); - - if (isFunction(send)) { - send(result); - } else { - return result; - } - }; - - // Export the escaping function so that the user may override it. - // See https://github.com/janl/mustache.js/issues/244 - mustache.escape = escapeHtml; - - // Export these mainly for testing, but also for advanced usage. - mustache.Scanner = Scanner; - mustache.Context = Context; - mustache.Writer = Writer; - -})); diff --git a/public/js/manga_collection.js b/public/js/manga_collection.js index 6d1c0c31..2c969145 100644 --- a/public/js/manga_collection.js +++ b/public/js/manga_collection.js @@ -2,31 +2,22 @@ 'use strict'; - const search = (tempHtml, query) => { + const search = (query) => { _.$('.cssload-loader')[0].removeAttribute('hidden'); _.get(_.url('/manga/search'), {query}, (searchResults, status) => { searchResults = JSON.parse(searchResults); _.$('.cssload-loader')[0].setAttribute('hidden', 'hidden'); - - // Give mustache a key to iterate over - searchResults = { - data: searchResults.data - }; - - Mustache.parse(tempHtml); - _.$('#series_list')[0].innerHTML = Mustache.render(tempHtml, searchResults); + _.$('#series_list')[0].innerHTML = render_manga_search_results(searchResults.data); }); }; - _.get('/public/templates/manga-ajax-search-results.html', (tempHtml) => { - _.on('#search', 'keyup', _.throttle(250, function(e) { - let query = encodeURIComponent(this.value); - if (query === '') { - return; - } + _.on('#search', 'keyup', _.throttle(250, function(e) { + let query = encodeURIComponent(this.value); + if (query === '') { + return; + } - search(tempHtml, query); - })); - }); + search(query); + })); })(AnimeClient); \ No newline at end of file diff --git a/public/js/manga_search_results.js b/public/js/manga_search_results.js new file mode 100644 index 00000000..6e394938 --- /dev/null +++ b/public/js/manga_search_results.js @@ -0,0 +1,27 @@ +function render_manga_search_results (data) { + const results = []; + + data.forEach(x => { + const item = x.attributes; + const titles = item.titles.reduce((prev, current) => { + return prev + `${current}
`; + }, []); + + results.push(` + + `); + }); + + return results.join(''); +} diff --git a/public/templates/anime-ajax-search-results.html b/public/templates/anime-ajax-search-results.html deleted file mode 100644 index 3e9f5682..00000000 --- a/public/templates/anime-ajax-search-results.html +++ /dev/null @@ -1,19 +0,0 @@ -{{#data}} - -{{/data}} \ No newline at end of file diff --git a/public/templates/manga-ajax-search-results.html b/public/templates/manga-ajax-search-results.html deleted file mode 100644 index 346772c7..00000000 --- a/public/templates/manga-ajax-search-results.html +++ /dev/null @@ -1,19 +0,0 @@ -{{#data}} - -{{/data}} \ No newline at end of file diff --git a/src/API/Kitsu/Model.php b/src/API/Kitsu/Model.php index 3f43a782..b40b5d8f 100644 --- a/src/API/Kitsu/Model.php +++ b/src/API/Kitsu/Model.php @@ -117,8 +117,6 @@ class Model { ]); $data = Json::decode(wait($response->getBody())); - //dump($response); - if (array_key_exists('access_token', $data)) { return $data; @@ -129,7 +127,6 @@ class Model { dump($data['error']); dump($response); die(); - //throw new \Exception('auth error'); } return FALSE; diff --git a/src/Model/Anime.php b/src/Model/Anime.php index e56522c5..3669002b 100644 --- a/src/Model/Anime.php +++ b/src/Model/Anime.php @@ -149,7 +149,7 @@ class Anime extends API { $malData = $data; $malId = $this->kitsuModel->getMalIdForAnime($malData['id']); - if ( ! is_null($malId)) + if ($malId !== NULL) { $malData['id'] = $malId; $requester->addRequest($this->malModel->createListItem($malData), 'mal'); @@ -182,7 +182,7 @@ class Anime extends API { $results = $requester->makeRequests(); $body = Json::decode($results['kitsu']); - $statusCode = (array_key_exists('error', $body)) ? 400: 200; + $statusCode = array_key_exists('error', $body) ? 400: 200; return [ 'body' => Json::decode($results['kitsu']), @@ -201,7 +201,7 @@ class Anime extends API { { $requester = new ParallelAPIRequest(); - if ($this->useMALAPI && ! is_null($malId)) + if ($this->useMALAPI && $malId !== NULL) { $requester->addRequest($this->malModel->deleteListItem($malId), 'MAL'); }