From 2484ef93ed77607c11ec8fc178be6a8bdd5dcf6f Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 16 Jun 2016 18:05:15 +0800 Subject: [PATCH 1/6] Use ES6 arrow functions instead. --- app/assets/javascripts/discourse/controllers/composer.js.es6 | 2 +- app/assets/javascripts/discourse/lib/plugin-api.js.es6 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index bac746b3b..a52120b22 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -65,7 +65,7 @@ export default Ember.Controller.extend({ init() { this._super(); - addPopupMenuOptionsCallback(function() { + addPopupMenuOptionsCallback(() => { return { action: 'toggleWhisper', icon: 'eye-slash', diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index c97573fb4..1ccc1c067 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -231,7 +231,7 @@ class PluginApi { * Example: * * ``` - * api.addToolbarPopupMenuOptionsCallback(function() { + * api.addToolbarPopupMenuOptionsCallback(() => { * return { * action: 'toggleWhisper', * icon: 'eye-slash', From 5d9e6d239507827068b7d031fd5745ee7b96c0ca Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 16 Jun 2016 21:23:11 +0800 Subject: [PATCH 2/6] Push plugin options after default options. --- .../discourse/controllers/composer.js.es6 | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index a52120b22..6438e6e87 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -62,19 +62,6 @@ export default Ember.Controller.extend({ topic: null, linkLookup: null, - init() { - this._super(); - - addPopupMenuOptionsCallback(() => { - return { - action: 'toggleWhisper', - icon: 'eye-slash', - label: 'composer.toggle_whisper', - condition: "canWhisper" - }; - }); - }, - showToolbar: Em.computed({ get(){ const keyValueStore = this.container.lookup('key-value-store:main'); @@ -116,20 +103,35 @@ export default Ember.Controller.extend({ return popupMenuOptions ? popupMenuOptions.some(option => option.condition) : false; }, + _setupPopupMenuOption(callback) { + let option = callback(); + + if (option.condition) { + option.condition = this.get(option.condition); + } else { + option.condition = true; + } + + return option; + }, + @computed("model.composeState") popupMenuOptions(composeState) { if (composeState === 'open') { - return _popupMenuOptionsCallbacks.map(callback => { - let option = callback(); + let options = []; - if (option.condition) { - option.condition = this.get(option.condition); - } else { - option.condition = true; - } + options.push(this._setupPopupMenuOption(() => { + return { + action: 'toggleWhisper', + icon: 'eye-slash', + label: 'composer.toggle_whisper', + condition: "canWhisper" + }; + })); - return option; - }); + return options.concat(_popupMenuOptionsCallbacks.map(callback => { + return this._setupPopupMenuOption(callback); + })); } }, From 95a58b80d729071156103bf8adda7fe0fc7ce916 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 16 Jun 2016 21:23:58 +0800 Subject: [PATCH 3/6] Clicking on popup menu options should refocus on selected text. --- .../javascripts/discourse/components/composer-editor.js.es6 | 3 +++ app/assets/javascripts/discourse/components/d-editor.js.es6 | 1 + 2 files changed, 4 insertions(+) diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index add52b7f0..50572c40e 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -388,6 +388,9 @@ export default Ember.Component.extend({ left = replyWidth - popupWidth - 40; } + const selected = toolbarEvent.selected; + toolbarEvent.selectText(selected.start, selected.end - selected.start); + this.sendAction('showOptions', toolbarEvent, { position: "absolute", left, top }); }, diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index 9a4382a86..8f8d5397e 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -507,6 +507,7 @@ export default Ember.Component.extend({ const selected = this._getSelected(button.trimLeading); const toolbarEvent = { selected, + selectText: (from, length) => this._selectText(from, length), applySurround: (head, tail, exampleKey) => this._applySurround(selected, head, tail, exampleKey), applyList: (head, exampleKey) => this._applyList(selected, head, exampleKey), addText: text => this._addText(selected, text), From d4f03cc0e1ce0eb9dd44caf46f6a62b688c71bf9 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 16 Jun 2016 21:25:18 +0800 Subject: [PATCH 4/6] Add details to popup menu options. --- .../initializers/apply-details.js.es6 | 30 +++++++++++++++++-- .../config/locales/client.en.yml | 8 +++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 plugins/discourse-details/config/locales/client.en.yml diff --git a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 index 367607f8f..55421b68e 100644 --- a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 +++ b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 @@ -1,11 +1,35 @@ import { withPluginApi } from 'discourse/lib/plugin-api'; +function initializeDetails(api) { + api.decorateCooked($elem => $("details", $elem).details()); + + api.addToolbarPopupMenuOptionsCallback(() => { + return { + action: 'insertDetails', + icon: 'caret-right', + label: 'details.title' + }; + }); + + const ComposerController = api.container.lookup("controller:composer"); + + ComposerController.reopen({ + actions: { + insertDetails() { + this.get("toolbarEvent").applySurround( + "[details=", + `]${I18n.t("composer.details_text")}[/details]`, + "details_title") + ; + } + } + }); +} + export default { name: "apply-details", initialize() { - withPluginApi('0.1', api => { - api.decorateCooked($elem => $("details", $elem).details()); - }); + withPluginApi('0.1', initializeDetails); } }; diff --git a/plugins/discourse-details/config/locales/client.en.yml b/plugins/discourse-details/config/locales/client.en.yml new file mode 100644 index 000000000..d17c9a5c6 --- /dev/null +++ b/plugins/discourse-details/config/locales/client.en.yml @@ -0,0 +1,8 @@ +en: + js: + details: + title: Insert Details + composer: + details_title: Summary + details_text: "This text will be hidden" + From ff50e59c4fd181cf353d6e22bcad1ae04afc8201 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 17 Jun 2016 11:29:37 +0800 Subject: [PATCH 5/6] FIX: Surround passing in the wrong length. --- app/assets/javascripts/discourse/components/d-editor.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index 8f8d5397e..6ff564d54 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -461,7 +461,7 @@ export default Ember.Component.extend({ this.set('value', `${pre}${contents}${post}`); if (lines.length === 1 && tlen > 0) { - this._selectText(sel.start + hlen, contents.length - hlen - hlen); + this._selectText(sel.start + hlen, sel.value.length); } else { this._selectText(sel.start, contents.length); } From 45a5c2e8e617aa72559eec159db796f44a6d5b7c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 17 Jun 2016 13:27:14 +0800 Subject: [PATCH 6/6] Add acceptance tests for details button. --- .../acceptance/details-button-test.js.es6 | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 diff --git a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 new file mode 100644 index 000000000..a77e79ca9 --- /dev/null +++ b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 @@ -0,0 +1,96 @@ +import { acceptance } from "helpers/qunit-helpers"; + +acceptance('composer', { loggedIn: true }); + +function findTextarea() { + return find(".d-editor-input")[0]; +} + +test('details button', () => { + visit("/"); + + andThen(() => { + ok(exists('#create-topic'), 'the create button is visible'); + }); + + click('#create-topic'); + click('button.options'); + click('.popup-menu .fa-caret-right'); + + andThen(() => { + equal( + find(".d-editor-input").val(), + `[details=${I18n.t("composer.details_title")}]${I18n.t("composer.details_text")}[/details]`, + 'it should contain the right output' + ); + }); + + fillIn('.d-editor-input', "This is my title"); + + andThen(() => { + const textarea = findTextarea(); + textarea.selectionStart = 0; + textarea.selectionEnd = textarea.value.length; + }); + + click('button.options'); + click('.popup-menu .fa-caret-right'); + + andThen(() => { + equal( + find(".d-editor-input").val(), + `[details=This is my title]${I18n.t("composer.details_text")}[/details]`, + 'it should contain the right output' + ); + + const textarea = findTextarea(); + equal(textarea.selectionStart, 9, 'it should start highlighting at the right position'); + equal(textarea.selectionEnd, 25, 'it should end highlighting at the right position'); + }); + + fillIn('.d-editor-input', "Before some text in between After"); + + andThen(() => { + const textarea = findTextarea(); + textarea.selectionStart = 7; + textarea.selectionEnd = 28; + }); + + click('button.options'); + click('.popup-menu .fa-caret-right'); + + andThen(() => { + equal( + find(".d-editor-input").val(), + `Before [details=some text in between]${I18n.t("composer.details_text")}[/details] After`, + 'it should contain the right output' + ); + + const textarea = findTextarea(); + equal(textarea.selectionStart, 16, 'it should start highlighting at the right position'); + equal(textarea.selectionEnd, 36, 'it should end highlighting at the right position'); + }); + + fillIn('.d-editor-input', "Before\nsome text in between\nAfter"); + + andThen(() => { + const textarea = findTextarea(); + textarea.selectionStart = 7; + textarea.selectionEnd = 28; + }); + + click('button.options'); + click('.popup-menu .fa-caret-right'); + + andThen(() => { + equal( + find(".d-editor-input").val(), + `Before\n[details=some text in between]${I18n.t("composer.details_text")}[/details]\nAfter`, + 'it should contain the right output' + ); + + const textarea = findTextarea(); + equal(textarea.selectionStart, 16, 'it should start highlighting at the right position'); + equal(textarea.selectionEnd, 36, 'it should end highlighting at the right position'); + }); +});