summaryrefslogtreecommitdiffstats
path: root/client/lib
diff options
context:
space:
mode:
Diffstat (limited to 'client/lib')
-rw-r--r--client/lib/datepicker.js86
-rw-r--r--client/lib/escapeActions.js2
-rw-r--r--client/lib/filter.js425
-rw-r--r--client/lib/inlinedform.js12
-rw-r--r--client/lib/modal.js14
-rw-r--r--client/lib/popup.js12
-rw-r--r--client/lib/utils.js153
7 files changed, 677 insertions, 27 deletions
diff --git a/client/lib/datepicker.js b/client/lib/datepicker.js
new file mode 100644
index 00000000..ab2da0bd
--- /dev/null
+++ b/client/lib/datepicker.js
@@ -0,0 +1,86 @@
+DatePicker = BlazeComponent.extendComponent({
+ template() {
+ return 'datepicker';
+ },
+
+ onCreated() {
+ this.error = new ReactiveVar('');
+ this.card = this.data();
+ this.date = new ReactiveVar(moment.invalid());
+ },
+
+ onRendered() {
+ const $picker = this.$('.js-datepicker').datepicker({
+ todayHighlight: true,
+ todayBtn: 'linked',
+ language: TAPi18n.getLanguage(),
+ }).on('changeDate', function(evt) {
+ this.find('#date').value = moment(evt.date).format('L');
+ this.error.set('');
+ this.find('#time').focus();
+ }.bind(this));
+
+ if (this.date.get().isValid()) {
+ $picker.datepicker('update', this.date.get().toDate());
+ }
+ },
+
+ showDate() {
+ if (this.date.get().isValid())
+ return this.date.get().format('L');
+ return '';
+ },
+ showTime() {
+ if (this.date.get().isValid())
+ return this.date.get().format('LT');
+ return '';
+ },
+ dateFormat() {
+ return moment.localeData().longDateFormat('L');
+ },
+ timeFormat() {
+ return moment.localeData().longDateFormat('LT');
+ },
+
+ events() {
+ return [{
+ 'keyup .js-date-field'() {
+ // parse for localized date format in strict mode
+ const dateMoment = moment(this.find('#date').value, 'L', true);
+ if (dateMoment.isValid()) {
+ this.error.set('');
+ this.$('.js-datepicker').datepicker('update', dateMoment.toDate());
+ }
+ },
+ 'keyup .js-time-field'() {
+ // parse for localized time format in strict mode
+ const dateMoment = moment(this.find('#time').value, 'LT', true);
+ if (dateMoment.isValid()) {
+ this.error.set('');
+ }
+ },
+ 'submit .edit-date'(evt) {
+ evt.preventDefault();
+
+ // if no time was given, init with 12:00
+ const time = evt.target.time.value || moment(new Date().setHours(12, 0, 0)).format('LT');
+
+ const dateString = `${evt.target.date.value} ${time}`;
+ const newDate = moment(dateString, 'L LT', true);
+ if (newDate.isValid()) {
+ this._storeDate(newDate.toDate());
+ Popup.close();
+ }
+ else {
+ this.error.set('invalid-date');
+ evt.target.date.focus();
+ }
+ },
+ 'click .js-delete-date'(evt) {
+ evt.preventDefault();
+ this._deleteDate();
+ Popup.close();
+ },
+ }];
+ },
+});
diff --git a/client/lib/escapeActions.js b/client/lib/escapeActions.js
index 666e33e0..0757ae46 100644
--- a/client/lib/escapeActions.js
+++ b/client/lib/escapeActions.js
@@ -135,6 +135,6 @@ $(document).on('click', (evt) => {
}
});
-$(document).on('click', 'a[href=#]', (evt) => {
+$(document).on('click', 'a[href=\\#]', (evt) => {
evt.preventDefault();
});
diff --git a/client/lib/filter.js b/client/lib/filter.js
index 8129776b..c3c1b070 100644
--- a/client/lib/filter.js
+++ b/client/lib/filter.js
@@ -3,17 +3,19 @@
// RangeFilter, dateFilter, etc.). We then define a global `Filter` object whose
// goal is to filter complete documents by using the local filters for each
// fields.
-
function showFilterSidebar() {
Sidebar.setView('filter');
}
// Use a "set" filter for a field that is a set of documents uniquely
// identified. For instance `{ labels: ['labelA', 'labelC', 'labelD'] }`.
+// use "subField" for searching inside object Fields.
+// For instance '{ 'customFields._id': ['field1','field2']} (subField would be: _id)
class SetFilter {
- constructor() {
+ constructor(subField = '') {
this._dep = new Tracker.Dependency();
this._selectedElements = [];
+ this.subField = subField;
}
isSelected(val) {
@@ -61,7 +63,9 @@ class SetFilter {
_getMongoSelector() {
this._dep.depend();
- return { $in: this._selectedElements };
+ return {
+ $in: this._selectedElements,
+ };
}
_getEmptySelector() {
@@ -72,10 +76,385 @@ class SetFilter {
includeEmpty = true;
}
});
- return includeEmpty ? { $eq: [] } : null;
+ return includeEmpty ? {
+ $eq: [],
+ } : null;
}
}
+
+// Advanced filter forms a MongoSelector from a users String.
+// Build by: Ignatz 19.05.2018 (github feuerball11)
+class AdvancedFilter {
+ constructor() {
+ this._dep = new Tracker.Dependency();
+ this._filter = '';
+ this._lastValide = {};
+ }
+
+ set(str) {
+ this._filter = str;
+ this._dep.changed();
+ }
+
+ reset() {
+ this._filter = '';
+ this._lastValide = {};
+ this._dep.changed();
+ }
+
+ _isActive() {
+ this._dep.depend();
+ return this._filter !== '';
+ }
+
+ _filterToCommands() {
+ const commands = [];
+ let current = '';
+ let string = false;
+ let regex = false;
+ let wasString = false;
+ let ignore = false;
+ for (let i = 0; i < this._filter.length; i++) {
+ const char = this._filter.charAt(i);
+ if (ignore) {
+ ignore = false;
+ current += char;
+ continue;
+ }
+ if (char === '/') {
+ string = !string;
+ if (string) regex = true;
+ current += char;
+ continue;
+ }
+ if (char === '\'') {
+ string = !string;
+ if (string) wasString = true;
+ continue;
+ }
+ if (char === '\\' && !string) {
+ ignore = true;
+ continue;
+ }
+ if (char === ' ' && !string) {
+ commands.push({
+ 'cmd': current,
+ 'string': wasString,
+ regex,
+ });
+ wasString = false;
+ current = '';
+ continue;
+ }
+ current += char;
+ }
+ if (current !== '') {
+ commands.push({
+ 'cmd': current,
+ 'string': wasString,
+ regex,
+ });
+ }
+ return commands;
+ }
+
+ _fieldNameToId(field) {
+ const found = CustomFields.findOne({
+ 'name': field,
+ });
+ return found._id;
+ }
+
+ _fieldValueToId(field, value) {
+ const found = CustomFields.findOne({
+ 'name': field,
+ });
+ if (found.settings.dropdownItems && found.settings.dropdownItems.length > 0) {
+ for (let i = 0; i < found.settings.dropdownItems.length; i++) {
+ if (found.settings.dropdownItems[i].name === value) {
+ return found.settings.dropdownItems[i]._id;
+ }
+ }
+ }
+ return value;
+ }
+
+ _arrayToSelector(commands) {
+ try {
+ //let changed = false;
+ this._processSubCommands(commands);
+ } catch (e) {
+ return this._lastValide;
+ }
+ this._lastValide = {
+ $or: commands,
+ };
+ return {
+ $or: commands,
+ };
+ }
+
+ _processSubCommands(commands) {
+ const subcommands = [];
+ let level = 0;
+ let start = -1;
+ for (let i = 0; i < commands.length; i++) {
+ if (commands[i].cmd) {
+ switch (commands[i].cmd) {
+ case '(':
+ {
+ level++;
+ if (start === -1) start = i;
+ continue;
+ }
+ case ')':
+ {
+ level--;
+ commands.splice(i, 1);
+ i--;
+ continue;
+ }
+ default:
+ {
+ if (level > 0) {
+ subcommands.push(commands[i]);
+ commands.splice(i, 1);
+ i--;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ if (start !== -1) {
+ this._processSubCommands(subcommands);
+ if (subcommands.length === 1)
+ commands.splice(start, 0, subcommands[0]);
+ else
+ commands.splice(start, 0, subcommands);
+ }
+ this._processConditions(commands);
+ this._processLogicalOperators(commands);
+ }
+
+ _processConditions(commands) {
+ for (let i = 0; i < commands.length; i++) {
+ if (!commands[i].string && commands[i].cmd) {
+ switch (commands[i].cmd) {
+ case '=':
+ case '==':
+ case '===':
+ {
+ const field = commands[i - 1].cmd;
+ const str = commands[i + 1].cmd;
+ if (commands[i + 1].regex) {
+ const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
+ let regex = null;
+ if (match.length > 2)
+ regex = new RegExp(match[1], match[2]);
+ else
+ regex = new RegExp(match[1]);
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': regex,
+ };
+ } else {
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $in: [this._fieldValueToId(field, str), parseInt(str, 10)],
+ },
+ };
+ }
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case '!=':
+ case '!==':
+ {
+ const field = commands[i - 1].cmd;
+ const str = commands[i + 1].cmd;
+ if (commands[i + 1].regex) {
+ const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
+ let regex = null;
+ if (match.length > 2)
+ regex = new RegExp(match[1], match[2]);
+ else
+ regex = new RegExp(match[1]);
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $not: regex,
+ },
+ };
+ } else {
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $not: {
+ $in: [this._fieldValueToId(field, str), parseInt(str, 10)],
+ },
+ },
+ };
+ }
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case '>':
+ case 'gt':
+ case 'Gt':
+ case 'GT':
+ {
+ const field = commands[i - 1].cmd;
+ const str = commands[i + 1].cmd;
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $gt: parseInt(str, 10),
+ },
+ };
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case '>=':
+ case '>==':
+ case 'gte':
+ case 'Gte':
+ case 'GTE':
+ {
+ const field = commands[i - 1].cmd;
+ const str = commands[i + 1].cmd;
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $gte: parseInt(str, 10),
+ },
+ };
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case '<':
+ case 'lt':
+ case 'Lt':
+ case 'LT':
+ {
+ const field = commands[i - 1].cmd;
+ const str = commands[i + 1].cmd;
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $lt: parseInt(str, 10),
+ },
+ };
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case '<=':
+ case '<==':
+ case 'lte':
+ case 'Lte':
+ case 'LTE':
+ {
+ const field = commands[i - 1].cmd;
+ const str = commands[i + 1].cmd;
+ commands[i] = {
+ 'customFields._id': this._fieldNameToId(field),
+ 'customFields.value': {
+ $lte: parseInt(str, 10),
+ },
+ };
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ _processLogicalOperators(commands) {
+ for (let i = 0; i < commands.length; i++) {
+ if (!commands[i].string && commands[i].cmd) {
+ switch (commands[i].cmd) {
+ case 'or':
+ case 'Or':
+ case 'OR':
+ case '|':
+ case '||':
+ {
+ const op1 = commands[i - 1];
+ const op2 = commands[i + 1];
+ commands[i] = {
+ $or: [op1, op2],
+ };
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case 'and':
+ case 'And':
+ case 'AND':
+ case '&':
+ case '&&':
+ {
+ const op1 = commands[i - 1];
+ const op2 = commands[i + 1];
+ commands[i] = {
+ $and: [op1, op2],
+ };
+ commands.splice(i - 1, 1);
+ commands.splice(i, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ case 'not':
+ case 'Not':
+ case 'NOT':
+ case '!':
+ {
+ const op1 = commands[i + 1];
+ commands[i] = {
+ $not: op1,
+ };
+ commands.splice(i + 1, 1);
+ //changed = true;
+ i--;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ _getMongoSelector() {
+ this._dep.depend();
+ const commands = this._filterToCommands();
+ return this._arrayToSelector(commands);
+ }
+
+}
+
// The global Filter object.
// XXX It would be possible to re-write this object more elegantly, and removing
// the need to provide a list of `_fields`. We also should move methods into the
@@ -86,8 +465,10 @@ Filter = {
// before changing the schema.
labelIds: new SetFilter(),
members: new SetFilter(),
+ customFields: new SetFilter('_id'),
+ advanced: new AdvancedFilter(),
- _fields: ['labelIds', 'members'],
+ _fields: ['labelIds', 'members', 'customFields'],
// We don't filter cards that have been added after the last filter change. To
// implement this we keep the id of these cards in this `_exceptions` fields
@@ -98,7 +479,7 @@ Filter = {
isActive() {
return _.any(this._fields, (fieldName) => {
return this[fieldName]._isActive();
- });
+ }) || this.advanced._isActive();
},
_getMongoSelector() {
@@ -111,7 +492,11 @@ Filter = {
this._fields.forEach((fieldName) => {
const filter = this[fieldName];
if (filter._isActive()) {
- filterSelector[fieldName] = filter._getMongoSelector();
+ if (filter.subField !== '') {
+ filterSelector[`${fieldName}.${filter.subField}`] = filter._getMongoSelector();
+ } else {
+ filterSelector[fieldName] = filter._getMongoSelector();
+ }
emptySelector[fieldName] = filter._getEmptySelector();
if (emptySelector[fieldName] !== null) {
includeEmptySelectors = true;
@@ -119,13 +504,24 @@ Filter = {
}
});
- const exceptionsSelector = {_id: {$in: this._exceptions}};
+ const exceptionsSelector = {
+ _id: {
+ $in: this._exceptions,
+ },
+ };
this._exceptionsDep.depend();
- if (includeEmptySelectors)
- return {$or: [filterSelector, exceptionsSelector, emptySelector]};
- else
- return {$or: [filterSelector, exceptionsSelector]};
+ const selectors = [exceptionsSelector];
+
+ if (_.any(this._fields, (fieldName) => {
+ return this[fieldName]._isActive();
+ })) selectors.push(filterSelector);
+ if (includeEmptySelectors) selectors.push(emptySelector);
+ if (this.advanced._isActive()) selectors.push(this.advanced._getMongoSelector());
+
+ return {
+ $or: selectors,
+ };
},
mongoSelector(additionalSelector) {
@@ -133,7 +529,9 @@ Filter = {
if (_.isUndefined(additionalSelector))
return filterSelector;
else
- return {$and: [filterSelector, additionalSelector]};
+ return {
+ $and: [filterSelector, additionalSelector],
+ };
},
reset() {
@@ -141,6 +539,7 @@ Filter = {
const filter = this[fieldName];
filter.reset();
});
+ this.advanced.reset();
this.resetExceptions();
},
diff --git a/client/lib/inlinedform.js b/client/lib/inlinedform.js
index 56768a13..e5e4d4ed 100644
--- a/client/lib/inlinedform.js
+++ b/client/lib/inlinedform.js
@@ -75,6 +75,16 @@ InlinedForm = BlazeComponent.extendComponent({
EscapeActions.register('inlinedForm',
() => { currentlyOpenedForm.get().close(); },
() => { return currentlyOpenedForm.get() !== null; }, {
- noClickEscapeOn: '.js-inlined-form',
+ enabledOnClick: false,
}
);
+
+// submit on click outside
+document.addEventListener('click', function(evt) {
+ const openedForm = currentlyOpenedForm.get();
+ const isClickOutside = $(evt.target).closest('.js-inlined-form').length === 0;
+ if (openedForm && isClickOutside) {
+ $('.js-inlined-form button[type=submit]').click();
+ openedForm.close();
+ }
+}, true);
diff --git a/client/lib/modal.js b/client/lib/modal.js
index d5350264..3c27a179 100644
--- a/client/lib/modal.js
+++ b/client/lib/modal.js
@@ -4,6 +4,7 @@ window.Modal = new class {
constructor() {
this._currentModal = new ReactiveVar(closedValue);
this._onCloseGoTo = '';
+ this._isWideModal = false;
}
getHeaderName() {
@@ -20,6 +21,10 @@ window.Modal = new class {
return this.getTemplateName() !== closedValue;
}
+ isWide(){
+ return this._isWideModal;
+ }
+
close() {
this._currentModal.set(closedValue);
if (this._onCloseGoTo) {
@@ -27,9 +32,16 @@ window.Modal = new class {
}
}
+ openWide(modalName, { header = '', onCloseGoTo = ''} = {}) {
+ this._currentModal.set({ header, modalName });
+ this._onCloseGoTo = onCloseGoTo;
+ this._isWideModal = true;
+ }
+
open(modalName, { header = '', onCloseGoTo = ''} = {}) {
this._currentModal.set({ header, modalName });
this._onCloseGoTo = onCloseGoTo;
+
}
}();
@@ -38,5 +50,5 @@ Blaze.registerHelper('Modal', Modal);
EscapeActions.register('modalWindow',
() => Modal.close(),
() => Modal.isOpen(),
- { noClickEscapeOn: '.modal-content' }
+ { noClickEscapeOn: '.modal-container' }
);
diff --git a/client/lib/popup.js b/client/lib/popup.js
index 0a700f82..9abe48aa 100644
--- a/client/lib/popup.js
+++ b/client/lib/popup.js
@@ -4,9 +4,9 @@ window.Popup = new class {
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
+ // in this `Popup.current` variable. If there is no popup currently opened
// the value is `null`.
- this._current = 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
@@ -27,11 +27,9 @@ window.Popup = new class {
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.
@@ -57,7 +55,6 @@ window.Popup = new class {
self._stack = [];
openerElement = evt.currentTarget;
}
-
$(openerElement).addClass('is-active');
evt.preventDefault();
@@ -139,6 +136,7 @@ window.Popup = new class {
const openerElement = this._getTopStack().openerElement;
$(openerElement).removeClass('is-active');
+
this._stack = [];
}
}
@@ -186,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;
};
}
@@ -200,7 +198,7 @@ escapeActions.forEach((actionName) => {
() => Popup[actionName](),
() => Popup.isOpen(),
{
- noClickEscapeOn: '.js-pop-over',
+ noClickEscapeOn: '.js-pop-over,.js-open-card-title-popup',
enabledOnClick: actionName === 'close',
}
);
diff --git a/client/lib/utils.js b/client/lib/utils.js
index 1f44c60d..e2339763 100644
--- a/client/lib/utils.js
+++ b/client/lib/utils.js
@@ -39,11 +39,11 @@ Utils = {
if (!prevData && !nextData) {
base = 0;
increment = 1;
- // If we drop the card in the first position
+ // If we drop the card in the first position
} else if (!prevData) {
base = nextData.sort - 1;
increment = -1;
- // If we drop the card in the last position
+ // If we drop the card in the last position
} else if (!nextData) {
base = prevData.sort + 1;
increment = 1;
@@ -71,11 +71,11 @@ Utils = {
if (!prevCardDomElement && !nextCardDomElement) {
base = 0;
increment = 1;
- // If we drop the card in the first position
+ // If we drop the card in the first position
} else if (!prevCardDomElement) {
base = Blaze.getData(nextCardDomElement).sort - 1;
increment = -1;
- // If we drop the card in the last position
+ // If we drop the card in the last position
} else if (!nextCardDomElement) {
base = Blaze.getData(prevCardDomElement).sort + 1;
increment = 1;
@@ -95,6 +95,151 @@ Utils = {
increment,
};
},
+
+ // Detect touch device
+ isTouchDevice() {
+ const isTouchable = (() => {
+ const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
+ const mq = function(query) {
+ return window.matchMedia(query).matches;
+ };
+
+ if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
+ return true;
+ }
+
+ // include the 'heartz' as a way to have a non matching MQ to help terminate the join
+ // https://git.io/vznFH
+ const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
+ return mq(query);
+ })();
+ Utils.isTouchDevice = () => isTouchable;
+ return isTouchable;
+ },
+
+ calculateTouchDistance(touchA, touchB) {
+ return Math.sqrt(
+ Math.pow(touchA.screenX - touchB.screenX, 2) +
+ Math.pow(touchA.screenY - touchB.screenY, 2)
+ );
+ },
+
+ enableClickOnTouch(selector) {
+ let touchStart = null;
+ let lastTouch = null;
+
+ $(document).on('touchstart', selector, function(e) {
+ touchStart = e.originalEvent.touches[0];
+ });
+ $(document).on('touchmove', selector, function(e) {
+ const touches = e.originalEvent.touches;
+ lastTouch = touches[touches.length - 1];
+ });
+ $(document).on('touchend', selector, function(e) {
+ if (touchStart && lastTouch && Utils.calculateTouchDistance(touchStart, lastTouch) <= 20) {
+ e.preventDefault();
+ const clickEvent = document.createEvent('MouseEvents');
+ clickEvent.initEvent('click', true, true);
+ e.target.dispatchEvent(clickEvent);
+ }
+ });
+ },
+
+ manageCustomUI(){
+ Meteor.call('getCustomUI', (err, data) => {
+ if (err && err.error[0] === 'var-not-exist'){
+ Session.set('customUI', false); // siteId || address server not defined
+ }
+ if (!err){
+ Utils.setCustomUI(data);
+ }
+ });
+ },
+
+ setCustomUI(data){
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ if (currentBoard) {
+ DocHead.setTitle(`${currentBoard.title } - ${ data.productName}`);
+ } else {
+ DocHead.setTitle(`${data.productName}`);
+ }
+ },
+
+ setMatomo(data){
+ window._paq = window._paq || [];
+ window._paq.push(['setDoNotTrack', data.doNotTrack]);
+ if (data.withUserName){
+ window._paq.push(['setUserId', Meteor.user().username]);
+ }
+ window._paq.push(['trackPageView']);
+ window._paq.push(['enableLinkTracking']);
+
+ (function() {
+ window._paq.push(['setTrackerUrl', `${data.address}piwik.php`]);
+ window._paq.push(['setSiteId', data.siteId]);
+
+ const script = document.createElement('script');
+ Object.assign(script, {
+ id: 'scriptMatomo',
+ type: 'text/javascript',
+ async: 'true',
+ defer: 'true',
+ src: `${data.address}piwik.js`,
+ });
+
+ const s = document.getElementsByTagName('script')[0];
+ s.parentNode.insertBefore(script, s);
+ })();
+
+ Session.set('matomo', true);
+ },
+
+ manageMatomo() {
+ const matomo = Session.get('matomo');
+ if (matomo === undefined){
+ Meteor.call('getMatomoConf', (err, data) => {
+ if (err && err.error[0] === 'var-not-exist'){
+ Session.set('matomo', false); // siteId || address server not defined
+ }
+ if (!err){
+ Utils.setMatomo(data);
+ }
+ });
+ } else if (matomo) {
+ window._paq.push(['trackPageView']);
+ }
+ },
+
+ getTriggerActionDesc(event, tempInstance) {
+ const jqueryEl = tempInstance.$(event.currentTarget.parentNode);
+ const triggerEls = jqueryEl.find('.trigger-content').children();
+ let finalString = '';
+ for (let i = 0; i < triggerEls.length; i++) {
+ const element = tempInstance.$(triggerEls[i]);
+ if (element.hasClass('trigger-text')) {
+ finalString += element.text().toLowerCase();
+ } else if (element.hasClass('user-details')) {
+ let username = element.find('input').val();
+ if(username === undefined || username === ''){
+ username = '*';
+ }
+ finalString += `${element.find('.trigger-text').text().toLowerCase() } ${ username}`;
+ } else if (element.find('select').length > 0) {
+ finalString += element.find('select option:selected').text().toLowerCase();
+ } else if (element.find('input').length > 0) {
+ let inputvalue = element.find('input').val();
+ if(inputvalue === undefined || inputvalue === ''){
+ inputvalue = '*';
+ }
+ finalString += inputvalue;
+ }
+ // Add space
+ if (i !== length - 1) {
+ finalString += ' ';
+ }
+ }
+ return finalString;
+ },
};
// A simple tracker dependency that we invalidate every time the window is