summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/components/activities/activities.jade15
-rw-r--r--client/components/activities/activities.js26
-rw-r--r--client/components/boards/boardArchive.js6
-rw-r--r--client/components/boards/boardBody.jade11
-rw-r--r--client/components/boards/boardHeader.jade256
-rw-r--r--client/components/boards/boardHeader.js175
-rw-r--r--client/components/boards/boardsList.jade3
-rw-r--r--client/components/boards/boardsList.js21
-rw-r--r--client/components/boards/miniboard.jade8
-rw-r--r--client/components/cards/cardDetails.jade28
-rw-r--r--client/components/cards/cardDetails.js119
-rw-r--r--client/components/cards/cardDetails.styl3
-rw-r--r--client/components/lists/list.js12
-rw-r--r--client/components/lists/list.styl4
-rw-r--r--client/components/lists/listBody.jade91
-rw-r--r--client/components/lists/listBody.js299
-rw-r--r--client/components/lists/minilist.jade8
-rwxr-xr-xclient/components/main/editor.js4
-rw-r--r--client/components/main/header.jade70
-rw-r--r--client/components/main/layouts.jade22
-rw-r--r--client/components/settings/connectionMethod.jade7
-rw-r--r--client/components/settings/connectionMethod.js3
-rw-r--r--client/components/settings/settingBody.jade6
-rw-r--r--client/components/settings/settingBody.js2
-rw-r--r--client/components/settings/settingBody.styl4
-rw-r--r--client/components/settings/settingHeader.jade31
-rw-r--r--client/components/sidebar/sidebar.jade156
-rw-r--r--client/components/sidebar/sidebar.js224
-rw-r--r--client/components/sidebar/sidebarCustomFields.js16
-rw-r--r--client/components/swimlanes/miniswimlane.jade8
-rw-r--r--client/components/swimlanes/swimlaneHeader.jade36
-rw-r--r--client/components/swimlanes/swimlaneHeader.js3
-rw-r--r--client/components/swimlanes/swimlanes.jade18
-rw-r--r--client/components/swimlanes/swimlanes.js18
-rw-r--r--client/components/users/userHeader.jade20
-rw-r--r--client/components/users/userHeader.js9
-rw-r--r--client/lib/popup.js2
37 files changed, 1004 insertions, 740 deletions
diff --git a/client/components/activities/activities.jade b/client/components/activities/activities.jade
index bddc4dad..54066da8 100644
--- a/client/components/activities/activities.jade
+++ b/client/components/activities/activities.jade
@@ -99,6 +99,9 @@ template(name="boardActivities")
else
| {{{_ 'activity-added' memberLink cardLink}}}.
+ if($eq activityType 'moveCardBoard')
+ | {{{_ 'activity-moved' cardLink oldBoardName boardName}}}.
+
if($eq activityType 'moveCard')
| {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
@@ -114,6 +117,12 @@ template(name="boardActivities")
if($eq activityType 'removedLabel')
| {{{_ 'activity-removed-label' lastLabel cardLink}}}.
+ if($eq activityType 'setCustomField')
+ | {{{_ 'activity-set-customfield' lastCustomField lastCustomFieldValue cardLink}}}.
+
+ if($eq activityType 'unsetCustomField')
+ | {{{_ 'activity-unset-customfield' lastCustomField cardLink}}}.
+
if($eq activityType 'unjoinMember')
if($eq user._id member._id)
| {{{_ 'activity-unjoined' cardLink}}}.
@@ -129,7 +138,7 @@ template(name="cardActivities")
p.activity-desc
+memberName(user=user)
if($eq activityType 'createCard')
- | {{_ 'activity-added' cardLabel list.title}}.
+ | {{_ 'activity-added' cardLabel listName}}.
if($eq activityType 'importCard')
| {{{_ 'activity-imported' cardLabel list.title sourceLink}}}.
if($eq activityType 'joinMember')
@@ -170,6 +179,10 @@ template(name="cardActivities")
| {{_ 'activity-sent' cardLabel boardLabel}}.
if($eq activityType 'moveCard')
| {{_ 'activity-moved' cardLabel oldList.title list.title}}.
+
+ if($eq activityType 'moveCardBoard')
+ | {{{_ 'activity-moved' cardLink oldBoardName boardName}}}.
+
if($eq activityType 'addAttachment')
| {{{_ 'activity-attached' attachmentLink cardLabel}}}.
if attachment.isImage
diff --git a/client/components/activities/activities.js b/client/components/activities/activities.js
index b3fe8f50..0476897f 100644
--- a/client/components/activities/activities.js
+++ b/client/components/activities/activities.js
@@ -74,6 +74,8 @@ BlazeComponent.extendComponent({
lastLabel(){
const lastLabelId = this.currentData().labelId;
+ if (!lastLabelId)
+ return null;
const lastLabel = Boards.findOne(Session.get('currentBoard')).getLabelById(lastLabelId);
if(lastLabel.name === undefined || lastLabel.name === ''){
return lastLabel.color;
@@ -82,6 +84,28 @@ BlazeComponent.extendComponent({
}
},
+ lastCustomField(){
+ const lastCustomField = CustomFields.findOne(this.currentData().customFieldId);
+ if (!lastCustomField)
+ return null;
+ return lastCustomField.name;
+ },
+
+ lastCustomFieldValue(){
+ const lastCustomField = CustomFields.findOne(this.currentData().customFieldId);
+ if (!lastCustomField)
+ return null;
+ const value = this.currentData().value;
+ if (lastCustomField.settings.dropdownItems && lastCustomField.settings.dropdownItems.length > 0) {
+ const dropDownValue = _.find(lastCustomField.settings.dropdownItems, (item) => {
+ return item._id === value;
+ });
+ if (dropDownValue)
+ return dropDownValue.name;
+ }
+ return value;
+ },
+
listLabel() {
return this.currentData().list().title;
},
@@ -117,6 +141,8 @@ BlazeComponent.extendComponent({
customField() {
const customField = this.currentData().customField();
+ if (!customField)
+ return null;
return customField.name;
},
diff --git a/client/components/boards/boardArchive.js b/client/components/boards/boardArchive.js
index 8f4d5434..c8bbb341 100644
--- a/client/components/boards/boardArchive.js
+++ b/client/components/boards/boardArchive.js
@@ -1,9 +1,3 @@
-Template.boardListHeaderBar.events({
- 'click .js-open-archived-board'() {
- Modal.open('archivedBoards');
- },
-});
-
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('archivedBoards');
diff --git a/client/components/boards/boardBody.jade b/client/components/boards/boardBody.jade
index 3a40921d..32f8629f 100644
--- a/client/components/boards/boardBody.jade
+++ b/client/components/boards/boardBody.jade
@@ -20,12 +20,15 @@ template(name="boardBody")
class="{{#if draggingActive.get}}is-dragging-active{{/if}}")
if showOverlay.get
.board-overlay
- if isViewSwimlanes
+ if currentBoard.isTemplatesBoard
each currentBoard.swimlanes
+swimlane(this)
- if isViewLists
- +listsGroup
- if isViewCalendar
+ else if isViewSwimlanes
+ each currentBoard.swimlanes
+ +swimlane(this)
+ else if isViewLists
+ +listsGroup(currentBoard)
+ else if isViewCalendar
+calendarView
template(name="calendarView")
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade
index 75b2f02b..823bd806 100644
--- a/client/components/boards/boardHeader.jade
+++ b/client/components/boards/boardHeader.jade
@@ -7,71 +7,69 @@ template(name="boardHeaderBar")
.board-header-btns.left
unless isMiniScreen
- unless isSandstorm
- if currentBoard
- if currentUser
- a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
- title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
- i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
- if showStarCounter
- span
- = currentBoard.stars
-
- a.board-header-btn(
- class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
- title="{{_ currentBoard.permission}}")
- i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
- span {{_ currentBoard.permission}}
-
- a.board-header-btn.js-watch-board(
- title="{{_ watchLevel }}")
- if $eq watchLevel "watching"
- i.fa.fa-eye
- if $eq watchLevel "tracking"
- i.fa.fa-bell
- if $eq watchLevel "muted"
- i.fa.fa-bell-slash
- span {{_ watchLevel}}
+ if currentBoard
+ if currentUser
+ a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
+ title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
+ i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
+ if showStarCounter
+ span
+ = currentBoard.stars
+
+ a.board-header-btn(
+ class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
+ title="{{_ currentBoard.permission}}")
+ i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
+ span {{_ currentBoard.permission}}
+
+ a.board-header-btn.js-watch-board(
+ title="{{_ watchLevel }}")
+ if $eq watchLevel "watching"
+ i.fa.fa-eye
+ if $eq watchLevel "tracking"
+ i.fa.fa-bell
+ if $eq watchLevel "muted"
+ i.fa.fa-bell-slash
+ span {{_ watchLevel}}
- else
- a.board-header-btn.js-log-in(
- title="{{_ 'log-in'}}")
- i.fa.fa-sign-in
- span {{_ 'log-in'}}
+ else
+ a.board-header-btn.js-log-in(
+ title="{{_ 'log-in'}}")
+ i.fa.fa-sign-in
+ span {{_ 'log-in'}}
.board-header-btns.right
if currentBoard
if isMiniScreen
- unless isSandstorm
- if currentUser
- a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
- title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
- i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
- if showStarCounter
- span
- = currentBoard.stars
-
- a.board-header-btn(
- class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
- title="{{_ currentBoard.permission}}")
- i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
- span {{_ currentBoard.permission}}
-
- a.board-header-btn.js-watch-board(
- title="{{_ watchLevel }}")
- if $eq watchLevel "watching"
- i.fa.fa-eye
- if $eq watchLevel "tracking"
- i.fa.fa-bell
- if $eq watchLevel "muted"
- i.fa.fa-bell-slash
- span {{_ watchLevel}}
+ if currentUser
+ a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
+ title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
+ i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
+ if showStarCounter
+ span
+ = currentBoard.stars
+
+ a.board-header-btn(
+ class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
+ title="{{_ currentBoard.permission}}")
+ i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
+ span {{_ currentBoard.permission}}
+
+ a.board-header-btn.js-watch-board(
+ title="{{_ watchLevel }}")
+ if $eq watchLevel "watching"
+ i.fa.fa-eye
+ if $eq watchLevel "tracking"
+ i.fa.fa-bell
+ if $eq watchLevel "muted"
+ i.fa.fa-bell-slash
+ span {{_ watchLevel}}
- else
- a.board-header-btn.js-log-in(
- title="{{_ 'log-in'}}")
- i.fa.fa-sign-in
- span {{_ 'log-in'}}
+ else
+ a.board-header-btn.js-log-in(
+ title="{{_ 'log-in'}}")
+ i.fa.fa-sign-in
+ span {{_ 'log-in'}}
if isSandstorm
if currentUser
@@ -96,10 +94,11 @@ template(name="boardHeaderBar")
i.fa.fa-search
span {{_ 'search'}}
- a.board-header-btn.js-toggle-board-view(
- title="{{_ 'board-view'}}")
- i.fa.fa-th-large
- span {{_ currentUser.profile.boardView}}
+ unless currentBoard.isTemplatesBoard
+ a.board-header-btn.js-toggle-board-view(
+ title="{{_ 'board-view'}}")
+ i.fa.fa-th-large
+ span {{_ currentUser.profile.boardView}}
if canModifyBoard
a.board-header-btn.js-multiselection-activate(
@@ -112,40 +111,8 @@ template(name="boardHeaderBar")
i.fa.fa-times-thin
.separator
- a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}")
- i.board-header-btn-icon.fa.fa-navicon
-
-template(name="boardMenuPopup")
- ul.pop-over-list
- 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'}}
- //-
- XXX Language should be handled by sandstorm, but for now display a
- language selection link in the board menu. This link is normally present
- in the header bar that is not displayed on sandstorm.
- if isSandstorm
- li: a.js-change-language {{_ 'language'}}
- unless isSandstorm
- if currentUser.isBoardAdmin
- hr
- ul.pop-over-list
- li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
- li: a.js-archive-board {{_ 'archive-board'}}
- li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
- hr
- ul.pop-over-list
- li: a.js-subtask-settings {{_ 'subtask-settings'}}
-
- if isSandstorm
- hr
- ul.pop-over-list
- li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
- li: a.js-import-board {{_ 'import-board-c'}}
- hr
- ul.pop-over-list
- li: a.js-subtask-settings {{_ 'subtask-settings'}}
+ a.board-header-btn.js-toggle-sidebar
+ i.fa.fa-navicon
template(name="boardVisibilityList")
ul.pop-over-list
@@ -196,64 +163,6 @@ template(name="boardChangeWatchPopup")
i.fa.fa-check
span.sub-name {{_ 'muted-info'}}
-template(name="boardChangeColorPopup")
- .board-backgrounds-list.clearfix
- each backgroundColors
- .board-background-select.js-select-background
- span.background-box(class="board-color-{{this}}")
- if isSelected
- i.fa.fa-check
-
-template(name="boardSubtaskSettingsPopup")
- form.board-subtask-settings
- h3 {{_ 'show-parent-in-minicard'}}
- a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
- .materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
- span {{_ 'prefix-with-full-path'}}
- a#prefix-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
- .materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
- span {{_ 'prefix-with-parent'}}
- a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
- .materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
- span {{_ 'subtext-with-full-path'}}
- a#subtext-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
- .materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
- span {{_ 'subtext-with-parent'}}
- a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
- .materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
- span {{_ 'no-parent'}}
- div
- hr
-
- div.check-div
- a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
- .materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
- span {{_ 'show-subtasks-field'}}
-
- label
- | {{_ 'deposit-subtasks-board'}}
- select.js-field-deposit-board(disabled="{{#unless allowsSubtasks}}disabled{{/unless}}")
- each boards
- if isBoardSelected
- option(value=_id selected="selected") {{title}}
- else
- option(value=_id) {{title}}
- if isNullBoardSelected
- option(value='null' selected="selected") {{_ 'custom-field-dropdown-none'}}
- else
- option(value='null') {{_ 'custom-field-dropdown-none'}}
- div
- hr
-
- label
- | {{_ 'deposit-subtasks-list'}}
- select.js-field-deposit-list(disabled="{{#unless hasLists}}disabled{{/unless}}")
- each lists
- if isListSelected
- option(value=_id selected="selected") {{title}}
- else
- option(value=_id) {{title}}
-
template(name="createBoard")
form
label
@@ -275,14 +184,10 @@ template(name="createBoard")
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
- a.js-import-board {{_ 'import-board'}}
-
-template(name="chooseBoardSource")
- ul.pop-over-list
- li
- a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}}
- li
- a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}}
+ a.js-import-board {{_ 'import'}}
+ span.quiet
+ | /
+ a.js-board-template {{_ 'template'}}
template(name="boardChangeTitlePopup")
form
@@ -297,28 +202,3 @@ template(name="boardChangeTitlePopup")
template(name="boardCreateRulePopup")
p {{_ 'close-board-pop'}}
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
-
-
-template(name="archiveBoardPopup")
- p {{_ 'close-board-pop'}}
- button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
-
-template(name="outgoingWebhooksPopup")
- each integrations
- form.integration-form
- if title
- h4 {{title}}
- else
- h4 {{_ 'no-name'}}
- label
- | URL
- input.js-outgoing-webhooks-url(type="text" name="url" value=url)
- input(type="hidden" value=_id name="id")
- input.primary.wide(type="submit" value="{{_ 'save'}}")
- form.integration-form
- h4
- | {{_ 'new-outgoing-webhook'}}
- label
- | URL
- input.js-outgoing-webhooks-url(type="text" name="url" autofocus)
- input.primary.wide(type="submit" value="{{_ 'save'}}")
diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js
index 89f686ab..86fbebb3 100644
--- a/client/components/boards/boardHeader.js
+++ b/client/components/boards/boardHeader.js
@@ -97,6 +97,9 @@ BlazeComponent.extendComponent({
currentUser.setBoardView('board-view-lists');
}
},
+ 'click .js-toggle-sidebar'() {
+ Sidebar.toggle();
+ },
'click .js-open-filter-view'() {
Sidebar.setView('filter');
},
@@ -135,124 +138,6 @@ Template.boardHeaderBar.helpers({
},
});
-BlazeComponent.extendComponent({
- backgroundColors() {
- return Boards.simpleSchema()._schema.color.allowedValues;
- },
-
- isSelected() {
- const currentBoard = Boards.findOne(Session.get('currentBoard'));
- return currentBoard.color === this.currentData().toString();
- },
-
- events() {
- return [{
- 'click .js-select-background'(evt) {
- const currentBoard = Boards.findOne(Session.get('currentBoard'));
- const newColor = this.currentData().toString();
- currentBoard.setColor(newColor);
- evt.preventDefault();
- },
- }];
- },
-}).register('boardChangeColorPopup');
-
-BlazeComponent.extendComponent({
- onCreated() {
- this.currentBoard = Boards.findOne(Session.get('currentBoard'));
- },
-
- allowsSubtasks() {
- return this.currentBoard.allowsSubtasks;
- },
-
- isBoardSelected() {
- return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
- },
-
- isNullBoardSelected() {
- return (this.currentBoard.subtasksDefaultBoardId === null) || (this.currentBoard.subtasksDefaultBoardId === undefined);
- },
-
- boards() {
- return Boards.find({
- archived: false,
- 'members.userId': Meteor.userId(),
- }, {
- sort: ['title'],
- });
- },
-
- lists() {
- return Lists.find({
- boardId: this.currentBoard._id,
- archived: false,
- }, {
- sort: ['title'],
- });
- },
-
- hasLists() {
- return this.lists().count() > 0;
- },
-
- isListSelected() {
- return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
- },
-
- presentParentTask() {
- let result = this.currentBoard.presentParentTask;
- if ((result === null) || (result === undefined)) {
- result = 'no-parent';
- }
- return result;
- },
-
- events() {
- return [{
- 'click .js-field-has-subtasks'(evt) {
- evt.preventDefault();
- this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
- this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
- $('.js-field-has-subtasks .materialCheckBox').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
- $('.js-field-has-subtasks').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
- $('.js-field-deposit-board').prop('disabled', !this.currentBoard.allowsSubtasks);
- },
- 'change .js-field-deposit-board'(evt) {
- let value = evt.target.value;
- if (value === 'null') {
- value = null;
- }
- this.currentBoard.setSubtasksDefaultBoardId(value);
- evt.preventDefault();
- },
- 'change .js-field-deposit-list'(evt) {
- this.currentBoard.setSubtasksDefaultListId(evt.target.value);
- evt.preventDefault();
- },
- 'click .js-field-show-parent-in-minicard'(evt) {
- const value = evt.target.id || $(evt.target).parent()[0].id || $(evt.target).parent()[0].parent()[0].id;
- const options = [
- 'prefix-with-full-path',
- 'prefix-with-parent',
- 'subtext-with-full-path',
- 'subtext-with-parent',
- 'no-parent'];
- options.forEach(function(element) {
- if (element !== value) {
- $(`#${element} .materialCheckBox`).toggleClass('is-checked', false);
- $(`#${element}`).toggleClass('is-checked', false);
- }
- });
- $(`#${value} .materialCheckBox`).toggleClass('is-checked', true);
- $(`#${value}`).toggleClass('is-checked', true);
- this.currentBoard.setPresentParentTask(value);
- evt.preventDefault();
- },
- }];
- },
-}).register('boardSubtaskSettingsPopup');
-
const CreateBoard = BlazeComponent.extendComponent({
template() {
return 'createBoard';
@@ -304,16 +189,11 @@ const CreateBoard = BlazeComponent.extendComponent({
'click .js-import': Popup.open('boardImportBoard'),
submit: this.onSubmit,
'click .js-import-board': Popup.open('chooseBoardSource'),
+ 'click .js-board-template': Popup.open('searchElement'),
}];
},
}).register('createBoardPopup');
-BlazeComponent.extendComponent({
- template() {
- return 'chooseBoardSource';
- },
-}).register('chooseBoardSourcePopup');
-
(class HeaderBarCreateBoard extends CreateBoard {
onSubmit(evt) {
super.onSubmit(evt);
@@ -363,50 +243,3 @@ BlazeComponent.extendComponent({
}];
},
}).register('boardChangeWatchPopup');
-
-BlazeComponent.extendComponent({
- integrations() {
- const boardId = Session.get('currentBoard');
- return Integrations.find({ boardId: `${boardId}` }).fetch();
- },
-
- integration(id) {
- const boardId = Session.get('currentBoard');
- return Integrations.findOne({ _id: id, boardId: `${boardId}` });
- },
-
- events() {
- return [{
- 'submit'(evt) {
- evt.preventDefault();
- const url = evt.target.url.value;
- const boardId = Session.get('currentBoard');
- let id = null;
- let integration = null;
- if (evt.target.id) {
- id = evt.target.id.value;
- integration = this.integration(id);
- if (url) {
- Integrations.update(integration._id, {
- $set: {
- url: `${url}`,
- },
- });
- } else {
- Integrations.remove(integration._id);
- }
- } else if (url) {
- Integrations.insert({
- userId: Meteor.userId(),
- enabled: true,
- type: 'outgoing-webhooks',
- url: `${url}`,
- boardId: `${boardId}`,
- activities: ['all'],
- });
- }
- Popup.close();
- },
- }];
- },
-}).register('outgoingWebhooksPopup');
diff --git a/client/components/boards/boardsList.jade b/client/components/boards/boardsList.jade
index 753724fc..abb009f7 100644
--- a/client/components/boards/boardsList.jade
+++ b/client/components/boards/boardsList.jade
@@ -36,3 +36,6 @@ template(name="boardListHeaderBar")
a.board-header-btn.js-open-archived-board
i.fa.fa-archive
span {{_ 'archives'}}
+ a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
+ i.fa.fa-clone
+ span {{_ 'templates'}}
diff --git a/client/components/boards/boardsList.js b/client/components/boards/boardsList.js
index 68f4a1dc..ad28fee8 100644
--- a/client/components/boards/boardsList.js
+++ b/client/components/boards/boardsList.js
@@ -1,5 +1,20 @@
const subManager = new SubsManager();
+Template.boardListHeaderBar.events({
+ 'click .js-open-archived-board'() {
+ Modal.open('archivedBoards');
+ },
+});
+
+Template.boardListHeaderBar.helpers({
+ templatesBoardId() {
+ return Meteor.user().getTemplatesBoardId();
+ },
+ templatesBoardSlug() {
+ return Meteor.user().getTemplatesBoardSlug();
+ },
+});
+
BlazeComponent.extendComponent({
onCreated() {
Meteor.subscribe('setting');
@@ -9,11 +24,9 @@ BlazeComponent.extendComponent({
return Boards.find({
archived: false,
'members.userId': Meteor.userId(),
- }, {
- sort: ['title'],
- });
+ type: 'board',
+ }, { sort: ['title'] });
},
-
isStarred() {
const user = Meteor.user();
return user && user.hasStarred(this.currentData()._id);
diff --git a/client/components/boards/miniboard.jade b/client/components/boards/miniboard.jade
new file mode 100644
index 00000000..d1fb0b07
--- /dev/null
+++ b/client/components/boards/miniboard.jade
@@ -0,0 +1,8 @@
+template(name="miniboard")
+ .minicard(
+ class="minicard-{{colorClass}}")
+ .minicard-title
+ .handle
+ .fa.fa-arrows
+ +viewer
+ = title
diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade
index 25316d04..5fd7b748 100644
--- a/client/components/cards/cardDetails.jade
+++ b/client/components/cards/cardDetails.jade
@@ -19,16 +19,14 @@ template(name="cardDetails")
a.js-parent-card(href=linkForCard) {{title}}
// else
{{_ 'top-level-card'}}
- unless isSandstorm
- if isLinkedCard
- h3.linked-card-location
- +viewer
- | {{getBoardTitle}} > {{getTitle}}
+ if isLinkedCard
+ h3.linked-card-location
+ +viewer
+ | {{getBoardTitle}} > {{getTitle}}
if getArchived
if isLinkedBoard
- unless isSandstorm
- p.warning {{_ 'board-archived'}}
+ p.warning {{_ 'board-archived'}}
else
p.warning {{_ 'card-archived'}}
@@ -192,11 +190,9 @@ template(name="cardDetails")
unless currentUser.isNoComments
if isLoaded.get
if isLinkedCard
- unless isSandstorm
- +activities(card=this mode="linkedcard")
+ +activities(card=this mode="linkedcard")
else if isLinkedBoard
- unless isSandstorm
- +activities(card=this mode="linkedboard")
+ +activities(card=this mode="linkedboard")
else
+activities(card=this mode="card")
@@ -310,27 +306,27 @@ template(name="cardMorePopup")
h2 {{_ 'change-card-parent'}}
label {{_ 'source-board'}}:
select.js-field-parent-board
+ if isTopLevel
+ option(value="none" selected) {{_ 'custom-field-dropdown-none'}}
+ else
+ option(value="none") {{_ 'custom-field-dropdown-none'}}
each boards
if isParentBoard
option(value="{{_id}}" selected) {{title}}
else
option(value="{{_id}}") {{title}}
- if isTopLevel
- option(value="none" selected) {{_ 'custom-field-dropdown-none'}}
- else
- option(value="none") {{_ 'custom-field-dropdown-none'}}
label {{_ 'parent-card'}}:
select.js-field-parent-card
if isTopLevel
option(value="none" selected) {{_ 'custom-field-dropdown-none'}}
else
+ option(value="none") {{_ 'custom-field-dropdown-none'}}
each cards
if isParentCard
option(value="{{_id}}" selected) {{title}}
else
option(value="{{_id}}") {{title}}
- option(value="none") {{_ 'custom-field-dropdown-none'}}
br
| {{_ 'added'}}
span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js
index a571e21a..79e9e311 100644
--- a/client/components/cards/cardDetails.js
+++ b/client/components/cards/cardDetails.js
@@ -412,11 +412,13 @@ Template.moveCardPopup.events({
// XXX We should *not* get the currentCard from the global state, but
// instead from a “component” state.
const card = Cards.findOne(Session.get('currentCard'));
+ const bSelect = $('.js-select-boards')[0];
+ const boardId = bSelect.options[bSelect.selectedIndex].value;
const lSelect = $('.js-select-lists')[0];
- const newListId = lSelect.options[lSelect.selectedIndex].value;
+ const listId = lSelect.options[lSelect.selectedIndex].value;
const slSelect = $('.js-select-swimlanes')[0];
- card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
- card.move(card.swimlaneId, newListId, 0);
+ const swimlaneId = slSelect.options[slSelect.selectedIndex].value;
+ card.move(boardId, swimlaneId, listId, 0);
Popup.close();
},
});
@@ -430,6 +432,7 @@ BlazeComponent.extendComponent({
const boards = Boards.find({
archived: false,
'members.userId': Meteor.userId(),
+ _id: {$ne: Meteor.user().getTemplatesBoardId()},
}, {
sort: ['title'],
});
@@ -456,32 +459,15 @@ BlazeComponent.extendComponent({
},
}).register('boardsAndLists');
-
-function cloneCheckList(_id, checklist) {
- 'use strict';
- const checklistId = checklist._id;
- checklist.cardId = _id;
- checklist._id = null;
- const newChecklistId = Checklists.insert(checklist);
- ChecklistItems.find({checklistId}).forEach(function(item) {
- item._id = null;
- item.checklistId = newChecklistId;
- item.cardId = _id;
- ChecklistItems.insert(item);
- });
-}
-
Template.copyCardPopup.events({
'click .js-done'() {
const card = Cards.findOne(Session.get('currentCard'));
- const oldId = card._id;
- card._id = null;
const lSelect = $('.js-select-lists')[0];
- card.listId = lSelect.options[lSelect.selectedIndex].value;
+ listId = lSelect.options[lSelect.selectedIndex].value;
const slSelect = $('.js-select-swimlanes')[0];
- card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
+ const swimlaneId = slSelect.options[slSelect.selectedIndex].value;
const bSelect = $('.js-select-boards')[0];
- card.boardId = bSelect.options[bSelect.selectedIndex].value;
+ const boardId = bSelect.options[bSelect.selectedIndex].value;
const textarea = $('#copy-card-title');
const title = textarea.val().trim();
// insert new card to the bottom of new list
@@ -490,38 +476,13 @@ Template.copyCardPopup.events({
if (title) {
card.title = title;
card.coverId = '';
- const _id = Cards.insert(card);
+ const _id = card.copy(boardId, swimlaneId, listId);
// In case the filter is active we need to add the newly inserted card in
// the list of exceptions -- cards that are not filtered. Otherwise the
// card will disappear instantly.
// See https://github.com/wekan/wekan/issues/80
Filter.addException(_id);
- // copy checklists
- let cursor = Checklists.find({cardId: oldId});
- cursor.forEach(function() {
- cloneCheckList(_id, arguments[0]);
- });
-
- // copy subtasks
- cursor = Cards.find({parentId: oldId});
- cursor.forEach(function() {
- 'use strict';
- const subtask = arguments[0];
- subtask.parentId = _id;
- subtask._id = null;
- /* const newSubtaskId = */ Cards.insert(subtask);
- });
-
- // copy card comments
- cursor = CardComments.find({cardId: oldId});
- cursor.forEach(function () {
- 'use strict';
- const comment = arguments[0];
- comment.cardId = _id;
- comment._id = null;
- CardComments.insert(comment);
- });
Popup.close();
}
},
@@ -558,9 +519,8 @@ Template.copyChecklistToManyCardsPopup.events({
Filter.addException(_id);
// copy checklists
- let cursor = Checklists.find({cardId: oldId});
- cursor.forEach(function() {
- cloneCheckList(_id, arguments[0]);
+ Checklists.find({cardId: oldId}).forEach((ch) => {
+ ch.copy(_id);
});
// copy subtasks
@@ -574,13 +534,8 @@ Template.copyChecklistToManyCardsPopup.events({
});
// copy card comments
- cursor = CardComments.find({cardId: oldId});
- cursor.forEach(function () {
- 'use strict';
- const comment = arguments[0];
- comment.cardId = _id;
- comment._id = null;
- CardComments.insert(comment);
+ CardComments.find({cardId: oldId}).forEach((cmt) => {
+ cmt.copy(_id);
});
}
Popup.close();
@@ -625,11 +580,14 @@ BlazeComponent.extendComponent({
BlazeComponent.extendComponent({
onCreated() {
this.currentCard = this.currentData();
+ this.parentBoard = new ReactiveVar(null);
this.parentCard = this.currentCard.parentCard();
if (this.parentCard) {
- this.parentBoard = this.parentCard.board();
+ const list = $('.js-field-parent-card');
+ list.val(this.parentCard._id);
+ this.parentBoard.set(this.parentCard.board()._id);
} else {
- this.parentBoard = null;
+ this.parentBoard.set(null);
}
},
@@ -637,6 +595,9 @@ BlazeComponent.extendComponent({
const boards = Boards.find({
archived: false,
'members.userId': Meteor.userId(),
+ _id: {
+ $ne: Meteor.user().getTemplatesBoardId(),
+ },
}, {
sort: ['title'],
});
@@ -644,8 +605,12 @@ BlazeComponent.extendComponent({
},
cards() {
- if (this.parentBoard) {
- return this.parentBoard.cards();
+ const currentId = Session.get('currentCard');
+ if (this.parentBoard.get()) {
+ return Cards.find({
+ boardId: this.parentBoard.get(),
+ _id: {$ne: currentId},
+ });
} else {
return [];
}
@@ -653,8 +618,8 @@ BlazeComponent.extendComponent({
isParentBoard() {
const board = this.currentData();
- if (this.parentBoard) {
- return board._id === this.parentBoard;
+ if (this.parentBoard.get()) {
+ return board._id === this.parentBoard.get();
}
return false;
},
@@ -668,11 +633,10 @@ BlazeComponent.extendComponent({
},
setParentCardId(cardId) {
- if (cardId === 'null') {
- cardId = null;
- this.parentCard = null;
- } else {
+ if (cardId) {
this.parentCard = Cards.findOne(cardId);
+ } else {
+ this.parentCard = null;
}
this.currentCard.setParentId(cardId);
},
@@ -709,23 +673,14 @@ BlazeComponent.extendComponent({
'change .js-field-parent-board'(evt) {
const selection = $(evt.currentTarget).val();
const list = $('.js-field-parent-card');
- list.empty();
if (selection === 'none') {
- this.parentBoard = null;
- list.prop('disabled', true);
+ this.parentBoard.set(null);
} else {
- this.parentBoard = Boards.findOne(selection);
- this.parentBoard.cards().forEach(function(card) {
- list.append(
- $('<option></option>').val(card._id).html(card.title)
- );
- });
+ subManager.subscribe('board', $(evt.currentTarget).val());
+ this.parentBoard.set(selection);
list.prop('disabled', false);
}
- list.append(
- `<option value='none' selected='selected'>${TAPi18n.__('custom-field-dropdown-none')}</option>`
- );
- this.setParentCardId('null');
+ this.setParentCardId(null);
},
'change .js-field-parent-card'(evt) {
const selection = $(evt.currentTarget).val();
diff --git a/client/components/cards/cardDetails.styl b/client/components/cards/cardDetails.styl
index bf50c071..c1d6b7e1 100644
--- a/client/components/cards/cardDetails.styl
+++ b/client/components/cards/cardDetails.styl
@@ -133,7 +133,8 @@ input[type="submit"].attachment-add-link-submit
.card-details-canvas
width: 100%
-
+ padding-left: 0px;
+
.card-details-header
.close-card-details
margin-right: 0px
diff --git a/client/components/lists/list.js b/client/components/lists/list.js
index 043cb77c..12932a82 100644
--- a/client/components/lists/list.js
+++ b/client/components/lists/list.js
@@ -67,7 +67,13 @@ BlazeComponent.extendComponent({
const nCards = MultiSelection.isActive() ? MultiSelection.count() : 1;
const sortIndex = calculateIndex(prevCardDom, nextCardDom, nCards);
const listId = Blaze.getData(ui.item.parents('.list').get(0))._id;
- const swimlaneId = Blaze.getData(ui.item.parents('.swimlane').get(0))._id;
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ let swimlaneId = '';
+ const boardView = Meteor.user().profile.boardView;
+ if (boardView === 'board-view-swimlanes' || currentBoard.isTemplatesBoard())
+ swimlaneId = Blaze.getData(ui.item.parents('.swimlane').get(0))._id;
+ else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal'))
+ swimlaneId = currentBoard.getDefaultSwimline()._id;
// Normally the jquery-ui sortable library moves the dragged DOM element
// to its new position, which disrupts Blaze reactive updates mechanism
@@ -80,12 +86,12 @@ BlazeComponent.extendComponent({
if (MultiSelection.isActive()) {
Cards.find(MultiSelection.getMongoSelector()).forEach((card, i) => {
- card.move(swimlaneId, listId, sortIndex.base + i * sortIndex.increment);
+ card.move(currentBoard._id, swimlaneId, listId, sortIndex.base + i * sortIndex.increment);
});
} else {
const cardDomElement = ui.item.get(0);
const card = Blaze.getData(cardDomElement);
- card.move(swimlaneId, listId, sortIndex.base);
+ card.move(currentBoard._id, swimlaneId, listId, sortIndex.base);
}
boardComponent.setIsDragging(false);
},
diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl
index 70502083..7e4550a4 100644
--- a/client/components/lists/list.styl
+++ b/client/components/lists/list.styl
@@ -84,6 +84,7 @@
padding-left: 10px
color: #a6a6a6
+
.list-header-menu
position: absolute
padding: 27px 19px
@@ -155,6 +156,9 @@
float: left
@media screen and (max-width: 800px)
+ .list-header-menu
+ margin-right: 30px
+
.mini-list
flex: 0 0 60px
height: 60px
diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade
index f030833b..61fec93a 100644
--- a/client/components/lists/listBody.jade
+++ b/client/components/lists/listBody.jade
@@ -13,14 +13,7 @@ template(name="listBody")
class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}")
+minicard(this)
if (showSpinner (idOrNull ../../_id))
- .sk-spinner.sk-spinner-wave.sk-spinner-list(
- class=currentBoard.colorClass
- id="showMoreResults")
- .sk-rect1
- .sk-rect2
- .sk-rect3
- .sk-rect4
- .sk-rect5
+ +spinnerList
if canSeeAddCard
+inlinedForm(autoclose=false position="bottom")
@@ -30,6 +23,16 @@ template(name="listBody")
i.fa.fa-plus
| {{_ 'add-card'}}
+template(name="spinnerList")
+ .sk-spinner.sk-spinner-wave.sk-spinner-list(
+ class=currentBoard.colorClass
+ id="showMoreResults")
+ .sk-rect1
+ .sk-rect2
+ .sk-rect3
+ .sk-rect4
+ .sk-rect5
+
template(name="addCardForm")
.minicard.minicard-composer.js-composer
if getLabels
@@ -44,14 +47,19 @@ template(name="addCardForm")
.add-controls.clearfix
button.primary.confirm(type="submit") {{_ 'add'}}
- unless isSandstorm
- span.quiet
- | {{_ 'or'}}
- a.js-link {{_ 'link'}}
- span.quiet
- | &nbsp;
- | /
- a.js-search {{_ 'search'}}
+ unless currentBoard.isTemplatesBoard
+ unless currentBoard.isTemplateBoard
+ span.quiet
+ | {{_ 'or'}}
+ a.js-link {{_ 'link'}}
+ span.quiet
+ | &nbsp;
+ | /
+ a.js-search {{_ 'search'}}
+ span.quiet
+ | &nbsp;
+ | /
+ a.js-card-template {{_ 'template'}}
template(name="autocompleteLabelLine")
.minicard-label(class="card-label-{{colorName}}" title=labelName)
@@ -61,11 +69,9 @@ template(name="linkCardPopup")
label {{_ 'boards'}}:
.link-board-wrapper
select.js-select-boards
+ option(value="")
each boards
- if $eq _id currentBoard._id
- option(value="{{_id}}" selected) {{_ 'current'}}
- else
- option(value="{{_id}}") {{title}}
+ option(value="{{_id}}") {{title}}
input.primary.confirm.js-link-board(type="button" value="{{_ 'link'}}")
label {{_ 'swimlanes'}}:
@@ -84,22 +90,41 @@ template(name="linkCardPopup")
option(value="{{getId}}") {{getTitle}}
.edit-controls.clearfix
- unless isSandstorm
- input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
+ input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
-template(name="searchCardPopup")
- label {{_ 'boards'}}:
- .link-board-wrapper
- select.js-select-boards
- each boards
- if $eq _id currentBoard._id
- option(value="{{_id}}" selected) {{_ 'current'}}
- else
+template(name="searchElementPopup")
+ form
+ label
+ | {{_ 'title'}}
+ input.js-element-title(type="text" placeholder="{{_ 'title'}}" autofocus required)
+ unless isTemplateSearch
+ label {{_ 'boards'}}:
+ .link-board-wrapper
+ select.js-select-boards
+ option(value="")
+ each boards
option(value="{{_id}}") {{title}}
form.js-search-term-form
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
.list-body.js-perfect-scrollbar.search-card-results
.minicards.clearfix.js-minicards
- each results
- a.minicard-wrapper.js-minicard
- +minicard(this)
+ if isBoardTemplateSearch
+ each results
+ a.minicard-wrapper.js-minicard
+ +miniboard(this)
+ if isListTemplateSearch
+ each results
+ a.minicard-wrapper.js-minicard
+ +minilist(this)
+ if isSwimlaneTemplateSearch
+ each results
+ a.minicard-wrapper.js-minicard
+ +miniswimlane(this)
+ if isCardTemplateSearch
+ each results
+ a.minicard-wrapper.js-minicard
+ +minicard(this)
+ unless isTemplateSearch
+ each results
+ a.minicard-wrapper.js-minicard
+ +minicard(this)
diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js
index 0f5caac5..43619890 100644
--- a/client/components/lists/listBody.js
+++ b/client/components/lists/listBody.js
@@ -7,28 +7,6 @@ BlazeComponent.extendComponent({
this.cardlimit = new ReactiveVar(InfiniteScrollIter);
},
- onRendered() {
- const domElement = this.find('.js-perfect-scrollbar');
-
- this.$(domElement).on('scroll', () => this.updateList(domElement));
- $(window).on(`resize.${this.data().listId}`, () => this.updateList(domElement));
-
- // we add a Mutation Observer to allow propagations of cardlimit
- // when the spinner stays in the current view (infinite scrolling)
- this.mutationObserver = new MutationObserver(() => this.updateList(domElement));
-
- this.mutationObserver.observe(domElement, {
- childList: true,
- });
-
- this.updateList(domElement);
- },
-
- onDestroyed() {
- $(window).off(`resize.${this.data().listId}`);
- this.mutationObserver.disconnect();
- },
-
mixins() {
return [Mixins.PerfectScrollbar];
},
@@ -67,25 +45,47 @@ BlazeComponent.extendComponent({
const labelIds = formComponent.labels.get();
const customFields = formComponent.customFields.get();
- const boardId = this.data().board();
+ const board = this.data().board();
+ let linkedId = '';
let swimlaneId = '';
const boardView = Meteor.user().profile.boardView;
- if (boardView === 'board-view-swimlanes')
- swimlaneId = this.parentComponent().parentComponent().data()._id;
- else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal'))
- swimlaneId = boardId.getDefaultSwimline()._id;
-
+ let cardType = 'cardType-card';
if (title) {
+ if (board.isTemplatesBoard()) {
+ swimlaneId = this.parentComponent().parentComponent().data()._id; // Always swimlanes view
+ const swimlane = Swimlanes.findOne(swimlaneId);
+ // If this is the card templates swimlane, insert a card template
+ if (swimlane.isCardTemplatesSwimlane())
+ cardType = 'template-card';
+ // If this is the board templates swimlane, insert a board template and a linked card
+ else if (swimlane.isBoardTemplatesSwimlane()) {
+ linkedId = Boards.insert({
+ title,
+ permission: 'private',
+ type: 'template-board',
+ });
+ Swimlanes.insert({
+ title: TAPi18n.__('default'),
+ boardId: linkedId,
+ });
+ cardType = 'cardType-linkedBoard';
+ }
+ } else if (boardView === 'board-view-swimlanes')
+ swimlaneId = this.parentComponent().parentComponent().data()._id;
+ else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal'))
+ swimlaneId = board.getDefaultSwimline()._id;
+
const _id = Cards.insert({
title,
members,
labelIds,
customFields,
listId: this.data()._id,
- boardId: boardId._id,
+ boardId: board._id,
sort: sortIndex,
swimlaneId,
- type: 'cardType-card',
+ type: cardType,
+ linkedId,
});
// if the displayed card count is less than the total cards in the list,
@@ -127,9 +127,9 @@ BlazeComponent.extendComponent({
const methodName = evt.shiftKey ? 'toggleRange' : 'toggle';
MultiSelection[methodName](this.currentData()._id);
- // If the card is already selected, we want to de-select it.
- // XXX We should probably modify the minicard href attribute instead of
- // overwriting the event in case the card is already selected.
+ // If the card is already selected, we want to de-select it.
+ // XXX We should probably modify the minicard href attribute instead of
+ // overwriting the event in case the card is already selected.
} else if (Session.equals('currentCard', this.currentData()._id)) {
evt.stopImmediatePropagation();
evt.preventDefault();
@@ -149,7 +149,8 @@ BlazeComponent.extendComponent({
idOrNull(swimlaneId) {
const currentUser = Meteor.user();
- if (currentUser.profile.boardView === 'board-view-swimlanes')
+ if (currentUser.profile.boardView === 'board-view-swimlanes' ||
+ this.data().board().isTemplatesBoard())
return swimlaneId;
return undefined;
},
@@ -168,38 +169,11 @@ BlazeComponent.extendComponent({
});
},
- spinnerInView(container) {
- const parentViewHeight = container.clientHeight;
- const bottomViewPosition = container.scrollTop + parentViewHeight;
-
- const spinner = this.find('.sk-spinner-list');
-
- const threshold = spinner.offsetTop;
-
- return bottomViewPosition > threshold;
- },
-
showSpinner(swimlaneId) {
const list = Template.currentData();
return list.cards(swimlaneId).count() > this.cardlimit.get();
},
- updateList(container) {
- // first, if the spinner is not rendered, we have reached the end of
- // the list of cards, so skip and disable firing the events
- const target = this.find('.sk-spinner-list');
- if (!target) {
- this.$(container).off('scroll');
- $(window).off(`resize.${this.data().listId}`);
- return;
- }
-
- if (this.spinnerInView(container)) {
- this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
- Ps.update(container);
- }
- },
-
canSeeAddCard() {
return !this.reachedWipLimit() && Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
},
@@ -269,8 +243,8 @@ BlazeComponent.extendComponent({
// work.
$form.find('button[type=submit]').click();
- // Pressing Tab should open the form of the next column, and Maj+Tab go
- // in the reverse order
+ // Pressing Tab should open the form of the next column, and Maj+Tab go
+ // in the reverse order
} else if (evt.keyCode === 9) {
evt.preventDefault();
const isReverse = evt.shiftKey;
@@ -292,7 +266,8 @@ BlazeComponent.extendComponent({
return [{
keydown: this.pressKey,
'click .js-link': Popup.open('linkCard'),
- 'click .js-search': Popup.open('searchCard'),
+ 'click .js-search': Popup.open('searchElement'),
+ 'click .js-card-template': Popup.open('searchElement'),
}];
},
@@ -330,7 +305,7 @@ BlazeComponent.extendComponent({
const currentBoard = Boards.findOne(Session.get('currentBoard'));
callback($.map(currentBoard.labels, (label) => {
if (label.name.indexOf(term) > -1 ||
- label.color.indexOf(term) > -1) {
+ label.color.indexOf(term) > -1) {
return label;
}
return null;
@@ -367,17 +342,7 @@ BlazeComponent.extendComponent({
BlazeComponent.extendComponent({
onCreated() {
- // Prefetch first non-current board id
- const boardId = Boards.findOne({
- archived: false,
- 'members.userId': Meteor.userId(),
- _id: {$ne: Session.get('currentBoard')},
- }, {
- sort: ['title'],
- })._id;
- // Subscribe to this board
- subManager.subscribe('board', boardId);
- this.selectedBoardId = new ReactiveVar(boardId);
+ this.selectedBoardId = new ReactiveVar('');
this.selectedSwimlaneId = new ReactiveVar('');
this.selectedListId = new ReactiveVar('');
@@ -403,6 +368,7 @@ BlazeComponent.extendComponent({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Session.get('currentBoard')},
+ type: 'board',
}, {
sort: ['title'],
});
@@ -410,7 +376,7 @@ BlazeComponent.extendComponent({
},
swimlanes() {
- if (!this.selectedBoardId) {
+ if (!this.selectedBoardId.get()) {
return [];
}
const swimlanes = Swimlanes.find({boardId: this.selectedBoardId.get()});
@@ -420,7 +386,7 @@ BlazeComponent.extendComponent({
},
lists() {
- if (!this.selectedBoardId) {
+ if (!this.selectedBoardId.get()) {
return [];
}
const lists = Lists.find({boardId: this.selectedBoardId.get()});
@@ -441,6 +407,7 @@ BlazeComponent.extendComponent({
archived: false,
linkedId: {$nin: ownCardsIds},
_id: {$nin: ownCardsIds},
+ type: {$nin: ['template-card']},
});
},
@@ -508,12 +475,25 @@ BlazeComponent.extendComponent({
},
onCreated() {
- // Prefetch first non-current board id
- let board = Boards.findOne({
- archived: false,
- 'members.userId': Meteor.userId(),
- _id: {$ne: Session.get('currentBoard')},
- });
+ this.isCardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-card-template');
+ this.isListTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-list-template');
+ this.isSwimlaneTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-open-add-swimlane-menu');
+ this.isBoardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-add-board');
+ this.isTemplateSearch = this.isCardTemplateSearch ||
+ this.isListTemplateSearch ||
+ this.isSwimlaneTemplateSearch ||
+ this.isBoardTemplateSearch;
+ let board = {};
+ if (this.isTemplateSearch) {
+ board = Boards.findOne(Meteor.user().profile.templatesBoardId);
+ } else {
+ // Prefetch first non-current board id
+ board = Boards.findOne({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$nin: [Session.get('currentBoard'), Meteor.user().profile.templatesBoardId]},
+ });
+ }
if (!board) {
Popup.close();
return;
@@ -523,20 +503,21 @@ BlazeComponent.extendComponent({
subManager.subscribe('board', boardId);
this.selectedBoardId = new ReactiveVar(boardId);
- this.boardId = Session.get('currentBoard');
- // In order to get current board info
- subManager.subscribe('board', this.boardId);
- board = Boards.findOne(this.boardId);
- // List where to insert card
- const list = $(Popup._getTopStack().openerElement).closest('.js-list');
- this.listId = Blaze.getData(list[0])._id;
- // Swimlane where to insert card
- const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
- this.swimlaneId = '';
- if (board.view === 'board-view-swimlanes')
- this.swimlaneId = Blaze.getData(swimlane[0])._id;
- else
- this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+ if (!this.isBoardTemplateSearch) {
+ this.boardId = Session.get('currentBoard');
+ // In order to get current board info
+ subManager.subscribe('board', this.boardId);
+ this.swimlaneId = '';
+ // Swimlane where to insert card
+ const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
+ if (Meteor.user().profile.boardView === 'board-view-swimlanes')
+ this.swimlaneId = Blaze.getData(swimlane[0])._id;
+ else
+ this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+ // List where to insert card
+ const list = $(Popup._getTopStack().openerElement).closest('.js-list');
+ this.listId = Blaze.getData(list[0])._id;
+ }
this.term = new ReactiveVar('');
},
@@ -545,6 +526,7 @@ BlazeComponent.extendComponent({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Session.get('currentBoard')},
+ type: 'board',
}, {
sort: ['title'],
});
@@ -556,7 +538,21 @@ BlazeComponent.extendComponent({
return [];
}
const board = Boards.findOne(this.selectedBoardId.get());
- return board.searchCards(this.term.get(), false);
+ if (!this.isTemplateSearch || this.isCardTemplateSearch) {
+ return board.searchCards(this.term.get(), false);
+ } else if (this.isListTemplateSearch) {
+ return board.searchLists(this.term.get());
+ } else if (this.isSwimlaneTemplateSearch) {
+ return board.searchSwimlanes(this.term.get());
+ } else if (this.isBoardTemplateSearch) {
+ const boards = board.searchBoards(this.term.get());
+ boards.forEach((board) => {
+ subManager.subscribe('board', board.linkedId);
+ });
+ return boards;
+ } else {
+ return [];
+ }
},
events() {
@@ -570,20 +566,99 @@ BlazeComponent.extendComponent({
this.term.set(evt.target.searchTerm.value);
},
'click .js-minicard'(evt) {
- // LINK CARD
- const card = Blaze.getData(evt.currentTarget);
- const _id = Cards.insert({
- title: card.title, //dummy
- listId: this.listId,
- swimlaneId: this.swimlaneId,
- boardId: this.boardId,
- sort: Lists.findOne(this.listId).cards().count(),
- type: 'cardType-linkedCard',
- linkedId: card.linkedId || card._id,
- });
- Filter.addException(_id);
+ // 0. Common
+ const title = $('.js-element-title').val().trim();
+ if (!title)
+ return;
+ const element = Blaze.getData(evt.currentTarget);
+ element.title = title;
+ let _id = '';
+ if (!this.isTemplateSearch || this.isCardTemplateSearch) {
+ // Card insertion
+ // 1. Common
+ element.sort = Lists.findOne(this.listId).cards().count();
+ // 1.A From template
+ if (this.isTemplateSearch) {
+ element.type = 'cardType-card';
+ element.linkedId = '';
+ _id = element.copy(this.boardId, this.swimlaneId, this.listId);
+ // 1.B Linked card
+ } else {
+ delete element._id;
+ element.type = 'cardType-linkedCard';
+ element.linkedId = element.linkedId || element._id;
+ _id = Cards.insert(element);
+ }
+ Filter.addException(_id);
+ // List insertion
+ } else if (this.isListTemplateSearch) {
+ element.sort = Swimlanes.findOne(this.swimlaneId).lists().count();
+ element.type = 'list';
+ _id = element.copy(this.boardId, this.swimlaneId);
+ } else if (this.isSwimlaneTemplateSearch) {
+ element.sort = Boards.findOne(this.boardId).swimlanes().count();
+ element.type = 'swimlalne';
+ _id = element.copy(this.boardId);
+ } else if (this.isBoardTemplateSearch) {
+ board = Boards.findOne(element.linkedId);
+ board.sort = Boards.find({archived: false}).count();
+ board.type = 'board';
+ board.title = element.title;
+ delete board.slug;
+ _id = board.copy();
+ }
Popup.close();
},
}];
},
-}).register('searchCardPopup');
+}).register('searchElementPopup');
+
+BlazeComponent.extendComponent({
+ onCreated() {
+ this.cardlimit = this.parentComponent().cardlimit;
+
+ this.listId = this.parentComponent().data()._id;
+ this.swimlaneId = '';
+
+ const boardView = Meteor.user().profile.boardView;
+ if (boardView === 'board-view-swimlanes')
+ this.swimlaneId = this.parentComponent().parentComponent().parentComponent().data()._id;
+ },
+
+ onRendered() {
+ this.spinner = this.find('.sk-spinner-list');
+ this.container = this.$(this.spinner).parents('.js-perfect-scrollbar')[0];
+
+ $(this.container).on(`scroll.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList());
+ $(window).on(`resize.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList());
+
+ this.updateList();
+ },
+
+ onDestroyed() {
+ $(this.container).off(`scroll.spinner_${this.swimlaneId}_${this.listId}`);
+ $(window).off(`resize.spinner_${this.swimlaneId}_${this.listId}`);
+ },
+
+ updateList() {
+ if (this.spinnerInView()) {
+ this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
+ window.requestIdleCallback(() => this.updateList());
+ }
+ },
+
+ spinnerInView() {
+ const parentViewHeight = this.container.clientHeight;
+ const bottomViewPosition = this.container.scrollTop + parentViewHeight;
+
+ const threshold = this.spinner.offsetTop;
+
+ // spinner deleted
+ if (!this.spinner.offsetTop) {
+ return false;
+ }
+
+ return bottomViewPosition > threshold;
+ },
+
+}).register('spinnerList');
diff --git a/client/components/lists/minilist.jade b/client/components/lists/minilist.jade
new file mode 100644
index 00000000..e34214c4
--- /dev/null
+++ b/client/components/lists/minilist.jade
@@ -0,0 +1,8 @@
+template(name="minilist")
+ .minicard(
+ class="minicard-{{colorClass}}")
+ .minicard-title
+ .handle
+ .fa.fa-arrows
+ +viewer
+ = title
diff --git a/client/components/main/editor.js b/client/components/main/editor.js
index 20ece562..88d8abf0 100755
--- a/client/components/main/editor.js
+++ b/client/components/main/editor.js
@@ -36,7 +36,10 @@ import sanitizeXss from 'xss';
const at = HTML.CharRef({html: '&commat;', str: '@'});
Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
const view = this;
+ let content = Blaze.toHTML(view.templateContentBlock);
const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ if (!currentBoard)
+ return HTML.Raw(sanitizeXss(content));
const knowedUsers = currentBoard.members.map((member) => {
const u = Users.findOne(member.userId);
if(u){
@@ -45,7 +48,6 @@ Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
return member;
});
const mentionRegex = /\B@([\w.]*)/gi;
- let content = Blaze.toHTML(view.templateContentBlock);
let currentMention;
while ((currentMention = mentionRegex.exec(content)) !== null) {
diff --git a/client/components/main/header.jade b/client/components/main/header.jade
index e21ce096..75e84c0c 100644
--- a/client/components/main/header.jade
+++ b/client/components/main/header.jade
@@ -4,39 +4,38 @@ template(name="header")
list all starred boards with a link to go there. This is inspired by the
Reddit "subreddit" bar.
The first link goes to the boards page.
- unless isSandstorm
- if currentUser
- #header-quick-access(class=currentBoard.colorClass)
- if isMiniScreen
- ul
- li
- a(href="{{pathFor 'home'}}")
- span.fa.fa-home
+ if currentUser
+ #header-quick-access(class=currentBoard.colorClass)
+ if isMiniScreen
+ ul
+ li
+ a(href="{{pathFor 'home'}}")
+ span.fa.fa-home
- if currentList
- each currentBoard.lists
- li(class="{{#if $.Session.equals 'currentList' _id}}current{{/if}}")
- a.js-select-list
- = title
- #header-new-board-icon
- else
- ul
- li
- a(href="{{pathFor 'home'}}")
- span.fa.fa-home
- | {{_ 'all-boards'}}
- each currentUser.starredBoards
- li.separator -
- li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
- a(href="{{pathFor 'board' id=_id slug=slug}}")
+ if currentList
+ each currentBoard.lists
+ li(class="{{#if $.Session.equals 'currentList' _id}}current{{/if}}")
+ a.js-select-list
= title
- else
- li.current {{_ 'quick-access-description'}}
+ #header-new-board-icon
+ else
+ ul
+ li
+ a(href="{{pathFor 'home'}}")
+ span.fa.fa-home
+ | {{_ 'all-boards'}}
+ each currentUser.starredBoards
+ li.separator -
+ li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
+ a(href="{{pathFor 'board' id=_id slug=slug}}")
+ = title
+ else
+ li.current {{_ 'quick-access-description'}}
- a#header-new-board-icon.js-create-board
- i.fa.fa-plus(title="Create a new board")
+ a#header-new-board-icon.js-create-board
+ i.fa.fa-plus(title="Create a new board")
- +headerUserBar
+ +headerUserBar
#header(class=currentBoard.colorClass)
//-
@@ -46,19 +45,16 @@ template(name="header")
#header-main-bar(class="{{#if wrappedHeader}}wrapper{{/if}}")
+Template.dynamic(template=headerBar)
- unless hideLogo
+ //unless hideLogo
//-
On sandstorm, the logo shouldn't be clickable, because we only have one
page/document on it, and we don't want to see the home page containing
the list of all boards.
- if isSandstorm
- .wekan-logo
- img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
- else
- unless currentSetting.hideLogo
- a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
- img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
+
+ // unless currentSetting.hideLogo
+ // a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
+ // img(src="{{pathFor '/logo-header.png'}}" alt="")
if appIsOffline
+offlineWarning
diff --git a/client/components/main/layouts.jade b/client/components/main/layouts.jade
index a6115ec1..ac2e4bf3 100644
--- a/client/components/main/layouts.jade
+++ b/client/components/main/layouts.jade
@@ -1,5 +1,5 @@
head
- title Wekan
+ title
meta(name="viewport"
content="maximum-scale=1.0,width=device-width,initial-scale=1.0,user-scalable=0")
meta(http-equiv="X-UA-Compatible" content="IE=edge")
@@ -7,24 +7,20 @@ head
where the application is deployed with a path prefix, but it seems to be
difficult to do that cleanly with Blaze -- at least without adding extra
packages.
- link(rel="shortcut icon" href="/public/wekan-favicon.png")
- link(rel="apple-touch-icon" href="/public/wekan-favicon.png")
- link(rel="mask-icon" href="/public/wekan-150.svg")
- link(rel="manifest" href="/public/wekan-manifest.json")
+ link(rel="shortcut icon" href="/wekan-favicon.png")
+ link(rel="apple-touch-icon" href="/wekan-favicon.png")
+ link(rel="mask-icon" href="/wekan-logo-150.svg")
+ link(rel="manifest" href="/wekan-manifest.json")
template(name="userFormsLayout")
section.auth-layout
- unless currentSetting.hideLogo
- h1.at-form-landing-logo
- img(src="{{pathFor '/wekan-logo.png'}}" alt="Wekan")
- if currentSetting.hideLogo
- h1
- br
- br
+ h1
+ br
+ br
section.auth-dialog
+Template.dynamic(template=content)
if currentSetting.displayAuthenticationMethod
- +connectionMethod
+ +connectionMethod(authenticationMethod=currentSetting.defaultAuthenticationMethod)
div.at-form-lang
select.select-lang.js-userform-set-language
each languages
diff --git a/client/components/settings/connectionMethod.jade b/client/components/settings/connectionMethod.jade
index ac4c8c64..d191929f 100644
--- a/client/components/settings/connectionMethod.jade
+++ b/client/components/settings/connectionMethod.jade
@@ -2,5 +2,8 @@ template(name='connectionMethod')
div.at-form-authentication
label {{_ 'authentication-method'}}
select.select-authentication
- each authentications
- option(value="{{value}}") {{_ value}}
+ each authentications
+ if isSelected value
+ option(value="{{value}}" selected) {{_ value}}
+ else
+ option(value="{{value}}") {{_ value}} \ No newline at end of file
diff --git a/client/components/settings/connectionMethod.js b/client/components/settings/connectionMethod.js
index 9fe8f382..db9da25f 100644
--- a/client/components/settings/connectionMethod.js
+++ b/client/components/settings/connectionMethod.js
@@ -31,4 +31,7 @@ Template.connectionMethod.helpers({
authentications() {
return Template.instance().authenticationMethods.get();
},
+ isSelected(match) {
+ return Template.instance().data.authenticationMethod === match;
+ },
});
diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade
index 220dbb50..89911e09 100644
--- a/client/components/settings/settingBody.jade
+++ b/client/components/settings/settingBody.jade
@@ -134,7 +134,7 @@ template(name='announcementSettings')
template(name='layoutSettings')
ul#layout-setting.setting-detail
- li.layout-form
+ //li.layout-form
.title {{_ 'hide-logo'}}
.form-group.flex
input.form-control#hide-logo(type="radio" name="hideLogo" value="true" checked="{{#if currentSetting.hideLogo}}checked{{/if}}")
@@ -154,7 +154,7 @@ template(name='layoutSettings')
li.layout-form
.title {{_ 'custom-product-name'}}
.form-group
- input.form-control#product-name(type="text", placeholder="Wekan" value="{{currentSetting.productName}}")
+ input.form-control#product-name(type="text", placeholder="" value="{{currentSetting.productName}}")
li.layout-form
.title {{_ 'add-custom-html-after-body-start'}}
textarea#customHTMLafterBodyStart.form-control= currentSetting.customHTMLafterBodyStart
@@ -171,4 +171,4 @@ template(name='selectAuthenticationMethod')
if isSelected value
option(value="{{value}}" selected) {{_ value}}
else
- option(value="{{value}}") {{_ value}} \ No newline at end of file
+ option(value="{{value}}") {{_ value}}
diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js
index 2f58d551..8279a092 100644
--- a/client/components/settings/settingBody.js
+++ b/client/components/settings/settingBody.js
@@ -90,7 +90,7 @@ BlazeComponent.extendComponent({
},
inviteThroughEmail() {
- const emails = $('#email-to-invite').val().trim().split('\n').join(',').split(',');
+ const emails = $('#email-to-invite').val().toLowerCase().trim().split('\n').join(',').split(',');
const boardsToInvite = [];
$('.js-toggle-board-choose .materialCheckBox.is-checked').each(function () {
boardsToInvite.push($(this).data('id'));
diff --git a/client/components/settings/settingBody.styl b/client/components/settings/settingBody.styl
index 7f8bd4c0..dbf91a6c 100644
--- a/client/components/settings/settingBody.styl
+++ b/client/components/settings/settingBody.styl
@@ -52,6 +52,10 @@
.main-body
padding: 0.1em 1em
+ -webkit-user-select: auto // Safari 3.1+
+ -moz-user-select: auto // Firefox 2+
+ -ms-user-select: auto // IE 10+
+ user-select: auto // Standard syntax
ul
li
diff --git a/client/components/settings/settingHeader.jade b/client/components/settings/settingHeader.jade
index c2d4db3a..221c1b79 100644
--- a/client/components/settings/settingHeader.jade
+++ b/client/components/settings/settingHeader.jade
@@ -4,22 +4,21 @@ template(name="settingHeaderBar")
.setting-header-btns.left
unless isMiniScreen
- unless isSandstorm
- if currentUser
- a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
- i.fa(class="fa-cog")
- span {{_ 'settings'}}
+ if currentUser
+ a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
+ i.fa(class="fa-cog")
+ span {{_ 'settings'}}
- a.setting-header-btn.people(href="{{pathFor 'people'}}")
- i.fa(class="fa-users")
- span {{_ 'people'}}
+ a.setting-header-btn.people(href="{{pathFor 'people'}}")
+ i.fa(class="fa-users")
+ span {{_ 'people'}}
- a.setting-header-btn.informations(href="{{pathFor 'information'}}")
- i.fa(class="fa-info-circle")
- span {{_ 'info'}}
+ a.setting-header-btn.informations(href="{{pathFor 'information'}}")
+ i.fa(class="fa-info-circle")
+ span {{_ 'info'}}
- else
- a.setting-header-btn.js-log-in(
- title="{{_ 'log-in'}}")
- i.fa.fa-sign-in
- span {{_ 'log-in'}}
+ else
+ a.setting-header-btn.js-log-in(
+ title="{{_ 'log-in'}}")
+ i.fa.fa-sign-in
+ span {{_ 'log-in'}}
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade
index ec88ce7e..4e4d355c 100644
--- a/client/components/sidebar/sidebar.jade
+++ b/client/components/sidebar/sidebar.jade
@@ -1,9 +1,9 @@
template(name="sidebar")
.board-sidebar.sidebar(class="{{#if isOpen}}is-open{{/if}}")
- a.sidebar-tongue.js-toggle-sidebar(
- class="{{#if isTongueHidden}}is-hidden{{/if}}",
- title="{{showTongueTitle}}")
- i.fa.fa-angle-left
+ //a.sidebar-tongue.js-toggle-sidebar(
+ // class="{{#if isTongueHidden}}is-hidden{{/if}}",
+ // title="{{showTongueTitle}}")
+ // i.fa.fa-navicon
.sidebar-shadow
.sidebar-content.sidebar-shortcuts
a.board-header-btn.js-shortcuts
@@ -11,7 +11,7 @@ template(name="sidebar")
span {{_ 'keyboard-shortcuts' }}
.sidebar-content.js-board-sidebar-content.js-perfect-scrollbar
a.hide-btn.js-hide-sidebar
- i.fa.fa-angle-right
+ i.fa.fa-navicon
unless isDefaultView
h2
a.fa.fa-chevron-left.js-back-home
@@ -34,6 +34,9 @@ template(name="membersWidget")
h3
i.fa.fa-user
| {{_ 'members'}}
+ a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}").right
+ i.board-header-btn-icon.fa.fa-cog
+
.board-widget-content
each currentBoard.activeMembers
+userAvatar(userId=this.userId showStatus=true)
@@ -53,6 +56,130 @@ template(name="membersWidget")
button.js-member-invite-accept.primary {{_ 'accept'}}
button.js-member-invite-decline {{_ 'decline'}}
+template(name="boardChangeColorPopup")
+ .board-backgrounds-list.clearfix
+ each backgroundColors
+ .board-background-select.js-select-background
+ span.background-box(class="board-color-{{this}}")
+ if isSelected
+ i.fa.fa-check
+
+template(name="boardSubtaskSettingsPopup")
+ form.board-subtask-settings
+ h3 {{_ 'show-parent-in-minicard'}}
+ a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
+ .materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
+ span {{_ 'prefix-with-full-path'}}
+ a#prefix-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
+ .materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
+ span {{_ 'prefix-with-parent'}}
+ a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
+ .materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
+ span {{_ 'subtext-with-full-path'}}
+ a#subtext-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
+ .materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
+ span {{_ 'subtext-with-parent'}}
+ a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
+ .materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
+ span {{_ 'no-parent'}}
+ div
+ hr
+
+ div.check-div
+ a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
+ .materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
+ span {{_ 'show-subtasks-field'}}
+
+ label
+ | {{_ 'deposit-subtasks-board'}}
+ select.js-field-deposit-board(disabled="{{#unless allowsSubtasks}}disabled{{/unless}}")
+ each boards
+ if isBoardSelected
+ option(value=_id selected="selected") {{title}}
+ else
+ option(value=_id) {{title}}
+ if isNullBoardSelected
+ option(value='null' selected="selected") {{_ 'custom-field-dropdown-none'}}
+ else
+ option(value='null') {{_ 'custom-field-dropdown-none'}}
+ div
+ hr
+
+ label
+ | {{_ 'deposit-subtasks-list'}}
+ select.js-field-deposit-list(disabled="{{#unless hasLists}}disabled{{/unless}}")
+ each lists
+ if isListSelected
+ option(value=_id selected="selected") {{title}}
+ else
+ option(value=_id) {{title}}
+
+template(name="chooseBoardSource")
+ ul.pop-over-list
+ li
+ a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}}
+ li
+ a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}}
+
+template(name="archiveBoardPopup")
+ p {{_ 'close-board-pop'}}
+ button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
+
+template(name="outgoingWebhooksPopup")
+ each integrations
+ form.integration-form
+ if title
+ h4 {{title}}
+ else
+ h4 {{_ 'no-name'}}
+ label
+ | URL
+ input.js-outgoing-webhooks-url(type="text" name="url" value=url)
+ input(type="hidden" value=_id name="id")
+ input.primary.wide(type="submit" value="{{_ 'save'}}")
+ form.integration-form
+ h4
+ | {{_ 'new-outgoing-webhook'}}
+ label
+ | URL
+ input.js-outgoing-webhooks-url(type="text" name="url" autofocus)
+ input.primary.wide(type="submit" value="{{_ 'save'}}")
+
+template(name="boardMenuPopup")
+ ul.pop-over-list
+ 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'}}
+ //-
+ XXX Language should be handled by sandstorm, but for now display a
+ language selection link in the board menu. This link is normally present
+ in the header bar that is not displayed on sandstorm.
+ if isSandstorm
+ li: a.js-change-language {{_ 'language'}}
+ unless isSandstorm
+ if currentUser.isBoardAdmin
+ hr
+ ul.pop-over-list
+ li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
+ unless currentBoard.isTemplatesBoard
+ li: a.js-archive-board {{_ 'archive-board'}}
+ li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
+ hr
+ ul.pop-over-list
+ li: a.js-subtask-settings {{_ 'subtask-settings'}}
+
+ if isSandstorm
+ hr
+ ul.pop-over-list
+ li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
+ li: a.js-import-board {{_ 'import-board-c'}}
+ li: a.js-archive-board {{_ 'archive-board'}}
+ li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
+ hr
+ ul.pop-over-list
+ li: a.js-subtask-settings {{_ 'subtask-settings'}}
+
template(name="labelsWidget")
.board-widget.board-widget-labels
h3
@@ -83,17 +210,16 @@ template(name="memberPopup")
ul.pop-over-list
li
a.js-filter-member {{_ 'filter-cards'}}
- unless isSandstorm
- if currentUser.isBoardAdmin
- li
- a.js-change-role
- | {{_ 'change-permissions'}}
- span.quiet (#{memberType})
+ if currentUser.isBoardAdmin
li
- if $eq currentUser._id userId
- a.js-leave-member {{_ 'leave-board'}}
- else if currentUser.isBoardAdmin
- a.js-remove-member {{_ 'remove-from-board'}}
+ a.js-change-role
+ | {{_ 'change-permissions'}}
+ span.quiet (#{memberType})
+ li
+ if $eq currentUser._id userId
+ a.js-leave-member {{_ 'leave-board'}}
+ else if currentUser.isBoardAdmin
+ a.js-remove-member {{_ 'remove-from-board'}}
template(name="removeMemberPopup")
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index 83b12666..e8de3c96 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -142,6 +142,52 @@ Template.memberPopup.helpers({
},
});
+Template.boardMenuPopup.events({
+ 'click .js-rename-board': Popup.open('boardChangeTitle'),
+ 'click .js-custom-fields'() {
+ Sidebar.setView('customFields');
+ Popup.close();
+ },
+ 'click .js-open-archives'() {
+ Sidebar.setView('archives');
+ Popup.close();
+ },
+ 'click .js-change-board-color': Popup.open('boardChangeColor'),
+ 'click .js-change-language': Popup.open('changeLanguage'),
+ 'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ currentBoard.archive();
+ // XXX We should have some kind of notification on top of the page to
+ // confirm that the board was successfully archived.
+ FlowRouter.go('home');
+ }),
+ 'click .js-delete-board': Popup.afterConfirm('deleteBoard', function() {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ Popup.close();
+ Boards.remove(currentBoard._id);
+ FlowRouter.go('home');
+ }),
+ 'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'),
+ 'click .js-import-board': Popup.open('chooseBoardSource'),
+ 'click .js-subtask-settings': Popup.open('boardSubtaskSettings'),
+});
+
+Template.boardMenuPopup.helpers({
+ exportUrl() {
+ const params = {
+ boardId: Session.get('currentBoard'),
+ };
+ const queryParams = {
+ authToken: Accounts._storedLoginToken(),
+ };
+ return FlowRouter.path('/api/boards/:boardId/export', params, queryParams);
+ },
+ exportFilename() {
+ const boardId = Session.get('currentBoard');
+ return `wekan-export-board-${boardId}.json`;
+ },
+});
+
Template.memberPopup.events({
'click .js-filter-member'() {
Filter.members.toggle(this.userId);
@@ -190,7 +236,14 @@ Template.membersWidget.helpers({
Template.membersWidget.events({
'click .js-member': Popup.open('member'),
+ 'click .js-open-board-menu': Popup.open('boardMenu'),
'click .js-manage-board-members': Popup.open('addMember'),
+ 'click .js-import': Popup.open('boardImportBoard'),
+ submit: this.onSubmit,
+ 'click .js-import-board': Popup.open('chooseBoardSource'),
+ 'click .js-open-archived-board'() {
+ Modal.open('archivedBoards');
+ },
'click .sandstorm-powerbox-request-identity'() {
window.sandstormRequestIdentity();
},
@@ -209,6 +262,59 @@ Template.membersWidget.events({
},
});
+BlazeComponent.extendComponent({
+ integrations() {
+ const boardId = Session.get('currentBoard');
+ return Integrations.find({ boardId: `${boardId}` }).fetch();
+ },
+
+ integration(id) {
+ const boardId = Session.get('currentBoard');
+ return Integrations.findOne({ _id: id, boardId: `${boardId}` });
+ },
+
+ events() {
+ return [{
+ 'submit'(evt) {
+ evt.preventDefault();
+ const url = evt.target.url.value;
+ const boardId = Session.get('currentBoard');
+ let id = null;
+ let integration = null;
+ if (evt.target.id) {
+ id = evt.target.id.value;
+ integration = this.integration(id);
+ if (url) {
+ Integrations.update(integration._id, {
+ $set: {
+ url: `${url}`,
+ },
+ });
+ } else {
+ Integrations.remove(integration._id);
+ }
+ } else if (url) {
+ Integrations.insert({
+ userId: Meteor.userId(),
+ enabled: true,
+ type: 'outgoing-webhooks',
+ url: `${url}`,
+ boardId: `${boardId}`,
+ activities: ['all'],
+ });
+ }
+ Popup.close();
+ },
+ }];
+ },
+}).register('outgoingWebhooksPopup');
+
+BlazeComponent.extendComponent({
+ template() {
+ return 'chooseBoardSource';
+ },
+}).register('chooseBoardSourcePopup');
+
Template.labelsWidget.events({
'click .js-label': Popup.open('editLabel'),
'click .js-add-label': Popup.open('createLabel'),
@@ -259,6 +365,124 @@ Template.membersWidget.onRendered(draggableMembersLabelsWidgets);
Template.labelsWidget.onRendered(draggableMembersLabelsWidgets);
BlazeComponent.extendComponent({
+ backgroundColors() {
+ return Boards.simpleSchema()._schema.color.allowedValues;
+ },
+
+ isSelected() {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ return currentBoard.color === this.currentData().toString();
+ },
+
+ events() {
+ return [{
+ 'click .js-select-background'(evt) {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ const newColor = this.currentData().toString();
+ currentBoard.setColor(newColor);
+ evt.preventDefault();
+ },
+ }];
+ },
+}).register('boardChangeColorPopup');
+
+BlazeComponent.extendComponent({
+ onCreated() {
+ this.currentBoard = Boards.findOne(Session.get('currentBoard'));
+ },
+
+ allowsSubtasks() {
+ return this.currentBoard.allowsSubtasks;
+ },
+
+ isBoardSelected() {
+ return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
+ },
+
+ isNullBoardSelected() {
+ return (this.currentBoard.subtasksDefaultBoardId === null) || (this.currentBoard.subtasksDefaultBoardId === undefined);
+ },
+
+ boards() {
+ return Boards.find({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ }, {
+ sort: ['title'],
+ });
+ },
+
+ lists() {
+ return Lists.find({
+ boardId: this.currentBoard._id,
+ archived: false,
+ }, {
+ sort: ['title'],
+ });
+ },
+
+ hasLists() {
+ return this.lists().count() > 0;
+ },
+
+ isListSelected() {
+ return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
+ },
+
+ presentParentTask() {
+ let result = this.currentBoard.presentParentTask;
+ if ((result === null) || (result === undefined)) {
+ result = 'no-parent';
+ }
+ return result;
+ },
+
+ events() {
+ return [{
+ 'click .js-field-has-subtasks'(evt) {
+ evt.preventDefault();
+ this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
+ this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
+ $('.js-field-has-subtasks .materialCheckBox').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
+ $('.js-field-has-subtasks').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
+ $('.js-field-deposit-board').prop('disabled', !this.currentBoard.allowsSubtasks);
+ },
+ 'change .js-field-deposit-board'(evt) {
+ let value = evt.target.value;
+ if (value === 'null') {
+ value = null;
+ }
+ this.currentBoard.setSubtasksDefaultBoardId(value);
+ evt.preventDefault();
+ },
+ 'change .js-field-deposit-list'(evt) {
+ this.currentBoard.setSubtasksDefaultListId(evt.target.value);
+ evt.preventDefault();
+ },
+ 'click .js-field-show-parent-in-minicard'(evt) {
+ const value = evt.target.id || $(evt.target).parent()[0].id || $(evt.target).parent()[0].parent()[0].id;
+ const options = [
+ 'prefix-with-full-path',
+ 'prefix-with-parent',
+ 'subtext-with-full-path',
+ 'subtext-with-parent',
+ 'no-parent'];
+ options.forEach(function(element) {
+ if (element !== value) {
+ $(`#${element} .materialCheckBox`).toggleClass('is-checked', false);
+ $(`#${element}`).toggleClass('is-checked', false);
+ }
+ });
+ $(`#${value} .materialCheckBox`).toggleClass('is-checked', true);
+ $(`#${value}`).toggleClass('is-checked', true);
+ this.currentBoard.setPresentParentTask(value);
+ evt.preventDefault();
+ },
+ }];
+ },
+}).register('boardSubtaskSettingsPopup');
+
+BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
diff --git a/client/components/sidebar/sidebarCustomFields.js b/client/components/sidebar/sidebarCustomFields.js
index ccc8ffb9..28af973b 100644
--- a/client/components/sidebar/sidebarCustomFields.js
+++ b/client/components/sidebar/sidebarCustomFields.js
@@ -2,7 +2,7 @@ BlazeComponent.extendComponent({
customFields() {
return CustomFields.find({
- boardId: Session.get('currentBoard'),
+ boardIds: {$in: [Session.get('currentBoard')]},
});
},
@@ -103,7 +103,6 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
evt.preventDefault();
const data = {
- boardId: Session.get('currentBoard'),
name: this.find('.js-field-name').value.trim(),
type: this.type.get(),
settings: this.getSettings(),
@@ -114,6 +113,7 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
// insert or update
if (!this.data()._id) {
+ data.boardIds = [Session.get('currentBoard')];
CustomFields.insert(data);
} else {
CustomFields.update(this.data()._id, {$set: data});
@@ -122,8 +122,16 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
Popup.back();
},
'click .js-delete-custom-field': Popup.afterConfirm('deleteCustomField', function() {
- const customFieldId = this._id;
- CustomFields.remove(customFieldId);
+ const customField = CustomFields.findOne(this._id);
+ if (customField.boardIds.length > 1) {
+ CustomFields.update(customField._id, {
+ $pull: {
+ boardIds: Session.get('currentBoard'),
+ },
+ });
+ } else {
+ CustomFields.remove(customField._id);
+ }
Popup.close();
}),
}];
diff --git a/client/components/swimlanes/miniswimlane.jade b/client/components/swimlanes/miniswimlane.jade
new file mode 100644
index 00000000..d4be8599
--- /dev/null
+++ b/client/components/swimlanes/miniswimlane.jade
@@ -0,0 +1,8 @@
+template(name="miniswimlane")
+ .minicard(
+ class="minicard-{{colorClass}}")
+ .minicard-title
+ .handle
+ .fa.fa-arrows
+ +viewer
+ = title
diff --git a/client/components/swimlanes/swimlaneHeader.jade b/client/components/swimlanes/swimlaneHeader.jade
index 33eb5731..de9621d5 100644
--- a/client/components/swimlanes/swimlaneHeader.jade
+++ b/client/components/swimlanes/swimlaneHeader.jade
@@ -1,15 +1,21 @@
template(name="swimlaneHeader")
.swimlane-header-wrap.js-swimlane-header(class='{{#if colorClass}}swimlane-{{colorClass}}{{/if}}')
- +inlinedForm
- +editSwimlaneTitleForm
+ if this.isTemplateContainer
+ +swimlaneFixedHeader(this)
else
- .swimlane-header(
- class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
- = title
- .swimlane-header-menu
- unless currentUser.isCommentOnly
- a.fa.fa-plus.js-open-add-swimlane-menu.swimlane-header-plus-icon
- a.fa.fa-navicon.js-open-swimlane-menu
+ +inlinedForm
+ +editSwimlaneTitleForm
+ else
+ +swimlaneFixedHeader(this)
+
+template(name="swimlaneFixedHeader")
+ .swimlane-header(
+ class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
+ = title
+ .swimlane-header-menu
+ unless currentUser.isCommentOnly
+ a.fa.fa-plus.js-open-add-swimlane-menu.swimlane-header-plus-icon
+ a.fa.fa-navicon.js-open-swimlane-menu
template(name="editSwimlaneTitleForm")
.list-composer
@@ -22,9 +28,10 @@ template(name="swimlaneActionPopup")
unless currentUser.isCommentOnly
ul.pop-over-list
li: a.js-set-swimlane-color {{_ 'select-color'}}
- hr
- ul.pop-over-list
- li: a.js-close-swimlane {{_ 'archive-swimlane'}}
+ unless this.isTemplateContainer
+ hr
+ ul.pop-over-list
+ li: a.js-close-swimlane {{_ 'archive-swimlane'}}
template(name="swimlaneAddPopup")
unless currentUser.isCommentOnly
@@ -33,6 +40,11 @@ template(name="swimlaneAddPopup")
autocomplete="off" autofocus)
.edit-controls.clearfix
button.primary.confirm(type="submit") {{_ 'add'}}
+ unless currentBoard.isTemplatesBoard
+ unless currentBoard.isTemplateBoard
+ span.quiet
+ | {{_ 'or'}}
+ a.js-swimlane-template {{_ 'template'}}
template(name="setSwimlaneColorPopup")
form.edit-label
diff --git a/client/components/swimlanes/swimlaneHeader.js b/client/components/swimlanes/swimlaneHeader.js
index 1004cb25..e7f3cc76 100644
--- a/client/components/swimlanes/swimlaneHeader.js
+++ b/client/components/swimlanes/swimlaneHeader.js
@@ -47,12 +47,14 @@ BlazeComponent.extendComponent({
const titleInput = this.find('.swimlane-name-input');
const title = titleInput.value.trim();
const sortValue = calculateIndexData(this.currentSwimlane, nextSwimlane, 1);
+ const swimlaneType = (currentBoard.isTemplatesBoard())?'template-swimlane':'swimlane';
if (title) {
Swimlanes.insert({
title,
boardId: Session.get('currentBoard'),
sort: sortValue.base,
+ type: swimlaneType,
});
titleInput.value = '';
@@ -63,6 +65,7 @@ BlazeComponent.extendComponent({
// with a minimum of interactions
Popup.close();
},
+ 'click .js-swimlane-template': Popup.open('searchElement'),
}];
},
}).register('swimlaneAddPopup');
diff --git a/client/components/swimlanes/swimlanes.jade b/client/components/swimlanes/swimlanes.jade
index 34177a02..c56834df 100644
--- a/client/components/swimlanes/swimlanes.jade
+++ b/client/components/swimlanes/swimlanes.jade
@@ -3,15 +3,15 @@ template(name="swimlane")
+swimlaneHeader
.swimlane.js-lists.js-swimlane
if isMiniScreen
- if currentList
+ if currentListIsInThisSwimlane _id
+list(currentList)
- else
- each currentBoard.lists
+ unless currentList
+ each lists
+miniList(this)
if currentUser.isBoardMember
+addListForm
else
- each currentBoard.lists
+ each lists
+list(this)
if currentCardIsInThisList _id ../_id
+cardDetails(currentCard)
@@ -24,12 +24,12 @@ template(name="listsGroup")
if currentList
+list(currentList)
else
- each currentBoard.lists
+ each lists
+miniList(this)
if currentUser.isBoardMember
+addListForm
else
- each currentBoard.lists
+ each lists
+list(this)
if currentCardIsInThisList _id null
+cardDetails(currentCard)
@@ -44,7 +44,11 @@ template(name="addListForm")
autocomplete="off" autofocus)
.edit-controls.clearfix
button.primary.confirm(type="submit") {{_ 'save'}}
- a.fa.fa-times-thin.js-close-inlined-form
+ unless currentBoard.isTemplatesBoard
+ unless currentBoard.isTemplateBoard
+ span.quiet
+ | {{_ 'or'}}
+ a.js-list-template {{_ 'template'}}
else
a.open-list-composer.js-open-inlined-form
i.fa.fa-plus
diff --git a/client/components/swimlanes/swimlanes.js b/client/components/swimlanes/swimlanes.js
index ce327f54..519b00d2 100644
--- a/client/components/swimlanes/swimlanes.js
+++ b/client/components/swimlanes/swimlanes.js
@@ -1,5 +1,10 @@
const { calculateIndex, enableClickOnTouch } = Utils;
+function currentListIsInThisSwimlane(swimlaneId) {
+ const currentList = Lists.findOne(Session.get('currentList'));
+ return currentList && (currentList.swimlaneId === swimlaneId || currentList.swimlaneId === '');
+}
+
function currentCardIsInThisList(listId, swimlaneId) {
const currentCard = Cards.findOne(Session.get('currentCard'));
const currentUser = Meteor.user();
@@ -114,6 +119,10 @@ BlazeComponent.extendComponent({
return currentCardIsInThisList(listId, swimlaneId);
},
+ currentListIsInThisSwimlane(swimlaneId) {
+ return currentListIsInThisSwimlane(swimlaneId);
+ },
+
events() {
return [{
// Click-and-drag action
@@ -153,6 +162,12 @@ BlazeComponent.extendComponent({
}).register('swimlane');
BlazeComponent.extendComponent({
+ onCreated() {
+ this.currentBoard = Boards.findOne(Session.get('currentBoard'));
+ this.isListTemplatesSwimlane = this.currentBoard.isTemplatesBoard() && this.currentData().isListTemplatesSwimlane();
+ this.currentSwimlane = this.currentData();
+ },
+
// Proxy
open() {
this.childComponents('inlinedForm')[0].open();
@@ -169,12 +184,15 @@ BlazeComponent.extendComponent({
title,
boardId: Session.get('currentBoard'),
sort: $('.list').length,
+ type: (this.isListTemplatesSwimlane)?'template-list':'list',
+ swimlaneId: (this.currentBoard.isTemplatesBoard())?this.currentSwimlane._id:'',
});
titleInput.value = '';
titleInput.focus();
}
},
+ 'click .js-list-template': Popup.open('searchElement'),
}];
},
}).register('addListForm');
diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade
index b6e10d8a..c55b65c2 100644
--- a/client/components/users/userHeader.jade
+++ b/client/components/users/userHeader.jade
@@ -4,10 +4,11 @@ template(name="headerUserBar")
.header-user-bar-avatar
+userAvatar(userId=currentUser._id)
unless isMiniScreen
- if currentUser.profile.fullname
- = currentUser.profile.fullname
- else
- = currentUser.username
+ unless isSandstorm
+ if currentUser.profile.fullname
+ = currentUser.profile.fullname
+ else
+ = currentUser.username
template(name="memberMenuPopup")
ul.pop-over-list
@@ -15,13 +16,18 @@ template(name="memberMenuPopup")
li: a.js-edit-profile {{_ 'edit-profile'}}
li: a.js-change-settings {{_ 'change-settings'}}
li: a.js-change-avatar {{_ 'edit-avatar'}}
- li: a.js-change-password {{_ 'changePasswordPopup-title'}}
- li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
+ unless isSandstorm
+ li: a.js-change-password {{_ 'changePasswordPopup-title'}}
+ li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
if currentUser.isAdmin
li: a.js-go-setting(href="{{pathFor 'setting'}}") {{_ 'admin-panel'}}
hr
ul.pop-over-list
- li: a.js-logout {{_ 'log-out'}}
+ li: a(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}") {{_ 'templates'}}
+ unless isSandstorm
+ hr
+ ul.pop-over-list
+ li: a.js-logout {{_ 'log-out'}}
template(name="editProfilePopup")
form
diff --git a/client/components/users/userHeader.js b/client/components/users/userHeader.js
index 63cbb14f..6a2397a4 100644
--- a/client/components/users/userHeader.js
+++ b/client/components/users/userHeader.js
@@ -3,6 +3,15 @@ Template.headerUserBar.events({
'click .js-change-avatar': Popup.open('changeAvatar'),
});
+Template.memberMenuPopup.helpers({
+ templatesBoardId() {
+ return Meteor.user().getTemplatesBoardId();
+ },
+ templatesBoardSlug() {
+ return Meteor.user().getTemplatesBoardSlug();
+ },
+});
+
Template.memberMenuPopup.events({
'click .js-edit-profile': Popup.open('editProfile'),
'click .js-change-settings': Popup.open('changeSettings'),
diff --git a/client/lib/popup.js b/client/lib/popup.js
index 5b640f50..9abe48aa 100644
--- a/client/lib/popup.js
+++ b/client/lib/popup.js
@@ -184,7 +184,7 @@ window.Popup = new class {
// positives.
const title = TAPi18n.__(translationKey);
// when popup showed as full of small screen, we need a default header to clearly see [X] button
- const defaultTitle = Utils.isMiniScreen() ? 'Wekan' : false;
+ const defaultTitle = Utils.isMiniScreen() ? '' : false;
return title !== translationKey ? title : defaultTitle;
};
}