From 2acb885c727050f773cf736dd4f7f5b7f0a97ead Mon Sep 17 00:00:00 2001 From: Joe <33972521+hnb-ku@users.noreply.github.com> Date: Mon, 15 Oct 2018 10:59:49 +0800 Subject: [PATCH] FEATURE: fullscreen composer mode on desktop Adds keyboard shortcut and icon that allows expanding composer to full screen. --- .../components/composer-messages.js.es6 | 2 +- .../components/composer-toggles.js.es6 | 28 ++-- .../discourse/controllers/composer.js.es6 | 27 +++- .../discourse/lib/keyboard-shortcuts.js.es6 | 8 + .../discourse/models/composer.js.es6 | 22 ++- .../templates/components/composer-toggles.hbs | 10 +- .../discourse/templates/composer.hbs | 146 +++++++++--------- .../modal/keyboard-shortcuts-help.hbs | 1 + .../stylesheets/common/base/compose.scss | 2 +- app/assets/stylesheets/desktop/compose.scss | 50 ++++++ config/locales/client.en.yml | 3 + 11 files changed, 209 insertions(+), 90 deletions(-) diff --git a/app/assets/javascripts/discourse/components/composer-messages.js.es6 b/app/assets/javascripts/discourse/components/composer-messages.js.es6 index cf0fdaad8fc..1ac68616f8e 100644 --- a/app/assets/javascripts/discourse/components/composer-messages.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-messages.js.es6 @@ -13,7 +13,7 @@ export default Ember.Component.extend({ _yourselfConfirm: null, similarTopics: null, - hidden: Ember.computed.not("composer.viewOpen"), + hidden: Ember.computed.not("composer.viewOpenOrFullscreen"), didInsertElement() { this._super(); diff --git a/app/assets/javascripts/discourse/components/composer-toggles.js.es6 b/app/assets/javascripts/discourse/components/composer-toggles.js.es6 index 918cfe2baba..e1172df2e29 100644 --- a/app/assets/javascripts/discourse/components/composer-toggles.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-toggles.js.es6 @@ -4,18 +4,28 @@ export default Ember.Component.extend({ tagName: "", @computed("composeState") - title(composeState) { - if (composeState === "draft" || composeState === "saving") { - return "composer.abandon"; - } - return "composer.collapse"; + toggleTitle(composeState) { + return composeState === "draft" || composeState === "saving" + ? "composer.abandon" + : "composer.collapse"; + }, + + @computed("composeState") + fullscreenTitle(composeState) { + return composeState === "fullscreen" + ? "composer.exit_fullscreen" + : "composer.enter_fullscreen"; }, @computed("composeState") toggleIcon(composeState) { - if (composeState === "draft" || composeState === "saving") { - return "times"; - } - return "chevron-down"; + return composeState === "draft" || composeState === "saving" + ? "times" + : "chevron-down"; + }, + + @computed("composeState") + fullscreenIcon(composeState) { + return composeState === "fullscreen" ? "compress" : "expand"; } }); diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 1a6bf47dd0f..8a0946c5e9d 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -231,7 +231,7 @@ export default Ember.Controller.extend({ @computed("model.composeState", "model.creatingTopic") popupMenuOptions(composeState) { - if (composeState === "open") { + if (composeState === "open" || composeState === "fullscreen") { let options = []; options.push( @@ -386,7 +386,10 @@ export default Ember.Controller.extend({ ) { this.close(); } else { - if (this.get("model.composeState") === Composer.OPEN) { + if ( + this.get("model.composeState") === Composer.OPEN || + this.get("model.composeState") === Composer.FULLSCREEN + ) { this.shrink(); } else { this.cancelComposer(); @@ -396,6 +399,11 @@ export default Ember.Controller.extend({ return false; }, + fullscreenComposer() { + this.toggleFullscreen(); + return false; + }, + // Import a quote from the post importQuote(toolbarEvent) { const postStream = this.get("topic.postStream"); @@ -457,7 +465,7 @@ export default Ember.Controller.extend({ return; } - if (this.get("model.viewOpen")) { + if (this.get("model.viewOpen") || this.get("model.viewFullscreen")) { this.shrink(); } }, @@ -881,6 +889,10 @@ export default Ember.Controller.extend({ } ]); } else { + // in case the composer is + // cancelled while in fullscreen + $("html").removeClass("fullscreen-composer"); + // it is possible there is some sort of crazy draft with no body ... just give up on it this.destroyDraft(); this.get("model").clearState(); @@ -947,6 +959,15 @@ export default Ember.Controller.extend({ this.set("model.composeState", Composer.DRAFT); }, + toggleFullscreen() { + this._saveDraft(); + if (this.get("model.composeState") === Composer.FULLSCREEN) { + this.set("model.composeState", Composer.OPEN); + } else { + this.set("model.composeState", Composer.FULLSCREEN); + } + }, + close() { this.setProperties({ model: null, lastValidatedAt: null }); }, diff --git a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 index 01b9e3372e3..31f1c9a2140 100644 --- a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 +++ b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 @@ -65,6 +65,7 @@ const bindings = { "shift+s": { click: "#topic-footer-buttons button.share", anonymous: true }, // share topic "shift+u": { handler: "goToUnreadPost" }, "shift+z shift+z": { handler: "logout" }, + "shift+f11": { handler: "fullscreenComposer" }, t: { postAction: "replyAsNewTopic" }, u: { handler: "goBack", anonymous: true }, "x r": { @@ -212,6 +213,13 @@ export default { } }, + fullscreenComposer() { + const composer = this.container.lookup("controller:composer"); + if (composer.get("model")) { + composer.toggleFullscreen(); + } + }, + pinUnpinTopic() { this.container.lookup("controller:topic").togglePinnedState(); }, diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 483bb66eef7..a86e48de2d3 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -26,6 +26,7 @@ const CLOSED = "closed", SAVING = "saving", OPEN = "open", DRAFT = "draft", + FULLSCREEN = "fullscreen", // When creating, these fields are moved into the post model from the composer model _create_serializer = { raw: "reply", @@ -144,15 +145,24 @@ const Composer = RestModel.extend({ viewOpen: Em.computed.equal("composeState", OPEN), viewDraft: Em.computed.equal("composeState", DRAFT), + viewFullscreen: Em.computed.equal("composeState", FULLSCREEN), + viewOpenOrFullscreen: Em.computed.or("viewOpen", "viewFullscreen"), composeStateChanged: function() { - var oldOpen = this.get("composerOpened"); + let oldOpen = this.get("composerOpened"), + elem = $("html"); + + if (this.get("composeState") === FULLSCREEN) { + elem.addClass("fullscreen-composer"); + } else { + elem.removeClass("fullscreen-composer"); + } if (this.get("composeState") === OPEN) { this.set("composerOpened", oldOpen || new Date()); } else { if (oldOpen) { - var oldTotal = this.get("composerTotalOpened") || 0; + let oldTotal = this.get("composerTotalOpened") || 0; this.set("composerTotalOpened", oldTotal + (new Date() - oldOpen)); } this.set("composerOpened", null); @@ -160,9 +170,8 @@ const Composer = RestModel.extend({ }.observes("composeState"), composerTime: function() { - var total = this.get("composerTotalOpened") || 0; - - var oldOpen = this.get("composerOpened"); + let total = this.get("composerTotalOpened") || 0, + oldOpen = this.get("composerOpened"); if (oldOpen) { total += new Date() - oldOpen; } @@ -183,7 +192,7 @@ const Composer = RestModel.extend({ // view detected user is typing typing: _.throttle( function() { - var typingTime = this.get("typingTime") || 0; + let typingTime = this.get("typingTime") || 0; this.set("typingTime", typingTime + 100); }, 100, @@ -1041,6 +1050,7 @@ Composer.reopenClass({ SAVING, OPEN, DRAFT, + FULLSCREEN, // The actions the composer can take CREATE_TOPIC, diff --git a/app/assets/javascripts/discourse/templates/components/composer-toggles.hbs b/app/assets/javascripts/discourse/templates/components/composer-toggles.hbs index 93263ae3cbe..a9efe1f6d58 100644 --- a/app/assets/javascripts/discourse/templates/components/composer-toggles.hbs +++ b/app/assets/javascripts/discourse/templates/components/composer-toggles.hbs @@ -10,5 +10,13 @@ class="toggler" icon=toggleIcon action=toggleComposer - title=title}} + title=toggleTitle}} + + {{#unless site.mobileView}} + {{flat-button + class="toggle-fullscreen" + icon=fullscreenIcon + action=toggleFullscreen + title=fullscreenTitle}} + {{/unless}} diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index dc71db36f76..d60ed2e804d 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -9,73 +9,77 @@ {{composer-messages composer=model messageCount=messageCount addLinkLookup="addLinkLookup"}} - {{#if model.viewOpen}} + {{#if model.viewOpenOrFullscreen}}
{{plugin-outlet name="composer-open" args=(hash model=model)}}
-
- {{composer-action-title model=model canWhisper=canWhisper tabindex=8}} + {{#unless model.viewFullscreen}} +
+ {{composer-action-title model=model canWhisper=canWhisper tabindex=8}} - {{#unless site.mobileView}} - {{#if whisperOrUnlistTopicText}} - ({{whisperOrUnlistTopicText}}) - {{/if}} - {{#if model.noBump}} - {{d-icon "anchor"}} - {{/if}} - {{/unless}} + {{#unless site.mobileView}} + {{#if whisperOrUnlistTopicText}} + ({{whisperOrUnlistTopicText}}) + {{/if}} + {{#if model.noBump}} + {{d-icon "anchor"}} + {{/if}} + {{/unless}} - {{#if canEdit}} - {{#link-to-input onClick=(action "displayEditReason") showInput=showEditReason key="composer.show_edit_reason" class="display-edit-reason"}} - {{text-field value=editReason tabindex="7" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}} - {{/link-to-input}} - {{/if}} -
+ {{#if canEdit}} + {{#link-to-input onClick=(action "displayEditReason") showInput=showEditReason key="composer.show_edit_reason" class="display-edit-reason"}} + {{text-field value=editReason tabindex="7" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}} + {{/link-to-input}} + {{/if}} +
+ {{/unless}} {{composer-toggles composeState=model.composeState toggleComposer=(action "toggle") - toggleToolbar=(action "toggleToolbar")}} + toggleToolbar=(action "toggleToolbar") + toggleFullscreen=(action "fullscreenComposer")}}
+ {{#unless model.viewFullscreen}} + {{#if model.canEditTitle}} + {{#if model.creatingPrivateMessage}} +
+ {{composer-user-selector topicId=topicModel.id + usernames=model.targetUsernames + hasGroups=model.hasTargetGroups + focusTarget=focusTarget + class="users-input"}} + {{#if showWarning}} + + {{/if}} +
+ {{/if}} - {{#if model.canEditTitle}} - {{#if model.creatingPrivateMessage}} -
- {{composer-user-selector topicId=topicModel.id - usernames=model.targetUsernames - hasGroups=model.hasTargetGroups - focusTarget=focusTarget - class="users-input"}} - {{#if showWarning}} - +
+ + {{composer-title composer=model lastValidatedAt=lastValidatedAt focusTarget=focusTarget}} + + {{#if model.showCategoryChooser}} +
+ {{category-chooser + fullWidthOnMobile=true + value=model.categoryId + scopedCategoryId=scopedCategoryId + tabindex="3"}} + {{popup-input-tip validation=categoryValidation}} +
+ {{/if}} + {{#if canEditTags}} + {{mini-tag-chooser tags=model.tags tabindex="4" categoryId=model.categoryId minimum=model.minimumRequiredTags}} + {{popup-input-tip validation=tagValidation}} {{/if}}
{{/if}} -
- - {{composer-title composer=model lastValidatedAt=lastValidatedAt focusTarget=focusTarget}} - - {{#if model.showCategoryChooser}} -
- {{category-chooser - fullWidthOnMobile=true - value=model.categoryId - scopedCategoryId=scopedCategoryId - tabindex="3"}} - {{popup-input-tip validation=categoryValidation}} -
- {{/if}} - {{#if canEditTags}} - {{mini-tag-chooser tags=model.tags tabindex="4" categoryId=model.categoryId minimum=model.minimumRequiredTags}} - {{popup-input-tip validation=tagValidation}} - {{/if}} -
- {{/if}} - - {{plugin-outlet name="composer-fields" args=(hash model=model)}} + {{plugin-outlet name="composer-fields" args=(hash model=model)}} + {{/unless}}
@@ -104,21 +108,24 @@ {{plugin-outlet name="composer-fields-below" args=(hash model=model)}}
- {{composer-save-button action=(action "save") - icon=model.saveIcon - label=model.saveLabel - disableSubmit=disableSubmit}} - {{#if site.mobileView}} - - {{#if canEdit}} - {{d-icon "times"}} - {{else}} - {{d-icon "trash-o"}} - {{/if}} - - {{else}} - {{i18n 'cancel'}} - {{/if}} + {{#unless model.viewFullscreen}} + {{composer-save-button action=(action "save") + icon=model.saveIcon + label=model.saveLabel + disableSubmit=disableSubmit}} + + {{#if site.mobileView}} + + {{#if canEdit}} + {{d-icon "times"}} + {{else}} + {{d-icon "trash-o"}} + {{/if}} + + {{else}} + {{i18n 'cancel'}} + {{/if}} + {{/unless}} {{#if site.mobileView}} @@ -165,7 +172,7 @@
- {{else}} + {{else}}
{{#if model.createdPost}} {{i18n 'composer.saved'}} @@ -183,6 +190,7 @@
{{composer-toggles composeState=model.composeState + toggleFullscreen=(action "fullscreenComposer") toggleComposer=(action "toggle") toggleToolbar=(action "toggleToolbar")}} diff --git a/app/assets/javascripts/discourse/templates/modal/keyboard-shortcuts-help.hbs b/app/assets/javascripts/discourse/templates/modal/keyboard-shortcuts-help.hbs index 9d5ae70e07c..58b432b06ad 100644 --- a/app/assets/javascripts/discourse/templates/modal/keyboard-shortcuts-help.hbs +++ b/app/assets/javascripts/discourse/templates/modal/keyboard-shortcuts-help.hbs @@ -40,6 +40,7 @@

{{i18n 'keyboard_shortcuts_help.composing.title'}}