Replaces toolbar popup-menu with select-kit

This commit is contained in:
Joffrey JAFFEUX 2017-12-13 10:49:32 +01:00 committed by GitHub
parent d5293aeae2
commit c1c31b99ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 250 additions and 172 deletions

View File

@ -108,14 +108,6 @@ export default Ember.Component.extend({
this._bindUploadTarget();
this.appEvents.trigger('composer:will-open');
if (this.site.mobileView) {
$(window).on('resize.composer-popup-menu', () => {
if (this.get('optionsVisible')) {
this.appEvents.trigger('popup-menu:open', this._optionsLocation());
}
});
}
},
@computed('composer.reply', 'composer.replyLength', 'composer.missingReplyCharacters', 'composer.minimumPostLength', 'lastValidatedAt')
@ -515,34 +507,6 @@ export default Ember.Component.extend({
this._firefoxPastingHack();
},
_optionsLocation() {
const composer = $("#reply-control");
const composerOffset = composer.offset();
const composerPosition = composer.position();
const buttonBarOffset = $('#reply-control .d-editor-button-bar').offset();
const optionsButton = $('#reply-control .d-editor-button-bar .options');
const popupMenu = $("#reply-control .popup-menu");
const popupWidth = popupMenu.outerWidth();
const popupHeight = popupMenu.outerHeight();
const headerHeight = $(".d-header").outerHeight();
let left = optionsButton.offset().left - composerOffset.left;
let top = buttonBarOffset.top - composerOffset.top - popupHeight + popupMenu.innerHeight();
if (top + composerPosition.top - headerHeight - popupHeight < 0) {
top += popupHeight + optionsButton.outerHeight();
}
if (left + popupWidth > composer.width()) {
left -= popupWidth - optionsButton.outerWidth();
}
return { position: "absolute", left, top };
},
// Believe it or not pasting an image in Firefox doesn't work without this code
_firefoxPastingHack() {
const uaMatch = navigator.userAgent.match(/Firefox\/(\d+)\.\d/);
@ -653,10 +617,6 @@ export default Ember.Component.extend({
});
if (this._enableAdvancedEditorPreviewSync()) this._teardownInputPreviewSync();
if (this.site.mobileView) {
$(window).off('resize.composer-popup-menu');
}
},
actions: {
@ -672,15 +632,10 @@ export default Ember.Component.extend({
this._resetUpload(true);
},
toggleOptions(toolbarEvent) {
if (this.get('optionsVisible')) {
this.sendAction('hideOptions');
} else {
const selected = toolbarEvent.selected;
toolbarEvent.selectText(selected.start, selected.end - selected.start);
this.sendAction('showOptions', toolbarEvent, this._optionsLocation());
}
onExpandPopupMenuOptions(toolbarEvent) {
const selected = toolbarEvent.selected;
toolbarEvent.selectText(selected.start, selected.end - selected.start);
this.sendAction('storeToolbarState', toolbarEvent);
},
togglePreview() {
@ -709,15 +664,14 @@ export default Ember.Component.extend({
sendAction: 'showUploadModal'
});
if (this.get("showPopupMenu")) {
toolbar.addButton({
id: 'options',
group: 'extras',
icon: 'gear',
title: 'composer.options',
sendAction: 'toggleOptions'
});
}
toolbar.addButton({
id: 'options',
group: 'extras',
icon: 'gear',
title: 'composer.options',
sendAction: 'onExpandPopupMenuOptions',
popupMenu: true
});
if (this.site.mobileView) {
toolbar.addButton({

View File

@ -123,7 +123,8 @@ class Toolbar {
icon: button.label ? null : button.icon || button.id,
action: button.action || 'toolbarButton',
perform: button.perform || function() { },
trimLeading: button.trimLeading
trimLeading: button.trimLeading,
popupMenu: button.popupMenu || false
};
if (button.sendAction) {

View File

@ -1,47 +0,0 @@
import { on } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNameBindings: ["visible::hidden", ":popup-menu", "extraClasses"],
@on('didInsertElement')
_setup() {
this.appEvents.on("popup-menu:open", this, "_changeLocation");
$('html').on(`keydown.popup-menu-${this.get('elementId')}`, () => {
this.sendAction('hide');
});
$('html').on(`mouseup.popup-menu-${this.get('elementId')}`, () => {
this.sendAction('hide');
});
},
@on('willDestroyElement')
_cleanup() {
$('html').off(`mouseup.popup-menu-${this.get('elementId')}`);
$('html').off(`keydown.popup-menu-${this.get('elementId')}`);
this.appEvents.off("popup-menu:open", this, "_changeLocation");
},
_changeLocation(location) {
const $this = this.$();
switch (location.position) {
case "absolute": {
$this.css({
position: "absolute",
top: location.top - $this.innerHeight() + 5,
left: location.left,
});
break;
}
case "fixed": {
$this.css({
position: "fixed",
top: location.top,
left: location.left - $this.innerWidth(),
});
break;
}
}
}
});

View File

@ -63,7 +63,6 @@ export default Ember.Controller.extend({
showEditReason: false,
editReason: null,
scopedCategoryId: null,
optionsVisible: false,
lastValidatedAt: null,
isUploading: false,
topic: null,
@ -160,11 +159,6 @@ export default Ember.Controller.extend({
return isStaffUser && this.siteSettings.enable_whispers && action === Composer.REPLY;
},
@computed("popupMenuOptions")
showPopupMenu(popupMenuOptions) {
return popupMenuOptions ? popupMenuOptions.some(option => option.condition) : false;
},
_setupPopupMenuOption(callback) {
let option = callback();
@ -225,6 +219,13 @@ export default Ember.Controller.extend({
},
actions: {
onPopupMenuAction(action) {
this.send(action);
},
storeToolbarState(toolbarEvent) {
this.set('toolbarEvent', toolbarEvent);
},
togglePreview() {
this.toggleProperty('showPreview');
@ -237,7 +238,6 @@ export default Ember.Controller.extend({
cancelled() {
this.send('hitEsc');
this.send('hideOptions');
},
addLinkLookup(linkLookup) {
@ -290,16 +290,6 @@ export default Ember.Controller.extend({
this.toggleProperty('showToolbar');
},
showOptions(toolbarEvent, loc) {
this.set('toolbarEvent', toolbarEvent);
this.appEvents.trigger('popup-menu:open', loc);
this.set('optionsVisible', true);
},
hideOptions() {
this.set('optionsVisible', false);
},
// Toggle the reply view
toggle() {
this.closeAutocomplete();

View File

@ -5,13 +5,15 @@
markdownOptions=markdownOptions
extraButtons="extraButtons"
importQuote="importQuote"
toggleOptions="toggleOptions"
showUploadModal="showUploadModal"
togglePreview="togglePreview"
validation=validation
loading=composer.loading
forcePreview=forcePreview
composerEvents=true}}
composerEvents=true
onExpandPopupMenuOptions="onExpandPopupMenuOptions"
onPopupMenuAction=onPopupMenuAction
popupMenuOptions=popupMenuOptions}}
{{#if site.mobileView}}
<input type="file" id="mobile-uploader" multiple />

View File

@ -13,8 +13,25 @@
<div class='d-editor-button-bar'>
{{#each toolbar.groups as |group|}}
{{#each group.buttons as |b|}}
{{d-button action=b.action actionParam=b translatedTitle=b.title label=b.label icon=b.icon class=b.className}}
{{#if b.popupMenu}}
{{toolbar-popup-menu-options
onPopupMenuAction=onPopupMenuAction
onExpand=(action b.action b)
title="composer.options"
headerIcon=b.icon
class=b.className
content=popupMenuOptions}}
{{else}}
{{d-button
action=b.action
actionParam=b
translatedTitle=b.title
label=b.label
icon=b.icon
class=b.className}}
{{/if}}
{{/each}}
{{#unless group.lastGroup}}
<div class='d-editor-spacer'></div>
{{/unless}}

View File

@ -6,19 +6,6 @@
save="save"}}
{{#if visible}}
{{#if showPopupMenu}}
{{#popup-menu visible=optionsVisible hide="hideOptions" title="composer.options"}}
{{#each popupMenuOptions as |option|}}
{{#if option.condition}}
<li>
{{d-button action=option.action icon=option.icon label=option.label}}
</li>
{{/if}}
{{/each}}
{{/popup-menu}}
{{/if}}
{{composer-messages composer=model
messageCount=messageCount
addLinkLookup="addLinkLookup"}}
@ -76,9 +63,6 @@
{{category-chooser value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}}
{{popup-input-tip validation=categoryValidation}}
</div>
{{#if model.archetype.hasOptions}}
{{d-button action="showOptions" label="topic.options"}}
{{/if}}
{{/if}}
{{#if canEditTags}}
{{tag-chooser tags=model.tags tabIndex="4" categoryId=model.categoryId}}
@ -96,7 +80,9 @@
composer=model
lastValidatedAt=lastValidatedAt
canWhisper=canWhisper
showPopupMenu=showPopupMenu
storeToolbarState="storeToolbarState"
onPopupMenuAction=(action "onPopupMenuAction")
popupMenuOptions=popupMenuOptions
draftStatus=model.draftStatus
isUploading=isUploading
isCancellable=isCancellable
@ -104,9 +90,6 @@
groupsMentioned="groupsMentioned"
cannotSeeMention="cannotSeeMention"
importQuote="importQuote"
showOptions="showOptions"
hideOptions="hideOptions"
optionsVisible=optionsVisible
togglePreview="togglePreview"
showToolbar=showToolbar
showUploadSelector="showUploadSelector"

View File

@ -21,7 +21,7 @@ export default SingleSelectComponent.extend({
},
didClickOutside() {
if (this.get("isExpanded") === false) { return; }
if (this.get("isExpanded") === false) return;
this.close();
},

View File

@ -62,6 +62,7 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
limitMatches: 100,
nameChanges: false,
allowsContentReplacement: false,
collectionHeader: null,
init() {
this._super();
@ -228,6 +229,10 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
actions: {
onToggle() {
if (this.get("onToggle")) this.sendAction("onToggle");
if (this.get("onCollapse") && this.get("isExpanded") === true) this.sendAction("onCollapse");
if (this.get("onExpand") && this.get("isExpanded") === false) this.sendAction("onExpand");
this.get("isExpanded") === true ? this.collapse() : this.expand();
},

View File

@ -26,8 +26,10 @@ export default Ember.Component.extend({
@computed("computedContent.dataName", "name")
dataName(dataName, name) { return dataName || name; },
@computed("computedContent.title", "name")
title(title, name) { return title || name; },
@computed("title", "computedContent.title", "name")
title(title, computedContentTitle, name) {
return title || computedContentTitle || name;
},
click() {
this.sendAction("onToggle");

View File

@ -0,0 +1,47 @@
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
import computed from "ember-addons/ember-computed-decorators";
export default DropdownSelectBoxComponent.extend({
pluginApiIdentifiers: ["toolbar-popup-menu-options"],
classNames: ["toolbar-popup-menu-options"],
isHidden: Ember.computed.empty("computedContent"),
showFullTitle: false,
@computed("title")
collectionHeader(title) {
return `<h3>${I18n.t(title)}</h3>`;
},
mutateValue(value) {
this.sendAction("onPopupMenuAction", value);
this.setProperties({ value: null, highlightedValue: null });
},
computeContent(content) {
return content.map(contentItem => {
if (contentItem.condition) {
return {
icon: contentItem.icon,
name: I18n.t(contentItem.label),
id: contentItem.action
};
}
}).filter(contentItem => contentItem);
},
didInsertElement() {
this._super();
$("#reply-control").on("touchstart.toolbar-popup-menu-options", (event) => {
if (this.get("isExpanded") && !this.element.contains(event.target)) {
this.close(event);
}
});
},
willDestroyElement() {
this._super();
$("#reply-control").off("touchstart.toolbar-popup-menu-options");
}
});

View File

@ -9,6 +9,7 @@
onClear=(action "onClear")
options=headerComponentOptions
shouldDisplayFilter=shouldDisplayFilter
title=(i18n title)
}}
<div class="select-kit-body">
@ -23,6 +24,7 @@
{{#if renderedBodyOnce}}
{{component collectionComponent
collectionHeader=collectionHeader
hasSelection=hasSelection
noneRowComputedContent=noneRowComputedContent
createRowComputedContent=createRowComputedContent

View File

@ -1,3 +1,9 @@
{{#if collectionHeader}}
<div class="collection-header">
{{{collectionHeader}}}
</div>
{{/if}}
{{#if hasSelection}}
{{#if noneRowComputedContent}}
{{component noneRowComponent

View File

@ -0,0 +1,58 @@
#reply-control .d-editor-button-bar .toolbar-popup-menu-options .btn.select-kit-header {
padding: 7px 8px;
height: auto;
}
.select-kit {
&.dropdown-select-box {
&.toolbar-popup-menu-options {
.select-kit-body {
box-shadow: none;
padding: 10px 10px 5px 10px;
width: 230px;
}
.select-kit-row {
border-radius: 4px;
margin-bottom: 5px;
padding: 6px 3px;
background: $primary-low;
transition: all .25s;
.name, .d-icon {
font-size: 1em;
font-weight: normal;
color: $primary;
}
.d-icon {
opacity: 0.7;
}
&.is-highlighted {
background: $primary-medium;
.name, .d-icon {
color: $secondary;
color: $secondary;
}
}
&:hover {
background: $primary-medium;
color: $secondary;
}
&.is-selected {
color: $primary;
background: $primary-low;
}
&.is-selected.is-highlighted {
background: $primary-medium;
color: $primary;
}
}
}
}
}

View File

@ -20,7 +20,6 @@ function initializeDetails(api) {
"details_text",
{ multiline: false }
);
this.set('optionsVisible', false);
}
}
});

View File

@ -8,10 +8,9 @@ function findTextarea() {
test('details button', (assert) => {
visit("/");
click('#create-topic');
click('button.options');
click('.popup-menu .d-icon-caret-right');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('insertDetails', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.equal(
@ -29,8 +28,8 @@ test('details button', (assert) => {
textarea.selectionEnd = textarea.value.length;
});
click('button.options');
click('.popup-menu .d-icon-caret-right');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('insertDetails', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.equal(
@ -52,8 +51,8 @@ test('details button', (assert) => {
textarea.selectionEnd = 28;
});
click('button.options');
click('.popup-menu .d-icon-caret-right');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('insertDetails', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.equal(
@ -75,8 +74,8 @@ test('details button', (assert) => {
textarea.selectionEnd = 29;
});
click('button.options');
click('.popup-menu .d-icon-caret-right');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('insertDetails', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.equal(
@ -104,8 +103,8 @@ test('details button surrounds all selected text in a single details block', (as
textarea.selectionEnd = textarea.value.length;
});
click('button.options');
click('.popup-menu .d-icon-caret-right');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('insertDetails', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.equal(

View File

@ -16,7 +16,7 @@ test("regular user - sufficient trust level", (assert) => {
displayPollBuilderButton();
andThen(() => {
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
assert.ok(!exists(".select-kit-row[title='Build Poll']"), "it hides the builder button");
});
});
@ -26,7 +26,7 @@ test("regular user - insufficient trust level", (assert) => {
displayPollBuilderButton();
andThen(() => {
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
assert.ok(!exists(".select-kit-row[title='Build Poll']"), "it hides the builder button");
});
});
@ -36,6 +36,6 @@ test("staff", (assert) => {
displayPollBuilderButton();
andThen(() => {
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
assert.ok(!exists(".select-kit-row[title='Build Poll']"), "it hides the builder button");
});
});

View File

@ -16,7 +16,7 @@ test("regular user - sufficient trust level", (assert) => {
displayPollBuilderButton();
andThen(() => {
assert.ok(exists("button[title='Build Poll']"), "it shows the builder button");
assert.ok(exists(".select-kit-row[title='Build Poll']"), "it shows the builder button");
});
});
@ -26,7 +26,7 @@ test("regular user - insufficient trust level", (assert) => {
displayPollBuilderButton();
andThen(() => {
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
assert.ok(!exists(".select-kit-row[title='Build Poll']"), "it hides the builder button");
});
});
@ -36,6 +36,6 @@ test("staff - with insufficient trust level", (assert) => {
displayPollBuilderButton();
andThen(() => {
assert.ok(exists("button[title='Build Poll']"), "it shows the builder button");
assert.ok(exists(".select-kit-row[title='Build Poll']"), "it shows the builder button");
});
});

View File

@ -2,4 +2,6 @@ export function displayPollBuilderButton() {
visit("/");
click("#create-topic");
click(".d-editor-button-bar .options");
expandSelectKit('.toolbar-popup-menu-options');
}

View File

@ -261,10 +261,10 @@ QUnit.test("Composer can toggle between edit and reply", assert => {
QUnit.test("Composer can toggle between reply and createTopic", assert => {
visit("/t/this-is-a-test-topic/9");
click('.topic-post:eq(0) button.reply');
click('button.options');
click('.popup-menu .d-icon-eye-slash');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('toggleWhisper', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.ok(
find('.composer-fields .whisper').text().indexOf(I18n.t("composer.whisper")) > 0,
@ -285,8 +285,9 @@ QUnit.test("Composer can toggle between reply and createTopic", assert => {
);
});
click('button.options');
click('.popup-menu .d-icon-eye-slash');
expandSelectKit('.toolbar-popup-menu-options');
selectKitSelectRow('toggleInvisible', { selector: '.toolbar-popup-menu-options'});
andThen(() => {
assert.ok(
find('.composer-fields .whisper').text().indexOf(I18n.t("composer.unlist")) > 0,

View File

@ -440,3 +440,60 @@ componentTest('with null value', {
});
}
});
componentTest('with collection header', {
template: '{{single-select collectionHeader=collectionHeader}}',
beforeEach() {
this.set("collectionHeader", "<h2>Hello</h2>");
},
test(assert) {
expandSelectKit();
andThen(() => assert.ok(exists(".collection-header h2")));
}
});
componentTest('with onToggle', {
template: '{{single-select onToggle=onToggle}}',
beforeEach() {
this.set("onToggle", () => $(".select-kit").append("<span class='onToggleTest'></span>"));
},
test(assert) {
andThen(() => assert.notOk(exists(".onToggleTest")));
expandSelectKit();
andThen(() => assert.ok(exists(".onToggleTest")));
}
});
componentTest('with onExpand', {
template: '{{single-select onExpand=onExpand}}',
beforeEach() {
this.set("onExpand", () => $(".select-kit").append("<span class='onExpandTest'></span>"));
},
test(assert) {
andThen(() => assert.notOk(exists(".onExpandTest")));
expandSelectKit();
andThen(() => assert.ok(exists(".onExpandTest")));
}
});
componentTest('with onCollapse', {
template: '{{single-select onCollapse=onCollapse}}',
beforeEach() {
this.set("onCollapse", () => $(".select-kit").append("<span class='onCollapseTest'></span>"));
},
test(assert) {
andThen(() => assert.notOk(exists(".onCollapseTest")));
expandSelectKit();
andThen(() => assert.notOk(exists(".onCollapseTest")));
collapseSelectKit();
andThen(() => assert.ok(exists(".onCollapseTest")));
}
});