Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordizzy <diosmosis@users.noreply.github.com>2021-11-05 08:39:33 +0300
committerGitHub <noreply@github.com>2021-11-05 08:39:33 +0300
commit2b94200db7e08389466859377c1b4732207673a2 (patch)
treee2f8ed241b13b1792e4f7e18d80622c77859dea8 /plugins/CoreHome/vue
parent0917a39fc686ac2d5e349b3bcc5266598ce59ee7 (diff)
[Vue] migrate comparisons service + component (#18193)
* migrating RateFeature and ReviewLinks + adding AjaxHelper.fetch utility method (all untested) * get ratefeature component to work, modify matomodialog component to use v-model, add event parameters to createAngularAdapter, allow translate to use variadic args or one string array + rebuild * remove ratefeature angularjs files * rebuild + make vue mapping property optional in createANgularJsAdapter * migrate enrichedheadline and get to work * fix test * fix translate * fix another translate issue & migrate contentblock directive * fix anchor links, not including the "/" causes angularjs to fail (also on 4.x-dev) * update expected screenshots * fix ui test * fix some test failures * fix nested transclude issue * remove content block files * fix icon spacing that occurs due to angularjs inserting empty comments in between nodes while vue 3 does not * update some screenshots * update screenshot (actually fixes an alignment issue) * update screenshot * first pass at converting comparisons service/component * get new code to build and load without error in the UI * debugging * getting basic functionaltiy to work * fix UI test failure + URL encoding/angularjs issue causing back button to not work * using ref in setup() is not needed to access this.$refs * Convert comparisons service angularjs tests to comparison store typescript tests. * built vue files * rewrite URL handling to use computed properties in a URL store + do the same for other dependent data in the comparison store to allow vues to subscribe to the properties for changes to global state * fix some tests * some more fixes * more fixes + disallow modifications to MatomoUrl state * get angularjs unit tests to pass + fix a couple more issues * another fix * fix bad merge * self review + fixes * remove old fix as it may not be needed anymore * empty string is not a valid date + do not report invalid date exception just rethrow * update screenshots and try to fix random failure * use jquery $destroy event instead of scope one since the scope one is broadcasted * update expected screenshot
Diffstat (limited to 'plugins/CoreHome/vue')
-rw-r--r--plugins/CoreHome/vue/dist/CoreHome.umd.js1577
-rw-r--r--plugins/CoreHome/vue/dist/CoreHome.umd.min.js56
-rw-r--r--plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts80
-rw-r--r--plugins/CoreHome/vue/src/Comparisons/Comparisons.adapter.ts24
-rw-r--r--plugins/CoreHome/vue/src/Comparisons/Comparisons.less78
-rw-r--r--plugins/CoreHome/vue/src/Comparisons/Comparisons.store.instance.ts3
-rw-r--r--plugins/CoreHome/vue/src/Comparisons/Comparisons.store.spec.ts457
-rw-r--r--plugins/CoreHome/vue/src/Comparisons/Comparisons.store.ts411
-rw-r--r--plugins/CoreHome/vue/src/Comparisons/Comparisons.vue264
-rw-r--r--plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue11
-rw-r--r--plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue8
-rw-r--r--plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts19
-rw-r--r--plugins/CoreHome/vue/src/Matomo/Matomo.ts77
-rw-r--r--plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue9
-rw-r--r--plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.spec.ts (renamed from plugins/CoreHome/vue/src/Matomo/Matomo.spec.ts)11
-rw-r--r--plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts116
-rw-r--r--plugins/CoreHome/vue/src/Periods/Periods.adapter.ts2
-rw-r--r--plugins/CoreHome/vue/src/Periods/utilities.ts13
-rw-r--r--plugins/CoreHome/vue/src/Piwik/Piwik.adapter.ts22
-rw-r--r--plugins/CoreHome/vue/src/Piwik/Piwik.spec.ts152
-rw-r--r--plugins/CoreHome/vue/src/Piwik/Piwik.ts78
-rw-r--r--plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.adapter.ts19
-rw-r--r--plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.ts32
-rw-r--r--plugins/CoreHome/vue/src/Segmentation/Segments.store.ts43
-rw-r--r--plugins/CoreHome/vue/src/createAngularJsAdapter.ts4
-rw-r--r--plugins/CoreHome/vue/src/index.ts6
26 files changed, 2610 insertions, 962 deletions
diff --git a/plugins/CoreHome/vue/dist/CoreHome.umd.js b/plugins/CoreHome/vue/dist/CoreHome.umd.js
index b7c0b0f0db..6dc2a61e5d 100644
--- a/plugins/CoreHome/vue/dist/CoreHome.umd.js
+++ b/plugins/CoreHome/vue/dist/CoreHome.umd.js
@@ -134,7 +134,7 @@ __webpack_require__.d(__webpack_exports__, "ActivityIndicator", function() { ret
__webpack_require__.d(__webpack_exports__, "translate", function() { return /* reexport */ translate; });
__webpack_require__.d(__webpack_exports__, "alertAdapter", function() { return /* reexport */ Alert_adapter; });
__webpack_require__.d(__webpack_exports__, "AjaxHelper", function() { return /* reexport */ AjaxHelper_AjaxHelper; });
-__webpack_require__.d(__webpack_exports__, "MatomoUrl", function() { return /* reexport */ MatomoUrl_MatomoUrl; });
+__webpack_require__.d(__webpack_exports__, "MatomoUrl", function() { return /* reexport */ src_MatomoUrl_MatomoUrl; });
__webpack_require__.d(__webpack_exports__, "Matomo", function() { return /* reexport */ Matomo_Matomo; });
__webpack_require__.d(__webpack_exports__, "Periods", function() { return /* reexport */ Periods_Periods; });
__webpack_require__.d(__webpack_exports__, "Day", function() { return /* reexport */ Day_DayPeriod; });
@@ -149,6 +149,7 @@ __webpack_require__.d(__webpack_exports__, "todayIsInRange", function() { return
__webpack_require__.d(__webpack_exports__, "MatomoDialog", function() { return /* reexport */ MatomoDialog; });
__webpack_require__.d(__webpack_exports__, "EnrichedHeadline", function() { return /* reexport */ EnrichedHeadline; });
__webpack_require__.d(__webpack_exports__, "ContentBlock", function() { return /* reexport */ ContentBlock; });
+__webpack_require__.d(__webpack_exports__, "Comparisons", function() { return /* reexport */ Comparisons; });
// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js
// This file is imported into lib/wc client bundles.
@@ -166,54 +167,12 @@ if (typeof window !== 'undefined') {
// Indicate to webpack that this file can be concatenated
/* harmony default export */ var setPublicPath = (null);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-/**
- * Similar to angulars $location but works around some limitation. Use it if you need to access
- * search params
- */
-const MatomoUrl = {
- getSearchParam(paramName) {
- const hash = window.location.href.split('#');
- const regex = new RegExp(`${paramName}(\\[]|=)`);
-
- if (hash && hash[1] && regex.test(decodeURIComponent(hash[1]))) {
- const valueFromHash = window.broadcast.getValueFromHash(paramName, window.location.href); // for date, period and idsite fall back to parameter from url, if non in hash was provided
-
- if (valueFromHash || paramName !== 'date' && paramName !== 'period' && paramName !== 'idSite') {
- return valueFromHash;
- }
- }
-
- return window.broadcast.getValueFromUrl(paramName, window.location.search);
- }
-
-};
-/* harmony default export */ var MatomoUrl_MatomoUrl = (MatomoUrl);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.adapter.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
+// EXTERNAL MODULE: ./plugins/CoreHome/vue/src/noAdblockFlag.ts
+var noAdblockFlag = __webpack_require__("2342");
-function piwikUrl() {
- const model = {
- getSearchParam: MatomoUrl_MatomoUrl.getSearchParam.bind(MatomoUrl_MatomoUrl)
- };
- return model;
-}
+// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"}
+var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__("8bbf");
-piwikUrl.$inject = [];
-angular.module('piwikApp.service').service('piwikUrl', piwikUrl);
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/Periods.ts
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -301,6 +260,91 @@ class Periods {
}
/* harmony default export */ var Periods_Periods = (new Periods());
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Matomo/Matomo.ts
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+let originalTitle;
+const {
+ piwik: Matomo_piwik,
+ broadcast: Matomo_broadcast,
+ piwikHelper: Matomo_piwikHelper
+} = window;
+Matomo_piwik.helper = Matomo_piwikHelper;
+Matomo_piwik.broadcast = Matomo_broadcast;
+
+Matomo_piwik.updateDateInTitle = function updateDateInTitle(date, period) {
+ if (!$('.top_controls #periodString').length) {
+ return;
+ } // Cache server-rendered page title
+
+
+ originalTitle = originalTitle || document.title;
+
+ if (originalTitle.indexOf(Matomo_piwik.siteName) === 0) {
+ const dateString = ` - ${Periods_Periods.parse(period, date).getPrettyString()} `;
+ document.title = `${Matomo_piwik.siteName}${dateString}${originalTitle.substr(Matomo_piwik.siteName.length)}`;
+ }
+};
+
+Matomo_piwik.hasUserCapability = function hasUserCapability(capability) {
+ return window.angular.isArray(Matomo_piwik.userCapabilities) && Matomo_piwik.userCapabilities.indexOf(capability) !== -1;
+};
+
+Matomo_piwik.on = function addMatomoEventListener(eventName, listener) {
+ function listenerWrapper(evt) {
+ listener(...evt.detail); // eslint-disable-line
+ }
+
+ listener.wrapper = listenerWrapper;
+ window.addEventListener(eventName, listenerWrapper);
+};
+
+Matomo_piwik.off = function removeMatomoEventListener(eventName, listener) {
+ if (listener.wrapper) {
+ window.removeEventListener(eventName, listener.wrapper);
+ }
+};
+
+Matomo_piwik.postEventNoEmit = function postEventNoEmit(eventName, ...args // eslint-disable-line
+) {
+ const event = new CustomEvent(eventName, {
+ detail: args
+ });
+ window.dispatchEvent(event);
+};
+
+Matomo_piwik.postEvent = function postMatomoEvent(eventName, ...args // eslint-disable-line
+) {
+ Matomo_piwik.postEventNoEmit(eventName, ...args); // required until angularjs is removed
+
+ const $rootScope = Matomo_piwik.helper.getAngularDependency('$rootScope'); // eslint-disable-line
+
+ return $rootScope.$oldEmit(eventName, ...args);
+};
+
+const Matomo = Matomo_piwik;
+/* harmony default export */ var Matomo_Matomo = (Matomo);
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/translate.ts
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+function translate(translationStringId, ...values) {
+ let pkArgs = values; // handle variadic args AND single array of values (to match _pk_translate signature)
+
+ if (values.length === 1 && values[0] && values[0] instanceof Array) {
+ [pkArgs] = values;
+ }
+
+ return window._pk_translate(translationStringId, pkArgs); // eslint-disable-line
+}
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/utilities.ts
/*!
* Matomo - free/libre analytics platform
@@ -329,7 +373,11 @@ function parseDate(date) {
return date;
}
- const strDate = decodeURIComponent(date);
+ const strDate = decodeURIComponent(date).trim();
+
+ if (strDate === '') {
+ throw new Error('Invalid date, empty string.');
+ }
if (strDate === 'today' || strDate === 'now') {
return getToday();
@@ -361,13 +409,7 @@ function parseDate(date) {
return lastYear;
}
- try {
- return $.datepicker.parseDate('yy-mm-dd', strDate);
- } catch (err) {
- // angular swallows this error, so manual console log here
- console.error(err.message || err);
- throw err;
- }
+ return $.datepicker.parseDate('yy-mm-dd', strDate);
}
function todayIsInRange(dateRange) {
if (dateRange.length !== 2) {
@@ -380,7 +422,9 @@ function todayIsInRange(dateRange) {
return false;
}
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Matomo/Matomo.ts
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/Range.ts
+function Range_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
/*!
* Matomo - free/libre analytics platform
*
@@ -390,112 +434,204 @@ function todayIsInRange(dateRange) {
-let originalTitle;
-const {
- piwik,
- broadcast: Matomo_broadcast,
- piwikHelper: Matomo_piwikHelper
-} = window;
-piwik.helper = Matomo_piwikHelper;
-piwik.broadcast = Matomo_broadcast;
+class Range_RangePeriod {
+ constructor(startDate, endDate, childPeriodType) {
+ Range_defineProperty(this, "startDate", void 0);
-function isValidPeriod(periodStr, dateStr) {
- try {
- Periods_Periods.parse(periodStr, dateStr);
- return true;
- } catch (e) {
- return false;
- }
-}
+ Range_defineProperty(this, "endDate", void 0);
-piwik.updatePeriodParamsFromUrl = function updatePeriodParamsFromUrl() {
- let date = MatomoUrl_MatomoUrl.getSearchParam('date');
- const period = MatomoUrl_MatomoUrl.getSearchParam('period');
+ Range_defineProperty(this, "childPeriodType", void 0);
- if (!isValidPeriod(period, date)) {
- // invalid data in URL
- return;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ this.childPeriodType = childPeriodType;
}
+ /**
+ * Returns a range representing the last N childPeriodType periods, including the current one.
+ */
- if (piwik.period === period && piwik.currentDateString === date) {
- // this period / date is already loaded
- return;
- }
- piwik.period = period;
- const dateRange = Periods_Periods.parse(period, date).getDateRange();
- piwik.startDateString = format(dateRange[0]);
- piwik.endDateString = format(dateRange[1]);
- piwik.updateDateInTitle(date, period); // do not set anything to previousN/lastN, as it's more useful to plugins
- // to have the dates than previousN/lastN.
+ static getLastNRange(childPeriodType, strAmount, strEndDate) {
+ const nAmount = Math.max(parseInt(strAmount.toString(), 10) - 1, 0);
+
+ if (Number.isNaN(nAmount)) {
+ throw new Error('Invalid range strAmount');
+ }
+
+ let endDate = strEndDate ? parseDate(strEndDate) : getToday();
+ let startDate = new Date(endDate.getTime());
+
+ if (childPeriodType === 'day') {
+ startDate.setDate(startDate.getDate() - nAmount);
+ } else if (childPeriodType === 'week') {
+ startDate.setDate(startDate.getDate() - nAmount * 7);
+ } else if (childPeriodType === 'month') {
+ startDate.setDate(1);
+ startDate.setMonth(startDate.getMonth() - nAmount);
+ } else if (childPeriodType === 'year') {
+ startDate.setFullYear(startDate.getFullYear() - nAmount);
+ } else {
+ throw new Error(`Unknown period type '${childPeriodType}'.`);
+ }
+
+ if (childPeriodType !== 'day') {
+ const startPeriod = Periods_Periods.periods[childPeriodType].parse(startDate);
+ const endPeriod = Periods_Periods.periods[childPeriodType].parse(endDate);
+ [startDate] = startPeriod.getDateRange();
+ [, endDate] = endPeriod.getDateRange();
+ }
+
+ const firstWebsiteDate = new Date(1991, 7, 6);
+
+ if (startDate.getTime() - firstWebsiteDate.getTime() < 0) {
+ switch (childPeriodType) {
+ case 'year':
+ startDate = new Date(1992, 0, 1);
+ break;
+
+ case 'month':
+ startDate = new Date(1991, 8, 1);
+ break;
- if (piwik.period === 'range') {
- date = `${piwik.startDateString},${piwik.endDateString}`;
+ case 'week':
+ startDate = new Date(1991, 8, 12);
+ break;
+
+ case 'day':
+ default:
+ startDate = firstWebsiteDate;
+ break;
+ }
+ }
+
+ return new Range_RangePeriod(startDate, endDate, childPeriodType);
}
+ /**
+ * Returns a range representing a specific child date range counted back from the end date
+ *
+ * @param childPeriodType Type of the period, eg. day, week, year
+ * @param rangeEndDate
+ * @param countBack Return only the child date range for this specific period number
+ * @returns {RangePeriod}
+ */
- piwik.currentDateString = date;
-};
-piwik.updateDateInTitle = function updateDateInTitle(date, period) {
- if (!$('.top_controls #periodString').length) {
- return;
- } // Cache server-rendered page title
+ static getLastNRangeChild(childPeriodType, rangeEndDate, countBack) {
+ const ed = rangeEndDate ? parseDate(rangeEndDate) : getToday();
+ let startDate = new Date(ed.getTime());
+ let endDate = new Date(ed.getTime());
+ if (childPeriodType === 'day') {
+ startDate.setDate(startDate.getDate() - countBack);
+ endDate.setDate(endDate.getDate() - countBack);
+ } else if (childPeriodType === 'week') {
+ startDate.setDate(startDate.getDate() - countBack * 7);
+ endDate.setDate(endDate.getDate() - countBack * 7);
+ } else if (childPeriodType === 'month') {
+ startDate.setDate(1);
+ startDate.setMonth(startDate.getMonth() - countBack);
+ endDate.setDate(1);
+ endDate.setMonth(endDate.getMonth() - countBack);
+ } else if (childPeriodType === 'year') {
+ startDate.setFullYear(startDate.getFullYear() - countBack);
+ endDate.setFullYear(endDate.getFullYear() - countBack);
+ } else {
+ throw new Error(`Unknown period type '${childPeriodType}'.`);
+ }
- originalTitle = originalTitle || document.title;
+ if (childPeriodType !== 'day') {
+ const startPeriod = Periods_Periods.periods[childPeriodType].parse(startDate);
+ const endPeriod = Periods_Periods.periods[childPeriodType].parse(endDate);
+ [startDate] = startPeriod.getDateRange();
+ [, endDate] = endPeriod.getDateRange();
+ }
- if (originalTitle.indexOf(piwik.siteName) === 0) {
- const dateString = ` - ${Periods_Periods.parse(period, date).getPrettyString()} `;
- document.title = `${piwik.siteName}${dateString}${originalTitle.substr(piwik.siteName.length)}`;
+ const firstWebsiteDate = new Date(1991, 7, 6);
+
+ if (startDate.getTime() - firstWebsiteDate.getTime() < 0) {
+ switch (childPeriodType) {
+ case 'year':
+ startDate = new Date(1992, 0, 1);
+ break;
+
+ case 'month':
+ startDate = new Date(1991, 8, 1);
+ break;
+
+ case 'week':
+ startDate = new Date(1991, 8, 12);
+ break;
+
+ case 'day':
+ default:
+ startDate = firstWebsiteDate;
+ break;
+ }
+ }
+
+ return new Range_RangePeriod(startDate, endDate, childPeriodType);
}
-};
-piwik.hasUserCapability = function hasUserCapability(capability) {
- return window.angular.isArray(piwik.userCapabilities) && piwik.userCapabilities.indexOf(capability) !== -1;
-};
+ static parse(strDate, childPeriodType = 'day') {
+ if (/^previous/.test(strDate)) {
+ const endDate = Range_RangePeriod.getLastNRange(childPeriodType, '2').startDate;
+ return Range_RangePeriod.getLastNRange(childPeriodType, strDate.substring(8), endDate);
+ }
-const Matomo = piwik;
-/* harmony default export */ var Matomo_Matomo = (Matomo);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
+ if (/^last/.test(strDate)) {
+ return Range_RangePeriod.getLastNRange(childPeriodType, strDate.substring(4));
+ }
+ const parts = decodeURIComponent(strDate).split(',');
+ return new Range_RangePeriod(parseDate(parts[0]), parseDate(parts[1]), childPeriodType);
+ }
-function piwikService() {
- return Matomo_Matomo;
-}
+ static getDisplayText() {
+ return translate('General_DateRangeInPeriodList');
+ }
-angular.module('piwikApp.service').service('piwik', piwikService);
+ getPrettyString() {
+ const start = format(this.startDate);
+ const end = format(this.endDate);
+ return translate('General_DateRangeFromTo', [start, end]);
+ }
-function initPiwikService(piwik, $rootScope) {
- $rootScope.$on('$locationChangeSuccess', piwik.updatePeriodParamsFromUrl);
-}
+ getDateRange() {
+ return [this.startDate, this.endDate];
+ }
-initPiwikService.$inject = ['piwik', '$rootScope'];
-angular.module('piwikApp.service').run(initPiwikService);
-// EXTERNAL MODULE: ./plugins/CoreHome/vue/src/noAdblockFlag.ts
-var noAdblockFlag = __webpack_require__("2342");
+ containsToday() {
+ return todayIsInRange(this.getDateRange());
+ }
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/translate.ts
+}
+Periods_Periods.addCustomPeriod('range', Range_RangePeriod);
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/Periods.adapter.ts
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-function translate(translationStringId, ...values) {
- let pkArgs = values; // handle variadic args AND single array of values (to match _pk_translate signature)
- if (values.length === 1 && values[0] && values[0] instanceof Array) {
- [pkArgs] = values;
- }
- return window._pk_translate(translationStringId, pkArgs); // eslint-disable-line
+
+window.piwik.addCustomPeriod = Periods_Periods.addCustomPeriod.bind(Periods_Periods);
+
+function piwikPeriods() {
+ return {
+ getAllLabels: Periods_Periods.getAllLabels.bind(Periods_Periods),
+ isRecognizedPeriod: Periods_Periods.isRecognizedPeriod.bind(Periods_Periods),
+ get: Periods_Periods.get.bind(Periods_Periods),
+ parse: Periods_Periods.parse.bind(Periods_Periods),
+ parseDate: parseDate,
+ format: format,
+ RangePeriod: Range_RangePeriod,
+ todayIsInRange: todayIsInRange
+ };
}
+
+window.angular.module('piwikApp.service').factory('piwikPeriods', piwikPeriods);
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/Day.ts
function Day_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -681,9 +817,7 @@ class Year_YearPeriod {
}
Periods_Periods.addCustomPeriod('year', Year_YearPeriod);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/Range.ts
-function Range_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/index.ts
/*!
* Matomo - free/libre analytics platform
*
@@ -693,179 +827,137 @@ function Range_defineProperty(obj, key, value) { if (key in obj) { Object.define
-class Range_RangePeriod {
- constructor(startDate, endDate, childPeriodType) {
- Range_defineProperty(this, "startDate", void 0);
-
- Range_defineProperty(this, "endDate", void 0);
-
- Range_defineProperty(this, "childPeriodType", void 0);
- this.startDate = startDate;
- this.endDate = endDate;
- this.childPeriodType = childPeriodType;
- }
- /**
- * Returns a range representing the last N childPeriodType periods, including the current one.
- */
- static getLastNRange(childPeriodType, strAmount, strEndDate) {
- const nAmount = Math.max(parseInt(strAmount.toString(), 10) - 1, 0);
- if (Number.isNaN(nAmount)) {
- throw new Error('Invalid range strAmount');
- }
- let endDate = strEndDate ? parseDate(strEndDate) : getToday();
- let startDate = new Date(endDate.getTime());
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts
+function MatomoUrl_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
- if (childPeriodType === 'day') {
- startDate.setDate(startDate.getDate() - nAmount);
- } else if (childPeriodType === 'week') {
- startDate.setDate(startDate.getDate() - nAmount * 7);
- } else if (childPeriodType === 'month') {
- startDate.setDate(1);
- startDate.setMonth(startDate.getMonth() - nAmount);
- } else if (childPeriodType === 'year') {
- startDate.setFullYear(startDate.getFullYear() - nAmount);
- } else {
- throw new Error(`Unknown period type '${childPeriodType}'.`);
- }
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
- if (childPeriodType !== 'day') {
- const startPeriod = Periods_Periods.periods[childPeriodType].parse(startDate);
- const endPeriod = Periods_Periods.periods[childPeriodType].parse(endDate);
- [startDate] = startPeriod.getDateRange();
- [, endDate] = endPeriod.getDateRange();
- }
- const firstWebsiteDate = new Date(1991, 7, 6);
+ // important to load all periods here
- if (startDate.getTime() - firstWebsiteDate.getTime() < 0) {
- switch (childPeriodType) {
- case 'year':
- startDate = new Date(1992, 0, 1);
- break;
+const {
+ piwik: MatomoUrl_piwik,
+ broadcast: MatomoUrl_broadcast
+} = window;
- case 'month':
- startDate = new Date(1991, 8, 1);
- break;
+function isValidPeriod(periodStr, dateStr) {
+ try {
+ Periods_Periods.parse(periodStr, dateStr);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+/**
+ * URL store and helper functions.
+ */
- case 'week':
- startDate = new Date(1991, 8, 12);
- break;
- case 'day':
- default:
- startDate = firstWebsiteDate;
- break;
- }
- }
+class MatomoUrl_MatomoUrl {
+ constructor() {
+ MatomoUrl_defineProperty(this, "urlQuery", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(''));
- return new Range_RangePeriod(startDate, endDate, childPeriodType);
- }
- /**
- * Returns a range representing a specific child date range counted back from the end date
- *
- * @param childPeriodType Type of the period, eg. day, week, year
- * @param rangeEndDate
- * @param countBack Return only the child date range for this specific period number
- * @returns {RangePeriod}
- */
+ MatomoUrl_defineProperty(this, "hashQuery", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(''));
+ MatomoUrl_defineProperty(this, "urlParsed", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])(MatomoUrl_broadcast.getValuesFromUrl(`?${this.urlQuery.value}`, true))));
- static getLastNRangeChild(childPeriodType, rangeEndDate, countBack) {
- const ed = rangeEndDate ? parseDate(rangeEndDate) : getToday();
- let startDate = new Date(ed.getTime());
- let endDate = new Date(ed.getTime());
+ MatomoUrl_defineProperty(this, "hashParsed", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])(MatomoUrl_broadcast.getValuesFromUrl(`?${this.hashQuery.value}`, true))));
- if (childPeriodType === 'day') {
- startDate.setDate(startDate.getDate() - countBack);
- endDate.setDate(endDate.getDate() - countBack);
- } else if (childPeriodType === 'week') {
- startDate.setDate(startDate.getDate() - countBack * 7);
- endDate.setDate(endDate.getDate() - countBack * 7);
- } else if (childPeriodType === 'month') {
- startDate.setDate(1);
- startDate.setMonth(startDate.getMonth() - countBack);
- endDate.setDate(1);
- endDate.setMonth(endDate.getMonth() - countBack);
- } else if (childPeriodType === 'year') {
- startDate.setFullYear(startDate.getFullYear() - countBack);
- endDate.setFullYear(endDate.getFullYear() - countBack);
- } else {
- throw new Error(`Unknown period type '${childPeriodType}'.`);
- }
+ MatomoUrl_defineProperty(this, "parsed", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])({ ...this.urlParsed.value,
+ ...this.hashParsed.value
+ })));
- if (childPeriodType !== 'day') {
- const startPeriod = Periods_Periods.periods[childPeriodType].parse(startDate);
- const endPeriod = Periods_Periods.periods[childPeriodType].parse(endDate);
- [startDate] = startPeriod.getDateRange();
- [, endDate] = endPeriod.getDateRange();
- }
+ this.setUrlQuery(window.location.search);
+ this.setHashQuery(window.location.hash); // $locationChangeSuccess is triggered before angularjs changes actual window the hash, so we
+ // have to hook into this method if we want our event handlers to execute before other angularjs
+ // handlers (like the reporting page one)
- const firstWebsiteDate = new Date(1991, 7, 6);
+ Matomo_Matomo.on('$locationChangeSuccess', absUrl => {
+ const url = new URL(absUrl);
+ this.setUrlQuery(url.search.replace(/^\?/, ''));
+ this.setHashQuery(url.hash.replace(/^#/, ''));
+ });
+ this.updatePeriodParamsFromUrl();
+ }
- if (startDate.getTime() - firstWebsiteDate.getTime() < 0) {
- switch (childPeriodType) {
- case 'year':
- startDate = new Date(1992, 0, 1);
- break;
+ updateHash(params) {
+ const serializedParams = typeof params !== 'string' ? this.stringify(params) : params;
+ const $location = Matomo_Matomo.helper.getAngularDependency('$location');
+ $location.search(serializedParams);
+ }
- case 'month':
- startDate = new Date(1991, 8, 1);
- break;
+ getSearchParam(paramName) {
+ const hash = window.location.href.split('#');
+ const regex = new RegExp(`${paramName}(\\[]|=)`);
- case 'week':
- startDate = new Date(1991, 8, 12);
- break;
+ if (hash && hash[1] && regex.test(decodeURIComponent(hash[1]))) {
+ const valueFromHash = window.broadcast.getValueFromHash(paramName, window.location.href); // for date, period and idsite fall back to parameter from url, if non in hash was provided
- case 'day':
- default:
- startDate = firstWebsiteDate;
- break;
+ if (valueFromHash || paramName !== 'date' && paramName !== 'period' && paramName !== 'idSite') {
+ return valueFromHash;
}
}
- return new Range_RangePeriod(startDate, endDate, childPeriodType);
+ return window.broadcast.getValueFromUrl(paramName, window.location.search);
}
- static parse(strDate, childPeriodType = 'day') {
- if (/^previous/.test(strDate)) {
- const endDate = Range_RangePeriod.getLastNRange(childPeriodType, '2').startDate;
- return Range_RangePeriod.getLastNRange(childPeriodType, strDate.substring(8), endDate);
+ stringify(search) {
+ // TODO: using $ since URLSearchParams does not handle array params the way Matomo uses them
+ return $.param(search).replace(/%5B%5D/g, '[]');
+ }
+
+ updatePeriodParamsFromUrl() {
+ let date = this.getSearchParam('date');
+ const period = this.getSearchParam('period');
+
+ if (!isValidPeriod(period, date)) {
+ // invalid data in URL
+ return;
}
- if (/^last/.test(strDate)) {
- return Range_RangePeriod.getLastNRange(childPeriodType, strDate.substring(4));
+ if (MatomoUrl_piwik.period === period && MatomoUrl_piwik.currentDateString === date) {
+ // this period / date is already loaded
+ return;
}
- const parts = decodeURIComponent(strDate).split(',');
- return new Range_RangePeriod(parseDate(parts[0]), parseDate(parts[1]), childPeriodType);
- }
+ MatomoUrl_piwik.period = period;
+ const dateRange = Periods_Periods.parse(period, date).getDateRange();
+ MatomoUrl_piwik.startDateString = format(dateRange[0]);
+ MatomoUrl_piwik.endDateString = format(dateRange[1]);
+ MatomoUrl_piwik.updateDateInTitle(date, period); // do not set anything to previousN/lastN, as it's more useful to plugins
+ // to have the dates than previousN/lastN.
- static getDisplayText() {
- return translate('General_DateRangeInPeriodList');
- }
+ if (MatomoUrl_piwik.period === 'range') {
+ date = `${MatomoUrl_piwik.startDateString},${MatomoUrl_piwik.endDateString}`;
+ }
- getPrettyString() {
- const start = format(this.startDate);
- const end = format(this.endDate);
- return translate('General_DateRangeFromTo', [start, end]);
+ MatomoUrl_piwik.currentDateString = date;
}
- getDateRange() {
- return [this.startDate, this.endDate];
+ setUrlQuery(search) {
+ this.urlQuery.value = search.replace(/^\?/, '');
}
- containsToday() {
- return todayIsInRange(this.getDateRange());
+ setHashQuery(hash) {
+ this.hashQuery.value = hash.replace(/^[#/?]+/, '');
}
}
-Periods_Periods.addCustomPeriod('range', Range_RangePeriod);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/Periods.adapter.ts
+
+const instance = new MatomoUrl_MatomoUrl();
+/* harmony default export */ var src_MatomoUrl_MatomoUrl = (instance);
+MatomoUrl_piwik.updatePeriodParamsFromUrl = instance.updatePeriodParamsFromUrl.bind(instance);
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.adapter.ts
/*!
* Matomo - free/libre analytics platform
*
@@ -874,23 +966,50 @@ Periods_Periods.addCustomPeriod('range', Range_RangePeriod);
*/
+function piwikUrl() {
+ const model = {
+ getSearchParam: src_MatomoUrl_MatomoUrl.getSearchParam.bind(src_MatomoUrl_MatomoUrl)
+ };
+ return model;
+}
-window.piwik.addCustomPeriod = Periods_Periods.addCustomPeriod.bind(Periods_Periods);
+piwikUrl.$inject = [];
+angular.module('piwikApp.service').service('piwikUrl', piwikUrl);
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
-function piwikPeriods() {
- return {
- getAllLabels: Periods_Periods.getAllLabels.bind(Periods_Periods),
- isRecognizedPeriod: Periods_Periods.isRecognizedPeriod.bind(Periods_Periods),
- get: Periods_Periods.get.bind(Periods_Periods),
- parse: Periods_Periods.parse.bind(Periods_Periods),
- parseDate: parseDate,
- format: format,
- RangePeriod: Range_RangePeriod,
- todayIsInRange: todayIsInRange
+
+function piwikService() {
+ return Matomo_Matomo;
+}
+
+window.angular.module('piwikApp.service').service('piwik', piwikService);
+
+function initPiwikService(piwik, $rootScope) {
+ // overwrite $rootScope so all events also go through Matomo.postEvent(...) too.
+ $rootScope.$oldEmit = $rootScope.$emit; // eslint-disable-line
+
+ $rootScope.$emit = function emitWrapper(name, ...args) {
+ return Matomo_Matomo.postEvent(name, ...args);
+ };
+
+ $rootScope.$oldBroadcast = $rootScope.$broadcast; // eslint-disable-line
+
+ $rootScope.$broadcast = function broadcastWrapper(name, ...args) {
+ Matomo_Matomo.postEventNoEmit(name, ...args);
+ return $rootScope.$oldBroadcast(name, ...args); // eslint-disable-line
};
+
+ $rootScope.$on('$locationChangeSuccess', piwik.updatePeriodParamsFromUrl);
}
-angular.module('piwikApp.service').factory('piwikPeriods', piwikPeriods);
+initPiwikService.$inject = ['piwik', '$rootScope'];
+window.angular.module('piwikApp.service').run(initPiwikService);
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts
function AjaxHelper_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -939,6 +1058,12 @@ function defaultErrorCallback(deferred, status) {
return;
}
+ if (typeof Piwik_Popover === 'undefined') {
+ console.log(`Request failed: ${deferred.responseText}`); // mostly for tests
+
+ return;
+ }
+
const loadingError = $('#loadingError');
if (Piwik_Popover.isOpen() && deferred && deferred.status === 500) {
@@ -1062,18 +1187,14 @@ class AjaxHelper_AjaxHelper {
* Adds params to the request.
* If params are given more then once, the latest given value is used for the request
*
- * @param params
+ * @param initialParams
* @param type type of given parameters (POST or GET)
* @return {void}
*/
- addParams(params, type) {
- if (typeof params === 'string') {
- // TODO: add global types for broadcast (multiple uses below)
- params = window['broadcast'].getValuesFromUrl(params); // eslint-disable-line
- }
-
+ addParams(initialParams, type) {
+ const params = typeof initialParams === 'string' ? window.broadcast.getValuesFromUrl(initialParams) : initialParams;
const arrayParams = ['compareSegments', 'comparePeriods', 'compareDates'];
Object.keys(params).forEach(key => {
const value = params[key];
@@ -1108,7 +1229,7 @@ class AjaxHelper_AjaxHelper {
setBulkRequests(...urls) {
- const urlsProcessed = urls.map(u => $.param(u));
+ const urlsProcessed = urls.map(u => typeof u === 'string' ? u : $.param(u));
this.addParams({
module: 'API',
method: 'API.getBulkRequest',
@@ -1261,8 +1382,15 @@ class AjaxHelper_AjaxHelper {
}
this.requestHandle = this.buildAjaxCall();
- globalAjaxQueue.push(this.requestHandle);
- return this.requestHandle;
+ window.globalAjaxQueue.push(this.requestHandle);
+ return new Promise((resolve, reject) => {
+ this.requestHandle.then(resolve).fail(xhr => {
+ if (xhr.statusText !== 'abort') {
+ console.log(`Warning: the ${$.param(this.getParams)} request failed!`);
+ reject(xhr);
+ }
+ });
+ });
}
/**
* Aborts the current request if it is (still) running
@@ -1308,11 +1436,11 @@ class AjaxHelper_AjaxHelper {
url,
dataType: this.format || 'json',
complete: this.completeCallback,
- error: function errorCallback() {
- globalAjaxQueue.active -= 1;
+ error: function errorCallback(...args) {
+ window.globalAjaxQueue.active -= 1;
if (self.errorCallback) {
- self.errorCallback.apply(this, arguments); // eslint-disable-line
+ self.errorCallback.apply(this, args);
}
},
success: (response, status, request) => {
@@ -1346,7 +1474,7 @@ class AjaxHelper_AjaxHelper {
this.callback(response, status, request);
}
- globalAjaxQueue.active -= 1;
+ window.globalAjaxQueue.active -= 1;
if (Matomo_Matomo.ajaxRequestFinished) {
Matomo_Matomo.ajaxRequestFinished();
@@ -1400,9 +1528,9 @@ class AjaxHelper_AjaxHelper {
mixinDefaultGetParams(originalParams) {
- const segment = MatomoUrl_MatomoUrl.getSearchParam('segment');
+ const segment = src_MatomoUrl_MatomoUrl.getSearchParam('segment');
const defaultParams = {
- idSite: Matomo_Matomo.idSite || broadcast.getValueFromUrl('idSite'),
+ idSite: Matomo_Matomo.idSite ? Matomo_Matomo.idSite.toString() : broadcast.getValueFromUrl('idSite'),
period: Matomo_Matomo.period || broadcast.getValueFromUrl('period'),
segment
};
@@ -1436,155 +1564,7 @@ function ajaxQueue() {
}
angular.module('piwikApp.service').service('globalAjaxQueue', ajaxQueue);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-/**
- * Similar to angulars $location but works around some limitation. Use it if you need to access
- * search params
- */
-const PiwikUrl = {
- getSearchParam(paramName) {
- const hash = window.location.href.split('#');
- const regex = new RegExp(`${paramName}(\\[]|=)`);
-
- if (hash && hash[1] && regex.test(decodeURIComponent(hash[1]))) {
- const valueFromHash = window.broadcast.getValueFromHash(paramName, window.location.href); // for date, period and idsite fall back to parameter from url, if non in hash was provided
-
- if (valueFromHash || paramName !== 'date' && paramName !== 'period' && paramName !== 'idSite') {
- return valueFromHash;
- }
- }
-
- return window.broadcast.getValueFromUrl(paramName, window.location.search);
- }
-
-};
-/* harmony default export */ var PiwikUrl_PiwikUrl = (PiwikUrl);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.adapter.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-
-function PiwikUrl_adapter_piwikUrl() {
- const model = {
- getSearchParam: PiwikUrl_PiwikUrl.getSearchParam.bind(PiwikUrl_PiwikUrl)
- };
- return model;
-}
-
-PiwikUrl_adapter_piwikUrl.$inject = [];
-angular.module('piwikApp.service').service('piwikUrl', PiwikUrl_adapter_piwikUrl);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Piwik/Piwik.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-
-
-let Piwik_originalTitle;
-const {
- piwik: Piwik_piwik,
- broadcast: Piwik_broadcast,
- piwikHelper: Piwik_piwikHelper
-} = window;
-Piwik_piwik.helper = Piwik_piwikHelper;
-Piwik_piwik.broadcast = Piwik_broadcast;
-
-function Piwik_isValidPeriod(periodStr, dateStr) {
- try {
- Periods_Periods.parse(periodStr, dateStr);
- return true;
- } catch (e) {
- return false;
- }
-}
-
-Piwik_piwik.updatePeriodParamsFromUrl = function updatePeriodParamsFromUrl() {
- let date = PiwikUrl_PiwikUrl.getSearchParam('date');
- const period = PiwikUrl_PiwikUrl.getSearchParam('period');
-
- if (!Piwik_isValidPeriod(period, date)) {
- // invalid data in URL
- return;
- }
-
- if (Piwik_piwik.period === period && Piwik_piwik.currentDateString === date) {
- // this period / date is already loaded
- return;
- }
-
- Piwik_piwik.period = period;
- const dateRange = Periods_Periods.parse(period, date).getDateRange();
- Piwik_piwik.startDateString = format(dateRange[0]);
- Piwik_piwik.endDateString = format(dateRange[1]);
- Piwik_piwik.updateDateInTitle(date, period); // do not set anything to previousN/lastN, as it's more useful to plugins
- // to have the dates than previousN/lastN.
-
- if (Piwik_piwik.period === 'range') {
- date = `${Piwik_piwik.startDateString},${Piwik_piwik.endDateString}`;
- }
-
- Piwik_piwik.currentDateString = date;
-};
-
-Piwik_piwik.updateDateInTitle = function updateDateInTitle(date, period) {
- if (!$('.top_controls #periodString').length) {
- return;
- } // Cache server-rendered page title
-
-
- Piwik_originalTitle = Piwik_originalTitle || document.title;
-
- if (Piwik_originalTitle.indexOf(Piwik_piwik.siteName) === 0) {
- const dateString = ` - ${Periods_Periods.parse(period, date).getPrettyString()} `;
- document.title = `${Piwik_piwik.siteName}${dateString}${Piwik_originalTitle.substr(Piwik_piwik.siteName.length)}`;
- }
-};
-
-Piwik_piwik.hasUserCapability = function hasUserCapability(capability) {
- return window.angular.isArray(Piwik_piwik.userCapabilities) && Piwik_piwik.userCapabilities.indexOf(capability) !== -1;
-};
-
-const Piwik = Piwik_piwik;
-/* harmony default export */ var Piwik_Piwik = (Piwik);
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Piwik/Piwik.adapter.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-
-function Piwik_adapter_piwikService() {
- return Piwik_Piwik;
-}
-
-angular.module('piwikApp.service').service('piwik', Piwik_adapter_piwikService);
-
-function Piwik_adapter_initPiwikService(piwik, $rootScope) {
- $rootScope.$on('$locationChangeSuccess', piwik.updatePeriodParamsFromUrl);
-}
-
-Piwik_adapter_initPiwikService.$inject = ['piwik', '$rootScope'];
-angular.module('piwikApp.service').run(Piwik_adapter_initPiwikService);
-// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"}
-var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__("8bbf");
-
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue?vue&type=template&id=50fda6d8
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue?vue&type=template&id=15ad69b4
const _hoisted_1 = {
ref: "root"
@@ -1592,7 +1572,7 @@ const _hoisted_1 = {
function render(_ctx, _cache, $props, $setup, $data, $options) {
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])((Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderSlot"])(_ctx.$slots, "default")], 512)), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.modelValue]]);
}
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue?vue&type=template&id=50fda6d8
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue?vue&type=template&id=15ad69b4
// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/@vue/cli-plugin-typescript/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-3!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue?vue&type=script&lang=ts
@@ -1621,13 +1601,6 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
},
emits: ['yes', 'no', 'closeEnd', 'close', 'update:modelValue'],
- setup() {
- const root = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- return {
- root
- };
- },
-
activated() {
this.$emit('update:modelValue', false);
},
@@ -1691,7 +1664,8 @@ function createAngularJsAdapter(options) {
transclude,
mountPointFactory,
postCreate,
- noScope
+ noScope,
+ restrict = 'A'
} = options;
const currentTranscludeCounter = transcludeCounter;
@@ -1712,7 +1686,7 @@ function createAngularJsAdapter(options) {
function angularJsAdapter(...injectedServices) {
const adapter = {
- restrict: 'A',
+ restrict,
scope: noScope ? undefined : angularJsScope,
compile: function angularJsAdapterCompile() {
return {
@@ -1885,9 +1859,9 @@ function createAngularJsAdapter(options) {
},
noScope: true
}));
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue?vue&type=template&id=b71c9b1c
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue?vue&type=template&id=5653b0bd
-const EnrichedHeadlinevue_type_template_id_b71c9b1c_hoisted_1 = {
+const EnrichedHeadlinevue_type_template_id_5653b0bd_hoisted_1 = {
key: 0,
class: "title",
tabindex: "6"
@@ -1918,7 +1892,7 @@ const _hoisted_11 = {
};
const _hoisted_12 = ["innerHTML"];
const _hoisted_13 = ["href"];
-function EnrichedHeadlinevue_type_template_id_b71c9b1c_render(_ctx, _cache, $props, $setup, $data, $options) {
+function EnrichedHeadlinevue_type_template_id_5653b0bd_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_RateFeature = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("RateFeature");
return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
@@ -1926,7 +1900,7 @@ function EnrichedHeadlinevue_type_template_id_b71c9b1c_render(_ctx, _cache, $pro
onMouseenter: _cache[1] || (_cache[1] = $event => _ctx.showIcons = true),
onMouseleave: _cache[2] || (_cache[2] = $event => _ctx.showIcons = false),
ref: "root"
- }, [!_ctx.editUrl ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", EnrichedHeadlinevue_type_template_id_b71c9b1c_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderSlot"])(_ctx.$slots, "default")])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _ctx.editUrl ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("a", {
+ }, [!_ctx.editUrl ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", EnrichedHeadlinevue_type_template_id_5653b0bd_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderSlot"])(_ctx.$slots, "default")])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _ctx.editUrl ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("a", {
key: 1,
class: "title",
href: _ctx.editUrl,
@@ -1957,7 +1931,7 @@ function EnrichedHeadlinevue_type_template_id_b71c9b1c_render(_ctx, _cache, $pro
href: _ctx.helpUrl
}, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_MoreDetails')), 9, _hoisted_13)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.showInlineHelp]])], 544);
}
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue?vue&type=template&id=b71c9b1c
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue?vue&type=template&id=5653b0bd
// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/@vue/cli-plugin-typescript/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-3!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue?vue&type=script&lang=ts
@@ -2032,13 +2006,6 @@ const RateFeature = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["define
};
},
- setup() {
- const root = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- return {
- root
- };
- },
-
watch: {
inlineHelp(newValue) {
this.actualInlineHelp = newValue;
@@ -2100,7 +2067,7 @@ const RateFeature = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["define
-EnrichedHeadlinevue_type_script_lang_ts.render = EnrichedHeadlinevue_type_template_id_b71c9b1c_render
+EnrichedHeadlinevue_type_script_lang_ts.render = EnrichedHeadlinevue_type_template_id_5653b0bd_render
/* harmony default export */ var EnrichedHeadline = (EnrichedHeadlinevue_type_script_lang_ts);
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.adapter.ts
@@ -2134,39 +2101,39 @@ EnrichedHeadlinevue_type_script_lang_ts.render = EnrichedHeadlinevue_type_templa
directiveName: 'piwikEnrichedHeadline',
transclude: true
}));
-// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue?vue&type=template&id=5f6844c4
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue?vue&type=template&id=09ef9e02
-const ContentBlockvue_type_template_id_5f6844c4_hoisted_1 = {
+const ContentBlockvue_type_template_id_09ef9e02_hoisted_1 = {
class: "card",
ref: "root"
};
-const ContentBlockvue_type_template_id_5f6844c4_hoisted_2 = {
+const ContentBlockvue_type_template_id_09ef9e02_hoisted_2 = {
class: "card-content"
};
-const ContentBlockvue_type_template_id_5f6844c4_hoisted_3 = {
+const ContentBlockvue_type_template_id_09ef9e02_hoisted_3 = {
key: 0,
class: "card-title"
};
-const ContentBlockvue_type_template_id_5f6844c4_hoisted_4 = {
+const ContentBlockvue_type_template_id_09ef9e02_hoisted_4 = {
key: 1,
class: "card-title"
};
-const ContentBlockvue_type_template_id_5f6844c4_hoisted_5 = {
+const ContentBlockvue_type_template_id_09ef9e02_hoisted_5 = {
ref: "content"
};
-function ContentBlockvue_type_template_id_5f6844c4_render(_ctx, _cache, $props, $setup, $data, $options) {
+function ContentBlockvue_type_template_id_09ef9e02_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_EnrichedHeadline = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("EnrichedHeadline");
- return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", ContentBlockvue_type_template_id_5f6844c4_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", ContentBlockvue_type_template_id_5f6844c4_hoisted_2, [_ctx.contentTitle && !_ctx.actualFeature && !_ctx.helpUrl && !_ctx.actualHelpText ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("h2", ContentBlockvue_type_template_id_5f6844c4_hoisted_3, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.contentTitle), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _ctx.contentTitle && (_ctx.actualFeature || _ctx.helpUrl || _ctx.actualHelpText) ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("h2", ContentBlockvue_type_template_id_5f6844c4_hoisted_4, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_EnrichedHeadline, {
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", ContentBlockvue_type_template_id_09ef9e02_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", ContentBlockvue_type_template_id_09ef9e02_hoisted_2, [_ctx.contentTitle && !_ctx.actualFeature && !_ctx.helpUrl && !_ctx.actualHelpText ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("h2", ContentBlockvue_type_template_id_09ef9e02_hoisted_3, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.contentTitle), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), _ctx.contentTitle && (_ctx.actualFeature || _ctx.helpUrl || _ctx.actualHelpText) ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("h2", ContentBlockvue_type_template_id_09ef9e02_hoisted_4, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_EnrichedHeadline, {
"feature-name": _ctx.actualFeature,
"help-url": _ctx.helpUrl,
"inline-help": _ctx.actualHelpText
}, {
default: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(() => [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.contentTitle), 1)]),
_: 1
- }, 8, ["feature-name", "help-url", "inline-help"])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", ContentBlockvue_type_template_id_5f6844c4_hoisted_5, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderSlot"])(_ctx.$slots, "default")], 512)])], 512);
+ }, 8, ["feature-name", "help-url", "inline-help"])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", ContentBlockvue_type_template_id_09ef9e02_hoisted_5, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderSlot"])(_ctx.$slots, "default")], 512)])], 512);
}
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue?vue&type=template&id=5f6844c4
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue?vue&type=template&id=09ef9e02
// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/@vue/cli-plugin-typescript/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-3!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue?vue&type=script&lang=ts
@@ -2191,15 +2158,6 @@ let adminContent = null;
};
},
- setup() {
- const root = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- const content = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null);
- return {
- root,
- content
- };
- },
-
watch: {
feature(newValue) {
this.actualFeature = newValue;
@@ -2269,7 +2227,7 @@ let adminContent = null;
-ContentBlockvue_type_script_lang_ts.render = ContentBlockvue_type_template_id_5f6844c4_render
+ContentBlockvue_type_script_lang_ts.render = ContentBlockvue_type_template_id_09ef9e02_render
/* harmony default export */ var ContentBlock = (ContentBlockvue_type_script_lang_ts);
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/ContentBlock/ContentBlock.adapter.ts
@@ -2303,6 +2261,636 @@ ContentBlockvue_type_script_lang_ts.render = ContentBlockvue_type_template_id_5f
directiveName: 'piwikContentBlock',
transclude: true
}));
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Segmentation/Segments.store.ts
+function Segments_store_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+
+
+class Segments_store_SegmentsStore {
+ get state() {
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])(this.segmentState);
+ }
+
+ constructor() {
+ Segments_store_defineProperty(this, "segmentState", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["reactive"])({
+ availableSegments: []
+ }));
+
+ Matomo_Matomo.on('piwikSegmentationInited', () => this.setSegmentState());
+ }
+
+ setSegmentState() {
+ try {
+ const uiControlObject = $('.segmentEditorPanel').data('uiControlObject');
+ this.segmentState.availableSegments = uiControlObject.impl.availableSegments || [];
+ } catch (e) {// segment editor is not initialized yet
+ }
+ }
+
+}
+
+/* harmony default export */ var Segments_store = (new Segments_store_SegmentsStore());
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Comparisons/Comparisons.store.ts
+function Comparisons_store_defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+
+
+
+
+
+
+const SERIES_COLOR_COUNT = 8;
+const SERIES_SHADE_COUNT = 3;
+
+function wrapArray(values) {
+ if (!values) {
+ return [];
+ }
+
+ return values instanceof Array ? values : [values];
+}
+
+class Comparisons_store_ComparisonsStore {
+ // for tests
+ constructor() {
+ Comparisons_store_defineProperty(this, "privateState", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["reactive"])({
+ comparisonsDisabledFor: []
+ }));
+
+ Comparisons_store_defineProperty(this, "state", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["readonly"])(this.privateState));
+
+ Comparisons_store_defineProperty(this, "colors", {});
+
+ Comparisons_store_defineProperty(this, "segmentComparisons", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => this.parseSegmentComparisons()));
+
+ Comparisons_store_defineProperty(this, "periodComparisons", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => this.parsePeriodComparisons()));
+
+ Comparisons_store_defineProperty(this, "isEnabled", Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => this.checkEnabledForCurrentPage()));
+
+ this.loadComparisonsDisabledFor();
+ $(() => {
+ this.colors = this.getAllSeriesColors();
+ });
+ Object(external_commonjs_vue_commonjs2_vue_root_Vue_["watch"])(() => this.getComparisons(), () => Matomo_Matomo.postEvent('piwikComparisonsChanged'), {
+ deep: true
+ });
+ }
+
+ getComparisons() {
+ return this.getSegmentComparisons().concat(this.getPeriodComparisons());
+ }
+
+ isComparing() {
+ return this.isComparisonEnabled() // first two in each array are for the currently selected segment/period
+ && (this.segmentComparisons.value.length > 1 || this.periodComparisons.value.length > 1);
+ }
+
+ isComparingPeriods() {
+ return this.getPeriodComparisons().length > 1; // first is currently selected period
+ }
+
+ getSegmentComparisons() {
+ if (!this.isComparisonEnabled()) {
+ return [];
+ }
+
+ return this.segmentComparisons.value;
+ }
+
+ getPeriodComparisons() {
+ if (!this.isComparisonEnabled()) {
+ return [];
+ }
+
+ return this.periodComparisons.value;
+ }
+
+ getSeriesColor(segmentComparison, periodComparison, metricIndex = 0) {
+ const seriesIndex = this.getComparisonSeriesIndex(periodComparison.index, segmentComparison.index) % SERIES_COLOR_COUNT;
+
+ if (metricIndex === 0) {
+ return this.colors[`series${seriesIndex}`];
+ }
+
+ const shadeIndex = metricIndex % SERIES_SHADE_COUNT;
+ return this.colors[`series${seriesIndex}-shade${shadeIndex}`];
+ }
+
+ getSeriesColorName(seriesIndex, metricIndex) {
+ let colorName = `series${seriesIndex % SERIES_COLOR_COUNT}`;
+
+ if (metricIndex > 0) {
+ colorName += `-shade${metricIndex % SERIES_SHADE_COUNT}`;
+ }
+
+ return colorName;
+ }
+
+ isComparisonEnabled() {
+ return this.isEnabled.value;
+ }
+
+ getIndividualComparisonRowIndices(seriesIndex) {
+ const segmentCount = this.getSegmentComparisons().length;
+ const segmentIndex = seriesIndex % segmentCount;
+ const periodIndex = Math.floor(seriesIndex / segmentCount);
+ return {
+ segmentIndex,
+ periodIndex
+ };
+ }
+
+ getComparisonSeriesIndex(periodIndex, segmentIndex) {
+ const segmentCount = this.getSegmentComparisons().length;
+ return periodIndex * segmentCount + segmentIndex;
+ }
+
+ getAllComparisonSeries() {
+ const seriesInfo = [];
+ let seriesIndex = 0;
+ this.getPeriodComparisons().forEach(periodComp => {
+ this.getSegmentComparisons().forEach(segmentComp => {
+ seriesInfo.push({
+ index: seriesIndex,
+ params: { ...segmentComp.params,
+ ...periodComp.params
+ },
+ color: this.colors[`series${seriesIndex}`]
+ });
+ seriesIndex += 1;
+ });
+ });
+ return seriesInfo;
+ }
+
+ removeSegmentComparison(index) {
+ if (!this.isComparisonEnabled()) {
+ throw new Error('Comparison disabled.');
+ }
+
+ const newComparisons = [...this.segmentComparisons.value];
+ newComparisons.splice(index, 1);
+ const extraParams = {};
+
+ if (index === 0) {
+ extraParams.segment = newComparisons[0].params.segment;
+ }
+
+ this.updateQueryParamsFromComparisons(newComparisons, this.periodComparisons.value, extraParams);
+ }
+
+ addSegmentComparison(params) {
+ if (!this.isComparisonEnabled()) {
+ throw new Error('Comparison disabled.');
+ }
+
+ const newComparisons = this.segmentComparisons.value.concat([{
+ params,
+ index: -1,
+ title: ''
+ }]);
+ this.updateQueryParamsFromComparisons(newComparisons, this.periodComparisons.value);
+ }
+
+ updateQueryParamsFromComparisons(segmentComparisons, periodComparisons, extraParams = {}) {
+ // get unique segments/periods/dates from new Comparisons
+ const compareSegments = {};
+ const comparePeriodDatePairs = {};
+ let firstSegment = false;
+ let firstPeriod = false;
+ segmentComparisons.forEach(comparison => {
+ if (firstSegment) {
+ compareSegments[comparison.params.segment] = true;
+ } else {
+ firstSegment = true;
+ }
+ });
+ periodComparisons.forEach(comparison => {
+ if (firstPeriod) {
+ comparePeriodDatePairs[`${comparison.params.period}|${comparison.params.date}`] = true;
+ } else {
+ firstPeriod = true;
+ }
+ });
+ const comparePeriods = [];
+ const compareDates = [];
+ Object.keys(comparePeriodDatePairs).forEach(pair => {
+ const parts = pair.split('|');
+ comparePeriods.push(parts[0]);
+ compareDates.push(parts[1]);
+ });
+ const compareParams = {
+ compareSegments: Object.keys(compareSegments),
+ comparePeriods,
+ compareDates
+ }; // change the page w/ these new param values
+
+ if (Matomo_Matomo.helper.isAngularRenderingThePage()) {
+ const search = src_MatomoUrl_MatomoUrl.hashParsed.value;
+ const newSearch = { ...search,
+ ...compareParams,
+ ...extraParams
+ };
+ delete newSearch['compareSegments[]'];
+ delete newSearch['comparePeriods[]'];
+ delete newSearch['compareDates[]'];
+
+ if (JSON.stringify(newSearch) !== JSON.stringify(search)) {
+ src_MatomoUrl_MatomoUrl.updateHash(newSearch);
+ }
+
+ return;
+ }
+
+ const paramsToRemove = [];
+ ['compareSegments', 'comparePeriods', 'compareDates'].forEach(name => {
+ if (!compareParams[name].length) {
+ paramsToRemove.push(name);
+ }
+ }); // angular is not rendering the page (ie, we are in the embedded dashboard) or we need to change
+ // the segment
+
+ const url = src_MatomoUrl_MatomoUrl.stringify(extraParams);
+ const strHash = src_MatomoUrl_MatomoUrl.stringify(compareParams);
+ window.broadcast.propagateNewPage(url, undefined, strHash, paramsToRemove);
+ }
+
+ getAllSeriesColors() {
+ const {
+ ColorManager
+ } = Matomo_Matomo;
+ const seriesColorNames = [];
+
+ for (let i = 0; i < SERIES_COLOR_COUNT; i += 1) {
+ seriesColorNames.push(`series${i}`);
+
+ for (let j = 0; j < SERIES_SHADE_COUNT; j += 1) {
+ seriesColorNames.push(`series${i}-shade${j}`);
+ }
+ }
+
+ return ColorManager.getColors('comparison-series-color', seriesColorNames);
+ }
+
+ loadComparisonsDisabledFor() {
+ AjaxHelper_AjaxHelper.fetch({
+ module: 'API',
+ method: 'API.getPagesComparisonsDisabledFor'
+ }).then(result => {
+ this.privateState.comparisonsDisabledFor = result;
+ });
+ }
+
+ parseSegmentComparisons() {
+ const {
+ availableSegments
+ } = Segments_store.state;
+ const compareSegments = [...wrapArray(src_MatomoUrl_MatomoUrl.parsed.value.compareSegments)]; // add base comparisons
+
+ compareSegments.unshift(src_MatomoUrl_MatomoUrl.parsed.value.segment || '');
+ const newSegmentComparisons = [];
+ compareSegments.forEach((segment, idx) => {
+ let storedSegment;
+ availableSegments.forEach(s => {
+ if (s.definition === segment || s.definition === decodeURIComponent(segment) || decodeURIComponent(s.definition) === segment) {
+ storedSegment = s;
+ }
+ });
+ let segmentTitle = storedSegment ? storedSegment.name : translate('General_Unknown');
+
+ if (segment.trim() === '') {
+ segmentTitle = translate('SegmentEditor_DefaultAllVisits');
+ }
+
+ newSegmentComparisons.push({
+ params: {
+ segment
+ },
+ title: Matomo_Matomo.helper.htmlDecode(segmentTitle),
+ index: idx
+ });
+ });
+ return newSegmentComparisons;
+ }
+
+ parsePeriodComparisons() {
+ const comparePeriods = [...wrapArray(src_MatomoUrl_MatomoUrl.parsed.value.comparePeriods)];
+ const compareDates = [...wrapArray(src_MatomoUrl_MatomoUrl.parsed.value.compareDates)];
+ comparePeriods.unshift(src_MatomoUrl_MatomoUrl.parsed.value.period);
+ compareDates.unshift(src_MatomoUrl_MatomoUrl.parsed.value.date);
+ const newPeriodComparisons = [];
+
+ for (let i = 0; i < Math.min(compareDates.length, comparePeriods.length); i += 1) {
+ let title;
+
+ try {
+ title = Periods_Periods.parse(comparePeriods[i], compareDates[i]).getPrettyString();
+ } catch (e) {
+ title = translate('General_Error');
+ }
+
+ newPeriodComparisons.push({
+ params: {
+ date: compareDates[i],
+ period: comparePeriods[i]
+ },
+ title,
+ index: i
+ });
+ }
+
+ return newPeriodComparisons;
+ }
+
+ checkEnabledForCurrentPage() {
+ // category/subcategory is not included on top bar pages, so in that case we use module/action
+ const category = src_MatomoUrl_MatomoUrl.parsed.value.category || src_MatomoUrl_MatomoUrl.parsed.value.module;
+ const subcategory = src_MatomoUrl_MatomoUrl.parsed.value.subcategory || src_MatomoUrl_MatomoUrl.parsed.value.action;
+ const id = `${category}.${subcategory}`;
+ const isEnabled = this.privateState.comparisonsDisabledFor.indexOf(id) === -1 && this.privateState.comparisonsDisabledFor.indexOf(`${category}.*`) === -1;
+ document.documentElement.classList.toggle('comparisonsDisabled', !isEnabled);
+ return isEnabled;
+ }
+
+}
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Comparisons/Comparisons.store.instance.ts
+
+/* harmony default export */ var Comparisons_store_instance = (new Comparisons_store_ComparisonsStore());
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/Comparisons/Comparisons.vue?vue&type=template&id=1b8ecdd2
+
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_1 = {
+ key: 0,
+ ref: "root",
+ class: "matomo-comparisons"
+};
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_2 = {
+ class: "comparison-type"
+};
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_3 = ["title"];
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_4 = ["href"];
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_5 = ["title"];
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_6 = {
+ class: "comparison-period-label"
+};
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_7 = ["onClick"];
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_8 = ["title"];
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_9 = {
+ class: "loadingPiwik",
+ style: {
+ "display": "none"
+ }
+};
+const Comparisonsvue_type_template_id_1b8ecdd2_hoisted_10 = ["alt"];
+function Comparisonsvue_type_template_id_1b8ecdd2_render(_ctx, _cache, $props, $setup, $data, $options) {
+ return _ctx.isComparing ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", Comparisonsvue_type_template_id_1b8ecdd2_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h3", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Comparisons')), 1), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.segmentComparisons, (comparison, $index) => {
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
+ class: "comparison card",
+ key: comparison.index
+ }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", Comparisonsvue_type_template_id_1b8ecdd2_hoisted_2, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Segment')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", {
+ class: "title",
+ title: comparison.title + '<br/>' + decodeURIComponent(comparison.params.segment)
+ }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", {
+ target: "_blank",
+ href: _ctx.getUrlToSegment(comparison.params.segment)
+ }, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(comparison.title), 9, Comparisonsvue_type_template_id_1b8ecdd2_hoisted_4)], 8, Comparisonsvue_type_template_id_1b8ecdd2_hoisted_3), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.periodComparisons, periodComparison => {
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
+ class: "comparison-period",
+ key: periodComparison.index,
+ title: _ctx.getComparisonTooltip(comparison, periodComparison)
+ }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
+ class: "comparison-dot",
+ style: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeStyle"])({
+ 'background-color': _ctx.getSeriesColor(comparison, periodComparison)
+ })
+ }, null, 4), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", Comparisonsvue_type_template_id_1b8ecdd2_hoisted_6, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(periodComparison.title) + " (" + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.getComparisonPeriodType(periodComparison)) + ") ", 1)], 8, Comparisonsvue_type_template_id_1b8ecdd2_hoisted_5);
+ }), 128)), _ctx.segmentComparisons.length > 1 ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("a", {
+ key: 0,
+ class: "remove-button",
+ onClick: $event => _ctx.removeSegmentComparison($index)
+ }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
+ class: "icon icon-close",
+ title: _ctx.translate('General_ClickToRemoveComp')
+ }, null, 8, Comparisonsvue_type_template_id_1b8ecdd2_hoisted_8)], 8, Comparisonsvue_type_template_id_1b8ecdd2_hoisted_7)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)]);
+ }), 128)), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", Comparisonsvue_type_template_id_1b8ecdd2_hoisted_9, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("img", {
+ src: "plugins/Morpheus/images/loading-blue.gif",
+ alt: _ctx.translate('General_LoadingData')
+ }, null, 8, Comparisonsvue_type_template_id_1b8ecdd2_hoisted_10), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_LoadingData')), 1)])], 512)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true);
+}
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Comparisons/Comparisons.vue?vue&type=template&id=1b8ecdd2
+
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/@vue/cli-plugin-typescript/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-3!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/Comparisons/Comparisons.vue?vue&type=script&lang=ts
+
+
+
+
+
+
+/* harmony default export */ var Comparisonsvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({
+ props: {},
+
+ data() {
+ return {
+ comparisonTooltips: null
+ };
+ },
+
+ setup() {
+ // accessing has to be done through a computed property so we can use the computed
+ // instance directly in the template. unfortunately, vue won't register to changes.
+ const isComparing = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Comparisons_store_instance.isComparing());
+ const segmentComparisons = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Comparisons_store_instance.getSegmentComparisons());
+ const periodComparisons = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(() => Comparisons_store_instance.getPeriodComparisons());
+ const getSeriesColor = Comparisons_store_instance.getSeriesColor.bind(Comparisons_store_instance);
+ return {
+ isComparing,
+ segmentComparisons,
+ periodComparisons,
+ getSeriesColor
+ };
+ },
+
+ methods: {
+ comparisonHasSegment(comparison) {
+ return typeof comparison.params.segment !== 'undefined';
+ },
+
+ removeSegmentComparison(index) {
+ // otherwise the tooltip will be stuck on the screen
+ window.$(this.$refs.root).tooltip('destroy');
+ Comparisons_store_instance.removeSegmentComparison(index);
+ },
+
+ getComparisonPeriodType(comparison) {
+ const {
+ period
+ } = comparison.params;
+
+ if (period === 'range') {
+ return translate('CoreHome_PeriodRange');
+ }
+
+ const periodStr = translate(`Intl_Period${period.substring(0, 1).toUpperCase()}${period.substring(1)}`);
+ return periodStr.substring(0, 1).toUpperCase() + periodStr.substring(1);
+ },
+
+ getComparisonTooltip(segmentComparison, periodComparison) {
+ if (!this.comparisonTooltips || !Object.keys(this.comparisonTooltips).length) {
+ return undefined;
+ }
+
+ return (this.comparisonTooltips[periodComparison.index] || {})[segmentComparison.index];
+ },
+
+ getUrlToSegment(segment) {
+ const hash = { ...src_MatomoUrl_MatomoUrl.hashParsed.value
+ };
+ delete hash.comparePeriods;
+ delete hash.compareDates;
+ delete hash.compareSegments;
+ hash.segment = segment;
+ return `${window.location.search}#?${src_MatomoUrl_MatomoUrl.stringify(hash)}`;
+ },
+
+ setUpTooltips() {
+ const {
+ $
+ } = window;
+ $(this.$refs.root).tooltip({
+ track: true,
+ content: function transformTooltipContent() {
+ const title = $(this).attr('title');
+ return window.vueSanitize(title.replace(/\n/g, '<br />'));
+ },
+ show: {
+ delay: 200,
+ duration: 200
+ },
+ hide: false
+ });
+ },
+
+ onComparisonsChanged() {
+ this.comparisonTooltips = null;
+
+ if (!Comparisons_store_instance.isComparing()) {
+ return;
+ }
+
+ const periodComparisons = Comparisons_store_instance.getPeriodComparisons();
+ const segmentComparisons = Comparisons_store_instance.getSegmentComparisons();
+ AjaxHelper_AjaxHelper.fetch({
+ method: 'API.getProcessedReport',
+ apiModule: 'VisitsSummary',
+ apiAction: 'get',
+ compare: '1',
+ compareSegments: src_MatomoUrl_MatomoUrl.getSearchParam('compareSegments'),
+ comparePeriods: src_MatomoUrl_MatomoUrl.getSearchParam('comparePeriods'),
+ compareDates: src_MatomoUrl_MatomoUrl.getSearchParam('compareDates'),
+ format_metrics: '1'
+ }).then(report => {
+ this.comparisonTooltips = {};
+ periodComparisons.forEach(periodComp => {
+ this.comparisonTooltips[periodComp.index] = {};
+ segmentComparisons.forEach(segmentComp => {
+ const tooltip = this.generateComparisonTooltip(report, periodComp, segmentComp);
+ this.comparisonTooltips[periodComp.index][segmentComp.index] = tooltip;
+ });
+ });
+ });
+ },
+
+ generateComparisonTooltip(visitsSummary, periodComp, segmentComp) {
+ if (!visitsSummary.reportData.comparisons) {
+ // sanity check
+ return '';
+ }
+
+ const firstRowIndex = Comparisons_store_instance.getComparisonSeriesIndex(periodComp.index, 0);
+ const firstRow = visitsSummary.reportData.comparisons[firstRowIndex];
+ const comparisonRowIndex = Comparisons_store_instance.getComparisonSeriesIndex(periodComp.index, segmentComp.index);
+ const comparisonRow = visitsSummary.reportData.comparisons[comparisonRowIndex];
+ const firstPeriodRow = visitsSummary.reportData.comparisons[segmentComp.index];
+ let tooltip = '<div class="comparison-card-tooltip">';
+ let visitsPercent = (comparisonRow.nb_visits / firstRow.nb_visits * 100).toFixed(2);
+ visitsPercent = `${visitsPercent}%`;
+ tooltip += translate('General_ComparisonCardTooltip1', [`'${comparisonRow.compareSegmentPretty}'`, comparisonRow.comparePeriodPretty, visitsPercent, comparisonRow.nb_visits.toString(), firstRow.nb_visits.toString()]);
+
+ if (periodComp.index > 0) {
+ tooltip += '<br/><br/>';
+ tooltip += translate('General_ComparisonCardTooltip2', [comparisonRow.nb_visits_change.toString(), firstPeriodRow.compareSegmentPretty, firstPeriodRow.comparePeriodPretty]);
+ }
+
+ tooltip += '</div>';
+ return tooltip;
+ }
+
+ },
+
+ updated() {
+ setTimeout(() => this.setUpTooltips());
+ },
+
+ mounted() {
+ Matomo_Matomo.on('piwikComparisonsChanged', () => {
+ this.onComparisonsChanged();
+ });
+ this.onComparisonsChanged();
+ setTimeout(() => this.setUpTooltips());
+ },
+
+ beforeUnmount() {
+ try {
+ window.$(this.refs.root).tooltip('destroy');
+ } catch (e) {// ignore
+ }
+ }
+
+}));
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Comparisons/Comparisons.vue?vue&type=script&lang=ts
+
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Comparisons/Comparisons.vue
+
+
+
+Comparisonsvue_type_script_lang_ts.render = Comparisonsvue_type_template_id_1b8ecdd2_render
+
+/* harmony default export */ var Comparisons = (Comparisonsvue_type_script_lang_ts);
+// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Comparisons/Comparisons.adapter.ts
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+
+
+
+function ComparisonFactory() {
+ return Comparisons_store_instance;
+}
+
+ComparisonFactory.$inject = [];
+angular.module('piwikApp.service').factory('piwikComparisonsService', ComparisonFactory);
+/* harmony default export */ var Comparisons_adapter = (createAngularJsAdapter({
+ component: Comparisons,
+ directiveName: 'piwikComparisons',
+ restrict: 'E'
+}));
// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreHome/vue/src/ActivityIndicator/ActivityIndicator.vue?vue&type=template&id=6af4d064
const ActivityIndicatorvue_type_template_id_6af4d064_hoisted_1 = {
@@ -2421,21 +3009,6 @@ Alertvue_type_script_lang_ts.render = Alertvue_type_template_id_c3863ae2_render
directiveName: 'piwikAlert',
transclude: true
}));
-// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/Periods/index.ts
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-
-
-
-
-
-
-
// CONCATENATED MODULE: ./plugins/CoreHome/vue/src/index.ts
/*!
* Matomo - free/libre analytics platform
diff --git a/plugins/CoreHome/vue/dist/CoreHome.umd.min.js b/plugins/CoreHome/vue/dist/CoreHome.umd.min.js
index 0da652c656..a98ec10354 100644
--- a/plugins/CoreHome/vue/dist/CoreHome.umd.min.js
+++ b/plugins/CoreHome/vue/dist/CoreHome.umd.min.js
@@ -1,152 +1,152 @@
-(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("vue")):"function"===typeof define&&define.amd?define([],t):"object"===typeof exports?exports["CoreHome"]=t(require("vue")):e["CoreHome"]=t(e["Vue"])})("undefined"!==typeof self?self:this,(function(e){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="plugins/CoreHome/vue/dist/",n(n.s="fae3")}({2342:function(e,t,n){"use strict";
+(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("vue")):"function"===typeof define&&define.amd?define([],t):"object"===typeof exports?exports["CoreHome"]=t(require("vue")):e["CoreHome"]=t(e["Vue"])})("undefined"!==typeof self?self:this,(function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var a=t[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)r.d(n,a,function(t){return e[t]}.bind(null,a));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="plugins/CoreHome/vue/dist/",r(r.s="fae3")}({2342:function(e,t,r){"use strict";
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */window.hasBlockedContent=!1},"8bbf":function(t,n){t.exports=e},fae3:function(e,t,n){"use strict";if(n.r(t),n.d(t,"createAngularJsAdapter",(function(){return ie})),n.d(t,"activityIndicatorAdapter",(function(){return Ne})),n.d(t,"ActivityIndicator",(function(){return Fe})),n.d(t,"translate",(function(){return k})),n.d(t,"alertAdapter",(function(){return Ve})),n.d(t,"AjaxHelper",(function(){return U})),n.d(t,"MatomoUrl",(function(){return o})),n.d(t,"Matomo",(function(){return P})),n.d(t,"Periods",(function(){return u})),n.d(t,"Day",(function(){return S})),n.d(t,"Week",(function(){return E})),n.d(t,"Month",(function(){return I})),n.d(t,"Year",(function(){return H})),n.d(t,"Range",(function(){return A})),n.d(t,"format",(function(){return d})),n.d(t,"getToday",(function(){return p})),n.d(t,"parseDate",(function(){return h})),n.d(t,"todayIsInRange",(function(){return m})),n.d(t,"MatomoDialog",(function(){return re})),n.d(t,"EnrichedHeadline",(function(){return ve})),n.d(t,"ContentBlock",(function(){return Ie})),"undefined"!==typeof window){var r=window.document.currentScript,a=r&&r.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);a&&(n.p=a[1])}
+ */window.hasBlockedContent=!1},"8bbf":function(t,r){t.exports=e},fae3:function(e,t,r){"use strict";if(r.r(t),r.d(t,"createAngularJsAdapter",(function(){return X})),r.d(t,"activityIndicatorAdapter",(function(){return Ke})),r.d(t,"ActivityIndicator",(function(){return Xe})),r.d(t,"translate",(function(){return g})),r.d(t,"alertAdapter",(function(){return rt})),r.d(t,"AjaxHelper",(function(){return G})),r.d(t,"MatomoUrl",(function(){return R})),r.d(t,"Matomo",(function(){return h})),r.d(t,"Periods",(function(){return l})),r.d(t,"Day",(function(){return O})),r.d(t,"Week",(function(){return S})),r.d(t,"Month",(function(){return E})),r.d(t,"Year",(function(){return x})),r.d(t,"Range",(function(){return C})),r.d(t,"format",(function(){return f})),r.d(t,"getToday",(function(){return b})),r.d(t,"parseDate",(function(){return w})),r.d(t,"todayIsInRange",(function(){return y})),r.d(t,"MatomoDialog",(function(){return Y})),r.d(t,"EnrichedHeadline",(function(){return he})),r.d(t,"ContentBlock",(function(){return je})),r.d(t,"Comparisons",(function(){return Le})),"undefined"!==typeof window){var n=window.document.currentScript,a=n&&n.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);a&&(r.p=a[1])}r("2342");var o=r("8bbf");function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-const i={getSearchParam(e){const t=window.location.href.split("#"),n=new RegExp(e+"(\\[]|=)");if(t&&t[1]&&n.test(decodeURIComponent(t[1]))){const t=window.broadcast.getValueFromHash(e,window.location.href);if(t||"date"!==e&&"period"!==e&&"idSite"!==e)return t}return window.broadcast.getValueFromUrl(e,window.location.search)}};var o=i;
+ */class s{constructor(){i(this,"periods",{}),i(this,"periodOrder",[])}addCustomPeriod(e,t){if(this.periods[e])throw new Error(`The "${e}" period already exists! It cannot be overridden.`);this.periods[e]=t,this.periodOrder.push(e)}getAllLabels(){return Array().concat(this.periodOrder)}get(e){const t=this.periods[e];if(!t)throw new Error("Invalid period label: "+e);return t}parse(e,t){return this.get(e).parse(t)}isRecognizedPeriod(e){return!!this.periods[e]}}var l=new s;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function s(){const e={getSearchParam:o.getSearchParam.bind(o)};return e}function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */let c;const{piwik:d,broadcast:u,piwikHelper:p}=window;d.helper=p,d.broadcast=u,d.updateDateInTitle=function(e,t){if($(".top_controls #periodString").length&&(c=c||document.title,0===c.indexOf(d.siteName))){const r=` - ${l.parse(t,e).getPrettyString()} `;document.title=`${d.siteName}${r}${c.substr(d.siteName.length)}`}},d.hasUserCapability=function(e){return window.angular.isArray(d.userCapabilities)&&-1!==d.userCapabilities.indexOf(e)},d.on=function(e,t){function r(e){t(...e.detail)}t.wrapper=r,window.addEventListener(e,r)},d.off=function(e,t){t.wrapper&&window.removeEventListener(e,t.wrapper)},d.postEventNoEmit=function(e,...t){const r=new CustomEvent(e,{detail:t});window.dispatchEvent(r)},d.postEvent=function(e,...t){d.postEventNoEmit(e,...t);const r=d.helper.getAngularDependency("$rootScope");return r.$oldEmit(e,...t)};const m=d;var h=m;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */s.$inject=[],angular.module("piwikApp.service").service("piwikUrl",s);class c{constructor(){l(this,"periods",{}),l(this,"periodOrder",[])}addCustomPeriod(e,t){if(this.periods[e])throw new Error(`The "${e}" period already exists! It cannot be overridden.`);this.periods[e]=t,this.periodOrder.push(e)}getAllLabels(){return Array().concat(this.periodOrder)}get(e){const t=this.periods[e];if(!t)throw new Error("Invalid period label: "+e);return t}parse(e,t){return this.get(e).parse(t)}isRecognizedPeriod(e){return!!this.periods[e]}}var u=new c;
+ */function g(e,...t){let r=t;return 1===t.length&&t[0]&&t[0]instanceof Array&&([r]=t),window._pk_translate(e,r)}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function d(e){return $.datepicker.formatDate("yy-mm-dd",e)}function p(){const e=new Date(Date.now());return e.setTime(e.getTime()+60*e.getTimezoneOffset()*1e3),e.setHours(e.getHours()+(window.piwik.timezoneOffset||0)/3600),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0),e}function h(e){if(e instanceof Date)return e;const t=decodeURIComponent(e);if("today"===t||"now"===t)return p();if("yesterday"===t||"yesterdaySameTime"===t){const e=p();return e.setDate(e.getDate()-1),e}if(t.match(/last[ -]?week/i)){const e=p();return e.setDate(e.getDate()-7),e}if(t.match(/last[ -]?month/i)){const e=p();return e.setDate(1),e.setMonth(e.getMonth()-1),e}if(t.match(/last[ -]?year/i)){const e=p();return e.setFullYear(e.getFullYear()-1),e}try{return $.datepicker.parseDate("yy-mm-dd",t)}catch(n){throw console.error(n.message||n),n}}function m(e){return 2===e.length&&(p()>=e[0]&&p()<=e[1])}
+ */function f(e){return $.datepicker.formatDate("yy-mm-dd",e)}function b(){const e=new Date(Date.now());return e.setTime(e.getTime()+60*e.getTimezoneOffset()*1e3),e.setHours(e.getHours()+(window.piwik.timezoneOffset||0)/3600),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0),e}function w(e){if(e instanceof Date)return e;const t=decodeURIComponent(e).trim();if(""===t)throw new Error("Invalid date, empty string.");if("today"===t||"now"===t)return b();if("yesterday"===t||"yesterdaySameTime"===t){const e=b();return e.setDate(e.getDate()-1),e}if(t.match(/last[ -]?week/i)){const e=b();return e.setDate(e.getDate()-7),e}if(t.match(/last[ -]?month/i)){const e=b();return e.setDate(1),e.setMonth(e.getMonth()-1),e}if(t.match(/last[ -]?year/i)){const e=b();return e.setFullYear(e.getFullYear()-1),e}return $.datepicker.parseDate("yy-mm-dd",t)}function y(e){return 2===e.length&&(b()>=e[0]&&b()<=e[1])}function v(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */let g;const{piwik:f,broadcast:b,piwikHelper:w}=window;function y(e,t){try{return u.parse(e,t),!0}catch(n){return!1}}f.helper=w,f.broadcast=b,f.updatePeriodParamsFromUrl=function(){let e=o.getSearchParam("date");const t=o.getSearchParam("period");if(!y(t,e))return;if(f.period===t&&f.currentDateString===e)return;f.period=t;const n=u.parse(t,e).getDateRange();f.startDateString=d(n[0]),f.endDateString=d(n[1]),f.updateDateInTitle(e,t),"range"===f.period&&(e=`${f.startDateString},${f.endDateString}`),f.currentDateString=e},f.updateDateInTitle=function(e,t){if($(".top_controls #periodString").length&&(g=g||document.title,0===g.indexOf(f.siteName))){const n=` - ${u.parse(t,e).getPrettyString()} `;document.title=`${f.siteName}${n}${g.substr(f.siteName.length)}`}},f.hasUserCapability=function(e){return window.angular.isArray(f.userCapabilities)&&-1!==f.userCapabilities.indexOf(e)};const D=f;var P=D;
+ */class C{constructor(e,t,r){v(this,"startDate",void 0),v(this,"endDate",void 0),v(this,"childPeriodType",void 0),this.startDate=e,this.endDate=t,this.childPeriodType=r}static getLastNRange(e,t,r){const n=Math.max(parseInt(t.toString(),10)-1,0);if(Number.isNaN(n))throw new Error("Invalid range strAmount");let a=r?w(r):b(),o=new Date(a.getTime());if("day"===e)o.setDate(o.getDate()-n);else if("week"===e)o.setDate(o.getDate()-7*n);else if("month"===e)o.setDate(1),o.setMonth(o.getMonth()-n);else{if("year"!==e)throw new Error(`Unknown period type '${e}'.`);o.setFullYear(o.getFullYear()-n)}if("day"!==e){const t=l.periods[e].parse(o),r=l.periods[e].parse(a);[o]=t.getDateRange(),[,a]=r.getDateRange()}const i=new Date(1991,7,6);if(o.getTime()-i.getTime()<0)switch(e){case"year":o=new Date(1992,0,1);break;case"month":o=new Date(1991,8,1);break;case"week":o=new Date(1991,8,12);break;case"day":default:o=i;break}return new C(o,a,e)}static getLastNRangeChild(e,t,r){const n=t?w(t):b();let a=new Date(n.getTime()),o=new Date(n.getTime());if("day"===e)a.setDate(a.getDate()-r),o.setDate(o.getDate()-r);else if("week"===e)a.setDate(a.getDate()-7*r),o.setDate(o.getDate()-7*r);else if("month"===e)a.setDate(1),a.setMonth(a.getMonth()-r),o.setDate(1),o.setMonth(o.getMonth()-r);else{if("year"!==e)throw new Error(`Unknown period type '${e}'.`);a.setFullYear(a.getFullYear()-r),o.setFullYear(o.getFullYear()-r)}if("day"!==e){const t=l.periods[e].parse(a),r=l.periods[e].parse(o);[a]=t.getDateRange(),[,o]=r.getDateRange()}const i=new Date(1991,7,6);if(a.getTime()-i.getTime()<0)switch(e){case"year":a=new Date(1992,0,1);break;case"month":a=new Date(1991,8,1);break;case"week":a=new Date(1991,8,12);break;case"day":default:a=i;break}return new C(a,o,e)}static parse(e,t="day"){if(/^previous/.test(e)){const r=C.getLastNRange(t,"2").startDate;return C.getLastNRange(t,e.substring(8),r)}if(/^last/.test(e))return C.getLastNRange(t,e.substring(4));const r=decodeURIComponent(e).split(",");return new C(w(r[0]),w(r[1]),t)}static getDisplayText(){return g("General_DateRangeInPeriodList")}getPrettyString(){const e=f(this.startDate),t=f(this.endDate);return g("General_DateRangeFromTo",[e,t])}getDateRange(){return[this.startDate,this.endDate]}containsToday(){return y(this.getDateRange())}}function P(){return{getAllLabels:l.getAllLabels.bind(l),isRecognizedPeriod:l.isRecognizedPeriod.bind(l),get:l.get.bind(l),parse:l.parse.bind(l),parseDate:w,format:f,RangePeriod:C,todayIsInRange:y}}function j(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function v(){return P}function j(e,t){t.$on("$locationChangeSuccess",e.updatePeriodParamsFromUrl)}angular.module("piwikApp.service").service("piwik",v),j.$inject=["piwik","$rootScope"],angular.module("piwikApp.service").run(j);n("2342");
+ */l.addCustomPeriod("range",C),
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function k(e,...t){let n=t;return 1===t.length&&t[0]&&t[0]instanceof Array&&([n]=t),window._pk_translate(e,n)}function O(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */
+window.piwik.addCustomPeriod=l.addCustomPeriod.bind(l),window.angular.module("piwikApp.service").factory("piwikPeriods",P);class O{constructor(e){j(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new O(w(e))}static getDisplayText(){return g("Intl_PeriodDay")}getPrettyString(){return f(this.dateInPeriod)}getDateRange(){return[new Date(this.dateInPeriod.getTime()),new Date(this.dateInPeriod.getTime())]}containsToday(){return y(this.getDateRange())}}function D(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */class S{constructor(e){O(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new S(h(e))}static getDisplayText(){return k("Intl_PeriodDay")}getPrettyString(){return d(this.dateInPeriod)}getDateRange(){return[new Date(this.dateInPeriod.getTime()),new Date(this.dateInPeriod.getTime())]}containsToday(){return m(this.getDateRange())}}function T(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */l.addCustomPeriod("day",O);class S{constructor(e){D(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new S(w(e))}static getDisplayText(){return g("Intl_PeriodWeek")}getPrettyString(){const e=this.getDateRange(),t=f(e[0]),r=f(e[1]);return g("General_DateRangeFromTo",[t,r])}getDateRange(){const e=(this.dateInPeriod.getDay()+6)%7,t=new Date(this.dateInPeriod.getTime());t.setDate(this.dateInPeriod.getDate()-e);const r=new Date(t.getTime());return r.setDate(t.getDate()+6),[t,r]}containsToday(){return y(this.getDateRange())}}function k(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */u.addCustomPeriod("day",S);class E{constructor(e){T(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new E(h(e))}static getDisplayText(){return k("Intl_PeriodWeek")}getPrettyString(){const e=this.getDateRange(),t=d(e[0]),n=d(e[1]);return k("General_DateRangeFromTo",[t,n])}getDateRange(){const e=(this.dateInPeriod.getDay()+6)%7,t=new Date(this.dateInPeriod.getTime());t.setDate(this.dateInPeriod.getDate()-e);const n=new Date(t.getTime());return n.setDate(t.getDate()+6),[t,n]}containsToday(){return m(this.getDateRange())}}function C(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */l.addCustomPeriod("week",S);class E{constructor(e){k(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new E(w(e))}static getDisplayText(){return g("Intl_PeriodMonth")}getPrettyString(){const e=g("Intl_Month_Long_StandAlone_"+(this.dateInPeriod.getMonth()+1));return`${e} ${this.dateInPeriod.getFullYear()}`}getDateRange(){const e=new Date(this.dateInPeriod.getTime());e.setDate(1);const t=new Date(this.dateInPeriod.getTime());return t.setDate(1),t.setMonth(t.getMonth()+1),t.setDate(0),[e,t]}containsToday(){return y(this.getDateRange())}}function T(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */u.addCustomPeriod("week",E);class I{constructor(e){C(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new I(h(e))}static getDisplayText(){return k("Intl_PeriodMonth")}getPrettyString(){const e=k("Intl_Month_Long_StandAlone_"+(this.dateInPeriod.getMonth()+1));return`${e} ${this.dateInPeriod.getFullYear()}`}getDateRange(){const e=new Date(this.dateInPeriod.getTime());e.setDate(1);const t=new Date(this.dateInPeriod.getTime());return t.setDate(1),t.setMonth(t.getMonth()+1),t.setDate(0),[e,t]}containsToday(){return m(this.getDateRange())}}function x(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */l.addCustomPeriod("month",E);class x{constructor(e){T(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new x(w(e))}static getDisplayText(){return g("Intl_PeriodYear")}getPrettyString(){return this.dateInPeriod.getFullYear().toString()}getDateRange(){const e=new Date(this.dateInPeriod.getTime());e.setMonth(0),e.setDate(1);const t=new Date(this.dateInPeriod.getTime());return t.setMonth(12),t.setDate(0),[e,t]}containsToday(){return y(this.getDateRange())}}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */u.addCustomPeriod("month",I);class H{constructor(e){x(this,"dateInPeriod",void 0),this.dateInPeriod=e}static parse(e){return new H(h(e))}static getDisplayText(){return k("Intl_PeriodYear")}getPrettyString(){return this.dateInPeriod.getFullYear().toString()}getDateRange(){const e=new Date(this.dateInPeriod.getTime());e.setMonth(0),e.setDate(1);const t=new Date(this.dateInPeriod.getTime());return t.setMonth(12),t.setDate(0),[e,t]}containsToday(){return m(this.getDateRange())}}function R(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */
+function I(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */u.addCustomPeriod("year",H);class A{constructor(e,t,n){R(this,"startDate",void 0),R(this,"endDate",void 0),R(this,"childPeriodType",void 0),this.startDate=e,this.endDate=t,this.childPeriodType=n}static getLastNRange(e,t,n){const r=Math.max(parseInt(t.toString(),10)-1,0);if(Number.isNaN(r))throw new Error("Invalid range strAmount");let a=n?h(n):p(),i=new Date(a.getTime());if("day"===e)i.setDate(i.getDate()-r);else if("week"===e)i.setDate(i.getDate()-7*r);else if("month"===e)i.setDate(1),i.setMonth(i.getMonth()-r);else{if("year"!==e)throw new Error(`Unknown period type '${e}'.`);i.setFullYear(i.getFullYear()-r)}if("day"!==e){const t=u.periods[e].parse(i),n=u.periods[e].parse(a);[i]=t.getDateRange(),[,a]=n.getDateRange()}const o=new Date(1991,7,6);if(i.getTime()-o.getTime()<0)switch(e){case"year":i=new Date(1992,0,1);break;case"month":i=new Date(1991,8,1);break;case"week":i=new Date(1991,8,12);break;case"day":default:i=o;break}return new A(i,a,e)}static getLastNRangeChild(e,t,n){const r=t?h(t):p();let a=new Date(r.getTime()),i=new Date(r.getTime());if("day"===e)a.setDate(a.getDate()-n),i.setDate(i.getDate()-n);else if("week"===e)a.setDate(a.getDate()-7*n),i.setDate(i.getDate()-7*n);else if("month"===e)a.setDate(1),a.setMonth(a.getMonth()-n),i.setDate(1),i.setMonth(i.getMonth()-n);else{if("year"!==e)throw new Error(`Unknown period type '${e}'.`);a.setFullYear(a.getFullYear()-n),i.setFullYear(i.getFullYear()-n)}if("day"!==e){const t=u.periods[e].parse(a),n=u.periods[e].parse(i);[a]=t.getDateRange(),[,i]=n.getDateRange()}const o=new Date(1991,7,6);if(a.getTime()-o.getTime()<0)switch(e){case"year":a=new Date(1992,0,1);break;case"month":a=new Date(1991,8,1);break;case"week":a=new Date(1991,8,12);break;case"day":default:a=o;break}return new A(a,i,e)}static parse(e,t="day"){if(/^previous/.test(e)){const n=A.getLastNRange(t,"2").startDate;return A.getLastNRange(t,e.substring(8),n)}if(/^last/.test(e))return A.getLastNRange(t,e.substring(4));const n=decodeURIComponent(e).split(",");return new A(h(n[0]),h(n[1]),t)}static getDisplayText(){return k("General_DateRangeInPeriodList")}getPrettyString(){const e=d(this.startDate),t=d(this.endDate);return k("General_DateRangeFromTo",[e,t])}getDateRange(){return[this.startDate,this.endDate]}containsToday(){return m(this.getDateRange())}}function F(){return{getAllLabels:u.getAllLabels.bind(u),isRecognizedPeriod:u.isRecognizedPeriod.bind(u),get:u.get.bind(u),parse:u.parse.bind(u),parseDate:h,format:d,RangePeriod:A,todayIsInRange:m}}function N(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}
+ */l.addCustomPeriod("year",x);const{piwik:H,broadcast:N}=window;function F(e,t){try{return l.parse(e,t),!0}catch(r){return!1}}class B{constructor(){I(this,"urlQuery",Object(o["ref"])("")),I(this,"hashQuery",Object(o["ref"])("")),I(this,"urlParsed",Object(o["computed"])(()=>Object(o["readonly"])(N.getValuesFromUrl("?"+this.urlQuery.value,!0)))),I(this,"hashParsed",Object(o["computed"])(()=>Object(o["readonly"])(N.getValuesFromUrl("?"+this.hashQuery.value,!0)))),I(this,"parsed",Object(o["computed"])(()=>Object(o["readonly"])({...this.urlParsed.value,...this.hashParsed.value}))),this.setUrlQuery(window.location.search),this.setHashQuery(window.location.hash),h.on("$locationChangeSuccess",e=>{const t=new URL(e);this.setUrlQuery(t.search.replace(/^\?/,"")),this.setHashQuery(t.hash.replace(/^#/,""))}),this.updatePeriodParamsFromUrl()}updateHash(e){const t="string"!==typeof e?this.stringify(e):e,r=h.helper.getAngularDependency("$location");r.search(t)}getSearchParam(e){const t=window.location.href.split("#"),r=new RegExp(e+"(\\[]|=)");if(t&&t[1]&&r.test(decodeURIComponent(t[1]))){const t=window.broadcast.getValueFromHash(e,window.location.href);if(t||"date"!==e&&"period"!==e&&"idSite"!==e)return t}return window.broadcast.getValueFromUrl(e,window.location.search)}stringify(e){return $.param(e).replace(/%5B%5D/g,"[]")}updatePeriodParamsFromUrl(){let e=this.getSearchParam("date");const t=this.getSearchParam("period");if(!F(t,e))return;if(H.period===t&&H.currentDateString===e)return;H.period=t;const r=l.parse(t,e).getDateRange();H.startDateString=f(r[0]),H.endDateString=f(r[1]),H.updateDateInTitle(e,t),"range"===H.period&&(e=`${H.startDateString},${H.endDateString}`),H.currentDateString=e}setUrlQuery(e){this.urlQuery.value=e.replace(/^\?/,"")}setHashQuery(e){this.hashQuery.value=e.replace(/^[#/?]+/,"")}}const A=new B;var R=A;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function B(e,t){if("abort"===t)return;const n=$("#loadingError");Piwik_Popover.isOpen()&&e&&500===e.status?e&&500===e.status&&$(document.body).html(piwikHelper.escape(e.responseText)):n.show()}u.addCustomPeriod("range",A),
+ */
+function U(){const e={getSearchParam:R.getSearchParam.bind(R)};return e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-window.piwik.addCustomPeriod=u.addCustomPeriod.bind(u),angular.module("piwikApp.service").factory("piwikPeriods",F),window.globalAjaxQueue=[],window.globalAjaxQueue.active=0,window.globalAjaxQueue.clean=function(){for(let e=this.length;e>=0;e-=1)this[e]&&4!==this[e].readyState||this.splice(e,1)},window.globalAjaxQueue.push=function(...e){return this.active+=e.length,this.clean(),Array.prototype.push.call(this,...e)},window.globalAjaxQueue.abort=function(){this.forEach(e=>e&&e.abort&&e.abort()),this.splice(0,this.length),this.active=0};class U{static fetch(e){const t=new U;return t.setFormat("json"),t.addParams({module:"API",format:"json",...e},"get"),t.send()}constructor(){N(this,"format","json"),N(this,"timeout",null),N(this,"callback",null),N(this,"useRegularCallbackInCaseOfError",!1),N(this,"errorCallback",void 0),N(this,"withToken",!1),N(this,"completeCallback",void 0),N(this,"getParams",{}),N(this,"getUrl","?"),N(this,"postParams",{}),N(this,"loadingElement",null),N(this,"errorElement","#ajaxError"),N(this,"requestHandle",null),N(this,"defaultParams",["idSite","period","date","segment"]),this.errorCallback=B}addParams(e,t){"string"===typeof e&&(e=window["broadcast"].getValuesFromUrl(e));const n=["compareSegments","comparePeriods","compareDates"];Object.keys(e).forEach(r=>{const a=e[r];(-1===n.indexOf(r)||a)&&("get"===t.toLowerCase()?this.getParams[r]=a:"post"===t.toLowerCase()&&(this.postParams[r]=a))})}withTokenInUrl(){this.withToken=!0}setUrl(e){this.addParams(broadcast.getValuesFromUrl(e),"GET")}setBulkRequests(...e){const t=e.map(e=>$.param(e));this.addParams({module:"API",method:"API.getBulkRequest",urls:t,format:"json"},"post")}setTimeout(e){this.timeout=e}setCallback(e){this.callback=e}useCallbackInCaseOfError(){this.useRegularCallbackInCaseOfError=!0}redirectOnSuccess(e){this.setCallback(()=>{piwikHelper.redirect(e)})}setErrorCallback(e){this.errorCallback=e}setCompleteCallback(e){this.completeCallback=e}setFormat(e){this.format=e}setLoadingElement(e){this.loadingElement=e||"#ajaxLoadingDiv"}setErrorElement(e){e&&(this.errorElement=e)}useGETDefaultParameter(e){if(e&&this.defaultParams)for(let t=0;t<this.defaultParams.length;t+=1)if(this.defaultParams[t]===e)return!0;return!1}removeDefaultParameter(e){if(e&&this.defaultParams)for(let t=0;t<this.defaultParams.length;t+=1)this.defaultParams[t]===e&&this.defaultParams.splice(t,1)}send(){return $(this.errorElement).length&&$(this.errorElement).hide(),this.loadingElement&&$(this.loadingElement).fadeIn(),this.requestHandle=this.buildAjaxCall(),globalAjaxQueue.push(this.requestHandle),this.requestHandle}abort(){this.requestHandle&&"function"===typeof this.requestHandle.abort&&(this.requestHandle.abort(),this.requestHandle=null)}buildAjaxCall(){const e=this,t=this.mixinDefaultGetParams(this.getParams);let n=this.getUrl;"?"!==n[n.length-1]&&(n+="&"),t.segment&&(n=`${n}segment=${t.segment}&`,delete t.segment),t.date&&(n=`${n}date=${decodeURIComponent(t.date.toString())}&`,delete t.date),n+=$.param(t);const r={type:"POST",async:!0,url:n,dataType:this.format||"json",complete:this.completeCallback,error:function(){globalAjaxQueue.active-=1,e.errorCallback&&e.errorCallback.apply(this,arguments)},success:(e,t,n)=>{if(this.loadingElement&&$(this.loadingElement).hide(),e&&"error"===e.result&&!this.useRegularCallbackInCaseOfError){let t=null,n="toast";if($(this.errorElement).length&&e.message&&($(this.errorElement).show(),t=this.errorElement,n=null),e.message){const r=window["require"]("piwik/UI"),a=new r.Notification;a.show(e.message,{placeat:t,context:"error",type:n,id:"ajaxHelper"}),a.scrollToNotification()}}else this.callback&&this.callback(e,t,n);globalAjaxQueue.active-=1,P.ajaxRequestFinished&&P.ajaxRequestFinished()},data:this.mixinDefaultPostParams(this.postParams),timeout:null!==this.timeout?this.timeout:void 0};return $.ajax(r)}isRequestToApiMethod(){return this.getParams&&"API"===this.getParams.module&&this.getParams.method||this.postParams&&"API"===this.postParams.module&&this.postParams.method}isWidgetizedRequest(){return"Widgetize"===broadcast.getValueFromUrl("module")}getDefaultPostParams(){return this.withToken||this.isRequestToApiMethod()||P.shouldPropagateTokenAuth?{token_auth:P.token_auth,force_api_session:broadcast.isWidgetizeRequestWithoutSession()?0:1}:{}}mixinDefaultPostParams(e){const t=this.getDefaultPostParams(),n={...t,...e};return n}mixinDefaultGetParams(e){const t=o.getSearchParam("segment"),n={idSite:P.idSite||broadcast.getValueFromUrl("idSite"),period:P.period||broadcast.getValueFromUrl("period"),segment:t},r=e;return r.token_auth&&(r.token_auth=null,delete r.token_auth),Object.keys(n).forEach(e=>{this.useGETDefaultParameter(e)&&!r[e]&&!this.postParams[e]&&n[e]&&(r[e]=n[e])}),!this.useGETDefaultParameter("date")||r.date||this.postParams.date||(r.date=P.currentDateString),r}}function M(){return globalAjaxQueue}window.ajaxHelper=U,angular.module("piwikApp.service").service("globalAjaxQueue",M);
+function _(){return h}function V(e,t){t.$oldEmit=t.$emit,t.$emit=function(e,...t){return h.postEvent(e,...t)},t.$oldBroadcast=t.$broadcast,t.$broadcast=function(e,...r){return h.postEventNoEmit(e,...r),t.$oldBroadcast(e,...r)},t.$on("$locationChangeSuccess",e.updatePeriodParamsFromUrl)}function M(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-const V={getSearchParam(e){const t=window.location.href.split("#"),n=new RegExp(e+"(\\[]|=)");if(t&&t[1]&&n.test(decodeURIComponent(t[1]))){const t=window.broadcast.getValueFromHash(e,window.location.href);if(t||"date"!==e&&"period"!==e&&"idSite"!==e)return t}return window.broadcast.getValueFromUrl(e,window.location.search)}};var _=V;
+ */function q(e,t){if("abort"===t)return;if("undefined"===typeof Piwik_Popover)return void console.log("Request failed: "+e.responseText);const r=$("#loadingError");Piwik_Popover.isOpen()&&e&&500===e.status?e&&500===e.status&&$(document.body).html(piwikHelper.escape(e.responseText)):r.show()}H.updatePeriodParamsFromUrl=A.updatePeriodParamsFromUrl.bind(A),U.$inject=[],angular.module("piwikApp.service").service("piwikUrl",U),window.angular.module("piwikApp.service").service("piwik",_),V.$inject=["piwik","$rootScope"],window.angular.module("piwikApp.service").run(V),window.globalAjaxQueue=[],window.globalAjaxQueue.active=0,window.globalAjaxQueue.clean=function(){for(let e=this.length;e>=0;e-=1)this[e]&&4!==this[e].readyState||this.splice(e,1)},window.globalAjaxQueue.push=function(...e){return this.active+=e.length,this.clean(),Array.prototype.push.call(this,...e)},window.globalAjaxQueue.abort=function(){this.forEach(e=>e&&e.abort&&e.abort()),this.splice(0,this.length),this.active=0};class G{static fetch(e){const t=new G;return t.setFormat("json"),t.addParams({module:"API",format:"json",...e},"get"),t.send()}constructor(){M(this,"format","json"),M(this,"timeout",null),M(this,"callback",null),M(this,"useRegularCallbackInCaseOfError",!1),M(this,"errorCallback",void 0),M(this,"withToken",!1),M(this,"completeCallback",void 0),M(this,"getParams",{}),M(this,"getUrl","?"),M(this,"postParams",{}),M(this,"loadingElement",null),M(this,"errorElement","#ajaxError"),M(this,"requestHandle",null),M(this,"defaultParams",["idSite","period","date","segment"]),this.errorCallback=q}addParams(e,t){const r="string"===typeof e?window.broadcast.getValuesFromUrl(e):e,n=["compareSegments","comparePeriods","compareDates"];Object.keys(r).forEach(e=>{const a=r[e];(-1===n.indexOf(e)||a)&&("get"===t.toLowerCase()?this.getParams[e]=a:"post"===t.toLowerCase()&&(this.postParams[e]=a))})}withTokenInUrl(){this.withToken=!0}setUrl(e){this.addParams(broadcast.getValuesFromUrl(e),"GET")}setBulkRequests(...e){const t=e.map(e=>"string"===typeof e?e:$.param(e));this.addParams({module:"API",method:"API.getBulkRequest",urls:t,format:"json"},"post")}setTimeout(e){this.timeout=e}setCallback(e){this.callback=e}useCallbackInCaseOfError(){this.useRegularCallbackInCaseOfError=!0}redirectOnSuccess(e){this.setCallback(()=>{piwikHelper.redirect(e)})}setErrorCallback(e){this.errorCallback=e}setCompleteCallback(e){this.completeCallback=e}setFormat(e){this.format=e}setLoadingElement(e){this.loadingElement=e||"#ajaxLoadingDiv"}setErrorElement(e){e&&(this.errorElement=e)}useGETDefaultParameter(e){if(e&&this.defaultParams)for(let t=0;t<this.defaultParams.length;t+=1)if(this.defaultParams[t]===e)return!0;return!1}removeDefaultParameter(e){if(e&&this.defaultParams)for(let t=0;t<this.defaultParams.length;t+=1)this.defaultParams[t]===e&&this.defaultParams.splice(t,1)}send(){return $(this.errorElement).length&&$(this.errorElement).hide(),this.loadingElement&&$(this.loadingElement).fadeIn(),this.requestHandle=this.buildAjaxCall(),window.globalAjaxQueue.push(this.requestHandle),new Promise((e,t)=>{this.requestHandle.then(e).fail(e=>{"abort"!==e.statusText&&(console.log(`Warning: the ${$.param(this.getParams)} request failed!`),t(e))})})}abort(){this.requestHandle&&"function"===typeof this.requestHandle.abort&&(this.requestHandle.abort(),this.requestHandle=null)}buildAjaxCall(){const e=this,t=this.mixinDefaultGetParams(this.getParams);let r=this.getUrl;"?"!==r[r.length-1]&&(r+="&"),t.segment&&(r=`${r}segment=${t.segment}&`,delete t.segment),t.date&&(r=`${r}date=${decodeURIComponent(t.date.toString())}&`,delete t.date),r+=$.param(t);const n={type:"POST",async:!0,url:r,dataType:this.format||"json",complete:this.completeCallback,error:function(...t){window.globalAjaxQueue.active-=1,e.errorCallback&&e.errorCallback.apply(this,t)},success:(e,t,r)=>{if(this.loadingElement&&$(this.loadingElement).hide(),e&&"error"===e.result&&!this.useRegularCallbackInCaseOfError){let t=null,r="toast";if($(this.errorElement).length&&e.message&&($(this.errorElement).show(),t=this.errorElement,r=null),e.message){const n=window["require"]("piwik/UI"),a=new n.Notification;a.show(e.message,{placeat:t,context:"error",type:r,id:"ajaxHelper"}),a.scrollToNotification()}}else this.callback&&this.callback(e,t,r);window.globalAjaxQueue.active-=1,h.ajaxRequestFinished&&h.ajaxRequestFinished()},data:this.mixinDefaultPostParams(this.postParams),timeout:null!==this.timeout?this.timeout:void 0};return $.ajax(n)}isRequestToApiMethod(){return this.getParams&&"API"===this.getParams.module&&this.getParams.method||this.postParams&&"API"===this.postParams.module&&this.postParams.method}isWidgetizedRequest(){return"Widgetize"===broadcast.getValueFromUrl("module")}getDefaultPostParams(){return this.withToken||this.isRequestToApiMethod()||h.shouldPropagateTokenAuth?{token_auth:h.token_auth,force_api_session:broadcast.isWidgetizeRequestWithoutSession()?0:1}:{}}mixinDefaultPostParams(e){const t=this.getDefaultPostParams(),r={...t,...e};return r}mixinDefaultGetParams(e){const t=R.getSearchParam("segment"),r={idSite:h.idSite?h.idSite.toString():broadcast.getValueFromUrl("idSite"),period:h.period||broadcast.getValueFromUrl("period"),segment:t},n=e;return n.token_auth&&(n.token_auth=null,delete n.token_auth),Object.keys(r).forEach(e=>{this.useGETDefaultParameter(e)&&!n[e]&&!this.postParams[e]&&r[e]&&(n[e]=r[e])}),!this.useGETDefaultParameter("date")||n.date||this.postParams.date||(n.date=h.currentDateString),n}}function L(){return globalAjaxQueue}window.ajaxHelper=G,angular.module("piwikApp.service").service("globalAjaxQueue",L);const Q={ref:"root"};function J(e,t,r,n,a,i){return Object(o["withDirectives"])((Object(o["openBlock"])(),Object(o["createElementBlock"])("div",Q,[Object(o["renderSlot"])(e.$slots,"default")],512)),[[o["vShow"],e.modelValue]])}var z=Object(o["defineComponent"])({props:{modelValue:{type:Boolean,required:!0},element:{type:HTMLElement,required:!1}},emits:["yes","no","closeEnd","close","update:modelValue"],activated(){this.$emit("update:modelValue",!1)},watch:{modelValue(e,t){if(e){const e=this.element||this.$refs.root.firstElementChild;h.helper.modalConfirm(e,{yes:()=>{this.$emit("yes")},no:()=>{this.$emit("no")}},{onCloseEnd:()=>{this.element||this.$refs.root.appendChild(e),this.$emit("update:modelValue",!1),this.$emit("closeEnd")}})}else!1===e&&!0===t&&this.$emit("close")}}});z.render=J;var Y=z;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function q(){const e={getSearchParam:_.getSearchParam.bind(_)};return e}
+ */let W=0;function X(e){const{component:t,scope:r={},events:n={},$inject:a,directiveName:i,transclude:s,mountPointFactory:l,postCreate:c,noScope:d,restrict:u="A"}=e,p=W;s&&(W+=1);const m={};function h(...e){const a={restrict:u,scope:d?void 0:m,compile:function(){return{post:function(a,i,d){const u=s?i.find(`[ng-transclude][counter=${p}]`):null;let m="<root-component";Object.entries(r).forEach(([,e])=>{m+=` :${e.vue}="${e.vue}"`}),Object.entries(n).forEach(e=>{const[t]=e;m+=` @${t}="onEventHandler('${t}', $event)"`}),m+=">",s&&(m+='<div ref="transcludeTarget"/>'),m+="</root-component>";const h=Object(o["createApp"])({template:m,data(){const t={};return Object.entries(r).forEach(([r,n])=>{let o=a[r];"undefined"===typeof o&&"undefined"!==typeof n.default&&(o=n.default instanceof Function?n.default(a,i,d,...e):n.default),t[n.vue]=o}),t},setup(){if(s){const e=Object(o["ref"])(null);return{transcludeTarget:e}}},methods:{onEventHandler(t,r){n[t]&&n[t](r,a,i,d,...e)}}});h.config.globalProperties.$sanitize=window.vueSanitize,h.config.globalProperties.translate=g,h.component("root-component",t);const f=l?l(a,i,d,...e):i[0],b=h.mount(f);Object.entries(r).forEach(([t,r])=>{r.angularJsBind&&a.$watch(t,n=>{"undefined"!==typeof r.default&&"undefined"===typeof n?b[t]=r.default instanceof Function?r.default(a,i,d,...e):r.default:b[t]=n})}),s&&$(b.transcludeTarget).append(u),c&&c(b,a,i,d,...e),i.on("$destroy",()=>{h.unmount()})}}}};return s&&(a.transclude=!0,a.template=`<div ng-transclude counter="${p}"/>`),a}return Object.entries(r).forEach(([e,t])=>{t.vue||(t.vue=e),t.angularJsBind&&(m[e]=t.angularJsBind)}),h.$inject=a||[],angular.module("piwikApp").directive(i,h),h}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-let L;q.$inject=[],angular.module("piwikApp.service").service("piwikUrl",q);const{piwik:G,broadcast:J,piwikHelper:z}=window;function Y(e,t){try{return u.parse(e,t),!0}catch(n){return!1}}G.helper=z,G.broadcast=J,G.updatePeriodParamsFromUrl=function(){let e=_.getSearchParam("date");const t=_.getSearchParam("period");if(!Y(t,e))return;if(G.period===t&&G.currentDateString===e)return;G.period=t;const n=u.parse(t,e).getDateRange();G.startDateString=d(n[0]),G.endDateString=d(n[1]),G.updateDateInTitle(e,t),"range"===G.period&&(e=`${G.startDateString},${G.endDateString}`),G.currentDateString=e},G.updateDateInTitle=function(e,t){if($(".top_controls #periodString").length&&(L=L||document.title,0===L.indexOf(G.siteName))){const n=` - ${u.parse(t,e).getPrettyString()} `;document.title=`${G.siteName}${n}${L.substr(G.siteName.length)}`}},G.hasUserCapability=function(e){return window.angular.isArray(G.userCapabilities)&&-1!==G.userCapabilities.indexOf(e)};const Q=G;var W=Q;
+ */X({component:Y,scope:{show:{vue:"modelValue",default:!1},element:{default:(e,t)=>t[0]}},events:{yes:(e,t,r,n)=>{n.yes&&(t.$eval(n.yes),setTimeout(()=>{t.$apply()},0))},no:(e,t,r,n)=>{n.no&&(t.$eval(n.no),setTimeout(()=>{t.$apply()},0))},close:(e,t,r,n)=>{n.close&&(t.$eval(n.close),setTimeout(()=>{t.$apply()},0))},"update:modelValue":(e,t,r,n,a)=>{setTimeout(()=>{t.$apply(a(n.piwikDialog).assign(t,e))},0)}},$inject:["$parse"],directiveName:"piwikDialog",transclude:!0,mountPointFactory:(e,t)=>{const r=$('<div class="vue-placeholder"/>');return r.appendTo(t),r[0]},postCreate:(e,t,r,n)=>{t.$watch(n.piwikDialog,(t,r)=>{r!==t&&(e.modelValue=t||!1)})},noScope:!0});const K={key:0,class:"title",tabindex:"6"},Z=["href","title"],ee={class:"iconsBar"},te=["href","title"],re=Object(o["createElementVNode"])("span",{class:"icon-help"},null,-1),ne=[re],ae=["title"],oe=Object(o["createElementVNode"])("span",{class:"icon-info"},null,-1),ie=[oe],se={class:"ratingIcons"},le={class:"inlineHelp"},ce=["innerHTML"],de=["href"];function ue(e,t,r,n,a,i){const s=Object(o["resolveComponent"])("RateFeature");return Object(o["openBlock"])(),Object(o["createElementBlock"])("div",{class:"enrichedHeadline",onMouseenter:t[1]||(t[1]=t=>e.showIcons=!0),onMouseleave:t[2]||(t[2]=t=>e.showIcons=!1),ref:"root"},[e.editUrl?Object(o["createCommentVNode"])("",!0):(Object(o["openBlock"])(),Object(o["createElementBlock"])("div",K,[Object(o["renderSlot"])(e.$slots,"default")])),e.editUrl?(Object(o["openBlock"])(),Object(o["createElementBlock"])("a",{key:1,class:"title",href:e.editUrl,title:e.translate("CoreHome_ClickToEditX",e.$sanitize(e.actualFeatureName))},[Object(o["renderSlot"])(e.$slots,"default")],8,Z)):Object(o["createCommentVNode"])("",!0),Object(o["withDirectives"])(Object(o["createElementVNode"])("span",ee,[e.helpUrl&&!e.actualInlineHelp?(Object(o["openBlock"])(),Object(o["createElementBlock"])("a",{key:0,rel:"noreferrer noopener",target:"_blank",class:"helpIcon",href:e.helpUrl,title:e.translate("CoreHome_ExternalHelp")},ne,8,te)):Object(o["createCommentVNode"])("",!0),e.actualInlineHelp?(Object(o["openBlock"])(),Object(o["createElementBlock"])("a",{key:1,onClick:t[0]||(t[0]=t=>e.showInlineHelp=!e.showInlineHelp),class:Object(o["normalizeClass"])(["helpIcon",{active:e.showInlineHelp}]),title:e.translate(e.reportGenerated?"General_HelpReport":"General_Help")},ie,10,ae)):Object(o["createCommentVNode"])("",!0),Object(o["createElementVNode"])("div",se,[Object(o["createVNode"])(s,{title:e.actualFeatureName},null,8,["title"])])],512),[[o["vShow"],e.showIcons||e.showInlineHelp]]),Object(o["withDirectives"])(Object(o["createElementVNode"])("div",le,[Object(o["createElementVNode"])("div",{innerHTML:e.$sanitize(e.actualInlineHelp)},null,8,ce),e.helpUrl?(Object(o["openBlock"])(),Object(o["createElementBlock"])("a",{key:0,rel:"noreferrer noopener",target:"_blank",class:"readMore",href:e.helpUrl},Object(o["toDisplayString"])(e.translate("General_MoreDetails")),9,de)):Object(o["createCommentVNode"])("",!0)],512),[[o["vShow"],e.showInlineHelp]])],544)}const pe=Object(o["defineAsyncComponent"])(()=>new Promise(e=>{window.$(document).ready(()=>{e(window.Feedback.RateFeature)})}));var me=Object(o["defineComponent"])({props:{helpUrl:{type:String,default:""},editUrl:{type:String,default:""},reportGenerated:String,featureName:String,inlineHelp:String},components:{RateFeature:pe},data(){return{showIcons:!1,showInlineHelp:!1,actualFeatureName:this.featureName,actualInlineHelp:this.inlineHelp}},watch:{inlineHelp(e){this.actualInlineHelp=e},featureName(e){this.actualFeatureName=e}},mounted(){const{root:e}=this.$refs;setTimeout(()=>{if(!this.actualInlineHelp){let t=e.querySelector(".title .inlineHelp");if(!t&&e.parentElement.nextElementSibling&&(t=e.parentElement.nextElementSibling.querySelector(".reportDocumentation")),t){const e=t.getAttribute("data-content").trim();e.length&&(this.actualInlineHelp=`<p>${e}</p>`,setTimeout(()=>t.remove(),0))}}this.actualFeatureName||(this.actualFeatureName=e.querySelector(".title").textContent),this.reportGenerated&&l.parse(h.period,h.currentDateString).containsToday()&&window.$(e.querySelector(".report-generated")).tooltip({track:!0,content:this.reportGenerated,items:"div",show:!1,hide:!1})})}});me.render=ue;var he=me;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function X(){return W}function K(e,t){t.$on("$locationChangeSuccess",e.updatePeriodParamsFromUrl)}angular.module("piwikApp.service").service("piwik",X),K.$inject=["piwik","$rootScope"],angular.module("piwikApp.service").run(K);var Z=n("8bbf");const ee={ref:"root"};function te(e,t,n,r,a,i){return Object(Z["withDirectives"])((Object(Z["openBlock"])(),Object(Z["createElementBlock"])("div",ee,[Object(Z["renderSlot"])(e.$slots,"default")],512)),[[Z["vShow"],e.modelValue]])}var ne=Object(Z["defineComponent"])({props:{modelValue:{type:Boolean,required:!0},element:{type:HTMLElement,required:!1}},emits:["yes","no","closeEnd","close","update:modelValue"],setup(){const e=Object(Z["ref"])(null);return{root:e}},activated(){this.$emit("update:modelValue",!1)},watch:{modelValue(e,t){if(e){const e=this.element||this.$refs.root.firstElementChild;P.helper.modalConfirm(e,{yes:()=>{this.$emit("yes")},no:()=>{this.$emit("no")}},{onCloseEnd:()=>{this.element||this.$refs.root.appendChild(e),this.$emit("update:modelValue",!1),this.$emit("closeEnd")}})}else!1===e&&!0===t&&this.$emit("close")}}});ne.render=te;var re=ne;
+ */X({component:he,scope:{helpUrl:{angularJsBind:"@"},editUrl:{angularJsBind:"@"},reportGenerated:{angularJsBind:"@?"},featureName:{angularJsBind:"@"},inlineHelp:{angularJsBind:"@?"}},directiveName:"piwikEnrichedHeadline",transclude:!0});const ge={class:"card",ref:"root"},fe={class:"card-content"},be={key:0,class:"card-title"},we={key:1,class:"card-title"},ye={ref:"content"};function ve(e,t,r,n,a,i){const s=Object(o["resolveComponent"])("EnrichedHeadline");return Object(o["openBlock"])(),Object(o["createElementBlock"])("div",ge,[Object(o["createElementVNode"])("div",fe,[!e.contentTitle||e.actualFeature||e.helpUrl||e.actualHelpText?Object(o["createCommentVNode"])("",!0):(Object(o["openBlock"])(),Object(o["createElementBlock"])("h2",be,Object(o["toDisplayString"])(e.contentTitle),1)),e.contentTitle&&(e.actualFeature||e.helpUrl||e.actualHelpText)?(Object(o["openBlock"])(),Object(o["createElementBlock"])("h2",we,[Object(o["createVNode"])(s,{"feature-name":e.actualFeature,"help-url":e.helpUrl,"inline-help":e.actualHelpText},{default:Object(o["withCtx"])(()=>[Object(o["createTextVNode"])(Object(o["toDisplayString"])(e.contentTitle),1)]),_:1},8,["feature-name","help-url","inline-help"])])):Object(o["createCommentVNode"])("",!0),Object(o["createElementVNode"])("div",ye,[Object(o["renderSlot"])(e.$slots,"default")],512)])],512)}let Ce=null;var Pe=Object(o["defineComponent"])({props:{contentTitle:String,feature:String,helpUrl:String,helpText:String,anchor:String},components:{EnrichedHeadline:he},data(){return{actualFeature:this.feature,actualHelpText:this.helpText}},watch:{feature(e){this.actualFeature=e},helpText(e){this.actualHelpText=e}},mounted(){const{root:e,content:t}=this.$refs;if(this.anchor){const t=document.createElement("a");t.id=this.anchor,e.parentElement.prepend(t)}let r;if(setTimeout(()=>{const e=t.querySelector(".contentHelp");e&&(this.actualHelpText=e.innerHTML,e.remove())},0),!this.actualFeature||!0!==this.actualFeature&&"true"!==this.actualFeature||(this.actualFeature=this.contentTitle),null===Ce&&(Ce=document.querySelector("#content.admin")),Ce&&(r=Ce.offsetTop),r||0===r){const t=e.closest("[piwik-widget-loader]"),n=t?t.offsetTop:e.offsetTop;n-r<17&&(e.style.marginTop=0)}}});Pe.render=ve;var je=Pe;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */let ae=0;function ie(e){const{component:t,scope:n={},events:r={},$inject:a,directiveName:i,transclude:o,mountPointFactory:s,postCreate:l,noScope:c}=e,u=ae;o&&(ae+=1);const d={};function p(...e){const a={restrict:"A",scope:c?void 0:d,compile:function(){return{post:function(a,i,c){const d=o?i.find(`[ng-transclude][counter=${u}]`):null;let p="<root-component";Object.entries(n).forEach(([,e])=>{p+=` :${e.vue}="${e.vue}"`}),Object.entries(r).forEach(e=>{const[t]=e;p+=` @${t}="onEventHandler('${t}', $event)"`}),p+=">",o&&(p+='<div ref="transcludeTarget"/>'),p+="</root-component>";const h=Object(Z["createApp"])({template:p,data(){const t={};return Object.entries(n).forEach(([n,r])=>{let o=a[n];"undefined"===typeof o&&"undefined"!==typeof r.default&&(o=r.default instanceof Function?r.default(a,i,c,...e):r.default),t[r.vue]=o}),t},setup(){if(o){const e=Object(Z["ref"])(null);return{transcludeTarget:e}}},methods:{onEventHandler(t,n){r[t]&&r[t](n,a,i,c,...e)}}});h.config.globalProperties.$sanitize=window.vueSanitize,h.config.globalProperties.translate=k,h.component("root-component",t);const m=s?s(a,i,c,...e):i[0],g=h.mount(m);Object.entries(n).forEach(([t,n])=>{n.angularJsBind&&a.$watch(t,r=>{"undefined"!==typeof n.default&&"undefined"===typeof r?g[t]=n.default instanceof Function?n.default(a,i,c,...e):n.default:g[t]=r})}),o&&$(g.transcludeTarget).append(d),l&&l(g,a,i,c,...e),i.on("$destroy",()=>{h.unmount()})}}}};return o&&(a.transclude=!0,a.template=`<div ng-transclude counter="${u}"/>`),a}return Object.entries(n).forEach(([e,t])=>{t.vue||(t.vue=e),t.angularJsBind&&(d[e]=t.angularJsBind)}),p.$inject=a||[],angular.module("piwikApp").directive(i,p),p}
+ */X({component:je,scope:{contentTitle:{angularJsBind:"@"},feature:{angularJsBind:"@"},helpUrl:{angularJsBind:"@"},helpText:{angularJsBind:"@"},anchor:{angularJsBind:"@?"}},directiveName:"piwikContentBlock",transclude:!0});function Oe(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */ie({component:re,scope:{show:{vue:"modelValue",default:!1},element:{default:(e,t)=>t[0]}},events:{yes:(e,t,n,r)=>{r.yes&&(t.$eval(r.yes),setTimeout(()=>{t.$apply()},0))},no:(e,t,n,r)=>{r.no&&(t.$eval(r.no),setTimeout(()=>{t.$apply()},0))},close:(e,t,n,r)=>{r.close&&(t.$eval(r.close),setTimeout(()=>{t.$apply()},0))},"update:modelValue":(e,t,n,r,a)=>{setTimeout(()=>{t.$apply(a(r.piwikDialog).assign(t,e))},0)}},$inject:["$parse"],directiveName:"piwikDialog",transclude:!0,mountPointFactory:(e,t)=>{const n=$('<div class="vue-placeholder"/>');return n.appendTo(t),n[0]},postCreate:(e,t,n,r)=>{t.$watch(r.piwikDialog,(t,n)=>{n!==t&&(e.modelValue=t||!1)})},noScope:!0});const oe={key:0,class:"title",tabindex:"6"},se=["href","title"],le={class:"iconsBar"},ce=["href","title"],ue=Object(Z["createElementVNode"])("span",{class:"icon-help"},null,-1),de=[ue],pe=["title"],he=Object(Z["createElementVNode"])("span",{class:"icon-info"},null,-1),me=[he],ge={class:"ratingIcons"},fe={class:"inlineHelp"},be=["innerHTML"],we=["href"];function ye(e,t,n,r,a,i){const o=Object(Z["resolveComponent"])("RateFeature");return Object(Z["openBlock"])(),Object(Z["createElementBlock"])("div",{class:"enrichedHeadline",onMouseenter:t[1]||(t[1]=t=>e.showIcons=!0),onMouseleave:t[2]||(t[2]=t=>e.showIcons=!1),ref:"root"},[e.editUrl?Object(Z["createCommentVNode"])("",!0):(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("div",oe,[Object(Z["renderSlot"])(e.$slots,"default")])),e.editUrl?(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("a",{key:1,class:"title",href:e.editUrl,title:e.translate("CoreHome_ClickToEditX",e.$sanitize(e.actualFeatureName))},[Object(Z["renderSlot"])(e.$slots,"default")],8,se)):Object(Z["createCommentVNode"])("",!0),Object(Z["withDirectives"])(Object(Z["createElementVNode"])("span",le,[e.helpUrl&&!e.actualInlineHelp?(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("a",{key:0,rel:"noreferrer noopener",target:"_blank",class:"helpIcon",href:e.helpUrl,title:e.translate("CoreHome_ExternalHelp")},de,8,ce)):Object(Z["createCommentVNode"])("",!0),e.actualInlineHelp?(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("a",{key:1,onClick:t[0]||(t[0]=t=>e.showInlineHelp=!e.showInlineHelp),class:Object(Z["normalizeClass"])(["helpIcon",{active:e.showInlineHelp}]),title:e.translate(e.reportGenerated?"General_HelpReport":"General_Help")},me,10,pe)):Object(Z["createCommentVNode"])("",!0),Object(Z["createElementVNode"])("div",ge,[Object(Z["createVNode"])(o,{title:e.actualFeatureName},null,8,["title"])])],512),[[Z["vShow"],e.showIcons||e.showInlineHelp]]),Object(Z["withDirectives"])(Object(Z["createElementVNode"])("div",fe,[Object(Z["createElementVNode"])("div",{innerHTML:e.$sanitize(e.actualInlineHelp)},null,8,be),e.helpUrl?(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("a",{key:0,rel:"noreferrer noopener",target:"_blank",class:"readMore",href:e.helpUrl},Object(Z["toDisplayString"])(e.translate("General_MoreDetails")),9,we)):Object(Z["createCommentVNode"])("",!0)],512),[[Z["vShow"],e.showInlineHelp]])],544)}const De=Object(Z["defineAsyncComponent"])(()=>new Promise(e=>{window.$(document).ready(()=>{e(window.Feedback.RateFeature)})}));var Pe=Object(Z["defineComponent"])({props:{helpUrl:{type:String,default:""},editUrl:{type:String,default:""},reportGenerated:String,featureName:String,inlineHelp:String},components:{RateFeature:De},data(){return{showIcons:!1,showInlineHelp:!1,actualFeatureName:this.featureName,actualInlineHelp:this.inlineHelp}},setup(){const e=Object(Z["ref"])(null);return{root:e}},watch:{inlineHelp(e){this.actualInlineHelp=e},featureName(e){this.actualFeatureName=e}},mounted(){const{root:e}=this.$refs;setTimeout(()=>{if(!this.actualInlineHelp){let t=e.querySelector(".title .inlineHelp");if(!t&&e.parentElement.nextElementSibling&&(t=e.parentElement.nextElementSibling.querySelector(".reportDocumentation")),t){const e=t.getAttribute("data-content").trim();e.length&&(this.actualInlineHelp=`<p>${e}</p>`,setTimeout(()=>t.remove(),0))}}this.actualFeatureName||(this.actualFeatureName=e.querySelector(".title").textContent),this.reportGenerated&&u.parse(P.period,P.currentDateString).containsToday()&&window.$(e.querySelector(".report-generated")).tooltip({track:!0,content:this.reportGenerated,items:"div",show:!1,hide:!1})})}});Pe.render=ye;var ve=Pe;
+ */class De{get state(){return Object(o["readonly"])(this.segmentState)}constructor(){Oe(this,"segmentState",Object(o["reactive"])({availableSegments:[]})),h.on("piwikSegmentationInited",()=>this.setSegmentState())}setSegmentState(){try{const e=$(".segmentEditorPanel").data("uiControlObject");this.segmentState.availableSegments=e.impl.availableSegments||[]}catch(e){}}}var Se=new De;function ke(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */ie({component:ve,scope:{helpUrl:{angularJsBind:"@"},editUrl:{angularJsBind:"@"},reportGenerated:{angularJsBind:"@?"},featureName:{angularJsBind:"@"},inlineHelp:{angularJsBind:"@?"}},directiveName:"piwikEnrichedHeadline",transclude:!0});const je={class:"card",ref:"root"},ke={class:"card-content"},Oe={key:0,class:"card-title"},Se={key:1,class:"card-title"},Te={ref:"content"};function $e(e,t,n,r,a,i){const o=Object(Z["resolveComponent"])("EnrichedHeadline");return Object(Z["openBlock"])(),Object(Z["createElementBlock"])("div",je,[Object(Z["createElementVNode"])("div",ke,[!e.contentTitle||e.actualFeature||e.helpUrl||e.actualHelpText?Object(Z["createCommentVNode"])("",!0):(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("h2",Oe,Object(Z["toDisplayString"])(e.contentTitle),1)),e.contentTitle&&(e.actualFeature||e.helpUrl||e.actualHelpText)?(Object(Z["openBlock"])(),Object(Z["createElementBlock"])("h2",Se,[Object(Z["createVNode"])(o,{"feature-name":e.actualFeature,"help-url":e.helpUrl,"inline-help":e.actualHelpText},{default:Object(Z["withCtx"])(()=>[Object(Z["createTextVNode"])(Object(Z["toDisplayString"])(e.contentTitle),1)]),_:1},8,["feature-name","help-url","inline-help"])])):Object(Z["createCommentVNode"])("",!0),Object(Z["createElementVNode"])("div",Te,[Object(Z["renderSlot"])(e.$slots,"default")],512)])],512)}let Ee=null;var Ce=Object(Z["defineComponent"])({props:{contentTitle:String,feature:String,helpUrl:String,helpText:String,anchor:String},components:{EnrichedHeadline:ve},data(){return{actualFeature:this.feature,actualHelpText:this.helpText}},setup(){const e=Object(Z["ref"])(null),t=Object(Z["ref"])(null);return{root:e,content:t}},watch:{feature(e){this.actualFeature=e},helpText(e){this.actualHelpText=e}},mounted(){const{root:e,content:t}=this.$refs;if(this.anchor){const t=document.createElement("a");t.id=this.anchor,e.parentElement.prepend(t)}let n;if(setTimeout(()=>{const e=t.querySelector(".contentHelp");e&&(this.actualHelpText=e.innerHTML,e.remove())},0),!this.actualFeature||!0!==this.actualFeature&&"true"!==this.actualFeature||(this.actualFeature=this.contentTitle),null===Ee&&(Ee=document.querySelector("#content.admin")),Ee&&(n=Ee.offsetTop),n||0===n){const t=e.closest("[piwik-widget-loader]"),r=t?t.offsetTop:e.offsetTop;r-n<17&&(e.style.marginTop=0)}}});Ce.render=$e;var Ie=Ce;
+ */const Ee=8,Te=3;function $e(e){return e?e instanceof Array?e:[e]:[]}class xe{constructor(){ke(this,"privateState",Object(o["reactive"])({comparisonsDisabledFor:[]})),ke(this,"state",Object(o["readonly"])(this.privateState)),ke(this,"colors",{}),ke(this,"segmentComparisons",Object(o["computed"])(()=>this.parseSegmentComparisons())),ke(this,"periodComparisons",Object(o["computed"])(()=>this.parsePeriodComparisons())),ke(this,"isEnabled",Object(o["computed"])(()=>this.checkEnabledForCurrentPage())),this.loadComparisonsDisabledFor(),$(()=>{this.colors=this.getAllSeriesColors()}),Object(o["watch"])(()=>this.getComparisons(),()=>h.postEvent("piwikComparisonsChanged"),{deep:!0})}getComparisons(){return this.getSegmentComparisons().concat(this.getPeriodComparisons())}isComparing(){return this.isComparisonEnabled()&&(this.segmentComparisons.value.length>1||this.periodComparisons.value.length>1)}isComparingPeriods(){return this.getPeriodComparisons().length>1}getSegmentComparisons(){return this.isComparisonEnabled()?this.segmentComparisons.value:[]}getPeriodComparisons(){return this.isComparisonEnabled()?this.periodComparisons.value:[]}getSeriesColor(e,t,r=0){const n=this.getComparisonSeriesIndex(t.index,e.index)%Ee;if(0===r)return this.colors["series"+n];const a=r%Te;return this.colors[`series${n}-shade${a}`]}getSeriesColorName(e,t){let r="series"+e%Ee;return t>0&&(r+="-shade"+t%Te),r}isComparisonEnabled(){return this.isEnabled.value}getIndividualComparisonRowIndices(e){const t=this.getSegmentComparisons().length,r=e%t,n=Math.floor(e/t);return{segmentIndex:r,periodIndex:n}}getComparisonSeriesIndex(e,t){const r=this.getSegmentComparisons().length;return e*r+t}getAllComparisonSeries(){const e=[];let t=0;return this.getPeriodComparisons().forEach(r=>{this.getSegmentComparisons().forEach(n=>{e.push({index:t,params:{...n.params,...r.params},color:this.colors["series"+t]}),t+=1})}),e}removeSegmentComparison(e){if(!this.isComparisonEnabled())throw new Error("Comparison disabled.");const t=[...this.segmentComparisons.value];t.splice(e,1);const r={};0===e&&(r.segment=t[0].params.segment),this.updateQueryParamsFromComparisons(t,this.periodComparisons.value,r)}addSegmentComparison(e){if(!this.isComparisonEnabled())throw new Error("Comparison disabled.");const t=this.segmentComparisons.value.concat([{params:e,index:-1,title:""}]);this.updateQueryParamsFromComparisons(t,this.periodComparisons.value)}updateQueryParamsFromComparisons(e,t,r={}){const n={},a={};let o=!1,i=!1;e.forEach(e=>{o?n[e.params.segment]=!0:o=!0}),t.forEach(e=>{i?a[`${e.params.period}|${e.params.date}`]=!0:i=!0});const s=[],l=[];Object.keys(a).forEach(e=>{const t=e.split("|");s.push(t[0]),l.push(t[1])});const c={compareSegments:Object.keys(n),comparePeriods:s,compareDates:l};if(h.helper.isAngularRenderingThePage()){const e=R.hashParsed.value,t={...e,...c,...r};return delete t["compareSegments[]"],delete t["comparePeriods[]"],delete t["compareDates[]"],void(JSON.stringify(t)!==JSON.stringify(e)&&R.updateHash(t))}const d=[];["compareSegments","comparePeriods","compareDates"].forEach(e=>{c[e].length||d.push(e)});const u=R.stringify(r),p=R.stringify(c);window.broadcast.propagateNewPage(u,void 0,p,d)}getAllSeriesColors(){const{ColorManager:e}=h,t=[];for(let r=0;r<Ee;r+=1){t.push("series"+r);for(let e=0;e<Te;e+=1)t.push(`series${r}-shade${e}`)}return e.getColors("comparison-series-color",t)}loadComparisonsDisabledFor(){G.fetch({module:"API",method:"API.getPagesComparisonsDisabledFor"}).then(e=>{this.privateState.comparisonsDisabledFor=e})}parseSegmentComparisons(){const{availableSegments:e}=Se.state,t=[...$e(R.parsed.value.compareSegments)];t.unshift(R.parsed.value.segment||"");const r=[];return t.forEach((t,n)=>{let a;e.forEach(e=>{e.definition!==t&&e.definition!==decodeURIComponent(t)&&decodeURIComponent(e.definition)!==t||(a=e)});let o=a?a.name:g("General_Unknown");""===t.trim()&&(o=g("SegmentEditor_DefaultAllVisits")),r.push({params:{segment:t},title:h.helper.htmlDecode(o),index:n})}),r}parsePeriodComparisons(){const e=[...$e(R.parsed.value.comparePeriods)],t=[...$e(R.parsed.value.compareDates)];e.unshift(R.parsed.value.period),t.unshift(R.parsed.value.date);const r=[];for(let a=0;a<Math.min(t.length,e.length);a+=1){let o;try{o=l.parse(e[a],t[a]).getPrettyString()}catch(n){o=g("General_Error")}r.push({params:{date:t[a],period:e[a]},title:o,index:a})}return r}checkEnabledForCurrentPage(){const e=R.parsed.value.category||R.parsed.value.module,t=R.parsed.value.subcategory||R.parsed.value.action,r=`${e}.${t}`,n=-1===this.privateState.comparisonsDisabledFor.indexOf(r)&&-1===this.privateState.comparisonsDisabledFor.indexOf(e+".*");return document.documentElement.classList.toggle("comparisonsDisabled",!n),n}}var Ie=new xe;const He={key:0,ref:"root",class:"matomo-comparisons"},Ne={class:"comparison-type"},Fe=["title"],Be=["href"],Ae=["title"],Re={class:"comparison-period-label"},Ue=["onClick"],_e=["title"],Ve={class:"loadingPiwik",style:{display:"none"}},Me=["alt"];function qe(e,t,r,n,a,i){return e.isComparing?(Object(o["openBlock"])(),Object(o["createElementBlock"])("div",He,[Object(o["createElementVNode"])("h3",null,Object(o["toDisplayString"])(e.translate("General_Comparisons")),1),(Object(o["openBlock"])(!0),Object(o["createElementBlock"])(o["Fragment"],null,Object(o["renderList"])(e.segmentComparisons,(t,r)=>(Object(o["openBlock"])(),Object(o["createElementBlock"])("div",{class:"comparison card",key:t.index},[Object(o["createElementVNode"])("div",Ne,Object(o["toDisplayString"])(e.translate("General_Segment")),1),Object(o["createElementVNode"])("div",{class:"title",title:t.title+"<br/>"+decodeURIComponent(t.params.segment)},[Object(o["createElementVNode"])("a",{target:"_blank",href:e.getUrlToSegment(t.params.segment)},Object(o["toDisplayString"])(t.title),9,Be)],8,Fe),(Object(o["openBlock"])(!0),Object(o["createElementBlock"])(o["Fragment"],null,Object(o["renderList"])(e.periodComparisons,r=>(Object(o["openBlock"])(),Object(o["createElementBlock"])("div",{class:"comparison-period",key:r.index,title:e.getComparisonTooltip(t,r)},[Object(o["createElementVNode"])("span",{class:"comparison-dot",style:Object(o["normalizeStyle"])({"background-color":e.getSeriesColor(t,r)})},null,4),Object(o["createElementVNode"])("span",Re,Object(o["toDisplayString"])(r.title)+" ("+Object(o["toDisplayString"])(e.getComparisonPeriodType(r))+") ",1)],8,Ae))),128)),e.segmentComparisons.length>1?(Object(o["openBlock"])(),Object(o["createElementBlock"])("a",{key:0,class:"remove-button",onClick:t=>e.removeSegmentComparison(r)},[Object(o["createElementVNode"])("span",{class:"icon icon-close",title:e.translate("General_ClickToRemoveComp")},null,8,_e)],8,Ue)):Object(o["createCommentVNode"])("",!0)]))),128)),Object(o["createElementVNode"])("div",Ve,[Object(o["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif",alt:e.translate("General_LoadingData")},null,8,Me),Object(o["createTextVNode"])(" "+Object(o["toDisplayString"])(e.translate("General_LoadingData")),1)])],512)):Object(o["createCommentVNode"])("",!0)}var Ge=Object(o["defineComponent"])({props:{},data(){return{comparisonTooltips:null}},setup(){const e=Object(o["computed"])(()=>Ie.isComparing()),t=Object(o["computed"])(()=>Ie.getSegmentComparisons()),r=Object(o["computed"])(()=>Ie.getPeriodComparisons()),n=Ie.getSeriesColor.bind(Ie);return{isComparing:e,segmentComparisons:t,periodComparisons:r,getSeriesColor:n}},methods:{comparisonHasSegment(e){return"undefined"!==typeof e.params.segment},removeSegmentComparison(e){window.$(this.$refs.root).tooltip("destroy"),Ie.removeSegmentComparison(e)},getComparisonPeriodType(e){const{period:t}=e.params;if("range"===t)return g("CoreHome_PeriodRange");const r=g(`Intl_Period${t.substring(0,1).toUpperCase()}${t.substring(1)}`);return r.substring(0,1).toUpperCase()+r.substring(1)},getComparisonTooltip(e,t){if(this.comparisonTooltips&&Object.keys(this.comparisonTooltips).length)return(this.comparisonTooltips[t.index]||{})[e.index]},getUrlToSegment(e){const t={...R.hashParsed.value};return delete t.comparePeriods,delete t.compareDates,delete t.compareSegments,t.segment=e,`${window.location.search}#?${R.stringify(t)}`},setUpTooltips(){const{$:e}=window;e(this.$refs.root).tooltip({track:!0,content:function(){const t=e(this).attr("title");return window.vueSanitize(t.replace(/\n/g,"<br />"))},show:{delay:200,duration:200},hide:!1})},onComparisonsChanged(){if(this.comparisonTooltips=null,!Ie.isComparing())return;const e=Ie.getPeriodComparisons(),t=Ie.getSegmentComparisons();G.fetch({method:"API.getProcessedReport",apiModule:"VisitsSummary",apiAction:"get",compare:"1",compareSegments:R.getSearchParam("compareSegments"),comparePeriods:R.getSearchParam("comparePeriods"),compareDates:R.getSearchParam("compareDates"),format_metrics:"1"}).then(r=>{this.comparisonTooltips={},e.forEach(e=>{this.comparisonTooltips[e.index]={},t.forEach(t=>{const n=this.generateComparisonTooltip(r,e,t);this.comparisonTooltips[e.index][t.index]=n})})})},generateComparisonTooltip(e,t,r){if(!e.reportData.comparisons)return"";const n=Ie.getComparisonSeriesIndex(t.index,0),a=e.reportData.comparisons[n],o=Ie.getComparisonSeriesIndex(t.index,r.index),i=e.reportData.comparisons[o],s=e.reportData.comparisons[r.index];let l='<div class="comparison-card-tooltip">',c=(i.nb_visits/a.nb_visits*100).toFixed(2);return c+="%",l+=g("General_ComparisonCardTooltip1",[`'${i.compareSegmentPretty}'`,i.comparePeriodPretty,c,i.nb_visits.toString(),a.nb_visits.toString()]),t.index>0&&(l+="<br/><br/>",l+=g("General_ComparisonCardTooltip2",[i.nb_visits_change.toString(),s.compareSegmentPretty,s.comparePeriodPretty])),l+="</div>",l}},updated(){setTimeout(()=>this.setUpTooltips())},mounted(){h.on("piwikComparisonsChanged",()=>{this.onComparisonsChanged()}),this.onComparisonsChanged(),setTimeout(()=>this.setUpTooltips())},beforeUnmount(){try{window.$(this.refs.root).tooltip("destroy")}catch(e){}}});Ge.render=qe;var Le=Ge;
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */ie({component:Ie,scope:{contentTitle:{angularJsBind:"@"},feature:{angularJsBind:"@"},helpUrl:{angularJsBind:"@"},helpText:{angularJsBind:"@"},anchor:{angularJsBind:"@?"}},directiveName:"piwikContentBlock",transclude:!0});const xe={class:"loadingPiwik"},He=Object(Z["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif",alt:""},null,-1);function Re(e,t,n,r,a,i){return Object(Z["withDirectives"])((Object(Z["openBlock"])(),Object(Z["createElementBlock"])("div",xe,[He,Object(Z["createElementVNode"])("span",null,Object(Z["toDisplayString"])(e.loadingMessage),1)],512)),[[Z["vShow"],e.loading]])}var Ae=Object(Z["defineComponent"])({props:{loading:{type:Boolean,required:!0,default:!1},loadingMessage:{type:String,required:!1,default:k("General_LoadingData")}}});Ae.render=Re;var Fe=Ae,Ne=ie({component:Fe,scope:{loading:{vue:"loading",angularJsBind:"<"},loadingMessage:{vue:"loadingMessage",angularJsBind:"<",default:()=>k("General_LoadingData")}},$inject:[],directiveName:"piwikActivityIndicator"});
+ */function Qe(){return Ie}Qe.$inject=[],angular.module("piwikApp.service").factory("piwikComparisonsService",Qe);X({component:Le,directiveName:"piwikComparisons",restrict:"E"});const Je={class:"loadingPiwik"},ze=Object(o["createElementVNode"])("img",{src:"plugins/Morpheus/images/loading-blue.gif",alt:""},null,-1);function Ye(e,t,r,n,a,i){return Object(o["withDirectives"])((Object(o["openBlock"])(),Object(o["createElementBlock"])("div",Je,[ze,Object(o["createElementVNode"])("span",null,Object(o["toDisplayString"])(e.loadingMessage),1)],512)),[[o["vShow"],e.loading]])}var We=Object(o["defineComponent"])({props:{loading:{type:Boolean,required:!0,default:!1},loadingMessage:{type:String,required:!1,default:g("General_LoadingData")}}});We.render=Ye;var Xe=We,Ke=X({component:Xe,scope:{loading:{vue:"loading",angularJsBind:"<"},loadingMessage:{vue:"loadingMessage",angularJsBind:"<",default:()=>g("General_LoadingData")}},$inject:[],directiveName:"piwikActivityIndicator"});
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */function Be(e,t,n,r,a,i){return Object(Z["openBlock"])(),Object(Z["createElementBlock"])("div",{class:Object(Z["normalizeClass"])(["alert",{["alert-"+e.severity]:!0}])},[Object(Z["renderSlot"])(e.$slots,"default")],2)}var Ue=Object(Z["defineComponent"])({props:{severity:{type:String,required:!0}}});Ue.render=Be;var Me=Ue,Ve=ie({component:Me,scope:{severity:{vue:"severity",angularJsBind:"@piwikAlert"}},directiveName:"piwikAlert",transclude:!0});
+ */function Ze(e,t,r,n,a,i){return Object(o["openBlock"])(),Object(o["createElementBlock"])("div",{class:Object(o["normalizeClass"])(["alert",{["alert-"+e.severity]:!0}])},[Object(o["renderSlot"])(e.$slots,"default")],2)}var et=Object(o["defineComponent"])({props:{severity:{type:String,required:!0}}});et.render=Ze;var tt=et,rt=X({component:tt,scope:{severity:{vue:"severity",angularJsBind:"@piwikAlert"}},directiveName:"piwikAlert",transclude:!0});
/*!
* Matomo - free/libre analytics platform
*
diff --git a/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts b/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts
index 09eeaac874..b1bf30ca7f 100644
--- a/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts
+++ b/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts
@@ -5,15 +5,16 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
+import jqXHR = JQuery.jqXHR;
import MatomoUrl from '../MatomoUrl/MatomoUrl';
import Matomo from '../Matomo/Matomo';
-window.globalAjaxQueue = [] as GlobalAjaxQueue;
+window.globalAjaxQueue = [] as unknown as GlobalAjaxQueue;
window.globalAjaxQueue.active = 0;
window.globalAjaxQueue.clean = function globalAjaxQueueClean() {
for (let i = this.length; i >= 0; i -= 1) {
- if (!this[i] || this[i].readyState === 4) {
+ if (!this[i] || this[i]!.readyState === 4) {
this.splice(i, 1);
}
}
@@ -39,8 +40,6 @@ window.globalAjaxQueue.abort = function globalAjaxQueueAbort() {
this.active = 0;
};
-type ParameterValue = string | number | null | undefined | ParameterValue[];
-type Parameters = {[name: string]: ParameterValue | Parameters};
type AnyFunction = (...params:any[]) => any; // eslint-disable-line
/**
@@ -52,6 +51,11 @@ function defaultErrorCallback(deferred: XMLHttpRequest, status: string): void {
return;
}
+ if (typeof Piwik_Popover === 'undefined') {
+ console.log(`Request failed: ${deferred.responseText}`); // mostly for tests
+ return;
+ }
+
const loadingError = $('#loadingError');
if (Piwik_Popover.isOpen() && deferred && deferred.status === 500) {
if (deferred && deferred.status === 500) {
@@ -65,7 +69,7 @@ function defaultErrorCallback(deferred: XMLHttpRequest, status: string): void {
/**
* Global ajax helper to handle requests within Matomo
*/
-export default class AjaxHelper {
+export default class AjaxHelper<T = any> { // eslint-disable-line
/**
* Format of response
*/
@@ -74,12 +78,12 @@ export default class AjaxHelper {
/**
* A timeout for the request which will override any global timeout
*/
- timeout = null;
+ timeout: number|null = null;
/**
* Callback function to be executed on success
*/
- callback: AnyFunction = null;
+ callback: AnyFunction|null = null;
/**
* Use this.callback if an error is returned
@@ -100,13 +104,13 @@ export default class AjaxHelper {
*
* @deprecated use the jquery promise API
*/
- completeCallback: AnyFunction;
+ completeCallback?: AnyFunction;
/**
* Params to be passed as GET params
* @see ajaxHelper.mixinDefaultGetParams
*/
- getParams: Parameters = {};
+ getParams: QueryParameters = {};
/**
* Base URL used in the AJAX request. Can be set by setUrl.
@@ -124,7 +128,7 @@ export default class AjaxHelper {
* Params to be passed as GET params
* @see ajaxHelper.mixinDefaultPostParams
*/
- postParams: Parameters = {};
+ postParams: QueryParameters = {};
/**
* Element to be displayed while loading
@@ -139,13 +143,13 @@ export default class AjaxHelper {
/**
* Handle for current request
*/
- requestHandle: XMLHttpRequest|JQuery.jqXHR|null = null;
+ requestHandle: JQuery.jqXHR|null = null;
defaultParams = ['idSite', 'period', 'date', 'segment'];
// helper method entry point
- static fetch(params: Parameters): JQuery.jqXHR {
- const helper = new AjaxHelper();
+ static fetch<R = any>(params: QueryParameters): Promise<R> { // eslint-disable-line
+ const helper = new AjaxHelper<R>();
helper.setFormat('json');
helper.addParams({ module: 'API', format: 'json', ...params }, 'get');
return helper.send();
@@ -159,15 +163,13 @@ export default class AjaxHelper {
* Adds params to the request.
* If params are given more then once, the latest given value is used for the request
*
- * @param params
+ * @param initialParams
* @param type type of given parameters (POST or GET)
* @return {void}
*/
- addParams(params: Parameters|string, type: string): void {
- if (typeof params === 'string') {
- // TODO: add global types for broadcast (multiple uses below)
- params = window['broadcast'].getValuesFromUrl(params); // eslint-disable-line
- }
+ addParams(initialParams: QueryParameters|string, type: string): void {
+ const params: QueryParameters = typeof initialParams === 'string'
+ ? window.broadcast.getValuesFromUrl(initialParams) : initialParams;
const arrayParams = ['compareSegments', 'comparePeriods', 'compareDates'];
Object.keys(params).forEach((key) => {
@@ -201,8 +203,8 @@ export default class AjaxHelper {
* Gets this helper instance ready to send a bulk request. Each argument to this
* function is a single request to use.
*/
- setBulkRequests(...urls: string[]): void {
- const urlsProcessed = urls.map((u) => $.param(u));
+ setBulkRequests(...urls: Array<string|QueryParameters>): void {
+ const urlsProcessed = urls.map((u) => (typeof u === 'string' ? u : $.param(u)));
this.addParams({
module: 'API',
@@ -246,7 +248,7 @@ export default class AjaxHelper {
* @param [params] to modify in redirect url
* @return {void}
*/
- redirectOnSuccess(params: Parameters): void {
+ redirectOnSuccess(params: QueryParameters): void {
this.setCallback(() => {
piwikHelper.redirect(params);
});
@@ -333,7 +335,7 @@ export default class AjaxHelper {
/**
* Send the request
*/
- send(): JQuery.jqXHR {
+ send(): Promise<T> {
if ($(this.errorElement).length) {
$(this.errorElement).hide();
}
@@ -343,9 +345,17 @@ export default class AjaxHelper {
}
this.requestHandle = this.buildAjaxCall();
- globalAjaxQueue.push(this.requestHandle);
+ window.globalAjaxQueue.push(this.requestHandle);
- return this.requestHandle;
+ return new Promise<T>((resolve, reject) => {
+ this.requestHandle!.then(resolve).fail((xhr: jqXHR) => {
+ if (xhr.statusText !== 'abort') {
+ console.log(`Warning: the ${$.param(this.getParams)} request failed!`);
+
+ reject(xhr);
+ }
+ });
+ });
}
/**
@@ -387,21 +397,21 @@ export default class AjaxHelper {
url,
dataType: this.format || 'json',
complete: this.completeCallback,
- error: function errorCallback() {
- globalAjaxQueue.active -= 1;
+ error: function errorCallback(...args: any[]) { // eslint-disable-line
+ window.globalAjaxQueue.active -= 1;
if (self.errorCallback) {
- self.errorCallback.apply(this, arguments); // eslint-disable-line
+ self.errorCallback.apply(this, args);
}
},
- success: (response, status, request) => {
+ success: (response: any, status: string, request: jqXHR) => { // eslint-disable-line
if (this.loadingElement) {
$(this.loadingElement).hide();
}
if (response && response.result === 'error' && !this.useRegularCallbackInCaseOfError) {
let placeAt = null;
- let type = 'toast';
+ let type: string|null = 'toast';
if ($(this.errorElement).length && response.message) {
$(this.errorElement).show();
placeAt = this.errorElement;
@@ -423,7 +433,7 @@ export default class AjaxHelper {
this.callback(response, status, request);
}
- globalAjaxQueue.active -= 1;
+ window.globalAjaxQueue.active -= 1;
if (Matomo.ajaxRequestFinished) {
Matomo.ajaxRequestFinished();
}
@@ -462,7 +472,7 @@ export default class AjaxHelper {
*
* @param params parameter object
*/
- private mixinDefaultPostParams(params): Parameters {
+ private mixinDefaultPostParams(params: QueryParameters): QueryParameters {
const defaultParams = this.getDefaultPostParams();
const mergedParams = {
@@ -478,11 +488,11 @@ export default class AjaxHelper {
*
* @param params parameter object
*/
- private mixinDefaultGetParams(originalParams): Parameters {
+ private mixinDefaultGetParams(originalParams: QueryParameters): QueryParameters {
const segment = MatomoUrl.getSearchParam('segment');
- const defaultParams = {
- idSite: Matomo.idSite || broadcast.getValueFromUrl('idSite'),
+ const defaultParams: Record<string, string> = {
+ idSite: Matomo.idSite ? Matomo.idSite.toString() : broadcast.getValueFromUrl('idSite'),
period: Matomo.period || broadcast.getValueFromUrl('period'),
segment,
};
diff --git a/plugins/CoreHome/vue/src/Comparisons/Comparisons.adapter.ts b/plugins/CoreHome/vue/src/Comparisons/Comparisons.adapter.ts
new file mode 100644
index 0000000000..845c965081
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Comparisons/Comparisons.adapter.ts
@@ -0,0 +1,24 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+import createAngularJsAdapter from '../createAngularJsAdapter';
+import ComparisonsStoreInstance from './Comparisons.store.instance';
+import Comparisons from './Comparisons.vue';
+
+function ComparisonFactory() {
+ return ComparisonsStoreInstance;
+}
+
+ComparisonFactory.$inject = [];
+
+angular.module('piwikApp.service').factory('piwikComparisonsService', ComparisonFactory);
+
+export default createAngularJsAdapter({
+ component: Comparisons,
+ directiveName: 'piwikComparisons',
+ restrict: 'E',
+});
diff --git a/plugins/CoreHome/vue/src/Comparisons/Comparisons.less b/plugins/CoreHome/vue/src/Comparisons/Comparisons.less
new file mode 100644
index 0000000000..6b73255b5f
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Comparisons/Comparisons.less
@@ -0,0 +1,78 @@
+.matomo-comparisons {
+ h3 {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .comparison {
+ display: inline-block;
+ min-width: 164px;
+ margin-right: 16px;
+ padding: 14px;
+ background-color: white;
+ margin-bottom: 16px;
+ position: relative;
+ }
+
+ .comparison-type {
+ font-weight: bold;
+ text-transform: uppercase;
+ font-size: .7em;
+ color: #999;
+ }
+
+ .remove-button {
+ font-size: .6em;
+ color: #666;
+ position: absolute;
+ right: 12px;
+ top: 12px;
+ }
+
+ .title {
+ font-size: 1.1rem;
+ margin-top: 4px;
+ margin-bottom: 12px;
+
+ overflow-x: hidden;
+ max-width: 250px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ a {
+ color: #333;
+ }
+ }
+
+ .comparison-period {
+ margin-top: 4px;
+
+ > span {
+ display: inline-block;
+ }
+
+ .comparison-dot {
+ width: 1em;
+ height: 1em;
+ display: inline-block;
+ border-radius: .5em;
+ }
+
+ .comparison-period-label {
+ position: relative;
+ top: -3px;
+ margin-left: 6.5px;
+ display: inline-block;
+ font-size: .85rem;
+ font-style: italic;
+ }
+ }
+}
+
+.comparison-card-tooltip {
+ p {
+ font-size: 1.1em;
+ line-height: 1.3em;
+ color: #fff;
+ }
+} \ No newline at end of file
diff --git a/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.instance.ts b/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.instance.ts
new file mode 100644
index 0000000000..4e1a2b38ab
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.instance.ts
@@ -0,0 +1,3 @@
+import ComparisonsStore from './Comparisons.store';
+
+export default new ComparisonsStore();
diff --git a/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.spec.ts b/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.spec.ts
new file mode 100644
index 0000000000..97e1ad3f22
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.spec.ts
@@ -0,0 +1,457 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+import nock from 'nock';
+import '../Periods/Day';
+import '../Periods/Week';
+import '../Periods/Month';
+import '../Periods/Year';
+import '../Periods/Range';
+import '../Matomo/Matomo.adapter'; // for $rootScope.$oldEmit
+import ComparisonsStore from './Comparisons.store';
+import MatomoUrl from '../MatomoUrl/MatomoUrl';
+
+describe('CoreHome/Comparisons.store', () => {
+ const DISABLED_PAGES = [
+ 'MyModule1.disabledPage',
+ 'MyModule2.disabledPage2',
+ 'MyModule3.*',
+ ];
+ let piwikComparisonsService: ComparisonsStore;
+ let oldWindowHash: string;
+ let nockScope: nock.Scope;
+ let oldColorManager: ColorManagerService;
+
+ function wait() {
+ return new Promise(resolve => setTimeout(resolve, 0));
+ }
+
+ function angularApply() {
+ window.angular.element(document).injector().get('$rootScope').$apply();
+ }
+
+ async function setHash(search: string) {
+ MatomoUrl.updateHash(search);
+ angularApply();
+ await wait();
+
+ // more than one required for all callbacks to finish
+ while (!piwikComparisonsService.state.comparisonsDisabledFor.length) {
+ await wait();
+ }
+ }
+
+ beforeAll(() => {
+ nockScope = nock('http://localhost')
+ .persist()
+ .post('/')
+ .query((query) => {
+ return query.method === 'API.getPagesComparisonsDisabledFor';
+ })
+ .reply(200, JSON.stringify(DISABLED_PAGES));
+ });
+ beforeAll(() => {
+ // so piwikHelper.isAngularRenderingThePage will return true
+ document.body.innerHTML = document.body.innerHTML + '<div piwik-reporting-page />';
+ });
+ beforeAll(async () => {
+ await new Promise<void>((resolve) => {
+ window.angular.element(() => {
+ window.angular.bootstrap(document, ['piwikApp']);
+ resolve();
+ });
+ });
+ });
+
+ beforeEach(() => {
+ oldWindowHash = window.location.hash;
+ });
+ beforeEach(() => {
+ oldColorManager = window.piwik.ColorManager;
+ window.piwik.ColorManager = {
+ getColors(ns: string, colors: string[]) {
+ const result: {[key: string]: string} = {};
+ colors.forEach((name: string) => {
+ result[name] = `${ns}.${name}`;
+ });
+ return result;
+ }
+ } as unknown as ColorManagerService;
+ });
+ beforeEach(() => {
+ angularApply(); // necessary for some reason... doesn't work in beforeAll(), just beforeEach()
+ });
+ beforeEach(() => {
+ piwikComparisonsService = new ComparisonsStore();
+ });
+ afterEach(() => {
+ window.piwik.ColorManager = oldColorManager;
+ window.location.hash = oldWindowHash;
+ });
+
+ afterAll(() => {
+ nockScope.done();
+ });
+
+ describe('#getComparisons()', () => {
+ it('should return all comparisons in URL', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getComparisons()).toEqual([
+ {
+ params: {
+ segment: 'abcdefg',
+ },
+ title: 'General_Unknown',
+ index: 0,
+ },
+ {
+ params: {
+ segment: 'comparedsegment',
+ },
+ title: 'General_Unknown',
+ index: 1,
+ },
+ {
+ params: {
+ segment: '',
+ },
+ title: 'SegmentEditor_DefaultAllVisits',
+ index: 2,
+ },
+ {
+ params: {
+ date: '2018-01-02',
+ period: 'day'
+ },
+ title: '2018-01-02',
+ index: 0,
+ },
+ {
+ params: {
+ date: '2018-03-04',
+ period: 'week'
+ },
+ title: 'General_DateRangeFromTo',
+ index: 1,
+ },
+ ]);
+ });
+
+ it('should return base params if there are no comparisons', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg');
+
+ expect(piwikComparisonsService.getComparisons()).toEqual([
+ {
+ params: {
+ segment: 'abcdefg'
+ },
+ title: 'General_Unknown',
+ index: 0,
+ },
+ {
+ params: {
+ date: '2018-01-02',
+ period: 'day'
+ },
+ title: '2018-01-02',
+ index: 0,
+ },
+ ]);
+ });
+ it('should return nothing if comparison is not enabled for the page', async () => {
+ await setHash('category=MyModule1&subcategory=disabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getComparisons()).toEqual([]);
+ });
+ });
+
+ describe('#removeSegmentComparison()', () => {
+ it('should remove an existing segment comparison from the URL', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ piwikComparisonsService.removeSegmentComparison(1);
+ angularApply();
+ await wait();
+
+ expect(window.location.href).toEqual('http://localhost/#?category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates%5B%5D=2018-03-04&comparePeriods%5B%5D=week&compareSegments%5B%5D=');
+ });
+
+ it('should change the base comparison if the first segment is removed', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ piwikComparisonsService.removeSegmentComparison(0);
+ angularApply();
+ await wait();
+
+ expect(window.location.href).toEqual('http://localhost/#?category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=comparedsegment&compareDates%5B%5D=2018-03-04&comparePeriods%5B%5D=week&compareSegments%5B%5D=');
+ });
+ });
+
+ describe('#addSegmentComparison()', () => {
+ it('should add a new segment comparison to the URL', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment');
+
+ piwikComparisonsService.addSegmentComparison({
+ segment: 'newsegment',
+ });
+ angularApply();
+ await wait();
+
+ expect(piwikComparisonsService.getComparisons()).toEqual([
+ {"params":{"segment":""},"title":"SegmentEditor_DefaultAllVisits","index":0},
+ {"params":{"segment":"comparedsegment"},"title":"General_Unknown","index":1},
+ {"params":{"segment":"newsegment"},"title":"General_Unknown","index":2},
+ {"params":{"date":"2018-01-02","period":"day"},"title":"2018-01-02","index":0},
+ {"params":{"date":"2018-03-04","period":"week"},"title":"General_DateRangeFromTo","index":1},
+ ]);
+ });
+
+ it('should add the all visits segment to the URL', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment');
+
+ piwikComparisonsService.addSegmentComparison({
+ segment: '',
+ });
+ angularApply();
+ await wait();
+
+ expect(piwikComparisonsService.getComparisons()).toEqual([
+ {"params":{"segment":"abcdefg"},"title":"General_Unknown","index":0},
+ {"params":{"segment":"comparedsegment"},"title":"General_Unknown","index":1},
+ {"params":{"segment":""},"title":"SegmentEditor_DefaultAllVisits","index":2},
+ {"params":{"date":"2018-01-02","period":"day"},"title":"2018-01-02","index":0},
+ {"params":{"date":"2018-03-04","period":"week"},"title":"General_DateRangeFromTo","index":1}
+ ]);
+ });
+ });
+
+ describe('#isComparisonEnabled()', () => {
+ it('should return true if comparison is enabled for the page', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment');
+
+ expect(piwikComparisonsService.isComparisonEnabled()).toBe(true);
+ });
+
+ it('should return false if comparison is disabled for the page', async () => {
+ await setHash('category=MyModule2&subcategory=disabledPage2&date=2018-01-02&period=day&segment=&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment');
+
+ expect(piwikComparisonsService.isComparisonEnabled()).toBe(false);
+ });
+
+ it('should return false if comparison is disabled for the entire category', async () => {
+ await setHash('category=MyModule3&subcategory=enabledPage&date=2018-01-02&period=day&segment=&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment');
+
+ expect(piwikComparisonsService.isComparisonEnabled()).toBe(false);
+ });
+ });
+
+ describe('#getSegmentComparisons()', () => {
+ it('should return the segment comparisons only', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getSegmentComparisons()).toEqual([
+ {"params":{"segment":"abcdefg"},"title":"General_Unknown","index":0},
+ {"params":{"segment":"comparedsegment"},"title":"General_Unknown","index":1},
+ {"params":{"segment":""},"title":"SegmentEditor_DefaultAllVisits","index":2}
+ ]);
+ });
+
+ it('should return nothing if comparison is not enabled', async () => {
+ await setHash('category=MyModule1&subcategory=disabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getSegmentComparisons()).toEqual([]);
+ });
+ });
+
+ describe('#getPeriodComparisons()', () => {
+ it('should return the period comparisons only', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getPeriodComparisons()).toEqual([
+ {
+ params: {
+ date: '2018-01-02',
+ period: 'day',
+ },
+ title: '2018-01-02',
+ index: 0,
+ },
+ {
+ params: {
+ date: '2018-03-04',
+ period: 'week',
+ },
+ title: 'General_DateRangeFromTo',
+ index: 1,
+ },
+ ]);
+ });
+
+ it('should return nothing if comparison is not enabled', async () => {
+ await setHash('category=MyModule1&subcategory=disabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getPeriodComparisons()).toEqual([]);
+ });
+ });
+
+ describe('#getAllComparisonSeries()', () => {
+ it('should return all individual comparison serieses', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getAllComparisonSeries()).toEqual([
+ {
+ index: 0,
+ params: {
+ segment: 'abcdefg',
+ date: '2018-01-02',
+ period: 'day',
+ },
+ color: 'comparison-series-color.series0',
+ },
+ {
+ "index":1,
+ "params": {
+ "segment":"comparedsegment",
+ "date":"2018-01-02",
+ "period":"day"
+ },
+ color: 'comparison-series-color.series1',
+ },
+ {
+ "index":2,
+ "params": {
+ "segment":"",
+ "date":"2018-01-02",
+ "period":"day"
+ },
+ color: 'comparison-series-color.series2',
+ },
+ {
+ "index":3,
+ "params": {
+ "segment":"abcdefg",
+ "date":"2018-03-04",
+ "period":"week"
+ },
+ color: 'comparison-series-color.series3',
+ },
+ {
+ "index":4,
+ "params": {
+ "segment":"comparedsegment",
+ "date":"2018-03-04",
+ "period":"week"
+ },
+ color: 'comparison-series-color.series4',
+ },
+ {
+ "index":5,
+ "params": {
+ "segment":"",
+ "date":"2018-03-04",
+ "period":"week"
+ },
+ color: 'comparison-series-color.series5',
+ },
+ ]);
+ });
+
+ it('should return nothing if comparison is not enabled', async () => {
+ await setHash('category=MyModule1&subcategory=disabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getAllComparisonSeries()).toEqual([]);
+ });
+ });
+
+ describe('#isComparing()', () => {
+ it('should return true if there are comparison parameters present', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.isComparing()).toBe(true);
+ });
+
+ it('should return true if there are segment comparisons but no period comparisons', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.isComparing()).toBe(true);
+ });
+
+ it('should return true if there are period comparisons but no segment comparisons', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week');
+
+ expect(piwikComparisonsService.isComparing()).toBe(true);
+ });
+
+ it('should return false if there are no comparison parameters present', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg');
+
+ expect(piwikComparisonsService.isComparing()).toBe(false);
+
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day');
+
+ expect(piwikComparisonsService.isComparing()).toBe(false);
+ });
+
+ it('should return false if comparison is not enabled', async () => {
+ await setHash('category=MyModule1&subcategory=disabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.isComparing()).toBe(false);
+ });
+ });
+
+ describe('#isComparingPeriods()', () => {
+ it('should return true if there are periods being compared', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.isComparingPeriods()).toBe(true);
+ });
+
+ it('should return false if there are no periods being compared, just segments', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.isComparingPeriods()).toBe(false);
+ });
+
+ it('should return false if there is nothing being compared', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg');
+
+ expect(piwikComparisonsService.isComparingPeriods()).toBe(false);
+ });
+
+ it('should return false if comparing is not enabled', async () => {
+ await setHash('category=MyModule1&subcategory=disabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.isComparingPeriods()).toBe(false);
+ });
+ });
+
+ describe('#getIndividualComparisonRowIndices()', () => {
+ it('should calculate the segment/period index from the given series index', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getIndividualComparisonRowIndices(3)).toEqual({
+ segmentIndex: 0,
+ periodIndex: 1,
+ });
+
+ expect(piwikComparisonsService.getIndividualComparisonRowIndices(0)).toEqual({
+ segmentIndex: 0,
+ periodIndex: 0,
+ });
+ });
+ });
+
+ describe('#getComparisonSeriesIndex()', () => {
+ it('should return the comparison series index from the given segment & period indices', async () => {
+ await setHash('category=MyModule1&subcategory=enabledPage&date=2018-01-02&period=day&segment=abcdefg&compareDates[]=2018-03-04&comparePeriods[]=week&compareSegments[]=comparedsegment&compareSegments[]=');
+
+ expect(piwikComparisonsService.getComparisonSeriesIndex(1, 1)).toEqual(4);
+
+ expect(piwikComparisonsService.getComparisonSeriesIndex(0, 1)).toEqual(1);
+ });
+ });
+});
diff --git a/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.ts b/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.ts
new file mode 100644
index 0000000000..f3204f163a
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Comparisons/Comparisons.store.ts
@@ -0,0 +1,411 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+import {
+ reactive,
+ watch,
+ computed,
+ readonly,
+} from 'vue';
+import MatomoUrl from '../MatomoUrl/MatomoUrl';
+import Matomo from '../Matomo/Matomo';
+import translate from '../translate';
+import Periods from '../Periods/Periods';
+import AjaxHelper from '../AjaxHelper/AjaxHelper';
+import SegmentsStore from '../Segmentation/Segments.store';
+
+const SERIES_COLOR_COUNT = 8;
+const SERIES_SHADE_COUNT = 3;
+
+export interface SegmentComparison {
+ params: {
+ segment: string,
+ },
+ title: string,
+ index: number,
+}
+
+export interface PeriodComparison {
+ params: {
+ period: string,
+ date: string,
+ },
+ title: string,
+ index: number,
+}
+
+export interface AnyComparison {
+ params: { [name: string]: string },
+ title: string,
+ index: number,
+}
+
+export interface ComparisonsStoreState {
+ comparisonsDisabledFor: string[];
+}
+
+export interface ComparisonSeriesInfo {
+ index: number;
+ params: { [key: string]: string };
+ color: string;
+}
+
+function wrapArray<T>(values: T | T[]): T[] {
+ if (!values) {
+ return [];
+ }
+ return values instanceof Array ? values : [values];
+}
+
+export default class ComparisonsStore {
+ private privateState = reactive<ComparisonsStoreState>({
+ comparisonsDisabledFor: [],
+ });
+
+ readonly state = readonly(this.privateState); // for tests
+
+ private colors: { [key: string]: string } = {};
+
+ readonly segmentComparisons = computed(() => this.parseSegmentComparisons());
+
+ readonly periodComparisons = computed(() => this.parsePeriodComparisons());
+
+ readonly isEnabled = computed(() => this.checkEnabledForCurrentPage());
+
+ constructor() {
+ this.loadComparisonsDisabledFor();
+
+ $(() => {
+ this.colors = this.getAllSeriesColors() as { [key: string]: string };
+ });
+
+ watch(
+ () => this.getComparisons(),
+ () => Matomo.postEvent('piwikComparisonsChanged'),
+ { deep: true },
+ );
+ }
+
+ getComparisons(): AnyComparison[] {
+ return (this.getSegmentComparisons() as AnyComparison[])
+ .concat(this.getPeriodComparisons() as AnyComparison[]);
+ }
+
+ isComparing(): boolean {
+ return this.isComparisonEnabled()
+ // first two in each array are for the currently selected segment/period
+ && (this.segmentComparisons.value.length > 1
+ || this.periodComparisons.value.length > 1);
+ }
+
+ isComparingPeriods(): boolean {
+ return this.getPeriodComparisons().length > 1; // first is currently selected period
+ }
+
+ getSegmentComparisons(): SegmentComparison[] {
+ if (!this.isComparisonEnabled()) {
+ return [];
+ }
+
+ return this.segmentComparisons.value;
+ }
+
+ getPeriodComparisons(): PeriodComparison[] {
+ if (!this.isComparisonEnabled()) {
+ return [];
+ }
+
+ return this.periodComparisons.value;
+ }
+
+ getSeriesColor(
+ segmentComparison: SegmentComparison,
+ periodComparison: PeriodComparison,
+ metricIndex = 0,
+ ): string {
+ const seriesIndex = this.getComparisonSeriesIndex(
+ periodComparison.index,
+ segmentComparison.index,
+ ) % SERIES_COLOR_COUNT;
+
+ if (metricIndex === 0) {
+ return this.colors[`series${seriesIndex}`];
+ }
+
+ const shadeIndex = metricIndex % SERIES_SHADE_COUNT;
+ return this.colors[`series${seriesIndex}-shade${shadeIndex}`];
+ }
+
+ getSeriesColorName(seriesIndex: number, metricIndex: number): string {
+ let colorName = `series${(seriesIndex % SERIES_COLOR_COUNT)}`;
+ if (metricIndex > 0) {
+ colorName += `-shade${(metricIndex % SERIES_SHADE_COUNT)}`;
+ }
+ return colorName;
+ }
+
+ isComparisonEnabled(): boolean {
+ return this.isEnabled.value;
+ }
+
+ getIndividualComparisonRowIndices(seriesIndex: number): {
+ segmentIndex: number,
+ periodIndex: number,
+ } {
+ const segmentCount = this.getSegmentComparisons().length;
+ const segmentIndex = seriesIndex % segmentCount;
+ const periodIndex = Math.floor(seriesIndex / segmentCount);
+
+ return {
+ segmentIndex,
+ periodIndex,
+ };
+ }
+
+ getComparisonSeriesIndex(periodIndex: number, segmentIndex: number): number {
+ const segmentCount = this.getSegmentComparisons().length;
+ return periodIndex * segmentCount + segmentIndex;
+ }
+
+ getAllComparisonSeries(): ComparisonSeriesInfo[] {
+ const seriesInfo: ComparisonSeriesInfo[] = [];
+
+ let seriesIndex = 0;
+ this.getPeriodComparisons().forEach((periodComp) => {
+ this.getSegmentComparisons().forEach((segmentComp) => {
+ seriesInfo.push({
+ index: seriesIndex,
+ params: { ...segmentComp.params, ...periodComp.params },
+ color: this.colors[`series${seriesIndex}`],
+ });
+ seriesIndex += 1;
+ });
+ });
+
+ return seriesInfo;
+ }
+
+ removeSegmentComparison(index: number): void {
+ if (!this.isComparisonEnabled()) {
+ throw new Error('Comparison disabled.');
+ }
+
+ const newComparisons: SegmentComparison[] = [...this.segmentComparisons.value];
+ newComparisons.splice(index, 1);
+
+ const extraParams: {[key: string]: string} = {};
+ if (index === 0) {
+ extraParams.segment = newComparisons[0].params.segment;
+ }
+
+ this.updateQueryParamsFromComparisons(
+ newComparisons,
+ this.periodComparisons.value,
+ extraParams,
+ );
+ }
+
+ addSegmentComparison(params: { [name: string]: string }): void {
+ if (!this.isComparisonEnabled()) {
+ throw new Error('Comparison disabled.');
+ }
+
+ const newComparisons = this.segmentComparisons.value
+ .concat([{ params, index: -1, title: '' } as SegmentComparison]);
+ this.updateQueryParamsFromComparisons(newComparisons, this.periodComparisons.value);
+ }
+
+ private updateQueryParamsFromComparisons(
+ segmentComparisons: SegmentComparison[],
+ periodComparisons: PeriodComparison[],
+ extraParams = {},
+ ) {
+ // get unique segments/periods/dates from new Comparisons
+ const compareSegments: {[key: string]: boolean} = {};
+ const comparePeriodDatePairs: {[key: string]: boolean} = {};
+
+ let firstSegment = false;
+ let firstPeriod = false;
+
+ segmentComparisons.forEach((comparison) => {
+ if (firstSegment) {
+ compareSegments[comparison.params.segment] = true;
+ } else {
+ firstSegment = true;
+ }
+ });
+
+ periodComparisons.forEach((comparison) => {
+ if (firstPeriod) {
+ comparePeriodDatePairs[`${comparison.params.period}|${comparison.params.date}`] = true;
+ } else {
+ firstPeriod = true;
+ }
+ });
+
+ const comparePeriods: string[] = [];
+ const compareDates: string[] = [];
+ Object.keys(comparePeriodDatePairs).forEach((pair) => {
+ const parts = pair.split('|');
+ comparePeriods.push(parts[0]);
+ compareDates.push(parts[1]);
+ });
+
+ const compareParams: {[key: string]: string[]} = {
+ compareSegments: Object.keys(compareSegments),
+ comparePeriods,
+ compareDates,
+ };
+
+ // change the page w/ these new param values
+ if (Matomo.helper.isAngularRenderingThePage()) {
+ const search = MatomoUrl.hashParsed.value;
+
+ const newSearch: {[key: string]: string|string[]} = {
+ ...search,
+ ...compareParams,
+ ...extraParams,
+ };
+
+ delete newSearch['compareSegments[]'];
+ delete newSearch['comparePeriods[]'];
+ delete newSearch['compareDates[]'];
+
+ if (JSON.stringify(newSearch) !== JSON.stringify(search)) {
+ MatomoUrl.updateHash(newSearch);
+ }
+
+ return;
+ }
+
+ const paramsToRemove: string[] = [];
+ ['compareSegments', 'comparePeriods', 'compareDates'].forEach((name) => {
+ if (!compareParams[name].length) {
+ paramsToRemove.push(name);
+ }
+ });
+
+ // angular is not rendering the page (ie, we are in the embedded dashboard) or we need to change
+ // the segment
+ const url = MatomoUrl.stringify(extraParams);
+ const strHash = MatomoUrl.stringify(compareParams);
+
+ window.broadcast.propagateNewPage(url, undefined, strHash, paramsToRemove);
+ }
+
+ private getAllSeriesColors() {
+ const { ColorManager } = Matomo;
+ const seriesColorNames = [];
+
+ for (let i = 0; i < SERIES_COLOR_COUNT; i += 1) {
+ seriesColorNames.push(`series${i}`);
+ for (let j = 0; j < SERIES_SHADE_COUNT; j += 1) {
+ seriesColorNames.push(`series${i}-shade${j}`);
+ }
+ }
+
+ return ColorManager.getColors('comparison-series-color', seriesColorNames);
+ }
+
+ private loadComparisonsDisabledFor() {
+ AjaxHelper.fetch({
+ module: 'API',
+ method: 'API.getPagesComparisonsDisabledFor',
+ }).then((result) => {
+ this.privateState.comparisonsDisabledFor = result;
+ });
+ }
+
+ private parseSegmentComparisons(): SegmentComparison[] {
+ const { availableSegments } = SegmentsStore.state;
+
+ const compareSegments: string[] = [
+ ...wrapArray(MatomoUrl.parsed.value.compareSegments as string[]),
+ ];
+
+ // add base comparisons
+ compareSegments.unshift(MatomoUrl.parsed.value.segment as string || '');
+
+ const newSegmentComparisons: SegmentComparison[] = [];
+ compareSegments.forEach((segment, idx) => {
+ let storedSegment!: { definition: string, name: string };
+
+ availableSegments.forEach((s) => {
+ if (s.definition === segment
+ || s.definition === decodeURIComponent(segment)
+ || decodeURIComponent(s.definition) === segment
+ ) {
+ storedSegment = s;
+ }
+ });
+
+ let segmentTitle = storedSegment ? storedSegment.name : translate('General_Unknown');
+ if (segment.trim() === '') {
+ segmentTitle = translate('SegmentEditor_DefaultAllVisits');
+ }
+
+ newSegmentComparisons.push({
+ params: {
+ segment,
+ },
+ title: Matomo.helper.htmlDecode(segmentTitle),
+ index: idx,
+ });
+ });
+
+ return newSegmentComparisons;
+ }
+
+ private parsePeriodComparisons(): PeriodComparison[] {
+ const comparePeriods: string[] = [
+ ...wrapArray(MatomoUrl.parsed.value.comparePeriods as string[]),
+ ];
+
+ const compareDates: string[] = [
+ ...wrapArray(MatomoUrl.parsed.value.compareDates as string[]),
+ ];
+
+ comparePeriods.unshift(MatomoUrl.parsed.value.period as string);
+ compareDates.unshift(MatomoUrl.parsed.value.date as string);
+
+ const newPeriodComparisons: PeriodComparison[] = [];
+ for (let i = 0; i < Math.min(compareDates.length, comparePeriods.length); i += 1) {
+ let title;
+ try {
+ title = Periods.parse(comparePeriods[i], compareDates[i]).getPrettyString();
+ } catch (e) {
+ title = translate('General_Error');
+ }
+
+ newPeriodComparisons.push({
+ params: {
+ date: compareDates[i],
+ period: comparePeriods[i],
+ },
+ title,
+ index: i,
+ });
+ }
+
+ return newPeriodComparisons;
+ }
+
+ private checkEnabledForCurrentPage() {
+ // category/subcategory is not included on top bar pages, so in that case we use module/action
+ const category = MatomoUrl.parsed.value.category || MatomoUrl.parsed.value.module;
+ const subcategory = MatomoUrl.parsed.value.subcategory
+ || MatomoUrl.parsed.value.action;
+
+ const id = `${category}.${subcategory}`;
+ const isEnabled = this.privateState.comparisonsDisabledFor.indexOf(id) === -1
+ && this.privateState.comparisonsDisabledFor.indexOf(`${category}.*`) === -1;
+
+ document.documentElement.classList.toggle('comparisonsDisabled', !isEnabled);
+
+ return isEnabled;
+ }
+}
diff --git a/plugins/CoreHome/vue/src/Comparisons/Comparisons.vue b/plugins/CoreHome/vue/src/Comparisons/Comparisons.vue
new file mode 100644
index 0000000000..7639c2e620
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Comparisons/Comparisons.vue
@@ -0,0 +1,264 @@
+<!--
+ Matomo - free/libre analytics platform
+ @link https://matomo.org
+ @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+-->
+
+<template>
+ <div v-if="isComparing" ref="root" class="matomo-comparisons">
+ <h3>{{ translate('General_Comparisons') }}</h3>
+ <div
+ class="comparison card"
+ v-for="(comparison, $index) in segmentComparisons"
+ :key="comparison.index"
+ >
+ <div class="comparison-type">{{ translate('General_Segment') }}</div>
+ <div
+ class="title"
+ :title="comparison.title + '<br/>' + decodeURIComponent(comparison.params.segment)"
+ >
+ <a
+ target="_blank"
+ :href="getUrlToSegment(comparison.params.segment)"
+ >
+ {{ comparison.title }}
+ </a>
+ </div>
+ <div
+ class="comparison-period"
+ v-for="periodComparison in periodComparisons"
+ :key="periodComparison.index"
+ :title="getComparisonTooltip(comparison, periodComparison)"
+ >
+ <span
+ class="comparison-dot"
+ :style="{
+ 'background-color': getSeriesColor(comparison, periodComparison)
+ }"
+ />
+ <span class="comparison-period-label">
+ {{ periodComparison.title }} ({{ getComparisonPeriodType(periodComparison) }})
+ </span>
+ </div>
+ <a
+ class="remove-button"
+ v-on:click="removeSegmentComparison($index)"
+ v-if="segmentComparisons.length > 1"
+ >
+ <span
+ class="icon icon-close"
+ :title="translate('General_ClickToRemoveComp')"
+ />
+ </a>
+ </div>
+ <div
+ class="loadingPiwik"
+ style="display:none;"
+ >
+ <img
+ src="plugins/Morpheus/images/loading-blue.gif"
+ :alt="translate('General_LoadingData')"
+ />
+ {{ translate('General_LoadingData') }}
+ </div>
+ </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, computed } from 'vue';
+import { AnyComparison } from './Comparisons.store';
+import ComparisonsStoreInstance from './Comparisons.store.instance';
+import Matomo from '../Matomo/Matomo';
+import MatomoUrl from '../MatomoUrl/MatomoUrl';
+import AjaxHelper from '../AjaxHelper/AjaxHelper';
+import translate from '../translate';
+
+interface ProcessedReportComparison {
+ compareSegmentPretty: string;
+ comparePeriodPretty: string;
+ nb_visits: number;
+ nb_visits_change: number;
+}
+
+interface ProcessedReportData {
+ comparisons?: ProcessedReportComparison[];
+}
+
+interface ProcessedReportResponse {
+ reportData: ProcessedReportData;
+}
+
+export default defineComponent({
+ props: {
+ },
+ data() {
+ return {
+ comparisonTooltips: null,
+ };
+ },
+ setup() {
+ // accessing has to be done through a computed property so we can use the computed
+ // instance directly in the template. unfortunately, vue won't register to changes.
+ const isComparing = computed(() => ComparisonsStoreInstance.isComparing());
+ const segmentComparisons = computed(() => ComparisonsStoreInstance.getSegmentComparisons());
+ const periodComparisons = computed(() => ComparisonsStoreInstance.getPeriodComparisons());
+ const getSeriesColor = ComparisonsStoreInstance.getSeriesColor.bind(ComparisonsStoreInstance);
+ return {
+ isComparing,
+ segmentComparisons,
+ periodComparisons,
+ getSeriesColor,
+ };
+ },
+ methods: {
+ comparisonHasSegment(comparison: AnyComparison) {
+ return typeof comparison.params.segment !== 'undefined';
+ },
+ removeSegmentComparison(index: number) {
+ // otherwise the tooltip will be stuck on the screen
+ window.$(this.$refs.root).tooltip('destroy');
+ ComparisonsStoreInstance.removeSegmentComparison(index);
+ },
+ getComparisonPeriodType(comparison: AnyComparison) {
+ const { period } = comparison.params;
+ if (period === 'range') {
+ return translate('CoreHome_PeriodRange');
+ }
+ const periodStr = translate(
+ `Intl_Period${period.substring(0, 1).toUpperCase()}${period.substring(1)}`,
+ );
+ return periodStr.substring(0, 1).toUpperCase() + periodStr.substring(1);
+ },
+ getComparisonTooltip(
+ segmentComparison: AnyComparison,
+ periodComparison: AnyComparison,
+ ): string|undefined {
+ if (!this.comparisonTooltips
+ || !Object.keys(this.comparisonTooltips).length
+ ) {
+ return undefined;
+ }
+
+ return (this.comparisonTooltips[periodComparison.index] || {})[segmentComparison.index];
+ },
+ getUrlToSegment(segment: string) {
+ const hash = { ...MatomoUrl.hashParsed.value };
+ delete hash.comparePeriods;
+ delete hash.compareDates;
+ delete hash.compareSegments;
+ hash.segment = segment;
+ return `${window.location.search}#?${MatomoUrl.stringify(hash)}`;
+ },
+ setUpTooltips() {
+ const { $ } = window;
+ $(this.$refs.root).tooltip({
+ track: true,
+ content: function transformTooltipContent() {
+ const title = $(this).attr('title');
+ return window.vueSanitize(title.replace(/\n/g, '<br />'));
+ },
+ show: { delay: 200, duration: 200 },
+ hide: false,
+ });
+ },
+ onComparisonsChanged() {
+ this.comparisonTooltips = null;
+
+ if (!ComparisonsStoreInstance.isComparing()) {
+ return;
+ }
+
+ const periodComparisons = ComparisonsStoreInstance.getPeriodComparisons();
+ const segmentComparisons = ComparisonsStoreInstance.getSegmentComparisons();
+ AjaxHelper.fetch({
+ method: 'API.getProcessedReport',
+ apiModule: 'VisitsSummary',
+ apiAction: 'get',
+ compare: '1',
+ compareSegments: MatomoUrl.getSearchParam('compareSegments'),
+ comparePeriods: MatomoUrl.getSearchParam('comparePeriods'),
+ compareDates: MatomoUrl.getSearchParam('compareDates'),
+ format_metrics: '1',
+ }).then((report) => {
+ this.comparisonTooltips = {};
+ periodComparisons.forEach((periodComp) => {
+ this.comparisonTooltips[periodComp.index] = {};
+
+ segmentComparisons.forEach((segmentComp) => {
+ const tooltip = this.generateComparisonTooltip(report, periodComp, segmentComp);
+ this.comparisonTooltips[periodComp.index][segmentComp.index] = tooltip;
+ });
+ });
+ });
+ },
+ generateComparisonTooltip(
+ visitsSummary: ProcessedReportResponse,
+ periodComp: AnyComparison,
+ segmentComp: AnyComparison,
+ ): string {
+ if (!visitsSummary.reportData.comparisons) { // sanity check
+ return '';
+ }
+
+ const firstRowIndex = ComparisonsStoreInstance.getComparisonSeriesIndex(
+ periodComp.index,
+ 0,
+ );
+
+ const firstRow = visitsSummary.reportData.comparisons[firstRowIndex];
+
+ const comparisonRowIndex = ComparisonsStoreInstance.getComparisonSeriesIndex(
+ periodComp.index,
+ segmentComp.index,
+ );
+ const comparisonRow = visitsSummary.reportData.comparisons[comparisonRowIndex];
+
+ const firstPeriodRow = visitsSummary.reportData.comparisons[segmentComp.index];
+
+ let tooltip = '<div class="comparison-card-tooltip">';
+
+ let visitsPercent = ((comparisonRow.nb_visits / firstRow.nb_visits) * 100)
+ .toFixed(2);
+ visitsPercent = `${visitsPercent}%`;
+
+ tooltip += translate('General_ComparisonCardTooltip1', [
+ `'${comparisonRow.compareSegmentPretty}'`,
+ comparisonRow.comparePeriodPretty,
+ visitsPercent,
+ comparisonRow.nb_visits.toString(),
+ firstRow.nb_visits.toString(),
+ ]);
+ if (periodComp.index > 0) {
+ tooltip += '<br/><br/>';
+ tooltip += translate('General_ComparisonCardTooltip2', [
+ comparisonRow.nb_visits_change.toString(),
+ firstPeriodRow.compareSegmentPretty,
+ firstPeriodRow.comparePeriodPretty,
+ ]);
+ }
+
+ tooltip += '</div>';
+ return tooltip;
+ },
+ },
+ updated() {
+ setTimeout(() => this.setUpTooltips());
+ },
+ mounted() {
+ Matomo.on('piwikComparisonsChanged', () => {
+ this.onComparisonsChanged();
+ });
+
+ this.onComparisonsChanged();
+
+ setTimeout(() => this.setUpTooltips());
+ },
+ beforeUnmount() {
+ try {
+ window.$(this.refs.root).tooltip('destroy');
+ } catch (e) {
+ // ignore
+ }
+ },
+});
+</script>
diff --git a/plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue b/plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue
index 47774a4f39..12a89d770b 100644
--- a/plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue
+++ b/plugins/CoreHome/vue/src/ContentBlock/ContentBlock.vue
@@ -31,7 +31,7 @@
</template>
<script lang="ts">
-import { defineComponent, ref } from 'vue';
+import { defineComponent } from 'vue';
import EnrichedHeadline from '../EnrichedHeadline/EnrichedHeadline.vue';
let adminContent: HTMLElement|null = null;
@@ -53,15 +53,6 @@ export default defineComponent({
actualHelpText: this.helpText,
};
},
- setup() {
- const root = ref<HTMLElement>(null);
- const content = ref<HTMLElement>(null);
-
- return {
- root,
- content,
- };
- },
watch: {
feature(newValue: string) {
this.actualFeature = newValue;
diff --git a/plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue b/plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue
index 4adb7a43d3..f7d8cd7912 100644
--- a/plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue
+++ b/plugins/CoreHome/vue/src/EnrichedHeadline/EnrichedHeadline.vue
@@ -71,7 +71,6 @@
import {
defineComponent,
defineAsyncComponent,
- ref,
} from 'vue';
import Matomo from '../Matomo/Matomo';
import Periods from '../Periods/Periods';
@@ -143,13 +142,6 @@ export default defineComponent({
actualInlineHelp: this.inlineHelp,
};
},
- setup() {
- const root = ref<HTMLElement>(null);
-
- return {
- root,
- };
- },
watch: {
inlineHelp(newValue: string) {
this.actualInlineHelp = newValue;
diff --git a/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts b/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts
index e76adb190b..8ea591fca7 100644
--- a/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts
+++ b/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts
@@ -5,18 +5,31 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
+import { IAngularEvent, IRootScopeService } from 'angular';
import Matomo from './Matomo';
function piwikService() {
return Matomo;
}
-angular.module('piwikApp.service').service('piwik', piwikService);
+window.angular.module('piwikApp.service').service('piwik', piwikService);
+
+function initPiwikService(piwik: PiwikGlobal, $rootScope: IRootScopeService) {
+ // overwrite $rootScope so all events also go through Matomo.postEvent(...) too.
+ ($rootScope as any).$oldEmit = $rootScope.$emit; // eslint-disable-line
+ $rootScope.$emit = function emitWrapper(name: string, ...args: any[]): IAngularEvent { // eslint-disable-line
+ return Matomo.postEvent(name, ...args);
+ };
+
+ ($rootScope as any).$oldBroadcast = $rootScope.$broadcast; // eslint-disable-line
+ $rootScope.$broadcast = function broadcastWrapper(name: string, ...args: any[]): IAngularEvent { // eslint-disable-line
+ Matomo.postEventNoEmit(name, ...args);
+ return ($rootScope as any).$oldBroadcast(name, ...args); // eslint-disable-line
+ };
-function initPiwikService(piwik, $rootScope) {
$rootScope.$on('$locationChangeSuccess', piwik.updatePeriodParamsFromUrl);
}
initPiwikService.$inject = ['piwik', '$rootScope'];
-angular.module('piwikApp.service').run(initPiwikService);
+window.angular.module('piwikApp.service').run(initPiwikService);
diff --git a/plugins/CoreHome/vue/src/Matomo/Matomo.ts b/plugins/CoreHome/vue/src/Matomo/Matomo.ts
index 2a705f665e..85d74dfb3b 100644
--- a/plugins/CoreHome/vue/src/Matomo/Matomo.ts
+++ b/plugins/CoreHome/vue/src/Matomo/Matomo.ts
@@ -5,9 +5,8 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-import MatomoUrl from '../MatomoUrl/MatomoUrl';
+import { IAngularEvent } from 'angular';
import Periods from '../Periods/Periods';
-import { format } from '../Periods/utilities';
let originalTitle: string;
@@ -16,45 +15,6 @@ const { piwik, broadcast, piwikHelper } = window;
piwik.helper = piwikHelper;
piwik.broadcast = broadcast;
-function isValidPeriod(periodStr: string, dateStr: string) {
- try {
- Periods.parse(periodStr, dateStr);
- return true;
- } catch (e) {
- return false;
- }
-}
-
-piwik.updatePeriodParamsFromUrl = function updatePeriodParamsFromUrl() {
- let date = MatomoUrl.getSearchParam('date');
- const period = MatomoUrl.getSearchParam('period');
- if (!isValidPeriod(period, date)) {
- // invalid data in URL
- return;
- }
-
- if (piwik.period === period && piwik.currentDateString === date) {
- // this period / date is already loaded
- return;
- }
-
- piwik.period = period;
-
- const dateRange = Periods.parse(period, date).getDateRange();
- piwik.startDateString = format(dateRange[0]);
- piwik.endDateString = format(dateRange[1]);
-
- piwik.updateDateInTitle(date, period);
-
- // do not set anything to previousN/lastN, as it's more useful to plugins
- // to have the dates than previousN/lastN.
- if (piwik.period === 'range') {
- date = `${piwik.startDateString},${piwik.endDateString}`;
- }
-
- piwik.currentDateString = date;
-};
-
piwik.updateDateInTitle = function updateDateInTitle(date: string, period: string) {
if (!$('.top_controls #periodString').length) {
return;
@@ -74,5 +34,40 @@ piwik.hasUserCapability = function hasUserCapability(capability: string) {
&& piwik.userCapabilities.indexOf(capability) !== -1;
};
+piwik.on = function addMatomoEventListener(eventName: string, listener: WrappedEventListener) {
+ function listenerWrapper(evt: Event) {
+ listener(...(evt as CustomEvent<any[]>).detail); // eslint-disable-line
+ }
+
+ listener.wrapper = listenerWrapper;
+
+ window.addEventListener(eventName, listenerWrapper);
+};
+
+piwik.off = function removeMatomoEventListener(eventName: string, listener: WrappedEventListener) {
+ if (listener.wrapper) {
+ window.removeEventListener(eventName, listener.wrapper);
+ }
+};
+
+piwik.postEventNoEmit = function postEventNoEmit(
+ eventName: string,
+ ...args: any[] // eslint-disable-line
+): void {
+ const event = new CustomEvent(eventName, { detail: args });
+ window.dispatchEvent(event);
+};
+
+piwik.postEvent = function postMatomoEvent(
+ eventName: string,
+ ...args: any[] // eslint-disable-line
+): IAngularEvent {
+ piwik.postEventNoEmit(eventName, ...args);
+
+ // required until angularjs is removed
+ const $rootScope = piwik.helper.getAngularDependency('$rootScope') as any; // eslint-disable-line
+ return $rootScope.$oldEmit(eventName, ...args);
+};
+
const Matomo = piwik;
export default Matomo;
diff --git a/plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue b/plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue
index 779b0c155c..81a232f4ba 100644
--- a/plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue
+++ b/plugins/CoreHome/vue/src/MatomoDialog/MatomoDialog.vue
@@ -10,7 +10,7 @@
</div>
</template>
<script lang="ts">
-import { defineComponent, ref } from 'vue';
+import { defineComponent } from 'vue';
import Matomo from '../Matomo/Matomo';
export default defineComponent({
@@ -36,13 +36,6 @@ export default defineComponent({
},
},
emits: ['yes', 'no', 'closeEnd', 'close', 'update:modelValue'],
- setup() {
- const root = ref(null);
-
- return {
- root,
- };
- },
activated() {
this.$emit('update:modelValue', false);
},
diff --git a/plugins/CoreHome/vue/src/Matomo/Matomo.spec.ts b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.spec.ts
index 49ab7f5b4a..a6eea35483 100644
--- a/plugins/CoreHome/vue/src/Matomo/Matomo.spec.ts
+++ b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.spec.ts
@@ -4,14 +4,15 @@
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-import Matomo from './Matomo';
+import Matomo from '../Matomo/Matomo';
+import MatomoUrl from './MatomoUrl';
import '../Periods/Day';
import '../Periods/Week';
import '../Periods/Month';
import '../Periods/Year';
import '../Periods/Range';
-describe('CoreHome/Matomo', () => {
+describe('CoreHome/MatomoUrl', () => {
describe('#updatePeriodParamsFromUrl()', () => {
const DATE_PERIODS_TO_TEST = [
{
@@ -110,7 +111,7 @@ describe('CoreHome/Matomo', () => {
history.pushState(null, '', '?date=' + date + '&period=' + period);
- Matomo.updatePeriodParamsFromUrl();
+ MatomoUrl.updatePeriodParamsFromUrl();
expect(Matomo.currentDateString).toEqual(expected.currentDateString);
expect(Matomo.period).toEqual(expected.period);
@@ -126,7 +127,7 @@ describe('CoreHome/Matomo', () => {
history.pushState(null, '', '?someparam=somevalue#?date=' + date + '&period=' + period);
- Matomo.updatePeriodParamsFromUrl();
+ MatomoUrl.updatePeriodParamsFromUrl();
expect(Matomo.currentDateString).toEqual(expected.currentDateString);
expect(Matomo.period).toEqual(expected.period);
@@ -143,7 +144,7 @@ describe('CoreHome/Matomo', () => {
history.pushState(null, '', '?someparam=somevalue#?date=' + Matomo.currentDateString + '&period=' + Matomo.period);
- Matomo.updatePeriodParamsFromUrl();
+ MatomoUrl.updatePeriodParamsFromUrl();
expect(Matomo.startDateString).toEqual('shouldnotchange');
expect(Matomo.endDateString).toEqual('shouldnotchangeeither');
diff --git a/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts
index 8c69e2834f..11eec228a8 100644
--- a/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts
+++ b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts
@@ -5,11 +5,69 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
+import { ILocationService } from 'angular';
+import { computed, ref, readonly } from 'vue';
+import Matomo from '../Matomo/Matomo';
+import { Periods, format } from '../Periods'; // important to load all periods here
+
+const { piwik, broadcast } = window;
+
+function isValidPeriod(periodStr: string, dateStr: string) {
+ try {
+ Periods.parse(periodStr, dateStr);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+// using unknown since readonly does not work well with recursive types like QueryParameters
+type ParsedQueryParameters = Record<string, unknown>;
+
/**
- * Similar to angulars $location but works around some limitation. Use it if you need to access
- * search params
+ * URL store and helper functions.
*/
-const MatomoUrl = {
+class MatomoUrl {
+ private urlQuery = ref('');
+
+ private hashQuery = ref('');
+
+ readonly urlParsed = computed(() => readonly(
+ broadcast.getValuesFromUrl(`?${this.urlQuery.value}`, true) as ParsedQueryParameters,
+ ));
+
+ readonly hashParsed = computed(() => readonly(
+ broadcast.getValuesFromUrl(`?${this.hashQuery.value}`, true) as ParsedQueryParameters,
+ ));
+
+ readonly parsed = computed(() => readonly({
+ ...this.urlParsed.value,
+ ...this.hashParsed.value,
+ } as ParsedQueryParameters));
+
+ constructor() {
+ this.setUrlQuery(window.location.search);
+ this.setHashQuery(window.location.hash);
+
+ // $locationChangeSuccess is triggered before angularjs changes actual window the hash, so we
+ // have to hook into this method if we want our event handlers to execute before other angularjs
+ // handlers (like the reporting page one)
+ Matomo.on('$locationChangeSuccess', (absUrl: string) => {
+ const url = new URL(absUrl);
+ this.setUrlQuery(url.search.replace(/^\?/, ''));
+ this.setHashQuery(url.hash.replace(/^#/, ''));
+ });
+
+ this.updatePeriodParamsFromUrl();
+ }
+
+ updateHash(params: QueryParameters|string) {
+ const serializedParams: string = typeof params !== 'string' ? this.stringify(params) : params;
+
+ const $location: ILocationService = Matomo.helper.getAngularDependency('$location');
+ $location.search(serializedParams);
+ }
+
getSearchParam(paramName: string): string {
const hash = window.location.href.split('#');
@@ -26,7 +84,53 @@ const MatomoUrl = {
}
return window.broadcast.getValueFromUrl(paramName, window.location.search);
- },
-};
+ }
+
+ stringify(search: QueryParameters): string {
+ // TODO: using $ since URLSearchParams does not handle array params the way Matomo uses them
+ return $.param(search).replace(/%5B%5D/g, '[]');
+ }
+
+ updatePeriodParamsFromUrl(): void {
+ let date = this.getSearchParam('date');
+ const period = this.getSearchParam('period');
+ if (!isValidPeriod(period, date)) {
+ // invalid data in URL
+ return;
+ }
+
+ if (piwik.period === period && piwik.currentDateString === date) {
+ // this period / date is already loaded
+ return;
+ }
+
+ piwik.period = period;
+
+ const dateRange = Periods.parse(period, date).getDateRange();
+ piwik.startDateString = format(dateRange[0]);
+ piwik.endDateString = format(dateRange[1]);
+
+ piwik.updateDateInTitle(date, period);
+
+ // do not set anything to previousN/lastN, as it's more useful to plugins
+ // to have the dates than previousN/lastN.
+ if (piwik.period === 'range') {
+ date = `${piwik.startDateString},${piwik.endDateString}`;
+ }
+
+ piwik.currentDateString = date;
+ }
+
+ private setUrlQuery(search: string) {
+ this.urlQuery.value = search.replace(/^\?/, '');
+ }
+
+ private setHashQuery(hash: string) {
+ this.hashQuery.value = hash.replace(/^[#/?]+/, '');
+ }
+}
+
+const instance = new MatomoUrl();
+export default instance;
-export default MatomoUrl;
+piwik.updatePeriodParamsFromUrl = instance.updatePeriodParamsFromUrl.bind(instance);
diff --git a/plugins/CoreHome/vue/src/Periods/Periods.adapter.ts b/plugins/CoreHome/vue/src/Periods/Periods.adapter.ts
index 4d9e6820f9..aff5d6c4f1 100644
--- a/plugins/CoreHome/vue/src/Periods/Periods.adapter.ts
+++ b/plugins/CoreHome/vue/src/Periods/Periods.adapter.ts
@@ -24,4 +24,4 @@ function piwikPeriods() {
};
}
-angular.module('piwikApp.service').factory('piwikPeriods', piwikPeriods);
+window.angular.module('piwikApp.service').factory('piwikPeriods', piwikPeriods);
diff --git a/plugins/CoreHome/vue/src/Periods/utilities.ts b/plugins/CoreHome/vue/src/Periods/utilities.ts
index b5488b7c01..a183b4ed68 100644
--- a/plugins/CoreHome/vue/src/Periods/utilities.ts
+++ b/plugins/CoreHome/vue/src/Periods/utilities.ts
@@ -31,7 +31,10 @@ export function parseDate(date: string|Date): Date {
return date;
}
- const strDate = decodeURIComponent(date);
+ const strDate = decodeURIComponent(date).trim();
+ if (strDate === '') {
+ throw new Error('Invalid date, empty string.');
+ }
if (strDate === 'today'
|| strDate === 'now'
@@ -67,13 +70,7 @@ export function parseDate(date: string|Date): Date {
return lastYear;
}
- try {
- return $.datepicker.parseDate('yy-mm-dd', strDate);
- } catch (err) {
- // angular swallows this error, so manual console log here
- console.error(err.message || err);
- throw err;
- }
+ return $.datepicker.parseDate('yy-mm-dd', strDate);
}
export function todayIsInRange(dateRange: Date[]): boolean {
diff --git a/plugins/CoreHome/vue/src/Piwik/Piwik.adapter.ts b/plugins/CoreHome/vue/src/Piwik/Piwik.adapter.ts
deleted file mode 100644
index 856916a248..0000000000
--- a/plugins/CoreHome/vue/src/Piwik/Piwik.adapter.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-import Piwik from './Piwik';
-
-function piwikService() {
- return Piwik;
-}
-
-angular.module('piwikApp.service').service('piwik', piwikService);
-
-function initPiwikService(piwik, $rootScope) {
- $rootScope.$on('$locationChangeSuccess', piwik.updatePeriodParamsFromUrl);
-}
-
-initPiwikService.$inject = ['piwik', '$rootScope'];
-
-angular.module('piwikApp.service').run(initPiwikService);
diff --git a/plugins/CoreHome/vue/src/Piwik/Piwik.spec.ts b/plugins/CoreHome/vue/src/Piwik/Piwik.spec.ts
deleted file mode 100644
index a07c5d3490..0000000000
--- a/plugins/CoreHome/vue/src/Piwik/Piwik.spec.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-import Piwik from './Piwik';
-import '../Periods/Day';
-import '../Periods/Week';
-import '../Periods/Month';
-import '../Periods/Year';
-import '../Periods/Range';
-
-describe('PiwikService', () => {
- describe('#updatePeriodParamsFromUrl()', () => {
- const DATE_PERIODS_TO_TEST = [
- {
- date: '2012-01-02',
- period: 'day',
- expected: {
- currentDateString: '2012-01-02',
- period: 'day',
- startDateString: '2012-01-02',
- endDateString: '2012-01-02'
- }
- },
- {
- date: '2012-01-02',
- period: 'week',
- expected: {
- currentDateString: '2012-01-02',
- period: 'week',
- startDateString: '2012-01-02',
- endDateString: '2012-01-08'
- }
- },
- {
- date: '2012-01-02',
- period: 'month',
- expected: {
- currentDateString: '2012-01-02',
- period: 'month',
- startDateString: '2012-01-01',
- endDateString: '2012-01-31'
- }
- },
- {
- date: '2012-01-02',
- period: 'year',
- expected: {
- currentDateString: '2012-01-02',
- period: 'year',
- startDateString: '2012-01-01',
- endDateString: '2012-12-31'
- }
- },
- {
- date: '2012-01-02,2012-02-03',
- period: 'range',
- expected: {
- currentDateString: '2012-01-02,2012-02-03',
- period: 'range',
- startDateString: '2012-01-02',
- endDateString: '2012-02-03'
- }
- },
- // invalid
- {
- date: '2012-01-02',
- period: 'range',
- expected: {
- currentDateString: undefined,
- period: undefined,
- startDateString: undefined,
- endDateString: undefined
- }
- },
- {
- date: 'sldfjkdslkfj',
- period: 'month',
- expected: {
- currentDateString: undefined,
- period: undefined,
- startDateString: undefined,
- endDateString: undefined
- }
- },
- {
- date: '2012-01-02',
- period: 'sflkjdslkfj',
- expected: {
- currentDateString: undefined,
- period: undefined,
- startDateString: undefined,
- endDateString: undefined
- }
- }
- ];
-
- DATE_PERIODS_TO_TEST.forEach((test) => {
- const date = test.date,
- period = test.period,
- expected = test.expected;
-
- it(`should parse the period in the URL correctly when date=${date} and period=${period}`, () => {
- delete Piwik.currentDateString;
- delete Piwik.period;
- delete Piwik.startDateString;
- delete Piwik.endDateString;
-
- history.pushState(null, '', '?date=' + date + '&period=' + period);
-
- Piwik.updatePeriodParamsFromUrl();
-
- expect(Piwik.currentDateString).toEqual(expected.currentDateString);
- expect(Piwik.period).toEqual(expected.period);
- expect(Piwik.startDateString).toEqual(expected.startDateString);
- expect(Piwik.endDateString).toEqual(expected.endDateString);
- });
-
- it('should parse the period in the URL hash correctly when date=' + date + ' and period=' + period, () => {
- delete Piwik.currentDateString;
- delete Piwik.period;
- delete Piwik.startDateString;
- delete Piwik.endDateString;
-
- history.pushState(null, '', '?someparam=somevalue#?date=' + date + '&period=' + period);
-
- Piwik.updatePeriodParamsFromUrl();
-
- expect(Piwik.currentDateString).toEqual(expected.currentDateString);
- expect(Piwik.period).toEqual(expected.period);
- expect(Piwik.startDateString).toEqual(expected.startDateString);
- expect(Piwik.endDateString).toEqual(expected.endDateString);
- });
- });
-
- it('should not change object values if the current date/period is the same as the URL date/period', () => {
- Piwik.period = 'range';
- Piwik.currentDateString = '2012-01-01,2012-01-02';
- Piwik.startDateString = 'shouldnotchange';
- Piwik.endDateString = 'shouldnotchangeeither';
-
- history.pushState(null, '', '?someparam=somevalue#?date=' + Piwik.currentDateString + '&period=' + Piwik.period);
-
- Piwik.updatePeriodParamsFromUrl();
-
- expect(Piwik.startDateString).toEqual('shouldnotchange');
- expect(Piwik.endDateString).toEqual('shouldnotchangeeither');
- });
- });
-});
diff --git a/plugins/CoreHome/vue/src/Piwik/Piwik.ts b/plugins/CoreHome/vue/src/Piwik/Piwik.ts
deleted file mode 100644
index 084dd53a1d..0000000000
--- a/plugins/CoreHome/vue/src/Piwik/Piwik.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-import PiwikUrl from '../PiwikUrl/PiwikUrl';
-import Periods from '../Periods/Periods';
-import { format } from '../Periods/utilities';
-
-let originalTitle: string;
-
-const { piwik, broadcast, piwikHelper } = window;
-
-piwik.helper = piwikHelper;
-piwik.broadcast = broadcast;
-
-function isValidPeriod(periodStr: string, dateStr: string) {
- try {
- Periods.parse(periodStr, dateStr);
- return true;
- } catch (e) {
- return false;
- }
-}
-
-piwik.updatePeriodParamsFromUrl = function updatePeriodParamsFromUrl() {
- let date = PiwikUrl.getSearchParam('date');
- const period = PiwikUrl.getSearchParam('period');
- if (!isValidPeriod(period, date)) {
- // invalid data in URL
- return;
- }
-
- if (piwik.period === period && piwik.currentDateString === date) {
- // this period / date is already loaded
- return;
- }
-
- piwik.period = period;
-
- const dateRange = Periods.parse(period, date).getDateRange();
- piwik.startDateString = format(dateRange[0]);
- piwik.endDateString = format(dateRange[1]);
-
- piwik.updateDateInTitle(date, period);
-
- // do not set anything to previousN/lastN, as it's more useful to plugins
- // to have the dates than previousN/lastN.
- if (piwik.period === 'range') {
- date = `${piwik.startDateString},${piwik.endDateString}`;
- }
-
- piwik.currentDateString = date;
-};
-
-piwik.updateDateInTitle = function updateDateInTitle(date: string, period: string) {
- if (!$('.top_controls #periodString').length) {
- return;
- }
-
- // Cache server-rendered page title
- originalTitle = originalTitle || document.title;
-
- if (originalTitle.indexOf(piwik.siteName) === 0) {
- const dateString = ` - ${Periods.parse(period, date).getPrettyString()} `;
- document.title = `${piwik.siteName}${dateString}${originalTitle.substr(piwik.siteName.length)}`;
- }
-};
-
-piwik.hasUserCapability = function hasUserCapability(capability: string) {
- return window.angular.isArray(piwik.userCapabilities)
- && piwik.userCapabilities.indexOf(capability) !== -1;
-};
-
-const Piwik = piwik;
-export default Piwik;
diff --git a/plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.adapter.ts b/plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.adapter.ts
deleted file mode 100644
index abf76cbcb5..0000000000
--- a/plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.adapter.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-import PiwikUrl from './PiwikUrl';
-
-function piwikUrl() {
- const model = {
- getSearchParam: PiwikUrl.getSearchParam.bind(PiwikUrl),
- };
-
- return model;
-}
-
-piwikUrl.$inject = [];
-
-angular.module('piwikApp.service').service('piwikUrl', piwikUrl);
diff --git a/plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.ts b/plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.ts
deleted file mode 100644
index 83ab1f68b2..0000000000
--- a/plugins/CoreHome/vue/src/PiwikUrl/PiwikUrl.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-/**
- * Similar to angulars $location but works around some limitation. Use it if you need to access
- * search params
- */
-const PiwikUrl = {
- getSearchParam(paramName: string): string {
- const hash = window.location.href.split('#');
-
- const regex = new RegExp(`${paramName}(\\[]|=)`);
- if (hash && hash[1] && regex.test(decodeURIComponent(hash[1]))) {
- const valueFromHash = window.broadcast.getValueFromHash(paramName, window.location.href);
-
- // for date, period and idsite fall back to parameter from url, if non in hash was provided
- if (valueFromHash
- || (paramName !== 'date' && paramName !== 'period' && paramName !== 'idSite')
- ) {
- return valueFromHash;
- }
- }
-
- return window.broadcast.getValueFromUrl(paramName, window.location.search);
- },
-};
-
-export default PiwikUrl;
diff --git a/plugins/CoreHome/vue/src/Segmentation/Segments.store.ts b/plugins/CoreHome/vue/src/Segmentation/Segments.store.ts
new file mode 100644
index 0000000000..0ab754079a
--- /dev/null
+++ b/plugins/CoreHome/vue/src/Segmentation/Segments.store.ts
@@ -0,0 +1,43 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+import { reactive, readonly, DeepReadonly } from 'vue';
+import Matomo from '../Matomo/Matomo';
+
+interface SegmentInfo {
+ definition: string;
+ name: string;
+}
+
+interface SegmentsStoreData {
+ availableSegments: SegmentInfo[];
+}
+
+class SegmentsStore {
+ private segmentState = reactive<SegmentsStoreData>({
+ availableSegments: [],
+ });
+
+ get state(): DeepReadonly<SegmentsStoreData> {
+ return readonly(this.segmentState);
+ }
+
+ constructor() {
+ Matomo.on('piwikSegmentationInited', () => this.setSegmentState());
+ }
+
+ private setSegmentState() {
+ try {
+ const uiControlObject = $('.segmentEditorPanel').data('uiControlObject');
+ this.segmentState.availableSegments = uiControlObject.impl.availableSegments || [];
+ } catch (e) {
+ // segment editor is not initialized yet
+ }
+ }
+}
+
+export default new SegmentsStore();
diff --git a/plugins/CoreHome/vue/src/createAngularJsAdapter.ts b/plugins/CoreHome/vue/src/createAngularJsAdapter.ts
index 209fa98b15..32bd1e17b4 100644
--- a/plugins/CoreHome/vue/src/createAngularJsAdapter.ts
+++ b/plugins/CoreHome/vue/src/createAngularJsAdapter.ts
@@ -60,6 +60,7 @@ export default function createAngularJsAdapter<InjectTypes = []>(options: {
mountPointFactory?: AdapterFunction<InjectTypes, HTMLElement>,
postCreate?: PostCreateFunction<InjectTypes>,
noScope?: boolean,
+ restrict?: string,
}): ng.IDirectiveFactory {
const {
component,
@@ -71,6 +72,7 @@ export default function createAngularJsAdapter<InjectTypes = []>(options: {
mountPointFactory,
postCreate,
noScope,
+ restrict = 'A',
} = options;
const currentTranscludeCounter = transcludeCounter;
@@ -90,7 +92,7 @@ export default function createAngularJsAdapter<InjectTypes = []>(options: {
function angularJsAdapter(...injectedServices: InjectTypes) {
const adapter: ng.IDirective = {
- restrict: 'A',
+ restrict,
scope: noScope ? undefined : angularJsScope,
compile: function angularJsAdapterCompile() {
return {
diff --git a/plugins/CoreHome/vue/src/index.ts b/plugins/CoreHome/vue/src/index.ts
index fdc9743f57..1808a8e32c 100644
--- a/plugins/CoreHome/vue/src/index.ts
+++ b/plugins/CoreHome/vue/src/index.ts
@@ -5,9 +5,9 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
+import './noAdblockFlag';
import './MatomoUrl/MatomoUrl.adapter';
import './Matomo/Matomo.adapter';
-import './noAdblockFlag';
import './Periods/Day';
import './Periods/Week';
import './Periods/Month';
@@ -15,11 +15,10 @@ import './Periods/Year';
import './Periods/Range';
import './Periods/Periods.adapter';
import './AjaxHelper/AjaxHelper.adapter';
-import './PiwikUrl/PiwikUrl.adapter';
-import './Piwik/Piwik.adapter';
import './MatomoDialog/MatomoDialog.adapter';
import './EnrichedHeadline/EnrichedHeadline.adapter';
import './ContentBlock/ContentBlock.adapter';
+import './Comparisons/Comparisons.adapter';
export { default as createAngularJsAdapter } from './createAngularJsAdapter';
export { default as activityIndicatorAdapter } from './ActivityIndicator/ActivityIndicator.adapter';
@@ -33,3 +32,4 @@ export * from './Periods';
export { default as MatomoDialog } from './MatomoDialog/MatomoDialog.vue';
export { default as EnrichedHeadline } from './EnrichedHeadline/EnrichedHeadline.vue';
export { default as ContentBlock } from './ContentBlock/ContentBlock.vue';
+export { default as Comparisons } from './Comparisons/Comparisons.vue';