summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPouyan Savoli <papoola@hotmail.com>2017-09-18 00:46:17 +0200
committerPouyan Savoli <papoola@hotmail.com>2017-09-22 22:59:32 +0200
commit3753337d60e17e5e72ec071aa4a1b28e36297d15 (patch)
tree81363c3fb7d1af2c90e7a3e2b1233412569bd52d
parentcaad952bc1b29bb925c1347a14daa5d1ec8ada81 (diff)
downloadwekan-3753337d60e17e5e72ec071aa4a1b28e36297d15.tar.gz
wekan-3753337d60e17e5e72ec071aa4a1b28e36297d15.tar.bz2
wekan-3753337d60e17e5e72ec071aa4a1b28e36297d15.zip
dropdown items
-rw-r--r--client/components/boards/boardHeader.jade2
-rw-r--r--client/components/boards/boardHeader.js2
-rw-r--r--client/components/cards/cardCustomFields.jade29
-rw-r--r--client/components/cards/cardCustomFields.js62
-rw-r--r--client/components/forms/forms.styl3
-rw-r--r--client/components/sidebar/sidebar.js2
-rw-r--r--client/components/sidebar/sidebarCustomFields.jade23
-rw-r--r--client/components/sidebar/sidebarCustomFields.js129
-rw-r--r--i18n/en.i18n.json6
-rw-r--r--models/customFields.js19
10 files changed, 209 insertions, 68 deletions
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade
index 9d16b10a..67acdc9e 100644
--- a/client/components/boards/boardHeader.jade
+++ b/client/components/boards/boardHeader.jade
@@ -103,7 +103,7 @@ template(name="boardHeaderBar")
template(name="boardMenuPopup")
ul.pop-over-list
- li: a.js-configure-custom-fields {{_ 'configure-custom-fields'}}
+ li: a.js-custom-fields {{_ 'custom-fields'}}
li: a.js-open-archives {{_ 'archived-items'}}
if currentUser.isBoardAdmin
li: a.js-change-board-color {{_ 'board-change-color'}}
diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js
index 61cdb149..8983c722 100644
--- a/client/components/boards/boardHeader.js
+++ b/client/components/boards/boardHeader.js
@@ -1,6 +1,6 @@
Template.boardMenuPopup.events({
'click .js-rename-board': Popup.open('boardChangeTitle'),
- 'click .js-configure-custom-fields'() {
+ 'click .js-custom-fields'() {
Sidebar.setView('customFields');
Popup.close();
},
diff --git a/client/components/cards/cardCustomFields.jade b/client/components/cards/cardCustomFields.jade
index 6515aa79..9e9f7d84 100644
--- a/client/components/cards/cardCustomFields.jade
+++ b/client/components/cards/cardCustomFields.jade
@@ -8,11 +8,14 @@ template(name="cardCustomFieldsPopup")
if hasCustomField
i.fa.fa-check
hr
- a.quiet-button.full.js-configure-custom-fields
+ a.quiet-button.full.js-settings
i.fa.fa-cog
- span {{_ 'configure-custom-fields'}}
+ span {{_ 'settings'}}
-template(name="cardCustomFieldText")
+template(name="cardCustomField")
+ +Template.dynamic(template=getTemplate)
+
+template(name="cardCustomField-text")
if canModifyCard
+inlinedForm(classNames="js-card-customfield-text")
+editor(autofocus=true)
@@ -26,4 +29,24 @@ template(name="cardCustomFieldText")
+viewer
= value
else
+ | {{_ 'edit'}}
+
+template(name="cardCustomField-dropdown")
+ if canModifyCard
+ +inlinedForm(classNames="js-card-customfield-dropdown")
+ select.inline
+ each items
+ if($eq data.value this._id)
+ option(value=_id selected="selected") {{name}}
+ else
+ option(value=_id) {{name}}
+ .edit-controls.clearfix
+ button.primary(type="submit") {{_ 'save'}}
+ a.fa.fa-times-thin.js-close-inlined-form
+ else
+ a.js-open-inlined-form
+ if value
+ +viewer
+ = selectedItem
+ else
| {{_ 'edit'}} \ No newline at end of file
diff --git a/client/components/cards/cardCustomFields.js b/client/components/cards/cardCustomFields.js
index 7009dede..f9fa760c 100644
--- a/client/components/cards/cardCustomFields.js
+++ b/client/components/cards/cardCustomFields.js
@@ -13,7 +13,7 @@ Template.cardCustomFieldsPopup.events({
card.toggleCustomField(customFieldId);
evt.preventDefault();
},
- 'click .js-configure-custom-fields'(evt) {
+ 'click .js-settings'(evt) {
EscapeActions.executeUpTo('detailsPane');
Sidebar.setView('customFields');
evt.preventDefault();
@@ -21,23 +21,25 @@ Template.cardCustomFieldsPopup.events({
});
const CardCustomField = BlazeComponent.extendComponent({
- template() {
- return 'cardCustomFieldText';
+
+ getTemplate() {
+ return 'cardCustomField-' + this.data().definition.type;
},
onCreated() {
const self = this;
- self.date = ReactiveVar();
- self.now = ReactiveVar(moment());
},
- value() {
- return this.data().value;
+ canModifyCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
},
+});
+CardCustomField.register('cardCustomField');
- showISODate() {
- return this.date.get().toISOString();
- },
+(class extends CardCustomField {
+
+ onCreated() {
+ }
events() {
return [{
@@ -48,13 +50,39 @@ const CardCustomField = BlazeComponent.extendComponent({
const value = this.currentComponent().getValue();
card.setCustomField(customFieldId,value);
},
- 'click .js-edit-date': Popup.open('editCardStartDate'),
}];
- },
+ }
- canModifyCard() {
- return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
- },
-});
+}).register('cardCustomField-text');
+
+(class extends CardCustomField {
+
+ onCreated() {
+ this._items = this.data().definition.settings.dropdownItems;
+ this.items = this._items.slice(0);
+ this.items.unshift({
+ _id: "",
+ name: TAPi18n.__('custom-field-dropdown-none')
+ });
+ }
+
+ selectedItem() {
+ const selected = this._items.find((item) => {
+ return item._id == this.data().value;
+ });
+ return (selected) ? selected.name : TAPi18n.__('custom-field-dropdown-unknown');
+ }
+
+ events() {
+ return [{
+ 'submit .js-card-customfield-dropdown'(evt) {
+ evt.preventDefault();
+ const card = Cards.findOne(Session.get('currentCard'));
+ const customFieldId = this.data()._id;
+ const value = this.find('select').value;
+ card.setCustomField(customFieldId,value);
+ },
+ }];
+ }
-CardCustomField.register('cardCustomField'); \ No newline at end of file
+}).register('cardCustomField-dropdown'); \ No newline at end of file
diff --git a/client/components/forms/forms.styl b/client/components/forms/forms.styl
index 646da657..81780a6f 100644
--- a/client/components/forms/forms.styl
+++ b/client/components/forms/forms.styl
@@ -85,6 +85,9 @@ select
width: 256px
margin-bottom: 8px
+ &.inline
+ width: 100%
+
option[disabled]
color: #8c8c8c
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index 0ff73215..59a2b42c 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -5,7 +5,7 @@ const defaultView = 'home';
const viewTitles = {
filter: 'filter-cards',
multiselection: 'multi-selection',
- customFields: 'configure-custom-fields',
+ customFields: 'custom-fields',
archives: 'archives',
};
diff --git a/client/components/sidebar/sidebarCustomFields.jade b/client/components/sidebar/sidebarCustomFields.jade
index e17bb75d..def083e9 100644
--- a/client/components/sidebar/sidebarCustomFields.jade
+++ b/client/components/sidebar/sidebarCustomFields.jade
@@ -19,31 +19,34 @@ template(name="createCustomFieldPopup")
label
| {{_ 'name'}}
unless _id
- input.js-field-name(type="text" name="field-name" autofocus)
+ input.js-field-name(type="text" autofocus)
else
- input.js-field-name(type="text" name="field-name" value=name)
+ input.js-field-name(type="text" value=name)
label
| {{_ 'type'}}
- select.js-field-type(name="field-type" disabled="{{#if _id}}disabled{{/if}}")
+ select.js-field-type(disabled="{{#if _id}}disabled{{/if}}")
each types
if selected
- option(value=type selected="selected") {{name}}
+ option(value=value selected="selected") {{name}}
else
- option(value=type) {{name}}
+ option(value=value) {{name}}
+ div.js-field-settings.js-field-settings-dropdown(class="{{#if isTypeNotSelected 'dropdown'}}hide{{/if}}")
+ label
+ | {{_ 'custom-field-dropdown-options'}}
+ each dropdownItems.get
+ input.js-dropdown-item(type="text" value=name placeholder="")
+ input.js-dropdown-item.last(type="text" value="" placeholder="{{_ 'custom-field-dropdown-options-placeholder'}}")
a.flex.js-field-show-on-card
.materialCheckBox(class="{{#if showOnCard}}is-checked{{/if}}")
span {{_ 'show-field-on-card'}}
- button.primary.wide.left(type="submit")
+ button.primary.wide.left(type="button")
| {{_ 'save'}}
if _id
- button.negate.wide.right.js-delete-custom-field
+ button.negate.wide.right.js-delete-custom-field(type="button")
| {{_ 'delete'}}
-template(name="editCustomFieldPopup")
- | {{> createCustomFieldPopup}}
-
template(name="deleteCustomFieldPopup")
p {{_ "custom-field-delete-pop"}}
button.js-confirm.negate.full(type="submit") {{_ 'delete'}} \ No newline at end of file
diff --git a/client/components/sidebar/sidebarCustomFields.js b/client/components/sidebar/sidebarCustomFields.js
index 6ddd466e..139b8a42 100644
--- a/client/components/sidebar/sidebarCustomFields.js
+++ b/client/components/sidebar/sidebarCustomFields.js
@@ -15,50 +15,111 @@ BlazeComponent.extendComponent({
}).register('customFieldsSidebar');
-Template.createCustomFieldPopup.helpers({
+const CreateCustomFieldPopup = BlazeComponent.extendComponent({
+
+ _types: ['text', 'number', 'checkbox', 'date', 'dropdown'],
+
+ onCreated() {
+ this.type = new ReactiveVar((this.data().type) ? this.data().type : this._types[0]);
+ this.dropdownItems = new ReactiveVar((this.data().settings && this.data().settings.dropdownItems) ? this.data().settings.dropdownItems : []);
+ },
+
types() {
- var currentType = this.type;
- return ['text', 'number', 'checkbox', 'date', 'dropdown'].
- map(type => {return {
- type: type,
- name: TAPi18n.__('custom-field-' + type),
- selected: type == currentType,
- }});
+ const currentType = this.data().type;
+ return this._types.
+ map(type => {return {
+ value: type,
+ name: TAPi18n.__('custom-field-' + type),
+ selected: type == currentType,
+ }});
+ },
+
+ isTypeNotSelected(type) {
+ return this.type.get() !== type;
+ },
+
+ getDropdownItems() {
+ var items = this.dropdownItems.get();
+ Array.from(this.findAll('.js-field-settings-dropdown input')).forEach((el, index) => {
+ //console.log('each item!', index, el.value);
+ if (!items[index]) items[index] = {
+ _id: Random.id(6),
+ };
+ items[index].name = el.value.trim();
+ });
+ return items;
},
-});
-Template.createCustomFieldPopup.events({
- 'click .js-field-show-on-card'(event) {
- let $target = $(event.target);
- if(!$target.hasClass('js-field-show-on-card')){
- $target = $target.parent();
+ getSettings() {
+ let settings = {};
+ switch (this.type.get()) {
+ case 'dropdown':
+ let dropdownItems = this.getDropdownItems().filter(item => !!item.name.trim());
+ settings.dropdownItems = dropdownItems;
+ break;
}
- $target.find('.materialCheckBox').toggleClass('is-checked');
- $target.toggleClass('is-checked');
+ return settings;
},
- 'submit'(evt, tpl) {
- evt.preventDefault();
- const name = tpl.find('.js-field-name').value.trim();
- const type = tpl.find('.js-field-type').value.trim();
- const showOnCard = tpl.find('.js-field-show-on-card.is-checked') != null;
- //console.log('Create',name,type,showOnCard);
+ events() {
+ return [{
+ 'change .js-field-type'(evt) {
+ const value = evt.target.value;
+ this.type.set(value);
+ },
+ 'keydown .js-dropdown-item.last'(evt) {
+ if (evt.target.value.trim() && evt.keyCode === 13) {
+ let items = this.getDropdownItems();
+ this.dropdownItems.set(items);
+ evt.target.value = '';
+ }
+ },
+ 'click .js-field-show-on-card'(evt) {
+ let $target = $(evt.target);
+ if(!$target.hasClass('js-field-show-on-card')){
+ $target = $target.parent();
+ }
+ $target.find('.materialCheckBox').toggleClass('is-checked');
+ $target.toggleClass('is-checked');
+ },
+ 'click .primary'(evt) {
+ evt.preventDefault();
+
+ const data = {
+ boardId: Session.get('currentBoard'),
+ name: this.find('.js-field-name').value.trim(),
+ type: this.type.get(),
+ settings: this.getSettings(),
+ showOnCard: this.find('.js-field-show-on-card.is-checked') != null
+ }
- CustomFields.insert({
- boardId: Session.get('currentBoard'),
- name: name,
- type: type,
- showOnCard: showOnCard
- });
+ // insert or update
+ if (!this.data()._id) {
+ CustomFields.insert(data);
+ } else {
+ CustomFields.update(this.data()._id, {$set: data});
+ }
- Popup.back();
+ Popup.back();
+ },
+ 'click .js-delete-custom-field': Popup.afterConfirm('deleteCustomField', function() {
+ const customFieldId = this._id;
+ CustomFields.remove(customFieldId);
+ Popup.close();
+ }),
+ }];
},
- 'click .js-delete-custom-field': Popup.afterConfirm('deleteCustomField', function() {
- const customFieldId = this._id;
- CustomFields.remove(customFieldId);
- Popup.close();
- }),
+
});
+CreateCustomFieldPopup.register('createCustomFieldPopup');
+
+(class extends CreateCustomFieldPopup {
+
+ template() {
+ return 'createCustomFieldPopup';
+ }
+
+}).register('editCustomFieldPopup');
/*Template.deleteCustomFieldPopup.events({
'submit'(evt) {
diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json
index 1039d3c6..a6893117 100644
--- a/i18n/en.i18n.json
+++ b/i18n/en.i18n.json
@@ -155,7 +155,6 @@
"create": "Create",
"createBoardPopup-title": "Create Board",
"chooseBoardSourcePopup-title": "Import board",
- "configure-custom-fields": "Configure Custom Fields",
"createLabelPopup-title": "Create Label",
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
@@ -164,8 +163,13 @@
"custom-field-checkbox": "Checkbox",
"custom-field-date": "Date",
"custom-field-dropdown": "Dropdown List",
+ "custom-field-dropdown-none": "(none)",
+ "custom-field-dropdown-options": "List Options",
+ "custom-field-dropdown-options-placeholder": "Press enter to add more options",
+ "custom-field-dropdown-unknown": "(unknown)",
"custom-field-number": "Number",
"custom-field-text": "Text",
+ "custom-fields": "Custom Fields",
"date": "Date",
"decline": "Decline",
"default-avatar": "Default avatar",
diff --git a/models/customFields.js b/models/customFields.js
index 5e76db35..8b0abef4 100644
--- a/models/customFields.js
+++ b/models/customFields.js
@@ -9,6 +9,24 @@ CustomFields.attachSchema(new SimpleSchema({
},
type: {
type: String,
+ allowedValues: ['text', 'number', 'checkbox', 'date', 'dropdown']
+ },
+ settings: {
+ type: Object,
+ },
+ 'settings.dropdownItems': {
+ type: [Object],
+ optional: true
+ },
+ 'settings.dropdownItems.$': {
+ type: new SimpleSchema({
+ _id: {
+ type: String,
+ },
+ name: {
+ type: String,
+ },
+ })
},
showOnCard: {
type: Boolean,
@@ -83,6 +101,7 @@ if (Meteor.isServer) {
const id = CustomFields.direct.insert({
name: req.body.name,
type: req.body.type,
+ settings: req.body.settings,
showOnCard: req.body.showOnCard,
boardId: paramBoardId,
});