diff options
author | Thedro Neely <thedroneely@gmail.com> | 2018-08-30 04:40:53 -0400 |
---|---|---|
committer | Thedro Neely <thedroneely@gmail.com> | 2018-08-30 04:40:53 -0400 |
commit | 2659205908bd5cab508f4ff817123673e078ab74 (patch) | |
tree | e455f36b124e9b98f7005e6d4310b71881734623 /bootstrap/comments/api | |
download | edwinmattiacci.com-2659205908bd5cab508f4ff817123673e078ab74.tar.gz edwinmattiacci.com-2659205908bd5cab508f4ff817123673e078ab74.tar.bz2 edwinmattiacci.com-2659205908bd5cab508f4ff817123673e078ab74.zip |
Initialize Repo: First Commit
Diffstat (limited to 'bootstrap/comments/api')
-rw-r--r-- | bootstrap/comments/api/backend/count-link-ajax.php | 76 | ||||
-rw-r--r-- | bootstrap/comments/api/backend/latest-ajax.php | 207 | ||||
-rw-r--r-- | bootstrap/comments/api/count-link.php | 95 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/count-link/constructor.js | 43 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/count-link/getcommentcount.js | 19 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/count-link/instantiate.js | 4 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/latest/addcontrols.js | 22 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/latest/addratings.js | 22 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/latest/constructor.js | 79 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/latest/init.js | 37 | ||||
-rw-r--r-- | bootstrap/comments/api/frontends/latest/instantiate.js | 4 | ||||
-rw-r--r-- | bootstrap/comments/api/json.php | 76 | ||||
-rw-r--r-- | bootstrap/comments/api/latest.php | 154 | ||||
-rw-r--r-- | bootstrap/comments/api/rss.php | 327 |
14 files changed, 1165 insertions, 0 deletions
diff --git a/bootstrap/comments/api/backend/count-link-ajax.php b/bootstrap/comments/api/backend/count-link-ajax.php new file mode 100644 index 0000000..bf53312 --- /dev/null +++ b/bootstrap/comments/api/backend/count-link-ajax.php @@ -0,0 +1,76 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Change to the HashOver directory +chdir (realpath ('../../')); + +// Check if request is for JSONP +if (isset ($_GET['jsonp'])) { + // If so, setup HashOver for JavaScript + require ('backend/javascript-setup.php'); +} else { + // If not, setup HashOver for JSON + require ('backend/json-setup.php'); +} + +try { + // Instantiate HashOver class + $hashover = new \HashOver ('json', 'api'); + $hashover->setup->setPageURL ('request'); + $hashover->initiate (); + $hashover->finalize (); + + // Throw exception if the "Latest Comments" API is disabled + if ($hashover->setup->apiStatus ('count-link') === 'disabled') { + throw new \Exception ('This API is not enabled.'); + } + + // Count response array + $data = array ( + 'primary-count' => $hashover->thread->primaryCount - 1, + 'total-count' => $hashover->thread->totalCount - 1 + ); + + // Check if there are any comments + if ($hashover->thread->totalCount > 1) { + // If so, set the count link text to the comment count + $data['link-text'] = $hashover->getCommentCount (); + } else { + // If not, set the count link text to "Post Comment" + $data['link-text'] = $hashover->locale->text['post-button']; + } + + // Generate statistics + $hashover->statistics->executionEnd (); + + // HashOver statistics + $data['statistics'] = array ( + 'execution-time' => $hashover->statistics->executionTime, + 'script-memory' => $hashover->statistics->scriptMemory, + 'system-memory' => $hashover->statistics->systemMemory + ); + + // Encode JSON data + echo $hashover->misc->jsonData ($data); + +} catch (\Exception $error) { + $misc = new Misc ('json'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/api/backend/latest-ajax.php b/bootstrap/comments/api/backend/latest-ajax.php new file mode 100644 index 0000000..964fe34 --- /dev/null +++ b/bootstrap/comments/api/backend/latest-ajax.php @@ -0,0 +1,207 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Change to the HashOver directory +chdir (realpath ('../../')); + +// Check if request is for JSONP +if (isset ($_GET['jsonp'])) { + // If so, setup HashOver for JavaScript + require ('backend/javascript-setup.php'); +} else { + // If not, setup HashOver for JSON + require ('backend/json-setup.php'); +} + +try { + // Instantiate HashOver class + $hashover = new \HashOver ('json', 'api'); + $hashover->setup->setThreadName ('request'); + $hashover->initiate (); + $hashover->finalize (); + + // Throw exception if the "Latest Comments" API is disabled + if ($hashover->setup->apiStatus ('latest') === 'disabled') { + throw new \Exception ('This API is not enabled.'); + } + + // Comments and statistics response array + $data = array (); + + // Add locales to data + $data['locale'] = array ( + 'date-time' => $hashover->locale->text['date-time'], + 'dislike' => $hashover->locale->text['dislike'], + 'external-image-tip' => $hashover->locale->text['external-image-tip'], + 'like' => $hashover->locale->text['like'], + 'today' => $hashover->locale->text['date-today'], + 'commenter-tip' => $hashover->locale->text['commenter-tip'], + 'subscribed-tip' => $hashover->locale->text['subscribed-tip'], + 'unsubscribed-tip' => $hashover->locale->text['unsubscribed-tip'], + 'replies' => $hashover->locale->text['replies'], + 'reply' => $hashover->locale->text['reply'], + 'loading' => $hashover->locale->text['loading'], + 'click-to-close' => $hashover->locale->text['click-to-close'], + 'day-names' => $hashover->locale->text['date-day-names'], + 'month-names' => $hashover->locale->text['date-month-names'] + ); + + // Add setup information to data + $data['setup'] = array ( + 'server-eol' => PHP_EOL, + 'default-name' => $hashover->setup->defaultName, + 'user-is-logged-in' => $hashover->login->userIsLoggedIn, + 'time-format' => $hashover->setup->timeFormat, + 'image-extensions' => $hashover->setup->imageTypes, + 'image-placeholder' => $hashover->setup->getImagePath ('place-holder'), + 'theme-css' => $hashover->setup->getThemePath ('latest.css'), + 'device-type' => ($hashover->setup->isMobile === true) ? 'mobile' : 'desktop', + 'uses-user-timezone' => $hashover->setup->usesUserTimezone, + 'uses-short-dates' => $hashover->setup->usesShortDates, + 'allows-images' => $hashover->setup->allowsImages, + 'uses-markdown' => $hashover->setup->usesMarkdown + ); + + // Add UI HTML to data + $data['ui'] = array ( + 'user-avatar' => $hashover->ui->userAvatar (), + 'name-link' => $hashover->ui->nameElement ('a'), + 'name-span' => $hashover->ui->nameElement ('span'), + 'thread-link' => $hashover->ui->threadLink (), + 'reply-link' => $hashover->ui->formLink ('{{href}}', 'reply'), + 'like-count' => $hashover->ui->likeCount ('likes'), + 'dislike-count' => $hashover->ui->likeCount ('dislikes'), + 'name-wrapper' => $hashover->ui->nameWrapper (), + 'date-link' => $hashover->ui->dateLink (), + 'comment-wrapper' => $hashover->ui->commentWrapper (), + 'theme' => $hashover->templater->parseTheme ('latest.html') + ); + + // Attempt to get comment thread from GET/POST data + $get_thread = $hashover->setup->getRequest ('thread', 'auto'); + + // Check if we're getting metadata for a specific thread + if ($get_thread !== 'auto') { + // If so, attempt to read thread-specific latest comments metadata + $latest = $hashover->thread->data->readMeta ('latest-comments', $get_thread); + } else { + // If not, attempt to read global latest comments metadata + $latest = $hashover->thread->data->readMeta ('latest-comments', 'auto', true); + } + + // Check if the latest comments read successfully + if ($latest !== false) { + // If so, reduce number of latest comments to configured limit + $latest = array_slice ($latest, 0, $hashover->setup->latestMax); + } else { + // If not, set to empty array + $latest = array (); + } + + // Latest comments + $comments = array (); + + // Run through the latest comments + foreach ($latest as $item) { + // Get comment key + $key = basename ($item); + $key_parts = explode ('-', $key); + + // Decide proper thread + $thread = ($get_thread === 'auto') ? dirname ($item) : $get_thread; + + // Attempt to read page information metadata + $page_info = $hashover->thread->data->readMeta ('page-info', $thread); + + // Attempt to read comment + $raw = $hashover->thread->data->read ($key, $thread); + + // Skip failed or unapproved comments or missing metadata + if ((!empty ($raw['status']) and $raw['status'] !== 'approved') + or ($raw and $page_info) === false) + { + continue; + } + + // Parse comment + $comment = $hashover->commentParser->parse ($raw, $key, $key_parts); + + // Merge comment with page metadata + $comment = array_merge ($page_info, $comment); + + // Trim comment body to configurable length + if ($hashover->setup->latestTrimWidth > 0) { + // Instantiate WriteComments + // + // TODO: Split WriteComments into multiple classes so we + // can instantiate only the functionality that we need + // + $write_comments = new WriteComments ( + $hashover->setup, + $hashover->thread + ); + + // Shorthands + $trim_length = $hashover->setup->latestTrimWidth; + $close_tags = $write_comments->closeTags; + + // Add <code> to list of tags to close + $write_comments->closeTags[] = 'code'; + + // Trim the comment to configurable length + $body = rtrim (mb_strimwidth ($comment['body'], 0, $trim_length, '...')); + + // Close any tags that may have had their endings trimmed off + $body = $write_comments->tagCloser ($close_tags, $body); + + // Escape any HTML tags that may have been trimmed in half + $body = $write_comments->htmlSelectiveEscape ($body); + + // Update the comment + $comment['body'] = $body; + } + + // Add comment to response array + $comments[] = $comment; + } + + // HashOver instance information + $data['instance'] = array ( + 'comments' => array ('primary' => $comments), + 'total-count' => count ($comments) + ); + + // Generate statistics + $hashover->statistics->executionEnd (); + + // HashOver statistics + $data['statistics'] = array ( + 'execution-time' => $hashover->statistics->executionTime, + 'script-memory' => $hashover->statistics->scriptMemory, + 'system-memory' => $hashover->statistics->systemMemory + ); + + // Encode JSON data + echo $hashover->misc->jsonData ($data); + +} catch (\Exception $error) { + $misc = new Misc ('json'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/api/count-link.php b/bootstrap/comments/api/count-link.php new file mode 100644 index 0000000..f3da768 --- /dev/null +++ b/bootstrap/comments/api/count-link.php @@ -0,0 +1,95 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Change to the HashOver directory +chdir (realpath ('../')); + +// Setup HashOver for JavaScript +require ('backend/javascript-setup.php'); + +try { + // Instantiate general setup class + $setup = new Setup (array ( + 'mode' => 'javascript', + 'context' => 'api' + )); + + // Throw exception if the "Latest Comments" API is disabled + if ($setup->apiStatus ('count-link') === 'disabled') { + throw new \Exception ('This API is not enabled.'); + } + + // Instantiate HashOver statistics class + $statistics = new Statistics ('javascript'); + + // Start execution timer + $statistics->executionStart (); + + // Instantiate JavaScript build class + $javascript = new JavaScriptBuild ('api/frontends/count-link'); + + // Register initial constructor + $javascript->registerFile ('constructor.js'); + + // Register comment count AJAX request getter method + $javascript->registerFile ('getcommentcount.js'); + + // Change to standard frontend directory + $javascript->changeDirectory ('frontend'); + + // Register HashOver script tag getter method + $javascript->registerFile ('script.js'); + + // Register backend path setter + $javascript->registerFile ('backendpath.js'); + + // Register HashOver ready state detection method + $javascript->registerFile ('onready.js'); + + // Register element creation methods + $javascript->registerFile ('elements.js'); + + // Register AJAX-related methods + $javascript->registerFile ('ajax.js'); + + // Change back to count link frontend directory + $javascript->changeDirectory ('api/frontends/count-link'); + + // Register automatic instantiation code + $javascript->registerFile ('instantiate.js', array ( + 'include' => !isset ($_GET['nodefault']) + )); + + // JavaScript build process output + $output = $javascript->build ( + $setup->minifiesJavascript, + $setup->minifyLevel + ); + + // Display JavaScript build process output + echo $output, PHP_EOL; + + // Display statistics + echo $statistics->executionEnd (); + +} catch (\Exception $error) { + $misc = new Misc ('javascript'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/api/frontends/count-link/constructor.js b/bootstrap/comments/api/frontends/count-link/constructor.js new file mode 100644 index 0000000..7473788 --- /dev/null +++ b/bootstrap/comments/api/frontends/count-link/constructor.js @@ -0,0 +1,43 @@ +// @licstart The following is the entire license notice for the +// JavaScript code in this page. +// +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. +// +// @licend The above is the entire license notice for the +// JavaScript code in this page. + +"use strict"; + +// Count link API frontend constructor (constructor.js) +function HashOverCountLink () +{ + // Get count link class elements + var countLinks = document.getElementsByClassName ('hashover-count-link'); + + // Run through the count links + for (var i = 0, il = countLinks.length; i < il; i++) { + var link = countLinks[i]; + + // Instantiate new count link object + this.getCommentCount (link, { + url: link.href + }); + } +}; + +// Constructor to add HashOver methods to +var HashOverConstructor = HashOverCountLink; diff --git a/bootstrap/comments/api/frontends/count-link/getcommentcount.js b/bootstrap/comments/api/frontends/count-link/getcommentcount.js new file mode 100644 index 0000000..536824c --- /dev/null +++ b/bootstrap/comments/api/frontends/count-link/getcommentcount.js @@ -0,0 +1,19 @@ +// Send AJAX request to backend for a comment count (getcommentcount.js) +HashOverCountLink.prototype.getCommentCount = function (link, options) +{ + // Reference to this HashOver object + var hashover = this; + + // Get backend queries + var queries = ['url=' + options.url]; + + // Backend request path + var requestPath = '/countlinkajax'; + + // Handle backend request + this.ajax ('POST', requestPath, queries, function (json) { + if (json['link-text'] !== undefined) { + link.textContent = json['link-text']; + } + }, true); +}; diff --git a/bootstrap/comments/api/frontends/count-link/instantiate.js b/bootstrap/comments/api/frontends/count-link/instantiate.js new file mode 100644 index 0000000..9329ca6 --- /dev/null +++ b/bootstrap/comments/api/frontends/count-link/instantiate.js @@ -0,0 +1,4 @@ +// Instantiate after the DOM is parsed (instantiate.js) +HashOverCountLink.onReady (function () { + window.hashoverCountLink = new HashOverCountLink (); +}); diff --git a/bootstrap/comments/api/frontends/latest/addcontrols.js b/bootstrap/comments/api/frontends/latest/addcontrols.js new file mode 100644 index 0000000..b5642f1 --- /dev/null +++ b/bootstrap/comments/api/frontends/latest/addcontrols.js @@ -0,0 +1,22 @@ +// Add various events to various elements in each comment (addcontrols.js) +HashOverLatest.prototype.addControls = function (json, popular) +{ + // Reference to this object + var hashover = this; + + // Get permalink from JSON object + var permalink = json.permalink; + + // Set onclick functions for external images + if (this.setup['allows-images'] !== false) { + // Get embedded image elements + var embeddedImgs = document.getElementsByClassName ('hashover-embedded-image'); + + for (var i = 0, il = embeddedImgs.length; i < il; i++) { + embeddedImgs[i].onclick = function () + { + hashover.openEmbeddedImage (this); + }; + } + } +}; diff --git a/bootstrap/comments/api/frontends/latest/addratings.js b/bootstrap/comments/api/frontends/latest/addratings.js new file mode 100644 index 0000000..b4d7c8e --- /dev/null +++ b/bootstrap/comments/api/frontends/latest/addratings.js @@ -0,0 +1,22 @@ +// Add Like/Dislike link and count to template (addratings.js) +HashOverLatest.prototype.comments.addRatings = function (comment, template, action, commentKey) +{ + // Reference to the parent object + var hashover = this.parent; + + // Check if the comment has been likes/dislikes + if (comment[action + 's'] !== undefined) { + // Add likes/dislikes to HTML template + template[action + 's'] = comment[action + 's']; + + // Get "X Like/Dislike(s)" locale + var plural = (comment[action + 's'] === 1 ? 0 : 1); + var count = comment[action + 's'] + ' ' + hashover.locale[action][plural]; + } + + // Add like count to HTML template + template[action + '-count'] = hashover.strings.parseTemplate (hashover.ui[action + '-count'], { + permalink: commentKey, + text: count || '' + }); +}; diff --git a/bootstrap/comments/api/frontends/latest/constructor.js b/bootstrap/comments/api/frontends/latest/constructor.js new file mode 100644 index 0000000..32c1880 --- /dev/null +++ b/bootstrap/comments/api/frontends/latest/constructor.js @@ -0,0 +1,79 @@ +// @licstart The following is the entire license notice for the +// JavaScript code in this page. +// +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. +// +// @licend The above is the entire license notice for the +// JavaScript code in this page. + +"use strict"; + +// Latest comments API frontend constructor (constructor.js) +function HashOverLatest (options) +{ + // Reference to this HashOver object + var hashover = this; + + // Backend queries + if (options && options.thread !== undefined) { + var queries = ['thread=' + encodeURIComponent (options.thread)]; + } else { + var queries = []; + } + + // Backend request path + var requestPath = '/latestajax'; + + // Handle backend request + this.ajax ('POST', requestPath, queries, function (json) { + // Handle error messages + if (json.message !== undefined) { + hashover.displayError (json, 'hashover-widget'); + return; + } + + // Locales from HashOver backend + HashOverLatest.prototype.locale = json.locale; + + // Setup information from HashOver back-end + HashOverLatest.prototype.setup = json.setup; + + // UI HTML from HashOver back-end + HashOverLatest.prototype.ui = json.ui; + + // Thread information from HashOver back-end + hashover.instance = json.instance; + + // Backend execution time and memory usage statistics + hashover.statistics = json.statistics; + + // Initiate HashOver latest comments + hashover.init (); + }, true); + + // Add parent proterty to all prototype objects + for (var name in this) { + var value = this[name]; + + if (value && value.constructor === Object) { + value.parent = this; + } + } +}; + +// Constructor to add HashOver methods to +var HashOverConstructor = HashOverLatest; diff --git a/bootstrap/comments/api/frontends/latest/init.js b/bootstrap/comments/api/frontends/latest/init.js new file mode 100644 index 0000000..77185cd --- /dev/null +++ b/bootstrap/comments/api/frontends/latest/init.js @@ -0,0 +1,37 @@ +// HashOver latest comments UI initialization process (init.js) +HashOverLatest.prototype.init = function () +{ + // Shorthand + var comments = this.instance.comments.primary; + + // Initial comments HTML + var html = ''; + + // Append theme CSS if enabled + this.optionalMethod ('appendCSS', [ 'hashover-widget' ]); + + // Add main HashOver element to this HashOver instance + this.instance['main-element'] = this.getMainElement ('hashover-widget'); + + // Templatify UI HTML strings + for (var element in this.ui) { + this.ui[element] = this.strings.templatify (this.ui[element]); + } + + // Parse every comment + for (var i = 0, il = comments.length; i < il; i++) { + html += this.comments.parse (comments[i]); + } + + // Add comments to element's innerHTML + if ('insertAdjacentHTML' in this.instance['main-element']) { + this.instance['main-element'].insertAdjacentHTML ('beforeend', html); + } else { + this.instance['main-element'].innerHTML = html; + } + + // Add control events + for (var i = 0, il = comments.length; i < il; i++) { + this.addControls (comments[i]); + } +}; diff --git a/bootstrap/comments/api/frontends/latest/instantiate.js b/bootstrap/comments/api/frontends/latest/instantiate.js new file mode 100644 index 0000000..82ff971 --- /dev/null +++ b/bootstrap/comments/api/frontends/latest/instantiate.js @@ -0,0 +1,4 @@ +// Instantiate after the DOM is parsed +HashOverLatest.onReady (function () { + window.hashoverLatest = new HashOverLatest (); +}); diff --git a/bootstrap/comments/api/json.php b/bootstrap/comments/api/json.php new file mode 100644 index 0000000..2904960 --- /dev/null +++ b/bootstrap/comments/api/json.php @@ -0,0 +1,76 @@ +<?php namespace HashOver; + +// Copyright (C) 2010-2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Change to the HashOver directory +chdir (realpath ('../')); + +// Setup HashOver for JSON +require ('backend/json-setup.php'); + +try { + // Instantiate HashOver class + $hashover = new \HashOver ('json', 'api'); + + // Display error if the API is disabled + if ($hashover->setup->apiStatus ('json') === 'disabled') { + throw new \Exception ('<b>HashOver</b>: This API is not enabled.'); + } + + // Configure HashOver and load comments + $hashover->setup->setPageURL ('request'); + $hashover->setup->collapsesComments = false; + $hashover->initiate (); + + // Comments and statistics response array + $data = array (); + + // Setup where to start reading comments + $start = $hashover->setup->getRequest ('start', 0); + + // Check for comments + if ($hashover->thread->totalCount > 1) { + // Parse comments; TODO: Use starting point + $hashover->parsePrimary (); + $hashover->parsePopular (); + + // Display as JSON data + $data['comments'] = $hashover->comments; + } else { + // Return no comments message + $data = array ('No comments.'); + } + + // Generate statistics + $hashover->statistics->executionEnd (); + + // HashOver statistics + $data['statistics'] = array ( + 'execution-time' => $hashover->statistics->executionTime, + 'script-memory' => $hashover->statistics->scriptMemory, + 'system-memory' => $hashover->statistics->systemMemory + ); + + // Return JSON or JSONP function call + echo $hashover->misc->jsonData ($data); + +} catch (\Exception $error) { + $misc = new Misc ('json'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/api/latest.php b/bootstrap/comments/api/latest.php new file mode 100644 index 0000000..0582260 --- /dev/null +++ b/bootstrap/comments/api/latest.php @@ -0,0 +1,154 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Change to the HashOver directory +chdir (realpath ('../')); + +// Setup HashOver for JavaScript +require ('backend/javascript-setup.php'); + +try { + // Instantiate general setup class + $setup = new Setup (array ( + 'mode' => 'javascript', + 'context' => 'api' + )); + + // Throw exception if the "Latest Comments" API is disabled + if ($setup->apiStatus ('latest') === 'disabled') { + throw new \Exception ('This API is not enabled.'); + } + + // Instantiate HashOver statistics class + $statistics = new Statistics ('javascript'); + + // Start execution timer + $statistics->executionStart (); + + // Instantiate JavaScript build class + $javascript = new JavaScriptBuild ('api/frontends/latest'); + + // Register initial constructor + $javascript->registerFile ('constructor.js'); + + // Change to standard frontend directory + $javascript->changeDirectory ('frontend'); + + // Register HashOver script tag getter method + $javascript->registerFile ('script.js'); + + // Register backend path setter + $javascript->registerFile ('backendpath.js'); + + // Register HashOver ready state detection method + $javascript->registerFile ('onready.js'); + + // Register element creation methods + $javascript->registerFile ('elements.js'); + + // Register main HashOver element getter method + $javascript->registerFile ('getmainelement.js'); + + // Register error message handler method + $javascript->registerFile ('displayerror.js'); + + // Register AJAX-related methods + $javascript->registerFile ('ajax.js'); + + // Register pre-compiled regular expressions + $javascript->registerFile ('regex.js'); + + // Register end-of-line trimmer method + $javascript->registerFile ('eoltrim.js'); + + // Register parent permalink getter method + $javascript->registerFile ('permalinks.js'); + + // Register markdown methods + $javascript->registerFile ('markdown.js', array ( + 'include' => $setup->usesMarkdown + )); + + // Register date/time methods + $javascript->registerFile ('datetime.js', array ( + 'include' => $setup->usesUserTimezone + )); + + // Register search and replace methods + $javascript->registerFile ('strings.js'); + + // Register optional method handler method + $javascript->registerFile ('optionalmethod.js'); + + // Register comment parsing methods + $javascript->registerFile ('comments.js'); + + // Register embedded image method + $javascript->registerFile ('embedimage.js', array ( + 'include' => $setup->allowsImages, + + 'dependencies' => array ( + 'openembeddedimage.js' + ) + )); + + // Register classList polyfill methods + $javascript->registerFile ('classes.js'); + + // Register theme stylesheet appender method + $javascript->registerFile ('appendcss.js', array ( + 'include' => $setup->appendsCss + )); + + // Change back to latest frontend directory + $javascript->changeDirectory ('api/frontends/latest'); + + // Register Like/Dislike methods + $javascript->registerFile ('addratings.js', array ( + 'include' => ($setup->allowsLikes or $setup->allowsDislikes) + )); + + // Register control event handler attacher method + $javascript->registerFile ('addcontrols.js'); + + // Register initialization method + $javascript->registerFile ('init.js'); + + // Register automatic instantiation code + $javascript->registerFile ('instantiate.js', array ( + 'include' => !isset ($_GET['nodefault']) + )); + + // JavaScript build process output + $output = $javascript->build ( + $setup->minifiesJavascript, + $setup->minifyLevel + ); + + // Display JavaScript build process output + echo $output, PHP_EOL; + + // Display statistics + echo $statistics->executionEnd (); + +} catch (\Exception $error) { + $misc = new Misc ('javascript'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/api/rss.php b/bootstrap/comments/api/rss.php new file mode 100644 index 0000000..d1cf020 --- /dev/null +++ b/bootstrap/comments/api/rss.php @@ -0,0 +1,327 @@ +<?php namespace HashOver; + +// Copyright (C) 2010-2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Tell browser this is XML/RSS +header ('Content-Type: application/xml; charset=utf-8'); + +// Change to the HashOver directory +chdir (realpath ('../')); + +// Do some standard HashOver setup work +require ('backend/nocache-headers.php'); +require ('backend/standard-setup.php'); + +// Autoload class files +spl_autoload_register (function ($uri) { + $uri = str_replace ('\\', '/', strtolower ($uri)); + $class_name = basename ($uri); + $error = '"' . $class_name . '.php" file could not be included!'; + + if (!@include ('backend/classes/' . $class_name . '.php')) { + echo '<?xml version="1.0" encoding="UTF-8"?>', PHP_EOL; + echo '<error>', $error, '</error>'; + exit; + } +}); + +function create_rss (&$hashover) +{ + // Shorter variable name + $thread = $hashover->setup->threadName; + + // Attempt to read page information metadata + $metadata = $hashover->thread->data->readMeta ('page-info', $thread); + + // Check if metadata read successfully + if ($metadata !== false) { + // If so, set page URL blank if it's missing from the metadata + if (!isset ($metadata['url'])) { + $metadata['url'] = ''; + } + + // And set page title to "Untitled" if it's missing from the metadata + if (!isset ($metadata['title'])) { + $metadata['title'] = $hashover->locale->text['untitled']; + } + } else { + // If not, set default metadata information + $metadata = array ( + 'url' => '', + 'title' => $hashover->locale->text['untitled'] + ); + } + + // Create new DOM document. + $xml = new \DOMDocument ('1.0', 'UTF-8'); + $xml->preserveWhiteSpace = false; + $xml->formatOutput = true; + + // Create main RSS element + $rss = $xml->createElement ('rss'); + $rss->setAttribute ('version', '2.0'); + $rss->setAttribute ('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $rss->setAttribute ('xmlns:content', 'http://purl.org/rss/1.0/modules/content/'); + $rss->setAttribute ('xmlns:atom', 'http://www.w3.org/2005/Atom'); + + // Display error if the API is disabled + if ($hashover->setup->apiStatus ('rss') === 'disabled') { + $title = $xml->createElement ('title'); + $title_value = $xml->createTextNode ('HashOver: RSS API is not enabled.'); + $title->appendChild ($title_value); + $rss->appendChild ($title); + + $description = $xml->createElement ('description'); + $description_value = $xml->createTextNode ('Error!'); + $description->appendChild ($description_value); + $rss->appendChild ($description); + + // Add main RSS element to XML + $xml->appendChild ($rss); + + // Return RSS XML + exit (str_replace (' ', "\t", $xml->saveXML ())); + } + + // Create channel element + $channel = $xml->createElement ('channel'); + + // Create channel title element + $title = $xml->createElement ('title'); + $title_value = $xml->createTextNode (html_entity_decode ($metadata['title'], ENT_COMPAT, 'UTF-8')); + $title->appendChild ($title_value); + + // Add channel title to channel element + $channel->appendChild ($title); + + // Create channel link element + $link = $xml->createElement ('link'); + $link_value = $xml->createTextNode (html_entity_decode ($metadata['url'], ENT_COMPAT, 'UTF-8')); + $link->appendChild ($link_value); + + // Add channel link to channel element + $channel->appendChild ($link); + + // Create channel description element + $description = $xml->createElement ('description'); + $count_plural = ($hashover->thread->totalCount !== 1); + $showing_comments_locale = $hashover->locale->text['showing-comments'][$count_plural]; + $count_locale = sprintf ($showing_comments_locale, $hashover->thread->totalCount - 1); + $description_value = $xml->createTextNode ($count_locale); + $description->appendChild ($description_value); + + // Add channel description to channel element + $channel->appendChild ($description); + + // Create channel atom link element + $atom_link = $xml->createElement ('atom:link'); + $atom_link->setAttribute ('href', 'http://' . $hashover->setup->domain . $_SERVER['PHP_SELF'] . '?url=' . $metadata['url']); + $atom_link->setAttribute ('rel', 'self'); + + // Add channel atom link to channel element + $channel->appendChild ($atom_link); + + // Create channel language element + $language = $xml->createElement ('language'); + $language_value = $xml->createTextNode ('en-us'); + $language->appendChild ($language_value); + + // Add channel language to channel element + $channel->appendChild ($language); + + // Create channel ttl element + $ttl = $xml->createElement ('ttl'); + $ttl_value = $xml->createTextNode ('40'); + $ttl->appendChild ($ttl_value); + + // Add channel ttl to channel element + $channel->appendChild ($ttl); + + // Add channel element to main RSS element + $rss->appendChild ($channel); + + // Parse comments + function parse_comments (&$metadata, &$comment, &$rss, &$xml, &$hashover) + { + // Skip deleted/unmoderated comments + if (isset ($comment['notice'])) { + return; + } + + // Encode HTML entities + $comment['body'] = htmlentities ($comment['body'], ENT_COMPAT, 'UTF-8', true); + + // Decode HTML entities + $comment['body'] = html_entity_decode ($comment['body'], ENT_COMPAT, 'UTF-8'); + + // Remove [img] tags + $comment['body'] = preg_replace ('/\[(img|\/img)\]/iS', '', $comment['body']); + + // Parse comment as markdown + $comment['body'] = $hashover->markdown->parseMarkdown ($comment['body']); + + // Convert <code> tags to <pre> tags + $comment['body'] = preg_replace ('/(<|<\/)code>/iS', '\\1pre>', $comment['body']); + + // Get name from comment or use configured default + $name = !empty ($comment['name']) ? $comment['name'] : $hashover->setup->defaultName; + + // Create item element + $item = $xml->createElement ('item'); + + // Generate comment summary item title + $title = $name . ' : '; + $single_comment = str_replace (PHP_EOL, ' ', strip_tags ($comment['body'])); + + if (mb_strlen ($single_comment) > 40) { + $title .= mb_substr ($single_comment, 0, 40) . '...'; + } else { + $title .= $single_comment; + } + + // Create item title element + $item_title = $xml->createElement ('title'); + $item_title_value = $xml->createTextNode (html_entity_decode ($title, ENT_COMPAT, 'UTF-8')); + $item_title->appendChild ($item_title_value); + + // Add item title element to item element + $item->appendChild ($item_title); + + // Create item name element + $item_name = $xml->createElement ('name'); + $item_name_value = $xml->createTextNode (html_entity_decode ($name, ENT_COMPAT, 'UTF-8')); + $item_name->appendChild ($item_name_value); + + // Add item name element to item element + $item->appendChild ($item_name); + + // Add HTML anchor tag to URLs (hyperlinks) + $comment['body'] = preg_replace ('/((ftp|http|https):\/\/[a-z0-9-@:%_\+.~#?&\/=]+) {0,}/iS', '<a href="\\1" target="_blank">\\1</a>', $comment['body']); + + // Replace newlines with break tags + $comment['body'] = str_replace (PHP_EOL, '<br>', $comment['body']); + + // Create item description element + $item_description = $xml->createElement ('description'); + $item_description_value = $xml->createTextNode ($comment['body']); + $item_description->appendChild ($item_description_value); + + // Add item description element to item element + $item->appendChild ($item_description); + + // Create item avatar element + $item_avatar = $xml->createElement ('avatar'); + $web_root = 'http://' . $hashover->setup->domain . $hashover->setup->httpRoot; + $item_avatar_value = $xml->createTextNode ($web_root . $comment['avatar']); + $item_avatar->appendChild ($item_avatar_value); + + // Add item avatar element to item element + $item->appendChild ($item_avatar); + + if (!empty ($comment['likes'])) { + // Create item likes element + $item_likes = $xml->createElement ('likes'); + $item_likes_value = $xml->createTextNode ($comment['likes']); + $item_likes->appendChild ($item_likes_value); + + // Add item likes element to item element + $item->appendChild ($item_likes); + } + + if ($hashover->setup->allowsDislikes === true) { + if (!empty ($comment['dislikes'])) { + // Create item dislikes element + $item_dislikes = $xml->createElement ('dislikes'); + $item_dislikes_value = $xml->createTextNode ($comment['dislikes']); + $item_dislikes->appendChild ($item_dislikes_value); + + // Add item dislikes element to item element + $item->appendChild ($item_dislikes); + } + } + + // Create item publication date element + $item_pubDate = $xml->createElement ('pubDate'); + $item_pubDate_value = $xml->createTextNode (date ('D, d M Y H:i:s O', $comment['sort-date'])); + $item_pubDate->appendChild ($item_pubDate_value); + + // Add item pubDate element to item element + $item->appendChild ($item_pubDate); + + // URL to comment for item guide and link elements + $item_permalink_url = $metadata['url'] . '#' . $comment['permalink']; + + // Create item guide element + $item_guid = $xml->createElement ('guid'); + $item_guid_value = $xml->createTextNode ($item_permalink_url); + $item_guid->appendChild ($item_guid_value); + + // Add item guide element to item element + $item->appendChild ($item_guid); + + // Create item link element + $item_link = $xml->createElement ('link'); + $item_link_value = $xml->createTextNode ($item_permalink_url); + $item_link->appendChild ($item_link_value); + + // Add item link element to item element + $item->appendChild ($item_link); + + // Add item element to main RSS element + $rss->appendChild ($item); + + // Recursively parse replies + if (!empty ($comment['replies'])) { + foreach ($comment['replies'] as $reply) { + parse_comments ($metadata, $reply, $rss, $xml, $hashover); + } + } + } + + // Add item element to main RSS element + foreach ($hashover->comments['primary'] as $comment) { + parse_comments ($metadata, $comment, $rss, $xml, $hashover); + } + + // Add main RSS element to XML + $xml->appendChild ($rss); + + // Return RSS XML + echo preg_replace_callback ('/^(\s+)/m', function ($spaces) { + return str_repeat ("\t", strlen ($spaces[1]) / 2); + }, $xml->saveXML ()); + + // Return statistics + echo $hashover->statistics->executionEnd (); +} + +try { + // Instantiate HashOver class + $hashover = new \HashOver ('php', 'api'); + $hashover->setup->setPageURL ('request'); + $hashover->setup->collapsesComments = false; + $hashover->initiate (); + $hashover->parsePrimary (); + + // Create RSS feed + create_rss ($hashover); + +} catch (\Exception $error) { + $misc = new Misc ('rss'); + $misc->displayError ($error->getMessage ()); +} |