update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit d885a4baa9
5833 changed files with 418860 additions and 226988 deletions

View file

@ -0,0 +1,86 @@
/*!
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
(function () {
angular.module('piwikApp').controller('QuickAccessController', QuickAccessController);
QuickAccessController.$inject = ['$scope', '$filter', 'siteSelectorModel'];
function QuickAccessController($scope, $filter, siteSelectorModel){
this.menuItems = [];
this.numMenuItems = 0;
this.sitesModel = siteSelectorModel;
this.onKeypress = function (event) {
var areSearchResultsDisplayed = $scope.search && $scope.search.term && $scope.view && $scope.view.searchActive;
var isTabKey = 9 == event.which
var isEscKey = 27 == event.which
if (38 == event.which) {
$scope.highlightPreviousItem();
event.preventDefault();
} else if (40 == event.which) {
$scope.highlightNextItem();
event.preventDefault();
} else if (13 == event.which) {
$scope.clickQuickAccessMenuItem();
} else if (isTabKey && areSearchResultsDisplayed) {
$scope.deactivateSearch();
} else if (isEscKey && areSearchResultsDisplayed) {
$scope.deactivateSearch();
}
};
this.searchMenu = function (searchTerm) {
searchTerm = searchTerm.toLowerCase();
var index = -1;
var menuItemsIndex = {};
var menuItems = [];
var moveToCategory = function (i, submenuItem) {
submenuItem = angular.copy(submenuItem); // force rerender of element to prevent weird side effects
submenuItem.menuIndex = ++index; // needed for proper highlighting with arrow keys
var category = submenuItem.category;
if (!(category in menuItemsIndex)) {
menuItems.push({title: category, items: []});
menuItemsIndex[category] = menuItems.length - 1;
}
var indexOfCategory = menuItemsIndex[category];
menuItems[indexOfCategory].items.push(submenuItem);
};
$scope.resetSearchIndex();
if ($scope.hasSitesSelector) {
this.sitesModel.searchSite(searchTerm);
}
var topMenuItems = $filter('filter')($scope.getTopMenuItems(), searchTerm);
var leftMenuItems = $filter('filter')($scope.getLeftMenuItems(), searchTerm);
var segmentItems = $filter('filter')($scope.getSegmentItems(), searchTerm);
$.each(topMenuItems, moveToCategory);
$.each(leftMenuItems, moveToCategory);
$.each(segmentItems, moveToCategory);
this.numMenuItems = topMenuItems.length + leftMenuItems.length + segmentItems.length;
this.menuItems = menuItems;
};
this.selectSite = function (idsite) {
this.sitesModel.loadSite(idsite);
};
this.selectMenuItem = function (index) {
$scope.selectMenuItem(index);
};
}
})();

View file

@ -0,0 +1,38 @@
<div class="quick-access"
ng-class="{active: view.searchActive, expanded: view.searchActive}"
piwik-focus-anywhere-but-here="view.searchActive = false;">
<span class="icon-search" ng-hide="search.term || view.searchActive"
ng-mouseenter="view.searchActive=true"></span>
<input class="s"
title="{{ quickAccessTitle }}"
ng-keydown="quickAccess.onKeypress($event)"
ng-change="view.searchActive=true;quickAccess.searchMenu(search.term)"
ng-focus="view.searchActive=true"
ng-model="search.term" piwik-focus-if="view.searchActive"
type="text" tabindex="2"/>
<ul ng-hide="!search.term || !view.searchActive || (quickAccess.numMenuItems > 0) || (quickAccess.sitesModel.sites | length)">
<li class="no-result">{{ 'General_SearchNoResults' | translate }}</li>
</ul>
<ul ng-show="search.term && view.searchActive" ng-repeat="subcategory in quickAccess.menuItems">
<li class="quick-access-category"
ng-click="search.term = subcategory.title;quickAccess.searchMenu(search.term)">{{ subcategory.title }}</li>
<li class="result"
ng-class="{selected: submenuEntry.menuIndex == search.index}"
ng-mouseenter="search.index=submenuEntry.menuIndex"
ng-click="quickAccess.selectMenuItem(submenuEntry.index)"
ng-repeat="submenuEntry in subcategory.items"><a>{{ submenuEntry.name | trim }}</a></li>
</ul>
<ul ng-show="search.term && view.searchActive">
<li class="quick-access-category websiteCategory"
ng-show="hasSitesSelector && ((quickAccess.sitesModel.sites | length) || quickAccess.sitesModel.isLoading)"
>{{ 'SitesManager_Sites' | translate }}</li>
<li class="no-result"
ng-show="hasSitesSelector && quickAccess.sitesModel.isLoading">{{ 'MultiSites_LoadingWebsites' | translate }}</li>
<li class="result"
ng-show="hasSitesSelector && !quickAccess.sitesModel.isLoading"
ng-mouseenter="search.index=(quickAccess.numMenuItems + $index)"
ng-class="{selected: (quickAccess.numMenuItems + $index) == search.index}"
ng-click="quickAccess.selectSite(site.idsite)"
ng-repeat="site in quickAccess.sitesModel.sites"><a ng-bind-html="site.name"></a></li>
</ul>
</div>

View file

@ -0,0 +1,282 @@
/*!
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
/**
* Usage:
* <div piwik-dialog="showDialog">...</div>
* Will show dialog once showDialog evaluates to true.
*
* Will execute the "executeMyFunction" function in the current scope once the yes button is pressed.
*/
(function () {
angular.module('piwikApp').directive('piwikQuickAccess', QuickAccessDirective);
QuickAccessDirective.$inject = ['$rootElement', '$timeout', 'piwik', '$filter'];
function QuickAccessDirective ($rootElement, $timeout, piwik, $filter) {
return {
restrict: 'A',
replace: true,
scope: {},
templateUrl: 'plugins/CoreHome/angularjs/quick-access/quick-access.directive.html?cb=' + piwik.cacheBuster,
controller: 'QuickAccessController',
controllerAs: 'quickAccess',
link: function (scope, element, attrs) {
var menuIndex = -1; // the menu index is used to identify which element to click
var topMenuItems = []; // cache for top menu items
var leftMenuItems = []; // cache for left menu items
var segmentItems = []; // cache for segment items
var hasSegmentSelector = angular.element('.segmentEditorPanel').length;
scope.hasSitesSelector = angular.element('.top_controls [piwik-siteselector]').length;
var translate = $filter('translate');
var searchAreasTitle = '';
var searchAreas = [translate('CoreHome_MenuEntries')]
if (hasSegmentSelector) {
searchAreas.push(translate('CoreHome_Segments'))
}
if (scope.hasSitesSelector) {
searchAreas.push(translate('SitesManager_Sites'))
}
while (searchAreas.length) {
searchAreasTitle += searchAreas.shift();
if (searchAreas.length >= 2) {
searchAreasTitle += ', ';
} else if (searchAreas.length === 1) {
searchAreasTitle += ' ' + translate('General_And') + ' ';
}
}
scope.quickAccessTitle = translate('CoreHome_QuickAccessTitle', searchAreasTitle);
function trim(str) {
return str.replace(/^\s+|\s+$/g,'');
}
scope.getTopMenuItems = function()
{
if (topMenuItems && topMenuItems.length) {
return topMenuItems;
}
var category = _pk_translate('CoreHome_Menu');
$rootElement.find('#topRightBar .navbar-right li > a').each(function (index, element) {
var $element = $(element);
if ($element.is('#topmenu-usersmanager')) {
// ignore languages manager
return;
}
var text = trim($element.text());
if (!text) {
text = trim($element.attr('title')); // possibly a icon, use title instead
}
if (text) {
topMenuItems.push({name: text, index: ++menuIndex, category: category});
$element.attr('quick_access', menuIndex);
}
});
return topMenuItems;
};
scope.getLeftMenuItems = function ()
{
if (leftMenuItems && leftMenuItems.length) {
return leftMenuItems;
}
$rootElement.find('#secondNavBar .menuTab').each(function (index, element) {
var $element = angular.element(element);
var category = trim($element.find('> .item').text());
if (category && -1 !== category.lastIndexOf("\n")) {
// remove "\n\nMenu"
category = trim(category.substr(0, category.lastIndexOf("\n")));
}
$element.find('li .item').each(function (i, element) {
var $element = angular.element(element);
var text = trim($element.text());
if (text) {
leftMenuItems.push({name: text, category: category, index: ++menuIndex});
$element.attr('quick_access', menuIndex);
}
})
});
return leftMenuItems;
};
scope.getSegmentItems = function()
{
if (!hasSegmentSelector) {
return [];
}
if (segmentItems && segmentItems.length) {
return segmentItems;
}
var category = _pk_translate('CoreHome_Segments');
$rootElement.find('.segmentList [data-idsegment]').each(function (index, element) {
var $element = angular.element(element);
var text = trim($element.find('.segname').text());
if (text) {
segmentItems.push({name: text, category: category, index: ++menuIndex});
$element.attr('quick_access', menuIndex);
}
});
return segmentItems;
};
scope.activateSearch = function()
{
scope.$eval('view.searchActive = true');
$timeout(function () {
scope.$apply();
}, 0);
};
scope.deactivateSearch = function()
{
scope.$eval('search.term = ""');
scope.$eval('view.searchActive = false');
element.find('input').blur();
$timeout(function () {
scope.$apply();
}, 0);
};
function isElementInViewport(element) {
var rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= $(window).height() &&
rect.right <= $(window).width()
);
}
function getCurrentlySelectedElement(index)
{
var results = element.find('li.result');
if (results && results.length && results[scope.search.index]) {
return $(results[scope.search.index]);
}
}
function makeSureSelectedItemIsInViewport() {
var element = getCurrentlySelectedElement();
if (element && element[0] && !isElementInViewport(element[0])) {
scrollFirstElementIntoView(element);
}
}
function scrollFirstElementIntoView(element)
{
if (element && element[0] && element[0].scrollIntoView) {
// make sure search is visible
element[0].scrollIntoView();
}
}
scope.highlightPreviousItem = function()
{
if (0 >= (scope.search.index - 1)) {
scope.search.index = 0;
} else {
scope.search.index--;
}
makeSureSelectedItemIsInViewport();
};
scope.resetSearchIndex = function () {
scope.search.index = 0;
makeSureSelectedItemIsInViewport();
};
scope.highlightNextItem = function()
{
var numTotal = element.find('li.result').length;
if (numTotal <= (scope.search.index + 1)) {
scope.search.index = numTotal - 1;
} else {
scope.search.index++;
}
makeSureSelectedItemIsInViewport();
};
scope.clickQuickAccessMenuItem = function()
{
var selectedMenuElement = getCurrentlySelectedElement();
if (selectedMenuElement) {
$timeout(function () {
selectedMenuElement.click();
}, 20);
}
};
scope.selectMenuItem = function(index)
{
var target = $rootElement.find('[quick_access=' + index + ']');
if (target && target.length && target[0]) {
scope.deactivateSearch();
var actualTarget = target[0];
var href = $(actualTarget).attr('href');
if (href && href.length > 10 && actualTarget && actualTarget.click) {
try {
actualTarget.click();
} catch (e) {
$(actualTarget).click();
}
} else {
$(actualTarget).click();
}
}
};
Mousetrap.bind('f', function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false; // IE
}
scrollFirstElementIntoView(element);
scope.activateSearch();
});
}
};
}
})();

View file

@ -0,0 +1,55 @@
.quick-access {
position: relative;
li {
font-size: 11px;
}
li a {
padding: 10px 19px;
display: inline-block;
text-decoration: none;
word-break: break-all;
}
.icon-search {
position: absolute;
font-size: 14px;
top: 10px;
left: 10px;
}
input {
width:100%;
height: 100%;
border: 0 !important;
box-shadow: 0 0 !important;
border-radius: 0 !important;
font-size: 11px;
&:focus {
outline: none;
}
}
.selected {
background-color: @theme-color-background-tinyContrast !important;
}
.quick-access-category {
text-align: left !important;
font-size: 11px;
padding: 5px 5px 5px 10px;
cursor: pointer;
}
.result {
cursor: pointer;
}
.quick-access-category:hover {
background: none !important;
}
.no-result {
padding: 10px 19px;
cursor: default;
}
.websiteCategory {
cursor: default;
}
}