diff options
author | dizzy <diosmosis@users.noreply.github.com> | 2021-10-13 06:55:33 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-13 06:55:33 +0300 |
commit | b5e591c7d70fe64c5a3d375812d9e1bc20b25558 (patch) | |
tree | 98fa10365dbb5a2fca9bd9687c8cd447f82f070e /plugins/CoreHome/vue/src | |
parent | 68674d8fdf1464e0342f8413372ae702e7b7bc43 (diff) |
[Vue] add promise api to ajaxHelper and deprecate piwikApi service (#18114)
* incomplete conversion
* get ajax helper migration to work
* delete old periods.spec.js
* remove global-ajax-queue.js file
* migrate piwik service and test (w/ hacks to get it the test to work)
* rebuild and remove old files + get tests to pass
* unfinished commit
* return jqxhr object so promise api can be used
* move hasBlockedContent and deprecate piwikApi service
* remove alert files
* convert piwikHelper.spec.js
* in new vue code, use "Matomo" everywhere possible instead of "piwik" and rebuild vue files
* add another needed export line in command
* include polyfills after vue so we can add to vue engine
* Add HTML sanitizer for use w/ migrating ng-bind-html uses.
* fix broken merge, rebuild js, fix issue in build command
* add sanitize to other components for consistency (will be replaced by utility function eventually)
* add output when no plugins to build
* update expected screenshot
Diffstat (limited to 'plugins/CoreHome/vue/src')
-rw-r--r-- | plugins/CoreHome/vue/src/ActivityIndicator/ActivityIndicator.adapter.ts | 1 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts | 37 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Alert/Alert.adapter.ts | 1 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts | 22 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Matomo/Matomo.spec.ts | 152 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Matomo/Matomo.ts | 78 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/MatomoHelper/MatomoHelper.spec.ts | 29 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.adapter.ts | 19 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts | 32 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Periods/Periods.ts | 10 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Periods/index.ts | 1 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/Periods/utilities.ts | 2 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/index.ts | 13 | ||||
-rw-r--r-- | plugins/CoreHome/vue/src/noAdblockFlag.ts | 9 |
14 files changed, 384 insertions, 22 deletions
diff --git a/plugins/CoreHome/vue/src/ActivityIndicator/ActivityIndicator.adapter.ts b/plugins/CoreHome/vue/src/ActivityIndicator/ActivityIndicator.adapter.ts index 96ed62b476..0ca0ac8241 100644 --- a/plugins/CoreHome/vue/src/ActivityIndicator/ActivityIndicator.adapter.ts +++ b/plugins/CoreHome/vue/src/ActivityIndicator/ActivityIndicator.adapter.ts @@ -35,6 +35,7 @@ export default function activityIndicatorAdapter(): ng.IDirective { }; }, }); + app.config.globalProperties.$sanitize = window.vueSanitize; app.component('activity-indicator', ActivityIndicator); const vm = app.mount(element[0]); diff --git a/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts b/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts index 788f3a8f45..c4e61b2ad5 100644 --- a/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts +++ b/plugins/CoreHome/vue/src/AjaxHelper/AjaxHelper.ts @@ -5,7 +5,8 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ -import PiwikUrl from '../PiwikUrl/PiwikUrl'; +import MatomoUrl from '../MatomoUrl/MatomoUrl'; +import Matomo from '../Matomo/Matomo'; window.globalAjaxQueue = [] as GlobalAjaxQueue; window.globalAjaxQueue.active = 0; @@ -62,7 +63,7 @@ function defaultErrorCallback(deferred: XMLHttpRequest, status: string): void { } /** - * Global ajax helper to handle requests within piwik + * Global ajax helper to handle requests within Matomo */ export default class AjaxHelper { /** @@ -87,6 +88,8 @@ export default class AjaxHelper { /** * Callback function to be executed on error + * + * @deprecated use the jquery promise API */ errorCallback: AnyFunction; @@ -94,6 +97,8 @@ export default class AjaxHelper { /** * Callback function to be executed on complete (after error or success) + * + * @deprecated use the jquery promise API */ completeCallback: AnyFunction; @@ -212,6 +217,7 @@ export default class AjaxHelper { * Sets the callback called after the request finishes * * @param callback Callback function + * @deprecated use the jquery promise API */ setCallback(callback: AnyFunction): void { this.callback = callback; @@ -240,6 +246,8 @@ export default class AjaxHelper { /** * Sets the callback called in case of an error within the request + * + * @deprecated use the jquery promise API */ setErrorCallback(callback: AnyFunction): void { this.errorCallback = callback; @@ -247,6 +255,8 @@ export default class AjaxHelper { /** * Sets the complete callback which is called after an error or success callback. + * + * @deprecated use the jquery promise API */ setCompleteCallback(callback: AnyFunction): void { this.completeCallback = callback; @@ -315,7 +325,7 @@ export default class AjaxHelper { /** * Send the request */ - send(): void { + send(): JQuery.jqXHR { if ($(this.errorElement).length) { $(this.errorElement).hide(); } @@ -326,6 +336,8 @@ export default class AjaxHelper { this.requestHandle = this.buildAjaxCall(); globalAjaxQueue.push(this.requestHandle); + + return this.requestHandle; } /** @@ -404,11 +416,8 @@ export default class AjaxHelper { } globalAjaxQueue.active -= 1; - const { piwik } = window; - if (piwik - && piwik.ajaxRequestFinished - ) { - piwik.ajaxRequestFinished(); + if (Matomo.ajaxRequestFinished) { + Matomo.ajaxRequestFinished(); } }, data: this.mixinDefaultPostParams(this.postParams), @@ -428,9 +437,9 @@ export default class AjaxHelper { } private getDefaultPostParams() { - if (this.withToken || this.isRequestToApiMethod() || piwik.shouldPropagateTokenAuth) { + if (this.withToken || this.isRequestToApiMethod() || Matomo.shouldPropagateTokenAuth) { return { - token_auth: piwik.token_auth, + token_auth: Matomo.token_auth, // When viewing a widgetized report there won't be any session that can be used, so don't // force session usage force_api_session: broadcast.isWidgetizeRequestWithoutSession() ? 0 : 1, @@ -462,11 +471,11 @@ export default class AjaxHelper { * @param params parameter object */ private mixinDefaultGetParams(originalParams): Parameters { - const segment = PiwikUrl.getSearchParam('segment'); + const segment = MatomoUrl.getSearchParam('segment'); const defaultParams = { - idSite: piwik.idSite || broadcast.getValueFromUrl('idSite'), - period: piwik.period || broadcast.getValueFromUrl('period'), + idSite: Matomo.idSite || broadcast.getValueFromUrl('idSite'), + period: Matomo.period || broadcast.getValueFromUrl('period'), segment, }; @@ -490,7 +499,7 @@ export default class AjaxHelper { // handle default date & period if not already set if (this.useGETDefaultParameter('date') && !params.date && !this.postParams.date) { - params.date = piwik.currentDateString; + params.date = Matomo.currentDateString; } return params; diff --git a/plugins/CoreHome/vue/src/Alert/Alert.adapter.ts b/plugins/CoreHome/vue/src/Alert/Alert.adapter.ts index c1f32e8461..5cecb97a81 100644 --- a/plugins/CoreHome/vue/src/Alert/Alert.adapter.ts +++ b/plugins/CoreHome/vue/src/Alert/Alert.adapter.ts @@ -40,6 +40,7 @@ export default function alertAdapter(): ng.IDirective { }; }, }); + app.config.globalProperties.$sanitize = window.vueSanitize; app.component('alert', Alert); const vm = app.mount(element[0]); diff --git a/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts b/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts new file mode 100644 index 0000000000..e76adb190b --- /dev/null +++ b/plugins/CoreHome/vue/src/Matomo/Matomo.adapter.ts @@ -0,0 +1,22 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import Matomo from './Matomo'; + +function piwikService() { + return Matomo; +} + +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/Matomo/Matomo.spec.ts b/plugins/CoreHome/vue/src/Matomo/Matomo.spec.ts new file mode 100644 index 0000000000..49ab7f5b4a --- /dev/null +++ b/plugins/CoreHome/vue/src/Matomo/Matomo.spec.ts @@ -0,0 +1,152 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +import Matomo from './Matomo'; +import '../Periods/Day'; +import '../Periods/Week'; +import '../Periods/Month'; +import '../Periods/Year'; +import '../Periods/Range'; + +describe('CoreHome/Matomo', () => { + 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 Matomo.currentDateString; + delete Matomo.period; + delete Matomo.startDateString; + delete Matomo.endDateString; + + history.pushState(null, '', '?date=' + date + '&period=' + period); + + Matomo.updatePeriodParamsFromUrl(); + + expect(Matomo.currentDateString).toEqual(expected.currentDateString); + expect(Matomo.period).toEqual(expected.period); + expect(Matomo.startDateString).toEqual(expected.startDateString); + expect(Matomo.endDateString).toEqual(expected.endDateString); + }); + + it('should parse the period in the URL hash correctly when date=' + date + ' and period=' + period, () => { + delete Matomo.currentDateString; + delete Matomo.period; + delete Matomo.startDateString; + delete Matomo.endDateString; + + history.pushState(null, '', '?someparam=somevalue#?date=' + date + '&period=' + period); + + Matomo.updatePeriodParamsFromUrl(); + + expect(Matomo.currentDateString).toEqual(expected.currentDateString); + expect(Matomo.period).toEqual(expected.period); + expect(Matomo.startDateString).toEqual(expected.startDateString); + expect(Matomo.endDateString).toEqual(expected.endDateString); + }); + }); + + it('should not change object values if the current date/period is the same as the URL date/period', () => { + Matomo.period = 'range'; + Matomo.currentDateString = '2012-01-01,2012-01-02'; + Matomo.startDateString = 'shouldnotchange'; + Matomo.endDateString = 'shouldnotchangeeither'; + + history.pushState(null, '', '?someparam=somevalue#?date=' + Matomo.currentDateString + '&period=' + Matomo.period); + + Matomo.updatePeriodParamsFromUrl(); + + expect(Matomo.startDateString).toEqual('shouldnotchange'); + expect(Matomo.endDateString).toEqual('shouldnotchangeeither'); + }); + }); +}); diff --git a/plugins/CoreHome/vue/src/Matomo/Matomo.ts b/plugins/CoreHome/vue/src/Matomo/Matomo.ts new file mode 100644 index 0000000000..2a705f665e --- /dev/null +++ b/plugins/CoreHome/vue/src/Matomo/Matomo.ts @@ -0,0 +1,78 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import MatomoUrl from '../MatomoUrl/MatomoUrl'; +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 = 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; + } + + // 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 Matomo = piwik; +export default Matomo; diff --git a/plugins/CoreHome/vue/src/MatomoHelper/MatomoHelper.spec.ts b/plugins/CoreHome/vue/src/MatomoHelper/MatomoHelper.spec.ts new file mode 100644 index 0000000000..c936a6e5ed --- /dev/null +++ b/plugins/CoreHome/vue/src/MatomoHelper/MatomoHelper.spec.ts @@ -0,0 +1,29 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import '../../../../Morpheus/javascripts/piwikHelper'; + +describe('CoreHome/piwikHelper', () => { + describe('#htmlDecode', () => { + + it('should correctly decode html entities', function (done) { + let called = false; + (window as any)._testfunction = () => { + called = true; + }; + + const encoded = 'str <img src=\'x/\' onerror=\'_testfunction()\'/>'; + const decoded = window.piwikHelper.htmlDecode(encoded); + + setTimeout(() => { + expect(called).toBe(false); + expect(decoded).toEqual('str <img src=\'x/\' onerror=\'_testfunction()\'/>'); + done(); + }, 500); + }); + }); +}); diff --git a/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.adapter.ts b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.adapter.ts new file mode 100644 index 0000000000..b82329739b --- /dev/null +++ b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.adapter.ts @@ -0,0 +1,19 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +import MatomoUrl from './MatomoUrl'; + +function piwikUrl() { + const model = { + getSearchParam: MatomoUrl.getSearchParam.bind(MatomoUrl), + }; + + return model; +} + +piwikUrl.$inject = []; + +angular.module('piwikApp.service').service('piwikUrl', piwikUrl); diff --git a/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts new file mode 100644 index 0000000000..8c69e2834f --- /dev/null +++ b/plugins/CoreHome/vue/src/MatomoUrl/MatomoUrl.ts @@ -0,0 +1,32 @@ +/*! + * 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: 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 MatomoUrl; diff --git a/plugins/CoreHome/vue/src/Periods/Periods.ts b/plugins/CoreHome/vue/src/Periods/Periods.ts index b832629e26..ca56625212 100644 --- a/plugins/CoreHome/vue/src/Periods/Periods.ts +++ b/plugins/CoreHome/vue/src/Periods/Periods.ts @@ -17,16 +17,16 @@ interface PeriodClass { } /** - * Piwik period management service for the frontend. + * Matomo period management service for the frontend. * * Usage: * - * var DayPeriod = piwikPeriods.get('day'); + * var DayPeriod = matomoPeriods.get('day'); * var day = new DayPeriod(new Date()); * * or * - * var day = piwikPeriods.parse('day', '2013-04-05'); + * var day = matomoPeriods.parse('day', '2013-04-05'); * * Adding custom periods: * @@ -43,9 +43,9 @@ interface PeriodClass { * - (_static_) **getDisplayText**: returns translated text for the period, eg, 'month', * 'week', etc. * - * Then call piwik.addCustomPeriod w/ your period class: + * Then call Periods.addCustomPeriod w/ your period class: * - * piwik.addCustomPeriod('mycustomperiod', MyCustomPeriod); + * Periods.addCustomPeriod('mycustomperiod', MyCustomPeriod); * * NOTE: currently only single date periods like day, week, month year can * be extended. Other types of periods that require a special UI to diff --git a/plugins/CoreHome/vue/src/Periods/index.ts b/plugins/CoreHome/vue/src/Periods/index.ts index e0ec84affb..c1a265b4dc 100644 --- a/plugins/CoreHome/vue/src/Periods/index.ts +++ b/plugins/CoreHome/vue/src/Periods/index.ts @@ -12,3 +12,4 @@ export { default as Week } from './Week'; export { default as Month } from './Month'; export { default as Year } from './Year'; export { default as Range } from './Range'; +export * from './utilities'; diff --git a/plugins/CoreHome/vue/src/Periods/utilities.ts b/plugins/CoreHome/vue/src/Periods/utilities.ts index 167021fe36..b5488b7c01 100644 --- a/plugins/CoreHome/vue/src/Periods/utilities.ts +++ b/plugins/CoreHome/vue/src/Periods/utilities.ts @@ -15,7 +15,7 @@ export function getToday(): Date { // undo browser timezone date.setTime(date.getTime() + date.getTimezoneOffset() * 60 * 1000); - // apply piwik site timezone (if it exists) + // apply Matomo site timezone (if it exists) date.setHours(date.getHours() + ((window.piwik.timezoneOffset || 0) / 3600)); // get rid of hours/minutes/seconds/etc. diff --git a/plugins/CoreHome/vue/src/index.ts b/plugins/CoreHome/vue/src/index.ts index 97d056019f..d0b4b8a8fb 100644 --- a/plugins/CoreHome/vue/src/index.ts +++ b/plugins/CoreHome/vue/src/index.ts @@ -5,6 +5,15 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ +import './MatomoUrl/MatomoUrl.adapter'; +import './Matomo/Matomo.adapter'; +import './noAdblockFlag'; +import './Periods/Day'; +import './Periods/Week'; +import './Periods/Month'; +import './Periods/Year'; +import './Periods/Range'; +import './Periods/Periods.adapter'; import './AjaxHelper/AjaxHelper.adapter'; import './PiwikUrl/PiwikUrl.adapter'; import './Piwik/Piwik.adapter'; @@ -14,6 +23,6 @@ export { default as ActivityIndicator } from './ActivityIndicator/ActivityIndica export { default as translate } from './translate'; export { default as alertAdapter } from './Alert/Alert.adapter'; export { default as AjaxHelper } from './AjaxHelper/AjaxHelper'; -export { default as PiwikUrl } from './PiwikUrl/PiwikUrl'; -export { default as Piwik } from './Piwik/Piwik'; +export { default as MatomoUrl } from './MatomoUrl/MatomoUrl'; +export { default as Matomo } from './Matomo/Matomo'; export * from './Periods'; diff --git a/plugins/CoreHome/vue/src/noAdblockFlag.ts b/plugins/CoreHome/vue/src/noAdblockFlag.ts new file mode 100644 index 0000000000..3a5cd0a76e --- /dev/null +++ b/plugins/CoreHome/vue/src/noAdblockFlag.ts @@ -0,0 +1,9 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +// see https://github.com/matomo-org/matomo/issues/5094 used to detect an ad blocker +window.hasBlockedContent = false; |