From c9c650664fd92f0924afb4548a50c7bca167d955 Mon Sep 17 00:00:00 2001 From: amadilsons Date: Thu, 28 Sep 2017 16:59:53 +0200 Subject: [PATCH 1/6] basic frontend setup, List model updated with wipLimit field --- client/components/lists/listHeader.jade | 12 ++++++++++++ client/components/lists/listHeader.js | 6 ++++++ i18n/en-GB.i18n.json | 4 +++- i18n/en.i18n.json | 2 ++ i18n/pt-BR.i18n.json | 4 +++- models/lists.js | 5 +++++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index 68336320d..67fbe9581 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -6,6 +6,11 @@ template(name="listHeader") h2.list-header-name( class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}") = title + if hasWipLimit + span.wip-limit + | ( + = wipLimit + | ) if showCardsCountForList cards.count = cards.count span.lowercase @@ -33,6 +38,9 @@ template(name="listActionPopup") if cards.count li: a.js-select-cards {{_ 'list-select-cards'}} hr + ul.pop-over-list + li: a.js-set-wip-limit {{#if hasWipLimit}}{{_ 'edit-wip-limit'}}{{else}}{{_ 'set-wip-limit'}}{{/if}} + hr ul.pop-over-list li: a.js-close-list {{_ 'archive-list'}} hr @@ -64,3 +72,7 @@ template(name="listDeletePopup") unless archived p {{_ "list-delete-suggest-archive"}} button.js-confirm.negate.full(type="submit") {{_ 'delete'}} + +template(name="setWipLimitPopup") + p {{_ 'set-wip-limit'}} + input(type="number") diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index 7fe42884d..47fddd27f 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -21,6 +21,11 @@ BlazeComponent.extendComponent({ return count > this.limitToShowCardsCount(); }, + hasWipLimit() { + return null; + //return this.currentData().wipLimit ? true : false; + }, + events() { return [{ 'click .js-open-list-menu': Popup.open('listAction'), @@ -61,6 +66,7 @@ Template.listActionPopup.events({ this.archive(); Popup.close(); }, + 'click .js-set-wip-limit': Popup.open('setWipLimit'), 'click .js-more': Popup.open('listMore'), }); diff --git a/i18n/en-GB.i18n.json b/i18n/en-GB.i18n.json index 8db041a5a..2884ea682 100644 --- a/i18n/en-GB.i18n.json +++ b/i18n/en-GB.i18n.json @@ -167,6 +167,7 @@ "edit": "Edit", "edit-avatar": "Change Avatar", "edit-profile": "Edit Profile", + "edit-wip-limit": "Edit WIP Limit", "editCardStartDatePopup-title": "Change start date", "editCardDueDatePopup-title": "Change due date", "editLabelPopup-title": "Change Label", @@ -306,6 +307,7 @@ "save": "Save", "search": "Search", "select-color": "Select Color", + "set-wip-limit": "Set WIP Limit", "shortcut-assign-self": "Assign yourself to current card", "shortcut-autocomplete-emoji": "Autocomplete emoji", "shortcut-autocomplete-members": "Autocomplete members", @@ -391,4 +393,4 @@ "no": "No", "accounts": "Accounts", "accounts-allowEmailChange": "Allow Email Change" -} \ No newline at end of file +} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 64a720db0..0ccace571 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -167,6 +167,7 @@ "edit": "Edit", "edit-avatar": "Change Avatar", "edit-profile": "Edit Profile", + "edit-wip-limit": "Edit WIP Limit", "editCardStartDatePopup-title": "Change start date", "editCardDueDatePopup-title": "Change due date", "editLabelPopup-title": "Change Label", @@ -306,6 +307,7 @@ "save": "Save", "search": "Search", "select-color": "Select Color", + "set-wip-limit": "Set WIP Limit", "shortcut-assign-self": "Assign yourself to current card", "shortcut-autocomplete-emoji": "Autocomplete emoji", "shortcut-autocomplete-members": "Autocomplete members", diff --git a/i18n/pt-BR.i18n.json b/i18n/pt-BR.i18n.json index 1ea99b76c..e40d7ed0f 100644 --- a/i18n/pt-BR.i18n.json +++ b/i18n/pt-BR.i18n.json @@ -167,6 +167,7 @@ "edit": "Editar", "edit-avatar": "Alterar Avatar", "edit-profile": "Editar Perfil", + "edit-wip-limit": "Editar Limite WIP", "editCardStartDatePopup-title": "Altera data de início", "editCardDueDatePopup-title": "Altera data fim", "editLabelPopup-title": "Alterar Etiqueta", @@ -306,6 +307,7 @@ "save": "Salvar", "search": "Buscar", "select-color": "Selecionar Cor", + "set-wip-limit": "Definir Limite WIP", "shortcut-assign-self": "Atribuir a si o cartão atual", "shortcut-autocomplete-emoji": "Autocompletar emoji", "shortcut-autocomplete-members": "Preenchimento automático de membros", @@ -391,4 +393,4 @@ "no": "Não", "accounts": "Contas", "accounts-allowEmailChange": "Permitir Mudança de Email" -} \ No newline at end of file +} diff --git a/models/lists.js b/models/lists.js index d9a5b8e2a..80accefb8 100644 --- a/models/lists.js +++ b/models/lists.js @@ -42,6 +42,11 @@ Lists.attachSchema(new SimpleSchema({ } }, }, + + wipLimit: { + type: SimpleSchema.Integer, + optional: true, + }, })); Lists.allow({ From a918d36533bd61765f954f60c0e3af78b014907a Mon Sep 17 00:00:00 2001 From: amadilsons Date: Fri, 29 Sep 2017 16:52:53 +0200 Subject: [PATCH 2/6] mostly frontend work, lists coll update with wipLimit field --- client/components/lists/list.styl | 13 +++++++++++++ client/components/lists/listHeader.jade | 15 ++++++++------- client/components/lists/listHeader.js | 20 +++++++++++++++----- i18n/en-GB.i18n.json | 3 ++- i18n/en.i18n.json | 3 ++- i18n/pt-BR.i18n.json | 3 ++- models/lists.js | 5 ++++- 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl index 5e20476e3..4c6c792fb 100644 --- a/client/components/lists/list.styl +++ b/client/components/lists/list.styl @@ -110,3 +110,16 @@ background: #fafafa color: #222 box-shadow: 0 1px 2px rgba(0,0,0,.2) + +#js-wip-limit-edit + padding-top: 2% + + p + margin-bottom: 0 + + input + display: inline-block + + .wip-limit-value + width: 20% + margin-right: 5% diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index 67fbe9581..5d352b2e0 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -7,10 +7,8 @@ template(name="listHeader") class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}") = title if hasWipLimit - span.wip-limit - | ( - = wipLimit - | ) + span + | (#{wipLimit}) if showCardsCountForList cards.count = cards.count span.lowercase @@ -39,7 +37,7 @@ template(name="listActionPopup") li: a.js-select-cards {{_ 'list-select-cards'}} hr ul.pop-over-list - li: a.js-set-wip-limit {{#if hasWipLimit}}{{_ 'edit-wip-limit'}}{{else}}{{_ 'set-wip-limit'}}{{/if}} + li: a.js-set-wip-limit {{#if hasWipLimit}}{{_ 'edit-wip-limit'}}{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}} hr ul.pop-over-list li: a.js-close-list {{_ 'archive-list'}} @@ -74,5 +72,8 @@ template(name="listDeletePopup") button.js-confirm.negate.full(type="submit") {{_ 'delete'}} template(name="setWipLimitPopup") - p {{_ 'set-wip-limit'}} - input(type="number") + #js-wip-limit-edit + lable {{_ 'set-wip-limit-value'}} + p + input.wip-limit-value(type="number" value="#{wipLimit}" min="0" max="99" onkeydown="return false") + input.wip-limit-apply(type="submit" value="{{_ 'apply'}}") diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index 47fddd27f..0dc15315b 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -8,6 +8,10 @@ BlazeComponent.extendComponent({ } }, + hasWipLimit() { + return this.currentData().wipLimit > 0 ? true : false; + }, + isWatching() { const list = this.currentData(); return list.findWatcher(Meteor.userId()); @@ -21,11 +25,6 @@ BlazeComponent.extendComponent({ return count > this.limitToShowCardsCount(); }, - hasWipLimit() { - return null; - //return this.currentData().wipLimit ? true : false; - }, - events() { return [{ 'click .js-open-list-menu': Popup.open('listAction'), @@ -42,6 +41,10 @@ BlazeComponent.extendComponent({ }).register('listHeader'); Template.listActionPopup.helpers({ + hasWipLimit() { + return this.wipLimit > 0 ? true : false; + }, + isWatching() { return this.findWatcher(Meteor.userId()); }, @@ -70,6 +73,13 @@ Template.listActionPopup.events({ 'click .js-more': Popup.open('listMore'), }); +Template.setWipLimitPopup.events({ + 'click .wip-limit-apply'(_, instance) { + const limit = instance.$('.wip-limit-value').val(); + this.setWipLimit(limit); + }, +}); + Template.listMorePopup.events({ 'click .js-delete': Popup.afterConfirm('listDelete', function () { Popup.close(); diff --git a/i18n/en-GB.i18n.json b/i18n/en-GB.i18n.json index 2884ea682..816d42087 100644 --- a/i18n/en-GB.i18n.json +++ b/i18n/en-GB.i18n.json @@ -307,7 +307,8 @@ "save": "Save", "search": "Search", "select-color": "Select Color", - "set-wip-limit": "Set WIP Limit", + "set-wip-limit-value": "Set a limit for the maximum number of tasks in this list:", + "setWipLimitPopup-title": "Set WIP Limit", "shortcut-assign-self": "Assign yourself to current card", "shortcut-autocomplete-emoji": "Autocomplete emoji", "shortcut-autocomplete-members": "Autocomplete members", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 0ccace571..139a10114 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -307,7 +307,8 @@ "save": "Save", "search": "Search", "select-color": "Select Color", - "set-wip-limit": "Set WIP Limit", + "set-wip-limit-value": "Set a limit for the maximum number of tasks in this list", + "setWipLimitPopup-title": "Set WIP Limit", "shortcut-assign-self": "Assign yourself to current card", "shortcut-autocomplete-emoji": "Autocomplete emoji", "shortcut-autocomplete-members": "Autocomplete members", diff --git a/i18n/pt-BR.i18n.json b/i18n/pt-BR.i18n.json index e40d7ed0f..39bb67c16 100644 --- a/i18n/pt-BR.i18n.json +++ b/i18n/pt-BR.i18n.json @@ -307,7 +307,8 @@ "save": "Salvar", "search": "Buscar", "select-color": "Selecionar Cor", - "set-wip-limit": "Definir Limite WIP", + "set-wip-limit-value": "Defina um limite máximo para o número de tarefas nesta lista", + "setWipLimitPopup-title": "Definir Limite WIP", "shortcut-assign-self": "Atribuir a si o cartão atual", "shortcut-autocomplete-emoji": "Autocompletar emoji", "shortcut-autocomplete-members": "Preenchimento automático de membros", diff --git a/models/lists.js b/models/lists.js index 80accefb8..837af73c5 100644 --- a/models/lists.js +++ b/models/lists.js @@ -42,7 +42,6 @@ Lists.attachSchema(new SimpleSchema({ } }, }, - wipLimit: { type: SimpleSchema.Integer, optional: true, @@ -91,6 +90,10 @@ Lists.mutations({ restore() { return { $set: { archived: false } }; }, + + setWipLimit(limit) { + return { $set: { wipLimit: limit } }; + }, }); Lists.hookOptions.after.update = { fetchPrevious: false }; From 089dbf0cf6a3e144d0271a8666d58e689f8c8dba Mon Sep 17 00:00:00 2001 From: amadilsons Date: Wed, 4 Oct 2017 11:12:52 +0200 Subject: [PATCH 3/6] on its way --- client/components/lists/list.styl | 5 +- client/components/lists/listHeader.jade | 26 ++++++-- client/components/lists/listHeader.js | 83 ++++++++++++++++++++++--- i18n/en-GB.i18n.json | 1 + i18n/en.i18n.json | 1 + i18n/pt-BR.i18n.json | 1 + models/lists.js | 28 ++++++++- 7 files changed, 128 insertions(+), 17 deletions(-) diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl index 4c6c792fb..f426b243f 100644 --- a/client/components/lists/list.styl +++ b/client/components/lists/list.styl @@ -113,7 +113,7 @@ #js-wip-limit-edit padding-top: 2% - + p margin-bottom: 0 @@ -123,3 +123,6 @@ .wip-limit-value width: 20% margin-right: 5% + + .wip-limit-error + display: none diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index 5d352b2e0..97dbf1c88 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -6,9 +6,9 @@ template(name="listHeader") h2.list-header-name( class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}") = title - if hasWipLimit + if isWipLimitEnabled span - | (#{wipLimit}) + | (#{wipLimit.value}) if showCardsCountForList cards.count = cards.count span.lowercase @@ -37,7 +37,7 @@ template(name="listActionPopup") li: a.js-select-cards {{_ 'list-select-cards'}} hr ul.pop-over-list - li: a.js-set-wip-limit {{#if hasWipLimit}}{{_ 'edit-wip-limit'}}{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}} + li: a.js-set-wip-limit {{#if isWipLimitEnabled }}EDIT{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}} hr ul.pop-over-list li: a.js-close-list {{_ 'archive-list'}} @@ -74,6 +74,20 @@ template(name="listDeletePopup") template(name="setWipLimitPopup") #js-wip-limit-edit lable {{_ 'set-wip-limit-value'}} - p - input.wip-limit-value(type="number" value="#{wipLimit}" min="0" max="99" onkeydown="return false") - input.wip-limit-apply(type="submit" value="{{_ 'apply'}}") + {{one}} + ul.pop-over-list + li: a.js-enable-wip-limit Enable WIP Limit + if isWipLimitEnabled + i.fa.fa-check + + if isWipLimitEnabled + p + input.wip-limit-value(type="number" value="#{wipLimit.value}" min="1" max="99" onkeydown="return false") + input.wip-limit-apply(type="submit" value="{{_ 'apply'}}") + input.wip-limit-error + +template(name="wipLimitErrorPopup") + .wip-limit-invalid + p The number of tasks in this list is higher than the WIP limit you've defined. + p Please move some tasks out of this list, or set a higher WIP limit. + button.full.js-back-view(type="submit") {{_ 'cancel'}} diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index 0dc15315b..9ae2c1fe2 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -8,8 +8,9 @@ BlazeComponent.extendComponent({ } }, - hasWipLimit() { - return this.currentData().wipLimit > 0 ? true : false; + isWipLimitEnabled() { + const limit = this.currentData().wipLimit + return limit.enabled && limit.value > 0; }, isWatching() { @@ -41,10 +42,9 @@ BlazeComponent.extendComponent({ }).register('listHeader'); Template.listActionPopup.helpers({ - hasWipLimit() { - return this.wipLimit > 0 ? true : false; + isWipLimitEnabled() { + return Lists.findOne(this.data()._id, { 'wipLimit.enabled': 1 }).wipLimit.enabled; }, - isWatching() { return this.findWatcher(Meteor.userId()); }, @@ -73,13 +73,78 @@ Template.listActionPopup.events({ 'click .js-more': Popup.open('listMore'), }); -Template.setWipLimitPopup.events({ - 'click .wip-limit-apply'(_, instance) { - const limit = instance.$('.wip-limit-value').val(); - this.setWipLimit(limit); +Template.setWipLimitPopup.helpers({ + one() { + //console.log(this) + //console.log(Template.instance()) + } +}); + +BlazeComponent.extendComponent({ + onCreated() { + this.wipEnabled = new ReactiveVar(Template.currentData().wipLimit.enabled); + }, + + toggleWipEnabled() { + const list = Lists.findOne(this.data()._id); + list.wipLimit.enabled ? list.setWipLimitDisabled() : list.setWipLimitEnabled() + }, + + isWipLimitEnabled() { + return Lists.findOne(this.data()._id, { 'wipLimit.enabled': 1 }).wipLimit.enabled; + }, + events() { + return [{ + 'click .js-enable-wip-limit'(_, instance) { + //By default wipLimit.enabled is false or undefined. First click will always be to enable wip limiting + this.wipEnabled.set(!this.wipEnabled.get()); + //console.log(Template.parentData(2)) + //Template.parentData(2).data.toggleWipLimit(!Template.currentData().wipLimit.enabled); //If wipLimit.enabled is not yet definied, the negation of "undefined" is "true" + this.toggleWipEnabled() + }, + 'click .wip-limit-apply'(_, instance) { + const list = Template.currentData(); + const limit = Template.instance().$('.wip-limit-value').val(); + + if(limit < list.allCards().count()){ + Template.instance().$('.wip-limit-error').click(); + } else { + list.setWipLimit(limit); + } + }, + 'click .wip-limit-error': Popup.open('wipLimitError'), + }]; + }, +}).register('setWipLimitPopup'); + + +/* +Template.setWipLimitPopup.helpers({ + isWipLimitEnabled(instance) { + console.log(this); + console.log(Template.currentData()); + console.log(instance); + return Template.currentData().wipLimit.enabled; }, }); +Template.setWipLimitPopup.events({ + 'click .js-enable-wip-limit'(_, instance) { + //By default wipLimit.enabled is false or undefined. First click will always be to enable wip limiting + instance.wipEnabled.set(!instance.wipEnabled.get()) + // list.toggleWipLimit(!list.wipLimit.enabled); //If wipLimit.enabled is not yet definied, the negation of "undefined" is "true" + }, + 'click .wip-limit-apply'(_, instance) { + const limit = instance.$('.wip-limit-value').val(); + if(limit < this.allCards().count()){ + instance.$('.wip-limit-error').click(); //open popup with invisible button click + return; + } + this.setWipLimit(limit); + }, + 'click .wip-limit-error': Popup.open('wipLimitError'), +});*/ + Template.listMorePopup.events({ 'click .js-delete': Popup.afterConfirm('listDelete', function () { Popup.close(); diff --git a/i18n/en-GB.i18n.json b/i18n/en-GB.i18n.json index 816d42087..f49d3d843 100644 --- a/i18n/en-GB.i18n.json +++ b/i18n/en-GB.i18n.json @@ -349,6 +349,7 @@ "welcome-list1": "Basics", "welcome-list2": "Advanced", "what-to-do": "What do you want to do?", + "wipLimitErrorPopup-title": "Invalid WIP Limit", "admin-panel": "Admin Panel", "settings": "Settings", "people": "People", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 139a10114..a16a3b3bd 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -349,6 +349,7 @@ "welcome-list1": "Basics", "welcome-list2": "Advanced", "what-to-do": "What do you want to do?", + "wipLimitErrorPopup-title": "Invalid WIP Limit", "admin-panel": "Admin Panel", "settings": "Settings", "people": "People", diff --git a/i18n/pt-BR.i18n.json b/i18n/pt-BR.i18n.json index 39bb67c16..97927e6d5 100644 --- a/i18n/pt-BR.i18n.json +++ b/i18n/pt-BR.i18n.json @@ -349,6 +349,7 @@ "welcome-list1": "Básico", "welcome-list2": "Avançado", "what-to-do": "O que você gostaria de fazer?", + "wipLimitErrorPopup-title": "Limite WIP Inválido", "admin-panel": "Painel Administrativo", "settings": "Configurações", "people": "Pessoas", diff --git a/models/lists.js b/models/lists.js index 837af73c5..29dd28fbf 100644 --- a/models/lists.js +++ b/models/lists.js @@ -43,9 +43,22 @@ Lists.attachSchema(new SimpleSchema({ }, }, wipLimit: { + type: Object, + optional: true, + }, + "wipLimit.value": { type: SimpleSchema.Integer, optional: true, }, + "wipLimit.enabled":{ + type: Boolean, + autoValue() { + if(this.isInsert){ + return false; + } + }, + optional: true, + }, })); Lists.allow({ @@ -91,8 +104,21 @@ Lists.mutations({ return { $set: { archived: false } }; }, + toggleWipLimit(toggle) { + console.log("toggle " + this.wipLimit.enabled) + return { $set: { "wipLimit.enabled": !this.wipLimit.enabled } }; + }, + + setWipLimitEnabled() { + return { $set: { "wipLimit.enabled": true } }; + }, + + setWipLimitDisabled() { + return { $set: { "wipLimit.enabled": false } }; + }, + setWipLimit(limit) { - return { $set: { wipLimit: limit } }; + return { $set: { "wipLimit.value": limit } }; }, }); From c865bfe49785181d97b25cb683c0ed37d82c1a69 Mon Sep 17 00:00:00 2001 From: amadilsons Date: Wed, 4 Oct 2017 17:48:37 +0200 Subject: [PATCH 4/6] most work concluded, code needs clean up, further testing required --- client/components/lists/list.js | 4 +- client/components/lists/listBody.jade | 2 +- client/components/lists/listBody.js | 16 +-- client/components/lists/listHeader.jade | 13 ++- client/components/lists/listHeader.js | 101 ++++++++----------- client/components/sidebar/sidebarArchives.js | 4 +- client/lib/popup.js | 1 - models/cards.js | 8 ++ models/lists.js | 11 +- 9 files changed, 72 insertions(+), 88 deletions(-) diff --git a/client/components/lists/list.js b/client/components/lists/list.js index 9c191348f..d99fc963b 100644 --- a/client/components/lists/list.js +++ b/client/components/lists/list.js @@ -22,7 +22,7 @@ BlazeComponent.extendComponent({ const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)'; const $cards = this.$('.js-minicards'); $cards.sortable({ - connectWith: '.js-minicards', + connectWith: '.js-minicards:not(.js-list-full)', tolerance: 'pointer', appendTo: 'body', helper(evt, item) { @@ -81,7 +81,7 @@ BlazeComponent.extendComponent({ function userIsMember() { return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); } - + // Disable drag-dropping if the current user is not a board member or is comment only this.autorun(() => { $cards.sortable('option', 'disabled', !userIsMember()); diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade index 01aa71795..840fd8012 100644 --- a/client/components/lists/listBody.jade +++ b/client/components/lists/listBody.jade @@ -1,6 +1,6 @@ template(name="listBody") .list-body.js-perfect-scrollbar - .minicards.clearfix.js-minicards + .minicards.clearfix.js-minicards(class="{{#if reachedWipLimit}}js-list-full{{/if}}") if cards.count +inlinedForm(autoclose=false position="top") +addCardForm(listId=_id position="top") diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js index 724e805bc..5ae645a9d 100644 --- a/client/components/lists/listBody.js +++ b/client/components/lists/listBody.js @@ -96,6 +96,15 @@ BlazeComponent.extendComponent({ MultiSelection.toggle(this.currentData()._id); }, + canSeeAddCard() { + return !this.reachedWipLimit() && Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); + }, + + reachedWipLimit() { + const list = Template.currentData(); + return list.wipLimit.enabled && list.wipLimit.value == list.cards().count(); + }, + events() { return [{ 'click .js-minicard': this.clickOnMiniCard, @@ -239,10 +248,3 @@ BlazeComponent.extendComponent({ }); }, }).register('addCardForm'); - - -Template.listBody.helpers({ - canSeeAddCard() { - return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); - }, -}); diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index 97dbf1c88..df395d657 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -36,9 +36,10 @@ template(name="listActionPopup") if cards.count li: a.js-select-cards {{_ 'list-select-cards'}} hr - ul.pop-over-list - li: a.js-set-wip-limit {{#if isWipLimitEnabled }}EDIT{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}} - hr + if currentUser.isBoardAdmin + ul.pop-over-list + li: a.js-set-wip-limit {{#if isWipLimitEnabled }}{{_ 'edit-wip-limit'}}{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}} + hr ul.pop-over-list li: a.js-close-list {{_ 'archive-list'}} hr @@ -74,13 +75,11 @@ template(name="listDeletePopup") template(name="setWipLimitPopup") #js-wip-limit-edit lable {{_ 'set-wip-limit-value'}} - {{one}} ul.pop-over-list li: a.js-enable-wip-limit Enable WIP Limit - if isWipLimitEnabled + if wipEnabled.get i.fa.fa-check - - if isWipLimitEnabled + if wipEnabled.get p input.wip-limit-value(type="number" value="#{wipLimit.value}" min="1" max="99" onkeydown="return false") input.wip-limit-apply(type="submit" value="{{_ 'apply'}}") diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index 9ae2c1fe2..94b70f2bb 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -43,8 +43,14 @@ BlazeComponent.extendComponent({ Template.listActionPopup.helpers({ isWipLimitEnabled() { - return Lists.findOne(this.data()._id, { 'wipLimit.enabled': 1 }).wipLimit.enabled; + const prevState = Template.parentData(4).stack[0].dataContext.wipEnableState; + // If user was already inside setWipLimitPopup, return previous state. Popup stack not reacting to database mutations + if(typeof prevState !== "undefined") { + return prevState; + } + return Template.currentData().wipLimit.enabled; }, + isWatching() { return this.findWatcher(Meteor.userId()); }, @@ -73,78 +79,55 @@ Template.listActionPopup.events({ 'click .js-more': Popup.open('listMore'), }); -Template.setWipLimitPopup.helpers({ - one() { - //console.log(this) - //console.log(Template.instance()) - } -}); - BlazeComponent.extendComponent({ onCreated() { - this.wipEnabled = new ReactiveVar(Template.currentData().wipLimit.enabled); + const prevState = Template.parentData(4).stack[0].dataContext.wipEnableState; + // Check if the user as already opened this popup before and retrieve previous state + // This check is necessary due to the fact that database mutations inside popups are not reactive inside the popup stack. + //The use of ReactiveVar is due to the same reason. + if(typeof prevState !== "undefined") { + this.wipEnabled = new ReactiveVar(prevState) + } else { + this.wipEnabled = new ReactiveVar(Template.currentData().wipLimit.enabled); + } }, - toggleWipEnabled() { - const list = Lists.findOne(this.data()._id); - list.wipLimit.enabled ? list.setWipLimitDisabled() : list.setWipLimitEnabled() + onDestroyed() { + // Save current wipEnabled state in the first element of the popup stack to maintain UI coherence if user returns to popup + Template.parentData(4).stack[0].dataContext.wipEnableState = this.wipEnabled.get(); }, - isWipLimitEnabled() { - return Lists.findOne(this.data()._id, { 'wipLimit.enabled': 1 }).wipLimit.enabled; + applyWipLimit() { + const list = Template.currentData(); + const limit = Template.instance().$('.wip-limit-value').val(); + + if(limit < list.cards().count()){ + Template.instance().$('.wip-limit-error').click(); + } else { + list.setWipLimit(limit); + } }, + + enableWipLimit() { + const list = Template.currentData(); + // Prevent user from using previously stored wipLimit.value if it is less than the current number of cards in the list + if(!list.wipLimit.enabled && list.wipLimit.value < list.cards().count()){ + list.setWipLimit(list.cards().count()); + } + + this.wipEnabled.set(!this.wipEnabled.get()); //If wipLimit.enabled is not yet definied, the negation of "undefined" is "true" + list.toggleWipLimit(this.wipEnabled.get()); + }, + events() { return [{ - 'click .js-enable-wip-limit'(_, instance) { - //By default wipLimit.enabled is false or undefined. First click will always be to enable wip limiting - this.wipEnabled.set(!this.wipEnabled.get()); - //console.log(Template.parentData(2)) - //Template.parentData(2).data.toggleWipLimit(!Template.currentData().wipLimit.enabled); //If wipLimit.enabled is not yet definied, the negation of "undefined" is "true" - this.toggleWipEnabled() - }, - 'click .wip-limit-apply'(_, instance) { - const list = Template.currentData(); - const limit = Template.instance().$('.wip-limit-value').val(); - - if(limit < list.allCards().count()){ - Template.instance().$('.wip-limit-error').click(); - } else { - list.setWipLimit(limit); - } - }, + 'click .js-enable-wip-limit': this.enableWipLimit, + 'click .wip-limit-apply': this.applyWipLimit, 'click .wip-limit-error': Popup.open('wipLimitError'), }]; }, }).register('setWipLimitPopup'); - -/* -Template.setWipLimitPopup.helpers({ - isWipLimitEnabled(instance) { - console.log(this); - console.log(Template.currentData()); - console.log(instance); - return Template.currentData().wipLimit.enabled; - }, -}); - -Template.setWipLimitPopup.events({ - 'click .js-enable-wip-limit'(_, instance) { - //By default wipLimit.enabled is false or undefined. First click will always be to enable wip limiting - instance.wipEnabled.set(!instance.wipEnabled.get()) - // list.toggleWipLimit(!list.wipLimit.enabled); //If wipLimit.enabled is not yet definied, the negation of "undefined" is "true" - }, - 'click .wip-limit-apply'(_, instance) { - const limit = instance.$('.wip-limit-value').val(); - if(limit < this.allCards().count()){ - instance.$('.wip-limit-error').click(); //open popup with invisible button click - return; - } - this.setWipLimit(limit); - }, - 'click .wip-limit-error': Popup.open('wipLimitError'), -});*/ - Template.listMorePopup.events({ 'click .js-delete': Popup.afterConfirm('listDelete', function () { Popup.close(); diff --git a/client/components/sidebar/sidebarArchives.js b/client/components/sidebar/sidebarArchives.js index c8196f234..2e8754b0f 100644 --- a/client/components/sidebar/sidebarArchives.js +++ b/client/components/sidebar/sidebarArchives.js @@ -32,7 +32,9 @@ BlazeComponent.extendComponent({ return [{ 'click .js-restore-card'() { const card = this.currentData(); - card.restore(); + if(card.canBeRestored()){ + card.restore(); + } }, 'click .js-delete-card': Popup.afterConfirm('cardDelete', function() { const cardId = this._id; diff --git a/client/lib/popup.js b/client/lib/popup.js index 3658d883e..d9e29ff19 100644 --- a/client/lib/popup.js +++ b/client/lib/popup.js @@ -205,4 +205,3 @@ escapeActions.forEach((actionName) => { } ); }); - diff --git a/models/cards.js b/models/cards.js index 0a440697d..7d66bf8bc 100644 --- a/models/cards.js +++ b/models/cards.js @@ -179,6 +179,14 @@ Cards.helpers({ cardId: this._id, }); }, + + canBeRestored() { + const list = Lists.findOne({_id: this.listId}); + if(list.wipLimit.enabled && list.wipLimit.value == list.cards().count()){ + return false; + } + return true; + }, }); Cards.mutations({ diff --git a/models/lists.js b/models/lists.js index 29dd28fbf..442b9ee11 100644 --- a/models/lists.js +++ b/models/lists.js @@ -105,16 +105,7 @@ Lists.mutations({ }, toggleWipLimit(toggle) { - console.log("toggle " + this.wipLimit.enabled) - return { $set: { "wipLimit.enabled": !this.wipLimit.enabled } }; - }, - - setWipLimitEnabled() { - return { $set: { "wipLimit.enabled": true } }; - }, - - setWipLimitDisabled() { - return { $set: { "wipLimit.enabled": false } }; + return { $set: { "wipLimit.enabled": toggle } }; }, setWipLimit(limit) { From 214fe6a61f60513d3ddfc9eee423c1b932ff8463 Mon Sep 17 00:00:00 2001 From: amadilsons Date: Thu, 5 Oct 2017 16:46:55 +0200 Subject: [PATCH 5/6] feature implemented, known bugs fixed --- client/components/lists/list.js | 2 +- client/components/lists/listBody.js | 3 +- client/components/lists/listHeader.jade | 8 ++-- client/components/lists/listHeader.js | 54 ++++++++++--------------- models/cards.js | 2 +- models/lists.js | 47 ++++++++++++++++++--- 6 files changed, 71 insertions(+), 45 deletions(-) diff --git a/client/components/lists/list.js b/client/components/lists/list.js index d99fc963b..0e913207e 100644 --- a/client/components/lists/list.js +++ b/client/components/lists/list.js @@ -81,7 +81,7 @@ BlazeComponent.extendComponent({ function userIsMember() { return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); } - + // Disable drag-dropping if the current user is not a board member or is comment only this.autorun(() => { $cards.sortable('option', 'disabled', !userIsMember()); diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js index 5ae645a9d..22ed9e577 100644 --- a/client/components/lists/listBody.js +++ b/client/components/lists/listBody.js @@ -102,7 +102,8 @@ BlazeComponent.extendComponent({ reachedWipLimit() { const list = Template.currentData(); - return list.wipLimit.enabled && list.wipLimit.value == list.cards().count(); + if( !list.getWipLimit() ) { return false; } + return list.getWipLimit('enabled') && list.getWipLimit('value') === list.cards().count(); }, events() { diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index df395d657..f0c4e5f1e 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -8,7 +8,7 @@ template(name="listHeader") = title if isWipLimitEnabled span - | (#{wipLimit.value}) + | ({{cards.count}}/#{wipLimit.value}) if showCardsCountForList cards.count = cards.count span.lowercase @@ -77,11 +77,11 @@ template(name="setWipLimitPopup") lable {{_ 'set-wip-limit-value'}} ul.pop-over-list li: a.js-enable-wip-limit Enable WIP Limit - if wipEnabled.get + if isWipLimitEnabled i.fa.fa-check - if wipEnabled.get + if isWipLimitEnabled p - input.wip-limit-value(type="number" value="#{wipLimit.value}" min="1" max="99" onkeydown="return false") + input.wip-limit-value(type="number" value="{{ wipLimitValue }}" min="1" max="99" onkeydown="return false") input.wip-limit-apply(type="submit" value="{{_ 'apply'}}") input.wip-limit-error diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index 94b70f2bb..361f69cf9 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -8,16 +8,19 @@ BlazeComponent.extendComponent({ } }, - isWipLimitEnabled() { - const limit = this.currentData().wipLimit - return limit.enabled && limit.value > 0; - }, - isWatching() { const list = this.currentData(); return list.findWatcher(Meteor.userId()); }, + isWipLimitEnabled() { + const wipLimit = this.currentData().getWipLimit(); + if(!wipLimit) { + return 0; + } + return wipLimit.enabled && wipLimit.value > 0; + }, + limitToShowCardsCount() { return Meteor.user().getLimitToShowCardsCount(); }, @@ -43,12 +46,7 @@ BlazeComponent.extendComponent({ Template.listActionPopup.helpers({ isWipLimitEnabled() { - const prevState = Template.parentData(4).stack[0].dataContext.wipEnableState; - // If user was already inside setWipLimitPopup, return previous state. Popup stack not reacting to database mutations - if(typeof prevState !== "undefined") { - return prevState; - } - return Template.currentData().wipLimit.enabled; + return Template.currentData().getWipLimit('enabled'); }, isWatching() { @@ -80,43 +78,33 @@ Template.listActionPopup.events({ }); BlazeComponent.extendComponent({ - onCreated() { - const prevState = Template.parentData(4).stack[0].dataContext.wipEnableState; - // Check if the user as already opened this popup before and retrieve previous state - // This check is necessary due to the fact that database mutations inside popups are not reactive inside the popup stack. - //The use of ReactiveVar is due to the same reason. - if(typeof prevState !== "undefined") { - this.wipEnabled = new ReactiveVar(prevState) - } else { - this.wipEnabled = new ReactiveVar(Template.currentData().wipLimit.enabled); - } - }, - - onDestroyed() { - // Save current wipEnabled state in the first element of the popup stack to maintain UI coherence if user returns to popup - Template.parentData(4).stack[0].dataContext.wipEnableState = this.wipEnabled.get(); - }, - applyWipLimit() { const list = Template.currentData(); - const limit = Template.instance().$('.wip-limit-value').val(); + const limit = parseInt(Template.instance().$('.wip-limit-value').val(), 10); if(limit < list.cards().count()){ Template.instance().$('.wip-limit-error').click(); } else { - list.setWipLimit(limit); + Meteor.call('applyWipLimit', list._id, limit); + Popup.back(); } }, enableWipLimit() { const list = Template.currentData(); // Prevent user from using previously stored wipLimit.value if it is less than the current number of cards in the list - if(!list.wipLimit.enabled && list.wipLimit.value < list.cards().count()){ + if(list.getWipLimit() && !list.wipLimit.enabled && list.wipLimit.value < list.cards().count()){ list.setWipLimit(list.cards().count()); } + Meteor.call('enableWipLimit', Template.currentData()._id); + }, - this.wipEnabled.set(!this.wipEnabled.get()); //If wipLimit.enabled is not yet definied, the negation of "undefined" is "true" - list.toggleWipLimit(this.wipEnabled.get()); + isWipLimitEnabled() { + return Template.currentData().getWipLimit('enabled'); + }, + + wipLimitValue(){ + return Template.currentData().getWipLimit('value'); }, events() { diff --git a/models/cards.js b/models/cards.js index 7d66bf8bc..5b752ec35 100644 --- a/models/cards.js +++ b/models/cards.js @@ -182,7 +182,7 @@ Cards.helpers({ canBeRestored() { const list = Lists.findOne({_id: this.listId}); - if(list.wipLimit.enabled && list.wipLimit.value == list.cards().count()){ + if(list.getWipLimit() && list.getWipLimit('enabled') && list.getWipLimit('value') === list.cards().count()){ return false; } return true; diff --git a/models/lists.js b/models/lists.js index 442b9ee11..877b3d83f 100644 --- a/models/lists.js +++ b/models/lists.js @@ -46,16 +46,24 @@ Lists.attachSchema(new SimpleSchema({ type: Object, optional: true, }, - "wipLimit.value": { - type: SimpleSchema.Integer, + 'wipLimit.value': { + type: Number, + decimal: false, + autoValue() { + if(this.isInsert){ + return 0; + } + return this.value; + }, optional: true, }, - "wipLimit.enabled":{ + 'wipLimit.enabled':{ type: Boolean, autoValue() { if(this.isInsert){ return false; } + return this.value; }, optional: true, }, @@ -89,6 +97,17 @@ Lists.helpers({ board() { return Boards.findOne(this.boardId); }, + + getWipLimit(option){ + const list = Lists.findOne({ _id: this._id }); + if(!list.wipLimit) { // Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set + return 0; + } else if(!option) { + return list.wipLimit; + } else { + return list.wipLimit[option] ? list.wipLimit[option] : 0; // Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set + } + }, }); Lists.mutations({ @@ -105,11 +124,29 @@ Lists.mutations({ }, toggleWipLimit(toggle) { - return { $set: { "wipLimit.enabled": toggle } }; + return { $set: { 'wipLimit.enabled': toggle } }; }, setWipLimit(limit) { - return { $set: { "wipLimit.value": limit } }; + return { $set: { 'wipLimit.value': limit } }; + }, +}); + +Meteor.methods({ + applyWipLimit(listId, limit){ + check(listId, String); + check(limit, Number); + Lists.findOne({ _id: listId }).setWipLimit(limit); + }, + + enableWipLimit(listId) { + check(listId, String); + const list = Lists.findOne({ _id: listId }); + if( list.getWipLimit() ){ // Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set + list.toggleWipLimit(!list.wipLimit.enabled); + } else { + list.toggleWipLimit(true); // First time toggle is always to 'true' because default is 'false' + } }, }); From f77da76c682ec7ad1b5e141d113d4b74371f46ae Mon Sep 17 00:00:00 2001 From: amadilsons Date: Thu, 5 Oct 2017 17:22:03 +0200 Subject: [PATCH 6/6] added i18n translation, minor fix --- client/components/lists/listHeader.jade | 6 +++--- client/components/lists/listHeader.js | 4 ++-- i18n/en-GB.i18n.json | 3 +++ i18n/en.i18n.json | 3 +++ i18n/pt-BR.i18n.json | 3 +++ models/lists.js | 4 ++-- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade index f0c4e5f1e..d5738dd92 100644 --- a/client/components/lists/listHeader.jade +++ b/client/components/lists/listHeader.jade @@ -76,7 +76,7 @@ template(name="setWipLimitPopup") #js-wip-limit-edit lable {{_ 'set-wip-limit-value'}} ul.pop-over-list - li: a.js-enable-wip-limit Enable WIP Limit + li: a.js-enable-wip-limit {{_ 'enable-wip-limit'}} if isWipLimitEnabled i.fa.fa-check if isWipLimitEnabled @@ -87,6 +87,6 @@ template(name="setWipLimitPopup") template(name="wipLimitErrorPopup") .wip-limit-invalid - p The number of tasks in this list is higher than the WIP limit you've defined. - p Please move some tasks out of this list, or set a higher WIP limit. + p {{_ 'wipLimitErrorPopup-dialog-pt1'}} + p {{_ 'wipLimitErrorPopup-dialog-pt2'}} button.full.js-back-view(type="submit") {{_ 'cancel'}} diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js index 361f69cf9..9974c7889 100644 --- a/client/components/lists/listHeader.js +++ b/client/components/lists/listHeader.js @@ -93,10 +93,10 @@ BlazeComponent.extendComponent({ enableWipLimit() { const list = Template.currentData(); // Prevent user from using previously stored wipLimit.value if it is less than the current number of cards in the list - if(list.getWipLimit() && !list.wipLimit.enabled && list.wipLimit.value < list.cards().count()){ + if(list.getWipLimit() && !list.getWipLimit('enabled') && list.getWipLimit('value') < list.cards().count()){ list.setWipLimit(list.cards().count()); } - Meteor.call('enableWipLimit', Template.currentData()._id); + Meteor.call('enableWipLimit', list._id); }, isWipLimitEnabled() { diff --git a/i18n/en-GB.i18n.json b/i18n/en-GB.i18n.json index f49d3d843..9af3ed1c7 100644 --- a/i18n/en-GB.i18n.json +++ b/i18n/en-GB.i18n.json @@ -186,6 +186,7 @@ "email-sent": "Email sent", "email-verifyEmail-subject": "Verify your email address on __siteName__", "email-verifyEmail-text": "Hello __user__,\n\nTo verify your account email, simply click the link below.\n\n__url__\n\nThanks.", + "enable-wip-limit": "Enable WIP Limit", "error-board-doesNotExist": "This board does not exist", "error-board-notAdmin": "You need to be admin of this board to do that", "error-board-notAMember": "You need to be a member of this board to do that", @@ -350,6 +351,8 @@ "welcome-list2": "Advanced", "what-to-do": "What do you want to do?", "wipLimitErrorPopup-title": "Invalid WIP Limit", + "wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.", + "wipLimitErrorPopup-dialog-pt2": "Please move some tasks out of this list, or set a higher WIP limit.", "admin-panel": "Admin Panel", "settings": "Settings", "people": "People", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index a16a3b3bd..19844036b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -186,6 +186,7 @@ "email-sent": "Email sent", "email-verifyEmail-subject": "Verify your email address on __siteName__", "email-verifyEmail-text": "Hello __user__,\n\nTo verify your account email, simply click the link below.\n\n__url__\n\nThanks.", + "enable-wip-limit": "Enable WIP Limit", "error-board-doesNotExist": "This board does not exist", "error-board-notAdmin": "You need to be admin of this board to do that", "error-board-notAMember": "You need to be a member of this board to do that", @@ -350,6 +351,8 @@ "welcome-list2": "Advanced", "what-to-do": "What do you want to do?", "wipLimitErrorPopup-title": "Invalid WIP Limit", + "wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.", + "wipLimitErrorPopup-dialog-pt2": "Please move some tasks out of this list, or set a higher WIP limit.", "admin-panel": "Admin Panel", "settings": "Settings", "people": "People", diff --git a/i18n/pt-BR.i18n.json b/i18n/pt-BR.i18n.json index 97927e6d5..9a42d4047 100644 --- a/i18n/pt-BR.i18n.json +++ b/i18n/pt-BR.i18n.json @@ -186,6 +186,7 @@ "email-sent": "Email enviado", "email-verifyEmail-subject": "Verifique seu endereço de email em __siteName__", "email-verifyEmail-text": "Olá __user__\nPara verificar sua conta de email, clique no link abaixo.\n__url__\nObrigado.", + "enable-wip-limit": "Ativar Limite WIP", "error-board-doesNotExist": "Este quadro não existe", "error-board-notAdmin": "Você precisa ser administrador desse quadro para fazer isto", "error-board-notAMember": "Você precisa ser um membro desse quadro para fazer isto", @@ -350,6 +351,8 @@ "welcome-list2": "Avançado", "what-to-do": "O que você gostaria de fazer?", "wipLimitErrorPopup-title": "Limite WIP Inválido", + "wipLimitErrorPopup-dialog-pt1": "O número de tarefas nesta lista excede o limite WIP definido.", + "wipLimitErrorPopup-dialog-pt2": "Por favor, mova algumas tarefas para fora desta lista, ou defina um limite WIP mais elevado.", "admin-panel": "Painel Administrativo", "settings": "Configurações", "people": "Pessoas", diff --git a/models/lists.js b/models/lists.js index 877b3d83f..1b999b077 100644 --- a/models/lists.js +++ b/models/lists.js @@ -142,8 +142,8 @@ Meteor.methods({ enableWipLimit(listId) { check(listId, String); const list = Lists.findOne({ _id: listId }); - if( list.getWipLimit() ){ // Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set - list.toggleWipLimit(!list.wipLimit.enabled); + if(list.getWipLimit()){ // Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set + list.toggleWipLimit(!list.getWipLimit('enabled')); } else { list.toggleWipLimit(true); // First time toggle is always to 'true' because default is 'false' }