diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/components/activities/comments.js | 7 | ||||
-rw-r--r-- | client/components/boards/boardHeader.jade | 14 | ||||
-rw-r--r-- | client/components/boards/boardHeader.js | 4 | ||||
-rw-r--r-- | client/components/cards/attachments.jade | 2 | ||||
-rw-r--r-- | client/components/cards/cardDetails.jade | 11 | ||||
-rw-r--r-- | client/components/cards/minicard.styl | 2 | ||||
-rw-r--r-- | client/components/main/editor.jade | 7 | ||||
-rwxr-xr-x | client/components/main/editor.js | 66 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.jade | 4 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.js | 4 | ||||
-rw-r--r-- | client/lib/popup.js | 204 |
11 files changed, 37 insertions, 288 deletions
diff --git a/client/components/activities/comments.js b/client/components/activities/comments.js index e885459e..50ca019b 100644 --- a/client/components/activities/comments.js +++ b/client/components/activities/comments.js @@ -33,13 +33,6 @@ BlazeComponent.extendComponent({ cardId, }); resetCommentInput(input); - // With Richer editor is in use, and comment is submitted, - // clear comment form with JQuery. Id #summernote is defined - // at client/components/main/editor.jade where it previously was - // id=id, now it is id="summernote". - if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR === 'true') { - $('#summernote').summernote('code', ''); - } Tracker.flush(); autosize.update(input); input.trigger('submitted'); diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade index 53a74f76..4c0edac4 100644 --- a/client/components/boards/boardHeader.jade +++ b/client/components/boards/boardHeader.jade @@ -193,20 +193,6 @@ template(name="boardChangeViewPopup") | {{_ 'board-view-cal'}} if $eq Utils.boardView "board-view-cal" i.fa.fa-check - if currentUser.isAdmin - hr - li - with "board-view-rules" - a.js-open-rules-view(title="{{_ 'rules'}}") - i.fa.fa-magic - | {{_ 'rules'}} - else if currentUser.isBoardAdmin - hr - li - with "board-view-rules" - a.js-open-rules-view(title="{{_ 'rules'}}") - i.fa.fa-magic - | {{_ 'rules'}} template(name="createBoard") form diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js index 9040ed83..dc553134 100644 --- a/client/components/boards/boardHeader.js +++ b/client/components/boards/boardHeader.js @@ -191,10 +191,6 @@ Template.boardChangeViewPopup.events({ Utils.setBoardView('board-view-cal'); Popup.close(); }, - 'click .js-open-rules-view'() { - Modal.openWide('rulesMain'); - Popup.close(); - }, }); const CreateBoard = BlazeComponent.extendComponent({ diff --git a/client/components/cards/attachments.jade b/client/components/cards/attachments.jade index b695ea41..61454fa7 100644 --- a/client/components/cards/attachments.jade +++ b/client/components/cards/attachments.jade @@ -55,5 +55,5 @@ template(name="attachmentsGalery") unless currentUser.isWorker //li.attachment-item.add-attachment a.js-add-attachment - i.fa.fa-paperclip + i.fa.fa-plus | {{_ 'add-attachment' }} diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade index 615ae1d5..257ca0a8 100644 --- a/client/components/cards/cardDetails.jade +++ b/client/components/cards/cardDetails.jade @@ -203,6 +203,7 @@ template(name="cardDetails") if canModifyCard unless currentUser.isWorker if currentBoard.allowsDescriptionTitle + hr h3 i.fa.fa-align-left card-details-item-title {{_ 'description'}} @@ -229,6 +230,7 @@ template(name="cardDetails") a.js-close-inlined-form {{_ 'discard'}} else if getDescription if currentBoard.allowsDescriptionTitle + hr h3.card-details-item-title {{_ 'description'}} if currentBoard.allowsDescriptionText +viewer @@ -237,15 +239,16 @@ template(name="cardDetails") .card-checklist-attachmentGalerys .card-checklist-attachmentGalery.card-checklists if currentBoard.allowsChecklists + hr +checklists(cardId = _id) if currentBoard.allowsSubtasks hr +subtasks(cardId = _id) if currentBoard.allowsAttachments - //- hr - //- h3 - //- i.fa.fa-paperclip - //- | {{_ 'attachments'}} + hr + h3 + i.fa.fa-paperclip + | {{_ 'attachments'}} .card-checklist-attachmentGalery.card-attachmentGalery +attachmentsGalery diff --git a/client/components/cards/minicard.styl b/client/components/cards/minicard.styl index 8607e118..7d72a588 100644 --- a/client/components/cards/minicard.styl +++ b/client/components/cards/minicard.styl @@ -79,7 +79,7 @@ border-radius: top 2px .minicard-labels - float: right + float: none display: flex flex-wrap: wrap diff --git a/client/components/main/editor.jade b/client/components/main/editor.jade index 5c5454ee..dbd61715 100644 --- a/client/components/main/editor.jade +++ b/client/components/main/editor.jade @@ -1,13 +1,8 @@ template(name="editor") - // With Richer editor is in use, and comment is submitted, - // clear comment form with JQuery Comment at - // client/components/activities/comments.js . Id #summernote is defined - // here at client/components/main/editor.jade where it previously was - // id=id, now it is id="summernote". textarea.editor( dir="auto" class="{{class}}" - id="summernote" + id=id autofocus=autofocus placeholder="{{_ 'comment-placeholder'}}") +Template.contentBlock diff --git a/client/components/main/editor.js b/client/components/main/editor.js index 3f09d284..081c6521 100755 --- a/client/components/main/editor.js +++ b/client/components/main/editor.js @@ -30,7 +30,7 @@ Template.editor.onRendered(() => { autosize($textarea); $textarea.escapeableTextComplete(mentions); }; - if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR === 'true') { + if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR !== false) { const isSmall = Utils.isMiniScreen(); const toolbar = isSmall ? [ @@ -108,45 +108,17 @@ Template.editor.onRendered(() => { } return undefined; }; - // Prevent @member mentions on Add Comment input field - // from closing card, part 1. - let popupShown = false; inputs.each(function(idx, input) { mSummernotes[idx] = $(input).summernote({ placeholder, - // Prevent @member mentions on Add Comment input field - // from closing card, part 2. - onKeydown(e) { - if (popupShown) { - e.preventDefault(); - } - }, - onKeyup(e) { - if (popupShown) { - e.preventDefault(); - } - }, callbacks: { - // Prevent @member mentions on Add Comment input field - // from closing card, part 3. - onKeydown(e) { - if (popupShown) { - e.preventDefault(); - } - }, - onKeyup(e) { - if (popupShown) { - e.preventDefault(); - } - }, onInit(object) { const originalInput = this; - $(originalInput).on('input', function() { + $(originalInput).on('submitted', function() { // when comment is submitted, the original textarea will be set to '', so shall we if (!this.value) { const sn = getSummernote(this); - sn && sn.summernote('reset'); - object && object.editingArea.find('.note-placeholder').show(); + sn && sn.summernote('code', ''); } }); const jEditor = object && object.editable; @@ -163,6 +135,7 @@ Template.editor.onRendered(() => { }); } }, + onImageUpload(files) { const $summernote = getSummernote(this); if (files && files.length > 0) { @@ -249,7 +222,7 @@ Template.editor.onRendered(() => { // == Fix End == const original = someNote.summernote('code'); const cleaned = cleanPastedHTML(original); //this is where to call whatever clean function you want. I have mine in a different file, called CleanPastedHTML. - someNote.summernote('reset'); //clear original + someNote.summernote('code', ''); //clear original someNote.summernote('pasteHTML', cleaned); //this sets the displayed content editor to the cleaned pasted code. }; setTimeout(function() { @@ -316,15 +289,15 @@ Blaze.Template.registerHelper( let currentMention; while ((currentMention = mentionRegex.exec(content)) !== null) { - const [fullMention, username] = currentMention; + const [fullMention, quoteduser, simple] = currentMention; + const username = quoteduser || simple; const knowedUser = _.findWhere(knowedUsers, { username }); if (!knowedUser) { continue; } const linkValue = [' ', at, knowedUser.username]; - //let linkClass = 'atMention js-open-member'; - let linkClass = 'atMention'; + let linkClass = 'atMention js-open-member'; if (knowedUser.userId === Meteor.userId()) { linkClass += ' me'; } @@ -357,25 +330,24 @@ Template.viewer.events({ // the corresponding text). Clicking a link shouldn't fire these actions, stop // we stop these event at the viewer component level. 'click a'(event, templateInstance) { - event.stopPropagation(); - - // XXX We hijack the build-in browser action because we currently don't have - // `_blank` attributes in viewer links, and the transformer function is - // handled by a third party package that we can't configure easily. Fix that - // by using directly `_blank` attribute in the rendered HTML. - event.preventDefault(); - + let prevent = true; const userId = event.currentTarget.dataset.userid; if (userId) { - // Prevent @member mentions on Add Comment input field - // from closing card, part 4. - PopupNoClose.open('member').call({ userId }, event, templateInstance); - event.preventDefault(); + Popup.open('member').call({ userId }, event, templateInstance); } else { const href = event.currentTarget.href; if (href) { window.open(href, '_blank'); } } + if (prevent) { + event.stopPropagation(); + + // XXX We hijack the build-in browser action because we currently don't have + // `_blank` attributes in viewer links, and the transformer function is + // handled by a third party package that we can't configure easily. Fix that + // by using directly `_blank` attribute in the rendered HTML. + event.preventDefault(); + } }, }); diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index f0b0e4be..901fe99f 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -268,6 +268,10 @@ template(name="outgoingWebhooksPopup") template(name="boardMenuPopup") ul.pop-over-list li + a.js-open-rules-view(title="{{_ 'rules'}}") + i.fa.fa-magic + | {{_ 'rules'}} + li a.js-custom-fields i.fa.fa-list-alt | {{_ 'custom-fields'}} diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js index 8e640564..baf57114 100644 --- a/client/components/sidebar/sidebar.js +++ b/client/components/sidebar/sidebar.js @@ -182,6 +182,10 @@ Template.memberPopup.helpers({ Template.boardMenuPopup.events({ 'click .js-rename-board': Popup.open('boardChangeTitle'), + 'click .js-open-rules-view'() { + Modal.openWide('rulesMain'); + Popup.close(); + }, 'click .js-custom-fields'() { Sidebar.setView('customFields'); Popup.close(); diff --git a/client/lib/popup.js b/client/lib/popup.js index 8a55c2df..8095fbd2 100644 --- a/client/lib/popup.js +++ b/client/lib/popup.js @@ -206,207 +206,3 @@ escapeActions.forEach(actionName => { }, ); }); - -// Prevent @member mentions on Add Comment input field -// from closing card, part 5. -// This duplicate below of above popup function is needed, because at -// wekan/components/main/editor.js at bottom is popping up visible -// @member mention, and it seems to trigger closing also card popup, -// so in below closing popup is disabled. -window.PopupNoClose = new (class { - constructor() { - // The template we use to render popups - this.template = Template.popup; - - // We only want to display one popup at a time and we keep the view object - // in this `Popup.current` variable. If there is no popup currently opened - // the value is `null`. - this.current = null; - - // It's possible to open a sub-popup B from a popup A. In that case we keep - // the data of popup A so we can return back to it. Every time we open a new - // popup the stack grows, every time we go back the stack decrease, and if - // we close the popup the stack is reseted to the empty stack []. - this._stack = []; - - // We invalidate this internal dependency every time the top of the stack - // has changed and we want to re-render a popup with the new top-stack data. - this._dep = new Tracker.Dependency(); - } - - /// This function returns a callback that can be used in an event map: - /// Template.tplName.events({ - /// 'click .elementClass': Popup.open("popupName"), - /// }); - /// The popup inherit the data context of its parent. - open(name) { - const self = this; - const popupName = `${name}Popup`; - function clickFromPopup(evt) { - return $(evt.target).closest('.js-pop-over').length !== 0; - } - return function(evt) { - // If a popup is already opened, clicking again on the opener element - // should close it -- and interrupt the current `open` function. - /* - if (self.isOpen()) { - const previousOpenerElement = self._getTopStack().openerElement; - if (previousOpenerElement === evt.currentTarget) { - self.close(); - return; - } else { - $(previousOpenerElement).removeClass('is-active'); - } - } - */ - // We determine the `openerElement` (the DOM element that is being clicked - // and the one we take in reference to position the popup) from the event - // if the popup has no parent, or from the parent `openerElement` if it - // has one. This allows us to position a sub-popup exactly at the same - // position than its parent. - let openerElement; - if (clickFromPopup(evt)) { - openerElement = self._getTopStack().openerElement; - } else { - self._stack = []; - openerElement = evt.currentTarget; - } - $(openerElement).addClass('is-active'); - evt.preventDefault(); - - // We push our popup data to the stack. The top of the stack is always - // used as the data source for our current popup. - self._stack.push({ - popupName, - openerElement, - hasPopupParent: clickFromPopup(evt), - title: self._getTitle(popupName), - depth: self._stack.length, - offset: self._getOffset(openerElement), - dataContext: (this && this.currentData && this.currentData()) || this, - }); - - // If there are no popup currently opened we use the Blaze API to render - // one into the DOM. We use a reactive function as the data parameter that - // return the complete along with its top element and depends on our - // internal dependency that is being invalidated every time the top - // element of the stack has changed and we want to update the popup. - // - // Otherwise if there is already a popup open we just need to invalidate - // our internal dependency, and since we just changed the top element of - // our internal stack, the popup will be updated with the new data. - if (!self.isOpen()) { - self.current = Blaze.renderWithData( - self.template, - () => { - self._dep.depend(); - return { ...self._getTopStack(), stack: self._stack }; - }, - document.body, - ); - } else { - self._dep.changed(); - } - }; - } - - /// This function returns a callback that can be used in an event map: - /// Template.tplName.events({ - /// 'click .elementClass': Popup.afterConfirm("popupName", function() { - /// // What to do after the user has confirmed the action - /// }), - /// }); - afterConfirm(name, action) { - const self = this; - - return function(evt, tpl) { - const context = (this.currentData && this.currentData()) || this; - context.__afterConfirmAction = action; - self.open(name).call(context, evt, tpl); - }; - } - - /// The public reactive state of the popup. - isOpen() { - this._dep.changed(); - return Boolean(this.current); - } - - /// In case the popup was opened from a parent popup we can get back to it - /// with this `Popup.back()` function. You can go back several steps at once - /// by providing a number to this function, e.g. `Popup.back(2)`. In this case - /// intermediate popup won't even be rendered on the DOM. If the number of - /// steps back is greater than the popup stack size, the popup will be closed. - back(n = 1) { - if (this._stack.length > n) { - _.times(n, () => this._stack.pop()); - this._dep.changed(); - } - // else { - // this.close(); - //} - } - - /// Close the current opened popup. - /* - close() { - if (this.isOpen()) { - Blaze.remove(this.current); - this.current = null; - - const openerElement = this._getTopStack().openerElement; - $(openerElement).removeClass('is-active'); - - this._stack = []; - } - } - */ - - getOpenerComponent() { - const { openerElement } = Template.parentData(4); - return BlazeComponent.getComponentForElement(openerElement); - } - - // An utility fonction that returns the top element of the internal stack - _getTopStack() { - return this._stack[this._stack.length - 1]; - } - - // We automatically calculate the popup offset from the reference element - // position and dimensions. We also reactively use the window dimensions to - // ensure that the popup is always visible on the screen. - _getOffset(element) { - const $element = $(element); - return () => { - Utils.windowResizeDep.depend(); - - if (Utils.isMiniScreen()) return { left: 0, top: 0 }; - - const offset = $element.offset(); - const popupWidth = 300 + 15; - return { - left: Math.min(offset.left, $(window).width() - popupWidth), - top: offset.top + $element.outerHeight(), - }; - }; - } - - // We get the title from the translation files. Instead of returning the - // result, we return a function that compute the result and since `TAPi18n.__` - // is a reactive data source, the title will be changed reactively. - _getTitle(popupName) { - return () => { - const translationKey = `${popupName}-title`; - - // XXX There is no public API to check if there is an available - // translation for a given key. So we try to translate the key and if the - // translation output equals the key input we deduce that no translation - // was available and returns `false`. There is a (small) risk a false - // 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() ? '' : false; - return title !== translationKey ? title : defaultTitle; - }; - } -})(); |