diff --git a/client/components/lists/list.css b/client/components/lists/list.css index 5e503a4d7..5e5950aa9 100644 --- a/client/components/lists/list.css +++ b/client/components/lists/list.css @@ -179,6 +179,9 @@ #js-wip-limit-edit div { float: left; } +#js-list-width-edit .list-width-error { + display: none; +} @media screen and (max-width: 800px) { .mini-list { flex: 0 0 60px; diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index 847ea3ab2..485058100 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -62,6 +62,11 @@ template(name="listActionPopup") i.fa.fa-arrow-down | {{_ 'add-card-to-bottom-of-list'}} hr + ul.pop-over-list + li + a.js-set-list-width + i.fa.fa-arrows-h + | {{_ 'set-list-width'}} ul.pop-over-list li a.js-toggle-watch-list @@ -156,6 +161,19 @@ template(name="wipLimitErrorPopup") p {{_ 'wipLimitErrorPopup-dialog-pt2'}} button.full.js-back-view(type="submit") {{_ 'cancel'}} +template(name="setListWidthPopup") + #js-list-width-edit + label {{_ 'set-list-width-value'}} + p + input.list-width-value(type="number" value="{{ listWidthValue }}" min="100" max="800") + input.list-width-apply(type="submit" value="{{_ 'apply'}}") + input.list-width-error + +template(name="listWidthErrorPopup") + .list-width-invalid + p {{_ 'list-width-error-message'}} + button.full.js-back-view(type="submit") {{_ 'cancel'}} + template(name="setListColorPopup") form.edit-label .palette-colors: each colors diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index db5564974..923f89c22 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -151,6 +151,7 @@ Template.listActionPopup.events({ }); Popup.back(); }, + 'click .js-set-list-width': Popup.open('setListWidth'), 'click .js-set-color-list': Popup.open('setListColor'), 'click .js-select-cards'() { const cardIds = this.allCards().map(card => card._id); @@ -319,3 +320,41 @@ BlazeComponent.extendComponent({ ]; }, }).register('setListColorPopup'); + +BlazeComponent.extendComponent({ + applyListWidth() { + const list = Template.currentData(); + const board = list.boardId; + const width = parseInt( + Template.instance() + .$('.list-width-value') + .val(), + 10, + ); + + // FIXME(mark-i-m): where do we put constants? + if (width < 100 || !width) { + Template.instance() + .$('.list-width-error') + .click(); + } else { + Meteor.call('applyListWidth', board, list._id, width); + Popup.back(); + } + }, + + listWidthValue() { + const list = Template.currentData(); + const board = list.boardId; + return Meteor.user().getListWidth(board, list._id); + }, + + events() { + return [ + { + 'click .list-width-apply': this.applyListWidth, + 'click .list-width-error': Popup.open('listWidthError'), + }, + ]; + }, +}).register('setListWidthPopup'); diff --git a/imports/i18n/data/en.i18n.json b/imports/i18n/data/en.i18n.json index f6c74e490..f157537d1 100644 --- a/imports/i18n/data/en.i18n.json +++ b/imports/i18n/data/en.i18n.json @@ -85,6 +85,9 @@ "add-card": "Add Card", "add-card-to-top-of-list": "Add Card to Top of List", "add-card-to-bottom-of-list": "Add Card to Bottom of List", + "set-list-width": "Set List Width", + "set-list-width-value": "List Width (pixels)", + "list-width-error-message": "List width must be a positive integer between 100 and 800. TODO(mark-i-m): hard-coded constants", "add-swimlane": "Add Swimlane", "add-subtask": "Add Subtask", "add-checklist": "Add Checklist", diff --git a/models/lists.js b/models/lists.js index 50f7a7803..21e372114 100644 --- a/models/lists.js +++ b/models/lists.js @@ -79,21 +79,6 @@ Lists.attachSchema( // XXX We should probably provide a default optional: true, }, - width: { - /** - * list width, default 270px - */ - type: String, - defaultValue: '270px', - optional: true, - }, - height: { - /** - * list height - */ - type: String, - optional: true, - }, updatedAt: { /** * last update of the list diff --git a/models/users.js b/models/users.js index c707da6c0..d6487df82 100644 --- a/models/users.js +++ b/models/users.js @@ -422,6 +422,24 @@ Users.attachSchema( type: String, defaultValue: '', }, + 'profile.listWidths': { + /** + * User-specified width of each list (or nothing if default). + * profile[boardId][listId] = width; + */ + type: Object, + defaultValue: {}, + blackbox: true, + }, + 'profile.swimlaneHeights': { + /** + * User-specified heights of each swimlane (or nothing if default). + * profile[boardId][swimlaneId] = height; + */ + type: Object, + defaultValue: {}, + blackbox: true, + }, services: { /** * services field of the user @@ -760,6 +778,19 @@ Users.helpers({ return this._getListSortBy()[1]; }, + getListWidths() { + const { listWidths = {} } = this.profile || {}; + return listWidths; + }, + getListWidth(boardId, listId) { + const listWidths = this.getListWidths(); + if (listWidths[boardId] && listWidths[boardId][listId]) { + return listWidths[boardId][listId]; + } else { + return 270; //TODO(mark-i-m): default? + } + }, + /** returns all confirmed move and copy dialog field values *
  • the board, swimlane and list id is stored for each board */ @@ -1137,6 +1168,19 @@ Users.mutations({ }, }; }, + + setListWidth(boardId, listId, width) { + let currentWidths = this.getListWidths(); + if (!currentWidths[boardId]) { + currentWidths[boardId] = {}; + } + currentWidths[boardId][listId] = width; + return { + $set: { + 'profile.listWidths': currentWidths, + }, + }; + }, }); Meteor.methods({ @@ -1180,6 +1224,13 @@ Meteor.methods({ check(startDay, Number); Meteor.user().setStartDayOfWeek(startDay); }, + applyListWidth(boardId, listId, width) { + check(boardId, String); + check(listId, String); + check(width, Number); + const user = Meteor.user(); + user.setListWidth(boardId, listId, width); + }, }); if (Meteor.isServer) {