mirror of
https://github.com/discourse/discourse.git
synced 2024-11-24 08:56:36 +08:00
Merge pull request #4264 from tgxworld/poll_ui_builder
Poll UI Builder.
This commit is contained in:
commit
ba87181506
|
@ -45,6 +45,7 @@ before_install:
|
||||||
- eslint app/assets/javascripts
|
- eslint app/assets/javascripts
|
||||||
- eslint --ext .es6 app/assets/javascripts
|
- eslint --ext .es6 app/assets/javascripts
|
||||||
- eslint --ext .es6 test/javascripts
|
- eslint --ext .es6 test/javascripts
|
||||||
|
- eslint --ext .es6 plugins/**/assets/javascripts
|
||||||
- eslint test/javascripts
|
- eslint test/javascripts
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
|
|
@ -362,7 +362,7 @@ export default Ember.Component.extend({
|
||||||
this._resetUpload(true);
|
this._resetUpload(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
showOptions() {
|
showOptions(toolbarEvent) {
|
||||||
// long term we want some smart positioning algorithm in popup-menu
|
// long term we want some smart positioning algorithm in popup-menu
|
||||||
// the problem is that positioning in a fixed panel is a nightmare
|
// the problem is that positioning in a fixed panel is a nightmare
|
||||||
// cause offsetParent can end up returning a fixed element and then
|
// cause offsetParent can end up returning a fixed element and then
|
||||||
|
@ -388,9 +388,8 @@ export default Ember.Component.extend({
|
||||||
left = replyWidth - popupWidth - 40;
|
left = replyWidth - popupWidth - 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendAction('showOptions', { position: "absolute",
|
this.sendAction('showOptions', toolbarEvent,
|
||||||
left: left,
|
{ position: "absolute", left, top });
|
||||||
top: top });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showUploadModal(toolbarEvent) {
|
showUploadModal(toolbarEvent) {
|
||||||
|
@ -420,7 +419,7 @@ export default Ember.Component.extend({
|
||||||
sendAction: 'showUploadModal'
|
sendAction: 'showUploadModal'
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.get('canWhisper')) {
|
if (this.get("popupMenuOptions").some(option => option.condition)) {
|
||||||
toolbar.addButton({
|
toolbar.addButton({
|
||||||
id: 'options',
|
id: 'options',
|
||||||
group: 'extras',
|
group: 'extras',
|
||||||
|
|
|
@ -42,6 +42,12 @@ function loadDraft(store, opts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _popupMenuOptionsCallbacks = [];
|
||||||
|
|
||||||
|
export function addPopupMenuOptionsCallback(callback) {
|
||||||
|
_popupMenuOptionsCallbacks.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
needs: ['modal', 'topic', 'application'],
|
needs: ['modal', 'topic', 'application'],
|
||||||
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_TOPIC_KEY),
|
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_TOPIC_KEY),
|
||||||
|
@ -56,6 +62,19 @@ export default Ember.Controller.extend({
|
||||||
topic: null,
|
topic: null,
|
||||||
linkLookup: null,
|
linkLookup: null,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
addPopupMenuOptionsCallback(function() {
|
||||||
|
return {
|
||||||
|
action: 'toggleWhisper',
|
||||||
|
icon: 'eye-slash',
|
||||||
|
label: 'composer.toggle_whisper',
|
||||||
|
condition: "canWhisper"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
showToolbar: Em.computed({
|
showToolbar: Em.computed({
|
||||||
get(){
|
get(){
|
||||||
const keyValueStore = this.container.lookup('key-value-store:main');
|
const keyValueStore = this.container.lookup('key-value-store:main');
|
||||||
|
@ -92,6 +111,23 @@ export default Ember.Controller.extend({
|
||||||
return currentUser && currentUser.get('staff') && this.siteSettings.enable_whispers && action === Composer.REPLY;
|
return currentUser && currentUser.get('staff') && this.siteSettings.enable_whispers && action === Composer.REPLY;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@computed("model.composeState")
|
||||||
|
popupMenuOptions(composeState) {
|
||||||
|
if (composeState === 'open') {
|
||||||
|
return _popupMenuOptionsCallbacks.map(callback => {
|
||||||
|
let option = callback();
|
||||||
|
|
||||||
|
if (option.condition) {
|
||||||
|
option.condition = this.get(option.condition);
|
||||||
|
} else {
|
||||||
|
option.condition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
showWarning: function() {
|
showWarning: function() {
|
||||||
if (!Discourse.User.currentProp('staff')) { return false; }
|
if (!Discourse.User.currentProp('staff')) { return false; }
|
||||||
|
|
||||||
|
@ -154,7 +190,8 @@ export default Ember.Controller.extend({
|
||||||
this.toggleProperty('showToolbar');
|
this.toggleProperty('showToolbar');
|
||||||
},
|
},
|
||||||
|
|
||||||
showOptions(loc) {
|
showOptions(toolbarEvent, loc) {
|
||||||
|
this.set('toolbarEvent', toolbarEvent);
|
||||||
this.appEvents.trigger('popup-menu:open', loc);
|
this.appEvents.trigger('popup-menu:open', loc);
|
||||||
this.set('optionsVisible', true);
|
this.set('optionsVisible', true);
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { onPageChange } from 'discourse/lib/page-tracker';
|
||||||
import { preventCloak } from 'discourse/widgets/post-stream';
|
import { preventCloak } from 'discourse/widgets/post-stream';
|
||||||
import { h } from 'virtual-dom';
|
import { h } from 'virtual-dom';
|
||||||
import { addFlagProperty } from 'discourse/components/site-header';
|
import { addFlagProperty } from 'discourse/components/site-header';
|
||||||
|
import { addPopupMenuOptionsCallback } from 'discourse/controllers/composer';
|
||||||
|
|
||||||
class PluginApi {
|
class PluginApi {
|
||||||
constructor(version, container) {
|
constructor(version, container) {
|
||||||
|
@ -224,6 +225,26 @@ class PluginApi {
|
||||||
addToolbarCallback(callback);
|
addToolbarCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new button in the options popup menu.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* api.addToolbarPopupMenuOptionsCallback(function(controller) {
|
||||||
|
* return {
|
||||||
|
* action: 'toggleWhisper',
|
||||||
|
* icon: 'eye-slash',
|
||||||
|
* label: 'composer.toggle_whisper',
|
||||||
|
* condition: "canWhisper"
|
||||||
|
* };
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
**/
|
||||||
|
addToolbarPopupMenuOptionsCallback(callback) {
|
||||||
|
addPopupMenuOptionsCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hook that is called when the post stream is removed from the DOM.
|
* A hook that is called when the post stream is removed from the DOM.
|
||||||
* This advanced hook should be used if you end up wiring up any
|
* This advanced hook should be used if you end up wiring up any
|
||||||
|
|
|
@ -3,9 +3,13 @@
|
||||||
|
|
||||||
{{#if currentUser.staff}}
|
{{#if currentUser.staff}}
|
||||||
{{#popup-menu visible=optionsVisible hide="hideOptions" title="composer.options"}}
|
{{#popup-menu visible=optionsVisible hide="hideOptions" title="composer.options"}}
|
||||||
<li>
|
{{#each popupMenuOptions as |option|}}
|
||||||
{{d-button action="toggleWhisper" icon="eye-slash" label="composer.toggle_whisper"}}
|
{{#if option.condition}}
|
||||||
</li>
|
<li>
|
||||||
|
{{d-button action=option.action icon=option.icon label=option.label}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
{{/popup-menu}}
|
{{/popup-menu}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
@ -86,6 +90,7 @@
|
||||||
composer=model
|
composer=model
|
||||||
lastValidatedAt=lastValidatedAt
|
lastValidatedAt=lastValidatedAt
|
||||||
canWhisper=canWhisper
|
canWhisper=canWhisper
|
||||||
|
popupMenuOptions=popupMenuOptions
|
||||||
draftStatus=model.draftStatus
|
draftStatus=model.draftStatus
|
||||||
isUploading=isUploading
|
isUploading=isUploading
|
||||||
groupsMentioned="groupsMentioned"
|
groupsMentioned="groupsMentioned"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
import User from 'discourse/models/user';
|
|
||||||
import PollVoters from 'discourse/plugins/poll/components/poll-voters';
|
import PollVoters from 'discourse/plugins/poll/components/poll-voters';
|
||||||
|
|
||||||
export default PollVoters.extend({
|
export default PollVoters.extend({
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
import User from 'discourse/models/user';
|
|
||||||
import PollVoters from 'discourse/plugins/poll/components/poll-voters';
|
import PollVoters from 'discourse/plugins/poll/components/poll-voters';
|
||||||
|
|
||||||
export default PollVoters.extend({
|
export default PollVoters.extend({
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
needs: ['modal'],
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
this._setupPoll();
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed
|
||||||
|
pollTypes() {
|
||||||
|
return [I18n.t("poll.ui_builder.poll_type.number"), I18n.t("poll.ui_builder.poll_type.multiple")].map(type => {
|
||||||
|
return { name: type, value: type };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("pollType", "pollOptionsCount")
|
||||||
|
isMultiple(pollType, count) {
|
||||||
|
return (pollType === I18n.t("poll.ui_builder.poll_type.multiple")) && count > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("pollType")
|
||||||
|
isNumber(pollType) {
|
||||||
|
return pollType === I18n.t("poll.ui_builder.poll_type.number");
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("isNumber", "isMultiple")
|
||||||
|
showMinMax(isNumber, isMultiple) {
|
||||||
|
return isNumber || isMultiple;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("pollOptions")
|
||||||
|
pollOptionsCount(pollOptions) {
|
||||||
|
if (pollOptions.length === 0) return 0;
|
||||||
|
|
||||||
|
let length = 0;
|
||||||
|
|
||||||
|
pollOptions.split("\n").forEach(option => {
|
||||||
|
if (option.length !== 0) length += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return length;
|
||||||
|
},
|
||||||
|
|
||||||
|
@observes("isMultiple", "isNumber", "pollOptionsCount")
|
||||||
|
_setPollMax() {
|
||||||
|
const isMultiple = this.get("isMultiple");
|
||||||
|
const isNumber = this.get("isNumber");
|
||||||
|
if (!isMultiple && !isNumber) return;
|
||||||
|
|
||||||
|
if (isMultiple) {
|
||||||
|
this.set("pollMax", this.get("pollOptionsCount"));
|
||||||
|
} else if (isNumber) {
|
||||||
|
this.set("pollMax", this.siteSettings.poll_maximum_options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("isMultiple", "isNumber", "pollOptionsCount")
|
||||||
|
pollMinOptions(isMultiple, isNumber, count) {
|
||||||
|
if (!isMultiple && !isNumber) return;
|
||||||
|
|
||||||
|
if (isMultiple) {
|
||||||
|
return this._comboboxOptions(1, count + 1);
|
||||||
|
} else if (isNumber) {
|
||||||
|
return this._comboboxOptions(1, this.siteSettings.poll_maximum_options + 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("isMultiple", "isNumber", "pollOptionsCount", "pollMin", "pollStep")
|
||||||
|
pollMaxOptions(isMultiple, isNumber, count, pollMin, pollStep) {
|
||||||
|
if (!isMultiple && !isNumber) return;
|
||||||
|
const pollMinInt = parseInt(pollMin);
|
||||||
|
|
||||||
|
if (isMultiple) {
|
||||||
|
return this._comboboxOptions(pollMinInt + 1, count + 1);
|
||||||
|
} else if (isNumber) {
|
||||||
|
const pollStepInt = parseInt(pollStep);
|
||||||
|
return this._comboboxOptions(pollMinInt + 1, pollMinInt + (this.siteSettings.poll_maximum_options * pollStepInt));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("isNumber", "pollMax")
|
||||||
|
pollStepOptions(isNumber, pollMax) {
|
||||||
|
if (!isNumber) return;
|
||||||
|
return this._comboboxOptions(1, parseInt(pollMax) + 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("isNumber", "showMinMax", "pollName", "pollType", "publicPoll", "pollOptions", "pollMin", "pollMax", "pollStep")
|
||||||
|
pollOutput(isNumber, showMinMax, pollName, pollType, publicPoll, pollOptions, pollMin, pollMax, pollStep) {
|
||||||
|
let pollHeader = '[poll';
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
if (pollName) pollHeader += ` name=${pollName.replace(' ', '-')}`;
|
||||||
|
if (pollType) pollHeader += ` type=${pollType}`;
|
||||||
|
if (pollMin && showMinMax) pollHeader += ` min=${pollMin}`;
|
||||||
|
if (pollMax) pollHeader += ` max=${pollMax}`;
|
||||||
|
if (isNumber) pollHeader += ` step=${pollStep}`;
|
||||||
|
if (publicPoll) pollHeader += ' public=true';
|
||||||
|
pollHeader += ']';
|
||||||
|
output += `${pollHeader}\n`;
|
||||||
|
|
||||||
|
if (pollOptions.length > 0 && !isNumber) {
|
||||||
|
output += `${pollOptions.split("\n").map(option => `* ${option}`).join("\n")}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '[/poll]';
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("pollOptionsCount", "isNumber")
|
||||||
|
disableInsert(count, isNumber) {
|
||||||
|
return isNumber ? false : (count < 2);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("disableInsert")
|
||||||
|
minNumOfOptionsValidation(disableInsert) {
|
||||||
|
let options = { ok: true };
|
||||||
|
|
||||||
|
if (disableInsert) {
|
||||||
|
options = { failed: true, reason: I18n.t("poll.ui_builder.help.options_count") };
|
||||||
|
}
|
||||||
|
|
||||||
|
return Discourse.InputValidation.create(options);
|
||||||
|
},
|
||||||
|
|
||||||
|
_comboboxOptions(start_index, end_index) {
|
||||||
|
return _.range(start_index, end_index).map(number => {
|
||||||
|
return { value: number, name: number };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_setupPoll() {
|
||||||
|
this.setProperties({
|
||||||
|
pollName: '',
|
||||||
|
pollNamePlaceholder: I18n.t("poll.ui_builder.poll_name.placeholder"),
|
||||||
|
pollType: null,
|
||||||
|
publicPoll: false,
|
||||||
|
pollOptions: '',
|
||||||
|
pollMin: 1,
|
||||||
|
pollMax: null,
|
||||||
|
pollStep: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
insertPoll() {
|
||||||
|
this.get("toolbarEvent").addText(this.get("pollOutput"));
|
||||||
|
this.send("closeModal");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -147,7 +147,6 @@ export default Ember.Controller.extend({
|
||||||
}).then(results => {
|
}).then(results => {
|
||||||
const poll = results.poll;
|
const poll = results.poll;
|
||||||
const votes = results.vote;
|
const votes = results.vote;
|
||||||
const currentUser = this.currentUser;
|
|
||||||
|
|
||||||
this.setProperties({ vote: votes, showResults: true });
|
this.setProperties({ vote: votes, showResults: true });
|
||||||
this.set("model", Em.Object.create(poll));
|
this.set("model", Em.Object.create(poll));
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<div class="modal-body poll-ui-builder">
|
||||||
|
<form class="poll-ui-builder-form form-horizontal">
|
||||||
|
<div class="input-group">
|
||||||
|
<label>{{i18n 'poll.ui_builder.poll_name.label'}}</label>
|
||||||
|
{{input name="poll-name" value=pollName placeholder=pollNamePlaceholder}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label>{{i18n 'poll.ui_builder.poll_type.label'}}</label>
|
||||||
|
{{combo-box content=pollTypes
|
||||||
|
value=pollType
|
||||||
|
valueAttribute="value"
|
||||||
|
none="poll.ui_builder.poll_type.regular"}}
|
||||||
|
|
||||||
|
{{#if showMinMax}}
|
||||||
|
<label>{{i18n 'poll.ui_builder.poll_config.min'}}</label>
|
||||||
|
{{combo-box content=pollMinOptions
|
||||||
|
value=pollMin
|
||||||
|
valueAttribute="value"
|
||||||
|
class="poll-options-min"}}
|
||||||
|
|
||||||
|
<label>{{i18n 'poll.ui_builder.poll_config.max'}}</label>
|
||||||
|
{{combo-box content=pollMaxOptions
|
||||||
|
value=pollMax
|
||||||
|
valueAttribute="value"
|
||||||
|
class="poll-options-max"}}
|
||||||
|
|
||||||
|
{{#if isNumber}}
|
||||||
|
<label>{{i18n 'poll.ui_builder.poll_config.step'}}</label>
|
||||||
|
{{combo-box content=pollStepOptions
|
||||||
|
value=pollStep
|
||||||
|
valueAttribute="value"
|
||||||
|
class="poll-options-step"}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="poll-public">
|
||||||
|
{{input type='checkbox' checked=publicPoll}}
|
||||||
|
{{i18n "poll.ui_builder.poll_public.label"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#unless isNumber}}
|
||||||
|
<div class="input-group">
|
||||||
|
<label>{{i18n 'poll.ui_builder.poll_options.label'}}</label>
|
||||||
|
{{input-tip validation=minNumOfOptionsValidation}}
|
||||||
|
{{d-editor value=pollOptions}}
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{d-button action="insertPoll" class='btn-primary' label='poll.ui_builder.insert' disabled=disableInsert}}
|
||||||
|
</div>
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { withPluginApi } from 'discourse/lib/plugin-api';
|
||||||
|
import showModal from 'discourse/lib/show-modal';
|
||||||
|
|
||||||
|
function initializePollUIBuilder(api) {
|
||||||
|
const ComposerController = api.container.lookup("controller:composer");
|
||||||
|
|
||||||
|
ComposerController.reopen({
|
||||||
|
actions: {
|
||||||
|
showPollBuilder() {
|
||||||
|
showModal("poll-ui-builder").set("toolbarEvent", this.get("toolbarEvent"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addToolbarPopupMenuOptionsCallback(function() {
|
||||||
|
return {
|
||||||
|
action: 'showPollBuilder',
|
||||||
|
icon: 'bar-chart-o',
|
||||||
|
label: 'poll.ui_builder.title'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "add-poll-ui-builder",
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
withPluginApi('0.1', initializePollUIBuilder);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
import ModalBodyView from "discourse/views/modal-body";
|
||||||
|
|
||||||
|
export default ModalBodyView.extend({
|
||||||
|
needs: ['modal'],
|
||||||
|
|
||||||
|
templateName: 'modals/poll-ui-builder',
|
||||||
|
title: I18n.t("poll.ui_builder.title")
|
||||||
|
});
|
|
@ -1,5 +1,3 @@
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default Em.View.extend({
|
export default Em.View.extend({
|
||||||
templateName: "poll",
|
templateName: "poll",
|
||||||
classNames: ["poll"],
|
classNames: ["poll"],
|
||||||
|
|
18
plugins/poll/assets/stylesheets/common/poll-ui-builder.scss
Normal file
18
plugins/poll/assets/stylesheets/common/poll-ui-builder.scss
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
.poll-ui-builder-form {
|
||||||
|
.input-group {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combobox {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-options-min, .poll-options-max, .poll-options-step {
|
||||||
|
width: 70px !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,3 +68,26 @@ en:
|
||||||
error_while_toggling_status: "There was an error while toggling the status of this poll."
|
error_while_toggling_status: "There was an error while toggling the status of this poll."
|
||||||
error_while_casting_votes: "There was an error while casting your votes."
|
error_while_casting_votes: "There was an error while casting your votes."
|
||||||
error_while_fetching_voters: "There was an error while displaying the voters."
|
error_while_fetching_voters: "There was an error while displaying the voters."
|
||||||
|
|
||||||
|
ui_builder:
|
||||||
|
title: Poll Builder
|
||||||
|
insert: Insert Poll
|
||||||
|
reset: Reset Poll
|
||||||
|
help:
|
||||||
|
options_count: You must provide a minimum of 2 options.
|
||||||
|
poll_name:
|
||||||
|
label: Poll Name
|
||||||
|
placeholder: Enter Poll Name
|
||||||
|
poll_type:
|
||||||
|
label: Poll Type
|
||||||
|
regular: regular
|
||||||
|
multiple: multiple
|
||||||
|
number: number
|
||||||
|
poll_config:
|
||||||
|
max: Max
|
||||||
|
min: Min
|
||||||
|
step: Step
|
||||||
|
poll_public:
|
||||||
|
label: Make Public Poll
|
||||||
|
poll_options:
|
||||||
|
label: "Poll Choices: (one option per line)"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
enabled_site_setting :poll_enabled
|
enabled_site_setting :poll_enabled
|
||||||
|
|
||||||
register_asset "stylesheets/common/poll.scss"
|
register_asset "stylesheets/common/poll.scss"
|
||||||
|
register_asset "stylesheets/common/poll-ui-builder.scss"
|
||||||
register_asset "stylesheets/desktop/poll.scss", :desktop
|
register_asset "stylesheets/desktop/poll.scss", :desktop
|
||||||
register_asset "stylesheets/mobile/poll.scss", :mobile
|
register_asset "stylesheets/mobile/poll.scss", :mobile
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
moduleFor("controller:poll-ui-builder", "controller:poll-ui-builder", {
|
||||||
|
needs: ['controller:modal']
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isMultiple", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
pollType: I18n.t("poll.ui_builder.poll_type.multiple"),
|
||||||
|
pollOptionsCount: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(controller.get("isMultiple"), true, "it should be true");
|
||||||
|
|
||||||
|
controller.set("pollOptionsCount", 0);
|
||||||
|
|
||||||
|
equal(controller.get("isMultiple"), false, "it should be false");
|
||||||
|
|
||||||
|
controller.setProperties({ pollType: "random", pollOptionsCount: 1 });
|
||||||
|
|
||||||
|
equal(controller.get("isMultiple"), false, "it should be false");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isNumber", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
|
||||||
|
controller.set("pollType", "random");
|
||||||
|
|
||||||
|
equal(controller.get("isNumber"), false, "it should be false");
|
||||||
|
|
||||||
|
controller.set("pollType", I18n.t("poll.ui_builder.poll_type.number"));
|
||||||
|
|
||||||
|
equal(controller.get("isNumber"), true, "it should be true");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("showMinMax", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
isNumber: true,
|
||||||
|
isMultiple: false
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(controller.get("showMinMax"), true, "it should be true");
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
isNumber: false,
|
||||||
|
isMultiple: true
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(controller.get("showMinMax"), true, "it should be true");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pollOptionsCount", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
|
||||||
|
controller.set("pollOptions", "1\n2\n")
|
||||||
|
|
||||||
|
equal(controller.get("pollOptionsCount"), 2, "it should equal 2");
|
||||||
|
|
||||||
|
controller.set("pollOptions", "")
|
||||||
|
|
||||||
|
equal(controller.get("pollOptionsCount"), 0, "it should equal 0");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pollMinOptions", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
isMultiple: true,
|
||||||
|
pollOptionsCount: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollMinOptions"), [{ name: 1, value: 1 }], "it should return the right options");
|
||||||
|
|
||||||
|
controller.set("pollOptionsCount", 2);
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollMinOptions"), [
|
||||||
|
{ name: 1, value: 1 }, { name: 2, value: 2 }
|
||||||
|
], "it should return the right options");
|
||||||
|
|
||||||
|
controller.set("isNumber", true);
|
||||||
|
controller.siteSettings.poll_maximum_options = 2;
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollMinOptions"), [
|
||||||
|
{ name: 1, value: 1 }, { name: 2, value: 2 }
|
||||||
|
], "it should return the right options");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pollMaxOptions", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
|
||||||
|
controller.setProperties({ isMultiple: true, pollOptionsCount: 1, pollMin: 1 });
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollMaxOptions"), [], "it should return the right options");
|
||||||
|
|
||||||
|
controller.set("pollOptionsCount", 2);
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollMaxOptions"), [
|
||||||
|
{ name: 2, value: 2 }
|
||||||
|
], "it should return the right options");
|
||||||
|
|
||||||
|
controller.siteSettings.poll_maximum_options = 3;
|
||||||
|
controller.setProperties({ isMultiple: false, isNumber: true, pollStep: 2, pollMin: 1 });
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollMaxOptions"), [
|
||||||
|
{ name: 2, value: 2 },
|
||||||
|
{ name: 3, value: 3 },
|
||||||
|
{ name: 4, value: 4 },
|
||||||
|
{ name: 5, value: 5 },
|
||||||
|
{ name: 6, value: 6 }
|
||||||
|
], "it should return the right options");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pollStepOptions", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
controller.siteSettings.poll_maximum_options = 3;
|
||||||
|
|
||||||
|
controller.set("isNumber", false);
|
||||||
|
|
||||||
|
equal(controller.get("pollStepOptions"), null, "is should return null");
|
||||||
|
|
||||||
|
controller.setProperties({ isNumber: true });
|
||||||
|
|
||||||
|
deepEqual(controller.get("pollStepOptions"), [
|
||||||
|
{ name: 1, value: 1 },
|
||||||
|
{ name: 2, value: 2 },
|
||||||
|
{ name: 3, value: 3 }
|
||||||
|
], "it should return the right options");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("disableInsert", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
|
||||||
|
controller.setProperties({ isNumber: true });
|
||||||
|
|
||||||
|
equal(controller.get("disableInsert"), false, "it should be false");
|
||||||
|
|
||||||
|
controller.setProperties({ isNumber: false, pollOptionsCount: 3 });
|
||||||
|
|
||||||
|
equal(controller.get("disableInsert"), false, "it should be false");
|
||||||
|
|
||||||
|
controller.setProperties({ isNumber: false, pollOptionsCount: 1 });
|
||||||
|
|
||||||
|
equal(controller.get("disableInsert"), true, "it should be true");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("number pollOutput", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
controller.siteSettings.poll_maximum_options = 20;
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
isNumber: true,
|
||||||
|
pollType: I18n.t("poll.ui_builder.poll_type.number"),
|
||||||
|
pollMin: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll type=number min=1 max=20 step=1]\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("pollName", 'test');
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test type=number min=1 max=20 step=1]\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("pollName", 'test poll');
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test-poll type=number min=1 max=20 step=1]\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("pollStep", 2);
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test-poll type=number min=1 max=20 step=2]\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("publicPoll", true);
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test-poll type=number min=1 max=20 step=2 public=true]\n[/poll]", "it should return the right output");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("regular pollOutput", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
controller.siteSettings.poll_maximum_options = 20;
|
||||||
|
|
||||||
|
controller.set("pollOptions", "1\n2");
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll]\n* 1\n* 2\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("pollName", "test");
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test]\n* 1\n* 2\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("publicPoll", "true");
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test public=true]\n* 1\n* 2\n[/poll]", "it should return the right output");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("multiple pollOutput", function() {
|
||||||
|
const controller = this.subject();
|
||||||
|
controller.siteSettings = Discourse.SiteSettings;
|
||||||
|
controller.siteSettings.poll_maximum_options = 20;
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
isMultiple: true,
|
||||||
|
pollType: I18n.t("poll.ui_builder.poll_type.multiple"),
|
||||||
|
pollMin: 1,
|
||||||
|
pollOptions: "1\n2"
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll type=multiple min=1 max=2]\n* 1\n* 2\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("pollName", "test");
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test type=multiple min=1 max=2]\n* 1\n* 2\n[/poll]", "it should return the right output");
|
||||||
|
|
||||||
|
controller.set("publicPoll", "true");
|
||||||
|
|
||||||
|
equal(controller.get("pollOutput"), "[poll name=test type=multiple min=1 max=2 public=true]\n* 1\n* 2\n[/poll]", "it should return the right output");
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user