add icons for Character groups
136
www/analytics/plugins/Overlay/API.php
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\Overlay;
|
||||
|
||||
use Exception;
|
||||
use Piwik\Access;
|
||||
use Piwik\Config;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\SitesManager\API as APISitesManager;
|
||||
use Piwik\Plugins\SitesManager\SitesManager;
|
||||
use Piwik\Plugins\Transitions\API as APITransitions;
|
||||
use Piwik\Tracker\PageUrl;
|
||||
|
||||
/**
|
||||
* Class API
|
||||
* @method static \Piwik\Plugins\Overlay\API getInstance()
|
||||
*/
|
||||
class API extends \Piwik\Plugin\API
|
||||
{
|
||||
/**
|
||||
* Get translation strings
|
||||
*/
|
||||
public function getTranslations($idSite)
|
||||
{
|
||||
$this->authenticate($idSite);
|
||||
|
||||
$translations = array(
|
||||
'oneClick' => 'Overlay_OneClick',
|
||||
'clicks' => 'Overlay_Clicks',
|
||||
'clicksFromXLinks' => 'Overlay_ClicksFromXLinks',
|
||||
'link' => 'Overlay_Link'
|
||||
);
|
||||
|
||||
return array_map(array('\\Piwik\\Piwik','translate'), $translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get excluded query parameters for a site.
|
||||
* This information is used for client side url normalization.
|
||||
*/
|
||||
public function getExcludedQueryParameters($idSite)
|
||||
{
|
||||
$this->authenticate($idSite);
|
||||
|
||||
$sitesManager = APISitesManager::getInstance();
|
||||
$site = $sitesManager->getSiteFromId($idSite);
|
||||
|
||||
try {
|
||||
return SitesManager::getTrackerExcludedQueryParameters($site);
|
||||
} catch (Exception $e) {
|
||||
// an exception is thrown when the user has no view access.
|
||||
// do not throw the exception to the outside.
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get following pages of a url.
|
||||
* This is done on the logs - not the archives!
|
||||
*
|
||||
* Note: if you use this method via the regular API, the number of results will be limited.
|
||||
* Make sure, you set filter_limit=-1 in the request.
|
||||
*/
|
||||
public function getFollowingPages($url, $idSite, $period, $date, $segment = false)
|
||||
{
|
||||
$this->authenticate($idSite);
|
||||
|
||||
$url = PageUrl::excludeQueryParametersFromUrl($url, $idSite);
|
||||
// we don't unsanitize $url here. it will be done in the Transitions plugin.
|
||||
|
||||
$resultDataTable = new DataTable;
|
||||
|
||||
try {
|
||||
$limitBeforeGrouping = Config::getInstance()->General['overlay_following_pages_limit'];
|
||||
$transitionsReport = APITransitions::getInstance()->getTransitionsForAction(
|
||||
$url, $type = 'url', $idSite, $period, $date, $segment, $limitBeforeGrouping,
|
||||
$part = 'followingActions', $returnNormalizedUrls = true);
|
||||
} catch (Exception $e) {
|
||||
return $resultDataTable;
|
||||
}
|
||||
|
||||
$reports = array('followingPages', 'outlinks', 'downloads');
|
||||
foreach ($reports as $reportName) {
|
||||
if (!isset($transitionsReport[$reportName])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($transitionsReport[$reportName]->getRows() as $row) {
|
||||
// don't touch the row at all for performance reasons
|
||||
$resultDataTable->addRow($row);
|
||||
}
|
||||
}
|
||||
|
||||
return $resultDataTable;
|
||||
}
|
||||
|
||||
/** Do cookie authentication. This way, the token can remain secret. */
|
||||
private function authenticate($idSite)
|
||||
{
|
||||
/**
|
||||
* Triggered immediately before the user is authenticated.
|
||||
*
|
||||
* This event can be used by plugins that provide their own authentication mechanism
|
||||
* to make that mechanism available. Subscribers should set the `'auth'` object in
|
||||
* the {@link Piwik\Registry} to an object that implements the {@link Piwik\Auth} interface.
|
||||
*
|
||||
* **Example**
|
||||
*
|
||||
* use Piwik\Registry;
|
||||
*
|
||||
* public function initAuthenticationObject($activateCookieAuth)
|
||||
* {
|
||||
* Registry::set('auth', new LDAPAuth($activateCookieAuth));
|
||||
* }
|
||||
*
|
||||
* @param bool $activateCookieAuth Whether authentication based on `$_COOKIE` values should
|
||||
* be allowed.
|
||||
*/
|
||||
Piwik::postEvent('Request.initAuthenticationObject', array($activateCookieAuth = true));
|
||||
|
||||
$auth = \Piwik\Registry::get('auth');
|
||||
$success = Access::getInstance()->reloadAccess($auth);
|
||||
|
||||
if (!$success) {
|
||||
throw new Exception('Authentication failed');
|
||||
}
|
||||
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
}
|
||||
}
|
||||
236
www/analytics/plugins/Overlay/Controller.php
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\Overlay;
|
||||
|
||||
use Piwik\API\Request;
|
||||
use Piwik\Common;
|
||||
use Piwik\Config;
|
||||
use Piwik\Metrics;
|
||||
use Piwik\MetricsFormatter;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\Actions\ArchivingHelper;
|
||||
use Piwik\Plugins\SitesManager\API as APISitesManager;
|
||||
use Piwik\ProxyHttp;
|
||||
use Piwik\Tracker\Action;
|
||||
use Piwik\Tracker\PageUrl;
|
||||
use Piwik\View;
|
||||
|
||||
class Controller extends \Piwik\Plugin\Controller
|
||||
{
|
||||
|
||||
/** The index of the plugin */
|
||||
public function index()
|
||||
{
|
||||
Piwik::checkUserHasViewAccess($this->idSite);
|
||||
|
||||
$template = '@Overlay/index';
|
||||
if (Config::getInstance()->General['overlay_disable_framed_mode']) {
|
||||
$template = '@Overlay/index_noframe';
|
||||
}
|
||||
|
||||
$view = new View($template);
|
||||
|
||||
$this->setGeneralVariablesView($view);
|
||||
|
||||
$view->idSite = $this->idSite;
|
||||
$view->date = Common::getRequestVar('date', 'today');
|
||||
$view->period = Common::getRequestVar('period', 'day');
|
||||
|
||||
$view->ssl = ProxyHttp::isHttps();
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/** Render the area left of the iframe */
|
||||
public function renderSidebar()
|
||||
{
|
||||
$idSite = Common::getRequestVar('idSite');
|
||||
$period = Common::getRequestVar('period');
|
||||
$date = Common::getRequestVar('date');
|
||||
$currentUrl = Common::getRequestVar('currentUrl');
|
||||
$currentUrl = Common::unsanitizeInputValue($currentUrl);
|
||||
|
||||
$normalizedCurrentUrl = PageUrl::excludeQueryParametersFromUrl($currentUrl, $idSite);
|
||||
$normalizedCurrentUrl = Common::unsanitizeInputValue($normalizedCurrentUrl);
|
||||
|
||||
// load the appropriate row of the page urls report using the label filter
|
||||
ArchivingHelper::reloadConfig();
|
||||
$path = ArchivingHelper::getActionExplodedNames($normalizedCurrentUrl, Action::TYPE_PAGE_URL);
|
||||
$path = array_map('urlencode', $path);
|
||||
$label = implode('>', $path);
|
||||
$request = new Request(
|
||||
'method=Actions.getPageUrls'
|
||||
. '&idSite=' . urlencode($idSite)
|
||||
. '&date=' . urlencode($date)
|
||||
. '&period=' . urlencode($period)
|
||||
. '&label=' . urlencode($label)
|
||||
. '&format=original'
|
||||
);
|
||||
$dataTable = $request->process();
|
||||
|
||||
$data = array();
|
||||
if ($dataTable->getRowsCount() > 0) {
|
||||
$row = $dataTable->getFirstRow();
|
||||
|
||||
$translations = Metrics::getDefaultMetricTranslations();
|
||||
$showMetrics = array('nb_hits', 'nb_visits', 'nb_uniq_visitors',
|
||||
'bounce_rate', 'exit_rate', 'avg_time_on_page');
|
||||
|
||||
foreach ($showMetrics as $metric) {
|
||||
$value = $row->getColumn($metric);
|
||||
if ($value === false) {
|
||||
// skip unique visitors for period != day
|
||||
continue;
|
||||
}
|
||||
if ($metric == 'avg_time_on_page') {
|
||||
$value = MetricsFormatter::getPrettyTimeFromSeconds($value);
|
||||
}
|
||||
$data[] = array(
|
||||
'name' => $translations[$metric],
|
||||
'value' => $value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// generate page url string
|
||||
foreach ($path as &$part) {
|
||||
$part = preg_replace(';^/;', '', urldecode($part));
|
||||
}
|
||||
$page = '/' . implode('/', $path);
|
||||
$page = preg_replace(';/index$;', '/', $page);
|
||||
if ($page == '/') {
|
||||
$page = '/index';
|
||||
}
|
||||
|
||||
// render template
|
||||
$view = new View('@Overlay/renderSidebar');
|
||||
$view->data = $data;
|
||||
$view->location = $page;
|
||||
$view->normalizedUrl = $normalizedCurrentUrl;
|
||||
$view->label = $label;
|
||||
$view->idSite = $idSite;
|
||||
$view->period = $period;
|
||||
$view->date = $date;
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start an Overlay session: Redirect to the tracked website. The Piwik
|
||||
* tracker will recognize this referrer and start the session.
|
||||
*/
|
||||
public function startOverlaySession()
|
||||
{
|
||||
$idSite = Common::getRequestVar('idSite', 0, 'int');
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
$sitesManager = APISitesManager::getInstance();
|
||||
$site = $sitesManager->getSiteFromId($idSite);
|
||||
$urls = $sitesManager->getSiteUrlsFromId($idSite);
|
||||
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
return '
|
||||
<html><head><title></title></head><body>
|
||||
<script type="text/javascript">
|
||||
function handleProtocol(url) {
|
||||
if (' . (ProxyHttp::isHttps() ? 'true' : 'false') . ') {
|
||||
return url.replace(/http:\/\//i, "https://");
|
||||
} else {
|
||||
return url.replace(/https:\/\//i, "http://");
|
||||
}
|
||||
}
|
||||
|
||||
function removeUrlPrefix(url) {
|
||||
return url.replace(/http(s)?:\/\/(www\.)?/i, "");
|
||||
}
|
||||
|
||||
if (window.location.hash) {
|
||||
var match = false;
|
||||
|
||||
var urlToRedirect = window.location.hash.substr(1);
|
||||
var urlToRedirectWithoutPrefix = removeUrlPrefix(urlToRedirect);
|
||||
|
||||
var knownUrls = ' . Common::json_encode($urls) . ';
|
||||
for (var i = 0; i < knownUrls.length; i++) {
|
||||
var testUrl = removeUrlPrefix(knownUrls[i]);
|
||||
if (urlToRedirectWithoutPrefix.substr(0, testUrl.length) == testUrl) {
|
||||
match = true;
|
||||
if (navigator.appName == "Microsoft Internet Explorer") {
|
||||
// internet explorer loses the referrer if we use window.location.href=X
|
||||
var referLink = document.createElement("a");
|
||||
referLink.href = handleProtocol(urlToRedirect);
|
||||
document.body.appendChild(referLink);
|
||||
referLink.click();
|
||||
} else {
|
||||
window.location.href = handleProtocol(urlToRedirect);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
var idSite = window.location.href.match(/idSite=([0-9]+)/i)[1];
|
||||
window.location.href = "index.php?module=Overlay&action=showErrorWrongDomain"
|
||||
+ "&idSite=" + idSite
|
||||
+ "&url=" + encodeURIComponent(urlToRedirect);
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.location.href = handleProtocol("' . $site['main_url'] . '");
|
||||
};
|
||||
</script>
|
||||
</body></html>
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the JS from startOverlaySession() detects that the target domain
|
||||
* is not configured for the current site.
|
||||
*/
|
||||
public function showErrorWrongDomain()
|
||||
{
|
||||
$idSite = Common::getRequestVar('idSite', 0, 'int');
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
$url = Common::getRequestVar('url', '');
|
||||
$url = Common::unsanitizeInputValue($url);
|
||||
|
||||
$message = Piwik::translate('Overlay_RedirectUrlError', array($url, "\n"));
|
||||
$message = nl2br(htmlentities($message));
|
||||
|
||||
$view = new View('@Overlay/showErrorWrongDomain');
|
||||
$view->message = $message;
|
||||
|
||||
if (Piwik::isUserHasAdminAccess($idSite)) {
|
||||
// TODO use $idSite to link to the correct row. This is tricky because the #rowX ids don't match
|
||||
// the site ids when sites have been deleted.
|
||||
$url = 'index.php?module=SitesManager&action=index';
|
||||
$troubleshoot = htmlentities(Piwik::translate('Overlay_RedirectUrlErrorAdmin'));
|
||||
$troubleshoot = sprintf($troubleshoot, '<a href="' . $url . '" target="_top">', '</a>');
|
||||
$view->troubleshoot = $troubleshoot;
|
||||
} else {
|
||||
$view->troubleshoot = htmlentities(Piwik::translate('Overlay_RedirectUrlErrorUser'));
|
||||
}
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to pass information from the iframe back to Piwik.
|
||||
* Due to the same origin policy, we can't do that directly, so we inject
|
||||
* an additional iframe in the Overlay session that calls this controller
|
||||
* method.
|
||||
* The rendered iframe is from the same origin as the Piwik window so we
|
||||
* can bypass the same origin policy and call the parent.
|
||||
*/
|
||||
public function notifyParentIframe()
|
||||
{
|
||||
$view = new View('@Overlay/notifyParentIframe');
|
||||
return $view->render();
|
||||
}
|
||||
}
|
||||
49
www/analytics/plugins/Overlay/Overlay.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Plugins\Overlay;
|
||||
|
||||
|
||||
class Overlay extends \Piwik\Plugin
|
||||
{
|
||||
public function getInformation()
|
||||
{
|
||||
$suffix = ' Note: Requires the Transitions plugin enabled.';
|
||||
$info = parent::getInformation();
|
||||
$info['description'] .= ' ' . $suffix;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Piwik\Plugin::getListHooksRegistered
|
||||
*/
|
||||
function getListHooksRegistered()
|
||||
{
|
||||
return array(
|
||||
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
|
||||
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns required Js Files
|
||||
* @param $jsFiles
|
||||
*/
|
||||
public function getJsFiles(&$jsFiles)
|
||||
{
|
||||
$jsFiles[] = 'plugins/Overlay/javascripts/rowaction.js';
|
||||
$jsFiles[] = 'plugins/Overlay/javascripts/Overlay_Helper.js';
|
||||
}
|
||||
|
||||
public function getClientSideTranslationKeys(&$translationKeys)
|
||||
{
|
||||
$translationKeys[] = 'General_OverlayRowActionTooltipTitle';
|
||||
$translationKeys[] = 'General_OverlayRowActionTooltip';
|
||||
}
|
||||
}
|
||||
138
www/analytics/plugins/Overlay/client/client.css
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* Reset styles
|
||||
*/
|
||||
|
||||
#PIS_StatusBar,
|
||||
#PIS_StatusBar .PIS_Item,
|
||||
#PIS_StatusBar .PIS_Loading,
|
||||
.PIS_LinkTag,
|
||||
.PIS_LinkHighlightBoxTop,
|
||||
.PIS_LinkHighlightBoxRight,
|
||||
.PIS_LinkHighlightBoxLeft,
|
||||
.PIS_LinkHighlightBoxText {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 11px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
vertical-align: baseline;
|
||||
line-height: 1.4em;
|
||||
text-indent: 0;
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
cursor: default;
|
||||
text-align: left;
|
||||
float: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link Tags
|
||||
*/
|
||||
|
||||
.PIS_LinkTag {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
width: 36px;
|
||||
height: 21px;
|
||||
text-align: left;
|
||||
background: url(./linktags_lessshadow.png) no-repeat 0 -21px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.PIS_LinkTag span {
|
||||
position: absolute;
|
||||
width: 31px;
|
||||
height: 14px;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
line-height: 14px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Highlighted {
|
||||
z-index: 10002;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Highlighted span {
|
||||
color: #E87500;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Right {
|
||||
background-position: -36px -21px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Right span,
|
||||
.PIS_LinkTag.PIS_BottomRight span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Bottom {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Bottom span,
|
||||
.PIS_LinkTag.PIS_BottomRight span {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_BottomRight {
|
||||
background-position: -36px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link Highlights
|
||||
*/
|
||||
|
||||
.PIS_LinkHighlightBoxTop,
|
||||
.PIS_LinkHighlightBoxRight,
|
||||
.PIS_LinkHighlightBoxText,
|
||||
.PIS_LinkHighlightBoxLeft {
|
||||
position: absolute;
|
||||
z-index: 10001;
|
||||
overflow: hidden;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
background: #E87500;
|
||||
}
|
||||
|
||||
.PIS_LinkHighlightBoxText {
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
font-size: 11px;
|
||||
color: white;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status bar
|
||||
*/
|
||||
|
||||
#PIS_StatusBar {
|
||||
padding: 10px 0;
|
||||
position: fixed;
|
||||
z-index: 10020;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
border-left: 1px solid #ccc;
|
||||
background: #fbfbfb;
|
||||
border-radius: 6px 0 0;
|
||||
}
|
||||
|
||||
#PIS_StatusBar .PIS_Item {
|
||||
text-align: right;
|
||||
padding: 3px 5px 0 0;
|
||||
margin: 0 15px 0 20px;
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#PIS_StatusBar .PIS_Loading {
|
||||
background: url(./loading.gif) no-repeat right center;
|
||||
padding-right: 30px;
|
||||
}
|
||||
261
www/analytics/plugins/Overlay/client/client.js
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
var Piwik_Overlay_Client = (function () {
|
||||
|
||||
/** jQuery */
|
||||
var $;
|
||||
|
||||
/** Url of the Piwik root */
|
||||
var piwikRoot;
|
||||
|
||||
/** Piwik idsite */
|
||||
var idSite;
|
||||
|
||||
/** The current period and date */
|
||||
var period, date;
|
||||
|
||||
/** Reference to the status bar DOM element */
|
||||
var statusBar;
|
||||
|
||||
/** Load the client CSS */
|
||||
function loadCss() {
|
||||
var css = c('link').attr({
|
||||
rel: 'stylesheet',
|
||||
type: 'text/css',
|
||||
href: piwikRoot + 'plugins/Overlay/client/client.css'
|
||||
});
|
||||
$('head').append(css);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads jQuery, if it is not there yet.
|
||||
* The callback is triggered after jQuery is loaded.
|
||||
*/
|
||||
function loadJQuery(callback) {
|
||||
if (typeof jQuery != 'undefined') {
|
||||
$ = jQuery;
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
Piwik_Overlay_Client.loadScript('libs/jquery/jquery.js', function () {
|
||||
$ = jQuery;
|
||||
jQuery.noConflict();
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify Piwik of the current iframe location.
|
||||
* This way, we can display additional metrics on the side of the iframe.
|
||||
*/
|
||||
function notifyPiwikOfLocation() {
|
||||
// check whether the session has been opened in a new tab (instead of an iframe)
|
||||
if (window != window.top) {
|
||||
var iframe = c('iframe', false, {
|
||||
src: piwikRoot + 'index.php?module=Overlay&action=notifyParentIframe#' + window.location.href
|
||||
}).css({width: 0, height: 0, border: 0});
|
||||
|
||||
// in some cases, calling append right away doesn't work in IE8
|
||||
$(document).ready(function () {
|
||||
$('body').append(iframe);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a jqueryfied DOM element */
|
||||
function c(tagName, className, attributes) {
|
||||
var el = $(document.createElement(tagName));
|
||||
|
||||
if (className) {
|
||||
if (className.substring(0, 1) == '#') {
|
||||
var id = className.substring(1, className.length);
|
||||
id = 'PIS_' + id;
|
||||
el.attr('id', id);
|
||||
}
|
||||
else {
|
||||
className = 'PIS_' + className;
|
||||
el.addClass(className);
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes) {
|
||||
el.attr(attributes);
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
/** Special treatment for some internet explorers */
|
||||
var ieStatusBarEventsBound = false;
|
||||
|
||||
function handleIEStatusBar() {
|
||||
if (navigator.appVersion.indexOf("MSIE 7.") == -1
|
||||
&& navigator.appVersion.indexOf("MSIE 8.") == -1) {
|
||||
// this is not IE8 or lower
|
||||
return;
|
||||
}
|
||||
|
||||
// IE7/8 can't handle position:fixed so we need to do it by hand
|
||||
statusBar.css({
|
||||
position: 'absolute',
|
||||
right: 'auto',
|
||||
bottom: 'auto',
|
||||
left: 0,
|
||||
top: 0
|
||||
});
|
||||
|
||||
var position = function () {
|
||||
var scrollY = document.body.parentElement.scrollTop;
|
||||
var scrollX = document.body.parentElement.scrollLeft;
|
||||
statusBar.css({
|
||||
top: (scrollY + $(window).height() - statusBar.outerHeight()) + 'px',
|
||||
left: (scrollX + $(window).width() - statusBar.outerWidth()) + 'px'
|
||||
});
|
||||
};
|
||||
|
||||
position();
|
||||
|
||||
statusBar.css({width: 'auto'});
|
||||
if (statusBar.width() < 350) {
|
||||
statusBar.width(350);
|
||||
} else {
|
||||
statusBar.width(statusBar.width());
|
||||
}
|
||||
|
||||
if (!ieStatusBarEventsBound) {
|
||||
ieStatusBarEventsBound = true;
|
||||
$(window).resize(position);
|
||||
$(window).scroll(position);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
/** Initialize in-site analytics */
|
||||
initialize: function (pPiwikRoot, pIdSite, pPeriod, pDate) {
|
||||
piwikRoot = pPiwikRoot;
|
||||
idSite = pIdSite;
|
||||
period = pPeriod;
|
||||
date = pDate;
|
||||
|
||||
var load = this.loadScript;
|
||||
var loading = this.loadingNotification;
|
||||
|
||||
loadJQuery(function () {
|
||||
notifyPiwikOfLocation();
|
||||
loadCss();
|
||||
|
||||
// translations
|
||||
load('plugins/Overlay/client/translations.js', function () {
|
||||
Piwik_Overlay_Translations.initialize(function () {
|
||||
// following pages
|
||||
var finishPages = loading('Loading following pages');
|
||||
load('plugins/Overlay/client/followingpages.js', function () {
|
||||
Piwik_Overlay_FollowingPages.initialize(finishPages);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/** Create a jqueryfied DOM element */
|
||||
createElement: function (tagName, className, attributes) {
|
||||
return c(tagName, className, attributes);
|
||||
},
|
||||
|
||||
/** Load a script and wait for it to be loaded */
|
||||
loadScript: function (relativePath, callback) {
|
||||
var loaded = false;
|
||||
var onLoad = function () {
|
||||
if (!loaded) {
|
||||
loaded = true;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
|
||||
script.onreadystatechange = function () {
|
||||
if (this.readyState == 'loaded' || this.readyState == 'complete') {
|
||||
onLoad();
|
||||
}
|
||||
};
|
||||
script.onload = onLoad;
|
||||
|
||||
script.src = piwikRoot + relativePath + '?v=1';
|
||||
head.appendChild(script);
|
||||
},
|
||||
|
||||
/** Piwik Overlay API Request */
|
||||
api: function (method, callback, additionalParams) {
|
||||
var url = piwikRoot + 'index.php?module=API&method=Overlay.' + method
|
||||
+ '&idSite=' + idSite + '&period=' + period + '&date=' + date + '&format=JSON&filter_limit=-1';
|
||||
|
||||
if (additionalParams) {
|
||||
url += '&' + additionalParams;
|
||||
}
|
||||
|
||||
$.getJSON(url + "&jsoncallback=?", function (data) {
|
||||
if (typeof data.result != 'undefined' && data.result == 'error') {
|
||||
alert('Error: ' + data.message);
|
||||
}
|
||||
else {
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a notification
|
||||
* To hide the notification use the returned callback
|
||||
*/
|
||||
notification: function (message, addClass) {
|
||||
if (!statusBar) {
|
||||
statusBar = c('div', '#StatusBar').css('opacity', .8);
|
||||
$('body').prepend(statusBar);
|
||||
}
|
||||
|
||||
var item = c('div', 'Item').html(message);
|
||||
|
||||
if (addClass) {
|
||||
item.addClass('PIS_' + addClass);
|
||||
}
|
||||
|
||||
statusBar.show().append(item);
|
||||
|
||||
handleIEStatusBar();
|
||||
window.setTimeout(handleIEStatusBar, 100);
|
||||
|
||||
return function () {
|
||||
item.remove();
|
||||
if (statusBar.children().size() == 0) {
|
||||
statusBar.hide();
|
||||
} else {
|
||||
handleIEStatusBar();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/** Hide all notifications with a certain class */
|
||||
hideNotifications: function (className) {
|
||||
statusBar.find('.PIS_' + className).remove();
|
||||
if (statusBar.children().size() == 0) {
|
||||
statusBar.hide();
|
||||
} else {
|
||||
handleIEStatusBar();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a loading notification
|
||||
* To hide the notification use the returned callback
|
||||
*/
|
||||
loadingNotification: function (message) {
|
||||
return Piwik_Overlay_Client.notification(message, 'Loading');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
BIN
www/analytics/plugins/Overlay/client/close.png
Normal file
|
After Width: | Height: | Size: 655 B |
544
www/analytics/plugins/Overlay/client/followingpages.js
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
var Piwik_Overlay_FollowingPages = (function () {
|
||||
|
||||
/** jQuery */
|
||||
var $ = jQuery;
|
||||
|
||||
/** Info about the following pages */
|
||||
var followingPages = [];
|
||||
|
||||
/** List of excluded get parameters */
|
||||
var excludedParams = [];
|
||||
|
||||
/** Index of the links on the page */
|
||||
var linksOnPage = {};
|
||||
|
||||
/** Reference to create element function */
|
||||
var c;
|
||||
|
||||
/** Load the following pages */
|
||||
function load(callback) {
|
||||
// normalize current location
|
||||
var location = window.location.href;
|
||||
location = Piwik_Overlay_UrlNormalizer.normalize(location);
|
||||
location = (("https:" == document.location.protocol) ? 'https' : 'http') + '://' + location;
|
||||
|
||||
var excludedParamsLoaded = false;
|
||||
var followingPagesLoaded = false;
|
||||
|
||||
// load excluded params
|
||||
Piwik_Overlay_Client.api('getExcludedQueryParameters', function (data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (typeof data[i] == 'object') {
|
||||
data[i] = data[i][0];
|
||||
}
|
||||
}
|
||||
excludedParams = data;
|
||||
|
||||
excludedParamsLoaded = true;
|
||||
if (followingPagesLoaded) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
// load following pages
|
||||
Piwik_Overlay_Client.api('getFollowingPages', function (data) {
|
||||
followingPages = data;
|
||||
processFollowingPages();
|
||||
|
||||
followingPagesLoaded = true;
|
||||
if (excludedParamsLoaded) {
|
||||
callback();
|
||||
}
|
||||
}, 'url=' + encodeURIComponent(location));
|
||||
}
|
||||
|
||||
/** Normalize the URLs of following pages and aggregate some stats */
|
||||
function processFollowingPages() {
|
||||
var totalClicks = 0;
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
var page = followingPages[i];
|
||||
// though the following pages are returned without the prefix, downloads
|
||||
// and outlinks still have it.
|
||||
page.label = Piwik_Overlay_UrlNormalizer.removeUrlPrefix(page.label);
|
||||
totalClicks += followingPages[i].referrals;
|
||||
}
|
||||
for (i = 0; i < followingPages.length; i++) {
|
||||
followingPages[i].clickRate = followingPages[i].referrals / totalClicks * 100;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an index of links on the page.
|
||||
* This function is passed to $('a').each()
|
||||
*/
|
||||
var processLinkDelta = false;
|
||||
|
||||
function processLink() {
|
||||
var a = $(this);
|
||||
a[0].piwikDiscovered = true;
|
||||
|
||||
var href = a.attr('href');
|
||||
href = Piwik_Overlay_UrlNormalizer.normalize(href);
|
||||
|
||||
if (href) {
|
||||
if (typeof linksOnPage[href] == 'undefined') {
|
||||
linksOnPage[href] = [a];
|
||||
}
|
||||
else {
|
||||
linksOnPage[href].push(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (href && processLinkDelta !== false) {
|
||||
if (typeof processLinkDelta[href] == 'undefined') {
|
||||
processLinkDelta[href] = [a];
|
||||
}
|
||||
else {
|
||||
processLinkDelta[href].push(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var repositionTimeout = false;
|
||||
var resizeTimeout = false;
|
||||
|
||||
function build(callback) {
|
||||
// build an index of all links on the page
|
||||
$('a').each(processLink);
|
||||
|
||||
// add tags to known following pages
|
||||
createLinkTags(linksOnPage);
|
||||
|
||||
// position the tags
|
||||
positionLinkTags();
|
||||
|
||||
callback();
|
||||
|
||||
// check on a regular basis whether new links have appeared.
|
||||
// we use a timeout instead of an interval to make sure one call is done before
|
||||
// the next one is triggered
|
||||
var repositionAfterTimeout;
|
||||
repositionAfterTimeout = function () {
|
||||
repositionTimeout = window.setTimeout(function () {
|
||||
findNewLinks();
|
||||
positionLinkTags(repositionAfterTimeout);
|
||||
}, 1800);
|
||||
};
|
||||
repositionAfterTimeout();
|
||||
|
||||
// reposition link tags on window resize
|
||||
$(window).resize(function () {
|
||||
if (repositionTimeout) {
|
||||
window.clearTimeout(repositionTimeout);
|
||||
}
|
||||
if (resizeTimeout) {
|
||||
window.clearTimeout(resizeTimeout);
|
||||
}
|
||||
resizeTimeout = window.setTimeout(function () {
|
||||
positionLinkTags();
|
||||
repositionAfterTimeout();
|
||||
}, 70);
|
||||
});
|
||||
}
|
||||
|
||||
/** Create a batch of link tags */
|
||||
function createLinkTags(links) {
|
||||
var body = $('body');
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
var url = followingPages[i].label;
|
||||
if (typeof links[url] != 'undefined') {
|
||||
for (var j = 0; j < links[url].length; j++) {
|
||||
createLinkTag(links[url][j], url, followingPages[i], body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Create the link tag element */
|
||||
function createLinkTag(linkTag, linkUrl, data, body) {
|
||||
if (typeof linkTag[0].piwikTagElement != 'undefined' && linkTag[0].piwikTagElement !== null) {
|
||||
// this link tag already has a tag element. happens in rare cases.
|
||||
return;
|
||||
}
|
||||
|
||||
linkTag[0].piwikTagElement = true;
|
||||
|
||||
var rate = data.clickRate;
|
||||
if (rate < 10) {
|
||||
rate = Math.round(rate * 10) / 10;
|
||||
} else {
|
||||
rate = Math.round(rate);
|
||||
}
|
||||
|
||||
var span = c('span').html(rate + '%');
|
||||
var tagElement = c('div', 'LinkTag').append(span).hide();
|
||||
body.prepend(tagElement);
|
||||
|
||||
linkTag.add(tagElement).hover(function () {
|
||||
highlightLink(linkTag, linkUrl, data);
|
||||
}, function () {
|
||||
unHighlightLink(linkTag, linkUrl);
|
||||
});
|
||||
|
||||
// attach the tag element to the link element. we can't use .data() because jquery
|
||||
// would remove it when removing the link from the dom. but we still need to find
|
||||
// the tag element to remove it as well.
|
||||
linkTag[0].piwikTagElement = tagElement;
|
||||
}
|
||||
|
||||
/** Position the link tags next to the links */
|
||||
function positionLinkTags(callback) {
|
||||
var url, linkTag, tagElement, offset, top, left, isRight, hasOneChild, inlineChild;
|
||||
var tagWidth = 36, tagHeight = 21;
|
||||
var tagsToRemove = [];
|
||||
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
url = followingPages[i].label;
|
||||
if (typeof linksOnPage[url] != 'undefined') {
|
||||
for (var j = 0; j < linksOnPage[url].length; j++) {
|
||||
linkTag = linksOnPage[url][j];
|
||||
tagElement = linkTag[0].piwikTagElement;
|
||||
|
||||
if (linkTag.closest('html').length == 0 || !tagElement) {
|
||||
// the link has been removed from the dom
|
||||
if (tagElement) {
|
||||
tagElement.hide();
|
||||
}
|
||||
// mark for deletion. don't delete it now because we
|
||||
// are iterating of the array it's in. it will be deleted
|
||||
// below this for loop.
|
||||
tagsToRemove.push({
|
||||
index1: url,
|
||||
index2: j
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
hasOneChild = checkHasOneChild(linkTag);
|
||||
inlineChild = false;
|
||||
if (hasOneChild && linkTag.css('display') != 'block') {
|
||||
inlineChild = linkTag.children().eq(0);
|
||||
}
|
||||
|
||||
if (getVisibility(linkTag) == 'hidden' || (
|
||||
// in case of hasOneChild: jquery always returns linkTag.is(':visible')=false
|
||||
!linkTag.is(':visible') && !(hasOneChild && inlineChild && inlineChild.is(':visible'))
|
||||
)) {
|
||||
// link is not visible
|
||||
tagElement.hide();
|
||||
continue;
|
||||
}
|
||||
|
||||
tagElement.attr('class', 'PIS_LinkTag'); // reset class
|
||||
if (tagElement[0].piwikHighlighted) {
|
||||
tagElement.addClass('PIS_Highlighted');
|
||||
}
|
||||
|
||||
// see comment in highlightLink()
|
||||
if (hasOneChild && linkTag.find('> img').size() == 1) {
|
||||
offset = linkTag.find('> img').offset();
|
||||
if (offset.left == 0 && offset.top == 0) {
|
||||
offset = linkTag.offset();
|
||||
}
|
||||
} else if (inlineChild !== false) {
|
||||
offset = inlineChild.offset();
|
||||
} else {
|
||||
offset = linkTag.offset();
|
||||
}
|
||||
|
||||
top = offset.top - tagHeight + 6;
|
||||
left = offset.left - tagWidth + 10;
|
||||
|
||||
if (isRight = (left < 2)) {
|
||||
tagElement.addClass('PIS_Right');
|
||||
left = offset.left + linkTag.outerWidth() - 10;
|
||||
}
|
||||
|
||||
if (top < 2) {
|
||||
tagElement.addClass(isRight ? 'PIS_BottomRight' : 'PIS_Bottom');
|
||||
top = offset.top + linkTag.outerHeight() - 6;
|
||||
}
|
||||
|
||||
tagElement.css({
|
||||
top: top + 'px',
|
||||
left: left + 'px'
|
||||
}).show();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// walk tagsToRemove from back to front because it contains the indexes in ascending
|
||||
// order. removing something from the front will impact the indexes that come after-
|
||||
// wards. this can be avoided by starting in the back.
|
||||
for (var k = tagsToRemove.length - 1; k >= 0; k--) {
|
||||
var tagToRemove = tagsToRemove[k];
|
||||
linkTag = linksOnPage[tagToRemove.index1][tagToRemove.index2];
|
||||
// remove the tag element from the dom
|
||||
if (linkTag && linkTag[0] && linkTag[0].piwikTagElement) {
|
||||
tagElement = linkTag[0].piwikTagElement;
|
||||
if (tagElement[0].piwikHighlighted) {
|
||||
unHighlightLink(linkTag, tagToRemove.index1);
|
||||
}
|
||||
tagElement.remove();
|
||||
linkTag[0].piwikTagElement = null;
|
||||
}
|
||||
// remove the link from the index
|
||||
linksOnPage[tagToRemove.index1].splice(tagToRemove.index2, 1);
|
||||
if (linksOnPage[tagToRemove.index1].length == 0) {
|
||||
delete linksOnPage[tagToRemove.index1];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof callback == 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the visibility of an element */
|
||||
function getVisibility(el) {
|
||||
var visibility = el.css('visibility');
|
||||
if (visibility == 'inherit') {
|
||||
el = el.parent();
|
||||
if (el.size() > 0) {
|
||||
return getVisibility(el);
|
||||
}
|
||||
}
|
||||
return visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out whether a link has only one child. Using .children().size() == 1 doesn't work
|
||||
* because it doesn't take additional text nodes into account.
|
||||
*/
|
||||
function checkHasOneChild(linkTag) {
|
||||
var hasOneChild = (linkTag.children().size() == 1);
|
||||
if (hasOneChild) {
|
||||
// if the element contains one tag and some text, hasOneChild is set incorrectly
|
||||
var contents = linkTag.contents();
|
||||
if (contents.size() > 1) {
|
||||
// find non-empty text nodes
|
||||
contents = contents.filter(function () {
|
||||
return this.nodeType == 3 && // text node
|
||||
$.trim(this.data).length > 0; // contains more than whitespaces
|
||||
});
|
||||
if (contents.size() > 0) {
|
||||
hasOneChild = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasOneChild;
|
||||
}
|
||||
|
||||
/** Check whether new links have been added to the dom */
|
||||
function findNewLinks() {
|
||||
var newLinks = $('a').filter(function () {
|
||||
return typeof this.piwikDiscovered == 'undefined' || this.piwikDiscovered === null;
|
||||
});
|
||||
|
||||
if (newLinks.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
processLinkDelta = {};
|
||||
newLinks.each(processLink);
|
||||
createLinkTags(processLinkDelta);
|
||||
processLinkDelta = false;
|
||||
}
|
||||
|
||||
/** Dom elements used for drawing a box around the link */
|
||||
var highlightElements = [];
|
||||
|
||||
/** Highlight a link on hover */
|
||||
function highlightLink(linkTag, linkUrl, data) {
|
||||
if (highlightElements.length == 0) {
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxTop'));
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxRight'));
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxLeft'));
|
||||
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxText'));
|
||||
|
||||
var body = $('body');
|
||||
for (var i = 0; i < highlightElements.length; i++) {
|
||||
body.prepend(highlightElements[i].css({display: 'none'}));
|
||||
}
|
||||
}
|
||||
|
||||
var width = linkTag.outerWidth();
|
||||
|
||||
var offset, height;
|
||||
var hasOneChild = checkHasOneChild(linkTag);
|
||||
if (hasOneChild && linkTag.find('img').size() == 1) {
|
||||
// if the <a> tag contains only an <img>, the offset and height methods don't work properly.
|
||||
// as a result, the box around the image link would be wrong. we use the image to derive
|
||||
// the offset and height instead of the link to get correct values.
|
||||
var img = linkTag.find('img');
|
||||
offset = img.offset();
|
||||
height = img.outerHeight();
|
||||
}
|
||||
if (hasOneChild && linkTag.css('display') != 'block') {
|
||||
// if the <a> tag is not displayed as block and has only one child, using the child to
|
||||
// derive the offset and dimensions is more robust.
|
||||
var child = linkTag.children().eq(0);
|
||||
offset = child.offset();
|
||||
height = child.outerHeight();
|
||||
width = child.outerWidth();
|
||||
} else {
|
||||
offset = linkTag.offset();
|
||||
height = linkTag.outerHeight();
|
||||
}
|
||||
|
||||
var numLinks = linksOnPage[linkUrl].length;
|
||||
|
||||
putBoxAroundLink(offset, width, height, numLinks, data.referrals);
|
||||
|
||||
// highlight tags
|
||||
for (var j = 0; j < numLinks; j++) {
|
||||
var tag = linksOnPage[linkUrl][j][0].piwikTagElement;
|
||||
tag.addClass('PIS_Highlighted');
|
||||
tag[0].piwikHighlighted = true;
|
||||
}
|
||||
|
||||
// Sometimes it fails to remove the notification when the hovered element is removed.
|
||||
// To make sure we don't display more than one location at a time, we hide all before showing the new one.
|
||||
Piwik_Overlay_Client.hideNotifications('LinkLocation');
|
||||
|
||||
// we don't use .data() because jquery would remove the callback when the link tag is removed
|
||||
linkTag[0].piwikHideNotification = Piwik_Overlay_Client.notification(
|
||||
Piwik_Overlay_Translations.get('link') + ': ' + linkUrl, 'LinkLocation');
|
||||
}
|
||||
|
||||
function putBoxAroundLink(offset, width, height, numLinks, numReferrals) {
|
||||
var borderWidth = 2;
|
||||
var padding = 4; // the distance between the link and the border
|
||||
|
||||
// top border
|
||||
highlightElements[0]
|
||||
.width(width + 2 * padding)
|
||||
.css({
|
||||
top: offset.top - borderWidth - padding,
|
||||
left: offset.left - padding
|
||||
}).show();
|
||||
|
||||
// right border
|
||||
highlightElements[1]
|
||||
.height(height + 2 * borderWidth + 2 * padding)
|
||||
.css({
|
||||
top: offset.top - borderWidth - padding,
|
||||
left: offset.left + width + padding
|
||||
}).show();
|
||||
|
||||
// left border
|
||||
highlightElements[2]
|
||||
.height(height + 2 * borderWidth + 2 * padding)
|
||||
.css({
|
||||
top: offset.top - borderWidth - padding,
|
||||
left: offset.left - borderWidth - padding
|
||||
}).show();
|
||||
|
||||
// bottom box text
|
||||
var text;
|
||||
if (numLinks > 1) {
|
||||
text = Piwik_Overlay_Translations.get('clicksFromXLinks')
|
||||
.replace(/%1\$s/, numReferrals)
|
||||
.replace(/%2\$s/, numLinks);
|
||||
} else if (numReferrals == 1) {
|
||||
text = Piwik_Overlay_Translations.get('oneClick');
|
||||
} else {
|
||||
text = Piwik_Overlay_Translations.get('clicks')
|
||||
.replace(/%s/, numReferrals);
|
||||
}
|
||||
|
||||
// bottom box position and dimension
|
||||
var textPadding = ' ';
|
||||
highlightElements[3].html(textPadding + text + textPadding).css({
|
||||
width: 'auto',
|
||||
top: offset.top + height + padding,
|
||||
left: offset.left - borderWidth - padding
|
||||
}).show();
|
||||
|
||||
var minBoxWidth = width + 2 * borderWidth + 2 * padding;
|
||||
if (highlightElements[3].width() < minBoxWidth) {
|
||||
// we cannot use minWidth because of IE7
|
||||
highlightElements[3].width(minBoxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove highlight from link */
|
||||
function unHighlightLink(linkTag, linkUrl) {
|
||||
for (var i = 0; i < highlightElements.length; i++) {
|
||||
highlightElements[i].hide();
|
||||
}
|
||||
|
||||
var numLinks = linksOnPage[linkUrl].length;
|
||||
for (var j = 0; j < numLinks; j++) {
|
||||
var tag = linksOnPage[linkUrl][j][0].piwikTagElement;
|
||||
if (tag) {
|
||||
tag.removeClass('PIS_Highlighted');
|
||||
tag[0].piwikHighlighted = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((typeof linkTag[0].piwikHideNotification) == 'function') {
|
||||
linkTag[0].piwikHideNotification();
|
||||
linkTag[0].piwikHideNotification = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* The main method
|
||||
*/
|
||||
initialize: function (finishCallback) {
|
||||
c = Piwik_Overlay_Client.createElement;
|
||||
Piwik_Overlay_Client.loadScript('plugins/Overlay/client/urlnormalizer.js', function () {
|
||||
Piwik_Overlay_UrlNormalizer.initialize();
|
||||
load(function () {
|
||||
Piwik_Overlay_UrlNormalizer.setExcludedParameters(excludedParams);
|
||||
build(function () {
|
||||
finishCallback();
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the dom and terminate timeouts.
|
||||
* This can be used from the console in order to load a new implementation for debugging afterwards.
|
||||
* If you add `Piwik_Overlay_FollowingPages.remove();` to the beginning and
|
||||
* `Piwik_Overlay_FollowingPages.initialize(function(){});` to the end of this file, you can just
|
||||
* paste it into the console to inject the new implementation.
|
||||
*/
|
||||
remove: function () {
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
var url = followingPages[i].label;
|
||||
if (typeof linksOnPage[url] != 'undefined') {
|
||||
for (var j = 0; j < linksOnPage[url].length; j++) {
|
||||
var linkTag = linksOnPage[url][j];
|
||||
var tagElement = linkTag[0].piwikTagElement;
|
||||
if (tagElement) {
|
||||
tagElement.remove();
|
||||
}
|
||||
linkTag[0].piwikTagElement = null;
|
||||
|
||||
$(linkTag).unbind('mouseenter').unbind('mouseleave');
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < highlightElements.length; i++) {
|
||||
highlightElements[i].remove();
|
||||
}
|
||||
if (repositionTimeout) {
|
||||
window.clearTimeout(repositionTimeout);
|
||||
}
|
||||
if (resizeTimeout) {
|
||||
window.clearTimeout(resizeTimeout);
|
||||
}
|
||||
$(window).unbind('resize');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
5251
www/analytics/plugins/Overlay/client/linktags.eps
Normal file
BIN
www/analytics/plugins/Overlay/client/linktags.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
www/analytics/plugins/Overlay/client/linktags.psd
Normal file
BIN
www/analytics/plugins/Overlay/client/linktags_lessshadow.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
www/analytics/plugins/Overlay/client/linktags_noshadow.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
www/analytics/plugins/Overlay/client/loading.gif
Normal file
|
After Width: | Height: | Size: 723 B |
30
www/analytics/plugins/Overlay/client/translations.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
var Piwik_Overlay_Translations = (function () {
|
||||
|
||||
/** Translations strings */
|
||||
var translations = [];
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Initialize translations module.
|
||||
* Callback is triggered when data is available.
|
||||
*/
|
||||
initialize: function (callback) {
|
||||
// Load translation data
|
||||
Piwik_Overlay_Client.api('getTranslations', function (data) {
|
||||
translations = data[0];
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
/** Get translation string */
|
||||
get: function (identifier) {
|
||||
if (typeof translations[identifier] == 'undefined') {
|
||||
return identifier;
|
||||
}
|
||||
return translations[identifier];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
198
www/analytics/plugins/Overlay/client/urlnormalizer.js
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
* URL NORMALIZER
|
||||
* This utility preprocesses both the URLs in the document and
|
||||
* from the Piwik logs in order to make matching possible.
|
||||
*/
|
||||
var Piwik_Overlay_UrlNormalizer = (function () {
|
||||
|
||||
/** Base href of the current document */
|
||||
var baseHref = false;
|
||||
|
||||
/** Url of current folder */
|
||||
var currentFolder;
|
||||
|
||||
/** The current domain */
|
||||
var currentDomain;
|
||||
|
||||
/** Regular expressions for parameters to be excluded when matching links on the page */
|
||||
var excludedParamsRegEx = [];
|
||||
|
||||
/**
|
||||
* Basic normalizations for domain names
|
||||
* - remove protocol and www from absolute urls
|
||||
* - add a trailing slash to urls without a path
|
||||
*
|
||||
* Returns array
|
||||
* 0: normalized url
|
||||
* 1: true, if url was absolute (if not, no normalization was performed)
|
||||
*/
|
||||
function normalizeDomain(url) {
|
||||
if (url === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var absolute = false;
|
||||
|
||||
// remove protocol
|
||||
if (url.substring(0, 7) == 'http://') {
|
||||
absolute = true;
|
||||
url = url.substring(7, url.length);
|
||||
} else if (url.substring(0, 8) == 'https://') {
|
||||
absolute = true;
|
||||
url = url.substring(8, url.length);
|
||||
}
|
||||
|
||||
if (absolute) {
|
||||
// remove www.
|
||||
url = removeWww(url);
|
||||
|
||||
// add slash to domain names
|
||||
if (url.indexOf('/') == -1) {
|
||||
url += '/';
|
||||
}
|
||||
}
|
||||
|
||||
return [url, absolute];
|
||||
}
|
||||
|
||||
/** Remove www. from a domain */
|
||||
function removeWww(domain) {
|
||||
if (domain.substring(0, 4) == 'www.') {
|
||||
return domain.substring(4, domain.length);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
initialize: function () {
|
||||
this.setCurrentDomain(document.location.hostname);
|
||||
this.setCurrentUrl(window.location.href);
|
||||
|
||||
var head = document.getElementsByTagName('head');
|
||||
if (head.length) {
|
||||
var base = head[0].getElementsByTagName('base');
|
||||
if (base.length && base[0].href) {
|
||||
this.setBaseHref(base[0].href);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly set domain (for testing)
|
||||
*/
|
||||
setCurrentDomain: function (pCurrentDomain) {
|
||||
currentDomain = removeWww(pCurrentDomain);
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly set current url (for testing)
|
||||
*/
|
||||
setCurrentUrl: function (url) {
|
||||
var index = url.lastIndexOf('/');
|
||||
if (index != url.length - 1) {
|
||||
currentFolder = url.substring(0, index + 1);
|
||||
} else {
|
||||
currentFolder = url;
|
||||
}
|
||||
currentFolder = normalizeDomain(currentFolder)[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly set base href (for testing)
|
||||
*/
|
||||
setBaseHref: function (pBaseHref) {
|
||||
if (!pBaseHref) {
|
||||
baseHref = false;
|
||||
} else {
|
||||
baseHref = normalizeDomain(pBaseHref)[0];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the parameters to be excluded when matching links on the page
|
||||
*/
|
||||
setExcludedParameters: function (pExcludedParams) {
|
||||
excludedParamsRegEx = [];
|
||||
for (var i = 0; i < pExcludedParams.length; i++) {
|
||||
var paramString = pExcludedParams[i];
|
||||
excludedParamsRegEx.push(new RegExp('&' + paramString + '=([^&#]*)', 'ig'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the protocol and the prefix of a URL
|
||||
*/
|
||||
removeUrlPrefix: function (url) {
|
||||
return normalizeDomain(url)[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Normalize URL
|
||||
* Can be an absolute or a relative URL
|
||||
*/
|
||||
normalize: function (url) {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// ignore urls starting with #
|
||||
if (url.substring(0, 1) == '#') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// basic normalizations for absolute urls
|
||||
var normalized = normalizeDomain(url);
|
||||
url = normalized[0];
|
||||
|
||||
var absolute = normalized[1];
|
||||
|
||||
if (!absolute) {
|
||||
/** relative url */
|
||||
if (url.substring(0, 1) == '/') {
|
||||
// relative to domain root
|
||||
url = currentDomain + url;
|
||||
} else if (baseHref) {
|
||||
// relative to base href
|
||||
url = baseHref + url;
|
||||
} else {
|
||||
// relative to current folder
|
||||
url = currentFolder + url;
|
||||
}
|
||||
}
|
||||
|
||||
// replace multiple / with a single /
|
||||
url = url.replace(/\/\/+/g, '/');
|
||||
|
||||
// handle ./ and ../
|
||||
var parts = url.split('/');
|
||||
var urlArr = [];
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
if (parts[i] == '.') {
|
||||
// ignore
|
||||
}
|
||||
else if (parts[i] == '..') {
|
||||
urlArr.pop();
|
||||
}
|
||||
else {
|
||||
urlArr.push(parts[i]);
|
||||
}
|
||||
}
|
||||
url = urlArr.join('/');
|
||||
|
||||
// remove ignored parameters
|
||||
url = url.replace(/\?/, '?&');
|
||||
for (i = 0; i < excludedParamsRegEx.length; i++) {
|
||||
var regEx = excludedParamsRegEx[i];
|
||||
url = url.replace(regEx, '');
|
||||
}
|
||||
url = url.replace(/\?&/, '?');
|
||||
url = url.replace(/\?#/, '#');
|
||||
url = url.replace(/\?$/, '');
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
BIN
www/analytics/plugins/Overlay/images/info.png
Normal file
|
After Width: | Height: | Size: 778 B |
BIN
www/analytics/plugins/Overlay/images/overlay_icon.png
Executable file
|
After Width: | Height: | Size: 359 B |
BIN
www/analytics/plugins/Overlay/images/overlay_icon_hover.png
Executable file
|
After Width: | Height: | Size: 360 B |
31
www/analytics/plugins/Overlay/javascripts/Overlay_Helper.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
var Overlay_Helper = {
|
||||
|
||||
/** Encode the iframe url to put it behind the hash in sidebar mode */
|
||||
encodeFrameUrl: function (url) {
|
||||
// url encode + replace % with $ to make sure that browsers don't break the encoding
|
||||
return encodeURIComponent(url).replace(/%/g, '$')
|
||||
},
|
||||
|
||||
/** Decode the url after reading it from the hash */
|
||||
decodeFrameUrl: function (url) {
|
||||
// reverse encodeFrameUrl()
|
||||
return decodeURIComponent(url.replace(/\$/g, '%'));
|
||||
},
|
||||
|
||||
/** Get the url to launch overlay */
|
||||
getOverlayLink: function (idSite, period, date, link) {
|
||||
var url = 'index.php?module=Overlay&period=' + period + '&date=' + date + '&idSite=' + idSite;
|
||||
if (link) {
|
||||
url += '#l=' + Overlay_Helper.encodeFrameUrl(link);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
};
|
||||
252
www/analytics/plugins/Overlay/javascripts/Piwik_Overlay.js
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
var Piwik_Overlay = (function () {
|
||||
|
||||
var $body, $iframe, $sidebar, $main, $location, $loading, $errorNotLoading;
|
||||
var $rowEvolutionLink, $transitionsLink, $fullScreenLink;
|
||||
|
||||
var idSite, period, date;
|
||||
|
||||
var iframeSrcBase;
|
||||
var iframeDomain = '';
|
||||
var iframeCurrentPage = '';
|
||||
var iframeCurrentPageNormalized = '';
|
||||
var iframeCurrentActionLabel = '';
|
||||
var updateComesFromInsideFrame = false;
|
||||
|
||||
|
||||
/** Load the sidebar for a url */
|
||||
function loadSidebar(currentUrl) {
|
||||
showLoading();
|
||||
|
||||
$location.html(' ').unbind('mouseenter').unbind('mouseleave');
|
||||
|
||||
iframeCurrentPage = currentUrl;
|
||||
iframeDomain = currentUrl.match(/http(s)?:\/\/(www\.)?([^\/]*)/i)[3];
|
||||
|
||||
globalAjaxQueue.abort();
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Overlay',
|
||||
action: 'renderSidebar',
|
||||
currentUrl: currentUrl
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function (response) {
|
||||
hideLoading();
|
||||
|
||||
var $response = $(response);
|
||||
|
||||
var $responseLocation = $response.find('.Overlay_Location');
|
||||
var $url = $responseLocation.find('span');
|
||||
iframeCurrentPageNormalized = $url.data('normalizedUrl');
|
||||
iframeCurrentActionLabel = $url.data('label');
|
||||
$url.html(piwikHelper.addBreakpointsToUrl($url.text()));
|
||||
$location.html($responseLocation.html()).show();
|
||||
$responseLocation.remove();
|
||||
|
||||
var $locationSpan = $location.find('span');
|
||||
$locationSpan.html(piwikHelper.addBreakpointsToUrl($locationSpan.text()));
|
||||
if (iframeDomain) {
|
||||
// use addBreakpointsToUrl because it also encoded html entities
|
||||
$locationSpan.tooltip({
|
||||
track: true,
|
||||
items: '*',
|
||||
tooltipClass: 'Overlay_Tooltip',
|
||||
content: '<strong>' + Piwik_Overlay_Translations.domain + ':</strong> ' +
|
||||
piwikHelper.addBreakpointsToUrl(iframeDomain),
|
||||
show: false,
|
||||
hide: false
|
||||
});
|
||||
}
|
||||
|
||||
$sidebar.empty().append($response).show();
|
||||
|
||||
if ($sidebar.find('.Overlay_NoData').size() == 0) {
|
||||
$rowEvolutionLink.show();
|
||||
$transitionsLink.show()
|
||||
}
|
||||
}
|
||||
);
|
||||
ajaxRequest.setErrorCallback(function () {
|
||||
hideLoading();
|
||||
$errorNotLoading.show();
|
||||
});
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send(false);
|
||||
}
|
||||
|
||||
/** Adjust the dimensions of the iframe */
|
||||
function adjustDimensions() {
|
||||
$iframe.height($(window).height());
|
||||
$iframe.width($body.width() - $iframe.offset().left - 2); // -2 because of 2px border
|
||||
}
|
||||
|
||||
/** Display the loading message and hide other containers */
|
||||
function showLoading() {
|
||||
$loading.show();
|
||||
|
||||
$sidebar.hide();
|
||||
$location.hide();
|
||||
|
||||
$fullScreenLink.hide();
|
||||
$rowEvolutionLink.hide();
|
||||
$transitionsLink.hide();
|
||||
|
||||
$errorNotLoading.hide();
|
||||
}
|
||||
|
||||
/** Hide the loading message */
|
||||
function hideLoading() {
|
||||
$loading.hide();
|
||||
$fullScreenLink.show();
|
||||
}
|
||||
|
||||
/** $.history callback for hash change */
|
||||
function hashChangeCallback(urlHash) {
|
||||
var location = broadcast.getParamValue('l', urlHash);
|
||||
location = Overlay_Helper.decodeFrameUrl(location);
|
||||
|
||||
if (!updateComesFromInsideFrame) {
|
||||
var iframeUrl = iframeSrcBase;
|
||||
if (location) {
|
||||
iframeUrl += '#' + location;
|
||||
}
|
||||
$iframe.attr('src', iframeUrl);
|
||||
showLoading();
|
||||
} else {
|
||||
loadSidebar(location);
|
||||
}
|
||||
|
||||
updateComesFromInsideFrame = false;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
/** This method is called when Overlay loads */
|
||||
init: function (iframeSrc, pIdSite, pPeriod, pDate) {
|
||||
iframeSrcBase = iframeSrc;
|
||||
idSite = pIdSite;
|
||||
period = pPeriod;
|
||||
date = pDate;
|
||||
|
||||
$body = $('body');
|
||||
$iframe = $('#Overlay_Iframe');
|
||||
$sidebar = $('#Overlay_Sidebar');
|
||||
$location = $('#Overlay_Location');
|
||||
$main = $('#Overlay_Main');
|
||||
$loading = $('#Overlay_Loading');
|
||||
$errorNotLoading = $('#Overlay_Error_NotLoading');
|
||||
|
||||
$rowEvolutionLink = $('#Overlay_RowEvolution');
|
||||
$transitionsLink = $('#Overlay_Transitions');
|
||||
$fullScreenLink = $('#Overlay_FullScreen');
|
||||
|
||||
adjustDimensions();
|
||||
|
||||
showLoading();
|
||||
|
||||
// apply initial dimensions
|
||||
window.setTimeout(function () {
|
||||
adjustDimensions();
|
||||
}, 50);
|
||||
|
||||
// handle window resize
|
||||
// we manipulate broadcast.pageload because it unbinds all resize events on window
|
||||
var originalPageload = broadcast.pageload;
|
||||
broadcast.pageload = function (hash) {
|
||||
originalPageload(hash);
|
||||
$(window).resize(function () {
|
||||
adjustDimensions();
|
||||
});
|
||||
};
|
||||
$(window).resize(function () {
|
||||
adjustDimensions();
|
||||
});
|
||||
|
||||
// handle hash change
|
||||
broadcast.loadAjaxContent = hashChangeCallback;
|
||||
broadcast.init();
|
||||
|
||||
if (window.location.href.split('#').length == 1) {
|
||||
// if there's no hash, broadcast won't trigger the callback - we have to do it here
|
||||
hashChangeCallback('');
|
||||
}
|
||||
|
||||
// handle date selection
|
||||
var $select = $('select#Overlay_DateRangeSelect').change(function () {
|
||||
var parts = $(this).val().split(';');
|
||||
if (parts.length == 2) {
|
||||
period = parts[0];
|
||||
date = parts[1];
|
||||
window.location.href = Overlay_Helper.getOverlayLink(idSite, period, date, iframeCurrentPage);
|
||||
}
|
||||
});
|
||||
|
||||
var optionMatchFound = false;
|
||||
$select.find('option').each(function () {
|
||||
if ($(this).val() == period + ';' + date) {
|
||||
$(this).prop('selected', true);
|
||||
optionMatchFound = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!optionMatchFound) {
|
||||
$select.prepend('<option selected="selected">');
|
||||
}
|
||||
|
||||
// handle transitions link
|
||||
$transitionsLink.click(function () {
|
||||
DataTable_RowActions_Transitions.launchForUrl(iframeCurrentPageNormalized);
|
||||
return false;
|
||||
});
|
||||
|
||||
// handle row evolution link
|
||||
$rowEvolutionLink.click(function () {
|
||||
DataTable_RowActions_RowEvolution.launch('Actions.getPageUrls', iframeCurrentActionLabel);
|
||||
return false;
|
||||
});
|
||||
|
||||
// handle full screen link
|
||||
$fullScreenLink.click(function () {
|
||||
var href = iframeSrcBase;
|
||||
if (iframeCurrentPage) {
|
||||
href += '#' + iframeCurrentPage.replace(/#/g, '%23');
|
||||
}
|
||||
window.location.href = href;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
/** This callback is used from within the iframe */
|
||||
setCurrentUrl: function (currentUrl) {
|
||||
showLoading();
|
||||
|
||||
var locationParts = location.href.split('#');
|
||||
var currentLocation = '';
|
||||
if (locationParts.length > 1) {
|
||||
currentLocation = broadcast.getParamValue('l', locationParts[1]);
|
||||
}
|
||||
|
||||
var newLocation = Overlay_Helper.encodeFrameUrl(currentUrl);
|
||||
|
||||
if (newLocation != currentLocation) {
|
||||
updateComesFromInsideFrame = true;
|
||||
// put the current iframe url in the main url to enable refresh and deep linking.
|
||||
// use disableHistory=true to make sure that the back and forward buttons can be
|
||||
// used on the iframe (which in turn notifies the parent about the location change)
|
||||
broadcast.propagateAjax('l=' + newLocation, true);
|
||||
} else {
|
||||
// happens when the url is changed by hand or when the l parameter is there on page load
|
||||
loadSidebar(currentUrl);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
65
www/analytics/plugins/Overlay/javascripts/rowaction.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file registers the Overlay row action on the pages report.
|
||||
*/
|
||||
|
||||
function DataTable_RowActions_Overlay(dataTable) {
|
||||
this.dataTable = dataTable;
|
||||
}
|
||||
|
||||
DataTable_RowActions_Overlay.prototype = new DataTable_RowAction;
|
||||
|
||||
DataTable_RowActions_Overlay.prototype.onClick = function (actionA, tr, e) {
|
||||
if (!actionA.data('overlay-manipulated')) {
|
||||
actionA.data('overlay-manipulated', 1);
|
||||
|
||||
var link = tr.find('> td:first > a').attr('href');
|
||||
link = $('<textarea>').html(link).val(); // remove html entities
|
||||
|
||||
actionA.attr({
|
||||
target: '_blank',
|
||||
href: Overlay_Helper.getOverlayLink(this.dataTable.param.idSite, 'month', 'today', link)
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
DataTable_RowActions_Registry.register({
|
||||
|
||||
name: 'Overlay',
|
||||
|
||||
dataTableIcon: 'plugins/Overlay/images/overlay_icon.png',
|
||||
dataTableIconHover: 'plugins/Overlay/images/overlay_icon_hover.png',
|
||||
|
||||
order: 30,
|
||||
|
||||
dataTableIconTooltip: [
|
||||
_pk_translate('General_OverlayRowActionTooltipTitle'),
|
||||
_pk_translate('General_OverlayRowActionTooltip')
|
||||
],
|
||||
|
||||
createInstance: function (dataTable) {
|
||||
return new DataTable_RowActions_Overlay(dataTable);
|
||||
},
|
||||
|
||||
isAvailableOnReport: function (dataTableParams) {
|
||||
// Overlay plugin only works when Transitions plugin is enabled
|
||||
if (!window.DataTable_RowActions_Transitions) {
|
||||
return false;
|
||||
}
|
||||
return DataTable_RowActions_Transitions.isPageUrlReport(dataTableParams.module, dataTableParams.action);
|
||||
},
|
||||
|
||||
isAvailableOnRow: function (dataTableParams, tr) {
|
||||
var transitions = DataTable_RowActions_Registry.getActionByName('Transitions');
|
||||
return transitions.isAvailableOnRow(dataTableParams, tr);
|
||||
}
|
||||
|
||||
});
|
||||
159
www/analytics/plugins/Overlay/stylesheets/overlay.css
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/** hide scroll bar in ie7 */
|
||||
*overflow: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body #header {
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
body #logo {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
a#Overlay_Title {
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
color: #7e7363;
|
||||
text-decoration: none;
|
||||
margin: -3px 0 0 0;
|
||||
padding: 0 0 0 5px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
#Overlay_Title img {
|
||||
vertical-align: text-bottom;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
#Overlay_DateRangeSelection {
|
||||
padding: 30px 0 20px 23px;
|
||||
background: url(../../Zeitgeist/images/icon-calendar.gif) 2px 33px no-repeat;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#Overlay_Location {
|
||||
width: 200px;
|
||||
padding: 0 0 30px 0;
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#Overlay_Loading {
|
||||
background: url(../../Zeitgeist/images/loading-blue.gif) no-repeat center 10px;
|
||||
width: 190px;
|
||||
padding-top: 30px;
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#Overlay_Sidebar {
|
||||
width: 200px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#Overlay_Sidebar h2 {
|
||||
font-size: 15px;
|
||||
margin: 0;
|
||||
padding: 0 0 8px 23px;
|
||||
color: #255792;
|
||||
}
|
||||
|
||||
a#Overlay_FullScreen,
|
||||
a#Overlay_RowEvolution,
|
||||
a#Overlay_Transitions {
|
||||
display: block;
|
||||
color: #255792;
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
margin: 0 0 0 5px;
|
||||
padding: 8px 0 3px 25px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a#Overlay_RowEvolution {
|
||||
margin-top: 20px;
|
||||
background: url(../../Zeitgeist/images/row_evolution_hover.png) no-repeat 0 7px;
|
||||
}
|
||||
|
||||
a#Overlay_Transitions {
|
||||
background: url(../../Transitions/images/transitions_icon_hover.png) no-repeat 0 6px;
|
||||
}
|
||||
|
||||
a#Overlay_FullScreen {
|
||||
margin-top: 20px;
|
||||
background: url(../../Zeitgeist/images/fullscreen.png) no-repeat 3px 8px;
|
||||
}
|
||||
|
||||
a#Overlay_FullScreen:hover,
|
||||
a#Overlay_RowEvolution:hover,
|
||||
a#Overlay_Transitions:hover {
|
||||
color: #E87500;
|
||||
}
|
||||
|
||||
#Overlay_Main {
|
||||
margin-left: 220px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#Overlay_Iframe {
|
||||
border-left: 2px solid #ddd;
|
||||
}
|
||||
|
||||
.Overlay_Metric {
|
||||
font-size: 12px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.Overlay_MetricValue {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.Overlay_NoData {
|
||||
font-size: 12px;
|
||||
color: #7E7363;
|
||||
}
|
||||
|
||||
h2.Overlay_MainMetrics {
|
||||
background: url(../images/info.png) 0 1px no-repeat;
|
||||
}
|
||||
|
||||
body .ui-tooltip.Overlay_Tooltip {
|
||||
font-size: 11px;
|
||||
padding: 3px 5px 3px 6px;
|
||||
}
|
||||
|
||||
#Overlay_NoFrame {
|
||||
padding: 20px 0 40px 2px;
|
||||
}
|
||||
|
||||
#Overlay_Error_NotLoading {
|
||||
width: 190px;
|
||||
display: none;
|
||||
margin: 20px 0 0 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#Overlay_Error_NotLoading span {
|
||||
color: #E87500;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#topBars {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.overlay-sidebar-container {
|
||||
width: 220px;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
color: black;
|
||||
background: white;
|
||||
margin: 15px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #255792;
|
||||
}
|
||||
74
www/analytics/plugins/Overlay/templates/index.twig
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
{% extends 'dashboard.twig' %}
|
||||
|
||||
{% block head %}
|
||||
{{ parent() }}
|
||||
<script type="text/javascript" src="plugins/Overlay/javascripts/Piwik_Overlay.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="plugins/Overlay/stylesheets/overlay.css" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="overlay-sidebar-container">
|
||||
<a id="Overlay_Title" href="http://piwik.org/docs/page-overlay/" target="_blank">
|
||||
{{ 'Overlay_Overlay'|translate }}
|
||||
<img src="plugins/Zeitgeist/images/help.png" alt="Documentation"/>
|
||||
</a>
|
||||
|
||||
<div id="Overlay_DateRangeSelection">
|
||||
<select id="Overlay_DateRangeSelect" name="Overlay_DateRangeSelect">
|
||||
<option value="day;today">{{ 'General_Today'|translate }}</option>
|
||||
<option value="day;yesterday">{{ 'General_Yesterday'|translate }}</option>
|
||||
<option value="week;today">{{ 'General_CurrentWeek'|translate }}</option>
|
||||
<option value="month;today">{{ 'General_CurrentMonth'|translate }}</option>
|
||||
<option value="year;today">{{ 'General_CurrentYear'|translate }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="Overlay_Error_NotLoading">
|
||||
<p>
|
||||
<span>{{ 'Overlay_ErrorNotLoading'|translate }}</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{% if ssl %}
|
||||
{{ 'Overlay_ErrorNotLoadingDetailsSSL'|translate }}
|
||||
{% else %}
|
||||
{{ 'Overlay_ErrorNotLoadingDetails'|translate }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="http://piwik.org/docs/page-overlay/#toc-page-overlay-troubleshooting" target="_blank">
|
||||
{{ 'Overlay_ErrorNotLoadingLink'|translate }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="Overlay_Location"> </div>
|
||||
|
||||
<div id="Overlay_Loading">{{ 'General_Loading'|translate }}</div>
|
||||
|
||||
<div id="Overlay_Sidebar"></div>
|
||||
|
||||
<a id="Overlay_RowEvolution">{{ 'General_RowEvolutionRowActionTooltipTitle'|translate }}</a>
|
||||
<a id="Overlay_Transitions">{{ 'General_TransitionsRowActionTooltipTitle'|translate }}</a>
|
||||
</div>
|
||||
|
||||
<!-- TODO: rethink the way the sidebar works -->
|
||||
<!-- <a id="Overlay_FullScreen" href="#">
|
||||
{'Overlay_OpenFullScreen'|translate|escape:'html'}
|
||||
</a> -->
|
||||
|
||||
|
||||
<div id="Overlay_Main">
|
||||
<iframe id="Overlay_Iframe" src="" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var iframeSrc = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ date }}';
|
||||
Piwik_Overlay.init(iframeSrc, '{{ idSite }}', '{{ period }}', '{{ date }}');
|
||||
|
||||
Piwik_Overlay_Translations = {
|
||||
domain: "{{ 'Overlay_Domain'|translate }}"
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
21
www/analytics/plugins/Overlay/templates/index_noframe.twig
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{% extends 'dashboard.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ 'Overlay_Overlay'|translate }}</h1>
|
||||
|
||||
<div id="Overlay_NoFrame">
|
||||
|
||||
<script type="text/javascript">
|
||||
var newLocation = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ date }}';
|
||||
|
||||
var locationParts = window.location.href.split('#');
|
||||
if (locationParts.length > 1) {
|
||||
var url = broadcast.getParamValue('l', locationParts[1]);
|
||||
url = Overlay_Helper.decodeFrameUrl(url);
|
||||
newLocation += '#' + url;
|
||||
}
|
||||
window.location.href = newLocation;
|
||||
</script>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
// go up two iframes to find the piwik window
|
||||
var piwikWindow = window.parent.parent;
|
||||
// notify piwik of location change
|
||||
// the location has been passed as the hash part of the url from the overlay session
|
||||
piwikWindow.Piwik_Overlay.setCurrentUrl(window.location.hash.substring(1));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
22
www/analytics/plugins/Overlay/templates/renderSidebar.twig
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<div> <!-- Wrapper is needed that the html can be jqueryfied -->
|
||||
|
||||
<!-- This div is removed by JS and the content is put in the location div -->
|
||||
<div class="Overlay_Location">
|
||||
<strong>{{ 'Overlay_Location'|translate }}:</strong>
|
||||
<span data-normalized-url="{{ normalizedUrl }}" data-label="{{ label }}">
|
||||
{{ location }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if data|length > 0 %}
|
||||
<h2 class="Overlay_MainMetrics">{{ 'General_MainMetrics'|translate }}</h2>
|
||||
{% for metric in data %}
|
||||
<div class="Overlay_Metric">
|
||||
<span class="Overlay_MetricValue">{{ metric.value|raw }}</span> {{ metric.name }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<!-- note: the class Overlay_NoData is used in Piwik_Overlay.js -->
|
||||
<div class="Overlay_NoData">{{ 'Overlay_NoData'|translate }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<meta name="generator" content="Piwik - Open Source Web Analytics"/>
|
||||
<link rel="shortcut icon" href="plugins/CoreHome/images/favicon.ico"/>
|
||||
<link rel="stylesheet" type="text/css" href="plugins/Overlay/stylesheets/showErrorWrongDomain.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p><strong>{{ message|raw }}</strong></p>
|
||||
|
||||
<p>{{ troubleshoot|raw }}</p>
|
||||
</body>
|
||||
</html>
|
||||