Browse Source

dropdown items

Pouyan Savoli 7 years ago
parent
commit
3753337d60

+ 1 - 1
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'}}

+ 1 - 1
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();
   },

+ 26 - 3
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)
@@ -25,5 +28,25 @@ template(name="cardCustomFieldText")
                 if value
                     +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'}}

+ 45 - 17
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');
+}).register('cardCustomField-dropdown');

+ 3 - 0
client/components/forms/forms.styl

@@ -85,6 +85,9 @@ select
   width: 256px
   margin-bottom: 8px
 
+  &.inline
+  	width: 100%
+
 option[disabled]
   color: #8c8c8c
 

+ 1 - 1
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',
 };
 

+ 13 - 10
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'}}

+ 95 - 34
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) {

+ 5 - 1
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",

+ 19 - 0
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,
     });