add icons for Character groups
This commit is contained in:
commit
2d9a41a5fe
3461 changed files with 594457 additions and 0 deletions
147
www/analytics/plugins/Dashboard/API.php
Normal file
147
www/analytics/plugins/Dashboard/API.php
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<?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\Dashboard;
|
||||
|
||||
use Piwik\Piwik;
|
||||
use Piwik\WidgetsList;
|
||||
|
||||
/**
|
||||
* This API is the <a href='http://piwik.org/docs/analytics-api/reference/' target='_blank'>Dashboard API</a>: it gives information about dashboards.
|
||||
*
|
||||
* @method static \Piwik\Plugins\Dashboard\API getInstance()
|
||||
*/
|
||||
class API extends \Piwik\Plugin\API
|
||||
{
|
||||
private $dashboard = null;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->dashboard = new Dashboard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get each dashboard that belongs to a user including the containing widgets that are placed within each dashboard.
|
||||
* If the user has not created any dashboard yet, the default dashboard will be returned.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function getDashboards()
|
||||
{
|
||||
$dashboards = $this->getUserDashboards();
|
||||
|
||||
if (empty($dashboards)) {
|
||||
$dashboards = array($this->getDefaultDashboard());
|
||||
}
|
||||
|
||||
return $dashboards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default dashboard.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
private function getDefaultDashboard()
|
||||
{
|
||||
$defaultLayout = $this->dashboard->getDefaultLayout();
|
||||
$defaultLayout = $this->dashboard->decodeLayout($defaultLayout);
|
||||
|
||||
$defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout);
|
||||
|
||||
$widgets = $this->getExistingWidgetsWithinDashboard($defaultDashboard);
|
||||
|
||||
return $this->buildDashboard($defaultDashboard, $widgets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dashboards which a user has created.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
private function getUserDashboards()
|
||||
{
|
||||
$userLogin = Piwik::getCurrentUserLogin();
|
||||
$userDashboards = $this->dashboard->getAllDashboards($userLogin);
|
||||
|
||||
$dashboards = array();
|
||||
|
||||
foreach ($userDashboards as $userDashboard) {
|
||||
|
||||
if ($this->hasDashboardColumns($userDashboard)) {
|
||||
$widgets = $this->getExistingWidgetsWithinDashboard($userDashboard);
|
||||
$dashboards[] = $this->buildDashboard($userDashboard, $widgets);
|
||||
}
|
||||
}
|
||||
|
||||
return $dashboards;
|
||||
}
|
||||
|
||||
private function getExistingWidgetsWithinDashboard($dashboard)
|
||||
{
|
||||
$columns = $this->getColumnsFromDashboard($dashboard);
|
||||
|
||||
$widgets = array();
|
||||
$columns = array_filter($columns);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
foreach ($column as $widget) {
|
||||
|
||||
if ($this->widgetIsNotHidden($widget) && $this->widgetExists($widget)) {
|
||||
$module = $widget->parameters->module;
|
||||
$action = $widget->parameters->action;
|
||||
|
||||
$widgets[] = array('module' => $module, 'action' => $action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $widgets;
|
||||
}
|
||||
|
||||
private function getColumnsFromDashboard($dashboard)
|
||||
{
|
||||
if (is_array($dashboard['layout'])) {
|
||||
|
||||
return $dashboard['layout'];
|
||||
}
|
||||
|
||||
return $dashboard['layout']->columns;
|
||||
}
|
||||
|
||||
private function hasDashboardColumns($dashboard)
|
||||
{
|
||||
if (is_array($dashboard['layout'])) {
|
||||
|
||||
return !empty($dashboard['layout']);
|
||||
}
|
||||
|
||||
return !empty($dashboard['layout']->columns);
|
||||
}
|
||||
|
||||
private function buildDashboard($dashboard, $widgets)
|
||||
{
|
||||
return array('name' => $dashboard['name'], 'widgets' => $widgets);
|
||||
}
|
||||
|
||||
private function widgetExists($widget)
|
||||
{
|
||||
if (empty($widget->parameters)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$module = $widget->parameters->module;
|
||||
$action = $widget->parameters->action;
|
||||
|
||||
return WidgetsList::isDefined($module, $action);
|
||||
}
|
||||
|
||||
private function widgetIsNotHidden($widget)
|
||||
{
|
||||
return empty($widget->isHidden);
|
||||
}
|
||||
}
|
||||
345
www/analytics/plugins/Dashboard/Controller.php
Normal file
345
www/analytics/plugins/Dashboard/Controller.php
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
<?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\Dashboard;
|
||||
|
||||
use Piwik\Common;
|
||||
use Piwik\DataTable\Renderer\Json;
|
||||
use Piwik\Db;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Session\SessionNamespace;
|
||||
use Piwik\View;
|
||||
use Piwik\WidgetsList;
|
||||
|
||||
/**
|
||||
* Dashboard Controller
|
||||
*
|
||||
*/
|
||||
class Controller extends \Piwik\Plugin\Controller
|
||||
{
|
||||
/**
|
||||
* @var Dashboard
|
||||
*/
|
||||
private $dashboard;
|
||||
|
||||
protected function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->dashboard = new Dashboard();
|
||||
}
|
||||
|
||||
protected function _getDashboardView($template)
|
||||
{
|
||||
$view = new View($template);
|
||||
$this->setGeneralVariablesView($view);
|
||||
|
||||
$view->availableWidgets = Common::json_encode(WidgetsList::get());
|
||||
$view->availableLayouts = $this->getAvailableLayouts();
|
||||
|
||||
$view->dashboardId = Common::getRequestVar('idDashboard', 1, 'int');
|
||||
$view->dashboardLayout = $this->getLayout($view->dashboardId);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
public function embeddedIndex()
|
||||
{
|
||||
$view = $this->_getDashboardView('@Dashboard/embeddedIndex');
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$view = $this->_getDashboardView('@Dashboard/index');
|
||||
$view->dashboardSettingsControl = new DashboardManagerControl();
|
||||
$view->dashboards = array();
|
||||
if (!Piwik::isUserIsAnonymous()) {
|
||||
$login = Piwik::getCurrentUserLogin();
|
||||
|
||||
$view->dashboards = $this->dashboard->getAllDashboards($login);
|
||||
}
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function getDashboardSettingsControl()
|
||||
{
|
||||
$view = new DashboardManagerControl();
|
||||
$result = $view->render();
|
||||
|
||||
if (Common::getRequestVar('includeWidgetFactory', false)) {
|
||||
$factoryTemplateView = new View("@Dashboard/_widgetFactoryTemplate");
|
||||
$result .= $factoryTemplateView->render();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getAvailableWidgets()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
Json::sendHeaderJSON();
|
||||
return Common::json_encode(WidgetsList::get());
|
||||
}
|
||||
|
||||
public function getDashboardLayout()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
$idDashboard = Common::getRequestVar('idDashboard', 1, 'int');
|
||||
|
||||
$layout = $this->getLayout($idDashboard);
|
||||
|
||||
return $layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the dashboard to the default widget configuration
|
||||
*/
|
||||
public function resetLayout()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
$layout = $this->dashboard->getDefaultLayout();
|
||||
$idDashboard = Common::getRequestVar('idDashboard', 1, 'int');
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
$session = new SessionNamespace("Dashboard");
|
||||
$session->dashboardLayout = $layout;
|
||||
$session->setExpirationSeconds(1800);
|
||||
} else {
|
||||
$this->saveLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard, $layout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the layout in the DB for the given user.
|
||||
*
|
||||
* @param string $login
|
||||
* @param int $idDashboard
|
||||
* @param string $layout
|
||||
*/
|
||||
protected function saveLayoutForUser($login, $idDashboard, $layout)
|
||||
{
|
||||
$paramsBind = array($login, $idDashboard, $layout, $layout);
|
||||
$query = sprintf('INSERT INTO %s (login, iddashboard, layout) VALUES (?,?,?) ON DUPLICATE KEY UPDATE layout=?',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
Db::query($query, $paramsBind);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the name of a dashboard
|
||||
*
|
||||
* @param string $login
|
||||
* @param int $idDashboard
|
||||
* @param string $name
|
||||
*/
|
||||
protected function updateDashboardName($login, $idDashboard, $name)
|
||||
{
|
||||
$paramsBind = array($name, $login, $idDashboard);
|
||||
$query = sprintf('UPDATE %s SET name = ? WHERE login = ? AND iddashboard = ?',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
Db::query($query, $paramsBind);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the dashboard with the given id
|
||||
*/
|
||||
public function removeDashboard()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$idDashboard = Common::getRequestVar('idDashboard', 1, 'int');
|
||||
|
||||
// first layout can't be removed
|
||||
if ($idDashboard != 1) {
|
||||
$query = sprintf('DELETE FROM %s WHERE iddashboard = ? AND login = ?',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
Db::query($query, array($idDashboard, Piwik::getCurrentUserLogin()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs all available dashboards for the current user as a JSON string
|
||||
*/
|
||||
public function getAllDashboards()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
Json::sendHeaderJSON();
|
||||
return '[]';
|
||||
}
|
||||
|
||||
$login = Piwik::getCurrentUserLogin();
|
||||
$dashboards = $this->dashboard->getAllDashboards($login);
|
||||
|
||||
Json::sendHeaderJSON();
|
||||
return Common::json_encode($dashboards);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dashboard for the current user
|
||||
* User needs to be logged in
|
||||
*/
|
||||
public function createNewDashboard()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
return '0';
|
||||
}
|
||||
$user = Piwik::getCurrentUserLogin();
|
||||
$nextId = $this->getNextIdDashboard($user);
|
||||
|
||||
$name = urldecode(Common::getRequestVar('name', '', 'string'));
|
||||
$type = urldecode(Common::getRequestVar('type', 'default', 'string'));
|
||||
$layout = '{}';
|
||||
|
||||
if ($type == 'default') {
|
||||
$layout = $this->dashboard->getDefaultLayout();
|
||||
}
|
||||
|
||||
$query = sprintf('INSERT INTO %s (login, iddashboard, name, layout) VALUES (?, ?, ?, ?)',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
Db::query($query, array($user, $nextId, $name, $layout));
|
||||
|
||||
Json::sendHeaderJSON();
|
||||
return Common::json_encode($nextId);
|
||||
}
|
||||
|
||||
private function getNextIdDashboard($login)
|
||||
{
|
||||
$nextIdQuery = sprintf('SELECT MAX(iddashboard)+1 FROM %s WHERE login = ?',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
$nextId = Db::fetchOne($nextIdQuery, array($login));
|
||||
|
||||
if (empty($nextId)) {
|
||||
$nextId = 1;
|
||||
return $nextId;
|
||||
}
|
||||
return $nextId;
|
||||
}
|
||||
|
||||
public function copyDashboardToUser()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
if (!Piwik::hasUserSuperUserAccess()) {
|
||||
return '0';
|
||||
}
|
||||
$login = Piwik::getCurrentUserLogin();
|
||||
$name = urldecode(Common::getRequestVar('name', '', 'string'));
|
||||
$user = urldecode(Common::getRequestVar('user', '', 'string'));
|
||||
$idDashboard = Common::getRequestVar('dashboardId', 0, 'int');
|
||||
$layout = $this->dashboard->getLayoutForUser($login, $idDashboard);
|
||||
|
||||
if ($layout !== false) {
|
||||
$nextId = $this->getNextIdDashboard($user);
|
||||
|
||||
$query = sprintf('INSERT INTO %s (login, iddashboard, name, layout) VALUES (?, ?, ?, ?)',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
Db::query($query, array($user, $nextId, $name, $layout));
|
||||
|
||||
Json::sendHeaderJSON();
|
||||
return Common::json_encode($nextId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the layout for the current user
|
||||
* anonymous = in the session
|
||||
* authenticated user = in the DB
|
||||
*/
|
||||
public function saveLayout()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
$layout = Common::unsanitizeInputValue(Common::getRequestVar('layout'));
|
||||
$idDashboard = Common::getRequestVar('idDashboard', 1, 'int');
|
||||
$name = Common::getRequestVar('name', '', 'string');
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
$session = new SessionNamespace("Dashboard");
|
||||
$session->dashboardLayout = $layout;
|
||||
$session->setExpirationSeconds(1800);
|
||||
} else {
|
||||
$this->saveLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard, $layout);
|
||||
if (!empty($name)) {
|
||||
$this->updateDashboardName(Piwik::getCurrentUserLogin(), $idDashboard, $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the layout as default
|
||||
*/
|
||||
public function saveLayoutAsDefault()
|
||||
{
|
||||
$this->checkTokenInUrl();
|
||||
|
||||
if (Piwik::hasUserSuperUserAccess()) {
|
||||
$layout = Common::unsanitizeInputValue(Common::getRequestVar('layout'));
|
||||
$paramsBind = array('', '1', $layout, $layout);
|
||||
$query = sprintf('INSERT INTO %s (login, iddashboard, layout) VALUES (?,?,?) ON DUPLICATE KEY UPDATE layout=?',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
Db::query($query, $paramsBind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dashboard layout for the current user (anonymous or logged user)
|
||||
*
|
||||
* @param int $idDashboard
|
||||
*
|
||||
* @return string $layout
|
||||
*/
|
||||
protected function getLayout($idDashboard)
|
||||
{
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
|
||||
$session = new SessionNamespace("Dashboard");
|
||||
if (!isset($session->dashboardLayout)) {
|
||||
|
||||
return $this->dashboard->getDefaultLayout();
|
||||
}
|
||||
|
||||
$layout = $session->dashboardLayout;
|
||||
} else {
|
||||
$layout = $this->dashboard->getLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard);
|
||||
}
|
||||
|
||||
if (!empty($layout)) {
|
||||
$layout = $this->dashboard->removeDisabledPluginFromLayout($layout);
|
||||
}
|
||||
|
||||
if (empty($layout)) {
|
||||
$layout = $this->dashboard->getDefaultLayout();
|
||||
}
|
||||
|
||||
return $layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available column layouts for the dashboard
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAvailableLayouts()
|
||||
{
|
||||
return array(
|
||||
array(100),
|
||||
array(50, 50), array(67, 33), array(33, 67),
|
||||
array(33, 33, 33), array(40, 30, 30), array(30, 40, 30), array(30, 30, 40),
|
||||
array(25, 25, 25, 25)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
278
www/analytics/plugins/Dashboard/Dashboard.php
Normal file
278
www/analytics/plugins/Dashboard/Dashboard.php
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
<?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\Dashboard;
|
||||
|
||||
use Exception;
|
||||
use Piwik\Common;
|
||||
use Piwik\Db;
|
||||
use Piwik\DbHelper;
|
||||
use Piwik\Menu\MenuMain;
|
||||
use Piwik\Menu\MenuTop;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Site;
|
||||
use Piwik\WidgetsList;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Dashboard extends \Piwik\Plugin
|
||||
{
|
||||
/**
|
||||
* @see Piwik\Plugin::getListHooksRegistered
|
||||
*/
|
||||
public function getListHooksRegistered()
|
||||
{
|
||||
return array(
|
||||
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
|
||||
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
|
||||
'UsersManager.deleteUser' => 'deleteDashboardLayout',
|
||||
'Menu.Reporting.addItems' => 'addMenus',
|
||||
'Menu.Top.addItems' => 'addTopMenu',
|
||||
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the layout in the DB for the given user, or false if the layout has not been set yet.
|
||||
* Parameters must be checked BEFORE this function call
|
||||
*
|
||||
* @param string $login
|
||||
* @param int $idDashboard
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function getLayoutForUser($login, $idDashboard)
|
||||
{
|
||||
$paramsBind = array($login, $idDashboard);
|
||||
$query = sprintf('SELECT layout FROM %s WHERE login = ? AND iddashboard = ?',
|
||||
Common::prefixTable('user_dashboard'));
|
||||
$return = Db::fetchAll($query, $paramsBind);
|
||||
|
||||
if (count($return) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $return[0]['layout'];
|
||||
}
|
||||
|
||||
public function getDefaultLayout()
|
||||
{
|
||||
$defaultLayout = $this->getLayoutForUser('', 1);
|
||||
|
||||
if (empty($defaultLayout)) {
|
||||
if (Piwik::hasUserSuperUserAccess()) {
|
||||
$topWidget = '{"uniqueId":"widgetCoreHomegetDonateForm",'
|
||||
. '"parameters":{"module":"CoreHome","action":"getDonateForm"}},';
|
||||
} else {
|
||||
$topWidget = '{"uniqueId":"widgetCoreHomegetPromoVideo",'
|
||||
. '"parameters":{"module":"CoreHome","action":"getPromoVideo"}},';
|
||||
}
|
||||
|
||||
$defaultLayout = '[
|
||||
[
|
||||
{"uniqueId":"widgetVisitsSummarygetEvolutionGraphcolumnsArray","parameters":{"module":"VisitsSummary","action":"getEvolutionGraph","columns":"nb_visits"}},
|
||||
{"uniqueId":"widgetLivewidget","parameters":{"module":"Live","action":"widget"}},
|
||||
{"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDuration","parameters":{"module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}}
|
||||
],
|
||||
[
|
||||
' . $topWidget . '
|
||||
{"uniqueId":"widgetReferrersgetKeywords","parameters":{"module":"Referrers","action":"getKeywords"}},
|
||||
{"uniqueId":"widgetReferrersgetWebsites","parameters":{"module":"Referrers","action":"getWebsites"}}
|
||||
],
|
||||
[
|
||||
{"uniqueId":"widgetUserCountryMapvisitorMap","parameters":{"module":"UserCountryMap","action":"visitorMap"}},
|
||||
{"uniqueId":"widgetUserSettingsgetBrowser","parameters":{"module":"UserSettings","action":"getBrowser"}},
|
||||
{"uniqueId":"widgetReferrersgetSearchEngines","parameters":{"module":"Referrers","action":"getSearchEngines"}},
|
||||
{"uniqueId":"widgetVisitTimegetVisitInformationPerServerTime","parameters":{"module":"VisitTime","action":"getVisitInformationPerServerTime"}},
|
||||
{"uniqueId":"widgetExampleRssWidgetrssPiwik","parameters":{"module":"ExampleRssWidget","action":"rssPiwik"}}
|
||||
]
|
||||
]';
|
||||
}
|
||||
|
||||
$defaultLayout = $this->removeDisabledPluginFromLayout($defaultLayout);
|
||||
|
||||
return $defaultLayout;
|
||||
}
|
||||
|
||||
public function getAllDashboards($login)
|
||||
{
|
||||
$dashboards = Db::fetchAll('SELECT iddashboard, name, layout
|
||||
FROM ' . Common::prefixTable('user_dashboard') .
|
||||
' WHERE login = ? ORDER BY iddashboard', array($login));
|
||||
|
||||
$nameless = 1;
|
||||
foreach ($dashboards AS &$dashboard) {
|
||||
|
||||
if (empty($dashboard['name'])) {
|
||||
$dashboard['name'] = Piwik::translate('Dashboard_DashboardOf', $login);
|
||||
if ($nameless > 1) {
|
||||
$dashboard['name'] .= " ($nameless)";
|
||||
}
|
||||
|
||||
$nameless++;
|
||||
}
|
||||
|
||||
$dashboard['name'] = Common::unsanitizeInputValue($dashboard['name']);
|
||||
|
||||
$layout = '[]';
|
||||
if (!empty($dashboard['layout'])) {
|
||||
$layout = $dashboard['layout'];
|
||||
}
|
||||
|
||||
$dashboard['layout'] = $this->decodeLayout($layout);
|
||||
}
|
||||
|
||||
return $dashboards;
|
||||
}
|
||||
|
||||
private function isAlreadyDecodedLayout($layout)
|
||||
{
|
||||
return !is_string($layout);
|
||||
}
|
||||
|
||||
public function removeDisabledPluginFromLayout($layout)
|
||||
{
|
||||
$layoutObject = $this->decodeLayout($layout);
|
||||
|
||||
// if the json decoding works (ie. new Json format)
|
||||
// we will only return the widgets that are from enabled plugins
|
||||
|
||||
if (is_array($layoutObject)) {
|
||||
$layoutObject = (object)array(
|
||||
'config' => array('layout' => '33-33-33'),
|
||||
'columns' => $layoutObject
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($layoutObject) || empty($layoutObject->columns)) {
|
||||
$layoutObject = (object)array(
|
||||
'config' => array('layout' => '33-33-33'),
|
||||
'columns' => array()
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($layoutObject->columns as &$row) {
|
||||
if (!is_array($row)) {
|
||||
$row = array();
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($row as $widgetId => $widget) {
|
||||
if (isset($widget->parameters->module)) {
|
||||
$controllerName = $widget->parameters->module;
|
||||
$controllerAction = $widget->parameters->action;
|
||||
if (!WidgetsList::isDefined($controllerName, $controllerAction)) {
|
||||
unset($row[$widgetId]);
|
||||
}
|
||||
} else {
|
||||
unset($row[$widgetId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$layout = $this->encodeLayout($layoutObject);
|
||||
return $layout;
|
||||
}
|
||||
|
||||
public function decodeLayout($layout)
|
||||
{
|
||||
if ($this->isAlreadyDecodedLayout($layout)) {
|
||||
return $layout;
|
||||
}
|
||||
|
||||
$layout = html_entity_decode($layout);
|
||||
$layout = str_replace("\\\"", "\"", $layout);
|
||||
$layout = str_replace("\n", "", $layout);
|
||||
|
||||
return Common::json_decode($layout, $assoc = false);
|
||||
}
|
||||
|
||||
public function encodeLayout($layout)
|
||||
{
|
||||
return Common::json_encode($layout);
|
||||
}
|
||||
|
||||
public function addMenus()
|
||||
{
|
||||
MenuMain::getInstance()->add('Dashboard_Dashboard', '', array('module' => 'Dashboard', 'action' => 'embeddedIndex', 'idDashboard' => 1), true, 5);
|
||||
|
||||
if (!Piwik::isUserIsAnonymous()) {
|
||||
$login = Piwik::getCurrentUserLogin();
|
||||
|
||||
$dashboards = $this->getAllDashboards($login);
|
||||
|
||||
$pos = 0;
|
||||
foreach ($dashboards as $dashboard) {
|
||||
MenuMain::getInstance()->add('Dashboard_Dashboard', $dashboard['name'], array('module' => 'Dashboard', 'action' => 'embeddedIndex', 'idDashboard' => $dashboard['iddashboard']), true, $pos);
|
||||
$pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addTopMenu()
|
||||
{
|
||||
$tooltip = false;
|
||||
try {
|
||||
$idSite = Common::getRequestVar('idSite');
|
||||
$tooltip = Piwik::translate('Dashboard_TopLinkTooltip', Site::getNameFor($idSite));
|
||||
} catch (Exception $ex) {
|
||||
// if no idSite parameter, show no tooltip
|
||||
}
|
||||
|
||||
$urlParams = array('module' => 'CoreHome', 'action' => 'index');
|
||||
MenuTop::addEntry('Dashboard_Dashboard', $urlParams, true, 1, $isHTML = false, $tooltip);
|
||||
}
|
||||
|
||||
public function getJsFiles(&$jsFiles)
|
||||
{
|
||||
$jsFiles[] = "plugins/Dashboard/javascripts/widgetMenu.js";
|
||||
$jsFiles[] = "libs/javascript/json2.js";
|
||||
$jsFiles[] = "plugins/Dashboard/javascripts/dashboardObject.js";
|
||||
$jsFiles[] = "plugins/Dashboard/javascripts/dashboardWidget.js";
|
||||
$jsFiles[] = "plugins/Dashboard/javascripts/dashboard.js";
|
||||
}
|
||||
|
||||
public function getStylesheetFiles(&$stylesheets)
|
||||
{
|
||||
$stylesheets[] = "plugins/CoreHome/stylesheets/dataTable.less";
|
||||
$stylesheets[] = "plugins/Dashboard/stylesheets/dashboard.less";
|
||||
}
|
||||
|
||||
public function deleteDashboardLayout($userLogin)
|
||||
{
|
||||
Db::query('DELETE FROM ' . Common::prefixTable('user_dashboard') . ' WHERE login = ?', array($userLogin));
|
||||
}
|
||||
|
||||
public function install()
|
||||
{
|
||||
$dashboard = "login VARCHAR( 100 ) NOT NULL ,
|
||||
iddashboard INT NOT NULL ,
|
||||
name VARCHAR( 100 ) NULL DEFAULT NULL ,
|
||||
layout TEXT NOT NULL,
|
||||
PRIMARY KEY ( login , iddashboard )";
|
||||
|
||||
DbHelper::createTable('user_dashboard', $dashboard);
|
||||
}
|
||||
|
||||
public function uninstall()
|
||||
{
|
||||
Db::dropTables(Common::prefixTable('user_dashboard'));
|
||||
}
|
||||
|
||||
public function getClientSideTranslationKeys(&$translationKeys)
|
||||
{
|
||||
$translationKeys[] = 'Dashboard_AddPreviewedWidget';
|
||||
$translationKeys[] = 'Dashboard_WidgetPreview';
|
||||
$translationKeys[] = 'Dashboard_Maximise';
|
||||
$translationKeys[] = 'Dashboard_Minimise';
|
||||
$translationKeys[] = 'Dashboard_LoadingWidget';
|
||||
$translationKeys[] = 'Dashboard_WidgetNotFound';
|
||||
$translationKeys[] = 'Dashboard_DashboardCopied';
|
||||
$translationKeys[] = 'General_Close';
|
||||
$translationKeys[] = 'General_Refresh';
|
||||
}
|
||||
}
|
||||
53
www/analytics/plugins/Dashboard/DashboardManagerControl.php
Normal file
53
www/analytics/plugins/Dashboard/DashboardManagerControl.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?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\Dashboard;
|
||||
|
||||
use Piwik\View\UIControl;
|
||||
|
||||
/**
|
||||
* Generates the HTML for the dashboard manager control.
|
||||
*/
|
||||
class DashboardManagerControl extends DashboardSettingsControlBase
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->jsClass = "DashboardManagerControl";
|
||||
$this->cssIdentifier = "dashboard-manager";
|
||||
|
||||
$this->addDashboardActions();
|
||||
$this->addGeneralActions();
|
||||
}
|
||||
|
||||
private function addDashboardActions()
|
||||
{
|
||||
$this->dashboardActions['resetDashboard'] = 'Dashboard_ResetDashboard';
|
||||
$this->dashboardActions['showChangeDashboardLayoutDialog'] = 'Dashboard_ChangeDashboardLayout';
|
||||
|
||||
if ($this->userLogin && $this->userLogin != 'anonymous') {
|
||||
$this->dashboardActions['renameDashboard'] = 'Dashboard_RenameDashboard';
|
||||
$this->dashboardActions['removeDashboard'] = 'Dashboard_RemoveDashboard';
|
||||
|
||||
if ($this->isSuperUser) {
|
||||
$this->dashboardActions['setAsDefaultWidgets'] = 'Dashboard_SetAsDefaultWidgets';
|
||||
$this->dashboardActions['copyDashboardToUser'] = 'Dashboard_CopyDashboardToUser';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function addGeneralActions()
|
||||
{
|
||||
if ($this->userLogin && $this->userLogin != 'anonymous') {
|
||||
$this->generalActions['createDashboard'] = 'Dashboard_CreateNewDashboard';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?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\Dashboard;
|
||||
|
||||
use Piwik\View\UIControl;
|
||||
|
||||
/**
|
||||
* Generates the HTML for the dashboard manager control.
|
||||
*/
|
||||
abstract class DashboardSettingsControlBase extends UIControl
|
||||
{
|
||||
const TEMPLATE = "@Dashboard/_dashboardSettings";
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->cssClass = "piwikTopControl dashboardSettings";
|
||||
$this->dashboardActions = array();
|
||||
$this->generalActions = array();
|
||||
}
|
||||
}
|
||||
306
www/analytics/plugins/Dashboard/javascripts/dashboard.js
Normal file
306
www/analytics/plugins/Dashboard/javascripts/dashboard.js
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
function initDashboard(dashboardId, dashboardLayout) {
|
||||
|
||||
$('.dashboardSettings').show();
|
||||
|
||||
// Embed dashboard
|
||||
if (!$('#topBars').length) {
|
||||
$('.dashboardSettings').after($('#Dashboard'));
|
||||
$('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfHover');
|
||||
}
|
||||
|
||||
widgetsHelper.getAvailableWidgets();
|
||||
|
||||
$('#dashboardWidgetsArea')
|
||||
.on('dashboardempty', showEmptyDashboardNotification)
|
||||
.dashboard({
|
||||
idDashboard: dashboardId,
|
||||
layout: dashboardLayout
|
||||
});
|
||||
|
||||
$('#columnPreview').find('>div').each(function () {
|
||||
var width = [];
|
||||
$('div', this).each(function () {
|
||||
width.push(this.className.replace(/width-/, ''));
|
||||
});
|
||||
$(this).attr('layout', width.join('-'));
|
||||
});
|
||||
|
||||
$('#columnPreview').find('>div').on('click', function () {
|
||||
$('#columnPreview').find('>div').removeClass('choosen');
|
||||
$(this).addClass('choosen');
|
||||
});
|
||||
}
|
||||
|
||||
function createDashboard() {
|
||||
$('#createDashboardName').val('');
|
||||
piwikHelper.modalConfirm('#createDashboardConfirm', {yes: function () {
|
||||
var dashboardName = $('#createDashboardName').val();
|
||||
var type = ($('#dashboard_type_empty:checked').length > 0) ? 'empty' : 'default';
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.setLoadingElement();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'createNewDashboard'
|
||||
}, 'get');
|
||||
ajaxRequest.addParams({
|
||||
name: encodeURIComponent(dashboardName),
|
||||
type: type
|
||||
}, 'post');
|
||||
ajaxRequest.setCallback(
|
||||
function (id) {
|
||||
$('#dashboardWidgetsArea').dashboard('loadDashboard', id);
|
||||
}
|
||||
);
|
||||
ajaxRequest.send(true);
|
||||
}});
|
||||
}
|
||||
|
||||
function resetDashboard() {
|
||||
piwikHelper.modalConfirm('#resetDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); }});
|
||||
}
|
||||
|
||||
function renameDashboard() {
|
||||
$('#newDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
|
||||
piwikHelper.modalConfirm('#renameDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('setDashboardName', $('#newDashboardName').val()); }});
|
||||
}
|
||||
|
||||
function removeDashboard() {
|
||||
$('#removeDashboardConfirm').find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName'));
|
||||
piwikHelper.modalConfirm('#removeDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('removeDashboard'); }});
|
||||
}
|
||||
|
||||
function showChangeDashboardLayoutDialog() {
|
||||
$('#columnPreview').find('>div').removeClass('choosen');
|
||||
$('#columnPreview').find('>div[layout=' + $('#dashboardWidgetsArea').dashboard('getColumnLayout') + ']').addClass('choosen');
|
||||
piwikHelper.modalConfirm('#changeDashboardLayout', {yes: function () {
|
||||
$('#dashboardWidgetsArea').dashboard('setColumnLayout', $('#changeDashboardLayout').find('.choosen').attr('layout'));
|
||||
}});
|
||||
}
|
||||
|
||||
function showEmptyDashboardNotification() {
|
||||
piwikHelper.modalConfirm('#dashboardEmptyNotification', {
|
||||
resetDashboard: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); },
|
||||
addWidget: function () { $('.dashboardSettings').trigger('click'); }
|
||||
});
|
||||
}
|
||||
|
||||
function setAsDefaultWidgets() {
|
||||
piwikHelper.modalConfirm('#setAsDefaultWidgetsConfirm', {
|
||||
yes: function () { $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout'); }
|
||||
});
|
||||
}
|
||||
|
||||
function copyDashboardToUser() {
|
||||
$('#copyDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'API',
|
||||
method: 'UsersManager.getUsers',
|
||||
format: 'json'
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function (availableUsers) {
|
||||
$('#copyDashboardUser').empty();
|
||||
$('#copyDashboardUser').append(
|
||||
$('<option></option>').val(piwik.userLogin).text(piwik.userLogin)
|
||||
);
|
||||
$.each(availableUsers, function (index, user) {
|
||||
if (user.login != 'anonymous' && user.login != piwik.userLogin) {
|
||||
$('#copyDashboardUser').append(
|
||||
$('<option></option>').val(user.login).text(user.login + ' (' + user.alias + ')')
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
ajaxRequest.send(true);
|
||||
|
||||
piwikHelper.modalConfirm('#copyDashboardToUserConfirm', {
|
||||
yes: function () {
|
||||
var copyDashboardName = $('#copyDashboardName').val();
|
||||
var copyDashboardUser = $('#copyDashboardUser').val();
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'copyDashboardToUser'
|
||||
}, 'get');
|
||||
ajaxRequest.addParams({
|
||||
name: encodeURIComponent(copyDashboardName),
|
||||
dashboardId: $('#dashboardWidgetsArea').dashboard('getDashboardId'),
|
||||
user: encodeURIComponent(copyDashboardUser)
|
||||
}, 'post');
|
||||
ajaxRequest.setCallback(
|
||||
function (id) {
|
||||
$('#alert').find('h2').text(_pk_translate('Dashboard_DashboardCopied'));
|
||||
piwikHelper.modalConfirm('#alert', {});
|
||||
}
|
||||
);
|
||||
ajaxRequest.send(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(function () {
|
||||
var exports = window.require('piwik/UI');
|
||||
var UIControl = exports.UIControl;
|
||||
|
||||
/**
|
||||
* Contains logic common to all dashboard management controls. This is the JavaScript analog of
|
||||
* the DashboardSettingsControlBase PHP class.
|
||||
*
|
||||
* @param {Element} element The HTML element generated by the SegmentSelectorControl PHP class. Should
|
||||
* have the CSS class 'segmentEditorPanel'.
|
||||
* @constructor
|
||||
*/
|
||||
var DashboardSettingsControlBase = function (element) {
|
||||
UIControl.call(this, element);
|
||||
|
||||
// on menu item click, trigger action event on this
|
||||
var self = this;
|
||||
this.$element.on('click', 'ul.submenu li[data-action]', function (e) {
|
||||
self.$element.toggleClass('visible');
|
||||
|
||||
$(self).trigger($(this).attr('data-action'));
|
||||
});
|
||||
|
||||
// open manager on open
|
||||
this.$element.on('click', function (e) {
|
||||
if ($(e.target).is('.dashboardSettings,.dashboardSettings>span')) {
|
||||
self.$element.toggleClass('visible');
|
||||
|
||||
// fix position
|
||||
self.$element
|
||||
.find('.widgetpreview-widgetlist')
|
||||
.css('paddingTop', self.$element.find('.widgetpreview-categorylist').parent('li').position().top);
|
||||
|
||||
self.onOpen();
|
||||
}
|
||||
});
|
||||
|
||||
// handle manager close
|
||||
this.onBodyMouseUp = function (e) {
|
||||
if (!$(e.target).closest('.dashboardSettings').length
|
||||
&& !$(e.target).is('.dashboardSettings')
|
||||
) {
|
||||
self.$element.widgetPreview('reset');
|
||||
self.$element.removeClass('visible');
|
||||
}
|
||||
};
|
||||
|
||||
$('body').on('mouseup', this.onBodyMouseUp);
|
||||
|
||||
// setup widgetPreview
|
||||
this.$element.widgetPreview({
|
||||
isWidgetAvailable: function (widgetUniqueId) {
|
||||
return self.isWidgetAvailable(widgetUniqueId);
|
||||
},
|
||||
onSelect: function (widgetUniqueId) {
|
||||
var widget = widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId);
|
||||
self.$element.removeClass('visible');
|
||||
|
||||
self.widgetSelected(widget);
|
||||
},
|
||||
resetOnSelect: true
|
||||
});
|
||||
|
||||
// on enter widget list category, reset widget preview
|
||||
this.$element.on('mouseenter', '.submenu > li', function (event) {
|
||||
if (!$('.widgetpreview-categorylist', event.target).length) {
|
||||
self.$element.widgetPreview('reset');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.extend(DashboardSettingsControlBase.prototype, UIControl.prototype, {
|
||||
_destroy: function () {
|
||||
UIControl.prototype._destroy.call(this);
|
||||
|
||||
$('body').off('mouseup', null, this.onBodyMouseUp);
|
||||
}
|
||||
});
|
||||
|
||||
exports.DashboardSettingsControlBase = DashboardSettingsControlBase;
|
||||
|
||||
/**
|
||||
* Sets up and handles events for the dashboard manager control.
|
||||
*
|
||||
* @param {Element} element The HTML element generated by the SegmentSelectorControl PHP class. Should
|
||||
* have the CSS class 'segmentEditorPanel'.
|
||||
* @constructor
|
||||
*/
|
||||
var DashboardManagerControl = function (element) {
|
||||
DashboardSettingsControlBase.call(this, element);
|
||||
|
||||
$(this).on('resetDashboard', function () {
|
||||
this.hide();
|
||||
resetDashboard();
|
||||
});
|
||||
|
||||
$(this).on('showChangeDashboardLayoutDialog', function () {
|
||||
this.hide();
|
||||
showChangeDashboardLayoutDialog();
|
||||
});
|
||||
|
||||
$(this).on('renameDashboard', function () {
|
||||
this.hide();
|
||||
renameDashboard();
|
||||
});
|
||||
|
||||
$(this).on('removeDashboard', function () {
|
||||
this.hide();
|
||||
removeDashboard();
|
||||
});
|
||||
|
||||
$(this).on('setAsDefaultWidgets', function () {
|
||||
this.hide();
|
||||
setAsDefaultWidgets();
|
||||
});
|
||||
|
||||
$(this).on('copyDashboardToUser', function () {
|
||||
this.hide();
|
||||
copyDashboardToUser();
|
||||
});
|
||||
|
||||
$(this).on('createDashboard', function () {
|
||||
this.hide();
|
||||
createDashboard();
|
||||
});
|
||||
};
|
||||
|
||||
$.extend(DashboardManagerControl.prototype, DashboardSettingsControlBase.prototype, {
|
||||
onOpen: function () {
|
||||
if ($('#dashboardWidgetsArea').dashboard('isDefaultDashboard')) {
|
||||
$('.removeDashboardLink', this.$element).hide();
|
||||
} else {
|
||||
$('.removeDashboardLink', this.$element).show();
|
||||
}
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this.$element.removeClass('visible');
|
||||
},
|
||||
|
||||
isWidgetAvailable: function (widgetUniqueId) {
|
||||
return !$('#dashboardWidgetsArea').find('[widgetId=' + widgetUniqueId + ']').length;
|
||||
},
|
||||
|
||||
widgetSelected: function (widget) {
|
||||
$('#dashboardWidgetsArea').dashboard('addWidget', widget.uniqueId, 1, widget.parameters, true, false);
|
||||
}
|
||||
});
|
||||
|
||||
DashboardManagerControl.initElements = function () {
|
||||
UIControl.initElements(this, '.dashboard-manager');
|
||||
};
|
||||
|
||||
exports.DashboardManagerControl = DashboardManagerControl;
|
||||
}());
|
||||
577
www/analytics/plugins/Dashboard/javascripts/dashboardObject.js
Normal file
577
www/analytics/plugins/Dashboard/javascripts/dashboardObject.js
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
/**
|
||||
* Current dashboard column layout
|
||||
* @type {object}
|
||||
*/
|
||||
var dashboardLayout = {};
|
||||
/**
|
||||
* Id of current dashboard
|
||||
* @type {int}
|
||||
*/
|
||||
var dashboardId = 1;
|
||||
/**
|
||||
* Name of current dashboard
|
||||
* @type {string}
|
||||
*/
|
||||
var dashboardName = '';
|
||||
/**
|
||||
* Holds a reference to the dashboard element
|
||||
* @type {object}
|
||||
*/
|
||||
var dashboardElement = null;
|
||||
/**
|
||||
* Boolean indicating wether the layout config has been changed or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
var dashboardChanged = false;
|
||||
|
||||
/**
|
||||
* public methods of dashboard plugin
|
||||
* all methods defined here are accessible with $(selector).dashboard('method', param, param, ...)
|
||||
*/
|
||||
var methods = {
|
||||
|
||||
/**
|
||||
* creates a dashboard object
|
||||
*
|
||||
* @param {object} options
|
||||
*/
|
||||
init: function (options) {
|
||||
|
||||
dashboardElement = this;
|
||||
|
||||
if (options.idDashboard) {
|
||||
dashboardId = options.idDashboard;
|
||||
}
|
||||
|
||||
if (options.name) {
|
||||
dashboardName = options.name;
|
||||
}
|
||||
|
||||
if (options.layout) {
|
||||
generateLayout(options.layout);
|
||||
buildMenu();
|
||||
} else {
|
||||
methods.loadDashboard.apply(this, [dashboardId]);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys the dashboard object and all its childrens
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
destroy: function () {
|
||||
$(dashboardElement).remove();
|
||||
dashboardElement = null;
|
||||
var widgets = $('[widgetId]');
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
$(widgets[i]).dashboardWidget('destroy');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load dashboard with the given id
|
||||
*
|
||||
* @param {int} dashboardIdToLoad
|
||||
*/
|
||||
loadDashboard: function (dashboardIdToLoad) {
|
||||
$(dashboardElement).empty();
|
||||
dashboardName = '';
|
||||
dashboardLayout = null;
|
||||
dashboardId = dashboardIdToLoad;
|
||||
piwikHelper.showAjaxLoading();
|
||||
broadcast.updateHashOnly = true;
|
||||
broadcast.propagateAjax('?idDashboard=' + dashboardIdToLoad);
|
||||
fetchLayout(generateLayout);
|
||||
buildMenu();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Change current column layout to the given one
|
||||
*
|
||||
* @param {String} newLayout
|
||||
*/
|
||||
setColumnLayout: function (newLayout) {
|
||||
adjustDashboardColumns(newLayout);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current column layout
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
getColumnLayout: function () {
|
||||
return dashboardLayout.config.layout;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current dashboard name
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
getDashboardName: function () {
|
||||
return dashboardName;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current dashboard id
|
||||
*
|
||||
* @return {int}
|
||||
*/
|
||||
getDashboardId: function () {
|
||||
return dashboardId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets a new name for the current dashboard
|
||||
*
|
||||
* @param {String} newName
|
||||
*/
|
||||
setDashboardName: function (newName) {
|
||||
dashboardName = newName;
|
||||
dashboardChanged = true;
|
||||
saveLayout();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new widget to the dashboard
|
||||
*
|
||||
* @param {String} uniqueId
|
||||
* @param {int} columnNumber
|
||||
* @param {object} widgetParameters
|
||||
* @param {boolean} addWidgetOnTop
|
||||
* @param {boolean} isHidden
|
||||
*/
|
||||
addWidget: function (uniqueId, columnNumber, widgetParameters, addWidgetOnTop, isHidden) {
|
||||
addWidgetTemplate(uniqueId, columnNumber, widgetParameters, addWidgetOnTop, isHidden);
|
||||
reloadWidget(uniqueId);
|
||||
saveLayout();
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the current layout to the defaults
|
||||
*/
|
||||
resetLayout: function () {
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'resetLayout',
|
||||
idDashboard: dashboardId
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function () {
|
||||
methods.loadDashboard.apply(this, [dashboardId])
|
||||
}
|
||||
);
|
||||
ajaxRequest.setLoadingElement();
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the current dashboard
|
||||
*/
|
||||
removeDashboard: function () {
|
||||
removeDashboard();
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the current layout aus new default widget layout
|
||||
*/
|
||||
saveLayoutAsDefaultWidgetLayout: function () {
|
||||
saveLayout('saveLayoutAsDefault');
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if the current loaded dashboard is the default dashboard
|
||||
*/
|
||||
isDefaultDashboard: function () {
|
||||
return (dashboardId == 1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates the dashboard out of the given layout
|
||||
*
|
||||
* @param {object|string} layout
|
||||
*/
|
||||
function generateLayout(layout) {
|
||||
|
||||
dashboardLayout = parseLayout(layout);
|
||||
piwikHelper.hideAjaxLoading();
|
||||
adjustDashboardColumns(dashboardLayout.config.layout);
|
||||
|
||||
var dashboardContainsWidgets = false;
|
||||
for (var column = 0; column < dashboardLayout.columns.length; column++) {
|
||||
for (var i in dashboardLayout.columns[column]) {
|
||||
if (typeof dashboardLayout.columns[column][i] != 'object') {
|
||||
// Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function.
|
||||
// If we would continue with i="indexOf", an invalid widget would be created.
|
||||
continue;
|
||||
}
|
||||
var widget = dashboardLayout.columns[column][i];
|
||||
dashboardContainsWidgets = true;
|
||||
addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden)
|
||||
}
|
||||
}
|
||||
|
||||
if (!dashboardContainsWidgets) {
|
||||
$(dashboardElement).trigger('dashboardempty');
|
||||
}
|
||||
|
||||
makeWidgetsSortable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the layout for the currently set dashboard id
|
||||
* and passes the response to given callback function
|
||||
*
|
||||
* @param {function} callback
|
||||
*/
|
||||
function fetchLayout(callback) {
|
||||
globalAjaxQueue.abort();
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'getDashboardLayout',
|
||||
idDashboard: dashboardId
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(callback);
|
||||
ajaxRequest.send(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the dashboard columns to fit the new layout
|
||||
* removes or adds new columns if needed and sets the column sizes.
|
||||
*
|
||||
* @param {String} layout new layout in format xx-xx-xx
|
||||
* @return {void}
|
||||
*/
|
||||
function adjustDashboardColumns(layout) {
|
||||
var columnWidth = layout.split('-');
|
||||
var columnCount = columnWidth.length;
|
||||
|
||||
var currentCount = $('.col', dashboardElement).length;
|
||||
|
||||
if (currentCount < columnCount) {
|
||||
$('.menuClear', dashboardElement).remove();
|
||||
for (var i = currentCount; i < columnCount; i++) {
|
||||
if (dashboardLayout.columns.length < i) {
|
||||
dashboardLayout.columns.push({});
|
||||
}
|
||||
$(dashboardElement).append('<div class="col"> </div>');
|
||||
}
|
||||
$(dashboardElement).append('<div class="menuClear"> </div>');
|
||||
} else if (currentCount > columnCount) {
|
||||
for (var i = columnCount; i < currentCount; i++) {
|
||||
if (dashboardLayout.columns.length >= i) {
|
||||
dashboardLayout.columns.pop();
|
||||
}
|
||||
// move widgets to other columns depending on columns height
|
||||
$('[widgetId]', $('.col:last')).each(function (id, elem) {
|
||||
var cols = $('.col').slice(0, columnCount);
|
||||
var smallestColumn = $(cols[0]);
|
||||
var smallestColumnHeight = null;
|
||||
cols.each(function (colId, col) {
|
||||
if (smallestColumnHeight == null || smallestColumnHeight > $(col).height()) {
|
||||
smallestColumnHeight = $(col).height();
|
||||
smallestColumn = $(col);
|
||||
}
|
||||
});
|
||||
|
||||
$(elem).appendTo(smallestColumn);
|
||||
});
|
||||
|
||||
$('.col:last').remove();
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < columnCount; i++) {
|
||||
$('.col', dashboardElement)[i].className = 'col width-' + columnWidth[i];
|
||||
}
|
||||
|
||||
makeWidgetsSortable();
|
||||
|
||||
// if dashboard column count is changed (not on initial load)
|
||||
if (currentCount > 0 && dashboardLayout.config.layout != layout) {
|
||||
dashboardChanged = true;
|
||||
dashboardLayout.config.layout = layout;
|
||||
saveLayout();
|
||||
}
|
||||
|
||||
// trigger resize event on all widgets
|
||||
$('.widgetContent').each(function () {
|
||||
$(this).trigger('widget:resize');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given layout as an layout object
|
||||
* Used to parse old layout format into the new syntax
|
||||
*
|
||||
* @param {object} layout layout object or string
|
||||
* @return {object}
|
||||
*/
|
||||
function parseLayout(layout) {
|
||||
|
||||
// Handle layout array used in piwik before 1.7
|
||||
// column count was always 3, so use layout 33-33-33 as default
|
||||
if ($.isArray(layout)) {
|
||||
layout = {
|
||||
config: {layout: '33-33-33'},
|
||||
columns: layout
|
||||
};
|
||||
}
|
||||
|
||||
if (!layout.config.layout) {
|
||||
layout.config.layout = '33-33-33';
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the widget with the given uniqueId
|
||||
*
|
||||
* @param {String} uniqueId
|
||||
*/
|
||||
function reloadWidget(uniqueId) {
|
||||
$('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget('reload', false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an empty widget template to the dashboard in the given column
|
||||
* @param {String} uniqueId
|
||||
* @param {int} columnNumber
|
||||
* @param {object} widgetParameters
|
||||
* @param {boolean} addWidgetOnTop
|
||||
* @param {boolean} isHidden
|
||||
*/
|
||||
function addWidgetTemplate(uniqueId, columnNumber, widgetParameters, addWidgetOnTop, isHidden) {
|
||||
if (!columnNumber) {
|
||||
columnNumber = 1;
|
||||
}
|
||||
|
||||
// do not try to add widget if given column number is to high
|
||||
if (columnNumber > $('.col', dashboardElement).length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var widgetContent = '<div class="sortable" widgetId="' + uniqueId + '"></div>';
|
||||
|
||||
if (addWidgetOnTop) {
|
||||
$('.col:nth-child(' + columnNumber + ')', dashboardElement).prepend(widgetContent);
|
||||
} else {
|
||||
$('.col:nth-child(' + columnNumber + ')', dashboardElement).append(widgetContent);
|
||||
}
|
||||
|
||||
$('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget({
|
||||
uniqueId: uniqueId,
|
||||
widgetParameters: widgetParameters,
|
||||
onChange: function () {
|
||||
saveLayout();
|
||||
},
|
||||
isHidden: isHidden
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all widgets on the dashboard sortable
|
||||
*/
|
||||
function makeWidgetsSortable() {
|
||||
function onStart(event, ui) {
|
||||
if (!jQuery.support.noCloneEvent) {
|
||||
$('object', this).hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onStop(event, ui) {
|
||||
$('object', this).show();
|
||||
$('.widgetHover', this).removeClass('widgetHover');
|
||||
$('.widgetTopHover', this).removeClass('widgetTopHover');
|
||||
if ($('.widget:has(".piwik-graph")', ui.item).length) {
|
||||
reloadWidget($('.widget', ui.item).attr('id'));
|
||||
}
|
||||
saveLayout();
|
||||
}
|
||||
|
||||
//launch 'sortable' property on every dashboard widgets
|
||||
$( "div.col:data('ui-sortable')", dashboardElement ).sortable('destroy');
|
||||
|
||||
$('div.col', dashboardElement)
|
||||
.sortable({
|
||||
items: 'div.sortable',
|
||||
opacity: 0.6,
|
||||
forceHelperSize: true,
|
||||
forcePlaceholderSize: true,
|
||||
placeholder: 'hover',
|
||||
handle: '.widgetTop',
|
||||
helper: 'clone',
|
||||
start: onStart,
|
||||
stop: onStop,
|
||||
connectWith: 'div.col'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clicks for menu items for choosing between available dashboards
|
||||
*/
|
||||
function buildMenu() {
|
||||
var success = function (dashboards) {
|
||||
var dashboardMenuList = $('#Dashboard').find('> ul');
|
||||
var dashboardMenuListItems = dashboardMenuList.find('>li');
|
||||
|
||||
dashboardMenuListItems.filter(function () {
|
||||
return $(this).attr('id').indexOf('Dashboard_embeddedIndex') == 0;
|
||||
}).remove();
|
||||
|
||||
if (dashboards.length > 1
|
||||
|| dashboardMenuListItems.length >= 1
|
||||
) {
|
||||
dashboardMenuList.show();
|
||||
var items = [];
|
||||
for (var i = 0; i < dashboards.length; i++) {
|
||||
var $link = $('<a/>').attr('data-idDashboard', dashboards[i].iddashboard).text(dashboards[i].name);
|
||||
var $li = $('<li/>').attr('id', 'Dashboard_embeddedIndex_' + dashboards[i].iddashboard)
|
||||
.addClass('dashboardMenuItem').append($link);
|
||||
items.push($li);
|
||||
|
||||
if (dashboards[i].iddashboard == dashboardId) {
|
||||
dashboardName = dashboards[i].name;
|
||||
$li.addClass('sfHover');
|
||||
}
|
||||
}
|
||||
dashboardMenuList.prepend(items);
|
||||
} else {
|
||||
dashboardMenuList.hide();
|
||||
}
|
||||
|
||||
dashboardMenuList.find('a[data-idDashboard]').click(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var idDashboard = $(this).attr('data-idDashboard');
|
||||
|
||||
if (typeof piwikMenu != 'undefined') {
|
||||
piwikMenu.activateMenu('Dashboard', 'embeddedIndex');
|
||||
}
|
||||
$('#Dashboard ul li').removeClass('sfHover');
|
||||
if ($(dashboardElement).length) {
|
||||
$(dashboardElement).dashboard('loadDashboard', idDashboard);
|
||||
} else {
|
||||
broadcast.propagateAjax('module=Dashboard&action=embeddedIndex&idDashboard=' + idDashboard);
|
||||
}
|
||||
$(this).closest('li').addClass('sfHover');
|
||||
});
|
||||
};
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'getAllDashboards'
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(success);
|
||||
ajaxRequest.send(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current layout in database if it has changed
|
||||
* @param {string} [action] action to perform (defaults to saveLayout)
|
||||
*/
|
||||
function saveLayout(action) {
|
||||
var columns = [];
|
||||
|
||||
var columnNumber = 0;
|
||||
$('.col').each(function () {
|
||||
columns[columnNumber] = [];
|
||||
var items = $('[widgetId]', this);
|
||||
for (var j = 0; j < items.size(); j++) {
|
||||
columns[columnNumber][j] = $(items[j]).dashboardWidget('getWidgetObject');
|
||||
|
||||
// Do not store segment in the dashboard layout
|
||||
delete columns[columnNumber][j].parameters.segment;
|
||||
|
||||
}
|
||||
columnNumber++;
|
||||
});
|
||||
|
||||
if (JSON.stringify(dashboardLayout.columns) != JSON.stringify(columns) || dashboardChanged || action) {
|
||||
|
||||
dashboardLayout.columns = JSON.parse(JSON.stringify(columns));
|
||||
columns = null;
|
||||
|
||||
if (!action) {
|
||||
action = 'saveLayout';
|
||||
}
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: action,
|
||||
idDashboard: dashboardId
|
||||
}, 'get');
|
||||
ajaxRequest.addParams({
|
||||
layout: JSON.stringify(dashboardLayout),
|
||||
name: dashboardName
|
||||
}, 'post');
|
||||
ajaxRequest.setCallback(
|
||||
function () {
|
||||
if (dashboardChanged) {
|
||||
dashboardChanged = false;
|
||||
buildMenu();
|
||||
}
|
||||
}
|
||||
);
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the current dashboard
|
||||
*/
|
||||
function removeDashboard() {
|
||||
if (dashboardId == 1) {
|
||||
return; // dashboard with id 1 should never be deleted, as it is the default
|
||||
}
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.setLoadingElement();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'removeDashboard',
|
||||
idDashboard: dashboardId
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function () {
|
||||
methods.loadDashboard.apply(this, [1]);
|
||||
}
|
||||
);
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make plugin methods available
|
||||
*/
|
||||
$.fn.dashboard = function (method) {
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist on jQuery.dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
331
www/analytics/plugins/Dashboard/javascripts/dashboardWidget.js
Executable file
331
www/analytics/plugins/Dashboard/javascripts/dashboardWidget.js
Executable file
|
|
@ -0,0 +1,331 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$.widget('piwik.dashboardWidget', {
|
||||
|
||||
/**
|
||||
* Boolean indicating wether the widget is currently maximised
|
||||
* @type {Boolean}
|
||||
*/
|
||||
isMaximised: false,
|
||||
/**
|
||||
* Unique Id of the widget
|
||||
* @type {String}
|
||||
*/
|
||||
uniqueId: null,
|
||||
/**
|
||||
* Object holding the widget parameters
|
||||
* @type {Object}
|
||||
*/
|
||||
widgetParameters: {},
|
||||
|
||||
/**
|
||||
* Options available for initialization
|
||||
*/
|
||||
options: {
|
||||
uniqueId: null,
|
||||
isHidden: false,
|
||||
onChange: null,
|
||||
widgetParameters: {},
|
||||
title: null,
|
||||
onRemove: null,
|
||||
onRefresh: null,
|
||||
onMaximise: null,
|
||||
onMinimise: null,
|
||||
autoMaximiseVisualizations: ['tableAllColumns', 'tableGoals']
|
||||
},
|
||||
|
||||
/**
|
||||
* creates a widget object
|
||||
*/
|
||||
_create: function () {
|
||||
|
||||
if (!this.options.uniqueId) {
|
||||
piwikHelper.error('widgets can\'t be created without an uniqueId');
|
||||
return;
|
||||
} else {
|
||||
this.uniqueId = this.options.uniqueId;
|
||||
}
|
||||
|
||||
if (this.options.widgetParameters) {
|
||||
this.widgetParameters = this.options.widgetParameters;
|
||||
}
|
||||
|
||||
this._createDashboardWidget(this.uniqueId);
|
||||
|
||||
var self = this;
|
||||
this.element.on('setParameters.dashboardWidget', function (e, params) { self.setParameters(params); });
|
||||
|
||||
this.reload(true, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleanup some events and dialog
|
||||
* Called automatically upon removing the widgets domNode
|
||||
*/
|
||||
destroy: function () {
|
||||
if (this.isMaximised) {
|
||||
$('[widgetId=' + this.uniqueId + ']').dialog('destroy');
|
||||
}
|
||||
$('*', this.element).off('.dashboardWidget'); // unbind all events
|
||||
$('.widgetContent', this.element).trigger('widget:destroy');
|
||||
require('piwik/UI').UIControl.cleanupUnusedControls();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the data currently set for the widget
|
||||
* @return {object}
|
||||
*/
|
||||
getWidgetObject: function () {
|
||||
return {
|
||||
uniqueId: this.uniqueId,
|
||||
parameters: this.widgetParameters,
|
||||
isHidden: this.options.isHidden
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the current widget in an ui.dialog
|
||||
*/
|
||||
maximise: function () {
|
||||
this.isMaximised = true;
|
||||
|
||||
if (this.options.onMaximise) {
|
||||
this.options.onMaximise(this.element);
|
||||
} else {
|
||||
this._maximiseImpl();
|
||||
}
|
||||
|
||||
$('.widgetContent', this.element).trigger('widget:maximise');
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reloads the widgets content with the currently set parameters
|
||||
*/
|
||||
reload: function (hideLoading, notJQueryUI, overrideParams) {
|
||||
if (!notJQueryUI) {
|
||||
piwikHelper.log('widget.reload() was called by jquery.ui, ignoring', arguments.callee.caller);
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this, currentWidget = this.element;
|
||||
|
||||
function onWidgetLoadedReplaceElementWithContent(loadedContent) {
|
||||
$('.widgetContent', currentWidget).html(loadedContent);
|
||||
$('.widgetContent', currentWidget).removeClass('loading');
|
||||
$('.widgetContent', currentWidget).trigger('widget:create', [self]);
|
||||
}
|
||||
|
||||
// Reading segment from hash tag (standard case) or from the URL (when embedding dashboard)
|
||||
var segment = broadcast.getValueFromHash('segment') || broadcast.getValueFromUrl('segment');
|
||||
if (segment.length) {
|
||||
this.widgetParameters.segment = segment;
|
||||
}
|
||||
|
||||
if (!hideLoading) {
|
||||
$('.widgetContent', currentWidget).addClass('loading');
|
||||
}
|
||||
|
||||
var params = $.extend(this.widgetParameters, overrideParams || {});
|
||||
widgetsHelper.loadWidgetAjax(this.uniqueId, params, onWidgetLoadedReplaceElementWithContent);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update widget parameters
|
||||
*
|
||||
* @param {object} parameters
|
||||
*/
|
||||
setParameters: function (parameters) {
|
||||
if (!this.isMaximised
|
||||
&& this.options.autoMaximiseVisualizations.indexOf(parameters.viewDataTable) !== -1
|
||||
) {
|
||||
this.maximise();
|
||||
}
|
||||
for (var name in parameters) {
|
||||
this.widgetParameters[name] = parameters[name];
|
||||
}
|
||||
if (!this.isMaximised) {
|
||||
this.options.onChange();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get widget parameters
|
||||
*
|
||||
* @param {object} parameters
|
||||
*/
|
||||
getParameters: function () {
|
||||
return $.extend({}, this.widgetParameters);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creaates the widget markup for the given uniqueId
|
||||
*
|
||||
* @param {String} uniqueId
|
||||
*/
|
||||
_createDashboardWidget: function (uniqueId) {
|
||||
|
||||
var widgetName = widgetsHelper.getWidgetNameFromUniqueId(uniqueId);
|
||||
if (!widgetName) {
|
||||
widgetName = _pk_translate('Dashboard_WidgetNotFound');
|
||||
}
|
||||
|
||||
var title = this.options.title === null ? $('<span/>').text(widgetName) : this.options.title;
|
||||
var emptyWidgetContent = require('piwik/UI/Dashboard').WidgetFactory.make(uniqueId, title);
|
||||
this.element.html(emptyWidgetContent);
|
||||
|
||||
var widgetElement = $('#' + uniqueId, this.element);
|
||||
var self = this;
|
||||
widgetElement
|
||||
.on('mouseenter.dashboardWidget', function () {
|
||||
if (!self.isMaximised) {
|
||||
$(this).addClass('widgetHover');
|
||||
$('.widgetTop', this).addClass('widgetTopHover');
|
||||
}
|
||||
})
|
||||
.on('mouseleave.dashboardWidget', function () {
|
||||
if (!self.isMaximised) {
|
||||
$(this).removeClass('widgetHover');
|
||||
$('.widgetTop', this).removeClass('widgetTopHover');
|
||||
}
|
||||
});
|
||||
|
||||
if (this.options.isHidden) {
|
||||
$('.widgetContent', widgetElement).toggleClass('hidden').closest('.widget').toggleClass('hiddenContent');
|
||||
}
|
||||
|
||||
$('.button#close', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
piwikHelper.modalConfirm('#confirm', {yes: function () {
|
||||
if (self.options.onRemove) {
|
||||
self.options.onRemove(self.element);
|
||||
} else {
|
||||
self.element.remove();
|
||||
self.options.onChange();
|
||||
}
|
||||
}});
|
||||
});
|
||||
|
||||
$('.button#maximise', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
if (self.options.onMaximise) {
|
||||
self.options.onMaximise(self.element);
|
||||
} else {
|
||||
if ($('.widgetContent', $(this).parents('.widget')).hasClass('hidden')) {
|
||||
self.showContent();
|
||||
} else {
|
||||
self.maximise();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.button#minimise', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
if (self.options.onMinimise) {
|
||||
self.options.onMinimise(self.element);
|
||||
} else {
|
||||
if (!self.isMaximised) {
|
||||
self.hideContent();
|
||||
} else {
|
||||
self.element.dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.button#refresh', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
if (self.options.onRefresh) {
|
||||
self.options.onRefresh(self.element);
|
||||
} else {
|
||||
self.reload(false, true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the widget content. Triggers the onChange event.
|
||||
*/
|
||||
hideContent: function () {
|
||||
$('.widgetContent', this.element.find('.widget').addClass('hiddenContent')).addClass('hidden');
|
||||
this.options.isHidden = true;
|
||||
this.options.onChange();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the widget content. Triggers the onChange event.
|
||||
*/
|
||||
showContent: function () {
|
||||
this.isMaximised = false;
|
||||
this.options.isHidden = false;
|
||||
this.element.find('.widget').removeClass('hiddenContent').find('.widgetContent').removeClass('hidden');
|
||||
this.element.find('.widget').find('div.piwik-graph').trigger('resizeGraph');
|
||||
this.options.onChange();
|
||||
$('.widgetContent', this.element).trigger('widget:minimise');
|
||||
},
|
||||
|
||||
/**
|
||||
* Default maximise behavior. Will create a dialog that is 70% of the document's width,
|
||||
* displaying the widget alone.
|
||||
*/
|
||||
_maximiseImpl: function () {
|
||||
this.detachWidget();
|
||||
|
||||
var width = Math.floor($('body').width() * 0.7);
|
||||
|
||||
var self = this;
|
||||
this.element.dialog({
|
||||
title: '',
|
||||
modal: true,
|
||||
width: width,
|
||||
position: ['center', 'center'],
|
||||
resizable: true,
|
||||
autoOpen: true,
|
||||
close: function (event, ui) {
|
||||
self.isMaximised = false;
|
||||
$('body').off('.dashboardWidget');
|
||||
$(this).dialog("destroy");
|
||||
$('#' + self.uniqueId + '-placeholder').replaceWith(this);
|
||||
$(this).removeAttr('style');
|
||||
self.options.onChange();
|
||||
$(this).find('div.piwik-graph').trigger('resizeGraph');
|
||||
$('.widgetContent', self.element).trigger('widget:minimise');
|
||||
}
|
||||
});
|
||||
this.element.find('div.piwik-graph').trigger('resizeGraph');
|
||||
|
||||
var currentWidget = this.element;
|
||||
$('body').on('click.dashboardWidget', function (ev) {
|
||||
if (/ui-widget-overlay/.test(ev.target.className)) {
|
||||
$(currentWidget).dialog("close");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detaches the widget from the DOM and replaces it with a placeholder element.
|
||||
* The placeholder element will have the save dimensions as the widget and will have
|
||||
* the widgetPlaceholder CSS class.
|
||||
*
|
||||
* @return {jQuery} the detached widget
|
||||
*/
|
||||
detachWidget: function () {
|
||||
this.element.before('<div id="' + this.uniqueId + '-placeholder" class="widgetPlaceholder widget"> </div>');
|
||||
$('#' + this.uniqueId + '-placeholder').height(this.element.height());
|
||||
$('#' + this.uniqueId + '-placeholder').width(this.element.width() - 16);
|
||||
|
||||
return this.element.detach();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
421
www/analytics/plugins/Dashboard/javascripts/widgetMenu.js
Normal file
421
www/analytics/plugins/Dashboard/javascripts/widgetMenu.js
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
function widgetsHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available widgets fetched via AJAX (if not already done)
|
||||
*
|
||||
* @return {object} object containing available widgets
|
||||
*/
|
||||
widgetsHelper.getAvailableWidgets = function () {
|
||||
if (!widgetsHelper.availableWidgets) {
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'getAvailableWidgets'
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function (data) {
|
||||
widgetsHelper.availableWidgets = data;
|
||||
}
|
||||
);
|
||||
ajaxRequest.send(true);
|
||||
}
|
||||
|
||||
return widgetsHelper.availableWidgets;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the complete widget object by its unique id
|
||||
*
|
||||
* @param {string} uniqueId
|
||||
* @return {object} widget object
|
||||
*/
|
||||
widgetsHelper.getWidgetObjectFromUniqueId = function (uniqueId) {
|
||||
var widgets = widgetsHelper.getAvailableWidgets();
|
||||
for (var widgetCategory in widgets) {
|
||||
var widgetInCategory = widgets[widgetCategory];
|
||||
for (var i in widgetInCategory) {
|
||||
if (widgetInCategory[i]["uniqueId"] == uniqueId) {
|
||||
return widgetInCategory[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of a widget by its unique id
|
||||
*
|
||||
* @param {string} uniqueId unique id of the widget
|
||||
* @return {string}
|
||||
*/
|
||||
widgetsHelper.getWidgetNameFromUniqueId = function (uniqueId) {
|
||||
var widget = this.getWidgetObjectFromUniqueId(uniqueId);
|
||||
if (widget == false) {
|
||||
return false;
|
||||
}
|
||||
return widget["name"];
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends and ajax request to query for the widgets html
|
||||
*
|
||||
* @param {string} widgetUniqueId unique id of the widget
|
||||
* @param {object} widgetParameters parameters to be used for loading the widget
|
||||
* @param {function} onWidgetLoadedCallback callback to be executed after widget is loaded
|
||||
* @return {object}
|
||||
*/
|
||||
widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWidgetLoadedCallback) {
|
||||
var disableLink = broadcast.getValueFromUrl('disableLink');
|
||||
if (disableLink.length) {
|
||||
widgetParameters['disableLink'] = disableLink;
|
||||
}
|
||||
|
||||
widgetParameters['widget'] = 1;
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams(widgetParameters, 'get');
|
||||
ajaxRequest.setCallback(onWidgetLoadedCallback);
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send(false);
|
||||
return ajaxRequest;
|
||||
};
|
||||
|
||||
(function ($, require) {
|
||||
var exports = require('piwik/UI/Dashboard');
|
||||
|
||||
/**
|
||||
* Singleton instance that creates widget elements. Normally not needed even
|
||||
* when embedding/re-using dashboard widgets, but it can be useful when creating
|
||||
* elements with the same look and feel as dashboard widgets, but different
|
||||
* behavior (such as the widget preview in the dashboard manager control).
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var WidgetFactory = function () {
|
||||
// empty
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an HTML element for displaying a widget.
|
||||
*
|
||||
* @param {string} uniqueId unique id of the widget
|
||||
* @param {string} widgetName name of the widget
|
||||
* @return {Element} the empty widget
|
||||
*/
|
||||
WidgetFactory.prototype.make = function (uniqueId, widgetName) {
|
||||
var $result = this.getWidgetTemplate().clone();
|
||||
$result.attr('id', uniqueId).find('.widgetName').append(widgetName);
|
||||
return $result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the base widget template element. The template is stored in the
|
||||
* element with id == 'widgetTemplate'.
|
||||
*
|
||||
* @return {Element} the widget template
|
||||
*/
|
||||
WidgetFactory.prototype.getWidgetTemplate = function () {
|
||||
if (!this.widgetTemplate) {
|
||||
this.widgetTemplate = $('#widgetTemplate').find('>.widget').detach();
|
||||
}
|
||||
return this.widgetTemplate;
|
||||
};
|
||||
|
||||
exports.WidgetFactory = new WidgetFactory();
|
||||
})(jQuery, require);
|
||||
|
||||
/**
|
||||
* widgetPreview jQuery Extension
|
||||
*
|
||||
* Converts an dom element to a widget preview
|
||||
* Widget preview contains an categorylist, widgetlist and a preview
|
||||
*/
|
||||
(function ($) {
|
||||
$.extend({
|
||||
widgetPreview: new function () {
|
||||
|
||||
/**
|
||||
* Default settings for widgetPreview
|
||||
* @type {object}
|
||||
*/
|
||||
var defaultSettings = {
|
||||
/**
|
||||
* handler called after a widget preview is loaded in preview element
|
||||
* @type {function}
|
||||
*/
|
||||
onPreviewLoaded: function () {},
|
||||
/**
|
||||
* handler called on click on element in widgetlist or widget header
|
||||
* @type {function}
|
||||
*/
|
||||
onSelect: function () {},
|
||||
/**
|
||||
* callback used to determine if a widget is available or not
|
||||
* unavailable widgets aren't chooseable in widgetlist
|
||||
* @type {function}
|
||||
*/
|
||||
isWidgetAvailable: function (widgetUniqueId) { return true; },
|
||||
/**
|
||||
* should the lists and preview be reset on widget selection?
|
||||
* @type {boolean}
|
||||
*/
|
||||
resetOnSelect: false,
|
||||
/**
|
||||
* css classes for various elements
|
||||
* @type {string}
|
||||
*/
|
||||
baseClass: 'widgetpreview-base',
|
||||
categorylistClass: 'widgetpreview-categorylist',
|
||||
widgetlistClass: 'widgetpreview-widgetlist',
|
||||
widgetpreviewClass: 'widgetpreview-preview',
|
||||
choosenClass: 'widgetpreview-choosen',
|
||||
unavailableClass: 'widgetpreview-unavailable'
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the div to show category list in
|
||||
* - if element doesn't exist it will be created and added
|
||||
* - if element already exist it's content will be removed
|
||||
*
|
||||
* @return {$} category list element
|
||||
*/
|
||||
function createWidgetCategoryList(widgetPreview, availableWidgets) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
if (!$('.' + settings.categorylistClass, widgetPreview).length) {
|
||||
$(widgetPreview).append('<ul class="' + settings.categorylistClass + '"></ul>');
|
||||
} else {
|
||||
$('.' + settings.categorylistClass, widgetPreview).empty();
|
||||
}
|
||||
|
||||
for (var widgetCategory in availableWidgets) {
|
||||
|
||||
$('.' + settings.categorylistClass, widgetPreview).append('<li>' + widgetCategory + '</li>');
|
||||
}
|
||||
|
||||
return $('.' + settings.categorylistClass, widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the div to show widget list in
|
||||
* - if element doesn't exist it will be created and added
|
||||
* - if element already exist it's content will be removed
|
||||
*
|
||||
* @return {$} widget list element
|
||||
*/
|
||||
function createWidgetList(widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
if (!$('.' + settings.widgetlistClass, widgetPreview).length) {
|
||||
$(widgetPreview).append('<ul class="' + settings.widgetlistClass + '"></ul>');
|
||||
} else {
|
||||
$('.' + settings.widgetlistClass + ' li', widgetPreview).off('mouseover');
|
||||
$('.' + settings.widgetlistClass + ' li', widgetPreview).off('click');
|
||||
$('.' + settings.widgetlistClass, widgetPreview).empty();
|
||||
}
|
||||
|
||||
if ($('.' + settings.categorylistClass + ' .' + settings.choosenClass, widgetPreview).length) {
|
||||
var position = $('.' + settings.categorylistClass + ' .' + settings.choosenClass, widgetPreview).position().top -
|
||||
$('.' + settings.categorylistClass, widgetPreview).position().top;
|
||||
|
||||
$('.' + settings.widgetlistClass, widgetPreview).css('top', position);
|
||||
$('.' + settings.widgetlistClass, widgetPreview).css('marginBottom', position);
|
||||
}
|
||||
|
||||
return $('.' + settings.widgetlistClass, widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the given widgets in a widget list
|
||||
*
|
||||
* @param {object} widgets widgets to be displayed
|
||||
* @return {void}
|
||||
*/
|
||||
function showWidgetList(widgets, widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
var widgetList = createWidgetList(widgetPreview),
|
||||
widgetPreviewTimer;
|
||||
|
||||
for (var j = 0; j < widgets.length; j++) {
|
||||
var widgetName = widgets[j]["name"];
|
||||
var widgetUniqueId = widgets[j]["uniqueId"];
|
||||
// var widgetParameters = widgets[j]["parameters"];
|
||||
var widgetClass = '';
|
||||
if (!settings.isWidgetAvailable(widgetUniqueId)) {
|
||||
widgetClass += ' ' + settings.unavailableClass;
|
||||
}
|
||||
|
||||
widgetList.append('<li class="' + widgetClass + '" uniqueid="' + widgetUniqueId + '">' + widgetName + '</li>');
|
||||
}
|
||||
|
||||
// delay widget preview a few millisconds
|
||||
$('li', widgetList).on('mouseenter', function () {
|
||||
var that = this,
|
||||
widgetUniqueId = $(this).attr('uniqueid');
|
||||
clearTimeout(widgetPreview);
|
||||
widgetPreviewTimer = setTimeout(function () {
|
||||
$('li', widgetList).removeClass(settings.choosenClass);
|
||||
$(that).addClass(settings.choosenClass);
|
||||
|
||||
showPreview(widgetUniqueId, widgetPreview);
|
||||
}, 400);
|
||||
});
|
||||
|
||||
// clear timeout after mouse has left
|
||||
$('li:not(.' + settings.unavailableClass + ')', widgetList).on('mouseleave', function () {
|
||||
clearTimeout(widgetPreview);
|
||||
});
|
||||
|
||||
$('li:not(.' + settings.unavailableClass + ')', widgetList).on('click', function () {
|
||||
if (!$('.widgetLoading', widgetPreview).length) {
|
||||
settings.onSelect($(this).attr('uniqueid'));
|
||||
if (settings.resetOnSelect) {
|
||||
resetWidgetPreview(widgetPreview);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the div to show widget preview in
|
||||
* - if element doesn't exist it will be created and added
|
||||
* - if element already exist it's content will be removed
|
||||
*
|
||||
* @return {$} preview element
|
||||
*/
|
||||
function createPreviewElement(widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
if (!$('.' + settings.widgetpreviewClass, widgetPreview).length) {
|
||||
$(widgetPreview).append('<div class="' + settings.widgetpreviewClass + '"></div>');
|
||||
} else {
|
||||
$('.' + settings.widgetpreviewClass + ' .widgetTop', widgetPreview).off('click');
|
||||
$('.' + settings.widgetpreviewClass, widgetPreview).empty();
|
||||
}
|
||||
|
||||
return $('.' + settings.widgetpreviewClass, widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show widget with the given uniqueId in preview
|
||||
*
|
||||
* @param {string} widgetUniqueId unique id of widget to display
|
||||
* @return {void}
|
||||
*/
|
||||
function showPreview(widgetUniqueId, widgetPreview) {
|
||||
// do not reload id widget already displayed
|
||||
if ($('#' + widgetUniqueId, widgetPreview).length) return;
|
||||
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
var previewElement = createPreviewElement(widgetPreview);
|
||||
|
||||
var widget = widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId);
|
||||
var widgetParameters = widget['parameters'];
|
||||
|
||||
var emptyWidgetHtml = require('piwik/UI/Dashboard').WidgetFactory.make(
|
||||
widgetUniqueId,
|
||||
$('<div/>')
|
||||
.attr('title', _pk_translate("Dashboard_AddPreviewedWidget"))
|
||||
.text(_pk_translate('Dashboard_WidgetPreview'))
|
||||
);
|
||||
previewElement.html(emptyWidgetHtml);
|
||||
|
||||
var onWidgetLoadedCallback = function (response) {
|
||||
var widgetElement = $('#' + widgetUniqueId);
|
||||
$('.widgetContent', widgetElement).html($(response));
|
||||
$('.widgetContent', widgetElement).trigger('widget:create');
|
||||
settings.onPreviewLoaded(widgetUniqueId, widgetElement);
|
||||
$('.' + settings.widgetpreviewClass + ' .widgetTop', widgetPreview).on('click', function () {
|
||||
settings.onSelect(widgetUniqueId);
|
||||
if (settings.resetOnSelect) {
|
||||
resetWidgetPreview(widgetPreview);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
// abort previous sent request
|
||||
if (widgetPreview.widgetAjaxRequest) {
|
||||
widgetPreview.widgetAjaxRequest.abort();
|
||||
}
|
||||
|
||||
widgetPreview.widgetAjaxRequest = widgetsHelper.loadWidgetAjax(widgetUniqueId, widgetParameters, onWidgetLoadedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset function
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function resetWidgetPreview(widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
$('.' + settings.categorylistClass + ' li', widgetPreview).removeClass(settings.choosenClass);
|
||||
createWidgetList(widgetPreview);
|
||||
createPreviewElement(widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param {object} userSettings Settings to be used
|
||||
* @return {void}
|
||||
*/
|
||||
this.construct = function (userSettings) {
|
||||
|
||||
if (userSettings == 'reset') {
|
||||
resetWidgetPreview(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.widgetAjaxRequest = null;
|
||||
|
||||
$(this).addClass('widgetpreview-base');
|
||||
|
||||
this.settings = jQuery.extend({}, defaultSettings, userSettings);
|
||||
|
||||
// set onSelect callback
|
||||
if (typeof this.settings.onSelect == 'function') {
|
||||
this.onSelect = this.settings.onSelect;
|
||||
}
|
||||
|
||||
// set onPreviewLoaded callback
|
||||
if (typeof this.settings.onPreviewLoaded == 'function') {
|
||||
this.onPreviewLoaded = this.settings.onPreviewLoaded;
|
||||
}
|
||||
|
||||
availableWidgets = widgetsHelper.getAvailableWidgets();
|
||||
|
||||
var categoryList = createWidgetCategoryList(this, availableWidgets);
|
||||
|
||||
var self = this;
|
||||
$('li', categoryList).on('mouseover', function () {
|
||||
var category = $(this).text();
|
||||
var widgets = availableWidgets[category];
|
||||
$('li', categoryList).removeClass(self.settings.choosenClass);
|
||||
$(this).addClass(self.settings.choosenClass);
|
||||
showWidgetList(widgets, self);
|
||||
createPreviewElement(self); // empty preview
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Makes widgetPreview available with $().widgetPreview()
|
||||
*/
|
||||
$.fn.extend({
|
||||
widgetPreview: $.widgetPreview.construct
|
||||
})
|
||||
})(jQuery);
|
||||
540
www/analytics/plugins/Dashboard/stylesheets/dashboard.less
Normal file
540
www/analytics/plugins/Dashboard/stylesheets/dashboard.less
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
#dashboard {
|
||||
margin: 0 -7px;
|
||||
}
|
||||
|
||||
#root>.top_controls {
|
||||
margin-left:15px;
|
||||
margin-right:15px;
|
||||
}
|
||||
.top_controls {
|
||||
position: relative;
|
||||
height: 32px;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
@media all and (max-width: 749px) {
|
||||
.top_controls {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.top_controls #periodString,
|
||||
.top_controls .dashboardSettings,
|
||||
.top_controls #segmentEditorPanel {
|
||||
position: static;
|
||||
margin: 0 0 10px;
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
#dashboardWidgetsArea {
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.col {
|
||||
float: left;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.col.width-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.col.width-75 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.col.width-67 {
|
||||
width: 66.67%;
|
||||
}
|
||||
|
||||
.col.width-50 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.col.width-40 {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.col.width-33 {
|
||||
width: 33.33%;
|
||||
}
|
||||
|
||||
.col.width-30 {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.col.width-25 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.hover {
|
||||
border: 2px dashed #E3E3E3;
|
||||
}
|
||||
|
||||
.widget {
|
||||
background: #fff;
|
||||
border: 1px solid #bbb6ad;
|
||||
margin: 10px 7px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.widgetHover {
|
||||
border: 1px solid #aba494;
|
||||
}
|
||||
|
||||
.widget .entityContainer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.widget .sparkline {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.widgetContent.hidden {
|
||||
position: absolute;
|
||||
top: -5000px;
|
||||
}
|
||||
|
||||
.widgetContent.loading {
|
||||
opacity: 0.5;
|
||||
background: url(plugins/Zeitgeist/images/loading-blue.gif) no-repeat top right;
|
||||
}
|
||||
|
||||
.widget h2 {
|
||||
font-size: 1.2em;
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.widget p {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.widgetTop {
|
||||
background: #b5b0a7 url(plugins/Zeitgeist/images/dashboard_h_bg.png) repeat-x 0 0;
|
||||
cursor: move;
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.widgetTopHover {
|
||||
background: #C4BBAD url(plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0;
|
||||
}
|
||||
|
||||
.widgetName {
|
||||
font-size: 18px;
|
||||
padding: 2px 0 0 10px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
text-shadow: 1px 1px 2px #7e7363;
|
||||
}
|
||||
|
||||
// Overriding some dataTable css for better dashboard display
|
||||
.widget .dataTableWrapper {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.widgetTop .button {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
margin: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
.ui-confirm {
|
||||
display: none;
|
||||
width: 630px;
|
||||
background: #fff;
|
||||
color: #444;
|
||||
cursor: default;
|
||||
font-size: 12px !important;
|
||||
font-family: Arial, Verdana, Arial, Helvetica, sans-serif;
|
||||
border-radius: 4px;
|
||||
padding: 20px 10px;
|
||||
border-radius: 4px;
|
||||
min-height: 0 !important;
|
||||
}
|
||||
|
||||
.ui-confirm p {
|
||||
margin-top:10px;
|
||||
|
||||
}
|
||||
.ui-confirm h2 {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-dialog-buttonpane {
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.ui-dialog-buttonset input[type=button], .ui-dialog-buttonset button {
|
||||
background: #B5B0A7 url(plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0 !important;
|
||||
color: #fff !important;
|
||||
border: 0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 5px 20px !important;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 0 8px 3px 8px !important;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-button-text {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ui-widget-overlay {
|
||||
opacity: 0.6;
|
||||
background: none #000;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.ui-dialog {
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.widgetLoading {
|
||||
cursor: wait;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#closeMenuIcon {
|
||||
float: right;
|
||||
margin: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menuClear {
|
||||
clear: both;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.dashboardSettings {
|
||||
position: absolute;
|
||||
z-index: 120;
|
||||
background: #f7f7f7;
|
||||
border: 1px solid #e4e5e4;
|
||||
padding: 5px 10px 6px 10px;
|
||||
border-radius: 4px;
|
||||
color: #444;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dashboardSettings:hover {
|
||||
background: #f1f0eb;
|
||||
border-color: #a9a399;
|
||||
}
|
||||
|
||||
.dashboardSettings.visible {
|
||||
z-index: 1020; /* More than .jqplot-seriespicker-popover (1010) */
|
||||
}
|
||||
|
||||
.dashboardSettings > span {
|
||||
background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) right center no-repeat;
|
||||
padding-right: 20px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dashboardSettings ul.submenu {
|
||||
padding-top: 5px;
|
||||
display: none;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dashboardSettings.visible ul.submenu {
|
||||
display: block;
|
||||
list-style: square outside none;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.dashboardSettings > ul.submenu > li {
|
||||
padding: 5px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dashboardSettings > ul.submenu > li:hover {
|
||||
color: #e87500;
|
||||
}
|
||||
|
||||
#changeDashboardLayout h2 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#columnPreview {
|
||||
clear: both;
|
||||
width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#columnPreview > div {
|
||||
margin: 5px;
|
||||
float: left;
|
||||
opacity: 0.4;
|
||||
cursor: pointer;
|
||||
filter: Alpha(opacity=40);
|
||||
}
|
||||
|
||||
#columnPreview > div:hover, #columnPreview > div.choosen {
|
||||
opacity: 1;
|
||||
filter: Alpha(opacity=100);
|
||||
}
|
||||
|
||||
#columnPreview div div {
|
||||
height: 120px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#columnPreview div div span {
|
||||
background-color: #ddd;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
border: 2px dotted #555;
|
||||
margin: 0 1px;
|
||||
}
|
||||
|
||||
#columnPreview div.choosen div span, #columnPreview div:hover div span {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
#columnPreview .width-100 {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
#columnPreview .width-75 {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
#columnPreview .width-67 {
|
||||
width: 80.4px;
|
||||
}
|
||||
|
||||
#columnPreview .width-50 {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
#columnPreview .width-40 {
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
#columnPreview .width-33 {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
#columnPreview .width-30 {
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
#columnPreview .width-25 {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout for widget previews
|
||||
*/
|
||||
|
||||
.widgetpreview-base {
|
||||
clear: both;
|
||||
min-height: 600px;
|
||||
-height: 600px;
|
||||
}
|
||||
|
||||
.addWidget, .manageDashboard {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
ul.widgetpreview-widgetlist,
|
||||
ul.widgetpreview-categorylist {
|
||||
color: #5d5342;
|
||||
list-style: none;
|
||||
font-size: 11px;
|
||||
line-height: 20px;
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
ul.widgetpreview-categorylist {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
ul.widgetpreview-categorylist li,
|
||||
ul.widgetpreview-widgetlist li {
|
||||
line-height: 20px;
|
||||
padding: 0 25px 0 5px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.widgetpreview-base li.widgetpreview-choosen {
|
||||
background: #e4e2d7 url(plugins/Zeitgeist/images/arr_r.png) no-repeat right 6px;
|
||||
color: #255792;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.widgetpreview-categorylist li.widgetpreview-choosen {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.widgetpreview-base li.widgetpreview-unavailable {
|
||||
color: #D3D3D3;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
ul.widgetpreview-widgetlist {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
div.widgetpreview-preview {
|
||||
float: left;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.dashboardSettings {
|
||||
min-height: 0;
|
||||
height: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.dashboardSettings .submenu {
|
||||
font-weight: bold;
|
||||
color: #255792;
|
||||
}
|
||||
|
||||
.dashboardSettings .submenu ul {
|
||||
float: none;
|
||||
font-weight: normal;
|
||||
padding-top: 10px;
|
||||
margin-left: 10px;
|
||||
color: #5D5342;
|
||||
list-style: none;
|
||||
font-size: 11px;
|
||||
line-height: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.dashboardSettings .submenu ul li {
|
||||
line-height: 20px;
|
||||
padding: 0 25px 0 5px;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.dashboardSettings .submenu ul li:hover {
|
||||
color: #e87500;
|
||||
}
|
||||
|
||||
.dashboardSettings .widgetpreview-widgetlist {
|
||||
width: 228px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.dashboardSettings .widgetTop {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dashboardSettings .widgetpreview-widgetlist,
|
||||
.dashboardSettings .widgetpreview-preview {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboardSettings.visible .widgetpreview-widgetlist,
|
||||
.dashboardSettings.visible .widgetpreview-preview {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.widgetPlaceholder {
|
||||
border: 1px dashed #bbb6ad;
|
||||
}
|
||||
|
||||
#newDashboardName, #createDashboardName {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#newDashboardNameInput, #createDashboardNameInput {
|
||||
margin: 20px 0 0 100px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#createDashboardNameInput input {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.popoverSubMessage {
|
||||
text-align: center;
|
||||
padding: 10px 0 5px 0;
|
||||
}
|
||||
|
||||
#copyDashboardToUserConfirm .inputs {
|
||||
width: 375px;
|
||||
margin: 10px auto 0;
|
||||
}
|
||||
|
||||
#copyDashboardToUserConfirm .inputs select,
|
||||
#copyDashboardToUserConfirm .inputs input {
|
||||
width: 150px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#copyDashboardToUserConfirm .inputs label {
|
||||
width: 200px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
@media all and (max-width: 749px) {
|
||||
#dashboardWidgetsArea {
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.col.width-75,
|
||||
.col.width-67,
|
||||
.col.width-50,
|
||||
.col.width-40,
|
||||
.col.width-33,
|
||||
.col.width-30,
|
||||
.col.width-25 {
|
||||
width: 100%;
|
||||
.widget {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.widgetTop .button {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.widgetTop.widgetTopHover .button {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.widget.hiddenContent .widgetTop.widgetTopHover {
|
||||
.button#minimise,.button#refresh {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-dialog .widget {
|
||||
.button#close,.button#maximise {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
72
www/analytics/plugins/Dashboard/stylesheets/standalone.css
Normal file
72
www/analytics/plugins/Dashboard/stylesheets/standalone.css
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
body {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#dashboard {
|
||||
margin: 30px -6px 0 -12px;
|
||||
width: 100%;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#Dashboard {
|
||||
z-index: 5;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#Dashboard > ul {
|
||||
list-style: square inside none;
|
||||
background: #f7f7f7;
|
||||
border: 1px solid #e4e5e4;
|
||||
padding: 5px 10px 6px 10px;
|
||||
border-radius: 4px;
|
||||
color: #444;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#Dashboard:hover ul {
|
||||
background: #f1f0eb;
|
||||
border-color: #a9a399;
|
||||
}
|
||||
|
||||
#Dashboard > ul > li {
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
#Dashboard a {
|
||||
color: #444;
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#Dashboard > ul > li:hover,
|
||||
#Dashboard > ul > li:hover a,
|
||||
#Dashboard > ul > li.sfHover,
|
||||
#Dashboard > ul > li.sfHover a {
|
||||
color: #e87500;
|
||||
}
|
||||
|
||||
#Dashboard > ul > li.sfHover,
|
||||
#Dashboard > ul > li.sfHover a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.top_controls > #Dashboard,
|
||||
.top_controls > #periodString,
|
||||
.top_controls > .dashboardSettings {
|
||||
margin-left: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.jqplot-seriespicker-popover {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#ajaxLoading {
|
||||
margin: 40px 0 -30px 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<span>{{ 'Dashboard_WidgetsAndDashboard'|translate }}</span>
|
||||
<ul class="submenu">
|
||||
<li>
|
||||
<div class="addWidget">{{ 'Dashboard_AddAWidget'|translate }} ↓</div>
|
||||
<ul class="widgetpreview-categorylist"></ul>
|
||||
</li>
|
||||
{% if dashboardActions|length > 0 %}
|
||||
<li>
|
||||
<div class="manageDashboard">{{ 'Dashboard_ManageDashboard'|translate }} ↓</div>
|
||||
<ul>
|
||||
{% for action, title in dashboardActions %}
|
||||
<li data-action="{{ action }}">{{ title|translate }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for action, title in generalActions %}
|
||||
<li data-action="{{ action }}">{{ title|translate }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul class="widgetpreview-widgetlist"></ul>
|
||||
<div class="widgetpreview-preview"></div>
|
||||
16
www/analytics/plugins/Dashboard/templates/_header.twig
Normal file
16
www/analytics/plugins/Dashboard/templates/_header.twig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{# This header is for loading the dashboard in stand alone mode #}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ 'Dashboard_Dashboard'|translate }} - {{ 'CoreHome_WebAnalyticsReports'|translate }}</title>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script language="javascript" type="text/javascript" src="libs/jqplot/excanvas.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="plugins/Dashboard/stylesheets/standalone.css" />
|
||||
{% include "_jsGlobalVariables.twig" %}
|
||||
{% include "_jsCssIncludes.twig" %}
|
||||
</head>
|
||||
<body id="standalone">
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<div id="widgetTemplate" style="display:none;">
|
||||
<div class="widget">
|
||||
<div class="widgetTop">
|
||||
<div class="button" id="close">
|
||||
<img src="plugins/Zeitgeist/images/close.png" title="{{ 'General_Close'|translate }}" />
|
||||
</div>
|
||||
<div class="button" id="maximise">
|
||||
<img src="plugins/Zeitgeist/images/maximise.png" title="{{ 'Dashboard_Maximise'|translate }}" />
|
||||
</div>
|
||||
<div class="button" id="minimise">
|
||||
<img src="plugins/Zeitgeist/images/minimise.png" title="{{ 'Dashboard_Minimise'|translate }}" />
|
||||
</div>
|
||||
<div class="button" id="refresh">
|
||||
<img src="plugins/Zeitgeist/images/refresh.png" title="{{ 'General_Refresh'|translate }}" />
|
||||
</div>
|
||||
<div class="widgetName">{% if widgetName is defined %}{{ widgetName }}{% endif %}</div>
|
||||
</div>
|
||||
<div class="widgetContent">
|
||||
<div class="widgetLoading">{{ 'Dashboard_LoadingWidget'|translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
98
www/analytics/plugins/Dashboard/templates/embeddedIndex.twig
Normal file
98
www/analytics/plugins/Dashboard/templates/embeddedIndex.twig
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<script type="text/javascript">
|
||||
widgetsHelper.availableWidgets = {{ availableWidgets|raw }};
|
||||
$(function() {
|
||||
initDashboard({{ dashboardId }}, {{ dashboardLayout|raw }});
|
||||
});
|
||||
</script>
|
||||
<div id="dashboard">
|
||||
<div class="ui-confirm" id="confirm">
|
||||
<h2>{{ 'Dashboard_DeleteWidgetConfirm'|translate }}</h2>
|
||||
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
|
||||
<input role="no" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
|
||||
<div class="ui-confirm" id="setAsDefaultWidgetsConfirm">
|
||||
<h2>{{ 'Dashboard_SetAsDefaultWidgetsConfirm'|translate }}</h2>
|
||||
{% set resetDashboard %}{{ 'Dashboard_ResetDashboard'|translate }}{% endset %}
|
||||
<div class="popoverSubMessage">{{ 'Dashboard_SetAsDefaultWidgetsConfirmHelp'|translate(resetDashboard) }}</div>
|
||||
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
|
||||
<input role="no" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
|
||||
<div class="ui-confirm" id="resetDashboardConfirm">
|
||||
<h2>{{ 'Dashboard_ResetDashboardConfirm'|translate }}</h2>
|
||||
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
|
||||
<input role="no" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
|
||||
<div class="ui-confirm" id="dashboardEmptyNotification">
|
||||
<h2>{{ 'Dashboard_DashboardEmptyNotification'|translate }}</h2>
|
||||
<input role="addWidget" type="button" value="{{ 'Dashboard_AddAWidget'|translate }}"/>
|
||||
<input role="resetDashboard" type="button" value="{{ 'Dashboard_ResetDashboard'|translate }}"/>
|
||||
</div>
|
||||
|
||||
<div class="ui-confirm" id="changeDashboardLayout">
|
||||
<h2>{{ 'Dashboard_SelectDashboardLayout'|translate }}</h2>
|
||||
|
||||
<div id="columnPreview">
|
||||
{% for layout in availableLayouts %}
|
||||
<div>
|
||||
{% for column in layout %}
|
||||
<div class="width-{{ column }}"><span></span></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<input role="yes" type="button" value="{{ 'General_Save'|translate }}"/>
|
||||
</div>
|
||||
|
||||
<div class="ui-confirm" id="renameDashboardConfirm">
|
||||
<h2>{{ 'Dashboard_RenameDashboard'|translate }}</h2>
|
||||
|
||||
<div id="newDashboardNameInput"><label for="newDashboardName">{{ 'Dashboard_DashboardName'|translate }} </label>
|
||||
<input type="input" name="newDashboardName" id="newDashboardName" value=""/>
|
||||
</div>
|
||||
<input role="yes" type="button" value="{{ 'General_Save'|translate }}"/>
|
||||
<input role="cancel" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
|
||||
{% if isSuperUser %}
|
||||
<div class="ui-confirm" id="copyDashboardToUserConfirm">
|
||||
<h2>{{ 'Dashboard_CopyDashboardToUser'|translate }}</h2>
|
||||
|
||||
<div class="inputs">
|
||||
<label for="copyDashboardName">{{ 'Dashboard_DashboardName'|translate }} </label>
|
||||
<input type="input" name="copyDashboardName" id="copyDashboardName" value=""/>
|
||||
<label for="copyDashboardUser">{{ 'General_Username'|translate }} </label>
|
||||
<select name="copyDashboardUser" id="copyDashboardUser"></select>
|
||||
</div>
|
||||
<input role="yes" type="button" value="{{ 'General_Ok'|translate }}"/>
|
||||
<input role="cancel" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="ui-confirm" id="createDashboardConfirm">
|
||||
<h2>{{ 'Dashboard_CreateNewDashboard'|translate }}</h2>
|
||||
|
||||
<div id="createDashboardNameInput">
|
||||
<label>{{ 'Dashboard_DashboardName'|translate }} <input type="input" name="newDashboardName" id="createDashboardName" value=""/></label><br/>
|
||||
<label><input type="radio" checked="checked" name="type" value="default" id="dashboard_type_default">{{ 'Dashboard_DefaultDashboard'|translate }}
|
||||
</label><br/>
|
||||
<label><input type="radio" name="type" value="empty" id="dashboard_type_empty">{{ 'Dashboard_EmptyDashboard'|translate }}</label>
|
||||
</div>
|
||||
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
|
||||
<input role="no" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
|
||||
<div class="ui-confirm" id="removeDashboardConfirm">
|
||||
<h2>{{ 'Dashboard_RemoveDashboardConfirm'|translate('<span></span>')|raw }}</h2>
|
||||
|
||||
<div class="popoverSubMessage">{{ 'Dashboard_NotUndo'|translate(resetDashboard) }}</div>
|
||||
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
|
||||
<input role="no" type="button" value="{{ 'General_Cancel'|translate }}"/>
|
||||
</div>
|
||||
|
||||
{% include "@Dashboard/_widgetFactoryTemplate.twig" %}
|
||||
|
||||
<div id="dashboardWidgetsArea"></div>
|
||||
</div>
|
||||
20
www/analytics/plugins/Dashboard/templates/index.twig
Normal file
20
www/analytics/plugins/Dashboard/templates/index.twig
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{% include "@Dashboard/_header.twig" %}
|
||||
<div class="top_controls">
|
||||
{% include "@CoreHome/_periodSelect.twig" %}
|
||||
{{ postEvent("Template.nextToCalendar") }}
|
||||
{% render dashboardSettingsControl %}
|
||||
<div id="Dashboard" class="piwikTopControl">
|
||||
<ul>
|
||||
{% for dashboard in dashboards %}
|
||||
<li class="dashboardMenuItem" id="Dashboard_embeddedIndex_{{ dashboard.iddashboard }}">
|
||||
<a href="javascript:$('#dashboardWidgetsArea').dashboard('loadDashboard', {{ dashboard.iddashboard }});">{{ dashboard.name|escape }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% import 'ajaxMacros.twig' as ajax %}
|
||||
{{ ajax.loadingDiv }}
|
||||
{% include "@Dashboard/embeddedIndex.twig" %}
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue