diff --git a/.editorconfig b/.editorconfig index 47ae637..ee325e2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ -# For more information about the properties used in this file, -# please see the EditorConfig documentation: -# http://editorconfig.org +# For more information about the properties used in +# this file, please see the EditorConfig documentation: +# http://editorconfig.org/ [*] charset = utf-8 @@ -10,8 +10,17 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -[{*.yml,package.json}] -indent_size = 2 +[*.md] +trim_trailing_whitespace = false -# The indent size used in the package.json file cannot be changed: -# https://github.com/npm/npm/pull/3180#issuecomment-16336516 +[*.{yml,js,json,css,scss,feature}] +indent_size = 2 +indent_style = space + +[composer.json] +indent_size = 4 + +# Don't perform any clean-up on thirdparty files +[thirdparty/**] +trim_trailing_whitespace = false +insert_final_newline = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..f6a5eb5 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +# Ignore dist files +client/dist/ + +# Ignore legacy files +client/src/legacy/ + +# Ignore auto-generated language files +client/lang/ diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4b81cff --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@silverstripe/eslint-config/.eslintrc'); diff --git a/.nvmrc b/.nvmrc index 1e8b314..f599e28 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6 +10 diff --git a/.travis.yml b/.travis.yml index e7773f0..74ffa58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ matrix: - php: 7.2 env: DB=MYSQL INSTALLER_VERSION=4.3.x-dev PHPUNIT_TEST=1 - php: 7.3 - env: DB=MYSQL INSTALLER_VERSION=4.4.x-dev PHPUNIT_TEST=1 + env: DB=MYSQL INSTALLER_VERSION=4.4.x-dev PHPUNIT_TEST=1 NPM_TEST=1 - php: 7.3 env: DB=MYSQL INSTALLER_VERSION=4.x-dev PHPUNIT_TEST=1 @@ -23,11 +23,15 @@ before_script: - composer require silverstripe/installer:"$INSTALLER_VERSION" ezyang/htmlpurifier:* --no-update - if [[ $DB == PGSQL ]]; then composer require --no-update silverstripe/postgresql:2.2.x-dev; fi - composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile + - if [[ $NPM_TEST ]]; then nvm install $TRAVIS_NODE_VERSION && nvm use $TRAVIS_NODE_VERSION && npm install -g yarn && yarn install --network-concurrency 1 && yarn run build; fi script: - if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi - if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi - if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs src/ tests/ *.php; fi + - if [[ $NPM_TEST ]]; then git diff-files --quiet -w --relative=client; fi + - if [[ $NPM_TEST ]]; then git diff -w --no-color --relative=client; fi + - if [[ $NPM_TEST ]]; then yarn run lint; fi after_success: - if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi diff --git a/client/dist/js/CommentsInterface.js b/client/dist/js/CommentsInterface.js new file mode 100644 index 0000000..cb4976b --- /dev/null +++ b/client/dist/js/CommentsInterface.js @@ -0,0 +1 @@ +!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/legacy/CommentsInterface.js")}({"./client/src/legacy/CommentsInterface.js":function(e,t,n){"use strict";(function(e){!function(e){e(function(){e.validator.methods.url=function(e,t){return this.optional(t)||/^(?:(?:(?:https?|ftp):)?\/\/)?(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[\/?#]\S*)?$/i.test(e)},e(".comments-holder-container form").each(function(){e(this).validate({ignore:":hidden",errorClass:"required",errorElement:"span",invalidHandler:function(t,n){e("html, body").animate({scrollTop:e(n.errorList[0].element).offset().top-30},200)},errorPlacement:function(e,t){e.addClass("message").insertAfter(t)}})}),e(".comment").children(".info").not(window.document.location.hash).nextAll(".comment-replies-container").children(".comment-reply-form-holder").hide(),e(".comments-holder").on("click",".comment-reply-link",function(t){var n=e(".comment-reply-form-holder"),r="#"+e(this).attr("aria-controls"),o=e(r).closest(".comment-reply-form-holder");e(this).attr("aria-expanded",function(e,t){return"true"==t?"false":"true"}),t.preventDefault(),o.is(":visible")?n.slideUp():(n.not(o).slideUp(),o.slideDown())}),e(".comments-holder .comments-list").on("click","div.comment-moderation-options a",function(t){t.stopPropagation();var n=e(this);if(n.hasClass("delete")){var r=ss.i18n._t("CommentsInterface_singlecomment_ss.DELETE_CONFIRMATION");if(!window.confirm(r))return t.preventDefault(),!1}var o=n.parents(".comment:first");e.ajax({url:e(this).attr("href"),cache:!1,success:function(t){n.hasClass("ham")?(o.html(t),o.removeClass("spam")):n.hasClass("approve")?(o.html(t),o.removeClass("unmoderated")):n.hasClass("delete")?o.fadeOut(1e3,function(){o.remove(),0===e(".comments-holder .comments-list").children().length&&e(".no-comments-yet").show()}):n.hasClass("spam")&&o.html(t).addClass("spam")},failure:function(e){var t=ss.i18n._t("CommentsInterface_singlecomment_ss.AJAX_ERROR");alert(t)}}),t.preventDefault()})})}(e)}).call(t,n(0))},0:function(e,t){e.exports=jQuery}}); \ No newline at end of file diff --git a/client/dist/styles/cms.css b/client/dist/styles/cms.css new file mode 100644 index 0000000..f7a1920 --- /dev/null +++ b/client/dist/styles/cms.css @@ -0,0 +1 @@ +.cms table.ss-gridfield-table tr.spam{background-color:#ffd8d8}.cms table.ss-gridfield-table tr.spam:hover{background-color:#fff2f2} \ No newline at end of file diff --git a/css/styles/bundle.css b/client/dist/styles/comments.css similarity index 100% rename from css/styles/bundle.css rename to client/dist/styles/comments.css diff --git a/javascript/lang/en.js b/client/lang/en.js similarity index 100% rename from javascript/lang/en.js rename to client/lang/en.js diff --git a/client/lang/src/en.json b/client/lang/src/en.json new file mode 100644 index 0000000..827158c --- /dev/null +++ b/client/lang/src/en.json @@ -0,0 +1,4 @@ +{ + "CommentsInterface_singlecomment_ss.DELETE_CONFIRMATION": "Are you sure you want to delete this comment?", + "CommentsInterface_singlecomment_ss.AJAX_ERROR": "An error occurred whilst updating the comment", +} diff --git a/javascript/CommentsInterface.js b/client/src/legacy/CommentsInterface.js similarity index 100% rename from javascript/CommentsInterface.js rename to client/src/legacy/CommentsInterface.js diff --git a/css/cms.css b/client/src/styles/cms.scss similarity index 100% rename from css/cms.css rename to client/src/styles/cms.scss diff --git a/scss/comments.scss b/client/src/styles/comments.scss similarity index 100% rename from scss/comments.scss rename to client/src/styles/comments.scss diff --git a/composer.json b/composer.json index 08e7aae..d85c845 100644 --- a/composer.json +++ b/composer.json @@ -29,8 +29,8 @@ "dev-master": "3.x-dev" }, "expose": [ - "css", - "javascript", + "client/dist", + "client/lang", "thirdparty" ] }, diff --git a/css/comments.css b/css/comments.css deleted file mode 100644 index 19fa966..0000000 --- a/css/comments.css +++ /dev/null @@ -1,76 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }) -/******/ ]); \ No newline at end of file diff --git a/css/comments.css.map b/css/comments.css.map deleted file mode 100644 index 87afbf9..0000000 --- a/css/comments.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": "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", -"sources": ["../scss/comments.scss"], -"names": [], -"file": "comments.css" -} \ No newline at end of file diff --git a/package.json b/package.json index 3f33aba..44c43a0 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "test": "tests" }, "engines": { - "node": "^6.x" + "node": "^10.x" }, "scripts": { "build": "yarn && NODE_ENV=production webpack -p --bail --progress", @@ -32,21 +32,17 @@ "homepage": "https://github.com/silverstripe/silverstripe-comments", "dependencies": {}, "devDependencies": { - "@silverstripe/webpack-config": "^0.2.7", - "babel-core": "^6.7.4", + "@silverstripe/webpack-config": "^1.3", + "@silverstripe/eslint-config": "0.0.5", "babel-jest": "^19.0.0", "babel-preset-es2015": "^6.6.0", "babel-preset-es2016": "^6.24.1", "babel-preset-react": "^6.5.0", - "eslint": "^2.5.3", - "eslint-config-airbnb": "^6.2.0", - "eslint-plugin-react": "^4.2.3", "jest-cli": "^19.0.2", "react-addons-test-utils": "^15.3.1", "redux-logger": "^2.6.1", "redux-mock-store": "^1.2.3", - "redux-thunk": "^2.2.0", - "sass-lint": "^1.10.2" + "redux-thunk": "^2.2.0" }, "babel": { "presets": [ diff --git a/src/Extensions/CommentsExtension.php b/src/Extensions/CommentsExtension.php index 0a2132c..02ce049 100644 --- a/src/Extensions/CommentsExtension.php +++ b/src/Extensions/CommentsExtension.php @@ -468,8 +468,8 @@ class CommentsExtension extends DataExtension Requirements::javascript('//code.jquery.com/jquery-3.3.1.min.js'); Requirements::javascript('silverstripe/comments:thirdparty/jquery-validate/jquery.validate.min.js'); Requirements::javascript('silverstripe/admin:client/dist/js/i18n.js'); - Requirements::add_i18n_javascript('silverstripe/comments:javascript/lang'); - Requirements::javascript('silverstripe/comments:javascript/CommentsInterface.js'); + Requirements::add_i18n_javascript('silverstripe/comments:client/lang'); + Requirements::javascript('silverstripe/comments:client/dist/js/CommentsInterface.js'); } $controller = CommentingController::create(); @@ -554,7 +554,7 @@ class CommentsExtension extends DataExtension */ protected function updateModerationFields(FieldList $fields) { - Requirements::css('silverstripe/comments:css/cms.css'); + Requirements::css('silverstripe/comments:client/dist/styles/cms.css'); $newComments = $this->owner->AllComments()->filter('Moderated', 0); diff --git a/templates/CommentsInterface.ss b/templates/CommentsInterface.ss index fa891eb..b37f7d6 100755 --- a/templates/CommentsInterface.ss +++ b/templates/CommentsInterface.ss @@ -1,4 +1,4 @@ -<% require themedCSS('comments', 'comments') %> +<% require themedCSS('client/dist/styles/comments', 'comments') %> <% if $CommentsEnabled %>