| 
					
				 | 
			
			
				@@ -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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-})(); 
			 |