From 10519dc5d2387f45da30ff84e44a19215cd61c69 Mon Sep 17 00:00:00 2001 From: German Attanasio Ruiz Date: Thu, 23 Jun 2016 18:06:55 -0400 Subject: [PATCH] :shirt: fix aslant --- .eslintrc | 1 + LICENSE | 177 ++++++++++++++++++ app.js | 6 +- config/security.js | 6 +- package.json | 5 +- public/js/.eslintrc | 8 + public/js/components/App.js | 308 +++++++++++++++----------------- public/js/components/helpers.js | 60 ++++--- public/js/demo.js | 94 ++++++---- 9 files changed, 433 insertions(+), 232 deletions(-) create mode 100755 LICENSE create mode 100644 public/js/.eslintrc diff --git a/.eslintrc b/.eslintrc index fc5a13ca..5fc8f60c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,6 +2,7 @@ "rules": { "no-console": 0, "func-names": 0, + "one-var": 0, "vars-on-top": 0, "consistent-return": 0 }, diff --git a/LICENSE b/LICENSE new file mode 100755 index 00000000..4947287f --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/app.js b/app.js index 62d657b8..d2743219 100755 --- a/app.js +++ b/app.js @@ -41,10 +41,10 @@ app.get('/', function(req, res) { app.post('/api/tone', function(req, res, next) { toneAnalyzer.tone(req.body, function(err, data) { - if (err) + if (err) { return next(err); - else - return res.json(data); + } + return res.json(data); }); }); diff --git a/config/security.js b/config/security.js index 95bf4392..09634d3f 100644 --- a/config/security.js +++ b/config/security.js @@ -17,9 +17,9 @@ 'use strict'; // security.js -var rateLimit = require('express-rate-limit'); -var helmet = require('helmet'); -var csrf = require('csurf'); +var rateLimit = require('express-rate-limit'); +var helmet = require('helmet'); +var csrf = require('csurf'); var cookieParser = require('cookie-parser'); module.exports = function(app) { diff --git a/package.json b/package.json index f21ddee1..f5e9c9b5 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "express": "^4.12.2", "express-rate-limit": "^2.1.0", "express-secure-only": "^0.2.1", - "helmet": "^1.3.0", + "helmet": "^2.1.1", "watson-developer-cloud": "^1.8.0" }, "devDependencies": { @@ -54,7 +54,6 @@ "eslint-plugin-react": "^5.1.1", "istanbul": "^0.4.2", "mocha": "^2.4.5", - "supertest": "^1.2.0", - "nock": "7.7.0" + "supertest": "^1.2.0" } } diff --git a/public/js/.eslintrc b/public/js/.eslintrc new file mode 100644 index 00000000..e13ecf06 --- /dev/null +++ b/public/js/.eslintrc @@ -0,0 +1,8 @@ +{ + "extends": "../../.eslintrc", + "env": { + "browser": true, + "jquery": true, + "commonjs": true + } +} \ No newline at end of file diff --git a/public/js/components/App.js b/public/js/components/App.js index db170e13..a51a7713 100644 --- a/public/js/components/App.js +++ b/public/js/components/App.js @@ -13,17 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* global $:false, normalize, move */ + /* global normalize, move */ + /* eslint no-unused-vars: "warn" */ /** * This is a JS constructor that controls this application's model and state * logic. - * @param {Object} document tone data - * @param {Array} sentence tone array - * @param {Object} threshold data - * @param {String} selected sample id + * @param {Object} documentTones tone data + * @param {Array} sentences sentence tone array + * @param {Object} thresholds threshold data + * @param {String} selectedSample selected sample id * @return {Object} exposed functions that interact with application state logic + * */ function App(documentTones, sentences, thresholds, selectedSample) { var _selectedFilter = 'Anger', @@ -39,96 +40,96 @@ function App(documentTones, sentences, thresholds, selectedSample) { _socialToneHoverTexts, _toneHash, TONE_CATEGORIES_RESET = [{ - tones: [{ - score: 0, - tone_id: 'Anger', - tone_name: 'Anger', - tone_category_id: 'emotion_tone', - tone_category_name: 'Emotion Tone' - }, { - score: 0, - tone_id: 'Disgust', - tone_name: 'Disgust', - tone_category_id: 'emotion_tone', - tone_category_name: 'Emotion Tone' - }, { - score: 0, - tone_id: 'Fear', - tone_name: 'Fear', - tone_category_id: 'emotion_tone', - tone_category_name: 'Emotion Tone' - }, { - score: 0, - tone_id: 'Joy', - tone_name: 'Joy', - tone_category_id: 'emotion_tone', - tone_category_name: 'Emotion Tone' - }, { - score: 0, - tone_id: 'Sadness', - tone_name: 'Sadness', - tone_category_id: 'emotion_tone', - tone_category_name: 'Emotion Tone' - }], - category_id: 'emotion_tone', - category_name: 'Emotion Tone' + tones: [{ + score: 0, + tone_id: 'Anger', + tone_name: 'Anger', + tone_category_id: 'emotion_tone', + tone_category_name: 'Emotion Tone' + }, { + score: 0, + tone_id: 'Disgust', + tone_name: 'Disgust', + tone_category_id: 'emotion_tone', + tone_category_name: 'Emotion Tone' + }, { + score: 0, + tone_id: 'Fear', + tone_name: 'Fear', + tone_category_id: 'emotion_tone', + tone_category_name: 'Emotion Tone' + }, { + score: 0, + tone_id: 'Joy', + tone_name: 'Joy', + tone_category_id: 'emotion_tone', + tone_category_name: 'Emotion Tone' + }, { + score: 0, + tone_id: 'Sadness', + tone_name: 'Sadness', + tone_category_id: 'emotion_tone', + tone_category_name: 'Emotion Tone' + }], + category_id: 'emotion_tone', + category_name: 'Emotion Tone' + }, { + tones: [{ + score: 0, + tone_id: 'Analytical', + tone_name: 'Analytical', + tone_category_id: 'language_tone', + tone_category_name: 'Language Tone' + }, { + score: 0, + tone_id: 'Confident', + tone_name: 'Confident', + tone_category_id: 'language_tone', + tone_category_name: 'Language Tone' + }, { + score: 0, + tone_id: 'Tentative', + tone_name: 'Tentative', + tone_category_id: 'language_tone', + tone_category_name: 'Language Tone' + }], + category_id: 'language_tone', + category_name: 'Language Tone' + }, { + tones: [{ + score: 0, + tone_id: 'Openness_Big5', + tone_name: 'Openness', + tone_category_id: 'social_tone', + tone_category_name: 'Social Tone' + }, { + score: 0, + tone_id: 'Conscientiousness_Big5', + tone_name: 'Conscientiousness', + tone_category_id: 'social_tone', + tone_category_name: 'Social Tone' + }, { + score: 0, + tone_id: 'Extraversion_Big5', + tone_name: 'Extraversion', + tone_category_id: 'social_tone', + tone_category_name: 'Social Tone' }, { - tones: [{ - score: 0, - tone_id: 'Analytical', - tone_name: 'Analytical', - tone_category_id: 'language_tone', - tone_category_name: 'Language Tone' - }, { - score: 0, - tone_id: 'Confident', - tone_name: 'Confident', - tone_category_id: 'language_tone', - tone_category_name: 'Language Tone' - }, { - score: 0, - tone_id: 'Tentative', - tone_name: 'Tentative', - tone_category_id: 'language_tone', - tone_category_name: 'Language Tone' - }], - category_id: 'language_tone', - category_name: 'Language Tone' + score: 0, + tone_id: 'Agreeableness_Big5', + tone_name: 'Agreeableness', + tone_category_id: 'social_tone', + tone_category_name: 'Social Tone' }, { - tones: [{ - score: 0, - tone_id: 'Openness_Big5', - tone_name: 'Openness', - tone_category_id: 'social_tone', - tone_category_name: 'Social Tone' - }, { - score: 0, - tone_id: 'Conscientiousness_Big5', - tone_name: 'Conscientiousness', - tone_category_id: 'social_tone', - tone_category_name: 'Social Tone' - }, { - score: 0, - tone_id: 'Extraversion_Big5', - tone_name: 'Extraversion', - tone_category_id: 'social_tone', - tone_category_name: 'Social Tone' - }, { - score: 0, - tone_id: 'Agreeableness_Big5', - tone_name: 'Agreeableness', - tone_category_id: 'social_tone', - tone_category_name: 'Social Tone' - }, { - score: 0, - tone_id: 'Neuroticism_Big5', - tone_name: 'Emotional Range', - tone_category_id: 'social_tone', - tone_category_name: 'Social Tone' - }], - category_id: 'social_tone', - category_name: 'Social Tone' - }], SCORE_DECIMAL_PLACE = 2, + score: 0, + tone_id: 'Neuroticism_Big5', + tone_name: 'Emotional Range', + tone_category_id: 'social_tone', + tone_category_name: 'Social Tone' + }], + category_id: 'social_tone', + category_name: 'Social Tone' + }], SCORE_DECIMAL_PLACE = 2, PERCENTAGE_DECIMAL_PLACE = 1, SOCIAL_TONE_MIN_RANGE = -1, SOCIAL_TONE_MAX_RANGE = 1, @@ -137,18 +138,20 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Make sure sentences have proper tone data values. * Mutates _rankedSentences + * @return {undefined} */ function _cleanSentences() { // look for empty tone_categories and set tone_categories to 0 values _rankedSentences.forEach(function(item) { - if (item.tone_categories.length === 0) + if (item.tone_categories.length === 0) { item.tone_categories = TONE_CATEGORIES_RESET.slice(0); + } }); } /** * Get index of a tone - * @param {String} tone name as key + * @param {String} key tone name as key * @return {int} index positioning of tone */ function _searchIndex(key) { @@ -158,32 +161,32 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * This is a helper function to determine which classname to use by * comparing tone score with thresholds. - * @param {String} tone name as key - * @param {int} tone score to evaluate - * @param {String} class name type + * @param {String} toneKey tone name as key + * @param {int} score score to evaluate + * @param {String} classNameType class name type * @return {String} resulting class name */ function _toneLevel(toneKey, score, classNameType) { - var output, + var outputTone, toneValue = _toneHash[toneKey], newScore = score, baseThreshold = 0; - if (newScore <= baseThreshold) - output = ''; - else if (newScore < toneValue.low.score) - output = toneValue.low[classNameType]; - else if (newScore > toneValue.high.score) - output = toneValue.high[classNameType]; - else - output = toneValue.medium[classNameType]; - - return output; + if (newScore <= baseThreshold) { + outputTone = ''; + } else if (newScore < toneValue.low.score) { + outputTone = toneValue.low[classNameType]; + } else if (newScore > toneValue.high.score) { + outputTone = toneValue.high[classNameType]; + } else { + outputTone = toneValue.medium[classNameType]; + } + return outputTone; } /** * Percentagify - * @param {float} decimal score + * @param {float} score decimal score * @return {String} percentage score in PERCENTAGE_DECIMAL_PLACE placements */ function _percentagify(score) { @@ -193,10 +196,8 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Getter / Setter for _selectedFilter * Also sets _selectedTone appropriately - * @param {String} setter tone name - * @return (getter) {String} _selectedFilter - * or - * @return (setter) {Object} Constructor returned object + * @param {String} str setter tone name + * @return {String} _selectedFilter */ output.selectedFilter = function(str) { if (!arguments.length) return _selectedFilter; @@ -224,10 +225,8 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Getter / Setter for _lowToHigh - * @param {bool} setter boolean - * @return (getter) {bool} _lowToHigh - * or - * @return (setter) {Object} Constructor returned object + * @param {bool} bool setter boolean + * @return {bool} (getter) {bool} _lowToHigh */ output.lowToHigh = function(bool) { if (!arguments.length) return _lowToHigh; @@ -246,10 +245,8 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Getter / Setter for _isHoveringOriginalText - * @param {bool} setter boolean - * @return (getter) {bool} _isHoveringOriginalText - * or - * @return (setter) {Object} Constructor returned object + * @param {bool} bool setter boolean + * @return {bool} (getter) _isHoveringOriginalText */ output.isHoveringOriginalText = function(bool) { if (!arguments.length) return _isHoveringOriginalText; @@ -267,10 +264,8 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Getter / Setter for _currentHoveredOriginalSentence - * @param {DOMElement} setter element - * @return (getter) {DOMElement} _currentHoveredOriginalSentence - * or - * @return (setter) {Object} Constructor returned object + * @param {DOMElement} element setter element + * @return {DOMElement} (getter) _currentHoveredOriginalSentence */ output.currentHoveredOriginalSentence = function(element) { if (!arguments.length) return _currentHoveredOriginalSentence; @@ -293,20 +288,13 @@ function App(documentTones, sentences, thresholds, selectedSample) { - a.tone_categories[_searchIndex(_selectedTone)].tones[_searchIndex(_selectedFilter)].score; }, map = function(item) { - var score = item.tone_categories[_searchIndex(_selectedTone)].tones[_searchIndex(_selectedFilter)].score.toFixed(SCORE_DECIMAL_PLACE); - return { - text: item.text, - score: score, - className: 'sentence-rank--score_' + normalize(_selectedFilter) - }; - }, - filter = (_selectedTone === 'Social Tone') ? - function(item) { - return item.score >= -1; - } : - function(item) { - return item.score > 0; - }; + var score = item.tone_categories[_searchIndex(_selectedTone)].tones[_searchIndex(_selectedFilter)].score.toFixed(SCORE_DECIMAL_PLACE); + return { + text: item.text, + score: score, + className: 'sentence-rank--score_' + normalize(_selectedFilter) + }; + }; return _rankedSentences.sort(sort).map(map); }; @@ -326,7 +314,7 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Export an adaptation of original sentences tooltip model - * @param {int} sentence index + * @param {int} sentenceIndex sentence index * @return {Array} array of {Object} sentence data */ output.updateOriginalSentencesTooltips = function(sentenceIndex) { @@ -345,28 +333,30 @@ function App(documentTones, sentences, thresholds, selectedSample) { /** * Select initial filter depending on sample text picked + * @return {undefined} */ output.selectFilterBySample = function() { var getHighestTone = function(toneCategory) { var highestTone = _documentTones.tone_categories[_searchIndex(toneCategory)].tones[0].tone_name, - highestScore = 0; + highestScore = 0; _documentTones.tone_categories[_searchIndex(toneCategory)].tones.forEach(function(item) { - if (highestScore < item.score) { - highestScore = item.score; - highestTone = item.tone_name; - } - }); + if (highestScore < item.score) { + highestScore = item.score; + highestTone = item.tone_name; + } + }); return highestTone; }, sample = { - 'customer-call': getHighestTone('Emotion Tone'), - 'email': getHighestTone('Social Tone'), - 'corporate-announcement': getHighestTone('Language Tone'), - 'own-text': getHighestTone('Emotion Tone') - }; + 'customer-call': getHighestTone('Emotion Tone'), + 'email': getHighestTone('Social Tone'), + 'corporate-announcement': getHighestTone('Language Tone'), + 'own-text': getHighestTone('Emotion Tone') + }; - if (_selectedSample in sample) + if (_selectedSample in sample) { output.selectedFilter(sample[_selectedSample]); + } }; /** @@ -387,7 +377,7 @@ function App(documentTones, sentences, thresholds, selectedSample) { // Constructing the _toneHash hashmap _toneHash = sentences[0].tone_categories.reduce(function(prevVal, curVal, curIndex) { - prevVal = curVal.tones.reduce(function(prevVal2, curVal2, curIndex2) { + var reducedPrevVal = curVal.tones.reduce(function(prevVal2, curVal2, curIndex2) { prevVal2[curVal2.tone_name] = { index: curIndex2, tone: curVal.category_name, @@ -407,16 +397,16 @@ function App(documentTones, sentences, thresholds, selectedSample) { } }; - if (curVal.category_name === 'Social Tone') + if (curVal.category_name === 'Social Tone') { prevVal2[curVal2.tone_name].tooltip = _socialToneHoverTexts[curVal2.tone_name]; - + } return prevVal2; }, prevVal); - prevVal[curVal.category_name] = { + reducedPrevVal[curVal.category_name] = { index: curIndex, tone: curVal.category_name }; - return prevVal; + return reducedPrevVal; }, {}); return output; diff --git a/public/js/components/helpers.js b/public/js/components/helpers.js index dfdf98be..bd56019b 100644 --- a/public/js/components/helpers.js +++ b/public/js/components/helpers.js @@ -13,16 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - /* global $:false */ + /* eslint no-unused-vars: "off" */ 'use strict'; /** * Get range transformation of @param value - * @param {float} value - * @param {float} min - * @param {float} max + * @param {float} value value + * @param {float} min min + * @param {float} max max * @return {float} projected value */ function range(value, min, max) { @@ -31,9 +30,9 @@ function range(value, min, max) { /** * Get range transformation of @param value in percent - * @param {float} value - * @param {float} min - * @param {float} max + * @param {float} value The value + * @param {float} min Minimum + * @param {float} max Maximum * @return {float} projected value in percent */ function rangeToPercent(value, min, max) { @@ -42,7 +41,7 @@ function rangeToPercent(value, min, max) { /** * Cleans up string - * @param {String} str + * @param {String} str The String * @return {String} normalized string */ function normalize(str) { @@ -51,33 +50,36 @@ function normalize(str) { /** * Scrolls page to @param element - * @param {$element} $element + * @param {$element} $element The element + * @return {undefined} */ function scrollTo($element) { $('html, body').animate({ scrollTop: $element.offset().top }, 'fast'); } /** - * Move element in @param arr from @param old_index to @param new_index. - * Mutates @param arr - * @param {Array} arr - * @param {int} old_index - * @param {int} new_index + * Move element in @param arr from @param oldIndex to @param newIndex. + * @param {Array} arr the array + * @param {int} oldIndex old index + * @param {int} newIndex new index * @return {Array} arr */ -function move(arr, old_index, new_index) { - while (old_index < 0) { - old_index += arr.length; - } - while (new_index < 0) { - new_index += arr.length; - } - if (new_index >= arr.length) { - var k = new_index - arr.length; - while ((k--) + 1) { - arr.push(undefined); - } +function move(arr, oldIndex, newIndex) { + var internalArray = arr; + var internalOldIndex = oldIndex; + var internalNewIndex = newIndex; + while (internalOldIndex < 0) { + internalOldIndex += internalArray.length; + } + while (internalNewIndex < 0) { + internalNewIndex += internalArray.length; + } + if (internalNewIndex >= internalArray.length) { + var k = internalNewIndex - internalArray.length; + while ((k--) + 1) { + internalArray.push(undefined); } - arr.splice(new_index, 0, arr.splice(old_index, 1)[0]); - return arr; + } + internalArray.splice(internalNewIndex, 0, internalArray.splice(internalOldIndex, 1)[0]); + return internalArray; } diff --git a/public/js/demo.js b/public/js/demo.js index b10864c2..36236299 100755 --- a/public/js/demo.js +++ b/public/js/demo.js @@ -13,15 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - /* global $:false, _, normalize, scrollTo, move, Application */ + /* eslint camelcase: "warn" */ + /* global _, normalize, scrollTo, move, + Application, App + barGraphTemplate, + emotionBarGraphTemplate, + filtersTemplate, + originalTextTemplate, + sentenceRankTemplate, + originalTextTooltipTemplate, + originalTextLegendTemplate + */ 'use strict'; /* * JQuery on ready callback function */ function ready() { - // CSRF protection $.ajaxSetup({ headers: { @@ -48,8 +56,9 @@ function ready() { /** * Load application after initial json data is loaded - * @param {Object} thresholds json - * @param {Object} collection of sample text json + * @param {Object} thresholds thresholds json + * @param {Object} sampleText collection of sample text json + * @return {undefined} */ function allReady(thresholds, sampleText) { var $input = $('.input'), @@ -71,7 +80,6 @@ function allReady(thresholds, sampleText) { $emotionFilters = $('.filters--emotion'), $writingFilters = $('.filters--writing'), $socialFilters = $('.filters--social'), - $originalText = $('.original-text'), $originalTexts = $('.original-text--texts'), $originalTextTooltipContainer = $('.original-text--tooltip-container'), $legend = $('.original-text--legend'), @@ -80,7 +88,6 @@ function allReady(thresholds, sampleText) { $outputResetButton = $('.output--reset-button'), barGraph_template = barGraphTemplate.innerHTML, emotionBarGraph_template = emotionBarGraphTemplate.innerHTML, - verticalBarGraph_template = verticalBarGraphTemplate.innerHTML, filters_template = filtersTemplate.innerHTML, originalText_template = originalTextTemplate.innerHTML, sentenceRank_template = sentenceRankTemplate.innerHTML, @@ -90,10 +97,10 @@ function allReady(thresholds, sampleText) { /** * Callback function for AJAX post to get tone analyzer data - * @param {Object} response data from api + * @param {Object} data response data from api + * @return {undefined} */ function toneCallback(data) { - $input.show(); $loading.hide(); $error.hide(); @@ -109,7 +116,7 @@ function allReady(thresholds, sampleText) { app; // if only one sentence, sentences will not exist, so mutate sentences_tone manually - if (data.sentences_tone === undefined) { + if (typeof (data.sentences_tone) === 'undefined') { data.sentences_tone = [{ sentence_id: 0, text: selectedSampleText, @@ -121,7 +128,7 @@ function allReady(thresholds, sampleText) { /** * Map Callback function for emotion document tones - * @param {Object} current iterating element + * @param {Object} item current iterating element * @return {Object} label, score, threshold */ function emotionMap(item) { @@ -136,7 +143,7 @@ function allReady(thresholds, sampleText) { /** * Map Callback function for writing document tones - * @param {Object} current iterating element + * @param {Object} item current iterating element * @return {Object} label, score */ function writingMap(item) { @@ -148,7 +155,7 @@ function allReady(thresholds, sampleText) { /** * Map Callback function for social document tones - * @param {Object} current iterating element + * @param {Object} item current iterating element * @return {Object} label, score, threshold percent, tooltip text */ function socialMap(item) { @@ -161,6 +168,7 @@ function allReady(thresholds, sampleText) { /** * Make sure height of sentences view is same as filters view + * @return {undefined} */ function matchSentenceViewsHeight() { $('.sentences--sentence-views').css('height', $('.sentences--filters')[0].getBoundingClientRect().height + 'px'); @@ -168,6 +176,7 @@ function allReady(thresholds, sampleText) { /** * Toggle sentence rank, Emit view update + * @return {undefined} */ function toggleSort() { app.toggleLowToHigh(); @@ -176,10 +185,11 @@ function allReady(thresholds, sampleText) { /** * Select tone, Emit view update - * @param {String} tone name + * @param {String} toneName tone name + * @return {undefined} */ - function clickFilter(tone_name) { - app.selectedFilter(tone_name); + function clickFilter(toneName) { + app.selectedFilter(toneName); updateOriginalText(); updateSentenceRank(); updateLegend(); @@ -187,6 +197,7 @@ function allReady(thresholds, sampleText) { /** * Select right filter + * @return {undefined} */ function updateFilters() { $('.filters--radio[data-id=' + app.selectedFilter() + ']').prop('checked', true); @@ -194,6 +205,7 @@ function allReady(thresholds, sampleText) { /** * Emit view update for original text view + * @return {undefined} */ function updateOriginalText() { $originalTexts.html(_.template(originalText_template, { @@ -203,6 +215,7 @@ function allReady(thresholds, sampleText) { /** * Emit view update for sentence rank view + * @return {undefined} */ function updateSentenceRank() { $sentenceRankTable.html(_.template(sentenceRank_template, { @@ -212,7 +225,8 @@ function allReady(thresholds, sampleText) { /** * Update original text tooltip positioning - * @param {Object} event data object + * @param {Object} e event data object + * @return {undefined} */ function positionOriginalTextTooltip(e) { var element = app.currentHoveredOriginalSentence(), @@ -221,8 +235,9 @@ function allReady(thresholds, sampleText) { top = box.top, left = box.left + originalText.getBoundingClientRect().width * 0.05; - if (e !== undefined) + if (typeof (e) !== 'undefined') { left = e.clientX; + } $originalTextTooltipContainer.css({ 'top': top, 'left': left @@ -232,6 +247,7 @@ function allReady(thresholds, sampleText) { /** * Emit view update for original text tooltip view * @param {int} index of currently hovering original sentence element + * @return {undefined} */ function updateOriginalTextTooltip(index) { $originalTextTooltipContainer.html(_.template(originalTextTooltip_template, { @@ -242,6 +258,7 @@ function allReady(thresholds, sampleText) { /** * Emit view update for legend view + * @return {undefined} */ function updateLegend() { $legend.html(_.template(originalTextLegend_template, { @@ -252,6 +269,7 @@ function allReady(thresholds, sampleText) { /** * Bind original text view hover events for original text tooltip * interactions + * @return {undefined} */ function bindOriginalTextHoverEvents() { $('.original-text--sentence-container').click(function(e) { @@ -278,40 +296,41 @@ function allReady(thresholds, sampleText) { } }); - $(document).scroll(function(e) { + $(document).scroll(function() { $originalTextTooltipContainer.addClass('original-text--tooltip-container_hidden'); }); - // - $('.original-text--texts-container').scroll(function(e) { + + $('.original-text--texts-container').scroll(function() { $originalTextTooltipContainer.addClass('original-text--tooltip-container_hidden'); }); } /** * Emit view update for json view sentence tones - * @param {Object} data + * @return {undefined} */ - function updateJSONSentenceTones(data) { + function updateJSONSentenceTones() { $sentenceJson.empty(); - $sentenceJson.html(JSON.stringify({'sentences_tone' : data['sentences_tone']}, null, 2)); + $sentenceJson.html(JSON.stringify({'sentences_tone': data.sentences_tone}, null, 2)); } /** * Emit view update for json view sentence tones - * @param {Object} data + * @return {undefined} */ - function updateJSONDocumentTones(data) { + function updateJSONDocumentTones() { $summaryJsonCode.empty(); - $summaryJsonCode.html(JSON.stringify({'document_tone' : data['document_tone']}, null, 2)); + $summaryJsonCode.html(JSON.stringify({'document_tone': data.document_tone}, null, 2)); } /** * Emit view update for json view - * @param {Object} data + * @param {Object} jdonData The data + * @return {undefined} */ - function updateJSON(data) { - updateJSONSentenceTones(data); - updateJSONDocumentTones(data); + function updateJSON(jdonData) { + updateJSONSentenceTones(jdonData); + updateJSONDocumentTones(jdonData); } app.selectFilterBySample(); @@ -368,16 +387,18 @@ function allReady(thresholds, sampleText) { /** * AJAX Post request on error callback - * @param {Object} error + * @param {Object} error The error + * @return {undefined} */ function _error(error) { var message = typeof error.responseJSON.error === 'string' ? error.responseJSON.error : 'Error code ' + error.responseJSON.error.code + ': ' + error.responseJSON.error.message; - if (error.responseJSON.code === 429) + if (error.responseJSON.code === 429) { message = 'You\'ve sent a lot of requests in a short amount of time. ' + 'As the CPU cores cool off a bit, wait a few seonds before sending more requests.'; + } $errorMessage.html(message); $input.show(); $loading.hide(); @@ -388,7 +409,8 @@ function allReady(thresholds, sampleText) { /** * AJAX Post request for tone analyzer api - * @param {String} request body text + * @param {String} text request body text + * @return {undefined} */ function getToneAnalysis(text) { $.post('/api/tone', {'text': text }, toneCallback) @@ -397,7 +419,8 @@ function allReady(thresholds, sampleText) { /** * Emit view update for input text area view - * @param {String} sample text id + * @param {String} value sample text id + * @return {undefined} */ function updateTextarea(value) { $textarea.val(sampleText[value]); @@ -405,6 +428,7 @@ function allReady(thresholds, sampleText) { /** * Reset views to beginning state + * @return {undefined} */ function reset() { $input.show();