diff --git a/.gitignore b/.gitignore index d5261c7a705..4447a81e666 100644 --- a/.gitignore +++ b/.gitignore @@ -61,9 +61,12 @@ php_errors.log /tests/resources/overlay-test-site-real/ /tests/PHPUnit/proxy/libs /tests/PHPUnit/proxy/piwik.js +/tests/PHPUnit/proxy/matomo.js /tests/PHPUnit/proxy/plugins /tests/PHPUnit/proxy/tests +/tests/PHPUnit/proxy/misc /tests/resources/piwik.test.js +/tests/resources/matomo.test.js /config/*.config.ini.php /Vagrantfile /misc/vagrant diff --git a/CHANGELOG.md b/CHANGELOG.md index 1639b3bd9a3..89c90e9cf05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ The Product Changelog at **[matomo.org/changelog](https://matomo.org/changelog)* * It is now possible to queue a request on the JavaScript tracker using the method `queueRequest(requestUrl)`. This can be useful to group multiple tracking requests into one bulk request to reduce the number of tracking requests that are sent to your server making the tracking more efficient. * The output type "save on disk" in the API method `ScheduledReport.generateReport` has been replaced by the download output type. +### Internal change +* New Matomo installation will now use by default "matomo.js" and "matomo.php" as tracking endpoints. From Matomo 4.0 all installations will use "matomo.js" and "matomo.php" by default. We recommend you ensure those files can be accessed through the web and are not blocked. + +### Deprecations +* The method `Piwik\SettingsPiwik::isPiwikInstalled()` has been deprecated and renamed to `isMatomoInstalled()`. It is still supported to use the method, but the method will be removed in Piwik 4.0.0 + ## Matomo 3.6.1 ### New APIs diff --git a/LEGALNOTICE b/LEGALNOTICE index 5cf7a4285c7..235f8cb42cf 100644 --- a/LEGALNOTICE +++ b/LEGALNOTICE @@ -57,8 +57,9 @@ SEPARATELY LICENSED COMPONENTS AND LIBRARIES Link: https://github.com/matomo-org/piwik/blob/master/libs/jquery/truncate/ License: New BSD - Name: piwik.js - JavaScript tracker - Link: https://github.com/matomo-org/piwik/blob/master/js/piwik.js + Name: matomo.js & piwik.js - JavaScript tracker + Link: https://github.com/matomo-org/matomo/blob/master/js/piwik.js + Link: https://github.com/matomo-org/matomo/blob/master/js/matomo.js License: New BSD Name: PiwikTracker - server-side tracker (PHP) diff --git a/composer.json b/composer.json index 80decdbecb7..e2414f6f360 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "matomo/referrer-spam-blacklist": "~1.0", "matomo/searchengine-and-social-list": "~1.0", "tecnickcom/tcpdf": "~6.0", - "piwik/piwik-php-tracker": "^1.0", + "piwik/piwik-php-tracker": "^1.0.0", "composer/semver": "~1.3.0", "szymach/c-pchart": "^2.0", "geoip2/geoip2": "^2.8", diff --git a/composer.lock b/composer.lock index b795b8daf79..1bc233a31ff 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "53d9ab304551df4691f2057dc8b12c99", + "content-hash": "58af620cb0a5851205adfedd960f5c59", "packages": [ { "name": "composer/ca-bundle", diff --git a/config/global.ini.php b/config/global.ini.php index 4a768933042..289509ed357 100644 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -138,7 +138,7 @@ ; NOTE: you must also set [log] log_writers[] = "screen" to enable the profiler to print on screen enable_sql_profiler = 0 -; If set to 1, all requests to piwik.php will be forced to be 'new visitors' +; If set to 1, all requests to matomo.php will be forced to be 'new visitors' tracker_always_new_visitor = 0 ; if set to 1, all SQL queries will be logged using the DEBUG log level diff --git a/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php b/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php index f50508a7e28..b9dc8186519 100644 --- a/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php +++ b/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php @@ -74,6 +74,7 @@ protected function getPriorityOrder() 'libs/', 'js/', 'piwik.js', + 'matomo.js', 'plugins/CoreHome/javascripts/require.js', 'plugins/Morpheus/javascripts/piwikHelper.js', 'plugins/Morpheus/javascripts/', diff --git a/core/Db/Schema.php b/core/Db/Schema.php index b973af0b3b5..e6e26a99077 100644 --- a/core/Db/Schema.php +++ b/core/Db/Schema.php @@ -141,6 +141,22 @@ public function createAnonymousUser() $this->getSchema()->createAnonymousUser(); } + /** + * Records the Matomo version a user used when installing this Matomo for the first time + */ + public function recordInstallVersion() + { + $this->getSchema()->recordInstallVersion(); + } + + /** + * Returns which Matomo version was used to install this Matomo for the first time. + */ + public function getInstallVersion() + { + return $this->getSchema()->getInstallVersion(); + } + /** * Truncate all tables */ diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php index 60048bc30d1..b033940118f 100644 --- a/core/Db/Schema/Mysql.php +++ b/core/Db/Schema/Mysql.php @@ -14,12 +14,17 @@ use Piwik\Db\SchemaInterface; use Piwik\Db; use Piwik\DbHelper; +use Piwik\Option; +use Piwik\Plugins\Installation\Installation; +use Piwik\Version; /** * MySQL schema */ class Mysql implements SchemaInterface { + const OPTION_NAME_MATOMO_INSTALL_VERSION = 'install_version'; + private $tablesInstalled = null; /** @@ -472,6 +477,28 @@ public function createAnonymousUser() VALUES ( 'anonymous', '', 'anonymous', 'anonymous@example.org', 'anonymous', 0, '$now', '$now' );"); } + /** + * Records the Matomo version a user used when installing this Matomo for the first time + */ + public function recordInstallVersion() + { + if (!self::getInstallVersion()) { + Option::set(self::OPTION_NAME_MATOMO_INSTALL_VERSION, Version::VERSION); + } + } + + /** + * Returns which Matomo version was used to install this Matomo for the first time. + */ + public function getInstallVersion() + { + Option::clearCachedOption(self::OPTION_NAME_MATOMO_INSTALL_VERSION); + $version = Option::get(self::OPTION_NAME_MATOMO_INSTALL_VERSION); + if (!empty($version)) { + return $version; + } + } + /** * Truncate all tables */ diff --git a/core/Db/SchemaInterface.php b/core/Db/SchemaInterface.php index 8c22bb6818d..9fcf54008df 100644 --- a/core/Db/SchemaInterface.php +++ b/core/Db/SchemaInterface.php @@ -59,6 +59,16 @@ public function createTables(); */ public function createAnonymousUser(); + /** + * Records the Matomo version a user used when installing this Matomo for the first time + */ + public function recordInstallVersion(); + + /** + * Returns which Matomo version was used to install this Matomo for the first time. + */ + public function getInstallVersion(); + /** * Truncate all tables */ diff --git a/core/DbHelper.php b/core/DbHelper.php index 1687cc89e85..fdbbf3bd1f9 100644 --- a/core/DbHelper.php +++ b/core/DbHelper.php @@ -93,6 +93,31 @@ public static function createAnonymousUser() Schema::getInstance()->createAnonymousUser(); } + /** + * Records the Matomo version a user used when installing this Matomo for the first time + */ + public static function recordInstallVersion() + { + Schema::getInstance()->recordInstallVersion(); + } + + /** + * Returns which Matomo version was used to install this Matomo for the first time. + */ + public static function getInstallVersion() + { + return Schema::getInstance()->getInstallVersion(); + } + + public static function wasMatomoInstalledBeforeVersion($version) + { + $installVersion = self::getInstallVersion(); + if (empty($installVersion)) { + return true; // we assume yes it was installed + } + return true === version_compare($version, $installVersion, '>'); + } + /** * Create all tables */ diff --git a/core/FileIntegrity.php b/core/FileIntegrity.php index 9f95f2a66e9..98409756652 100644 --- a/core/FileIntegrity.php +++ b/core/FileIntegrity.php @@ -366,7 +366,7 @@ protected static function getMessagesFilesMismatch($messages) protected static function isModifiedPathValid($path) { - if ($path === 'piwik.js') { + if ($path === 'piwik.js' || $path === 'matomo.js') { // we could have used a postEvent hook to enrich "\Piwik\Manifest::$files;" which would also benefit plugins // that want to check for file integrity but we do not want to risk to break anything right now. It is not // as trivial because piwik.js might be already updated, or updated on the next request. We cannot define diff --git a/core/SettingsPiwik.php b/core/SettingsPiwik.php index bfd4ab4aeb5..dc208687e74 100644 --- a/core/SettingsPiwik.php +++ b/core/SettingsPiwik.php @@ -213,6 +213,15 @@ public static function getPiwikUrl() return $url; } + /** + * @see SettingsPiwik::isPiwikInstalled + * @return bool + */ + public static function isMatomoInstalled() + { + return self::isPiwikInstalled(); + } + /** * Return true if Piwik is installed (installation is done). * @return bool diff --git a/core/Tracker/Db/Pdo/Mysql.php b/core/Tracker/Db/Pdo/Mysql.php index 7641b7167ab..262d703a688 100644 --- a/core/Tracker/Db/Pdo/Mysql.php +++ b/core/Tracker/Db/Pdo/Mysql.php @@ -112,7 +112,7 @@ public function connect() $this->connection = @new PDO($this->dsn, $this->username, $this->password, $this->mysqlOptions); // we may want to setAttribute(PDO::ATTR_TIMEOUT ) to a few seconds (default is 60) in case the DB is locked - // the piwik.php would stay waiting for the database... bad! + // the matomo.php would stay waiting for the database... bad! // we delete the password from this object "just in case" it could be printed $this->password = ''; diff --git a/core/Tracker/Db/Pdo/Pgsql.php b/core/Tracker/Db/Pdo/Pgsql.php index b70122aa4a9..930a8bc29b2 100644 --- a/core/Tracker/Db/Pdo/Pgsql.php +++ b/core/Tracker/Db/Pdo/Pgsql.php @@ -43,7 +43,7 @@ public function connect() $this->connection = new PDO($this->dsn, $this->username, $this->password, $config = array()); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // we may want to setAttribute(PDO::ATTR_TIMEOUT ) to a few seconds (default is 60) in case the DB is locked - // the piwik.php would stay waiting for the database... bad! + // the matomo.php would stay waiting for the database... bad! // we delete the password from this object "just in case" it could be printed $this->password = ''; diff --git a/core/Tracker/TrackerCodeGenerator.php b/core/Tracker/TrackerCodeGenerator.php index 5870f098007..15851862915 100644 --- a/core/Tracker/TrackerCodeGenerator.php +++ b/core/Tracker/TrackerCodeGenerator.php @@ -9,6 +9,8 @@ namespace Piwik\Tracker; use Piwik\Common; +use Piwik\DbHelper; +use Piwik\Option; use Piwik\Piwik; use Piwik\Plugins\CustomVariables\CustomVariables; use Piwik\Plugins\SitesManager\API as APISitesManager; @@ -20,6 +22,17 @@ */ class TrackerCodeGenerator { + /** + * whether matomo.js|php should be forced over piwik.js|php + * @var bool + */ + private $shouldForceMatomoEndpoint = false; + + public function forceMatomoEndpoint() + { + $this->shouldForceMatomoEndpoint = true; + } + /** * @param int $idSite * @param string $piwikUrl http://path/to/piwik/site/ @@ -134,7 +147,9 @@ public function generate( 'optionsBeforeTrackerUrl' => $optionsBeforeTrackerUrl, 'protocol' => '//', 'loadAsync' => true, - 'trackNoScript' => $trackNoScript + 'trackNoScript' => $trackNoScript, + 'matomoJsFilename' => $this->getJsTrackerEndpoint(), + 'matomoPhpFilename' => $this->getPhpTrackerEndpoint(), ); if (SettingsPiwik::isHttpsForced()) { @@ -191,6 +206,34 @@ public function generate( return $jsCode; } + public function getJsTrackerEndpoint() + { + $name = 'matomo.js'; + if ($this->shouldPreferPiwikEndpoint()) { + $name = 'piwik.js'; + } + return $name; + } + + public function getPhpTrackerEndpoint() + { + $name = 'matomo.php'; + if ($this->shouldPreferPiwikEndpoint()) { + $name = 'piwik.php'; + } + return $name; + } + + public function shouldPreferPiwikEndpoint() + { + if ($this->shouldForceMatomoEndpoint) { + return false; + } + + // only since 3.7.0 we use the default matomo.js|php... for all other installs we need to keep BC + return DbHelper::wasMatomoInstalledBeforeVersion('3.7.0-b1'); + } + private function getJavascriptTagOptions($idSite, $mergeSubdomains, $mergeAliasUrls) { try { diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index 737c24c380f..c48f065dc79 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -31,7 +31,7 @@ * views, time spent, etc. * * Whether a visit is NEW or KNOWN we also save the action in the DB. - * One request to the piwik.php script is associated to one action. + * One request to the matomo.php script is associated to one action. * */ class Visit implements VisitInterface diff --git a/core/Updater.php b/core/Updater.php index dded2d245cb..ba9a0caa83f 100644 --- a/core/Updater.php +++ b/core/Updater.php @@ -10,12 +10,12 @@ use Piwik\Columns\Updater as ColumnUpdater; use Piwik\Container\StaticContainer; +use Piwik\Plugins\Installation\ServerFilesGenerator; use Piwik\Updater\Migration; use Piwik\Updater\Migration\Db\Sql; use Piwik\Exception\MissingFilePermissionException; use Piwik\Updater\UpdateObserver; use Zend_Db_Exception; -use Piwik\Plugins\Installation\ServerFilesGenerator; /** * Load and execute all relevant, incremental update scripts for Piwik core and plugins, and bump the component version numbers for completed updates. @@ -325,7 +325,7 @@ public function update($componentName) $this->markComponentSuccessfullyUpdated($componentName, $updatedVersion); $this->executeListenerHook('onComponentUpdateFinished', array($componentName, $updatedVersion, $warningMessages)); - + ServerFilesGenerator::createHtAccessFiles(); return $warningMessages; } diff --git a/js/README.md b/js/README.md index 9167ebc7876..b73ae1d2b08 100644 --- a/js/README.md +++ b/js/README.md @@ -16,11 +16,11 @@ The js/ folder contains: * it supports deflate/gzip compression if your web server (e.g., Apache without mod_deflate or mod_gzip), shrinking the data transfer to 8K -* js/index.php (or implicitly as "js/") can also act as a proxy to piwik.php +* js/index.php (or implicitly as "js/") can also act as a proxy to matomo.php * If you are concerned about the impact of browser-based privacy filters which attempt to block tracking, you can change your tracking code to use "js/" - instead of "piwik.js" and "piwik.php", respectively. + instead of "piwik.js" and "matomo.php", respectively. Note that in order for [Page Overlay](https://matomo.org/docs/page-overlay/) to work, the Piwik tracker method `setAPIUrl()` needs to be called with its parameter pointing to the root directory of Piwik. E.g.: @@ -44,7 +44,7 @@ The js/ folder contains: ```bash $ cd /path/to/piwik/js/ - $ sed '//,/<\/DEBUG>/d' < piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.8.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\/*!/' > piwik.min.js && cp piwik.min.js ../piwik.js + $ sed '//,/<\/DEBUG>/d' < piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.8.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\/*!/' > piwik.min.js && cp piwik.min.js ../piwik.js && cp piwik.min.js ../matomo.js ``` This will generate the minify /path/to/piwik/js/piwik.min.js and copy it to diff --git a/js/piwik.js b/js/piwik.js index a530a10fd71..0f3c912c0c9 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -4,7 +4,7 @@ * JavaScript tracking client * * @link https://piwik.org - * @source https://github.com/piwik/piwik/blob/master/js/piwik.js + * @source https://github.com/matomo-org/matomo/blob/master/js/piwik.js * @license https://piwik.org/free-software/bsd/ BSD-3 Clause (also in js/LICENSE.txt) * @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause */ @@ -2880,7 +2880,10 @@ if (typeof window.Piwik !== 'object') { trackerUrl = trackerUrl.slice(0, posQuery); } - if (stringEndsWith(trackerUrl, 'piwik.php')) { + if (stringEndsWith(trackerUrl, 'matomo.php')) { + // if eg without domain or path "matomo.php" => '' + trackerUrl = removeCharactersFromEndOfString(trackerUrl, 'matomo.php'.length); + } else if (stringEndsWith(trackerUrl, 'piwik.php')) { // if eg without domain or path "piwik.php" => '' trackerUrl = removeCharactersFromEndOfString(trackerUrl, 'piwik.php'.length); } else if (stringEndsWith(trackerUrl, '.php')) { @@ -7724,7 +7727,7 @@ if (typeof window.Piwik !== 'object') { /** * When calling plugin methods via "_paq.push(['...'])" and the plugin is loaded separately because - * piwik.js is not writable then there is a chance that first piwik.js is loaded and later the plugin. + * matomo.js is not writable then there is a chance that first matomo.js is loaded and later the plugin. * In this case we would have already executed all "_paq.push" methods and they would not have succeeded * because the plugin will be loaded only later. In this case, once a plugin is loaded, it should call * "Piwik.retryMissedPluginCalls()" so they will be executed after all. @@ -7798,7 +7801,7 @@ if (typeof window.Piwik !== 'object') { // needed to write it this way for jslint var consoleType = typeof console; if (consoleType !== 'undefined' && console && console.error) { - console.error('_paq.push() was used but Piwik tracker was not initialized before the piwik.js file was loaded. Make sure to configure the tracker via _paq.push before loading piwik.js. Alternatively, you can create a tracker via Piwik.addTracker() manually and then use _paq.push but it may not fully work as tracker methods may not be executed in the correct order.', args); + console.error('_paq.push() was used but Matomo tracker was not initialized before the matomo.js file was loaded. Make sure to configure the tracker via _paq.push before loading matomo.js. Alternatively, you can create a tracker via Matomo.addTracker() manually and then use _paq.push but it may not fully work as tracker methods may not be executed in the correct order.', args); } }}; } diff --git a/js/piwik.min.js b/js/piwik.min.js index f3fdc7998cf..43069ac8657 100644 --- a/js/piwik.min.js +++ b/js/piwik.min.js @@ -4,7 +4,7 @@ * JavaScript tracking client * * @link https://piwik.org - * @source https://github.com/piwik/piwik/blob/master/js/piwik.js + * @source https://github.com/matomo-org/matomo/blob/master/js/piwik.js * @license https://piwik.org/free-software/bsd/ BSD-3 Clause (also in js/LICENSE.txt) * @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause */ @@ -37,8 +37,8 @@ if(ao){return ac.getAttributeValueFromNode(ao,this.CONTENT_PIECE_ATTR)}var al=th if(!an){an="/"}}return an},findMediaUrlInNode:function(ap){if(!ap){return}var an=["img","embed","video","audio"];var al=ap.nodeName.toLowerCase();if(-1!==M(an,al)&&ac.findFirstNodeHavingAttributeWithValue(ap,"src")){var ao=ac.findFirstNodeHavingAttributeWithValue(ap,"src");return ac.getAttributeValueFromNode(ao,"src")}if(al==="object"&&ac.hasNodeAttributeWithValue(ap,"data")){return ac.getAttributeValueFromNode(ap,"data")}if(al==="object"){var aq=ac.findNodesByTagName(ap,"param");if(aq&&aq.length){var am;for(am=0;am0}var am=ao.clientWidth;if(T.innerWidth&&am>T.innerWidth){am=T.innerWidth}var al=ao.clientHeight;if(T.innerHeight&&al>T.innerHeight){al=T.innerHeight}return((ap.bottom>0||an)&&ap.right>0&&ap.left=0){c9=c9.slice(0,c8)}c8=c9.lastIndexOf("/");if(c8!==c9.length-1){c9=c9.slice(0,c8+1)}return c9+c7}function cz(c9,c7){var c8;c9=String(c9).toLowerCase();c7=String(c7).toLowerCase();if(c9===c7){return true}if(c7.slice(0,1)==="."){if(c9===c7.slice(1)){return true}c8=c9.length-c7.length;if((c8>0)&&(c9.slice(c8)===c7)){return true}}return false}function ce(c7){var c8=document.createElement("a"); if(c7.indexOf("//")!==0&&c7.indexOf("http")!==0){if(c7.indexOf("*")===0){c7=c7.substr(1)}if(c7.indexOf(".")===0){c7=c7.substr(1)}c7="http://"+c7}c8.href=v.toAbsoluteUrl(c7);if(c8.pathname){return c8.pathname}return""}function aY(c8,c7){if(!ag(c7,"/")){c7="/"+c7}if(!ag(c8,"/")){c8="/"+c8}var c9=(c7==="/"||c7==="/*");if(c9){return true}if(c8===c7){return true}c7=String(c7).toLowerCase();c8=String(c8).toLowerCase();if(R(c7,"*")){c7=c7.slice(0,-1);c9=(!c7||c7==="/");if(c9){return true}if(c8===c7){return true}return c8.indexOf(c7)===0}if(!R(c8,"/")){c8+="/"}if(!R(c7,"/")){c7+="/"}return c8.indexOf(c7)===0}function ao(db,dd){var c8,c7,c9,da,dc;for(c8=0;c80)&&(da.slice(c9)===c7)){return true}}}return false}function cj(c7,c9){c7=c7.replace("send_image=0","send_image=1"); var c8=new Image(1,1);c8.onload=function(){E=0;if(typeof c9==="function"){c9()}};c8.src=aA+(aA.indexOf("?")<0?"?":"&")+c7}function a1(c8){var dc="object"===typeof h&&"function"===typeof h.sendBeacon&&"function"===typeof Blob;if(!dc){return false}var db={type:"application/x-www-form-urlencoded; charset=UTF-8"};var da=false;try{var c7=new Blob([c8],db);da=h.sendBeacon(aA,c7)}catch(c9){return false}return da}function cU(c8,c9,c7){if(!J(c7)||null===c7){c7=true}if(m&&a1(c8)){return}setTimeout(function(){if(m&&a1(c8)){return}var dc;try{var db=T.XMLHttpRequest?new T.XMLHttpRequest():T.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;db.open("POST",aA,true);db.onreadystatechange=function(){if(this.readyState===4&&!(this.status>=200&&this.status<300)){var dd=m&&a1(c8);if(!dd&&c7){cj(c8,c9)}}else{if(this.readyState===4&&(typeof c9==="function")){c9()}}};db.setRequestHeader("Content-Type",cq);db.send(c8)}catch(da){dc=m&&a1(c8);if(!dc&&c7){cj(c8,c9)}}},50)}function b9(c8){var c7=new Date(); @@ -72,6 +72,6 @@ bR(cE,bj,cO);var c8,c7;for(c8=0;c81)))/4)-s((ac-1901+ad)/100)+s((ac-1601+ad)/400)}}if(!(r=n.hasOwnProperty)){r=function(ae){var ac={},ad;if((ac.__proto__=null,ac.__proto__={toString:1},ac).toString!=u){r=function(ah){var ag=this.__proto__,af=ah in (this.__proto__=null,this);this.__proto__=ag;return af}}else{ad=ac.constructor;r=function(ag){var af=(this.constructor||ad).prototype;return ag in this&&!(ag in af&&this[ag]===af[ag]) +}}ac=null;return r.call(this,ae)}}m=function(ae,ah){var af=0,ac,ad,ag;(ac=function(){this.valueOf=0}).prototype.valueOf=0;ad=new ac();for(ag in ad){if(r.call(ad,ag)){af++}}ac=ad=null;if(!af){ad=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];m=function(aj,an){var am=u.call(aj)==U,al,ak;var ai=!am&&typeof aj.constructor!="function"&&e[typeof aj.hasOwnProperty]&&aj.hasOwnProperty||r;for(al in aj){if(!(am&&al=="prototype")&&ai.call(aj,al)){an(al)}}for(ak=ad.length;al=ad[--ak];ai.call(aj,al)&&an(al)){}}}else{if(af==2){m=function(aj,am){var ai={},al=u.call(aj)==U,ak;for(ak in aj){if(!(al&&ak=="prototype")&&!r.call(ai,ak)&&(ai[ak]=1)&&r.call(aj,ak)){am(ak)}}}}else{m=function(aj,am){var al=u.call(aj)==U,ak,ai;for(ak in aj){if(!(al&&ak=="prototype")&&r.call(aj,ak)&&!(ai=ak==="constructor")){am(ak)}}if(ai||r.call(aj,(ak="constructor"))){am(ak)}}}}return m(ae,ah)};if(!o("json-stringify")){var q={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"}; +var I="000000";var t=function(ac,ad){return(I+(ad||0)).slice(-ac)};var z="\\u00";var C=function(ai){var ad='"',ag=0,ah=ai.length,ac=!F||ah>10;var af=ac&&(F?ai.split(""):ai);for(;ag-1/0&&at<1/0){if(D){ay=s(at/86400000);for(ap=s(ay/365.2425)+1970-1;D(ap+1,0)<=ay;ap++){}for(az=s((ay-D(ap,0))/30.42);D(ap,az+1)<=ay;az++){}ay=1+ay-D(ap,az);ak=(at%86400000+86400000)%86400000;aw=s(ak/3600000)%24;au=s(ak/60000)%60;aq=s(ak/1000)%60;an=ak%1000}else{ap=at.getUTCFullYear();az=at.getUTCMonth();ay=at.getUTCDate();aw=at.getUTCHours();au=at.getUTCMinutes();aq=at.getUTCSeconds();an=at.getUTCMilliseconds()}at=(ap<=0||ap>=10000?(ap<0?"-":"+")+t(6,ap<0?-ap:ap):t(4,ap))+"-"+t(2,az+1)+"-"+t(2,ay)+"T"+t(2,aw)+":"+t(2,au)+":"+t(2,aq)+"."+t(3,an)+"Z" +}else{at=null}}else{if(typeof at.toJSON=="function"&&((ae!=N&&ae!=O&&ae!=E)||r.call(at,"toJSON"))){at=at.toJSON(ai)}}}if(ag){at=ag.call(aA,ai,at)}if(at===null){return"null"}ae=u.call(at);if(ae==A){return""+at}else{if(ae==N){return at>-1/0&&at<1/0?""+at:"null"}else{if(ae==O){return C(""+at)}}}if(typeof at=="object"){for(af=aj.length;af--;){if(aj[af]===at){throw aa()}}aj.push(at);ar=[];av=ac;ac+=ax;if(ae==E){for(ah=0,af=at.length;ah0){for(ad="",af>10&&(af=10); +ad.length=48&&ad<=57||ad>=97&&ad<=102||ad>=65&&ad<=70)){H()}}ag+=M("0x"+ah.slice(ae,G));break;default:H()}}else{if(ad==34){break}ad=ah.charCodeAt(G);ae=G;while(ad>=32&&ad!=92&&ad!=34){ad=ah.charCodeAt(++G)}ag+=ah.slice(ae,G)}}}if(ah.charCodeAt(G)==34){G++; +return ag}H();default:ae=G;if(ad==45){ai=true;ad=ah.charCodeAt(++G)}if(ad>=48&&ad<=57){if(ad==48&&((ad=ah.charCodeAt(G+1)),ad>=48&&ad<=57)){H()}ai=false;for(;G=48&&ad<=57);G++){}if(ah.charCodeAt(G)==46){ac=++G;for(;ac=48&&ad<=57);ac++){}if(ac==G){H()}G=ac}ad=ah.charCodeAt(G);if(ad==101||ad==69){ad=ah.charCodeAt(++G);if(ad==43||ad==45){G++}for(ac=G;ac=48&&ad<=57);ac++){}if(ac==G){H()}G=ac}return +ah.slice(ae,G)}if(ai){H()}if(ah.slice(G,G+4)=="true"){G+=4;return true}else{if(ah.slice(G,G+5)=="false"){G+=5;return false}else{if(ah.slice(G,G+4)=="null"){G+=4;return null}}}H()}}return"$"};var W=function(ad){var ac,ae;if(ad=="$"){H()}if(typeof ad=="string"){if((F?ad.charAt(0):ad[0])=="@"){return ad.slice(1)}if(ad=="["){ac=[];for(;;ae||(ae=true)){ad=y();if(ad=="]"){break}if(ae){if(ad==","){ad=y();if(ad=="]"){H()}}else{H()}}if(ad==","){H()}ac.push(W(ad))}return ac}else{if(ad=="{"){ac={};for(;;ae||(ae=true)){ad=y(); +if(ad=="}"){break}if(ae){if(ad==","){ad=y();if(ad=="}"){H()}}else{H()}}if(ad==","||typeof ad!="string"||(F?ad.charAt(0):ad[0])!="@"||y()!=":"){H()}ac[ad.slice(1)]=W(y())}return ac}}H()}return ad};var P=function(ae,ad,af){var ac=w(ae,ad,af);if(ac===L){delete ae[ad]}else{ae[ad]=ac}};var w=function(af,ae,ag){var ad=af[ae],ac;if(typeof ad=="object"&&ad){if(u.call(ad)==E){for(ac=ad.length;ac--;){P(ad,ac,ag)}}else{m(ad,function(ah){P(ad,ah,ag)})}}return ag.call(af,ae,ad)};V.parse=function(ae,af){var ac,ad;G=0;X=""+ae;ac=W(y());if(y()!="$"){H()}G=X=null;return af&&u.call(af)==U?w((ad={},ad[""]=ac,ad),"",af):ac}}}V.runInContext=j;return V}if(h&&!c){j(i,h)}else{var f=i.JSON,k=i.JSON3,d=false;var g=j(i,(i.JSON3={noConflict:function(){if(!d){d=true;i.JSON=f;i.JSON3=k;f=k=null}return g}}));i.JSON={parse:g.parse,stringify:g.stringify}}if(c){define(function(){return g})}}).call(this);JSON_PIWIK=a})()}if(typeof _paq!=="object"){_paq=[]}if(typeof window.Piwik!=="object"){window.Matomo=window.Piwik=(function(){var r,b={},y={},G=document,h=navigator,X=screen,T=window,i=T.performance||T.mozPerformance||T.msPerformance||T.webkitPerformance,t=T.encodeURIComponent,S=T.decodeURIComponent,l=unescape,I=[],E,e,ae=[],x=0,U=0,m=false; +function p(al){try{return S(al)}catch(am){return unescape(al)}}function J(am){var al=typeof am;return al!=="undefined"}function A(al){return typeof al==="function"}function W(al){return typeof al==="object"}function w(al){return typeof al==="string"||al instanceof String}function B(am){if(!am){return true}var al;var an=true;for(al in am){if(Object.prototype.hasOwnProperty.call(am,al)){an=false}}return an}function ah(al){var am=typeof console;if(am!=="undefined"&&console&&console.error){console.error(al)}}function ad(){var aq,ap,at,am,al;for(aq=0;aq0;if(ao){ar=at.split("::");an=ar[0];at=ar[1];if("object"===typeof e[an]&&"function"===typeof e[an][at]){e[an][at].apply(e[an],am)}else{if(al){ae.push(al)}}}else{for(ap=0;ap0;if(au){ar=at.split(".");if(an&&"object"===typeof an[ar[0]]){an=an[ar[0]]; +at=ar[1]}else{if(al){ae.push(al);break}}}if(an[at]){an[at].apply(an,am)}else{var av="The method '"+at+'\' was not found in "_paq" variable. Please have a look at the Piwik tracker documentation: https://developer.piwik.org/api-reference/tracking-javascript';ah(av);if(!au){throw new TypeError(av)}}if(at==="addTracker"){break}if(at==="setTrackerUrl"||at==="setSiteId"){break}}else{at.apply(I[ap],am)}}}}}function ak(ao,an,am,al){if(ao.addEventListener){ao.addEventListener(an,am,al);return true}if(ao.attachEvent){return ao.attachEvent("on"+an,am)}ao["on"+an]=am}function n(al){if(G.readyState==="complete"){al()}else{if(T.addEventListener){T.addEventListener("load",al,false)}else{if(T.attachEvent){T.attachEvent("onload",al)}}}}function q(ao){var al=false;if(G.attachEvent){al=G.readyState==="complete"}else{al=G.readyState!=="loading"}if(al){ao();return}var an;if(G.addEventListener){ak(G,"DOMContentLoaded",function am(){G.removeEventListener("DOMContentLoaded",am,false);if(!al){al=true;ao()}})}else{if(G.attachEvent){G.attachEvent("onreadystatechange",function am(){if(G.readyState==="complete"){G.detachEvent("onreadystatechange",am); +if(!al){al=true;ao()}}});if(G.documentElement.doScroll&&T===T.top){(function am(){if(!al){try{G.documentElement.doScroll("left")}catch(ap){setTimeout(am,0);return}al=true;ao()}}())}}}ak(T,"load",function(){if(!al){al=true;ao()}},false)}function aa(am,ar,at){if(!am){return""}var al="",ao,an,ap,aq;for(ao in b){if(Object.prototype.hasOwnProperty.call(b,ao)){aq=b[ao]&&"function"===typeof b[ao][am];if(aq){an=b[ao][am];ap=an(ar||{},at);if(ap){al+=ap}}}}return al}function af(){var al;m=true;aa("unload");if(r){do{al=new Date()}while(al.getTimeAlias()=0;aq--){ap=ar[aq].split("=")[0];if(ap===an){ar.splice(aq,1)}}var av=ar.join("&");if(av){at=at+"?"+av}if(au){at+="#"+au}}return at}function f(an,am){var al="[\\?&#]"+am+"=([^&#]*)";var ap=new RegExp(al);var ao=ap.exec(an);return ao?S(ao[1]):""}function a(al){if(al&&String(al)===al){return al.replace(/^\s+|\s+$/g,"")}return al}function D(al){return unescape(t(al))}function aj(aB){var an=function(aH,aG){return(aH<>>(32-aG))},aC=function(aJ){var aH="",aI,aG;for(aI=7;aI>=0;aI--){aG=(aJ>>>(aI*4))&15;aH+=aG.toString(16)}return aH},aq,aE,aD,am=[],av=1732584193,at=4023233417,ar=2562383102,ap=271733878,ao=3285377520,aA,az,ay,ax,aw,aF,al,au=[];aB=D(aB);al=aB.length;for(aE=0;aE>>29);au.push((al<<3)&4294967295);for(aq=0;aqaq.offsetWidth+aq.scrollLeft||at+aw-axaq.offsetHeight+aq.scrollTop||ay+au-axau?-1:1});if(al.length<=1){return al}var am=0;var ao=0;var ap=[];var an;an=al[am++];while(an){if(an===al[am]){ao=ap.push(am) +}an=al[am++]||null}while(ao--){al.splice(ap[ao],1)}return al},getAttributeValueFromNode:function(ap,an){if(!this.hasNodeAttribute(ap,an)){return}if(ap&&ap.getAttribute){return ap.getAttribute(an)}if(!ap||!ap.attributes){return}var ao=(typeof ap.attributes[an]);if("undefined"===ao){return}if(ap.attributes[an].value){return ap.attributes[an].value}if(ap.attributes[an].nodeValue){return ap.attributes[an].nodeValue}var am;var al=ap.attributes;if(!al){return}for(am=0;am1000){break}al++}},findPieceNode:function(am){var al;al=ac.findFirstNodeHavingAttribute(am,this.CONTENT_PIECE_ATTR);if(!al){al=ac.findFirstNodeHavingClass(am,this.CONTENT_PIECE_CLASS)}if(al){return al}return am},findTargetNodeNoDefault:function(al){if(!al){return}var am=ac.findFirstNodeHavingAttributeWithValue(al,this.CONTENT_TARGET_ATTR); +if(am){return am}am=ac.findFirstNodeHavingAttribute(al,this.CONTENT_TARGET_ATTR);if(am){return am}am=ac.findFirstNodeHavingClass(al,this.CONTENT_TARGET_CLASS);if(am){return am}},findTargetNode:function(al){var am=this.findTargetNodeNoDefault(al);if(am){return am}return al},findContentName:function(am){if(!am){return}var ap=ac.findFirstNodeHavingAttributeWithValue(am,this.CONTENT_NAME_ATTR);if(ap){return ac.getAttributeValueFromNode(ap,this.CONTENT_NAME_ATTR)}var al=this.findContentPiece(am);if(al){return this.removeDomainIfIsInLink(al)}if(ac.hasNodeAttributeWithValue(am,"title")){return ac.getAttributeValueFromNode(am,"title")}var an=this.findPieceNode(am);if(ac.hasNodeAttributeWithValue(an,"title")){return ac.getAttributeValueFromNode(an,"title")}var ao=this.findTargetNode(am);if(ac.hasNodeAttributeWithValue(ao,"title")){return ac.getAttributeValueFromNode(ao,"title")}},findContentPiece:function(am){if(!am){return}var ao=ac.findFirstNodeHavingAttributeWithValue(am,this.CONTENT_PIECE_ATTR); +if(ao){return ac.getAttributeValueFromNode(ao,this.CONTENT_PIECE_ATTR)}var al=this.findPieceNode(am);var an=this.findMediaUrlInNode(al);if(an){return this.toAbsoluteUrl(an)}},findContentTarget:function(an){if(!an){return}var ao=this.findTargetNode(an);if(ac.hasNodeAttributeWithValue(ao,this.CONTENT_TARGET_ATTR)){return ac.getAttributeValueFromNode(ao,this.CONTENT_TARGET_ATTR)}var am;if(ac.hasNodeAttributeWithValue(ao,"href")){am=ac.getAttributeValueFromNode(ao,"href");return this.toAbsoluteUrl(am)}var al=this.findPieceNode(an);if(ac.hasNodeAttributeWithValue(al,"href")){am=ac.getAttributeValueFromNode(al,"href");return this.toAbsoluteUrl(am)}},isSameDomain:function(al){if(!al||!al.indexOf){return false}if(0===al.indexOf(this.getLocation().origin)){return true}var am=al.indexOf(this.getLocation().host);if(8>=am&&0<=am){return true}return false},removeDomainIfIsInLink:function(an){var am="^https?://[^/]+";var al="^.*//[^/]+";if(an&&an.search&&-1!==an.search(new RegExp(am))&&this.isSameDomain(an)){an=an.replace(new RegExp(al),""); +if(!an){an="/"}}return an},findMediaUrlInNode:function(ap){if(!ap){return}var an=["img","embed","video","audio"];var al=ap.nodeName.toLowerCase();if(-1!==M(an,al)&&ac.findFirstNodeHavingAttributeWithValue(ap,"src")){var ao=ac.findFirstNodeHavingAttributeWithValue(ap,"src");return ac.getAttributeValueFromNode(ao,"src")}if(al==="object"&&ac.hasNodeAttributeWithValue(ap,"data")){return ac.getAttributeValueFromNode(ap,"data")}if(al==="object"){var aq=ac.findNodesByTagName(ap,"param");if(aq&&aq.length){var am;for(am=0;am0}var am=ao.clientWidth;if(T.innerWidth&&am>T.innerWidth){am=T.innerWidth}var al=ao.clientHeight;if(T.innerHeight&&al>T.innerHeight){al=T.innerHeight}return((ap.bottom>0||an)&&ap.right>0&&ap.left=0){c9=c9.slice(0,c8)}c8=c9.lastIndexOf("/");if(c8!==c9.length-1){c9=c9.slice(0,c8+1)}return c9+c7}function cz(c9,c7){var c8;c9=String(c9).toLowerCase();c7=String(c7).toLowerCase();if(c9===c7){return true}if(c7.slice(0,1)==="."){if(c9===c7.slice(1)){return true}c8=c9.length-c7.length;if((c8>0)&&(c9.slice(c8)===c7)){return true}}return false}function ce(c7){var c8=document.createElement("a"); +if(c7.indexOf("//")!==0&&c7.indexOf("http")!==0){if(c7.indexOf("*")===0){c7=c7.substr(1)}if(c7.indexOf(".")===0){c7=c7.substr(1)}c7="http://"+c7}c8.href=v.toAbsoluteUrl(c7);if(c8.pathname){return c8.pathname}return""}function aY(c8,c7){if(!ag(c7,"/")){c7="/"+c7}if(!ag(c8,"/")){c8="/"+c8}var c9=(c7==="/"||c7==="/*");if(c9){return true}if(c8===c7){return true}c7=String(c7).toLowerCase();c8=String(c8).toLowerCase();if(R(c7,"*")){c7=c7.slice(0,-1);c9=(!c7||c7==="/");if(c9){return true}if(c8===c7){return true}return c8.indexOf(c7)===0}if(!R(c8,"/")){c8+="/"}if(!R(c7,"/")){c7+="/"}return c8.indexOf(c7)===0}function ao(db,dd){var c8,c7,c9,da,dc;for(c8=0;c80)&&(da.slice(c9)===c7)){return true}}}return false}function cj(c7,c9){c7=c7.replace("send_image=0","send_image=1"); +var c8=new Image(1,1);c8.onload=function(){E=0;if(typeof c9==="function"){c9()}};c8.src=aA+(aA.indexOf("?")<0?"?":"&")+c7}function a1(c8){var dc="object"===typeof h&&"function"===typeof h.sendBeacon&&"function"===typeof Blob;if(!dc){return false}var db={type:"application/x-www-form-urlencoded; charset=UTF-8"};var da=false;try{var c7=new Blob([c8],db);da=h.sendBeacon(aA,c7)}catch(c9){return false}return da}function cU(c8,c9,c7){if(!J(c7)||null===c7){c7=true}if(m&&a1(c8)){return}setTimeout(function(){if(m&&a1(c8)){return}var dc;try{var db=T.XMLHttpRequest?new T.XMLHttpRequest():T.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;db.open("POST",aA,true);db.onreadystatechange=function(){if(this.readyState===4&&!(this.status>=200&&this.status<300)){var dd=m&&a1(c8);if(!dd&&c7){cj(c8,c9)}}else{if(this.readyState===4&&(typeof c9==="function")){c9()}}};db.setRequestHeader("Content-Type",cq);db.send(c8)}catch(da){dc=m&&a1(c8);if(!dc&&c7){cj(c8,c9)}}},50)}function b9(c8){var c7=new Date(); +var c9=c7.getTime()+c8;if(!r||c9>r){r=c9}}function ch(c7){if(b5||!a0||!bv){return}b5=setTimeout(function c8(){b5=null;if(!a7){a7=(!G.hasFocus||G.hasFocus())}if(!a7){ch(a0);return}if(bK()){return}var c9=new Date(),da=a0-(c9.getTime()-cP);da=Math.min(a0,da);ch(da)},c7||a0)}function bD(){if(!b5){return}clearTimeout(b5);b5=null}function a5(){a7=true;if(bK()){return}ch()}function av(){bD()}function c4(){if(aJ||!a0){return}aJ=true;ak(T,"focus",a5);ak(T,"blur",av);ch()}function cv(db){var c8=new Date();var c7=c8.getTime();cP=c7;if(cu&&c72000){cU(c8,c9)}else{cj(c8,c9)}b9(c7)})}if(!aJ){c4()}else{ch()}}function cd(c7){if(cI){return false}return(c7&&c7.length)}function c3(c9,c7){if(!cd(c9)){return}if(!bv){cC.push(c9);return}var c8='{"requests":["?'+c9.join('","?')+'"]}'; +cv(function(){cU(c8,null,false);b9(c7)})}function aO(c7){return be+c7+"."+bZ+"."+bi}function bY(){if(bf){return"0"}if(!J(h.cookieEnabled)){var c7=aO("testcookie");c2(c7,"1");return az(c7)==="1"?"1":"0"}return h.cookieEnabled?"1":"0"}function bc(){bi=b0((cO||cM)+(bj||"/")).slice(0,4)}function bQ(){var c8=aO("cvar"),c7=az(c8);if(c7.length){c7=JSON_PIWIK.parse(c7);if(W(c7)){return c7}}return{}}function cw(){if(aL===false){aL=bQ()}}function cJ(){return b0((h.userAgent||"")+(h.platform||"")+JSON_PIWIK.stringify(cX)+(new Date()).getTime()+Math.random()).slice(0,16)}function aw(){return b0((h.userAgent||"")+(h.platform||"")+JSON_PIWIK.stringify(cX)).slice(0,6)}function ba(){return Math.floor((new Date()).getTime()/1000)}function aF(){var c8=ba();var c9=aw();var c7=String(c8)+c9;return c7}function cT(c9){c9=String(c9);var dc=aw();var da=dc.length;var db=c9.substr(-1*da,da);var c8=parseInt(c9.substr(0,c9.length-da),10);if(c8&&db&&db===dc){var c7=ba();if(aU<=0){return true}if(c7>=c8&&c7<=(c8+aU)){return true +}}return false}function c5(c7){if(!cF){return""}var db=f(c7,ar);if(!db){return""}db=String(db);var c9=new RegExp("^[a-zA-Z0-9]+$");if(db.length===32&&c9.test(db)){var c8=db.substr(16,32);if(cT(c8)){var da=db.substr(0,16);return da}}return""}function cG(){if(!bH){bH=c5(bG)}var c9=new Date(),c7=Math.round(c9.getTime()/1000),c8=aO("id"),dc=az(c8),db,da;if(dc){db=dc.split(".");db.unshift("0");if(bH.length){db[1]=bH}return db}if(bH.length){da=bH}else{if("0"===bY()){da=""}else{da=cJ()}}db=["1",da,c7,0,c7,"",""];return db}function aT(){var de=cG(),da=de[0],db=de[1],c8=de[2],c7=de[3],dc=de[4],c9=de[5];if(!J(de[6])){de[6]=""}var dd=de[6];return{newVisitor:da,uuid:db,createTs:c8,visitCount:c7,currentVisitTs:dc,lastVisitTs:c9,lastEcommerceOrderTs:dd}}function aD(){var da=new Date(),c8=da.getTime(),db=aT().createTs;var c7=parseInt(db,10);var c9=(c7*1000)+cB-c8;return c9}function aH(c7){if(!bZ){return}var c9=new Date(),c8=Math.round(c9.getTime()/1000);if(!J(c7)){c7=aT()}var da=c7.uuid+"."+c7.createTs+"."+c7.visitCount+"."+c8+"."+c7.lastVisitTs+"."+c7.lastEcommerceOrderTs; +c2(aO("id"),da,aD(),bj,cO,bL)}function bF(){var c7=az(aO("ref"));if(c7.length){try{c7=JSON_PIWIK.parse(c7);if(W(c7)){return c7}}catch(c8){}}return["","",0,""]}function bR(c9,c8,c7){c2(c9,"",-86400,c8,c7)}function bq(c8){var c7="testvalue";c2("test",c7,10000,null,c8);if(az("test")===c7){bR("test",null,c8);return true}return false}function aB(){var c8=bf;bf=false;var c7,c9;for(c7=0;c7dx){dn.visitCount++;dn.lastVisitTs=dn.currentVisitTs}if(!bp||!df.length){for(du in ck){if(Object.prototype.hasOwnProperty.call(ck,du)){df=f(dy,ck[du]);if(df.length){break}}}for(du in bz){if(Object.prototype.hasOwnProperty.call(bz,du)){c7=f(dy,bz[du]);if(c7.length){break}}}}dB=d(bh);di=dt.length?d(dt):"";if(dB.length&&!aQ(dB)&&(!bp||!di.length||aQ(di))){dt=bh}if(dt.length||df.length){de=dh;ds=[df,c7,de,bV(dt.slice(0,db))];c2(dp,JSON_PIWIK.stringify(ds),cV,bj,cO)}}c9+="&idsite="+bZ+"&rec=1&r="+String(Math.random()).slice(2,8)+"&h="+c8.getHours()+"&m="+c8.getMinutes()+"&s="+c8.getSeconds()+"&url="+t(bV(dy))+(bh.length?"&urlref="+t(bV(bh)):"")+((bs&&bs.length)?"&uid="+t(bs):"")+"&_id="+dn.uuid+"&_idts="+dn.createTs+"&_idvc="+dn.visitCount+"&_idn="+dn.newVisitor+(df.length?"&_rcn="+t(df):"")+(c7.length?"&_rck="+t(c7):"")+"&_refts="+de+"&_viewts="+dn.lastVisitTs+(String(dn.lastEcommerceOrderTs).length?"&_ects="+dn.lastEcommerceOrderTs:"")+(String(dt).length?"&_ref="+t(bV(dt.slice(0,db))):"")+(dk?"&cs="+t(dk):"")+"&send_image=0"; +for(du in cX){if(Object.prototype.hasOwnProperty.call(cX,du)){c9+="&"+du+"="+cX[du]}}var dA=[];if(dv){for(du in dv){if(Object.prototype.hasOwnProperty.call(dv,du)&&/^dimension\d+$/.test(du)){var dd=du.replace("dimension","");dA.push(parseInt(dd,10));dA.push(String(dd));c9+="&"+du+"="+dv[du];delete dv[du]}}}if(dv&&B(dv)){dv=null}for(du in bg){if(Object.prototype.hasOwnProperty.call(bg,du)){var dj=(-1===M(dA,du));if(dj){c9+="&dimension"+du+"="+bg[du]}}}if(dv){c9+="&data="+t(JSON_PIWIK.stringify(dv))}else{if(al){c9+="&data="+t(JSON_PIWIK.stringify(al))}}function dg(dC,dD){var dE=JSON_PIWIK.stringify(dC);if(dE.length>2){return"&"+dD+"="+t(dE)}return""}var dz=c6(bP);var dq=c6(cf);c9+=dg(dz,"cvar");c9+=dg(dq,"e_cvar");if(aL){c9+=dg(aL,"_cvar");for(du in dr){if(Object.prototype.hasOwnProperty.call(dr,du)){if(aL[du][0]===""||aL[du][1]===""){delete aL[du]}}}if(bJ){c2(dl,JSON_PIWIK.stringify(aL),ci,bj,cO)}}if(aX){if(cg){c9+=">_ms="+cg}else{if(i&&i.timing&&i.timing.requestStart&&i.timing.responseEnd){c9+=">_ms="+(i.timing.responseEnd-i.timing.requestStart) +}}}if(aG){c9+="&pv_id="+aG}dn.lastEcommerceOrderTs=J(da)&&String(da).length?da:dn.lastEcommerceOrderTs;aH(dn);b6();c9+=aa(dw,{tracker:bB,request:c9});if(cQ.length){c9+="&"+cQ}if(A(b4)){c9=b4(c9)}return c9}bK=function a2(){var c7=new Date();if(cP+a0<=c7.getTime()){var c8=cm("ping=1",null,"ping");by(c8,bC);return true}return false};function bk(da,c9,df,db,c7,di){var dd="idgoal=0",de,c8=new Date(),dg=[],dh,dc=String(da).length;if(dc){dd+="&ec_id="+t(da);de=Math.round(c8.getTime()/1000)}dd+="&revenue="+c9;if(String(df).length){dd+="&ec_st="+df}if(String(db).length){dd+="&ec_tx="+db}if(String(c7).length){dd+="&ec_sh="+c7}if(String(di).length){dd+="&ec_dt="+di}if(cR){for(dh in cR){if(Object.prototype.hasOwnProperty.call(cR,dh)){if(!J(cR[dh][1])){cR[dh][1]=""}if(!J(cR[dh][2])){cR[dh][2]=""}if(!J(cR[dh][3])||String(cR[dh][3]).length===0){cR[dh][3]=0}if(!J(cR[dh][4])||String(cR[dh][4]).length===0){cR[dh][4]=1}dg.push(cR[dh])}}dd+="&ec_items="+t(JSON_PIWIK.stringify(dg))}dd=cm(dd,al,"ecommerce",de); +by(dd,bC);if(dc){cR={}}}function bS(c7,db,da,c9,c8,dc){if(String(c7).length&&J(db)){bk(c7,db,da,c9,c8,dc)}}function bm(c7){if(J(c7)){bk("",c7,"","","","")}}function bT(c8,da,c9){aG=bb();var c7=cm("action_name="+t(ai(c8||bd)),da,"log");by(c7,bC,c9)}function aV(c9,c8){var da,c7="(^| )(piwik[_-]"+c8;if(c9){for(da=0;da0){c8+="&"}else{c8+="?"}var c9=bl();c8=F(c8,ar,c9);ac.setAnyAttribute(c7,"href",c8)}function ax(da){var db=ac.getAttributeValueFromNode(da,"href");if(!db){return false}db=String(db);var c8=db.indexOf("//")===0||db.indexOf("http://")===0||db.indexOf("https://")===0;if(!c8){return false}var c7=da.pathname||ce(da.href);var c9=(da.hostname||d(da.href)).toLowerCase();if(ao(c9,c7)){if(!cz(cM,L(c9))){return true}return false}return false}function cy(c7){var c8=c1(c7);if(c8&&c8.type){c8.href=p(c8.href);cS(c8.href,c8.type,undefined,null,c7);return}if(cF){c7=aq(c7);if(ax(c7)){cc(c7)}}}function cp(){return G.all&&!G.addEventListener}function cN(c7){var c9=c7.which;var c8=(typeof c7.button);if(!c9&&c8!=="undefined"){if(cp()){if(c7.button&1){c9=1}else{if(c7.button&2){c9=3}else{if(c7.button&4){c9=2}}}}else{if(c7.button===0||c7.button==="0"){c9=1}else{if(c7.button&1){c9=2}else{if(c7.button&2){c9=3}}}}}return c9}function bM(c7){switch(cN(c7)){case 1:return"left"; +case 2:return"middle";case 3:return"right"}}function aW(c7){return c7.target||c7.srcElement}function ay(c7){return function(da){da=da||T.event;var c9=bM(da);var db=aW(da);if(da.type==="click"){var c8=false;if(c7&&c9==="middle"){c8=true}if(db&&!c8){cy(db)}}else{if(da.type==="mousedown"){if(c9==="middle"&&db){aM=c9;bu=db}else{aM=bu=null}}else{if(da.type==="mouseup"){if(c9===aM&&db===bu){cy(db)}aM=bu=null}else{if(da.type==="contextmenu"){cy(db)}}}}}}function an(c9,c8){var c7=typeof c8;if(c7==="undefined"){c8=true}ak(c9,"click",ay(c8),false);if(c8){ak(c9,"mouseup",ay(c8),false);ak(c9,"mousedown",ay(c8),false);ak(c9,"contextmenu",ay(c8),false)}}function bw(c9,db){am=true;var da,c8=aV(bt,"ignore"),dc=G.links,c7=null,dd=null;if(dc){for(da=0;da0){db=parseInt(db,10);de(db)}})}function cx(){var c8,da,db={pdf:"application/pdf",qt:"video/quicktime",realp:"audio/x-pn-realaudio-plugin",wma:"application/x-mplayer2",dir:"application/x-director",fla:"application/x-shockwave-flash",java:"application/x-java-vm",gears:"application/x-googlegears",ag:"application/x-silverlight"};if(!((new RegExp("MSIE")).test(h.userAgent))){if(h.mimeTypes&&h.mimeTypes.length){for(c8 in db){if(Object.prototype.hasOwnProperty.call(db,c8)){da=h.mimeTypes[db[c8]];cX[c8]=(da&&da.enabledPlugin)?"1":"0"}}}if(!((new RegExp("Edge[ /](\\d+[\\.\\d]+)")).test(h.userAgent))&&typeof navigator.javaEnabled!=="unknown"&&J(h.javaEnabled)&&h.javaEnabled()){cX.java="1" +}if(A(T.GearsFactory)){cX.gears="1"}cX.cookie=bY()}var c9=parseInt(X.width,10);var c7=parseInt(X.height,10);cX.res=parseInt(c9,10)+"x"+parseInt(c7,10)}cx();bc();aH();this.getVisitorId=function(){return aT().uuid};this.getVisitorInfo=function(){return cG()};this.getAttributionInfo=function(){return bF()};this.getAttributionCampaignName=function(){return bF()[0]};this.getAttributionCampaignKeyword=function(){return bF()[1]};this.getAttributionReferrerTimestamp=function(){return bF()[2]};this.getAttributionReferrerUrl=function(){return bF()[3]};this.setTrackerUrl=function(c7){aA=c7};this.getTrackerUrl=function(){return aA};this.getPiwikUrl=function(){return O(this.getTrackerUrl(),bA)};this.addTracker=function(c7,c9){if(!c9){throw new Error("A siteId must be given to add a new tracker")}if(!J(c7)||null===c7){c7=this.getTrackerUrl()}var c8=new Q(c7,c9);I.push(c8);return c8};this.getSiteId=function(){return bZ};this.setSiteId=function(c7){bW(c7)};this.resetUserId=function(){bs=""};this.setUserId=function(c7){if(!J(c7)||!c7.length){return +}bs=c7};this.getUserId=function(){return bs};this.setCustomData=function(c7,c8){if(W(c7)){al=c7}else{if(!al){al={}}al[c7]=c8}};this.getCustomData=function(){return al};this.setCustomRequestProcessing=function(c7){b4=c7};this.appendToTrackingUrl=function(c7){cQ=c7};this.getRequest=function(c7){return cm(c7)};this.addPlugin=function(c7,c8){b[c7]=c8};this.setCustomDimension=function(c7,c8){c7=parseInt(c7,10);if(c7>0){if(!J(c8)){c8=""}if(!w(c8)){c8=String(c8)}bg[c7]=c8}};this.getCustomDimension=function(c7){c7=parseInt(c7,10);if(c7>0&&Object.prototype.hasOwnProperty.call(bg,c7)){return bg[c7]}};this.deleteCustomDimension=function(c7){c7=parseInt(c7,10);if(c7>0){delete bg[c7]}};this.setCustomVariable=function(c8,c7,db,c9){var da;if(!J(c9)){c9="visit"}if(!J(c7)){return}if(!J(db)){db=""}if(c8>0){c7=!w(c7)?String(c7):c7;db=!w(db)?String(db):db;da=[c7.slice(0,bn),db.slice(0,bn)];if(c9==="visit"||c9===2){cw();aL[c8]=da}else{if(c9==="page"||c9===3){bP[c8]=da}else{if(c9==="event"){cf[c8]=da}}}}};this.getCustomVariable=function(c8,c9){var c7; +if(!J(c9)){c9="visit"}if(c9==="page"||c9===3){c7=bP[c8]}else{if(c9==="event"){c7=cf[c8]}else{if(c9==="visit"||c9===2){cw();c7=aL[c8]}}}if(!J(c7)||(c7&&c7[0]==="")){return false}return c7};this.deleteCustomVariable=function(c7,c8){if(this.getCustomVariable(c7,c8)){this.setCustomVariable(c7,"","",c8)}};this.deleteCustomVariables=function(c7){if(c7==="page"||c7===3){bP={}}else{if(c7==="event"){cf={}}else{if(c7==="visit"||c7===2){aL={}}}}};this.storeCustomVariablesInCookie=function(){bJ=true};this.setLinkTrackingTimer=function(c7){bC=c7};this.getLinkTrackingTimer=function(){return bC};this.setDownloadExtensions=function(c7){if(w(c7)){c7=c7.split("|")}cW=c7};this.addDownloadExtensions=function(c8){var c7;if(w(c8)){c8=c8.split("|")}for(c7=0;c71&&am!=="addTracker"){ah("The method "+am+' is registered more than once in "_paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation: https://developer.piwik.org/guides/tracking-javascript-guide#multiple-piwik-trackers') +}ar[am]++}}}}return aq}var C=["addTracker","disableCookies","setTrackerUrl","setAPIUrl","enableCrossDomainLinking","setCrossDomainLinkingTimeout","setSecureCookie","setCookiePath","setCookieDomain","setDomains","setUserId","setSiteId","enableLinkTracking","requireConsent","setConsentGiven"];function ab(al,an){var am=new Q(al,an);I.push(am);_paq=c(_paq,C);for(E=0;E<_paq.length;E++){if(_paq[E]){ad(_paq[E])}}_paq=new H();return am}ak(T,"beforeunload",af,false);Date.prototype.getTimeAlias=Date.prototype.getTime;e={initialized:false,JSON:JSON_PIWIK,DOM:{addEventListener:function(ao,an,am,al){var ap=typeof al;if(ap==="undefined"){al=false}ak(ao,an,am,al)},onLoad:n,onReady:q,isNodeVisible:j,isOrWasNodeVisible:v.isNodeVisible},on:function(am,al){if(!y[am]){y[am]=[]}y[am].push(al)},off:function(an,am){if(!y[an]){return}var al=0;for(al;al -// content name = absolutePath(img-en.jpg) -// content piece = absoluteUrl(img-en.jpg) -// content target = "" - - -// content name = absolutePath(img-en.jpg) -// content piece = absoluteUrl(img-en.jpg) -// content target = "" -``` - -As you can see in these examples we do detect the content piece and name automatically based on the `src` attribute of the image. The content target cannot be detected since an image does not define a link. - -Note: In the future we may allow to define the name of the content using this attribute instead of `data-content-name` but I did not want this for two reasons: It could also define the actual content (the content piece) so it would not be intuitive, using `data-content-name` attribute allows to set the name also on nested attributes. - -### How do we detect the content piece element? -The content piece element is used to detect the actual content of a content block. - -To find the content piece element we will try to find an element having the attribute `data-content-piece` or the CSS class `piwikContentPiece`. This attribute/class can be specified anywhere within a content block. -If we do not find any specific content piece element, we will use the content block element. - -### How do we detect the content piece? - -* The simplest scenario is to provide an HTML attribute `data-content-piece="foo"` including a value anywhere within the content block or in the content block element itself. -* If there is no such attribute we will check whether the content piece element is a media (audio, video, image) and we will try to detect the URL to the media automatically. For instance using the `src` attribute. If a found media URL does not include a domain or is not an absolute URL we will make sure to have a fully qualified URL. - * In case of video and audio elements, when there are multiple sources defined, we will choose the URL of the first source -* If we haven't found anything we will fall back to use the value "Unknown". In such a case you should set the attribute `data-content-piece` telling us explicitly what the content is. - -Examples: -``` - -// content name = img.jpg -// content piece = img.jpg -// content target = http://www.example.com -``` -As you can see we can now define a specific value for the content piece which can be useful if your text or images are different in for each language. -This time we can also automatically detect the content target since we have set the content block on an `a` element. More about this later. The `data-content-piece` attribute can be set on any element, also in the `a` element. - -``` - - -// content name = absolutePath(img-en.jpg) -// content piece = absoluteUrl(img-en.jpg) -// content target = http://www.example.com -``` - -In this example we were able to detect the name and the piece of the content automatically based on the `src` attribute. - -``` -

Lorem ipsum dolor sit amet

-

Lorem ipsum dolor sit amet

-// content name = Unknown -// content piece = Unknown -// content target = http://www.example.com -``` - -As the content piece element is not an image, video or audio we cannot detect the content automatically. In such a case you have to define the `data-content-piece` attribute and set a value to it. We do not use the text of this element by default since the text might change often resulting in many content pieces, since it can be very long, since it can be translated and therefore results in many different content pieces although it is always the same, since it might contain user specific content and so on. - -Better: -``` -

Lorem ipsum dolor sit amet...

-// content name = My content -// content piece = My content -// content target = http://www.example.com -``` - -### How do we detect the content name? -The content name represents a content block which will help you in the Piwik UI to easily identify a specific block. - -* The simplest scenario is that you provide us an HTML attribute `data-content-name` with a value anywhere within a content block or in a content block element itself. -* If there is no such element we will use the value of the content piece in case there is one (if !== Unknown). - * A content piece will be usually detected automatically in case the content piece is an image, video or audio element. - * If content piece is a URL that is identical to the current domain of the website we will remove the domain from the URL -* If we do not find a name we will look for a `title` attribute in the content block element. -* If we do not find a name we will look for a `title` attribute in the content piece element. -* If we do not find a name we will look for a `title` attribute in the content target element. -* If we do not find a name we will fall back to "Unknown" - -Examples: -``` - -// content name = Image1 -// content piece = absoluteUrl(img-en.jpg) -// content target = "" -``` - -This example would be the way to go by defining a `data-content-name` attribute anywhere we can easily detect the name of the content. - -``` - -// content name = absolutePath(img-en.jpg) -// content piece = absoluteUrl(img-en.jpg) -// content target = "" -``` - -If no content name is set, it will default to the content piece in case there is one. - -``` - -// content name = /path/img-en.jpg -// content piece = http://www.example.com/path/img-en.jpg -// content target = "" -``` - -If content piece contains a domain that is the same as the current website's domain we will remove it - -``` -Lorem ipsum dolor sit amet...

-// content name = Unknown -// content piece = Unknown -// content target = http://www.example.com -``` - -In case there is no content name, no content piece and no title set anywhere it will default to "Unknown". To get a useful content name you should set either the `data-content-name` or a `title` attribute. - -``` -Lorem ipsum dolor sit amet... -// content name = Block Title -// content piece = Unknown -// content target = http://www.example.com -``` - -In case there is no content name and no content piece we will fall back to the `title` attribute of the content block. The `title` attribute of the block element takes precendence over the piece element in this example. - -### How do we detect the content target element? -The content target is the element that we will use to detect the URL of the landing page of the content block. The target element is usually a link or a button element. Generally said the target doesn't have to be a URL it can be anything but in most cases it will be a URL. A target could be for instance also a tab-container - -We detect the target element either by the attribute `data-content-target` or by the class `.piwikContentTarget`. If no such element can be found we will fall back to the content block element. - -### How do we detect the content target URL? - -* The simplest scenario is that you provide us an HTML attribute `data-content-target` with a value anywhere within a content block or in a content block element itself. -* If there is no such element we will look for an `href` attribute in the target element -* If there is no such attribute we will use an empty string "" - -Examples: -``` -Click me -// content name = Unknown -// content piece = Unknown -// content target = "http://www.example.com" -``` - -As no specific target element is set, we will read the `href` attribute of the content block. - -``` -Click me -// content name = Unknown -// content piece = Unknown -// content target = "http://www.example.com" -``` - -No `href` attribute is used as the link is executed via javascript. Therefore a `data-content-target` attribute with value has to be specified. - - -``` -
- -// content name = Unknown -// content piece = Unknown -// content target = "" -``` - -As there is neither a `data-content-target` attribute nor a `href` attribute we cannot detect the target. - -``` -
- -// content name = Unknown -// content piece = Unknown -// content target = "http://www.example.com" -``` - -As the `data-content-target` attribute is specifically set with a value, we can detect the target URL based on this. Otherwise we could not. - -``` - - -// content name = Unknown -// content piece = Unknown -// content target = "http://www.example.com" -``` - -As the target element has a `href` attribute we can detect the content target automatically. - -### How do we track an interaction automatically? - -Interactions can be detected declarative in case the detected target element is an `a` and `area` element with an `href` attribute. If not, you will have to track -the interaction programmatically, see one of the next sections. We generally treat links to the same page differently than downloads or outlinks. - -We use `click` events do detect an interaction with a content. On mobile devices you might want to listen to `touch` events. In this case you may have to disable automatic content interaction tracking see below. - -#### Links to the same domain -In case we detect a link to the same website we will replace the current `href` attribute with a link to the `piwik.php` tracker URL. Whenever a user clicks on such a link we will first send the user to the `piwik.php` of your Piwik installation and then redirect the user from there to the actual page. This click will be tracked as an event. Where the event category is the string `Content`, the event action is the value of the content interaction such as `click` and the event name will be the same as the content name. - -If the URL of the replaced `href` attribute changes meanwhile by your code we will respect the new `href` attribute and make sure to update the link with a `piwik.php` URL. Therefore we will add a `click` listener to the element. - -Note: The referrer information will get lost when redirecting from piwik.php to your page. If you depend on this you need to disable automatic tracking of interaction see below - -If you have added an `href` attribute after we scanned the DOM for content blocks we can not detect this and an interaction won't be tracked. - -#### Outlinks and downloads -Outlinks and downloads are handled as before. If a user clicks on a download or outlink we will track this action using an XHR. Along with the information of this action we will send the information related to the content block. We will not track an additional event for this. - -#### Anchor links -Anchor links will be tracked using an XHR. - -### How to prevent the automatic tracking of an interaction? - -Maybe you do not want us to track any interaction automatically as explained before. -To do so you can either set the attribute `data-content-ignoreinteraction` or the CSS class `piwikContentIgnoreInteraction` on the content target element. - -Examples -``` -Add to shopping cart -Add to shopping cart - -``` - -In all examples we would track the impression automatically but not the interaction. - -Note: In single page application you will most likely always have to disable automatic tracking of an interaction as otherwise a page reload and a redirect will happen. - -### Putting it all together - -A few Examples: - -``` - -// content name = My Ad -// content piece = http://www.example.com/path/xyz.jpg -// content target = /anylink -``` - -A typical example for a content block that displays an image - which is the content piece - and a call to action link - which is the content target - below. -We would replace the `href=/anylink` with a link to piwik.php of your Piwik installation which will in turn redirect the user to the actual target to actually track the interaction. - -``` - - - -// content name = /path/xyz.jpg -// content piece = http://www.example.com/path/xyz.jpg -// content target = http://ad.example.com -``` - -A typical example for a content block that displays a banner ad. - -``` - - Lorem ipsum.... - -// content name = My Ad -// content piece = Unknown -// content target = http://ad.example.com -``` - -A typical example for a content block that displays a text ad. - -## Tracking the content programmatically - -There are several ways to track a content impression and/or interaction manually, semi-automatically and automatically. Please be aware that content impressions will be tracked using bulk tracking which will always send a `POST` request, even if `GET` is configured which is the default. - -Note: In case you have link tracking enabled you should call `enableLinkTracking()` before any of those functions. - -#### `trackAllContentImpressions()` - -You can use this method to scan the entire DOM for content blocks. -For each content block we will track a content impression immediately. If you only want to track visible content impression have a look at `trackVisibleContentImpressions()`. - -Note: We will not send an impression of the same content block twice if you call this method multiple times unless `trackPageView()` is called meanwhile. This is useful for single page applications. The "same" content blocks means if a content block has the identical name, piece and target as an already tracked one. -Note: At this stage we do not exeute this method automatically along with a trackPageView(), we can do this later once we know it works - -#### `trackVisibleContentImpressions(checkOnSroll, timeIntervalInMs)` -If you enable to track only visible content we will only track an impression if a content block is actually visible. With visible we mean the content block has been in the view port, it is actually in the DOM and is not hidden via CSS (opacity, visibility, display, ...). - -* Optionally you can tell us to rescan the DOM automatically after each scroll event by passing `checkOnSroll=true`. We will then check whether the previously hidden content blocks are visible now and if so track the impression. - * Parameter defaults to boolean `true` if not specified. - * As the scroll event is triggered after each pixel scrolling would be very slow when checking for new visible content blocks each time the event is triggered. Instead we are checking every 100ms whether a scroll event was triggered and if so we scan the DOM for new visible content blocks - * Note: If a content block is placed within a scrollable element (`overflow: scroll`), we do currently not attach an event in case the user scrolls within this element. This means we would not detect that such an element becomes visible. -* Optionally you can tell us to rescan the entire DOM for new impressions every X milliseconds by passing `timeIntervalInMs=500` (rescan DOM every 500ms). - * If parameter is not set, a default interval sof 750ms will be used. - * Rescanning the entire DOM and detecting the visible state of content blocks can take a while depending on the browser and amount of content - * We do not really rescan every X milliseconds. We will schedule the next rescan after a previous scan has finished. So if it takes 20ms to scan the DOM and you tell us to rescan every 50ms it can actually take 70ms. - * In case your frames per second goes down you might want to increase this value -* If you do want to only track visible content but not want us to perform any checks automatically you can either call `trackVisibleContentImpressions()` manually at any time to rescan the entire DOM or `trackContentImpressionsWithinNode()` to check only a specific part of the DOM for visible content blocks. - * Call `trackVisibleContentImpressions(false, 0)` to initially track only visible content impressions - * Call `trackVisibleContentImpressions()` at any time again to rescan the entire DOM for newly visible content blocks or - * Call `trackContentImpressionsWithinNode(node)` at any time to rescan only a part of the DOM for newly visible content blocks - -Note: You can not change the `checkOnScroll` or `timeIntervalInMs` after this method was called the first time. - -#### `(checkOnSroll, timeIntervalInMs)` - -Is a shorthand for calling `enableTrackOnlyVisibleContent()` and `trackContentImpressions()`. - -#### `trackContentImpressionsWithinNode(domNode, contentTarget)` - -You can use this method if you, for instance, dynamically add an element using JavaScript to your DOM after the we have tracked the initial impressions. Calling this method will make sure an impression will be tracked for all content blocks contained within this node. - -Example -``` -var div = $('
...
...
...
...
'); -$('#id').append(div); - -_paq.push(['trackContentImpressionsWithinNode', div[0]]); -``` - -We would detect two new content blocks in this example. - -Please note: In case you have enabled to only track visible content blocks we will respect this. In case it contains a content block that was already tracked we will not track it again. - -#### trackContentInteractionNode(domNode, contentInteraction) - -By default we track interactions depending on a click and sometimes we cannot track interactions automatically add all. See "How do we track an interaction automatically?". In case you want to track an interaction manually for instance on a double click or on a form submit you can do this as following: - -Example -``` -anyElement.addEventListener('dblclick', function () { - _paq.push(['trackContentInteractionNode', this]); -}); -form.addEventListener('dblclick', function () { - _paq.push(['trackContentInteractionNode', this, 'submittedForm']); -}); -``` - -* The passed `domNode` can be any node within a content block or the content block element itself. Nothing will be tracked in case there is no content-block found. -* The content name and piece will be detected based on the content block -* Optionally you can set the name of the content interaction. If none is provided the `Unknown` will be used. Could be for instance `click` or `submit`. -* The interaction will actually only have any effect if an impression was tracked for this content-block - -#### `trackContentImpression(contentName, contentPiece, contentTarget)` and `trackContentInteraction(contentName, contentPiece, contentInteraction)` -You should use those methods only in conjunction together. It is not recommended to use `trackContentInteraction()` after an impression was tracked automatically using on of the other methods as an interaction would only count if you do set the same content name and piece that was used to track the related impression. - -Example -``` -_paq.push(['trackContentImpression', 'Content Name', 'Content Piece', 'http://www.example.com']); - -div.addEventListener('click', function () { - _paq.push(['trackContentInteraction', 'Content Name', 'Content Piece', 'tabActivated']); -}); -``` - -Be aware that each call to one of those two methods will send one request to your Piwik tracker instance. Calling those methods too many times can cause performance problems. - -## Tracking Content Impressions API - -Content impressions are logically not really events and I don't think it makes sense to use them here. It would also make it harder to analyze events when they are mixed with pieces of content. - -* To track a content impression you will need to send the URL parameters `c_n`, `c_p` and `c_t` for name, piece and target along a tracking request. -* `c_p` for content piece and `c_t` for content target is optional. -* Multiple content impressions can be sent using bulk tracking for faster performance - -## Tracking content interactions API -Contrary to impressions, clicks are actually events and it would be nice to use events here unless it is not an outlink or download to not lose such tracking data. - -* To track a content interaction you will need to send at least the URL parameters `c_n`, `c_p` and `c_i` for name and interaction - -We will link interactions to impressions at archiver time. - -## Database - -* New column `idaction_content_url` and `idaction_content_piece` in `log_link_visit_action`. For name `idaction_name` can be reused? - -Could we also reuse `idaction_url` instead of adding new column `idaction_content_url`? -And we could also store the URL of the page showing the Content in `idaction_url_ref`. (reusing columns is good in this case) - - * Would we need a new column for each piece of content in action table to make archiver work? --> would result in many! columns - * or would we need a new table for each piece of content to make archiver work? --> would be basically a copy of the link_action table and therefore not really makes sense I reckon. Only a lot of work. Logically I am not sure if an impression is actually an "action" so it could make sense - * or would we store the pieces serialized as JSON in a `content` column? I don't know anything about the archiver but I think it wouldn't work at all - * or would we create an action entry for each piece of content? --> yes I think! - -Yes it seems most logical to create an action entry for each Content. - -## Thoughts on piwik.js -* We need to find all dom nodes having css class or html attribute. - * Options for this is traversing over each node and checking for everything -> CSS selectors cannot be used on all browsers and it might be slow therefore -> maybe lot of work to make it cross browser compatible - * https://github.com/fabiomcosta/micro-selector --> tiny selector library but does not support attributes - * http://sizzlejs.com/ Used by jQuery & co but like 30kb (compressed + gzipped 4kb). Has way too many features we don't need - * https://github.com/ded/qwery Doesn't support IE8 and a few others, no support for attribute selector - * https://github.com/padolsey/satisfy 2.4KB and probably outdated - * https://github.com/digitarald/sly very tiny and many features but last commit 3 years old - * https://github.com/alpha123/Jaguar >10KB and last commit 2 years old - * As we don't need many features we could implement it ourselves but probably needs a lot of cross-browser testing which I wanted to avoid. We'd only start with `querySelectorAll()` maybe. Brings also incredible [performance benefits](http://jsperf.com/jquery-vs-native-selector-and-element-style/2) (2-10 faster than jQuery) but there might be problems see http://stackoverflow.com/questions/11503534/jquery-vs-document-queryselectorall, http://jsfiddle.net/QdMc5/ and http://ejohn.org/blog/thoughts-on-queryselectorall/ - -## Reports -Nothing special here I think. We would probably automatically detect the type of content (image, video, text, sound, ...) depending on the content eg in case it ends with [.jpg, .png, .gif] it could be recognized as image content and show a banner in the report. - -## TODO -* UI tests - - -## Notes: -* Referrer gets lost when using piwik.php -* Single page applications will always want to disable interactions as redirect would not fit into their concept!!! -* User can decide to manually setup the proper redirect URL via piwik.php?rec=1&idsite=1&clickurl={$URL_HERE}&.... - * Currently, the user would also have to add event URL parameters and make sure to send the correct name and piece to match an impression. - * If the user does not use any data-content-* attributes this is very likely to fail since the auto detected content name and piece can easily change and tracking would be broken - * The only advantage I see would be that we even track clicks if we haven't added a click listener to replace the URL yet (for instance before DOM loaded) -* and/or maybe we can replace the href="" directly within the DOM so right click, middle click, shift click are also tracked - * sounds ok to me, have implement it like this. Only problem is in case a replaced link changes later for instance based on a visitor form selection. - * To prevent this I added a click event on top of it and in case it does not start with configTrackerUrl I will build it again - * it might be bad for SEO - * FYI: outlinks/downloads will be still tracked as it is done currently for simplicity (500ms) so we are talking here only about internal links that are not anchor links (starting with "#"). Those would not be tracked - * http://outlink.example.org --> not replaced -> handled the old way - * #target --> not replaced -> handled the old way. In single page application users have to call trackWhatever again - * note to myself: They should be able to parse a node that we parse for all content as you maybe wanna parse only the replaced ajax content. maybe v2 - * index.php, /foo/bar --> will be directly replaced by piwik.php in case clickNode (element having clickAttribute/Class) is an "A" element - * Need to think about possible XSS. If an attacker can set href attributes on that website and we replace attribute based on that but should be ok ... -* FYI: Piwik Mobile displays currently only one metric, so people won't see impressions and number of interactions or ratio next to each other -* If user wants to track only visible content we'll need to wait until the websites load (not DOMContentLoaded) event is triggered. Otherwise CSS might be not be applied yet and we cannot detect whether node is actually visible. Downside: Some websites might take > 10 seconds until this event is triggered. Depending on how good they are developed. During this time the user might be already no longer on that page or might have already scrolled to somewhere else. -* If user wants to track all content impressions (not only the visible ones) we'd probably have to wait until at least DOMContentLoaded event is triggered -* If the load event takes like 10 seconds later, the user has maybe already scrolled and seen some content blocks but we cannot detect... so considering viewport we need to assume all above the deepest scrollpoint was seen - - -## Answered Questions -1. Can the same content piece have different names / targets? Can the same content name have different targets/pieces? - -Maybe the unique ID of a Content can be the { Content name + Content piece }. Then we would recommend users to set the same Content target for a given tuple { Content name, Content piece }. - -I hope it makes sense to assume this tuple will have always same Content target by design? - -In this case I would modify questionas as follows: - * Can the same content piece have different names? Yes (eg. a banner image is used by different Content names), - * Can the same { content name, content piece } have different targets? Yes, but it's not recommended: Piwik will only aggregate one content target value. (eg. keep the latest content target value tracked for this { content name, content piece } tuple on a given day) - - -2. Are we always assuming the "conversion" or "target URL" is caused by a click or can it be a hover or drag/drop, ...? For a general solution we might want to assume it can be anything? - * In this case we would also rename or need an additional attribute or whatever to [data-trackclick] etc. - -When drag and dropping there is a click needed by user, so maybe `data-trackclick` would still be OK in this case? -if you have better naming idea feel free to suggest. Or maybe you have other use cases besides clicks and drag n drop? - -3. Would a piece of content - such as a banner - have maybe custom variables etc? - -It would be nice to be able to set custom variables to Contents. - -One possible use case is A/B testing. Maybe it would make sense to use Contents plugin for A/B testing. We could measure Content name = Experiment_TopMenu, Content piece = http://host/a.jpg. In a custom variable we would store "experiment => B". Then we would know that the given experiment is called Experiment_TopMenu and is defined by the image and that it's the variant B being served. - -4. How do we present the data in a report? Similar to events with second dimensions? Probably depends on 1) - -Second dimension would be really powerful to have (as per suggestion in 1)). It would let user see different banner images for a given banner name. - -There would be two reports: - * First dimension: Banner Names, Second dimension: Banner pieces - * First dimension: Banner pieces, Second dimension: Banner names - -(It's a bit simpler than Events because we don't need to switch the second dimension.) - -5. I assume there can be nested content in theory. A piece of content that contains another piece of content. In this case we have to be careful when automatically picking name, target, ... - -Nested content makes sense (users will do this). How would it work when several contents are nested? -Note: we don't need to handle this case in MVP but maybe worth thinking about it. - -6. FYI: We would probably also need an attribute like data-target="$target" and/or the possibility for data-trackclick="$target" since not all links might be defined via href but onclick javascript links. See next section - -+1 - -7. HTML Attributes always take precendence over css classes or the other way around (if both defined)? I think attributes should take precendence which I think is also defined in the spec - -attributes take precedence over CSS classes - -8. Do we need to support IE7 and older? Firefox 3 and older? - -Support modern browsers is enough (ie. last 2 years or so?). - -9. "Maybe we could automatically detect when such element becomes visible, and send the Impression event automatically" - * I think we can detect whether a specific content was visible at a specific time in most cases but not necessarily automatically. We would have to check the DOM for this every few ms (in case of Carousel) and we'd also have to attach to events like scrolling etc. This can make other peoples website slow, especially on mobile but even browser. Website owners usually want to achieve 60fps to have animations and scrolling smooth and they usually invest a lot of time to achieve this. So it has to an opt-in if at all - -in case user tags an element with `data-noautotrack` then it's already a kind of opt-in by user, so maybe in this case it's acceptable to check whether element tagged is visible, eg. every 500 ms ? - - * Do I understand it right that we send an impression only if it is visible? - -Yes. - - * We'd probably have to offer a mode to send all banners independend of visibility - -Sounds good: this would make Contents plugin more generic. - - - * We'd probably have to offer a mode to rescan all banners again at a certain time and only track those content pieces now that were not visible before but are now - -In ticket I wrote `function trackContentPieces() that will let users re-scan the page for Content pieces when DOM has changed.` but maybe instead the function should be called `rescanPageForContents` ? - - * We'd probably have to offer a method to pass a DOM node and track it independent of visibility (useful for instance in case of carousel when the website owner already knows a specific content piece is visible now but does not want to use expensive events for this) - -if I understand correctly it would make life of JS developers easier by providing nicer APIs to them? - -so +1 - - * We'd maybe have to offer a mode where we are trying to detect automatically when an impression becomes visible and send it - -I think that should be the default mode, ie. on page load we detect impressions, and then we also attach to events like scrolling to check ie. every 500ms whether a given Contents is visible. Would that be work? - -10. FYI: "you may add a CSS class or attribute to the link element to track" => It could be also a span, a div or something else -11. FYI: There is way to much magic how content-name is found and it is neither predictable nor understandable by users, I will simplify this and rather require users to set specific attributes! See next section - -OK - -12. FYI: We need to define how a content piece is defined in markup since it can be anything (was something like piwik-banner before) see next section - -13. Why do we track an event for an interaction? Which is with the currently implementation done only on a click to an internal URL anyway... does it actually make sense? I mean there will be pageview -> content + event action -> same pageview after redirect. We would track same information 3 times -It makes actually no sense and I will remove it again. It makes no sense because: -* We would currently only track links to the same website as an event (as only there piwik.php is used), we could use it for other links as well but why... -* A click to an internal page of the same website is simply no event per se. Also to an outlink or download... it is not an event -* As it is possible that we would add many different EventNames (= ContentNames) and EventActions (=ContentInteraction) it would maybe make it harder for some users to analyze their event names/actions that they use for other things -* The tracked content will be already displayed in the content report anyway, why displaying the same data in 2 reports (events and contents or actually even 3 reports as a pageview will be later tracked as well). There is no value in it -* ... diff --git a/misc/others/tracker_simpleImageTracker.php b/misc/others/tracker_simpleImageTracker.php index 2f10fe279de..bf4ac796c5f 100644 --- a/misc/others/tracker_simpleImageTracker.php +++ b/misc/others/tracker_simpleImageTracker.php @@ -1,27 +1,27 @@ Page titles'); ?> - + - + -This page loads a Simple Tracker request to Piwik website id=1 +This page loads a Simple Tracker request to Matomo website id=1 '; diff --git a/piwik.js b/piwik.js index f3fdc7998cf..43069ac8657 100644 --- a/piwik.js +++ b/piwik.js @@ -4,7 +4,7 @@ * JavaScript tracking client * * @link https://piwik.org - * @source https://github.com/piwik/piwik/blob/master/js/piwik.js + * @source https://github.com/matomo-org/matomo/blob/master/js/piwik.js * @license https://piwik.org/free-software/bsd/ BSD-3 Clause (also in js/LICENSE.txt) * @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause */ @@ -37,8 +37,8 @@ if(ao){return ac.getAttributeValueFromNode(ao,this.CONTENT_PIECE_ATTR)}var al=th if(!an){an="/"}}return an},findMediaUrlInNode:function(ap){if(!ap){return}var an=["img","embed","video","audio"];var al=ap.nodeName.toLowerCase();if(-1!==M(an,al)&&ac.findFirstNodeHavingAttributeWithValue(ap,"src")){var ao=ac.findFirstNodeHavingAttributeWithValue(ap,"src");return ac.getAttributeValueFromNode(ao,"src")}if(al==="object"&&ac.hasNodeAttributeWithValue(ap,"data")){return ac.getAttributeValueFromNode(ap,"data")}if(al==="object"){var aq=ac.findNodesByTagName(ap,"param");if(aq&&aq.length){var am;for(am=0;am0}var am=ao.clientWidth;if(T.innerWidth&&am>T.innerWidth){am=T.innerWidth}var al=ao.clientHeight;if(T.innerHeight&&al>T.innerHeight){al=T.innerHeight}return((ap.bottom>0||an)&&ap.right>0&&ap.left=0){c9=c9.slice(0,c8)}c8=c9.lastIndexOf("/");if(c8!==c9.length-1){c9=c9.slice(0,c8+1)}return c9+c7}function cz(c9,c7){var c8;c9=String(c9).toLowerCase();c7=String(c7).toLowerCase();if(c9===c7){return true}if(c7.slice(0,1)==="."){if(c9===c7.slice(1)){return true}c8=c9.length-c7.length;if((c8>0)&&(c9.slice(c8)===c7)){return true}}return false}function ce(c7){var c8=document.createElement("a"); if(c7.indexOf("//")!==0&&c7.indexOf("http")!==0){if(c7.indexOf("*")===0){c7=c7.substr(1)}if(c7.indexOf(".")===0){c7=c7.substr(1)}c7="http://"+c7}c8.href=v.toAbsoluteUrl(c7);if(c8.pathname){return c8.pathname}return""}function aY(c8,c7){if(!ag(c7,"/")){c7="/"+c7}if(!ag(c8,"/")){c8="/"+c8}var c9=(c7==="/"||c7==="/*");if(c9){return true}if(c8===c7){return true}c7=String(c7).toLowerCase();c8=String(c8).toLowerCase();if(R(c7,"*")){c7=c7.slice(0,-1);c9=(!c7||c7==="/");if(c9){return true}if(c8===c7){return true}return c8.indexOf(c7)===0}if(!R(c8,"/")){c8+="/"}if(!R(c7,"/")){c7+="/"}return c8.indexOf(c7)===0}function ao(db,dd){var c8,c7,c9,da,dc;for(c8=0;c80)&&(da.slice(c9)===c7)){return true}}}return false}function cj(c7,c9){c7=c7.replace("send_image=0","send_image=1"); var c8=new Image(1,1);c8.onload=function(){E=0;if(typeof c9==="function"){c9()}};c8.src=aA+(aA.indexOf("?")<0?"?":"&")+c7}function a1(c8){var dc="object"===typeof h&&"function"===typeof h.sendBeacon&&"function"===typeof Blob;if(!dc){return false}var db={type:"application/x-www-form-urlencoded; charset=UTF-8"};var da=false;try{var c7=new Blob([c8],db);da=h.sendBeacon(aA,c7)}catch(c9){return false}return da}function cU(c8,c9,c7){if(!J(c7)||null===c7){c7=true}if(m&&a1(c8)){return}setTimeout(function(){if(m&&a1(c8)){return}var dc;try{var db=T.XMLHttpRequest?new T.XMLHttpRequest():T.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;db.open("POST",aA,true);db.onreadystatechange=function(){if(this.readyState===4&&!(this.status>=200&&this.status<300)){var dd=m&&a1(c8);if(!dd&&c7){cj(c8,c9)}}else{if(this.readyState===4&&(typeof c9==="function")){c9()}}};db.setRequestHeader("Content-Type",cq);db.send(c8)}catch(da){dc=m&&a1(c8);if(!dc&&c7){cj(c8,c9)}}},50)}function b9(c8){var c7=new Date(); @@ -72,6 +72,6 @@ bR(cE,bj,cO);var c8,c7;for(c8=0;c8setName('custom-piwik-js:update'); + $this->setAliases(array('custom-matomo-js:update')); $this->addOption('source-file', null, InputOption::VALUE_REQUIRED, 'Absolute path to source PiwikJS file.', $this->getPathOriginalPiwikJs()); - $this->addOption('target-file', null, InputOption::VALUE_REQUIRED, 'Absolute path to target file. Useful if your /piwik.js is not writable and you want to replace the file manually', PIWIK_DOCUMENT_ROOT . TrackerUpdater::TARGET_PIWIK_JS); + $this->addOption('target-file', null, InputOption::VALUE_REQUIRED, 'Absolute path to target file. Useful if your /matomo.js is not writable and you want to replace the file manually', PIWIK_DOCUMENT_ROOT . TrackerUpdater::TARGET_MATOMO_JS); $this->addOption('ignore-minified', null, InputOption::VALUE_NONE, 'Ignore minified tracker files, useful during development so the original source file can be debugged'); $this->setDescription('Update the Javascript Tracker with plugin tracker additions'); } diff --git a/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php b/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php index 3766dc650bd..b952214cd7f 100644 --- a/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php +++ b/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php @@ -12,7 +12,9 @@ use Piwik\Plugins\CustomPiwikJs\File; use Piwik\Plugins\Diagnostics\Diagnostic\Diagnostic; use Piwik\Plugins\Diagnostics\Diagnostic\DiagnosticResult; +use Piwik\SettingsPiwik; use Piwik\SettingsServer; +use Piwik\Tracker\TrackerCodeGenerator; use Piwik\Translation\Translator; /** @@ -32,23 +34,49 @@ public function __construct(Translator $translator) public function execute() { - $label = $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsWritable'); + // for users that installed matomo 3.7+ we only check for matomo.js being writable... for all other users we + // check both piwik.js and matomo.js as they can use both + $filesToCheck = array('matomo.js'); - $file = new File(PIWIK_DOCUMENT_ROOT . '/piwik.js'); + $jsCodeGenerator = new TrackerCodeGenerator(); + if (SettingsPiwik::isMatomoInstalled() && $jsCodeGenerator->shouldPreferPiwikEndpoint()) { + // if matomo is not installed yet, we definitely prefer matomo.js... check for isMatomoInstalled is needed + // cause otherwise it would perform a db query before matomo DB is configured + $filesToCheck[] = 'piwik.js'; + } + + $notWritableFiles = array(); + foreach ($filesToCheck as $fileToCheck) { + $file = new File(PIWIK_DOCUMENT_ROOT . '/' . $fileToCheck); + + if (!$file->hasWriteAccess()) { + $notWritableFiles[] = $fileToCheck; + } + } - if ($file->hasWriteAccess()) { + $label = $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsWritable', $this->makeFilesTitles($filesToCheck)); + + if (empty($notWritableFiles)) { return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_OK, '')); } - $comment = $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsNotWritable'); + $comment = $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsNotWritable', $this->makeFilesTitles($notWritableFiles)); - if(!SettingsServer::isWindows()) { - $realpath = Filesystem::realpath(PIWIK_INCLUDE_PATH . '/piwik.js'); - $command = "
chmod +w $realpath
chown ". Filechecks::getUserAndGroup() ." " . $realpath . "

"; - $comment .= $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsMakeWritable', $command); + if (!SettingsServer::isWindows()) { + $command = ''; + foreach ($notWritableFiles as $notWritableFile) { + $realpath = Filesystem::realpath(PIWIK_INCLUDE_PATH . '/' . $notWritableFile); + $command .= "
chmod +w $realpath
chown ". Filechecks::getUserAndGroup() ." " . $realpath . "

"; + } + $comment .= $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsMakeWritable', array($this->makeFilesTitles($notWritableFiles), $command)); } return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $comment)); } + private function makeFilesTitles($files) + { + return '"/'. implode('" & "/', $files) .'"'; + } + } diff --git a/plugins/CustomPiwikJs/TrackerUpdater.php b/plugins/CustomPiwikJs/TrackerUpdater.php index 37476a74234..ea15e7636aa 100644 --- a/plugins/CustomPiwikJs/TrackerUpdater.php +++ b/plugins/CustomPiwikJs/TrackerUpdater.php @@ -8,6 +8,7 @@ namespace Piwik\Plugins\CustomPiwikJs; +use Piwik\Common; use Piwik\Container\StaticContainer; use Piwik\Plugins\CustomPiwikJs\TrackingCode\PiwikJsManipulator; use Piwik\Plugins\CustomPiwikJs\TrackingCode\PluginTrackerFiles; @@ -23,7 +24,7 @@ class TrackerUpdater { const DEVELOPMENT_PIWIK_JS = '/js/piwik.js'; const ORIGINAL_PIWIK_JS = '/js/piwik.min.js'; - const TARGET_PIWIK_JS = '/piwik.js'; + const TARGET_MATOMO_JS = '/matomo.js'; /** * @var File @@ -48,7 +49,7 @@ public function __construct($fromFile = null, $toFile = null) } if (!isset($toFile)) { - $toFile = PIWIK_DOCUMENT_ROOT . self::TARGET_PIWIK_JS; + $toFile = PIWIK_DOCUMENT_ROOT . self::TARGET_MATOMO_JS; } $this->setFromFile($fromFile); @@ -139,5 +140,21 @@ public function update() */ Piwik::postEvent('CustomPiwikJs.piwikJsChanged', [$this->toFile->getPath()]); } + + // we need to make sure to sync matomo.js / piwik.js + $this->updateAlternative('piwik.js', 'matomo.js', $newContent); + $this->updateAlternative('matomo.js', 'piwik.js', $newContent); + } + + private function updateAlternative($fromFile, $toFile, $newContent) + { + if (Common::stringEndsWith($this->toFile->getName(), $fromFile)) { + $alternativeFilename = dirname($this->toFile->getName()) . DIRECTORY_SEPARATOR . $toFile; + $file = new File($alternativeFilename); + if ($file->hasWriteAccess() && $file->getContent() !== $newContent) { + $file->save($newContent); + Piwik::postEvent('CustomPiwikJs.piwikJsChanged', [$file->getPath()]); + } + } } } diff --git a/plugins/CustomPiwikJs/lang/en.json b/plugins/CustomPiwikJs/lang/en.json index 24fb9728b43..53e6c9c68c8 100644 --- a/plugins/CustomPiwikJs/lang/en.json +++ b/plugins/CustomPiwikJs/lang/en.json @@ -1,8 +1,8 @@ { "CustomPiwikJs": { - "PluginDescription": "Allows any plugin to extend the Matomo JavaScript Tracking file (piwik.js) and add new functionnality and website measurement capabilities.", - "DiagnosticPiwikJsWritable": "Writable JavaScript Tracker (\"/piwik.js\")", - "DiagnosticPiwikJsNotWritable": "The Matomo JavaScript tracker file \"/piwik.js\" is not writable which means other plugins cannot extend the JavaScript tracker. In the future even some core features might not work as expected. ", - "DiagnosticPiwikJsMakeWritable": "We recommend to piwik.js writable by running this command: %s" + "PluginDescription": "Allows any plugin to extend the Matomo JavaScript Tracking file (matomo.js) and add new functionnality and website measurement capabilities.", + "DiagnosticPiwikJsWritable": "Writable JavaScript Tracker (%s)", + "DiagnosticPiwikJsNotWritable": "The Matomo JavaScript tracker file %s is not writable which means other plugins cannot extend the JavaScript tracker. In the future even some core features might not work as expected. ", + "DiagnosticPiwikJsMakeWritable": "We recommend to make %1$s writable by running this command: %2$s" } } \ No newline at end of file diff --git a/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php b/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php index 653c5105c55..7a66b035fbb 100644 --- a/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php +++ b/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php @@ -67,7 +67,7 @@ public function test_construct_setsDefaults() $this->assertTrue($toFile instanceof File); $this->assertSame(basename(TrackerUpdater::ORIGINAL_PIWIK_JS), $fromFile->getName()); - $this->assertSame(basename(TrackerUpdater::TARGET_PIWIK_JS), $toFile->getName()); + $this->assertSame(basename(TrackerUpdater::TARGET_MATOMO_JS), $toFile->getName()); } public function test_setFormFile_getFromFile() diff --git a/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php b/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php index dd3f08ab3ae..a8ca3eb844f 100644 --- a/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php +++ b/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php @@ -23,7 +23,7 @@ class PiwikJsContentTest extends SystemTestCase public function test_piwikJsAndPiwikMinJsMustHaveSameContent() { $piwikMin = PIWIK_DOCUMENT_ROOT . TrackerUpdater::ORIGINAL_PIWIK_JS; - $piwikJs = PIWIK_DOCUMENT_ROOT . TrackerUpdater::TARGET_PIWIK_JS; + $piwikJs = PIWIK_DOCUMENT_ROOT . TrackerUpdater::TARGET_MATOMO_JS; $this->assertSame(file_get_contents($piwikMin), file_get_contents($piwikJs)); } diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php index a99ee07929f..1f85083ef17 100644 --- a/plugins/Installation/Controller.php +++ b/plugins/Installation/Controller.php @@ -16,7 +16,6 @@ use Piwik\Container\StaticContainer; use Piwik\DataAccess\ArchiveTableCreator; use Piwik\Db; -use Piwik\Db\Adapter; use Piwik\DbHelper; use Piwik\Filesystem; use Piwik\Http; @@ -26,11 +25,9 @@ use Piwik\Plugins\Diagnostics\DiagnosticService; use Piwik\Plugins\LanguagesManager\LanguagesManager; use Piwik\Plugins\SitesManager\API as APISitesManager; -use Piwik\Plugins\UserCountry\LocationProvider; use Piwik\Plugins\UsersManager\API as APIUsersManager; use Piwik\ProxyHeaders; use Piwik\SettingsPiwik; -use Piwik\Theme; use Piwik\Tracker\TrackerCodeGenerator; use Piwik\Translation\Translator; use Piwik\Updater; @@ -207,6 +204,7 @@ function tablesCreation() DbHelper::createTables(); DbHelper::createAnonymousUser(); + DbHelper::recordInstallVersion(); $this->updateComponents(); diff --git a/plugins/Installation/lang/en.json b/plugins/Installation/lang/en.json index e07969a7bcb..ff98d6a776a 100644 --- a/plugins/Installation/lang/en.json +++ b/plugins/Installation/lang/en.json @@ -118,7 +118,7 @@ "SystemCheckSummaryThereWereWarnings": "There are some issues with your system. Matomo will run, but you might experience some minor problems.", "SystemCheckTimeLimitHelp": "On a high traffic website, executing the archiving process may require more time than currently allowed. If necessary, change the max_execution_time directive in your php.ini file.", "SystemCheckTracker": "Tracker status", - "SystemCheckTrackerHelp": "GET request to piwik.php failed. Try whitelisting this URL from HTTP Authentication and disable mod_security (you may have to ask your webhost). For more information about the error, check your web server error log file.", + "SystemCheckTrackerHelp": "GET request to matomo.php failed. Try whitelisting this URL from HTTP Authentication and disable mod_security (you may have to ask your webhost). For more information about the error, check your web server error log file.", "SystemCheckWarnDomHelp": "You should enable the \"dom\" extension (e.g., install the \"php-dom\" and\/or \"php-xml\" package).", "SystemCheckWarning": "Matomo will work normally but some features may be missing", "SystemCheckWarnJsonHelp": "You should enable \"json\" extension (e.g., install the \"php-json\" package) for better performance.", diff --git a/plugins/Installation/templates/welcome.twig b/plugins/Installation/templates/welcome.twig index 39314784266..d32805f4694 100644 --- a/plugins/Installation/templates/welcome.twig +++ b/plugins/Installation/templates/welcome.twig @@ -12,7 +12,7 @@ // client-side test for broken tracker (e.g., mod_security rule) $('.next-step').hide(); $.ajax({ - url: 'piwik.php', + url: 'matomo.php', data: 'url=http://example.com', complete: function () { $('.next-step').show(); diff --git a/plugins/Installation/tests/UI/expected-screenshots/Installation_js_tracking.png b/plugins/Installation/tests/UI/expected-screenshots/Installation_js_tracking.png index 56eac1cb87c..64c6dfada74 100644 --- a/plugins/Installation/tests/UI/expected-screenshots/Installation_js_tracking.png +++ b/plugins/Installation/tests/UI/expected-screenshots/Installation_js_tracking.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3364ab2ed6eb9dd48eb48025bad28ae19c81facee829e2207474d5fe1efb39f -size 224953 +oid sha256:a403a5493fdb7a8dbf22cd99caafbf6b0c0b2ce837f59544f9bd839a7a114fd9 +size 224949 diff --git a/plugins/Installation/tests/UI/expected-screenshots/Installation_system_check.png b/plugins/Installation/tests/UI/expected-screenshots/Installation_system_check.png index 2afe761ea99..5fe151af691 100644 --- a/plugins/Installation/tests/UI/expected-screenshots/Installation_system_check.png +++ b/plugins/Installation/tests/UI/expected-screenshots/Installation_system_check.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca311ba80d2d5525a6ea9addf44161c2d960b3ec888a10f50e9fece4f9d7ba5d -size 192039 +oid sha256:1045b739708a3086bf86d862afc6ed61ea00bf9e0113854a10941f30f6213fa6 +size 192412 diff --git a/plugins/Morpheus/templates/javascriptCode.twig b/plugins/Morpheus/templates/javascriptCode.twig index 53a379d8ee4..dfa863d0d21 100644 --- a/plugins/Morpheus/templates/javascriptCode.twig +++ b/plugins/Morpheus/templates/javascriptCode.twig @@ -6,15 +6,15 @@ _paq.push(['enableLinkTracking']); (function() { {$setTrackerUrl} - {$optionsBeforeTrackerUrl}_paq.push(['setTrackerUrl', u+'piwik.php']); + {$optionsBeforeTrackerUrl}_paq.push(['setTrackerUrl', u+'{$matomoPhpFilename}']); _paq.push(['setSiteId', '{$idSite}']); {% if loadAsync %}var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);{% endif %} + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'{$matomoJsFilename}'; s.parentNode.insertBefore(g,s);{% endif %} })(); -{% if not loadAsync %} +{% if not loadAsync %} {% endif %} -{% if trackNoScript %} +{% if trackNoScript %} {% endif %} diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php index a6256d7ab50..94ad508d277 100644 --- a/plugins/SitesManager/API.php +++ b/plugins/SitesManager/API.php @@ -101,13 +101,14 @@ public function __construct(SettingsProvider $provider, SettingsMetadata $settin * @param bool $doNotTrack * @param bool $disableCookies * @param bool $trackNoScript + * @param bool $forceMatomoEndpoint Whether the Matomo endpoint should be forced if Matomo was installed prior 3.7.0. * @return string The Javascript tag ready to be included on the HTML pages */ public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = false, $groupPageTitlesByDomain = false, $mergeAliasUrls = false, $visitorCustomVariables = false, $pageCustomVariables = false, $customCampaignNameQueryParam = false, $customCampaignKeywordParam = false, $doNotTrack = false, $disableCookies = false, $trackNoScript = false, - $crossDomain = false) + $crossDomain = false, $forceMatomoEndpoint = false) { Piwik::checkUserHasViewAccess($idSite); @@ -124,6 +125,10 @@ public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = fal $customCampaignKeywordParam = Common::unsanitizeInputValue($customCampaignKeywordParam); $generator = new TrackerCodeGenerator(); + if ($forceMatomoEndpoint) { + $generator->forceMatomoEndpoint(); + } + $code = $generator->generate($idSite, $piwikUrl, $mergeSubdomains, $groupPageTitlesByDomain, $mergeAliasUrls, $visitorCustomVariables, $pageCustomVariables, $customCampaignNameQueryParam, $customCampaignKeywordParam, @@ -139,9 +144,10 @@ public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = fal * @param string $piwikUrl The domain and URL path to the Matomo installation. * @param int $idGoal An ID for a goal to trigger a conversion for. * @param int $revenue The revenue of the goal conversion. Only used if $idGoal is supplied. + * @param bool $forceMatomoEndpoint Whether the Matomo endpoint should be forced if Matomo was installed prior 3.7.0. * @return string The HTML tracking code. */ - public function getImageTrackingCode($idSite, $piwikUrl = '', $actionName = false, $idGoal = false, $revenue = false) + public function getImageTrackingCode($idSite, $piwikUrl = '', $actionName = false, $idGoal = false, $revenue = false, $forceMatomoEndpoint = false) { $urlParams = array('idsite' => $idSite, 'rec' => 1); @@ -168,7 +174,13 @@ public function getImageTrackingCode($idSite, $piwikUrl = '', $actionName = fals */ Piwik::postEvent('SitesManager.getImageTrackingCode', array(&$piwikUrl, &$urlParams)); - $url = (ProxyHttp::isHttps() ? "https://" : "http://") . $piwikUrl . '/piwik.php?' . Url::getQueryStringFromParameters($urlParams); + $trackerCodeGenerator = new TrackerCodeGenerator(); + if ($forceMatomoEndpoint) { + $trackerCodeGenerator->forceMatomoEndpoint(); + } + $matomoPhp = $trackerCodeGenerator->getPhpTrackerEndpoint(); + + $url = (ProxyHttp::isHttps() ? "https://" : "http://") . rtrim($piwikUrl, '/') . '/'.$matomoPhp.'?' . Url::getQueryStringFromParameters($urlParams); $html = " \"\" "; diff --git a/plugins/SitesManager/Controller.php b/plugins/SitesManager/Controller.php index 67c08f6ac1b..71a7c84e971 100644 --- a/plugins/SitesManager/Controller.php +++ b/plugins/SitesManager/Controller.php @@ -100,25 +100,6 @@ public function setGlobalSettings() return $toReturn; } - /** - * Displays the admin UI page showing all tracking tags - * @return string - */ - function displayJavascriptCode() - { - $this->checkSitePermission(); - Piwik::checkUserHasViewAccess($this->idSite); - $javascriptGenerator = new TrackerCodeGenerator(); - $jsTag = $javascriptGenerator->generate($this->idSite, SettingsPiwik::getPiwikUrl()); - $site = new Site($this->idSite); - - return $this->renderTemplate('displayJavascriptCode', array( - 'idSite' => $this->idSite, - 'displaySiteName' => $site->getName(), - 'jsTag' => $jsTag - )); - } - /** * User will download a file called PiwikTracker.php that is the content of the actual script */ @@ -146,6 +127,7 @@ public function ignoreNoDataMessage() public function siteWithoutData() { $javascriptGenerator = new TrackerCodeGenerator(); + $javascriptGenerator->forceMatomoEndpoint(); $piwikUrl = Url::getCurrentUrlWithoutFileName(); if (!$this->site && Piwik::hasUserSuperUserAccess()) { diff --git a/plugins/SitesManager/templates/_displayJavascriptCode.twig b/plugins/SitesManager/templates/_displayJavascriptCode.twig index e675220052b..aabdc93fce1 100644 --- a/plugins/SitesManager/templates/_displayJavascriptCode.twig +++ b/plugins/SitesManager/templates/_displayJavascriptCode.twig @@ -30,4 +30,4 @@ {{ postEvent('Template.endTrackingHelpPage') }} - + \ No newline at end of file diff --git a/plugins/SitesManager/templates/displayJavascriptCode.twig b/plugins/SitesManager/templates/displayJavascriptCode.twig deleted file mode 100644 index 05d867030e8..00000000000 --- a/plugins/SitesManager/templates/displayJavascriptCode.twig +++ /dev/null @@ -1,5 +0,0 @@ -{% extends 'admin.twig' %} - -{% block content %} -{% include "@SitesManager/_displayJavascriptCode.twig" %} -{% endblock %} \ No newline at end of file diff --git a/plugins/SitesManager/tests/System/ApiTest.php b/plugins/SitesManager/tests/System/ApiTest.php index 393a8fc6a44..34f57a849ca 100644 --- a/plugins/SitesManager/tests/System/ApiTest.php +++ b/plugins/SitesManager/tests/System/ApiTest.php @@ -8,6 +8,8 @@ namespace Piwik\Plugins\SitesManager\tests\System; +use Piwik\Db\Schema\Mysql; +use Piwik\Option; use Piwik\Plugins\SitesManager\tests\Fixtures\ManySites; use Piwik\Tests\Framework\TestCase\SystemTestCase; @@ -68,6 +70,39 @@ public function getApiForTesting() return $apiToTest; } + public function test_InstalledBeforeMatomo37() + { + $this->setInstallVersion('3.6.0'); + $this->runApiTests(array('SitesManager.getJavascriptTag', 'SitesManager.getImageTrackingCode'), array( + 'idSite' => 1, + 'testSuffix' => '_prior3_7_0' + )); + } + + public function test_InstalledBeforeMatomo37ButForced() + { + $this->setInstallVersion('3.6.0'); + $this->runApiTests(array('SitesManager.getJavascriptTag', 'SitesManager.getImageTrackingCode'), array( + 'idSite' => 1, + 'otherRequestParameters' => array('forceMatomoEndpoint' => 1), + 'testSuffix' => '_prior3_7_0_but_forced' + )); + } + + public function test_InstalledAfterMatomo37() + { + $this->setInstallVersion('3.7.0'); + $this->runApiTests(array('SitesManager.getJavascriptTag', 'SitesManager.getImageTrackingCode'), array( + 'idSite' => 1, + 'testSuffix' => '_after3_7_0' + )); + } + + private function setInstallVersion($installVersion) + { + Option::set(Mysql::OPTION_NAME_MATOMO_INSTALL_VERSION, $installVersion); + } + public static function getOutputPrefix() { return 'SitesManager'; diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager_after3_7_0__SitesManager.getImageTrackingCode.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager_after3_7_0__SitesManager.getImageTrackingCode.xml new file mode 100644 index 00000000000..b2f6990bc72 --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager_after3_7_0__SitesManager.getImageTrackingCode.xml @@ -0,0 +1,4 @@ + +<!-- Matomo Image Tracker--> +<img src="http://http://example.org/piwik/matomo.php?idsite=1&amp;rec=1" style="border:0" alt="" /> +<!-- End Matomo --> \ No newline at end of file diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager_after3_7_0__SitesManager.getJavascriptTag.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager_after3_7_0__SitesManager.getJavascriptTag.xml new file mode 100644 index 00000000000..a09f82642d5 --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager_after3_7_0__SitesManager.getJavascriptTag.xml @@ -0,0 +1,17 @@ + +<!-- Matomo --> +<script type="text/javascript"> + var _paq = _paq || []; + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="//example.org/piwik/"; + _paq.push(['setTrackerUrl', u+'matomo.php']); + _paq.push(['setSiteId', '1']); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); + })(); +</script> +<!-- End Matomo Code --> + \ No newline at end of file diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0__SitesManager.getImageTrackingCode.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0__SitesManager.getImageTrackingCode.xml new file mode 100644 index 00000000000..5854de6082d --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0__SitesManager.getImageTrackingCode.xml @@ -0,0 +1,4 @@ + +<!-- Matomo Image Tracker--> +<img src="http://http://example.org/piwik/piwik.php?idsite=1&amp;rec=1" style="border:0" alt="" /> +<!-- End Matomo --> \ No newline at end of file diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0__SitesManager.getJavascriptTag.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0__SitesManager.getJavascriptTag.xml new file mode 100644 index 00000000000..5a5a0088d6c --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0__SitesManager.getJavascriptTag.xml @@ -0,0 +1,17 @@ + +<!-- Matomo --> +<script type="text/javascript"> + var _paq = _paq || []; + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="//example.org/piwik/"; + _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setSiteId', '1']); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + })(); +</script> +<!-- End Matomo Code --> + \ No newline at end of file diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0_but_forced__SitesManager.getImageTrackingCode.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0_but_forced__SitesManager.getImageTrackingCode.xml new file mode 100644 index 00000000000..b2f6990bc72 --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0_but_forced__SitesManager.getImageTrackingCode.xml @@ -0,0 +1,4 @@ + +<!-- Matomo Image Tracker--> +<img src="http://http://example.org/piwik/matomo.php?idsite=1&amp;rec=1" style="border:0" alt="" /> +<!-- End Matomo --> \ No newline at end of file diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0_but_forced__SitesManager.getJavascriptTag.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0_but_forced__SitesManager.getJavascriptTag.xml new file mode 100644 index 00000000000..a09f82642d5 --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager_prior3_7_0_but_forced__SitesManager.getJavascriptTag.xml @@ -0,0 +1,17 @@ + +<!-- Matomo --> +<script type="text/javascript"> + var _paq = _paq || []; + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="//example.org/piwik/"; + _paq.push(['setTrackerUrl', u+'matomo.php']); + _paq.push(['setSiteId', '1']); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); + })(); +</script> +<!-- End Matomo Code --> + \ No newline at end of file diff --git a/plugins/TestRunner/Commands/TestsSetupFixture.php b/plugins/TestRunner/Commands/TestsSetupFixture.php index 35b19eb9836..e97319b6331 100644 --- a/plugins/TestRunner/Commands/TestsSetupFixture.php +++ b/plugins/TestRunner/Commands/TestsSetupFixture.php @@ -159,7 +159,7 @@ protected function execute(InputInterface $input, OutputInterface $output) private function createSymbolicLinksForUITests() { // make sure symbolic links exist (phantomjs doesn't support symlink-ing yet) - foreach (array('libs', 'plugins', 'tests', 'misc', 'piwik.js') as $linkName) { + foreach (array('libs', 'plugins', 'tests', 'misc', 'piwik.js', 'matomo.js') as $linkName) { $linkPath = PIWIK_INCLUDE_PATH . '/tests/PHPUnit/proxy/' . $linkName; if (!file_exists($linkPath)) { $target = PIWIK_INCLUDE_PATH . '/' . $linkName; diff --git a/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php b/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php index 0a9bf260dea..c07967c5636 100644 --- a/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php +++ b/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php @@ -266,7 +266,7 @@ private function logVisitsWithAllEnabled() } /** - * Logs a couple visit using log entries that are tracking requests to a piwik.php file. + * Logs a couple visit using log entries that are tracking requests to a matomo.php file. * Adds two visits to idSite=1 and two to non-existant sites. * * @param array $additonalOptions diff --git a/tests/PHPUnit/Framework/Fixture.php b/tests/PHPUnit/Framework/Fixture.php index 701f5a1f701..45f200bac58 100644 --- a/tests/PHPUnit/Framework/Fixture.php +++ b/tests/PHPUnit/Framework/Fixture.php @@ -247,6 +247,7 @@ public function performSetUp($setupEnvironmentOnly = false) Db::get()->query("SET wait_timeout=28800;"); DbHelper::createTables(); + DbHelper::recordInstallVersion(); self::getPluginManager()->unloadPlugins(); @@ -410,6 +411,7 @@ protected static function rememberCurrentlyInstalledPluginsAcrossRequests(Testin public static function loadAllPlugins(TestingEnvironmentVariables $testEnvironment = null, $testCaseClass = false, $extraPluginsToLoad = array()) { DbHelper::createTables(); + DbHelper::recordInstallVersion(); self::getPluginManager()->loadActivatedPlugins(); } @@ -575,7 +577,7 @@ public static function getRootUrl() */ public static function getTrackerUrl() { - return self::getTestRootUrl() . 'piwik.php'; + return self::getTestRootUrl() . 'matomo.php'; } /** diff --git a/tests/PHPUnit/Framework/TestCase/IntegrationTestCase.php b/tests/PHPUnit/Framework/TestCase/IntegrationTestCase.php index bf4e7f4c191..9e8b2abe07c 100644 --- a/tests/PHPUnit/Framework/TestCase/IntegrationTestCase.php +++ b/tests/PHPUnit/Framework/TestCase/IntegrationTestCase.php @@ -11,7 +11,9 @@ use Piwik\Access; use Piwik\Config; use Piwik\Db; +use Piwik\DbHelper; use Piwik\Menu\MenuAbstract; +use Piwik\Option; use Piwik\Tests\Framework\Fixture; use Piwik\Cache as PiwikCache; use Piwik\Tests\Framework\TestingEnvironmentVariables; @@ -91,6 +93,7 @@ public function setUp() PiwikCache::getEagerCache()->flushAll(); PiwikCache::getTransientCache()->flushAll(); MenuAbstract::clearMenus(); + Option::clearCache(); } /** diff --git a/tests/PHPUnit/Integration/DbHelperTest.php b/tests/PHPUnit/Integration/DbHelperTest.php index f8268f451ce..5b88015eab2 100644 --- a/tests/PHPUnit/Integration/DbHelperTest.php +++ b/tests/PHPUnit/Integration/DbHelperTest.php @@ -10,7 +10,9 @@ use Piwik\Db; use Piwik\DbHelper; +use Piwik\Option; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Piwik\Version; class DbHelperTest extends IntegrationTestCase { @@ -22,6 +24,52 @@ public function setUp() DbHelper::dropDatabase('testdb'); } + public function test_getInstallVersion_isCurrentVersion() + { + $this->assertSame(Version::VERSION, DbHelper::getInstallVersion()); + } + + public function test_recordInstallVersion_setsCurrentVersion() + { + Option::delete(Db\Schema\Mysql::OPTION_NAME_MATOMO_INSTALL_VERSION); + $this->assertNull(DbHelper::getInstallVersion()); + + DbHelper::recordInstallVersion(); + $this->assertSame(Version::VERSION, DbHelper::getInstallVersion()); + } + + public function test_recordInstallVersion_doesNotOverwritePreviouslySetVersion() + { + $this->setInstallVersion('2.1.0'); + DbHelper::recordInstallVersion(); + DbHelper::recordInstallVersion(); + DbHelper::recordInstallVersion(); + $this->assertSame('2.1.0', DbHelper::getInstallVersion()); + } + + public function test_wasMatomoInstalledBeforeVersion_sameVersion() + { + $this->setInstallVersion('2.1.0'); + $this->assertFalse(DbHelper::wasMatomoInstalledBeforeVersion('2.1.0')); + } + + public function test_wasMatomoInstalledBeforeVersion_whenUsedNewerVersion() + { + $this->setInstallVersion('2.1.0'); + $this->assertFalse(DbHelper::wasMatomoInstalledBeforeVersion('2.0.0')); + } + + public function test_wasMatomoInstalledBeforeVersion_whenWasInstalledBeforeThatVersion() + { + $this->setInstallVersion('2.1.0'); + $this->assertTrue(DbHelper::wasMatomoInstalledBeforeVersion('2.2.0')); + } + + private function setInstallVersion($version) + { + Option::set(Db\Schema\Mysql::OPTION_NAME_MATOMO_INSTALL_VERSION, $version); + } + public function test_createDatabase_escapesInputProperly() { $dbName = 'newdb`; create database anotherdb;`'; diff --git a/tests/PHPUnit/Integration/HttpTest.php b/tests/PHPUnit/Integration/HttpTest.php index 1e9a734dc7c..d7831f50215 100644 --- a/tests/PHPUnit/Integration/HttpTest.php +++ b/tests/PHPUnit/Integration/HttpTest.php @@ -35,8 +35,8 @@ public function getMethodsToTest() public function testFetchRemoteFile($method) { $this->assertNotNull(Http::getTransportMethod()); - $result = Http::sendHttpRequestBy($method, Fixture::getRootUrl() . 'piwik.js', 30); - $this->assertTrue(strpos($result, 'Piwik') !== false); + $result = Http::sendHttpRequestBy($method, Fixture::getRootUrl() . 'matomo.js', 30); + $this->assertTrue(strpos($result, 'Matomo') !== false); } public function testFetchApiLatestVersion() @@ -73,7 +73,7 @@ public function testCustomByteRange($method) $result = Http::sendHttpRequestBy( $method, - Fixture::getRootUrl() . '/piwik.js', + Fixture::getRootUrl() . '/matomo.js', 30, $userAgent = null, $destinationPath = null, diff --git a/tests/PHPUnit/Integration/JsProxyTest.php b/tests/PHPUnit/Integration/JsProxyTest.php index 17e2430401e..c1ff170166d 100644 --- a/tests/PHPUnit/Integration/JsProxyTest.php +++ b/tests/PHPUnit/Integration/JsProxyTest.php @@ -22,7 +22,7 @@ public function setUp() Fixture::createWebsite('2014-01-01 02:03:04'); } - public function testPiwikJs() + public function testMatomoJs() { $curlHandle = curl_init(); curl_setopt($curlHandle, CURLOPT_URL, $this->getStaticSrvUrl() . '/js/'); @@ -33,7 +33,7 @@ public function testPiwikJs() $this->assertEquals(200, $responseInfo["http_code"], 'Ok response'); - $piwik_js = file_get_contents(PIWIK_PATH_TEST_TO_ROOT . '/piwik.js'); + $piwik_js = file_get_contents(PIWIK_PATH_TEST_TO_ROOT . '/matomo.js'); $this->assertEquals($piwik_js, $fullResponse, 'script content'); } @@ -48,7 +48,7 @@ public function testPiwik_WhiteLabelledJs_HasNoComment() $this->assertEquals(200, $responseInfo["http_code"], 'Ok response'); - $piwikJs = file_get_contents(PIWIK_PATH_TEST_TO_ROOT . '/piwik.js'); + $piwikJs = file_get_contents(PIWIK_PATH_TEST_TO_ROOT . '/matomo.js'); $piwikNoCommentJs = substr($piwikJs, strpos($piwikJs, "*/\n") + 3); $this->assertEquals($piwikNoCommentJs, trim($fullResponse), 'script content (if comment shows, $byteStart value in /js/tracker.php)'); } diff --git a/tests/PHPUnit/Integration/ReleaseCheckListTest.php b/tests/PHPUnit/Integration/ReleaseCheckListTest.php index bce8b56c24c..0fb62a64c59 100644 --- a/tests/PHPUnit/Integration/ReleaseCheckListTest.php +++ b/tests/PHPUnit/Integration/ReleaseCheckListTest.php @@ -492,6 +492,15 @@ public function test_piwikJs_minified_isUpToDate() ); } + public function test_piwikJs_SameAsMatomoJs() + { + $this->assertFileEquals( + PIWIK_DOCUMENT_ROOT . '/matomo.js', + PIWIK_DOCUMENT_ROOT . '/piwik.js', + '/piwik.js does not match /matomo.js, please re-generate the minified files using instructions in /js/README' + ); + } + public function testTmpDirectoryContainsGitKeep() { $this->assertFileExists(PIWIK_DOCUMENT_ROOT . '/tmp/.gitkeep'); diff --git a/tests/PHPUnit/Integration/Tracker/TrackerCodeGeneratorTest.php b/tests/PHPUnit/Integration/Tracker/TrackerCodeGeneratorTest.php index 38273033746..2e9ee543b31 100644 --- a/tests/PHPUnit/Integration/Tracker/TrackerCodeGeneratorTest.php +++ b/tests/PHPUnit/Integration/Tracker/TrackerCodeGeneratorTest.php @@ -57,13 +57,13 @@ public function testJavascriptTrackingCode_withAllOptions() _paq.push(['enableLinkTracking']); (function() { var u="//piwik-server/piwik/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> -<noscript><p><img src="//piwik-server/piwik/piwik.php?idsite=1&amp;rec=1" style="border:0;" alt="" /></p></noscript> +<noscript><p><img src="//piwik-server/piwik/matomo.php?idsite=1&amp;rec=1" style="border:0;" alt="" /></p></noscript> <!-- End Matomo Code --> "; @@ -84,10 +84,10 @@ public function testJavascriptTrackingCode_noScriptTrackingDisabled_defaultTrack _paq.push(['enableLinkTracking']); (function() { var u="//localhost/piwik/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> <!-- End Matomo Code --> @@ -131,10 +131,10 @@ public function testJavascriptTrackingCode_withAllOptionsAndProtocolOverwrite() _paq.push(['enableLinkTracking']); (function() { var u="https://localhost/piwik/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> <!-- End Matomo Code --> @@ -179,10 +179,10 @@ public function testJavascriptTrackingCode_withAllOptionsAndOptionsBeforeTracker (function() { var u="//localhost/piwik/"; _paq.push(['setAPIUrl', 'http://localhost/statistics']); - _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> <!-- End Matomo Code --> @@ -214,12 +214,12 @@ public function testJavascriptTrackingCode_loadSync() _paq.push(['enableLinkTracking']); (function() { var u="//localhost/piwik/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); })(); </script> -<script type='text/javascript' src="//localhost/piwik/piwik.js"></script> +<script type='text/javascript' src="//localhost/piwik/matomo.js"></script> <!-- End Matomo Code --> "; @@ -257,10 +257,10 @@ public function testStringsAreEscaped() _paq.push([\'enableLinkTracking\']); (function() { var u="//abc"def/"; - _paq.push([\'setTrackerUrl\', u+\'piwik.php\']); + _paq.push([\'setTrackerUrl\', u+\'matomo.php\']); _paq.push([\'setSiteId\', \'1\']); var d=document, g=d.createElement(\'script\'), s=d.getElementsByTagName(\'script\')[0]; - g.type=\'text/javascript\'; g.async=true; g.defer=true; g.src=u+\'piwik.js\'; s.parentNode.insertBefore(g,s); + g.type=\'text/javascript\'; g.async=true; g.defer=true; g.src=u+\'matomo.js\'; s.parentNode.insertBefore(g,s); })(); </script> <!-- End Matomo Code --> @@ -284,10 +284,10 @@ public function testJavascriptTrackingCode_withForceSsl() _paq.push([\'enableLinkTracking\']); (function() { var u="https://localhost/piwik/"; - _paq.push([\'setTrackerUrl\', u+\'piwik.php\']); + _paq.push([\'setTrackerUrl\', u+\'matomo.php\']); _paq.push([\'setSiteId\', \'1\']); var d=document, g=d.createElement(\'script\'), s=d.getElementsByTagName(\'script\')[0]; - g.type=\'text/javascript\'; g.async=true; g.defer=true; g.src=u+\'piwik.js\'; s.parentNode.insertBefore(g,s); + g.type=\'text/javascript\'; g.async=true; g.defer=true; g.src=u+\'matomo.js\'; s.parentNode.insertBefore(g,s); })(); </script> <!-- End Matomo Code --> diff --git a/tests/PHPUnit/System/EnvironmentValidationTest.php b/tests/PHPUnit/System/EnvironmentValidationTest.php index 5c47714f4ed..18aa3ab4ad4 100644 --- a/tests/PHPUnit/System/EnvironmentValidationTest.php +++ b/tests/PHPUnit/System/EnvironmentValidationTest.php @@ -129,7 +129,7 @@ private function assertOutputContainsConfigFileMissingError($fileName, $output) private function assertOutputContainsBadConfigFileError($output) { - $this->assertRegExp("/Unable to read INI file \\{.*\\/piwik.php\\}:/", $output); + $this->assertRegExp("/Unable to read INI file \\{.*\\/matomo.php\\}:/", $output); $this->assertRegExp("/Your host may have disabled parse_ini_file\\(\\)/", $output); } @@ -158,11 +158,11 @@ private function simulateBadConfigFile($fileName) $testingEnvironment = new \Piwik\Tests\Framework\TestingEnvironmentVariables(); if ($fileName == 'global.ini.php') { - $testingEnvironment->configFileGlobal = PIWIK_INCLUDE_PATH . '/piwik.php'; + $testingEnvironment->configFileGlobal = PIWIK_INCLUDE_PATH . '/matomo.php'; } else if ($fileName == 'common.config.ini.php') { - $testingEnvironment->configFileCommon = PIWIK_INCLUDE_PATH . '/piwik.php'; + $testingEnvironment->configFileCommon = PIWIK_INCLUDE_PATH . '/matomo.php'; } else { - $testingEnvironment->configFileLocal = PIWIK_INCLUDE_PATH . '/piwik.php'; + $testingEnvironment->configFileLocal = PIWIK_INCLUDE_PATH . '/matomo.php'; } $testingEnvironment->save(); @@ -192,7 +192,7 @@ private function triggerPiwikFrom($entryPoint) private function sendRequestToTracker() { - list($response, $info) = $this->curl(Fixture::getRootUrl() . 'tests/PHPUnit/proxy/piwik.php?idsite=1&rec=1&action_name=something'); + list($response, $info) = $this->curl(Fixture::getRootUrl() . 'tests/PHPUnit/proxy/matomo.php?idsite=1&rec=1&action_name=something'); // Check Tracker requests return 200 $this->assertEquals(200, $info["http_code"], 'Ok response'); diff --git a/tests/PHPUnit/System/TrackerTest.php b/tests/PHPUnit/System/TrackerTest.php index 7f43afbe2f8..cc627d2cbf9 100644 --- a/tests/PHPUnit/System/TrackerTest.php +++ b/tests/PHPUnit/System/TrackerTest.php @@ -224,7 +224,7 @@ public function test_scheduledTasks_DoNotFailTracking_WhenScheduledTaskFails($do protected function issueBulkTrackingRequest($token_auth, $expectTrackingToSucceed) { - $piwikHost = Fixture::getRootUrl() . 'tests/PHPUnit/proxy/piwik.php'; + $piwikHost = Fixture::getRootUrl() . 'tests/PHPUnit/proxy/matomo.php'; $command = 'curl -s -X POST -d \'{"requests":["?idsite=1&url=http://example.org&action_name=Test bulk log Pageview&rec=1","?idsite=1&url=http://example.net/test.htm&action_name=Another bulk page view&rec=1"],"token_auth":"' . $token_auth . '"}\' ' . $piwikHost; @@ -251,7 +251,7 @@ private function sendTrackingRequestByCurl($url) } $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, Fixture::getRootUrl() . 'tests/PHPUnit/proxy/piwik.php' . $url); + curl_setopt($ch, CURLOPT_URL, Fixture::getRootUrl() . 'tests/PHPUnit/proxy/matomo.php' . $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml index 2c0a7d1cf97..17afa1ddc36 100644 --- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml @@ -7,10 +7,10 @@ _paq.push(['enableLinkTracking']); (function() { var u="//example.org/piwik/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> <!-- End Matomo Code --> diff --git a/tests/PHPUnit/Unit/DeprecatedMethodsTest.php b/tests/PHPUnit/Unit/DeprecatedMethodsTest.php index a0cd9905f06..ff490fe6ab3 100644 --- a/tests/PHPUnit/Unit/DeprecatedMethodsTest.php +++ b/tests/PHPUnit/Unit/DeprecatedMethodsTest.php @@ -84,6 +84,7 @@ public function test_deprecations() // THIS IS A REMINDER FOR PIWIK 4: We need to rename getColumnType() to getDbColumnType() and $columnType to $dbColumnType $this->assertDeprecatedMethodIsRemovedInPiwik4('Piwik\Columns\Dimension', 'getType'); + $this->assertDeprecatedMethodIsRemovedInPiwik4('Piwik\SettingsPiwik', 'isPiwikInstalled'); } diff --git a/tests/PHPUnit/proxy/matomo.php b/tests/PHPUnit/proxy/matomo.php new file mode 100644 index 00000000000..9a425e7d66b --- /dev/null +++ b/tests/PHPUnit/proxy/matomo.php @@ -0,0 +1,11 @@ +getMessage() . "\n" . $ex->getTraceAsString() . "\n"; } diff --git a/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard.png b/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard.png index 9d39cf1ae45..cb7362f5d3a 100644 --- a/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard.png +++ b/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd393fef5bdc4a5599a5fa9c09844b97cc40777c29de18953bbcfee9e695318f -size 256589 +oid sha256:3d70f20a9b025d311b498a3e196f5ef9f761433d43f395c015a6a6edb661e82d +size 256556 diff --git a/tests/UI/expected-screenshots/QuickAccess_search_1.png b/tests/UI/expected-screenshots/QuickAccess_search_1.png index a1375dd7470..662ed3401a6 100644 --- a/tests/UI/expected-screenshots/QuickAccess_search_1.png +++ b/tests/UI/expected-screenshots/QuickAccess_search_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9312923e5c8621e7633084faed5b53e3d4a7bcfec7198365c6a772360f70828 -size 92297 +oid sha256:bed0c18d4596f6df9a99779a77a3ba547f9598940ff646f5bf4e763ddd24a244 +size 93312 diff --git a/tests/UI/expected-screenshots/QuickAccess_search_sites.png b/tests/UI/expected-screenshots/QuickAccess_search_sites.png index 74654145f76..ccf80a5556f 100644 --- a/tests/UI/expected-screenshots/QuickAccess_search_sites.png +++ b/tests/UI/expected-screenshots/QuickAccess_search_sites.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b86fe6e1c50150f626b14242d4afc7fbaccedb86023a666bb83c7d2908d720 -size 39555 +oid sha256:b429ae6893b829de09cb7ddccecb032a67f7187cec8768a9600a3bbf93b7246a +size 40546 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png index 528dedf6ef7..da29f0d00aa 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:581a3dbcca6c3771b387e4e557ba21653a2fb09d2175c44ae4129f31412b64bc -size 4087434 +oid sha256:e524e9d92a5538ef3ec8a143875df9ff8074c4e06cb9d9a13187a6a596766410 +size 4079307 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_manage_tracking_code.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_manage_tracking_code.png index ce7340fa2e7..06315c1e0df 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_manage_tracking_code.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_manage_tracking_code.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc610bdf41ed85b618c07dfafc52cf92789e2fdff9dde8d1baf22190bf63fc2b -size 388941 +oid sha256:f29b3b308c2cc58c52e53c74b2e382c829c427e6eeeb0349d683f08206e172c9 +size 389096 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png index 8e568bf31d0..bb9f85998e6 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1111041dcb5e7c2ab84f3d8126a22cd90e97ea44e78285a81069603450b45fd5 -size 1044077 +oid sha256:b4adce722c2f48fbd883e5d142b13c425962122ac64d1817f27013fe6900408e +size 1043948 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins_no_internet.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins_no_internet.png index 19d702f6421..f8bfdc6983f 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins_no_internet.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins_no_internet.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da509b58beab3825a9705262b055e658ef191749543e34d0d94025ae18029d59 -size 1045702 +oid sha256:6f7580dc36fbd3090a3b93dd1f5290059c358b31a6841ed8f39e19e414236e46 +size 1045534 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png index 7a7b0dd6707..def09c3c194 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:186bdfac36d212eebb1e45267315d23c81f04e5da7ce75a8052a3f3772896b3e -size 929802 +oid sha256:40192c9d43e4afe6c9e83559d6851c939415fe9dedbc1bfe3f58e4b6aec9c88d +size 929225 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png index bc46e0199a1..5c0ab4cb66b 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e457fc12a138fed1195e5b23a4dd5156bad0f2846d3ad83bb0e7855a4f0f63a0 -size 4991621 +oid sha256:366c7a13712d0dbece1ebda33aea223a9989c9fe9c52b2526fa61df8cd8d2a2b +size 4995235 diff --git a/tests/angularjs/Gruntfile.js b/tests/angularjs/Gruntfile.js index 8dc577a407e..9338a8aabc6 100644 --- a/tests/angularjs/Gruntfile.js +++ b/tests/angularjs/Gruntfile.js @@ -34,7 +34,7 @@ module.exports = function(grunt) { }, "shell": { compilePiwikJs: { - command: "sed '//,/<\\/DEBUG>/d' < piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.7/build/yuicompressor-2.4.7.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\\/*!/' > piwik-min.js && cp piwik-min.js ../piwik.js", + command: "sed '//,/<\\/DEBUG>/d' < piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.7/build/yuicompressor-2.4.7.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\\/*!/' > piwik-min.js && cp piwik-min.js ../piwik.js && cp piwik-min.js ../matomo.js", options: { execOptions: { cwd: 'js' diff --git a/tests/angularjs/bootstrap.js b/tests/angularjs/bootstrap.js index 4b0ee79a10e..8ae7d16beee 100644 --- a/tests/angularjs/bootstrap.js +++ b/tests/angularjs/bootstrap.js @@ -26,9 +26,9 @@ if(typeof(piwik_translations) == 'undefined') { var piwik_translations = new Obj var piwikUsageTracking = { targets: [ - {url: 'http://localhost/piwik.php', idSite: 1, cookieDomain: ''}, - {url: 'http://127.0.0.1/piwik.php', idSite: 20, cookieDomain: ''}, - {url: 'http://localhost/piwik.php', idSite: 33, cookieDomain: ''}, + {url: 'http://localhost/matomo.php', idSite: 1, cookieDomain: ''}, + {url: 'http://127.0.0.1/matomo.php', idSite: 20, cookieDomain: ''}, + {url: 'http://localhost/matomo.php', idSite: 33, cookieDomain: ''}, ], visitorCustomVariables: [ {id: 1, name: 'Access', value: 'user'} diff --git a/tests/javascript/content-fixtures/trackerInternals.html b/tests/javascript/content-fixtures/trackerInternals.html index ee4494c65d7..1f12ad9c382 100644 --- a/tests/javascript/content-fixtures/trackerInternals.html +++ b/tests/javascript/content-fixtures/trackerInternals.html @@ -39,7 +39,7 @@ - + @@ -68,7 +68,7 @@ -Link +Link Link Link Link diff --git a/tests/javascript/index.php b/tests/javascript/index.php index f7670f71cf1..287e781cc99 100644 --- a/tests/javascript/index.php +++ b/tests/javascript/index.php @@ -3,7 +3,7 @@ - piwik.js: Unit Tests + matomo.js: Unit Tests - + @@ -274,7 +274,7 @@ function fetchTrackedRequests(token, parse) window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : null; - xhr.open("GET", "piwik.php?requests=" + token, false); + xhr.open("GET", "matomo.php?requests=" + token, false); xhr.send(null); var response = xhr.responseText; @@ -1846,31 +1846,31 @@ function assertTrackingRequest(actual, expectedStartsWith, message) strictEqual(actual, undefined, 'nothing set'); actual = tracker.buildContentInteractionTrackingRedirectUrl('/path?a=b'); - assertTrackingRequest(actual, 'piwik.php?redirecturl=' + encodeWrapper(origin + '/path?a=b') + '&c_t=%2Fpath%3Fa%3Db', + assertTrackingRequest(actual, 'matomo.php?redirecturl=' + encodeWrapper(origin + '/path?a=b') + '&c_t=%2Fpath%3Fa%3Db', 'should build redirect url including domain when absolute path. Target should also fallback to passed url if not set'); actual = tracker.buildContentInteractionTrackingRedirectUrl('path?a=b'); - assertTrackingRequest(actual, 'piwik.php?redirecturl=' + toEncodedAbsoluteUrl('path?a=b') + '&c_t=path%3Fa%3Db', + assertTrackingRequest(actual, 'matomo.php?redirecturl=' + toEncodedAbsoluteUrl('path?a=b') + '&c_t=path%3Fa%3Db', 'should build redirect url including domain when relative path. Target should also fallback to passed url if not set'); actual = tracker.buildContentInteractionTrackingRedirectUrl('#test', 'click', 'name', 'piece', 'target'); - assertTrackingRequest(actual, 'piwik.php?redirecturl=' + toEncodedAbsoluteUrl('#test') + '&c_i=click&c_n=name&c_p=piece&c_t=target', 'all params set'); + assertTrackingRequest(actual, 'matomo.php?redirecturl=' + toEncodedAbsoluteUrl('#test') + '&c_i=click&c_n=name&c_p=piece&c_t=target', 'all params set'); trackerUrl = tracker.getTrackerUrl(); - tracker.setTrackerUrl('piwik.php?test=1'); + tracker.setTrackerUrl('matomo.php?test=1'); actual = tracker.buildContentInteractionTrackingRedirectUrl('#test', 'click', 'name', 'piece', 'target'); - assertTrackingRequest(actual, 'piwik.php?test=1&redirecturl=' + toEncodedAbsoluteUrl('#test') + '&c_i=click&c_n=name&c_p=piece&c_t=target', 'should use & if tracker url already contains question mark'); + assertTrackingRequest(actual, 'matomo.php?test=1&redirecturl=' + toEncodedAbsoluteUrl('#test') + '&c_i=click&c_n=name&c_p=piece&c_t=target', 'should use & if tracker url already contains question mark'); - tracker.setTrackerUrl('piwik.php'); - actual = tracker.buildContentInteractionTrackingRedirectUrl('piwik.php?redirecturl=http://www.example.com', 'click', 'name', 'piece', 'target'); - strictEqual(actual, 'piwik.php?redirecturl=http://www.example.com', 'should return unmodified url if it is already a tracker url so users can set piwik.php link in href'); + tracker.setTrackerUrl('matomo.php'); + actual = tracker.buildContentInteractionTrackingRedirectUrl('matomo.php?redirecturl=http://www.example.com', 'click', 'name', 'piece', 'target'); + strictEqual(actual, 'matomo.php?redirecturl=http://www.example.com', 'should return unmodified url if it is already a tracker url so users can set matomo.php link in href'); actual = tracker.buildContentInteractionTrackingRedirectUrl('http://www.example.com', 'click', 'name'); - assertTrackingRequest(actual, 'piwik.php?redirecturl=' + encodeWrapper('http://www.example.com') + '&c_i=click&c_n=name&c_t=http%3A%2F%2Fwww.example.com', 'should not change url if absolute'); + assertTrackingRequest(actual, 'matomo.php?redirecturl=' + encodeWrapper('http://www.example.com') + '&c_i=click&c_n=name&c_t=http%3A%2F%2Fwww.example.com', 'should not change url if absolute'); actual = tracker.buildContentInteractionTrackingRedirectUrl(origin, 'something', 'name', undefined, 'target'); - assertTrackingRequest(actual, 'piwik.php?redirecturl=' + originEncoded + '&c_i=something&c_n=name&c_t=target', 'should not change url if same domain'); + assertTrackingRequest(actual, 'matomo.php?redirecturl=' + originEncoded + '&c_i=something&c_n=name&c_t=target', 'should not change url if same domain'); tracker.setTrackerUrl(trackerUrl); @@ -1938,7 +1938,7 @@ function assertTrackingRequest(actual, expectedStartsWith, message) ok('test trackContentImpressionClickInteraction()'); trackerUrl = tracker.getTrackerUrl(); - tracker.setTrackerUrl('piwik.php'); + tracker.setTrackerUrl('matomo.php'); tracker.disableLinkTracking(); ok(_s('#ignoreInteraction1') && _s('#ex108') && _s('#ex109'), 'make sure node exists otherwise test is useless'); @@ -1951,15 +1951,15 @@ function assertTrackingRequest(actual, expectedStartsWith, message) assertTrackingRequest(actual, 'c_i=click&c_n=http%3A%2F%2Fwww.example.com%2Fpath%2Fxyz.jpg&c_p=http%3A%2F%2Fwww.example.com%2Fpath%2Fxyz.jpg&c_t=http%3A%2F%2Fad.example.com', 'trackContentImpressionClickInteraction, is outlink but should use xhr as link tracking not enabled'); actual = (tracker.trackContentImpressionClickInteraction(_s('#ex109')))({target: _s('#ex109')}); strictEqual(actual, 'href', 'trackContentImpressionClickInteraction, is internal download but should use href as link tracking not enabled'); - assertTrackingRequest($(_s('#ex109')).attr('href'), 'piwik.php?redirecturl=' + toEncodedAbsoluteUrl('/file.pdf') + '&c_i=click&c_n=http%3A%2F%2Fwww.example.com%2Fpath%2Fxyz.jpg&c_p=http%3A%2F%2Fwww.example.com%2Fpath%2Fxyz.jpg&c_t=' + originEncoded + '%2Ffile.pdf', 'trackContentImpressionClickInteraction, the href download link should be replaced with a redirect link to tracker'); + assertTrackingRequest($(_s('#ex109')).attr('href'), 'matomo.php?redirecturl=' + toEncodedAbsoluteUrl('/file.pdf') + '&c_i=click&c_n=http%3A%2F%2Fwww.example.com%2Fpath%2Fxyz.jpg&c_p=http%3A%2F%2Fwww.example.com%2Fpath%2Fxyz.jpg&c_t=' + originEncoded + '%2Ffile.pdf', 'trackContentImpressionClickInteraction, the href download link should be replaced with a redirect link to tracker'); actual = (tracker.trackContentImpressionClickInteraction(_s('#ex110')))({target: _s('#ex110')}); strictEqual(actual, 'href', 'trackContentImpressionClickInteraction, should be tracked using redirect'); - assertTrackingRequest($(_s('#ex110')).attr('href'), 'piwik.php?redirecturl=' + toEncodedAbsoluteUrl('/example') + '&c_i=click&c_n=MyName&c_p=img.jpg&c_t=' + originEncoded + '%2Fexample', 'trackContentImpressionClickInteraction, the href link should be replaced with a redirect link to tracker'); + assertTrackingRequest($(_s('#ex110')).attr('href'), 'matomo.php?redirecturl=' + toEncodedAbsoluteUrl('/example') + '&c_i=click&c_n=MyName&c_p=img.jpg&c_t=' + originEncoded + '%2Fexample', 'trackContentImpressionClickInteraction, the href link should be replaced with a redirect link to tracker'); actual = (tracker.trackContentImpressionClickInteraction(_s('#ex111')))({target: _s('#ex111')}); strictEqual(actual, 'href', 'trackContentImpressionClickInteraction, should detect it is a link to same page'); - strictEqual($(_s('#ex111')).attr('href'), 'piwik.php?xyz=makesnosense', 'trackContentImpressionClickInteraction, a tracking link should not be changed'); + strictEqual($(_s('#ex111')).attr('href'), 'matomo.php?xyz=makesnosense', 'trackContentImpressionClickInteraction, a tracking link should not be changed'); actual = (tracker.trackContentImpressionClickInteraction(_s('#ex112')))({target: _s('#ex112')}); assertTrackingRequest(actual, 'c_i=click&c_n=img.jpg&c_p=img.jpg&c_t=' + toEncodedAbsoluteUrl('#example'), 'trackContentImpressionClickInteraction, a link that is an anchor should be tracked as XHR and no redirect'); @@ -1974,7 +1974,7 @@ function assertTrackingRequest(actual, expectedStartsWith, message) actual = (tracker.trackContentImpressionClickInteraction(_s('#ex108')))({target: _s('#ex108')}); strictEqual(actual, 'link', 'trackContentImpressionClickInteraction, should not track as is an outlink and link tracking enabled'); - $(_s('#ex109')).attr('href', '/file.pdf'); // reset download link as was replaced with piwik.php + $(_s('#ex109')).attr('href', '/file.pdf'); // reset download link as was replaced with matomo.php actual = (tracker.trackContentImpressionClickInteraction(_s('#ex109')))({target: _s('#ex109')}); strictEqual(actual, 'download', 'trackContentImpressionClickInteraction, should not track as is a download and link tracking enabled'); @@ -2069,20 +2069,20 @@ function assertTrackingRequest(actual, expectedStartsWith, message) ok('test replaceHrefIfInternalLink()') var trackerUrl = tracker.getTrackerUrl(); - tracker.setTrackerUrl('piwik.php'); + tracker.setTrackerUrl('matomo.php'); strictEqual(tracker.replaceHrefIfInternalLink(), false, 'no content node set'); strictEqual(tracker.replaceHrefIfInternalLink(_s('#ex117')), false, 'should be ignored'); $(_s('#ignoreInternalLink')).removeClass('piwikContentIgnoreInteraction'); // now it should be no longer ignored and as it is an intenral link replaced strictEqual(tracker.replaceHrefIfInternalLink(_s('#ex117')), true, 'should be replaced as is internal link'); - assertTrackingRequest($(_s('#ignoreInternalLink')).attr('href'), 'piwik.php?redirecturl=' + toEncodedAbsoluteUrl('/internallink') + '&c_i=click&c_n=Unknown&c_p=Unknown&c_t=' + originEncoded + '%2Finternallink', 'internal link should be replaced'); + assertTrackingRequest($(_s('#ignoreInternalLink')).attr('href'), 'matomo.php?redirecturl=' + toEncodedAbsoluteUrl('/internallink') + '&c_i=click&c_n=Unknown&c_p=Unknown&c_t=' + originEncoded + '%2Finternallink', 'internal link should be replaced'); strictEqual($(_s('#ignoreInternalLink')).attr('data-content-target'), origin + '/internallink', 'we need to set data-content-target when link is set otherwise a replace would not be found'); strictEqual(tracker.replaceHrefIfInternalLink(_s('#ex122')), true, 'should be replaced'); strictEqual($(_s('#replacedLinkWithTarget')).attr('data-content-target'), '/test', 'should replace href but not a data-content-target if already exists'); strictEqual(tracker.replaceHrefIfInternalLink(_s('#ex118')), true, 'should not replace already replaced link'); - strictEqual($(_s('#ex118')).attr('href'), 'piwik.php?test=5', 'link should not be replaced'); + strictEqual($(_s('#ex118')).attr('href'), 'matomo.php?test=5', 'link should not be replaced'); strictEqual(tracker.replaceHrefIfInternalLink(_s('#ex119')), false, 'anchor link should not be replaced'); strictEqual($(_s('#ex119')).attr('href'), '#test', 'link should not replace anchor link'); @@ -2091,7 +2091,7 @@ function assertTrackingRequest(actual, expectedStartsWith, message) strictEqual($(_s('#ex120')).attr('href'), 'http://www.example.com', 'should not replace external link'); strictEqual(tracker.replaceHrefIfInternalLink(_s('#ex121')), true, 'should replace download link if link tracking not enabled'); - assertTrackingRequest($(_s('#ex121')).attr('href'), 'piwik.php?redirecturl=' + toEncodedAbsoluteUrl('/download.pdf') + '&c_i=click&c_n=Unknown&c_p=Unknown&c_t=' + originEncoded + '%2Fdownload.pdf', 'should replace download link as link tracking disabled'); + assertTrackingRequest($(_s('#ex121')).attr('href'), 'matomo.php?redirecturl=' + toEncodedAbsoluteUrl('/download.pdf') + '&c_i=click&c_n=Unknown&c_p=Unknown&c_t=' + originEncoded + '%2Fdownload.pdf', 'should replace download link as link tracking disabled'); $(_s('#ex121')).attr('href', '/download.pdf'); // reset link tracker.enableLinkTracking(); @@ -2510,7 +2510,7 @@ function assertTrackingRequest(actual, expectedStartsWith, message) equal( typeof tracker.hook.test._titleFixup, 'function', 'titleFixup' ); equal( tracker.hook.test._titleFixup( 'hello' ), 'hello', 'hello string' ); - equal( tracker.hook.test._titleFixup( document.title ), 'piwik.js: Unit Tests', 'hello string' ); + equal( tracker.hook.test._titleFixup( document.title ), 'matomo.js: Unit Tests', 'hello string' ); equal( typeof tracker.hook.test._purify, 'function', 'purify' ); @@ -3048,7 +3048,7 @@ function makeIsLinkToDifferentDomainButSamePiwikWebsite(url) { expect(4); var tracker = Piwik.getTracker(); - tracker.setTrackerUrl("piwik.php"); + tracker.setTrackerUrl("matomo.php"); tracker.setSiteId(1); cookieName = tracker.hook.test._getCookieName('testing'); @@ -3139,20 +3139,20 @@ function runTests(messagePrefix) { tracker.setDownloadClasses([]); tracker.setLinkClasses([]); - equal( tracker.hook.test._getLinkType('something', 'piwik.php', false), 'link', 'an empty tracker url should not match configtrackerurl' ); + equal( tracker.hook.test._getLinkType('something', 'matomo.php', false), 'link', 'an empty tracker url should not match configtrackerurl' ); runTests('without tracker url, '); - tracker.setTrackerUrl('piwik.php'); + tracker.setTrackerUrl('matomo.php'); tracker.setDownloadClasses([]); tracker.setLinkClasses([]); tracker.setDownloadExtensions(downloadExtensions); runTests('with tracker url, '); - equal( tracker.hook.test._getLinkType('something', 'piwik.php', true, false), 0, 'matches tracker url and should never return any tracker Url' ); - equal( tracker.hook.test._getLinkType('something', 'piwik.php?redirecturl=http://example.com/test.pdf', true, false), 0, 'should not match download as is config tracker url' ); - equal( tracker.hook.test._getLinkType('something', 'piwik.php?redirecturl=http://example.com/', true, false), 0, 'should not match link as is config tracker url' ); + equal( tracker.hook.test._getLinkType('something', 'matomo.php', true, false), 0, 'matches tracker url and should never return any tracker Url' ); + equal( tracker.hook.test._getLinkType('something', 'matomo.php?redirecturl=http://example.com/test.pdf', true, false), 0, 'should not match download as is config tracker url' ); + equal( tracker.hook.test._getLinkType('something', 'matomo.php?redirecturl=http://example.com/', true, false), 0, 'should not match link as is config tracker url' ); tracker.setTrackerUrl(trackerUrl); }); @@ -3486,13 +3486,13 @@ function callNonExistingMethodWithParameter() { equal( getPiwikUrlForOverlay('http://www.example.com/tracker.php?version=232323'), 'http://www.example.com/', 'with query and no js folder' ); equal( getPiwikUrlForOverlay('http://www.example.com/js/tracker.php'), 'http://www.example.com/', 'no query, custom tracker and js folder' ); equal( getPiwikUrlForOverlay('http://www.example.com/tracker.php'), 'http://www.example.com/', 'no query, custom tracker and no js folder' ); - equal( getPiwikUrlForOverlay('http://www.example.com/js/piwik.php'), 'http://www.example.com/', 'with piwik.php and no js folder' ); - equal( getPiwikUrlForOverlay('http://www.example.com/piwik.php'), 'http://www.example.com/', 'with piwik.php and no js folder' ); - equal( getPiwikUrlForOverlay('http://www.example.com/master/js/piwik.php'), 'http://www.example.com/master/', 'installed in custom folder and js folder' ); - equal( getPiwikUrlForOverlay('http://www.example.com/master/piwik.php'), 'http://www.example.com/master/', 'installed in custom folder and no js folder' ); - equal( getPiwikUrlForOverlay('/piwik.php'), toAbsoluteUrl('/'), 'only piwik.php with leading slash' ); - equal( getPiwikUrlForOverlay('piwik.php'), toAbsoluteUrl(''), 'only piwik.php' ); - equal( getPiwikUrlForOverlay('/piwik.php?version=1234'), toAbsoluteUrl('/'), 'only piwik.php with leading slash with query' ); + equal( getPiwikUrlForOverlay('http://www.example.com/js/matomo.php'), 'http://www.example.com/', 'with matomo.php and no js folder' ); + equal( getPiwikUrlForOverlay('http://www.example.com/matomo.php'), 'http://www.example.com/', 'with matomo.php and no js folder' ); + equal( getPiwikUrlForOverlay('http://www.example.com/master/js/matomo.php'), 'http://www.example.com/master/', 'installed in custom folder and js folder' ); + equal( getPiwikUrlForOverlay('http://www.example.com/master/matomo.php'), 'http://www.example.com/master/', 'installed in custom folder and no js folder' ); + equal( getPiwikUrlForOverlay('/matomo.php'), toAbsoluteUrl('/'), 'only matomo.php with leading slash' ); + equal( getPiwikUrlForOverlay('matomo.php'), toAbsoluteUrl(''), 'only matomo.php' ); + equal( getPiwikUrlForOverlay('/matomo.php?version=1234'), toAbsoluteUrl('/'), 'only matomo.php with leading slash with query' ); }); function generateAnIframeInDocument() { @@ -3504,7 +3504,7 @@ function generateAnIframeInDocument() { var html = '\ \ \ - \ + \ \ \ window.onload = function() { \ @@ -3591,7 +3591,7 @@ function generateAnIframeInDocument() { }; var tracker = Piwik.getTracker(); - tracker.setTrackerUrl("piwik.php"); + tracker.setTrackerUrl("matomo.php"); tracker.setSiteId(1); strictEqual(0, tracker.getNumTrackedPageViews(), 'getNumTrackedPageViews, is zero by default'); @@ -3602,19 +3602,19 @@ function generateAnIframeInDocument() { } equal(tracker.getPiwikUrl(), piwikUrl, "getPiwikUrl, relative tracker url" ); - tracker.setTrackerUrl("http://apache.piwik/piwik.php"); + tracker.setTrackerUrl("http://apache.piwik/matomo.php"); equal(tracker.getPiwikUrl(), 'http://apache.piwik/', "getPiwikUrl, in root directory" ); tracker.setTrackerUrl("http://apache.piwik/tracker.php"); equal(tracker.getPiwikUrl(), 'http://apache.piwik/', "getPiwikUrl, with different file name" ); - tracker.setTrackerUrl("http://apache.piwik/tests/javascript/piwik.php?x=1"); + tracker.setTrackerUrl("http://apache.piwik/tests/javascript/matomo.php?x=1"); equal(tracker.getPiwikUrl(), 'http://apache.piwik/tests/javascript/', "getPiwikUrl, with path and query" ); - tracker.setTrackerUrl("http://apache.piwik/js/piwik.php?x=1"); + tracker.setTrackerUrl("http://apache.piwik/js/matomo.php?x=1"); equal(tracker.getPiwikUrl(), 'http://apache.piwik/', "getPiwikUrl, when using unminified piwik.js" ); - tracker.setTrackerUrl("piwik.php"); + tracker.setTrackerUrl("matomo.php"); var thirteenMonths = 1000 * 60 * 60 * 24 * 393; strictEqual(thirteenMonths, tracker.getConfigVisitorCookieTimeout(), 'default visitor timeout should be 13 months'); @@ -3750,7 +3750,7 @@ function generateAnIframeInDocument() { tracker.setRequestMethod("POST"); tracker.trackGoal(42, 69, { "token" : getToken(), "boy" : "Michael", "girl" : "Mandy"}); - piwik_log("CompatibilityLayer", 1, "piwik.php", { "token" : getToken() }); + piwik_log("CompatibilityLayer", 1, "matomo.php", { "token" : getToken() }); tracker.hook.test._addEventListener(_e("click8"), "click", stopEvent); triggerEvent(_e("click8"), 'click'); @@ -3866,7 +3866,7 @@ function generateAnIframeInDocument() { tracker.trackPageView("MultipleCategories"); var tracker2 = Piwik.getTracker(); - tracker2.setTrackerUrl("piwik.php"); + tracker2.setTrackerUrl("matomo.php"); tracker2.setSiteId(1); tracker2.storeCustomVariablesInCookie(); tracker2.setCustomData({ "token" : getToken() }); @@ -3883,7 +3883,7 @@ function generateAnIframeInDocument() { tracker2.trackPageView("DeleteCustomVariableCookie"); var tracker3 = Piwik.getTracker(); - tracker3.setTrackerUrl("piwik.php"); + tracker3.setTrackerUrl("matomo.php"); tracker3.setSiteId(1); tracker3.setCustomData({ "token" : getToken() }); tracker3.setCookieNamePrefix("PREFIX"); @@ -3977,7 +3977,7 @@ function generateAnIframeInDocument() { stop(); setTimeout(function() { - xhr.open("GET", "piwik.php?requests=" + getToken(), false); + xhr.open("GET", "matomo.php?requests=" + getToken(), false); xhr.send(null); results = xhr.responseText; equal( (/([0-9]+)\<\/span\>/.exec(results))[1], "40", "count tracking events" ); @@ -3987,7 +3987,7 @@ function generateAnIframeInDocument() { // tracking requests ok( /PiwikTest/.test( results ), "trackPageView(), setDocumentTitle()" ); - ok( results.indexOf("tests/javascript/piwik.php?action_name=Asynchronous%20Tracker%20ONE&idsite=1&rec=1") >= 0 , "async trackPageView() called before setTrackerUrl() should work" ); + ok( results.indexOf("tests/javascript/matomo.php?action_name=Asynchronous%20Tracker%20ONE&idsite=1&rec=1") >= 0 , "async trackPageView() called before setTrackerUrl() should work" ); ok( /Asynchronous%20tracking%20TWO/.test( results ), "async trackPageView() called after another trackPageView()" ); ok( /CustomTitleTest/.test( results ), "trackPageView(customTitle)" ); ok( results.indexOf('&pv_id=' + idPageview) !== -1, "trackPageView, configPageId should be sent along requests" ); @@ -4083,8 +4083,8 @@ function generateAnIframeInDocument() { ok( /e_c=JavaScript%20Errors&e_a=http%3A%2F%2Fpiwik.org%2Fpath%2Fto%2Ffile.js%3Fcb%3D34343%3A44%3A12&e_n=Uncaught%20Error%3A%20The%20message&idsite=1/.test( results ), "enableJSErrorTracking() function with predefined onerror event"); ok( /e_c=JavaScript%20Errors&e_a=http%3A%2F%2Fpiwik.org%2Fpath%2Fto%2Ffile.js%3Fcb%3D3kfkf%3A45&e_n=Second%20Error%3A%20With%20less%20data&idsite=1/.test( results ), "enableJSErrorTracking() function without predefined onerror event and less parameters"); - ok( /piwik.php\?action_name=twoTrackers&idsite=1&/.test( results ), "addTracker() trackPageView() sends request to both Piwik instances"); - ok( /piwik.php\?action_name=twoTrackers&idsite=13&/.test( results ), "addTracker() trackPageView() sends request to both Piwik instances"); + ok( /matomo.php\?action_name=twoTrackers&idsite=1&/.test( results ), "addTracker() trackPageView() sends request to both Piwik instances"); + ok( /matomo.php\?action_name=twoTrackers&idsite=13&/.test( results ), "addTracker() trackPageView() sends request to both Piwik instances"); start(); }, 5000); @@ -4097,7 +4097,7 @@ function generateAnIframeInDocument() { var tokenBase = getHeartbeatToken(); var tracker = Piwik.getTracker(); - tracker.setTrackerUrl("piwik.php"); + tracker.setTrackerUrl("matomo.php"); tracker.setSiteId(1); tracker.enableHeartBeatTimer(3); @@ -4186,7 +4186,7 @@ function assertTrackingRequest(actual, expectedStartsWith, message) message += ', '; } - expectedStartsWith = '' + toAbsolutePath('piwik.php') + '?' + expectedStartsWith; + expectedStartsWith = '' + toAbsolutePath('matomo.php') + '?' + expectedStartsWith; strictEqual(actual.indexOf(expectedStartsWith), 0, message + actual + ' should start with ' + expectedStartsWith); strictEqual(actual.indexOf('&idsite=1&rec=1'), expectedStartsWith.length); @@ -4203,7 +4203,7 @@ function resetTracker(track, token, replace) var token = getContentToken(); var tracker = Piwik.getTracker(); - tracker.setTrackerUrl("piwik.php"); + tracker.setTrackerUrl("matomo.php"); tracker.setSiteId(1); resetTracker(tracker, token); @@ -4620,7 +4620,7 @@ function assertTrackingRequest(actual, expectedStartsWith, message) message += ', '; } - expectedStartsWith = '' + toAbsolutePath('piwik.php') + '?' + expectedStartsWith; + expectedStartsWith = '' + toAbsolutePath('matomo.php') + '?' + expectedStartsWith; strictEqual(actual.indexOf(expectedStartsWith), 0, message + actual + ' should start with ' + expectedStartsWith); strictEqual(actual.indexOf('&idsite=1&rec=1'), expectedStartsWith.length); @@ -4645,7 +4645,7 @@ function preventClickDefault(selector) var actual, expected, trackerUrl; var tracker = Piwik.getTracker(); - tracker.setTrackerUrl("piwik.php"); + tracker.setTrackerUrl("matomo.php"); tracker.setSiteId(1); resetTracker(tracker, token); @@ -4694,7 +4694,7 @@ function preventClickDefault(selector) var token5 = '5' + token; resetTracker(tracker, token5); preventClickDefault('#internalLink'); - var expectedLink = toAbsoluteUrl('piwik.php') + '?redirecturl=' + toEncodedAbsoluteUrl('/anylink5') + '&c_i=click&c_n=My%20Ad%205&c_p=http%3A%2F%2Fimg5.example.com%2Fpath%2Fxyz.jpg&c_t=' + originEncoded + '%2Fanylink5&idsite=1&rec=1'; + var expectedLink = toAbsoluteUrl('matomo.php') + '?redirecturl=' + toEncodedAbsoluteUrl('/anylink5') + '&c_i=click&c_n=My%20Ad%205&c_p=http%3A%2F%2Fimg5.example.com%2Fpath%2Fxyz.jpg&c_t=' + originEncoded + '%2Fanylink5&idsite=1&rec=1'; var newHref = _s('#internalLink').href; strictEqual(0, newHref.indexOf(expectedLink), 'replaced href is replaced: ' + newHref); // make sure was already replace by trackContentImpressions() strictEqual(_s('#internalLink').wasContentTargetAttrReplaced, true, 'has to be marked as replaced so we know we have to update content target again in case the url changes meanwhile'); @@ -4705,7 +4705,7 @@ function preventClickDefault(selector) triggerEvent(_s('#internalLink'), 'click'); // should replace href php newHref = _s('#internalLink').href; - expectedLink = toAbsoluteUrl('piwik.php') + '?redirecturl=' + toEncodedAbsoluteUrl('/newlink') + '&c_i=click&c_n=My%20Ad%205&c_p=http%3A%2F%2Fimg5.example.com%2Fpath%2Fxyz.jpg&c_t=' + originEncoded + '%2Fnewlink&idsite=1&rec=1'; + expectedLink = toAbsoluteUrl('matomo.php') + '?redirecturl=' + toEncodedAbsoluteUrl('/newlink') + '&c_i=click&c_n=My%20Ad%205&c_p=http%3A%2F%2Fimg5.example.com%2Fpath%2Fxyz.jpg&c_t=' + originEncoded + '%2Fnewlink&idsite=1&rec=1'; strictEqual(0, newHref.indexOf(expectedLink), 'replaced href2 is replaced again: ' + newHref); // make sure was already replace by trackContentImpressions() wait(300); @@ -4920,7 +4920,7 @@ function customAddEventListener(element, eventType, eventHandler, useCapture) { Navbar example