From 55a702882870b0de707599facfe2273c4c3b8001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Menrath=20Andr=C3=A9?= Date: Wed, 11 May 2022 12:16:11 +0200 Subject: [PATCH] add wordlimit indicator --- .github/workflows/ci.yml | 24 +-- CHANGES.md | 8 +- README.md | 8 +- classes/privacy/provider.php | 2 - classes/wordlimit.php | 131 +++++++++++++++ lib.php | 15 +- scss/styles.scss | 42 +++-- styles.css | 51 +++++- tests/behat/wordcount.feature | 157 ++++++++++++++++++ version.php | 8 +- .../moodle-atto_wordcount-button-debug.js | 58 ++++++- .../moodle-atto_wordcount-button-min.js | 2 +- .../moodle-atto_wordcount-button.js | 58 ++++++- yui/src/button/js/button.js | 58 ++++++- 14 files changed, 550 insertions(+), 72 deletions(-) create mode 100644 classes/wordlimit.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3ffab8..6f8e55f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,22 +38,14 @@ jobs: fail-fast: false matrix: include: - - {moodle-branch: 'MOODLE_39_STABLE', php: '7.2', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'MOODLE_39_STABLE', php: '7.2', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'MOODLE_39_STABLE', php: '7.3', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'MOODLE_39_STABLE', php: '7.3', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'MOODLE_39_STABLE', php: '7.4', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'MOODLE_39_STABLE', php: '7.4', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'MOODLE_310_STABLE', php: '7.4', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'MOODLE_310_STABLE', php: '7.4', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'MOODLE_311_STABLE', php: '7.4', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'MOODLE_311_STABLE', php: '7.4', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'MOODLE_311_STABLE', php: '8.0', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'MOODLE_311_STABLE', php: '8.0', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'master', php: '7.4', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'master', php: '7.4', node: '16.14.2', database: 'pgsql'} - - {moodle-branch: 'master', php: '8.0', node: '16.14.2', database: 'mariadb'} - - {moodle-branch: 'master', php: '8.0', node: '16.14.2', database: 'pgsql'} + - {moodle-branch: 'MOODLE_311_STABLE', php: '7.4', node: '14.18.0', database: 'mariadb'} + - {moodle-branch: 'MOODLE_311_STABLE', php: '7.4', node: '14.18.0', database: 'pgsql'} + - {moodle-branch: 'MOODLE_311_STABLE', php: '8.0', node: '14.18.0', database: 'mariadb'} + - {moodle-branch: 'MOODLE_311_STABLE', php: '8.0', node: '14.18.0', database: 'pgsql'} + - {moodle-branch: 'MOODLE_400_STABLE', php: '7.4', node: '14.18.0', database: 'mariadb'} + - {moodle-branch: 'MOODLE_400_STABLE', php: '7.4', node: '14.18.0', database: 'pgsql'} + - {moodle-branch: 'MOODLE_400_STABLE', php: '8.0', node: '14.18.0', database: 'mariadb'} + - {moodle-branch: 'MOODLE_400_STABLE', php: '8.0', node: '14.18.0', database: 'pgsql'} steps: - name: Check out repository code diff --git a/CHANGES.md b/CHANGES.md index 8125a42..d33493f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,7 @@ -## [1.1.2] - 2022-03-19 +## [1.1.2] - 2022-05-11 ### Changed -- Stylesheet for fix ui for atto in Moodle 4.0 -- Fix behat test to support Moodle 4.0 +- Moodle 3.11+ required +- Added wordlimit indicator for assignments and quizs ## [1.1.0] - 2022-02-01 ### Changed @@ -11,7 +11,7 @@ ### Added - Add stylesheets for bottom toolbar -### Changed +### Changed - Update the release workflow to new one with token - Fix screen reader only view on question editor diff --git a/README.md b/README.md index 815b42d..1eb8b98 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ Add "real time" words count to Moodle Atto editor, By enable this Atto plugin th The count is change will the user type or change the Atto editor content. You can see examples in the screenshots bellow. + ## Requirements -- Moodle 2.7 or later. +- Moodle 3.11 or later. ## Installation 1. Add the plugin to /lib/editor/atto/plugins @@ -16,12 +17,15 @@ You can see examples in the screenshots bellow. ## Records Thanks to the Hebrew University Of Jerusalem that sponsor this plugin development. ![Hebrew University Of Jerusalem](https://moodle.org/pluginfile.php/50/local_plugins/plugin_description/2743/logo-ltr.png) + ## Author Avi Levy (avi@sysbind.co.il) ![SysBind](https://moodle.org/pluginfile.php/50/local_plugins/plugin_description/2743/Sysbind-Moodle-Partner-Landscape.png) -## License ## +André Menrath (andre.menrath@uni-graz.at) +## License ## 2021 SysBind +2022 University of Graz This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php index 6e0eea2..36ce2b5 100644 --- a/classes/privacy/provider.php +++ b/classes/privacy/provider.php @@ -24,8 +24,6 @@ namespace atto_wordcount\privacy; -defined('MOODLE_INTERNAL') || die(); - /** * Privacy Subsystem for atto_wordcount implementing null_provider. * diff --git a/classes/wordlimit.php b/classes/wordlimit.php new file mode 100644 index 0000000..b1fa120 --- /dev/null +++ b/classes/wordlimit.php @@ -0,0 +1,131 @@ +. + +/** + * atto_wordcount extensions for fetching wordlimits. + * + * @package atto_wordcount + * @copyright 2022 André Menrath + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace atto_wordcount; + +/** + * Collection of functions thich get the wordlimit for the text written in atto if it is set. + * + * @copyright 2022 André Menrath + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class wordlimit { + + /** + * Get the wordlimit for an onlinesubmission in an essay. + * + * @param string $assignmentid the instance-id of the assignment + * @return string $wordlimit + */ + protected static function get_wordlimit_for_onlinesubmission($assignmentid) { + // Get settings from onlinepage submission plugin: Check if the wordlimit is enabled. + global $DB; + $wordlimitenabled = $DB->get_record( + 'assign_plugin_config', + array( + 'assignment' => $assignmentid, + 'name' => 'wordlimitenabled' + ), + 'value', + MUST_EXIST, + ); + // If the wordlimit is enabled get the word limit and pass it to the javascript module. + if ( '1' === $wordlimitenabled->value ) { + $wordlimit = $DB->get_record( + 'assign_plugin_config', + array( + 'assignment' => $assignmentid, + 'name' => 'wordlimit' + ), + 'value', + MUST_EXIST, + ); + return $wordlimit->value; + } + return null; + } + + /** + * Get the wordlimits for an essay of a certain page inside a quiz. + * + * @param int $attempdid the attempd-id of the quiz + * @param string $page the number of the page as in the database, offset +1 in the frontend. + * @return array $wordlimits + */ + protected static function get_wordlimits_for_essay_in_quiz($attempdid, $page) { + global $DB; + // Make a database query to see if a maxwordlimit is set on this question. + // We need to also select slot, because the slot is unique here: there might be multiple + // editors with the same wordlimit on the same page, and then only the first would be returned. + $sql = "SELECT {question_attempts}.slot, {qtype_essay_options}.maxwordlimit + FROM {qtype_essay_options} + JOIN {question_attempts} ON {question_attempts}.questionid = {qtype_essay_options}.questionid + JOIN {quiz_attempts} ON {quiz_attempts}.uniqueid = {question_attempts}.questionusageid + JOIN {quiz_slots} ON {quiz_slots}.quizid = {quiz_attempts}.quiz AND {quiz_slots}.slot = {question_attempts}.slot + WHERE {quiz_attempts}.id = ? AND {quiz_slots}.page = ? + ORDER BY slot;"; + $wordlimits = $DB->get_records_sql( $sql, array( $attempdid, $page ) ); + $wordlimits = array_column( $wordlimits, 'maxwordlimit' ); + return $wordlimits; + } + + /** + * Get the wordlimit depending on the type of page which is beein edited. + * + * @return array $wordlimits + */ + public static function get_wordlimits() { + + global $PAGE; + + // Define the parameter array which is served to the javascript of the plugin. + $wordlimits = array( null ); + + $path = $PAGE->url->get_path(); + + // Check if we are on a page where the users submits/edits an onlinetext for an assignment. + $action = optional_param('action', null, PARAM_ALPHANUMEXT); + if ( '/mod/assign/view.php' === $path && 'editsubmission' === $action ) { + $id = $PAGE->cm->instance; + $wordlimit = self::get_wordlimit_for_onlinesubmission($id); + // We have to pass wordlimits as an array. + $wordlimits = array( 0 => $wordlimit); + // We can return now and don't need to check for a quiz page. + return $wordlimits; + } + + if ( '/mod/quiz/attempt.php' === $path && "mod-quiz-attempt" === $PAGE->pagetype ) { + // The attempt id is a required parameter for the quiz/attemp.php page. + $attemptid = required_param('attempt', PARAM_INT); + // See on which page of the quiz we are. + $page = optional_param('page', 0, PARAM_INT); + // The page in the URL Params is starting with zero, in the database they start with 1. So there is an offset. + $page = $page + 1; + $wordlimits = self::get_wordlimits_for_essay_in_quiz( $attemptid, $page ); + } + + return $wordlimits; + } + +} diff --git a/lib.php b/lib.php index 1b680d2..f98f6c0 100644 --- a/lib.php +++ b/lib.php @@ -19,10 +19,10 @@ * * @package atto_wordcount * @copyright Avi Levy + * 2022 André Menrath * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); /** * Initialise the js strings required for this module. @@ -32,3 +32,16 @@ function atto_wordcount_strings_for_js() { $PAGE->requires->strings_for_js(['words', 'wordscount'], 'atto_wordcount'); } + + +/** + * Pass the wordlimits to the js part of the plugin. + * + * @return array $params. + */ +function atto_wordcount_params_for_js() { + $wordlimits = atto_wordcount\wordlimit::get_wordlimits(); + // Wrapp the wordlimits into an array whith wordlimits as the key. + $params = array ( 'wordlimits' => $wordlimits ); + return $params; +} diff --git a/scss/styles.scss b/scss/styles.scss index 829df76..e2737e8 100644 --- a/scss/styles.scss +++ b/scss/styles.scss @@ -18,19 +18,41 @@ body.path-question-type { } .editor_atto_wrap { - .editor_atto_content_wrap { - .editor_atto_content.form-control { - border-radius: 0; - } - } .editor_atto_toolbar { &.editor_atto_toolbar_bottom { - font-size: 0.7rem; + font-size: 0.8rem; min-height: unset; - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 0.5rem; - border-bottom-right-radius: 0.5rem; + justify-content: right; + background: inherit; + border: none; + .danger { + background-color: var(--danger); + color: #fff; + font-weight: bolder; + padding: 0 4px; + border-radius: 4px; + } + .warning { + background-color: var(--warning); + font-weight: normal; + padding: 0 4px; + border-radius: 4px; + } + .warning-icon { + align-items: center; + justify-content: center; + height: 100%; + display: none; + } + > div { + padding: 2px 5px; + > *:first-child { + margin: 0 0.2rem; + } + > * { + margin: 0 0.05rem; + } + } } } } diff --git a/styles.css b/styles.css index 082dfa1..6699bb3 100644 --- a/styles.css +++ b/styles.css @@ -8,15 +8,48 @@ body.path-question-type .form-group .sr-only:not(legend):not([for="id_category"] overflow: hidden; } -.editor_atto_wrap .editor_atto_content_wrap .editor_atto_content.form-control { - border-radius: 0; -} - .editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom { - font-size: 0.7rem; + font-size: 0.8rem; min-height: unset; - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 0.5rem; - border-bottom-right-radius: 0.5rem; + justify-content: right; + background: inherit; + border: none; +} + +.editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom .danger { + background-color: var(--danger); + color: #fff; + font-weight: bolder; + padding: 0 4px; + border-radius: 4px; +} + +.editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom .warning { + background-color: var(--warning); + font-weight: normal; + padding: 0 4px; + border-radius: 4px; +} + +.editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom .warning-icon { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + height: 100%; + display: none; +} + +.editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom > div { + padding: 2px 5px; +} + +.editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom > div > *:first-child { + margin: 0 0.2rem; +} + +.editor_atto_wrap .editor_atto_toolbar.editor_atto_toolbar_bottom > div > * { + margin: 0 0.05rem; } diff --git a/tests/behat/wordcount.feature b/tests/behat/wordcount.feature index a412213..b998fc7 100644 --- a/tests/behat/wordcount.feature +++ b/tests/behat/wordcount.feature @@ -20,6 +20,17 @@ Feature: Atto wordcount button other = html,wordcount """ And I press "Save changes" + And the following "courses" exist: + | fullname | shortname | category | groupmode | + | Course 1 | C1 | 0 | 1 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@example.com | + | student1 | Student | 1 | student1@example.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | @javascript Scenario: Count words on atto is Zero @@ -104,3 +115,149 @@ Feature: Atto wordcount button And I set the field "Loop" to "1" When I click on "Insert media" "button" Then I should see "Words: 430" + + @javascript + Scenario: Display wordcount in onlinesubmissions if wordlimit is not set + Given the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment name | + | intro | Submit your online text | + | submissiondrafts | 0 | + | assignsubmission_onlinetext_enabled | 1 | + | assignsubmission_onlinetext_wordlimit_enabled | 0 | + | assignsubmission_file_enabled | 0 | + And I am on the "Test assignment name" Activity page logged in as student1 + When I press "Add submission" + And I wait until the page is ready + And I set the following fields to these values: + | Online text | two words | + And I click on "Show more buttons" "button" + And I click on "HTML" "button" + When I click on "HTML" "button" + Then I should see "Words: 2" + + @javascript + Scenario: Display wordcount in onlinesubmissions if wordlimit is set + Given the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment name | + | intro | Submit your online text | + | submissiondrafts | 0 | + | assignsubmission_onlinetext_enabled | 1 | + | assignsubmission_onlinetext_wordlimit_enabled | 1 | + | assignsubmission_onlinetext_wordlimit | 8010 | + | assignsubmission_file_enabled | 0 | + And I am on the "Test assignment name" Activity page logged in as student1 + When I press "Add submission" + And I wait until the page is ready + And I set the following fields to these values: + | Online text | two words | + And I click on "Show more buttons" "button" + And I click on "HTML" "button" + When I click on "HTML" "button" + Then I should see "Words: 2/8010" + + @javascript + Scenario: Display wordcount in essay inside quiz if wordlimit is not set + Given the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | + And the following "questions" exist: + | questioncategory | qtype | name | template | maxwordenabled | maxwordlimit | + | Test questions | essay | essay1 | editor | 0 | 0 | + And quiz "Quiz 1" contains the following questions: + | question | page | + | essay1 | 1 | + And quiz "Quiz 1" contains the following sections: + | heading | firstslot | shuffle | + | Section 1 | 1 | 0 | + When I am on the "Quiz 1" "mod_quiz > View" page logged in as "student1" + And I press "Attempt quiz" + Then I should see "Section 1" in the "Quiz navigation" "block" + And I wait until the page is ready + And I set the following fields to these values: + | Answer text | I have already written six words! | + And I click on "Show more buttons" "button" + And I click on "HTML" "button" + When I click on "HTML" "button" + Then I should see "Words: 6" + + @javascript + Scenario: Display wordcount in essay inside quiz if wordlimit is set + Given the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | + And the following "questions" exist: + | questioncategory | qtype | name | template | maxwordenabled | maxwordlimit | + | Test questions | essay | essay1 | editor | 1 | 20 | + And quiz "Quiz 1" contains the following questions: + | question | page | + | essay1 | 1 | + And quiz "Quiz 1" contains the following sections: + | heading | firstslot | shuffle | + | Section 1 | 1 | 0 | + When I am on the "Quiz 1" "mod_quiz > View" page logged in as "student1" + And I press "Attempt quiz" + Then I should see "Section 1" in the "Quiz navigation" "block" + And I wait until the page is ready + And I set the following fields to these values: + | Answer text | I have already written nine out of twenty words | + And I click on "Show more buttons" "button" + And I click on "HTML" "button" + When I click on "HTML" "button" + Then I should see "Words: 9/20" + + @javascript + Scenario: Display wordcount in multiple essays inside quiz if wordlimit is sometimes set + Given the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | + And the following "questions" exist: + | questioncategory | qtype | name | questiontext | template | maxwordenabled | maxwordlimit | + | Test questions | essay | essay1 | Write not more than 111 words | editor | 1 | 111 | + | Test questions | essay | essay2 | Write as much as you want Nr1 | editor | 0 | 0 | + | Test questions | essay | essay3 | Write not more than 222 words | editor | 1 | 222 | + | Test questions | essay | essay4 | Write as much as you want Nr2 | editor | 0 | 0 | + | Test questions | essay | essay5 | Write not more than 333 words | editor | 0 | 0 | + | Test questions | essay | essay6 | Write as much as you want Nr2 | editor | 1 | 333 | + And quiz "Quiz 1" contains the following questions: + | question | page | + | essay1 | 1 | + | essay2 | 1 | + | essay3 | 1 | + | essay4 | 1 | + | essay5 | 2 | + | essay6 | 2 | + And quiz "Quiz 1" contains the following sections: + | heading | firstslot | shuffle | + | Section 1 | 1 | 0 | + | Section 2 | 5 | 0 | + When I am on the "Quiz 1" "mod_quiz > View" page logged in as "student1" + And I press "Attempt quiz" + Then I should see "Section 1" in the "Quiz navigation" "block" + And I wait until the page is ready + And I set the following fields to these values: + | Answer text | I have already written ten words out of 111 words! | + And I click on "Show more buttons" "button" + And I click on "HTML" "button" + When I click on "HTML" "button" + Then I should see "Words: 10/111" + When I click on "#quiznavbutton5" "css_element" + And I wait until the page is ready + And I set the following fields to these values: + | Answer text | I have written exaclty fourteen words so far out of as many i want | + And I click on "Show more buttons" "button" + And I click on "HTML" "button" + When I click on "HTML" "button" + Then I should see "Words: 14" diff --git a/version.php b/version.php index 52b7130..aa9d994 100644 --- a/version.php +++ b/version.php @@ -18,14 +18,16 @@ * atto_wordcount version file. * * @package atto_wordcount - * @copyright 2022 Avi Levy + * @copyright 2011 Avi Levy + * 2022 Graz University + * 2022 André Menrath * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2022031900; +$plugin->version = 2022051100; $plugin->requires = 2014051200; $plugin->component = 'atto_wordcount'; -$plugin->release = '1.1.2'; +$plugin->release = '1.2.0'; $plugin->maturity = MATURITY_STABLE; diff --git a/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-debug.js b/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-debug.js index 6c19285..965480e 100644 --- a/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-debug.js +++ b/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-debug.js @@ -17,7 +17,7 @@ YUI.add('moodle-atto_wordcount-button', function (Y, NAME) { /* * @package atto_wordcount - * @copyright 2022 Avi Levy 0 + * @copyright 2021 Avi Levy 0 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -27,13 +27,19 @@ YUI.add('moodle-atto_wordcount-button', function (Y, NAME) { /** * Atto text editor wordcount plugin. - * - * @namespace M.atto_wordcount - * @class button - * @extends M.editor_atto.EditorPlugin + * @package atto_wordcount + * @copyright 2021 Avi Levy + * 2022 André Menrath + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @namespace M.atto_wordcount + * @class button + * @extends M.editor_atto.EditorPlugin */ +// Global Variable which keeps track if more than one editor is on page, as possible inside a quiz. +var editorInstance = 0; + Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { block: 0, @@ -51,10 +57,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto this.counterElement = Y.Node.create('0'); wrapper.appendChild( Y.Node.create('
' + - '
' + '
' + M.util.get_string('words', 'atto_wordcount') + ': ' + '0' + '
')); + this.wordlimit = this.get('wordlimits')[editorInstance]; + if (this.wordlimit) { + var seperatorField = document.createElement('span'); + seperatorField.innerHTML = '/'; + document.getElementById(this.counterid).parentNode.appendChild(seperatorField); + var wordLimitField = document.createElement('span'); + wordLimitField.innerHTML = this.wordlimit; + document.getElementById(this.counterid).parentNode.appendChild(wordLimitField); + } + editorInstance += 1; this._count(host.get('editor')); this.get('host').on('pluginsloaded', function() { // Adds the current value to the stack. @@ -69,7 +85,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto wordcount.block = 1; setTimeout(function() { - Y.one('#' + wordcount.counterid).set('text', wordcount._getCount(editor)); + var currentCount = wordcount._getCount(editor); + Y.one('#' + wordcount.counterid).set('text', currentCount); + if (wordcount.wordlimit) { + if (wordcount.wordlimit - currentCount < 0) { + Y.one('#' + wordcount.counterid).addClass('danger'); + Y.one('#' + wordcount.counterid).removeClass('warning'); + } else if (wordcount.wordlimit - currentCount < 10) { + Y.one('#' + wordcount.counterid).addClass('warning'); + Y.one('#' + wordcount.counterid).removeClass('danger'); + } else { + Y.one('#' + wordcount.counterid).removeClass('warning'); + Y.one('#' + wordcount.counterid).removeClass('danger'); + } + } setTimeout(function() { wordcount.block = 0; }, wordcount.updateRate); @@ -93,7 +122,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto return wordCounts; } -}); +}, { + ATTRS: { + /** + * Whether or not to allow borders + * + * @attribute wordlimits + * @type Array + */ + wordlimits: { + value: [0] + }, + } +} +); }, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-min.js b/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-min.js index a111362..81116a3 100644 --- a/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-min.js +++ b/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button-min.js @@ -1 +1 @@ -YUI.add("moodle-atto_wordcount-button",function(o,t){o.namespace("M.atto_wordcount").Button=o.Base.create("button",o.M.editor_atto.EditorPlugin,[],{block:0,updateRate:200,counterid:null,spacer:/(<\/(?!a>|b>|del>|em>|i>|ins>|s>|small>|strong>|sub>|sup>|u>)\w+>|
| )/g,mediaTags:/(<(audio|video)).*(<\/(audio|video)>)/gm,counter:new RegExp("[\\p{Z}\\p{Cc}—–]+","gu"),initializer:function(){var t=this.get("host"),e=t._wrapper;this.counterid=t.get("elementid")+"-word-count",this.counterid=this.counterid.replace(":","-"),this.counterElement=o.Node.create('0'),e.appendChild(o.Node.create('
'+M.util.get_string("words","atto_wordcount")+': 0
')),this._count(t.get("editor")),this.get("host").on("pluginsloaded",function(){this.get("host").on("atto:selectionchanged",this._count,this)},this)},_count:function(t){var e=this;e.block||(e.block=1,setTimeout(function(){o.one("#"+e.counterid).set("text",e._getCount(t)),setTimeout(function(){e.block=0},e.updateRate)}))},_getCount:function(){var t,e=0,o=this.get("host").getCleanHTML();return e=o&&(t=(t=(o=(o=(o=o.replace(this.spacer,"$1 ")).replace(/<.[^<>]*?>/g,"")).replace(/ | /gi," ")).split(this.counter,-1)).filter(function(t){return""!=t.trim()}))?t.length:e}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file +YUI.add("moodle-atto_wordcount-button",function(o,t){var i=0;o.namespace("M.atto_wordcount").Button=o.Base.create("button",o.M.editor_atto.EditorPlugin,[],{block:0,updateRate:200,counterid:null,spacer:/(<\/(?!a>|b>|del>|em>|i>|ins>|s>|small>|strong>|sub>|sup>|u>)\w+>|
| )/g,mediaTags:/(<(audio|video)).*(<\/(audio|video)>)/gm,counter:new RegExp("[\\p{Z}\\p{Cc}—–]+","gu"),initializer:function(){var t=this.get("host"),e=t._wrapper;this.counterid=t.get("elementid")+"-word-count",this.counterid=this.counterid.replace(":","-"),this.counterElement=o.Node.create('0'),e.appendChild(o.Node.create('
'+M.util.get_string("words","atto_wordcount")+': 0
')),this.wordlimit=this.get("wordlimits")[i],this.wordlimit&&((e=document.createElement("span")).innerHTML="/",document.getElementById(this.counterid).parentNode.appendChild(e),(e=document.createElement("span")).innerHTML=this.wordlimit,document.getElementById(this.counterid).parentNode.appendChild(e)),i+=1,this._count(t.get("editor")),this.get("host").on("pluginsloaded",function(){this.get("host").on("atto:selectionchanged",this._count,this)},this)},_count:function(e){var i=this;i.block||(i.block=1,setTimeout(function(){var t=i._getCount(e);o.one("#"+i.counterid).set("text",t),i.wordlimit&&(i.wordlimit-t<0?(o.one("#"+i.counterid).addClass("danger"),o.one("#"+i.counterid).removeClass("warning")):(i.wordlimit-t<10?o.one("#"+i.counterid).addClass("warning"):o.one("#"+i.counterid).removeClass("warning"),o.one("#"+i.counterid).removeClass("danger"))),setTimeout(function(){i.block=0},i.updateRate)}))},_getCount:function(){var t,e=0,i=this.get("host").getCleanHTML();return e=i&&(t=(t=(i=(i=(i=i.replace(this.spacer,"$1 ")).replace(/<.[^<>]*?>/g,"")).replace(/ | /gi," ")).split(this.counter,-1)).filter(function(t){return""!=t.trim()}))?t.length:e}},{ATTRS:{wordlimits:{value:[0]}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button.js b/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button.js index 6c19285..965480e 100644 --- a/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button.js +++ b/yui/build/moodle-atto_wordcount-button/moodle-atto_wordcount-button.js @@ -17,7 +17,7 @@ YUI.add('moodle-atto_wordcount-button', function (Y, NAME) { /* * @package atto_wordcount - * @copyright 2022 Avi Levy 0 + * @copyright 2021 Avi Levy 0 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -27,13 +27,19 @@ YUI.add('moodle-atto_wordcount-button', function (Y, NAME) { /** * Atto text editor wordcount plugin. - * - * @namespace M.atto_wordcount - * @class button - * @extends M.editor_atto.EditorPlugin + * @package atto_wordcount + * @copyright 2021 Avi Levy + * 2022 André Menrath + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @namespace M.atto_wordcount + * @class button + * @extends M.editor_atto.EditorPlugin */ +// Global Variable which keeps track if more than one editor is on page, as possible inside a quiz. +var editorInstance = 0; + Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { block: 0, @@ -51,10 +57,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto this.counterElement = Y.Node.create('0'); wrapper.appendChild( Y.Node.create('
' + - '
' + '
' + M.util.get_string('words', 'atto_wordcount') + ': ' + '0' + '
')); + this.wordlimit = this.get('wordlimits')[editorInstance]; + if (this.wordlimit) { + var seperatorField = document.createElement('span'); + seperatorField.innerHTML = '/'; + document.getElementById(this.counterid).parentNode.appendChild(seperatorField); + var wordLimitField = document.createElement('span'); + wordLimitField.innerHTML = this.wordlimit; + document.getElementById(this.counterid).parentNode.appendChild(wordLimitField); + } + editorInstance += 1; this._count(host.get('editor')); this.get('host').on('pluginsloaded', function() { // Adds the current value to the stack. @@ -69,7 +85,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto wordcount.block = 1; setTimeout(function() { - Y.one('#' + wordcount.counterid).set('text', wordcount._getCount(editor)); + var currentCount = wordcount._getCount(editor); + Y.one('#' + wordcount.counterid).set('text', currentCount); + if (wordcount.wordlimit) { + if (wordcount.wordlimit - currentCount < 0) { + Y.one('#' + wordcount.counterid).addClass('danger'); + Y.one('#' + wordcount.counterid).removeClass('warning'); + } else if (wordcount.wordlimit - currentCount < 10) { + Y.one('#' + wordcount.counterid).addClass('warning'); + Y.one('#' + wordcount.counterid).removeClass('danger'); + } else { + Y.one('#' + wordcount.counterid).removeClass('warning'); + Y.one('#' + wordcount.counterid).removeClass('danger'); + } + } setTimeout(function() { wordcount.block = 0; }, wordcount.updateRate); @@ -93,7 +122,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto return wordCounts; } -}); +}, { + ATTRS: { + /** + * Whether or not to allow borders + * + * @attribute wordlimits + * @type Array + */ + wordlimits: { + value: [0] + }, + } +} +); }, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]}); diff --git a/yui/src/button/js/button.js b/yui/src/button/js/button.js index 3e62ec6..ae78dfd 100644 --- a/yui/src/button/js/button.js +++ b/yui/src/button/js/button.js @@ -15,7 +15,7 @@ /* * @package atto_wordcount - * @copyright 2022 Avi Levy 0 + * @copyright 2021 Avi Levy 0 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -25,13 +25,19 @@ /** * Atto text editor wordcount plugin. - * - * @namespace M.atto_wordcount - * @class button - * @extends M.editor_atto.EditorPlugin + * @package atto_wordcount + * @copyright 2021 Avi Levy + * 2022 André Menrath + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @namespace M.atto_wordcount + * @class button + * @extends M.editor_atto.EditorPlugin */ +// Global Variable which keeps track if more than one editor is on page, as possible inside a quiz. +var editorInstance = 0; + Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { block: 0, @@ -49,10 +55,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto this.counterElement = Y.Node.create('0'); wrapper.appendChild( Y.Node.create('
' + - '
' + '
' + M.util.get_string('words', 'atto_wordcount') + ': ' + '0' + '
')); + this.wordlimit = this.get('wordlimits')[editorInstance]; + if (this.wordlimit) { + var seperatorField = document.createElement('span'); + seperatorField.innerHTML = '/'; + document.getElementById(this.counterid).parentNode.appendChild(seperatorField); + var wordLimitField = document.createElement('span'); + wordLimitField.innerHTML = this.wordlimit; + document.getElementById(this.counterid).parentNode.appendChild(wordLimitField); + } + editorInstance += 1; this._count(host.get('editor')); this.get('host').on('pluginsloaded', function() { // Adds the current value to the stack. @@ -67,7 +83,20 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto wordcount.block = 1; setTimeout(function() { - Y.one('#' + wordcount.counterid).set('text', wordcount._getCount(editor)); + var currentCount = wordcount._getCount(editor); + Y.one('#' + wordcount.counterid).set('text', currentCount); + if (wordcount.wordlimit) { + if (wordcount.wordlimit - currentCount < 0) { + Y.one('#' + wordcount.counterid).addClass('danger'); + Y.one('#' + wordcount.counterid).removeClass('warning'); + } else if (wordcount.wordlimit - currentCount < 10) { + Y.one('#' + wordcount.counterid).addClass('warning'); + Y.one('#' + wordcount.counterid).removeClass('danger'); + } else { + Y.one('#' + wordcount.counterid).removeClass('warning'); + Y.one('#' + wordcount.counterid).removeClass('danger'); + } + } setTimeout(function() { wordcount.block = 0; }, wordcount.updateRate); @@ -91,4 +120,17 @@ Y.namespace('M.atto_wordcount').Button = Y.Base.create('button', Y.M.editor_atto return wordCounts; } -}); +}, { + ATTRS: { + /** + * Whether or not to allow borders + * + * @attribute wordlimits + * @type Array + */ + wordlimits: { + value: [0] + }, + } +} +);