Bladeren bron

Dashboard : delete old plugin

idleman 2 jaren geleden
bovenliggende
commit
c64f88cae4

+ 1 - 1
.gitignore

@@ -6,4 +6,4 @@
 *.sublime-project
 *.sublime-workspace
 /plugin/document/logs/*.*
-/plugin/chat/node/node_modules
+/plugin/chat/node/node_modules

+ 0 - 21
dashboard/Dashboard.class.php

@@ -1,21 +0,0 @@
-<?php
-/**
- * Define a dashboard.
- * @author Administrateur
- * @category Plugin
- * @license copyright
- */
-class Dashboard extends Entity{
-	public $id,$user,$label,$icon,$default,$mandatory;
-	protected $TABLE_NAME = 'dashboard_dashboard';
-	public $fields =
-	array(
-		'id' => 'key',
-		'user' => 'string',
-		'label' => 'string',
-		'icon' => 'string',
-		'mandatory' => 'boolean',
-		'default' => 'boolean'
-	);
-}
-?>

+ 0 - 93
dashboard/DashboardWidget.class.php

@@ -1,93 +0,0 @@
-<?php
-/**
- * Define a dashboardwidget.
- * @author Administrateur
- * @category Plugin
- * @license copyright
- */
-class DashboardWidget extends Entity{
-	public $id,$minified,$position,$model,$dashboard,$title,$icon,$background,$width,$load,$configure,$configure_callback,$configure_init,$move,$delete,$options,$js,$css,$content,$data,$description,$defaultWidth;
-	protected $TABLE_NAME = 'dashboard_dashboard_widget';
-	public $fields =
-	array(
-		'id' => 'key',
-		'model' => 'string',
-		'data' => 'longstring',
-		'position' => 'int',
-		'minified' => 'boolean',
-		'width' => 'int',
-		'dashboard' => 'int'
-	);
-
-	function __construct(){
- 		parent::__construct();
- 		$this->options = array();
- 		$this->icon = 'fa-caret-right';
- 		$this->title = 'Sans titre';
- 		$this->defaultWidth = 4;
- 		$this->width = 0;
- 	}
-
- 	public function toArray($decoded= false){
-		$fields = parent::toArray($decoded);
-		$fields['options'] = $this->options;
-		$fields['icon'] =  $this->icon;
-		$fields['background'] =  $this->background;
-		$fields['load'] =  $this->load;
-		$fields['configure'] =  $this->configure;
-		$fields['configure_callback'] =  $this->configure_callback;
-		$fields['configure_init'] =  $this->configure_init;
-		$fields['js'] =  $this->js;
-		$fields['css'] =  $this->css;
-		$fields['description'] =  $this->description;
-		$fields['content'] =  $this->content;
-		$fields['title'] =  $this->title;
-		return $fields;
- 	}
-
- 	function data($key=null,$value=null){
- 		$data = json_decode($this->data,true);
- 		if($key==null) return $data;
- 		if(is_array($key) && $value==null){
- 			foreach ($key as $k => $v) {
- 				$data[$k] = $v;
- 				$this->data = json_encode($data);
- 			}
- 			return true;
- 		}
- 	
- 		if($value===null) return isset($data[$key])?$data[$key]:'';
- 		
- 		$data[$key] = $value;
-
- 		$this->data = json_encode($data);
- 		return true;
- 	}
-
- 	public static function current(){
- 		global $_;
- 		$dbWidget = self::getById($_['id']);
-
- 		$widget = DashboardWidget::models($dbWidget->model);
- 		$widget->id = $dbWidget->id;
- 		$widget->position =  $dbWidget->position;
- 		$widget->minified =  $dbWidget->minified;
- 		$widget->width = $dbWidget->width;
- 		$widget->dashboard = $dbWidget->dashboard;
- 		$widget->data = $dbWidget->data;
-
- 		return $widget;
- 	}
-
- 	public static function models($modelUid = null){
- 		Plugin::callHook('widget',array(&$models));
-
-		foreach($models as $model)
-			$models[$model->model] = $model;
-
-		if(!isset($modelUid)) return $models;
-		
-		return isset($models[$modelUid]) ? $models[$modelUid] : array();
- 	}
-}
-?>

+ 0 - 31
dashboard/DashboardWidgetShare.class.php

@@ -1,31 +0,0 @@
-<?php
-/**
- * Define a dashboardwidgetshare.
- * @author Administrateur
- * @category Plugin
- * @license copyright
- */
-class DashboardWidgetShare extends Entity{
-
-	public $id;
-	public $widget; //ID Widget (Entier)
-	public $mandatory; //Obligatoire (Booléen)
-	public $entity; //Entité de partage (Texte)
-	public $uid; //Uid de partage (Texte)
-	public $sort; //Ordre par défaut (Entier)
-	
-	protected $TABLE_NAME = 'dashboard_dashboard_widget_share';
-	public $fields = array(
-		'id' => 'key',
-		'widget' => array('label'=>'Widget','type'=>'int','link'=>'plugin/dashboard/DashboardWidget.class.php'),
-		'mandatory' => 'boolean',
-		'entity' => 'string',
-		'uid' => 'string',
-		'sort' => 'int'
-	);
-
-
-	//Colonnes indexées
-	public $indexes = array();
-}
-?>

+ 0 - 381
dashboard/action.php

@@ -1,381 +0,0 @@
-<?php
-
-
-	/** DASHBOARD **/
-	//Récuperation d'une liste de dashboard
-	Action::register('dashboard_dashboard_search',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-
-		$filters = array();
-		if(!$myUser->can('dashboard','configure')) $filters['creator'] = $myUser->login;
-
-		foreach(Dashboard::loadAll($filters,array('label','creator')) as $dashboard){
-			$userName = User::byLogin($dashboard->user)->fullName();
-			$dashboard->user = !empty($userName) ? $userName : $dashboard->user;
-			$dashboard->mandatory = $dashboard->mandatory == 1;
-			$dashboard->default = $dashboard->default == 1;
-			$response['rows'][] = $dashboard;
-		}
-	});
-
-	//Ajout ou modification d'élément dashboard
-	Action::register('dashboard_dashboard_save',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		if($_['mandatory']==1 && !$myUser->can('dashboard','configure'))  throw new Exception("Vous n'avez pas les droits pour rendre ce dashboard obigatoire",403);
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-
-		$item = Dashboard::provide();
-		if(!isset($_['user']) || empty($_['user'])) $_['user'] = $myUser->login;
-
-		if($myUser->login!=$item->creator && !$myUser->can('dashboard','configure') && $item->id!=0)  throw new Exception("Vous n'avez pas les droits pour éditer le dashboard d'un autre utilisateur",403);
-		if($myUser->login!=$_['user'] && !$myUser->can('dashboard','configure')) throw new Exception("Vous n'avez pas les droits pour créer un dashboard à un autre utilisateur");
-
-		$item->user = $_['user'];
-		$item->label = $_['label'];
-		$item->icon = $_['icon'];
-		$item->default = $_['default'];
-		if($item->default) Dashboard::change(array('default'=>0), array('user'=>$item->user));
-		$item->mandatory = $_['mandatory'];
-		if($item->mandatory) Dashboard::change(array('mandatory'=>0));
-		$item->save();
-	});
-
-	//Récuperation ou edition d'élément dashboard
-	Action::register('dashboard_dashboard_edit',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-		$response = Dashboard::getById($_['id']);
-	});
-
-	//Suppression d'élement dashboard
-	Action::register('dashboard_dashboard_delete',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','delete');
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-		$item = Dashboard::provide();
-		if($myUser->login!=$item->creator && !$myUser->can('dashboard','configure'))  throw new Exception("Vous n'avez pas les droits pour supprimer le dashboard d'un autre utilisateur",403);
-		Dashboard::deleteById($_['id']);
-	});
-
-	//Sauvegarde des configurations de dashboard
-	Action::register('dashboard_setting_save',function(&$response){
-		global $myUser,$_,$conf;
-		User::check_access('dashboard','configure');
-		foreach(Configuration::setting('dashboard') as $key=>$value){
-			if(!is_array($value)) continue;
-			$allowed[] = $key;
-		}
-		foreach ($_['fields'] as $key => $value)
-			if(in_array($key, $allowed)) $conf->put($key,$value);
-	});
-
-	/** DASHBOARDWIDGET **/
-	//Récuperation d'une liste de dashboardwidget
-	Action::register('dashboard_dashboardwidget_search',function(&$response){
-	
-		global $myUser,$myFirm,$_;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-
-		$models = DashboardWidget::models();
-		$ranksId = $myUser->getRanksId($myFirm->id);
-		$widgetsQry = "SELECT {{table}}.*,ds.mandatory,ds.sort as sort
-			FROM {{table}}
-			LEFT JOIN ".DashboardWidgetShare::tableName()." ds ON ds.widget={{table}}.id
-			WHERE dashboard=?
-				OR {{table}}.id IN (
-					SELECT widget FROM ".DashboardWidgetShare::tableName()." WHERE (entity=? AND uid=?) OR (entity=? and uid IN (".str_repeat('?,', count($ranksId) - 1) . '?'.")) OR (entity IS NULL)
-				)
-				ORDER BY sort, position DESC";
-		$widgets = DashboardWidget::staticQuery($widgetsQry,array_merge(array($_['dashboard'],'user',$myUser->login,'rank'),$ranksId),true);
-
-		foreach($widgets as $widget){
-			if(!isset($models[$widget->model])) continue;
-			$model = clone $models[$widget->model];
-
-			$row = $model->toArray();
-			$row['id'] = $widget->id;
-			$row['width'] = !empty($widget->width) && $widget->width>0 ? $widget->width : $model->defaultWidth;
-			$row['position'] = $widget->position;
-			$row['minified'] = $widget->minified;
-			$row['dashboard'] = $widget->dashboard;
-
-			if(!empty($widget->foreign('mandatory'))) $row['mandatory'] = $widget->foreign('mandatory');
-			if(!empty($widget->foreign('sort'))) $row['position'] = $widget->foreign('sort');
-
-			$response['rows'][] = $row;
-		}
-
-		if(isset($response['rows'])){
-			usort($response['rows'],function($a,$b){
-				return $a['position'] - $b['position'];
-			});
-		}
-	});
-
-	//Ajout ou modification d'élément dashboardwidget
-	Action::register('dashboard_dashboardwidget_save',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$item = DashboardWidget::provide();
-		$item->model = $_['model'];
-		$item->data = $_['data'];
-		$item->position = $_['position'];
-		$item->minified = $_['minified'];
-		$item->dashboard = $_['dashboard'];
-		$item->save();
-	});
-
-	//Récuperation ou edition d'élément dashboardwidget
-	Action::register('dashboard_dashboardwidget_edit',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$response = DashboardWidget::getById($_['id']);
-	});
-
-	//Suppression d'élement dashboardwidget
-	Action::register('dashboard_dashboardwidget_delete',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','delete');
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$widget = DashboardWidget::getById($_['widget']);
-		if(!$widget) return;
-
-		$dashboard = Dashboard::getById($_['dashboard']);
-		if($widget->dashboard!=$dashboard->id || $dashboard->user!=$myUser->login)
-			throw new Exception("Vous ne pouvez supprimer que vos propres widgets");
-
-		$widget->deleteById($widget->id);
-		$response['message'] = 'Widget supprimé';
-	});
-
-	//Resize largeur d'élement dashboardwidget
-	Action::register('dashboard_dashboardwidget_resize',function(&$response){
-		global $myUser,$_;
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		User::check_access('dashboard','edit');
-
-		$widget = DashboardWidget::getById($_['widget']);
-		$dashboard = Dashboard::getById($widget->dashboard);
-		if($widget->dashboard!=$dashboard->id || $dashboard->user!=$myUser->login)
-			throw new Exception("Vous ne pouvez redimenssioner que vos propres widgets");
-
-		$widget->width = $_['width'];
-		$widget->save();
-	});
-
-	Action::register('dashboard_dashboardwidget_refresh',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','read');
-		$widgets = array();
-		Plugin::callHook('widget_refresh',array(&$widgets));
-		$response['rows'] = $widgets;
-	});
-
-	Action::register('dashboard_dashboardwidget_add',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$widget = new DashboardWidget();
-		$widget->model = $_['widget'];
-		$widget->position = 666;
-		$widget->minified = false;
-		$widget->width = $widget->width> 0 ? $widget->width: $widget->defaultWidth ;
-		$widget->dashboard = $_['dashboard'];
-		$widget->save();
-		$response['message'] = 'Widget ajouté';
-	});
-
-	Action::register('dashboard_dashboardwidget_save_position',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'Dashboard.class.php');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$dashboard = Dashboard::getById($_['dashboard']);
-
-		if($dashboard->user!=$myUser->login) throw new Exception("Vous ne pouvez modifier que vos propres widgets");
-		$dashboard_widgets = DashboardWidget::loadAll( array('dashboard' => $dashboard->id ) );
-
-		foreach($_['positions'] as $move){
-			foreach($dashboard_widgets as $dashboard_widget){
-				if($dashboard_widget->id!=$move['id']) continue;
-				$dashboard_widget->position = $move['position'];
-				$dashboard_widget->save();
-			}
-		}
-	});
-
-	/* CLOCK */
-	Action::register('dashboard_widget_clock_load',function(&$response){
-		global $myUser;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$widget = DashboardWidget::current();
-		ob_start();
-		require_once(__DIR__.SLASH.'widget.clock.php');
-		$widget->content = ob_get_clean();
-		echo json_encode($widget);
-		exit;
-	});
-
-	/* LOGS */
-	Action::register('dashboard_widget_log_load',function(&$response){
-		global $myUser;
-		require_once('DashboardWidget.class.php');
-		User::check_access('log','read');
-
-		$widget = DashboardWidget::current();
-		$widget->title = '30 derniers logs';
-
-		ob_start();
-		require_once(__DIR__.SLASH.'widget.logs.php');
-		$widget->content = ob_get_clean();
-		echo json_encode($widget);
-		exit;
-	});
-
-	/* PROFILE */
-	Action::register('dashboard_widget_profile_load',function(&$response){
-		global $myUser;
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		User::check_access('dashboard','read');
-		$widget = DashboardWidget::current();
-		if(!empty($widget->data('background-color'))) $widget->background = $widget->data('background-color');
-		ob_start();
-		require_once(__DIR__.SLASH.'widget.profile.php');
-		$widget->content = ob_get_clean();
-		echo json_encode($widget);
-		exit;
-	});
-
-	Action::register('dashboard_widget_profile_configure',function(&$response){
-		global $myUser;
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		User::check_access('dashboard','read');
-		$widget = DashboardWidget::current();
-		ob_start();
-		require_once(__DIR__.SLASH.'widget.profile.configure.php');
-		$content = ob_get_clean();
-
-		echo $content ;
-		exit;
-	});
-
-	Action::register('dashboard_widget_profile_configure_save',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$widget = DashboardWidget::getById($_['id']);
-		$widget->data('background-color',$_['widget-profile-background-color']);
-		$widget->save();
-	});
-
-
-	/* HTML */
-	Action::register('dashboard_widget_html_load',function(&$response){
-		global $myUser;
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		User::check_access('dashboard','read');
-		$widget = DashboardWidget::current();
-		$widget->title = $widget->data('title') != "" ? $widget->data('title') :  'Bloc HTML';
-		if($widget->data('color') != "") $widget->background = $widget->data('color');
-		ob_start();
-		require_once(__DIR__.SLASH.'widget.html.php');
-		$widget->content = ob_get_clean();
-		echo json_encode($widget);
-		exit;
-	});
-
-	Action::register( 'dashboard_widget_html_configure',function(&$response){
-		global $myUser;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$widget = DashboardWidget::current();
-		ob_start();
-		require_once(__DIR__.SLASH.'widget.html.configure.php');
-		$content = ob_get_clean();
-		echo $content ;
-		exit;
-	});
-
-	Action::register('dashboard_widget_html_configure_save',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$widget = DashboardWidget::getById($_['id']);
-		$widget->data('html',html_entity_decode($_['widget-html-content']));
-		$widget->data('title',$_['widget-html-title']);
-		$widget->data('color',$_['widget-html-color']);
-		$widget->save();
-	});
-
-	/* DASHBOARD SHARE */
-	/** DASHBOARDWIDGETSHARE **/
-	//Récuperation d'une liste de dashboardwidgetshare
-	Action::register('dashboard_widget_share_search',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','read');
-		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-		$dashboardwidgetshares = DashboardWidgetShare::loadAll(array(), null,  null,array('*'), 1);
-		foreach($dashboardwidgetshares as $dashboardwidgetshare){
-			$row = $dashboardwidgetshare->toArray();
-
-			$row['widget'] = $dashboardwidgetshare->join('widget')->toArray();
-			$row['for'] = 'Tout le monde';
-			if($row['entity'] == 'rank' ) $row['for'] = 'Rang: '. Rank::getById($row['uid'] )->label;
-			if($row['entity'] == 'user' ) $row['for'] ='Utilisateur: '. User::byLogin($row['uid'] )->fullName();
-			$response['rows'][] = $row;
-		}
-	});
-
-	//Ajout ou modification d'élément dashboardwidgetshare
-	Action::register('dashboard_widget_share_save',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-		//DashboardWidgetShare::create();
-		$item = DashboardWidgetShare::provide();
-
-		if(!isset( $_['widget']) || !is_numeric($_['widget'])) throw new Exception("Widget non spécifié ou invalide");
-
-		$item->widget = $_['widget'];
-		$item->mandatory = 1;//$_['mandatory'];
-
-		if(isset($_['entity'])){
-			$item->entity = $_['entity'];
-			$item->uid = $_['uid'];
-		}
-		$item->sort = !isset($_['sort']) ? 0 : $_['sort'];
-		$item->save();
-	});
-
-
-	//Récuperation ou edition d'élément dashboardwidgetshare
-	Action::register('dashboard_widget_share_edit',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','edit');
-		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-		$response = DashboardWidgetShare::getById($_['id'],1)->toArray();
-	});
-
-	//Suppression d'élement dashboardwidgetshare
-	Action::register('dashboard_widget_share_delete',function(&$response){
-		global $myUser,$_;
-		User::check_access('dashboard','delete');
-		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-		DashboardWidgetShare::deleteById($_['id']);
-	});
-
-?>

+ 0 - 13
dashboard/app.json

@@ -1,13 +0,0 @@
-{
-	"id": "fr.core.dashboard",
-	"name": "Dashboard",
-	"author" : {
-		"name" : "Valentin CARRUESCO",
-		"mail" : ""
-	},
-	"version": "2.0",
-	"url": "http://no-url.com",
-	"licence": {"name": "MIT","url" : ""},
-	"description": "Dashboard avec widgets dynamiques",
-	"require" : {}
-}

+ 0 - 315
dashboard/css/main.css

@@ -1,315 +0,0 @@
-/** DASHBOARD **/
-.module-index body{
-    background-color: #f5f5f5;
-}
-/* Conteneur principal du plugin dashboard */
-.dashboard {
-	
-}
-.dashboard-widget-log,.dashboard-widget-log li{
-	list-style-type: none;
-	margin: 0;
-	padding: 5px;
-	border-bottom: 1px solid #f1f1f1;
-}
-.dashboard-widget-log{
-	padding:0 15px 15px 15px;
-}
-.dashboard-widget-log li {
-	font-size: 11px;
-}
-.dashboard-widget-log li >h2{
-	font-size: 14px;
-	margin-top: 15px;
-	padding: 3px 0 3px 0;
-	border-bottom: 2px solid #cecece;
-}
-
-/** DASHBOARD **/
-.widget[data-mandatory] {
-    border-left: 0px;
-}
-
-.widget .readonly-veil{
-	width:100%;
-	height:100%;
-	position:absolute;
-	top:0;
-	left:0;
-	opacity: 0.5;
-	background-color: #ffffff;
-	border-radius: 10px;
-	z-index: 100;
-}
-
-.widget[data-mandatory="1"] .widget_resize,.widget[data-mandatory="1"] .widget_header{
-	cursor: default;
-}
-.widget[data-mandatory="1"] .widget_options{
-	display: none;
-}
-.dashboard-container.readonly .dashboard-widget-menu, .dashboard-container.readonly .widget_options,.dashboard-container.readonly .widget_resize{
-	display: none;
-}
-.dashboard-container.readonly .widget_header{
-	cursor:default;
-}
-#dashboardForm #icon{
-	font-family:"Font Awesome 5 Free";
-}
-#widget-list{
-	width: 100%;
-    display: block;
-    overflow-y: auto;
-    padding: 5px;
-}
-#dashboard{
-	list-style-type:none;
-	margin:0;
-	padding:0;
-}
-#dashboard > li{
-	float:left;
-}
-#dashboard-view{
-	width: 50px;
-    background-color: #343a40;
-    list-style-type: none;
-    color: #505050;
-    margin: 0;
-    padding: 0;
-    min-height: 100%;
-    position: fixed;
-    left: 0;
-    top: 50px;
-    border-top: 4px solid #454a4e;
-}
-#dashboard-view li{
-	cursor:pointer;
-	text-align: center;
-    font-size: 1.3em;
-	transition:background 0.2s ease-in-out;
-}
-#dashboard-view li.dashboard-view-title{
-	color: #cecece;
-    font-size: 11px;
-    cursor: default;
-    background-color: #475058;
-    font-weight: bold;
-}
-#dashboard-view li.dashboard-item{
-	width: 50px;
-	position: relative;
-	padding: 10px;
-	transition: padding-bottom 0.2s ease-in-out;
-}
-#dashboard-view li.dashboard-item > div{
-	padding-top: 0.15rem;
-	display: flex;
-	width: 30px;
-	height: 30px;
-	z-index: 10;
-	background-color: #fafafa;
-	border-radius: 100%;
-	text-align: center;
-	border: 2px solid #fafafa;
-	transition: all 0.2s ease-in-out;
-}
-#dashboard-view li.dashboard-item i {
-	margin: auto;
-    font-size: 0.7em;
-    transition: all 0.2s ease-in-out;
-}
-#dashboard-view li.dashboard-item:hover{
-	padding-bottom: 20px;
-}
-#dashboard-view li.dashboard-item span {
-	transform: translateY(-25px);
-	font-size: 9px;
-	position: absolute;
-	left: 0;
-	bottom: 5px;
-	color: #808a94;
-	text-transform: uppercase;
-	display: block;
-	width: 100%;
-	text-align: center;
-	font-weight: bold;
-	overflow: hidden;
-	text-overflow: ellipsis;
-	opacity: 0;
-	z-index: 1;
-	transition: all 0.2s ease-in-out;
-}
-#dashboard-view li.dashboard-item:hover span {
-	transform: translateX(0px);
-	opacity: 1;
-}
-#dashboard-view li:hover{
-	background-color: #475058;
-	transition:
-		background-color 0.2s ease-in-out,
-		padding-bottom 0.2s ease-in-out;
-}
-#dashboard-view li[data-selected] > div{
-	background-color: #1d1d1d;
-    border-color: #1d1d1d;
-    border-top: 2px solid #dc3545;
-    color: #fafafa;
-}
-.widget_placeholder{
-	display: block;
-	width: auto;
-	background: rgba(0,0,0,0.1);
-	height: 335px;
-	margin-top: 20px;
-	border-radius: 10px;
-    border: 2px dashed #cecece;
-    transition: all 0.2s linear 0s;
-}
-.widget{
-	transition: width 0.2s linear,height 0.2s linear,opacity 0.2s linear;
-	/*display: table;*/
-	padding:20px;
-	transition: transform 0.2s ease-in-out,max-width 0.2s ease-in-out;
-}
-.widget.ui-sortable-helper{
-	transform: scale(1.05);
-}
-.widget_window{
-	border-radius: 10px;
-    box-shadow: 0 0 20px 0 #cecece!important;
-	padding: 0;
-	text-align: left;
-	transition: opacity 0.2s linear 0s;
-	z-index: 100;
-	position: relative;
-}
-.widget_resize{
-	position: absolute;
-	height: 100%;
-	cursor: ew-resize;
-	width:5px;
-	top:0px;
-	right:0px;
-	z-index: 100;
-}
-.widget_header{
-	background-color: #50597b;
-	padding: 5px;
-	border-radius: 10px 10px 0 0;
-	box-sizing: border-box;
-	color: #ffffff;
-	cursor: move;
-	transition:background 0.2s linear;
-}
-.widget_header > i {
-	display: inline-block;
-}
-.widget_options{
-	float: right;
-	margin: -5px 0 0 10px;
-	padding: 0;
-}
-.widget_options li{
-	cursor: pointer;
-	display: inline-block;
-	opacity: 0.5;
-	padding: 5px;
-	transition: opacity 0.2s linear 0s;
-	vertical-align: top;
-}
-.widget_options li:hover{
-	opacity: 1;
-}
-.widget_content{
-	background-color: #ffffff;
-	border-top:0;
-	overflow:auto;
-	border-radius: 0 0 10px 10px;
-	width:100%;
-	height:300px;
-	padding: 0px;
-}
-.widget_content::-webkit-scrollbar {
-	width: 6px;
-	height: 6px;
-}
-.widget_content::-webkit-scrollbar-button {
-	width: 0px;
-	height: 0px;
-}
-.widget_content::-webkit-scrollbar-thumb {
-	background: #cecece;
-	border: 0px none #ffffff;
-	border-radius: 50px;
-}
-.widget_content::-webkit-scrollbar-thumb:hover {
-	background: #707070;
-}
-.widget_content::-webkit-scrollbar-thumb:active {
-	background: #949494;
-}
-.widget_content::-webkit-scrollbar-track {
-	background: transparent;
-	border: 0px none #ffffff;
-	border-radius: 50px;
-}
-.widget_content::-webkit-scrollbar-track:hover {
-	background: #d4d4d4;
-}
-.widget_content::-webkit-scrollbar-track:active {
-	background: #d3d3d3;
-}
-.widget_content::-webkit-scrollbar-corner {
-	background: transparent;
-}
-.dashboard-container{
-	padding: 10px 0 0 0;
-}
-.dashboard-widget-menu{
-	margin: 0 0 0 15px;
-	padding: 0;
-}
-.dashboard-widget-menu li{
-	list-style-type: none;
-	color:#cecece;
-	display: inline-block;
-	cursor: pointer;
-	padding:5px;
-}
-.dashboard-widget-menu li {
-	opacity:0.5;
-	display: inline-block;
-	transition : all 0.2s ease-in-out;
-}
-.dashboard-widget-menu li:hover {
-	opacity:1;
-}
-.widgetDescription{
-	
-}
-.widgetColor{
-	display: inline-block;
-	vertical-align: top;
-	padding-right: 5px;
-	color:#333333;
-}
-.widgetColor small{
-	width:15px;
-	height:15px;
-	border-radius: 100%;
-	display: inline-block;
-	margin-right: 5px;
-	margin-top: 4px;
-	vertical-align: top;
-}
-@media only screen and (max-width: 500px) {
-	.widget_dropper{
-		display: none;
-	}
-	.widget,.widget_window{
-		display: block;
-		width:100%;
-	}
-}

+ 0 - 151
dashboard/css/widget.css

@@ -1,151 +0,0 @@
-.clockContainer .daydate{
-	font-size: 10px;
-}
-.clockContainer{
-	background-color:#343a40;
-	width:100%;
-	height:100%;
-	min-height: 263px;
-	box-sizing:border-box;
-	text-align:center;
-	padding:20px;
-}
-.clock {	
-	height: 200px;
-	width: 200px;
-	margin: 30px auto auto auto;
-	position:relative;
-	background-color:#343a40;
-}
-
-.progress > svg {
-	height: 100%;
-	display: block;
-}
-.progressbar-text{
-	position:absolute;
-	left:0px;
-	top:60px;
-	width:100%;
-	text-align:center;
-	font-weight:200;
-	color:#ffffff!important;
-}
-.progressbar-text .dayName,.progressbar-text .dayDate{
-	font-size:15px;
-	color:#cecece;
-	margin: 10px 0;
-	font-weight:400;
-}
-.progressbar-text .dayName{
-	font-weight:bold;
-	color:#ffffff;
-	margin-top: 0px ;
-}
-
-/* profile widget */
-.profileContainer{
-	padding-bottom: 10px;
-	height:100%;
-	position: relative;
-	text-align: center;
-}
-.profileContainer .profile-buttons{
-    position: absolute;
-    bottom: 10px;
-    width: 100%;
-}
-.profileContainer .profile-buttons a.btn{
-    font-weight: bold;
-    color:#666666;
-    font-size: 12px;
-    padding: 0 .5rem;
-    transition: color 0.2s ease-in-out;
-}
-.profileContainer .profile-buttons a.btn:hover{
-    color: #007bff;
-}
-.profileContainer .profileHeader{
-	background-color: #007bff;
-	/*background-image: url('../img/default-background.jpg');*/
-	border-bottom:5px solid rgba(255, 255, 255,0.5);
-	height:100px;
-	width:100%;
-	background-size: cover;
-    background-image: none; 
-}
-.profileContainer .profileImage{
-	margin-top: -60px;
-	display: block;
-	text-align: center;
-}
-.profileContainer .profileImage > a {
-	border-radius: 120px;
-	position: relative;
-	display: inline-block;
-}
-.profileContainer .profileImage .edit-overlay {
-	opacity: 0;
-	position: absolute;
-	top: 0;
-	transition: all 0.1s ease-in-out;
-}
-.profileContainer .profileImage .edit-overlay:after {
-	content: "\f044";
-	font-family: "Font Awesome 5 Free";
-	font-weight: 400;
-	position: absolute;
-	top: 50%;
-	left: 50%;
-	font-size: 2em;
-	color: grey;
-	transform: translateX(-40%) translateY(-50%);
-}
-.profileContainer .profileImage > a:hover .edit-overlay {
-	opacity: 0.85;
-	background: #dedede;
-}
-.profileContainer .profileImage .edit-overlay,
-.profileContainer .profileImage img {
-    border-radius: 120px;
-    height: 120px;
-    width: 120px;
-    border: 4px solid #ffffff;
-}
-.profileContainer .profileImage img {
-	/*width: auto;*/
-}
-.profileContainer h3{
-    text-align: center;
-    margin-bottom: 0px;
-    font-size: 20px;
-    margin-top: 6px;
-}
-.profileContainer small,
-.profileContainer small *{
-    text-align: center;
-    font-size: 15px;
-    font-style: italic;
-    color:#cecece;
- 
-}
-.profileToken{
-	display: block;
-
-}
-
-.profileToken input{
-	padding: 2px 4px;
-    font-size: 90%;
-    color: #c7254e;
-    background-color: #f9f2f4;
-    border-radius: 4px;
-    border:none;
-    text-align: center;
-}
-
-.widgetHtmlContainer h4.noContent{
-	text-align: center;
-	margin-top: 120px;
-	color:#cecece;
-}

+ 0 - 134
dashboard/dashboard.plugin.php

@@ -1,134 +0,0 @@
-<?php
-//Cette fonction va generer une page quand on clique sur dashboard dans menu
-function dashboard_page(){
-	global $_,$myUser,$conf;
-	if(isset($_['module']) || !$myUser->connected()) return;
-	$page = !isset($_['page']) ? 'home' : $_['page'];
-	$file = __DIR__.SLASH.'page.'.$page.'.php';
-	if(!file_exists($file)) throw new Exception("Page ".$page." inexistante");
-	require_once($file);
-}
-
-//Fonction executée lors de l'activation du plugin
-function dashboard_install($id){
-	if($id != 'fr.core.dashboard') return;
-	global $conf;
-	Entity::install(__DIR__);
-	$conf->put('dashboard_enable_sidebar',1);
-}
-
-//Fonction executée lors de la désactivation du plugin
-function dashboard_uninstall($id){
-	if($id != 'fr.core.dashboard') return;
-	Entity::uninstall(__DIR__);
-}
-
-//Déclaration des sections de droits du plugin
-//Déclaration des sections de droits du plugin
-Right::register('dashboard',array('label'=>'Gestion des droits sur le plugin dashboard'));
-
-
-//Comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-require_once(__DIR__.SLASH.'action.php');
-
-
-//Déclaration du menu de réglages
-function dashboard_menu_setting(&$settingMenu){
-	global  $myUser;
-	
-	if(!$myUser->can('dashboard','configure')) return;
-	$settingMenu[] = array(
-		'sort' =>1,
-		'url' => 'setting.php?section=dashboard',
-		'icon' => 'fas fa-angle-right',
-		'label' => 'Dashboard'
-	);
-}
-
-//Déclaration des pages de réglages
-function dashboard_content_setting(){
-	global $_;
-	$_['section'] = str_replace('..', '', $_['section']);
-
-	if(file_exists(__DIR__.SLASH.'setting.'.$_['section'].'.php'))
-		require_once(__DIR__.SLASH.'setting.'.$_['section'].'.php');
-}
-
-
-
-function dashboard_default_widget(&$widgets){
-	global $myUser;
-	require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-	$modelWidget = new DashboardWidget();
-	$modelWidget->model = 'clock';
-	$modelWidget->title = 'Horloge';
-	$modelWidget->icon = 'far fa-clock';
-	$modelWidget->background = '#212529';
-	$modelWidget->load = 'action.php?action=dashboard_widget_clock_load';
-	$modelWidget->js = [Plugin::url().'/js/progressbar.min.js?v=2',Plugin::url().'/js/widget.js?v=2'];
-	$modelWidget->css = [Plugin::url().'/css/widget.css?v='.time()];
-	$modelWidget->description = "Affiche l'heure en temps réel";
-	$widgets[] = $modelWidget;
-
-	$modelWidget = new DashboardWidget();
-	$modelWidget->model = 'profile';
-	$modelWidget->title = 'Profil';
-	$modelWidget->minWidth = 2;
-	$modelWidget->maxWidth = 4;
-	$modelWidget->icon = 'far fa-user';
-	$modelWidget->background = '#007bff';
-	$modelWidget->load = 'action.php?action=dashboard_widget_profile_load';
-	$modelWidget->js = [Plugin::url().'/js/widget.js?v='.time()];
-	$modelWidget->css = [Plugin::url().'/css/widget.css?v='.time()];
-	$modelWidget->configure = 'action.php?action=dashboard_widget_profile_configure';
-	$modelWidget->configure_callback = 'dashboard_widget_profile_configure_save';
-	$modelWidget->description = "Affiche les informations de profil";
-	$widgets[] = $modelWidget;
-
-	$modelWidget = new DashboardWidget();
-	$modelWidget->model = 'html';
-	$modelWidget->title = 'Texte / Code HTML';
-	$modelWidget->icon = 'fas fa-code';
-	$modelWidget->background = '#686de0';
-	$modelWidget->load = 'action.php?action=dashboard_widget_html_load';
-	$modelWidget->js = [Plugin::url().'/js/widget.js?v='.time()];
-	$modelWidget->css = [Plugin::url().'/css/widget.css?v='.time()];
-	$modelWidget->configure = 'action.php?action=dashboard_widget_html_configure';
-	$modelWidget->configure_callback = 'dashboard_widget_html_configure_save';
-	$modelWidget->description = "Affiche un texte ou un morceau de code html intégré";
-	$widgets[] = $modelWidget;
-
-	$modelWidget = new DashboardWidget();
-	$modelWidget->model = 'log';
-	$modelWidget->title = 'Logs';
-	$modelWidget->defaultWidth = 8;
-	$modelWidget->options[] = array('function'=>'window.location = \'setting.php?section=log\';','icon'=>'fa-eye','title'=>'Voir tous les logs');
-	$modelWidget->icon = 'far fa-comment-dots';
-	$modelWidget->background = '#28a745';
-	$modelWidget->load = 'action.php?action=dashboard_widget_log_load';
-	$modelWidget->js = [Plugin::url().'/js/widget.js?v='.time()];
-	$modelWidget->css = [Plugin::url().'/css/widget.css?v='.time()];
-	$modelWidget->description = "Affiche les informations des 30 derniers logs";
-	if($myUser->can('log','read')) 
-		$widgets[] = $modelWidget;
-}
-
-
-
-//Déclation des assets
-Plugin::addCss("/css/main.css"); 
-Plugin::addJs("/js/main.js"); 
-
-//Mapping hook / fonctions
-Plugin::addHook("install", "dashboard_install");
-Plugin::addHook("uninstall", "dashboard_uninstall"); 
-
-
-Plugin::addHook("page", "dashboard_page");  
-
-Plugin::addHook("menu_setting", "dashboard_menu_setting");    
-Plugin::addHook("content_setting", "dashboard_content_setting");   
-Plugin::addHook("widget", "dashboard_default_widget");
-
-?>

BIN
dashboard/img/default-background.jpg


+ 0 - 525
dashboard/js/main.js

@@ -1,525 +0,0 @@
-//handle target
-var target = false;
-var refreshInterval = null;
-var resizeTarget = false;
-
-//CHARGEMENT DE LA PAGE
-$(function(){
-
-	if($.urlParam('section') == 'list.widget.share') dashboard_widget_share_search();
-	if(($.page()!='' && $.page()!='index') || $.urlParam('module')!=null) return;
-	dashboard_dashboardwidget_search();
-		
-	$('#dashboard-view li').click(function(){
-		$('#dashboard-view li').removeAttr('data-selected');
-		$(this).attr('data-selected',1);
-		dashboard_dashboardwidget_search();
-	});
-	$('#widget-list').change(function(){
-		var option = $('#widget-list option:selected').data();
-		option.text = $('#widget-list option:selected').text();
-
-		var description = $('.widgetDescription');
-		description.removeClass('hidden');
-		$('h3 span', description).text($(this).val() == '' ? 'Sélectionnez un widget' : option.text);
-		$('h3 i', description).attr('class',option.icon);
-		$('p', description).text(option.description);
-		$('.widgetWidth', description).html(option.width=='' ? '' : '<span class="text-muted font-weight-bold mr-2">LARGEUR</span> '+Math.round(option.width*100 /12)+'%');
-		$('.widgetColor', description).html(option.background=='' ? '' : '<span class="text-muted font-weight-bold  mr-2">COULEUR</span> <small style="background-color:'+option.background+'"></small><span>'+option.background+'</span>   ');
-	});
-
-	if(!$('.dashboard-container').hasClass('readonly')){
-		$('#dashboard').sortable({
-			distance: 15,
-			cancel :'[data-mandatory="1"]',
-			tolerance: "pointer",
-			handle: ".widget_header",
-			opacity: 0.8,
-			placeholder: {
-				element: function(clone, ui) {
-					var classes = clone.attr('class').split(' ');
-					for(var key in classes){
-						var number = classes[key].match(/col-xl-([0-9])/i);
-						if(number != null)
-							colSize = number[1] > 9 ? 9 : number[1];
-					}
-	                return $('<div class="ui_sortable_placeholder widget_placeholder col-xl-'+colSize+' col-md-'+colSize*2+' col-lg-'+colSize*2+'"></div>');
-	            },
-	            update: function() {
-	                return;
-	            }
-			},
-			update:function(event,ui){
-				var data = dashboard_dashboardwidget_save_position();
-			}
-		});
-		$( ".widget" ).disableSelection();
-	}
-});
-
-
-function init_setting_dashboard(){
-	dashboard_dashboard_search();
-	dashboard_widget_share_search();
-}
-
-//Enregistrement des configurations
-function dashboard_setting_save(){
-	$.action({ 
-		action : 'dashboard_setting_save', 
-		fields :  $('#dashboard-setting-form').toJson() 
-	},function(){
-		$.message('success','Enregistré');
-	});
-}
-
-
-/** DASHBOARD **/
-//Récuperation d'une liste de dashboard dans le tableau #dashboards
-function dashboard_dashboard_search(callback){
-	$('#dashboards').fill({
-		action:'dashboard_dashboard_search'
-	},function(){
-		if(callback!=null) callback();
-	});
-}
-
-//Ajout ou modification d'élément dashboard
-function dashboard_dashboard_save(){
-	var form = $('#dashboard-form');
-	var data = form.toJson();
-
-	$.action(data,function(r){
-		form.attr('data-id','');
-		reset_inputs(form);
-		$('#icon').val('far fa-bookmark');
-		init_components(form);
-		
-		$.message('success','Enregistré');
-		
-		dashboard_dashboard_search();
-	});
-}
-
-//Récuperation ou edition d'élément dashboard
-function dashboard_dashboard_edit(element){
-	var line = $(element).closest('tr');
-
-	$.action({
-		action:'dashboard_dashboard_edit',
-		id:line.attr('data-id')
-	},function(r){
-		$.setForm('#dashboard-form',r);
-		$('#dashboard-form').attr('data-id',r.id);
-		init_components('#dashboard-form');
-	});
-}
-
-//Suppression d'élement dashboard
-function dashboard_dashboard_delete(element){
-	if(!confirm('Êtes-vous sûr de vouloir supprimer ce dashboard ?')) return;
-	var line = $(element).closest('tr');
-
-	$.action({
-		action : 'dashboard_dashboard_delete',
-		id : line.attr('data-id')
-	},function(r){
-		line.remove();
-		$.message('info','Dashboard supprimé');
-	});
-}
-
-/** DASHBOARDWIDGET **/
-function configure_widget(element){
-	var widget = $(element).closest('.widget');
-	var configureUrl = widget.attr('data-configure');
-	
-	if(configureUrl.substring(0,11) == 'setting.php'){
-		window.open(configureUrl); 
-	}else{
-		var modal = $('#configureWidgetModal');
-		modal.attr('data-widget',widget.attr('data-id')).modal('show');
-		$('.pluginContent', modal).load(widget.attr('data-configure'),{
-			id : widget.attr('data-id')
-		},function(){
-			init_components();
-			var callback = widget.attr('data-configure-init');
-			if(window[callback]!=null) window[callback](widget,modal);
-		});
-	}
-}
-
-function dashboard_dashboardwidget_save_configuration(){
-	var modal = $('#configureWidgetModal');
-	var widget = $('.widget[data-id="'+modal.attr('data-widget')+'"]');
-
-	modal.modal('hide');
-	
-	var callback = widget.attr('data-configure-callback');
-	if(window[callback]!=null) window[callback](widget,modal);
-}
-
-
-//Récuperation d'une liste de dashboardwidget dans le tableau #dashboardwidgets
-function dashboard_dashboardwidget_search(callback){
-	var dashboard = $('#dashboard-view li[data-selected]').attr('data-id');
-	if(!dashboard || dashboard=='') return;
-	$.action({
-		action : 'dashboard_dashboardwidget_search',
-		dashboard : dashboard
-	},function(r){
-		$('#dashboard .widget:visible').remove();
-
-		for(var i in r.rows){
-			var widget = r.rows[i];
-			dashboard_dashboardwidget_append(widget,function(widget){
-				dashboard_dashboardwidget_load(widget);
-			});
-		}
-		clearInterval(refreshInterval);
-		refreshInterval = setInterval(function(){
-			dashboard_dashboardwidget_refresh();
-		},3000);
-
-		if(!$('.dashboard-container').hasClass('readonly')){
-			//Gestion du resize de largeur
-			$('.widget_resize').draggable({
-				axis: "x",
-				cancel :'[data-mandatory="1"]',
-				start : function(event,ui){
-					var widget = ui.helper.closest('.widget');
-					$('.widget_content',widget).append('<div class="readonly-veil"></div>');
-				},
-				drag: function(event,ui) {
-					var widget = ui.helper.closest('.widget');
-				    var width = widget.attr('data-width');
-				    var percent = ui.position.left * 100 / ui.originalPosition.left;
-				    var newWidth = Math.round(width * percent/100);
-				    newWidth = newWidth<1 ? 1 : newWidth;
-				    newWidth = newWidth>12 ? 12 : newWidth;
-
-				    //Gestion taille widget max
-				    if(widget.attr('data-maxWidth') && widget.attr('data-maxWidth').length){
-				    	maxWidth = widget.attr('data-maxWidth');
-					    newWidth = newWidth>maxWidth ? maxWidth : newWidth;
-				    }
-				    //Gestion taille widget min
-			        if(widget.attr('data-minWidth') && widget.attr('data-minWidth').length){
-			        	minWidth = widget.attr('data-minWidth');
-					    newWidth = newWidth<minWidth ? minWidth : newWidth;
-			        }
-	
-				    widget.removeClass('col-xl-1 col-xl-2 col-xl-3 col-xl-4 col-xl-5 col-xl-6 col-xl-7 col-xl-8 col-xl-9 col-xl-10 col-xl-11 col-xl-12');
-				    widget.addClass('col-xl-'+newWidth);
-
-				    widget.removeClass('col-lg-1 col-lg-2 col-lg-3 col-lg-4 col-lg-5 col-lg-6 col-lg-7 col-lg-8 col-lg-9 col-lg-10 col-lg-11 col-lg-12');
-				    widget.addClass('col-lg-'+newWidth*2);
-
-				    widget.removeClass('col-md-1 col-md-2 col-md-3 col-md-4 col-md-5 col-md-6 col-md-7 col-md-8 col-md-9 col-md-10 col-md-11 col-md-12');
-				    widget.addClass('col-md-'+newWidth*2);
-	
-				},
-				stop: function(event,ui){
-					var resizebar = ui.helper;
-					var widget = resizebar.closest('.widget');
-					$('.widget .readonly-veil').remove();
-					var width = widget.attr('data-width');
-					var newWidth = widget.attr('class').match(/col-xl-([0-9]*)/)
-					newWidth = newWidth[1];
-					
-					if(newWidth!=width){
-					    $.action({
-							action : 'dashboard_dashboardwidget_resize',
-							widget : widget.attr('data-id'),
-							width: newWidth
-						},function(r){
-							widget.attr('data-width',newWidth);
-							
-						});
-					}
-					resizebar.removeAttr('style');
-				}
-			});
-		}
-	});
-}
-
-function dashboard_dashboardwidget_refresh(){
-	$.action({
-		action : 'dashboard_dashboardwidget_refresh',
-		dashboard : $('#dashboard-view li[data-selected]').attr('data-id')
-	},function(r){
-
-		for(var id in r.rows){
-			var widget = r.rows[id];
-
-			if(widget.widget){
-				var header = $('.widget[data-id="'+id+'"]').find('.widget_header'); 
-				if(widget.widget.title) header.find('span').text(widget.widget.title);
-				if(widget.widget.icon) header.find('i').attr('class','fa '+widget.widget.icon);
-				if(widget.widget.background) header.css('backgroundColor',widget.widget.background);
-			}
-
-			if(widget.callback){
-				if(window[widget.callback]!=null) window[widget.callback]($('.widget[data-id="'+id+'"]'),widget.data);
-			}
-			
-		}
-	});
-}
-
-//Mise à jour des infos d'un élement widget à partir d'un object data
-function dashboard_dashboardwidget_render(widget,data){
-	widget.attr('data-id',data.id);
-	widget.removeClass (function (index, css) {
-		return (css.match (/(^|\s)col-xl-\S+/g) || []).join(' ');
-	});
-	var width = data.width!=0 ? data.width : data.defaultWidth; 
-
-	widget.attr('data-id',data.id)
-		.attr('data-load',data.load)
-		.attr('data-configure',data.configure)
-		.attr('data-configure-callback',data.configure_callback)
-		.attr('data-configure-init',data.configure_init)
-		.attr('data-delete',data.delete)
-		.attr('data-mandatory',data.mandatory && data.mandatory==1 ?1:0)
-		.attr('data-model',data.model)
-		.attr('data-width',width)
-		.addClass('col-xl-'+width)
-		.addClass('col-lg-'+width*2)
-		.addClass('col-md-'+width*2)
-		.find('.widget_header')
-		.css('background',data.background)
-		.find('i:eq(0)').attr('class',data.icon);
-
-	if(data.minWidth && data.minWidth!=0) widget.attr('data-minWidth', data.minWidth);
-	if(data.maxWidth && data.maxWidth!=0) widget.attr('data-maxWidth', data.maxWidth);
-
-	widget.find('.widget_header span:eq(0)').html(data.title);
-	widget.find('.widget_content').html(data.content);
-		
-	var options = '';
-	for(var k in data.options){
-		var option = data.options[k];
-		options+='<li onclick="'+option.function+'" '+(option.title ? 'title="'+option.title+'"':'')+'><i class="fa '+option.icon+'"></i> '+(option.label ? option.label:'')+'</li>';
-	}
-	if(data.configure) options+="<li title='Configurer' onclick='configure_widget(this);'><i class='fa fa-wrench'></i></li>";
-	options+="<li title='Supprimer' onclick='dashboard_dashboardwidget_delete(this);'><i class='fa fa-times'></i></li>";
-
-	widget.find('.widget_options').html(options);
-	widget.data('data',data);
-	widget.removeClass('hidden');
-
-	return widget;
-}
-
-//Modification d'un widget existant
-function dashboard_dashboardwidget_update(data){
-	var widget = $('.widget[data-id="'+data.id+'"]');
-	var data = $.extend(widget.data('data'), data);
-	dashboard_dashboardwidget_render(widget,data);
-}
-
-//Ajout ou modification d'élément dashboardwidget
-function dashboard_dashboardwidget_save(){
-	var data = $('#dashboardwidget-form').toJson();
-	$.action(data,function(r){
-		$('#dashboardwidget-form').attr('data-id','');
-		dashboard_dashboardwidget_search();
-		$.message('success','Enregistré');
-	});
-}
-
-//Chargement du contenu php du widget
-function dashboard_dashboardwidget_load(widget){
-	
-	$.getJSON(widget.load,{
-		id : widget.id,
-		model : widget.model,
-		content:'',
-	},function(r){
-		if(r.error && r.error.code == 403){
-			$('.widget[data-id="'+widget.id+'"]').remove();
-			return;
-		}
-		dashboard_dashboardwidget_update(r);
-		var data = $.extend($('.widget[data-id="'+widget.id+'"]').data('data'), r.widget);
-
-		var init = 'widget_'+data.model.replace(/[^a-z0-9]/i,'_')+'_init';
-		if(window[init]!=null) window[init]();
-	});
-}
-
-//Ajout (manuel par l'user) d'un widget
-function dashboard_dashboardwidget_add(){
-	$.action({
-		action : 'dashboard_dashboardwidget_add',
-		dashboard : $('#dashboard-view li[data-selected]').attr('data-id'),
-		widget : $('#widget-list').val()
-	},function(r){
-		if(r.message) $.message('info',r.message);
-		$('#dashboard_dashboardwidget_appendModal').modal('hide');
-		dashboard_dashboardwidget_search();
-	});
-}
-
-//Ajout (depuis le code) d'un widget
-function dashboard_dashboardwidget_append(data,callback){
-	var tpl = $('#dashboard .widget:hidden').get(0).outerHTML;
-	var widget = $(tpl);
-	$('#dashboard').append(widget);
-	if(data.css!=null){
-		for(k in data.css){
-			var css = data.css[k];
-			if($('link[href="'+css+'"]').length!=0) continue;
-
-			//on supprime tout autre css ayant la même base mais des versions plus vielles
-			var baseCss = css.replace(/\?v=.*/gm,'');
-			$('link[href^="'+baseCss+'"]').remove();
-
-			var cssFile = document.createElement('link');
-			cssFile.setAttribute("rel","stylesheet");
-			cssFile.setAttribute("type","text/css");
-			cssFile.setAttribute("href", css);
-			document.getElementsByTagName("body")[0].appendChild(cssFile);
-		}
-	}
-	dashboard_dashboardwidget_render(widget,data);
-	if(data.js!=null){
-		dashboard_load_js(data.js,0,function(){
-			if(callback) callback(data);
-		});
-	}else{
-		if(callback) callback(data);
-	}
-	
-	
-}
-
-function dashboard_load_js(files,iteration,callback){
-	var js = files[iteration];
-
-	if($('script[src="'+js+'"]').length!=0 || js==null) {
-		if(files.length > iteration) dashboard_load_js(files,iteration+1,callback);
-		if((files.length-1) == iteration) if(callback) callback();
-		return;
-	}
-	//on supprime tout autre js ayant la même base mais des versions plus vielles
-	var baseJs = js.replace(/\?v=.*/gm,'');
-	$('script[src^="'+baseJs+'?"]').remove();
-
-	var jsFile = document.createElement('script');
-	jsFile.setAttribute("type","text/javascript");
-	document.getElementsByTagName("body")[0].appendChild(jsFile);
-	jsFile.onload = function() {
-		if(files.length > iteration) dashboard_load_js(files,iteration+1,callback);
-		if((files.length-1) == iteration) if(callback) callback();
-	};
-	jsFile.src =  js;
-}
-
-//Récuperation ou edition d'élément dashboardwidget
-function dashboard_dashboardwidget_edit(widget){
-	var line = $(element).closest('tr');
-	$.action({action:'dashboard_dashboardwidget_edit',id:line.attr('data-id')},function(r){
-		$.setForm('#dashboardwidget-form',r);
-		$('#dashboardwidget-form').attr('data-id',r.id);
-	});
-}
-
-//Suppression d'élement dashboardwidget
-function dashboard_dashboardwidget_delete(element){
-	var element = $(element).closest('.widget');
-	var data = element.data('data');
-	
-	$.action({
-		action : 'dashboard_dashboardwidget_delete',
-		dashboard : $('#dashboard-view li[data-selected]').attr('data-id'),
-		widget : data.id,
-	},function(r){
-		element.remove();
-		if(r.message) $.message('info',r.message);
-		else $.message('info', 'Widget supprimé');
-		if(data.delete != null){
-			$.getJSON(data.delete,$.extend(data,{content:''}));
-		}
-	});
-}
-
-
-
-//Enregistrement de toutes les positions de widget
-function dashboard_dashboardwidget_save_position(){
-	var positions = [];
-	$('.widget:visible').each(function(i,element){
-		positions.push({id:$(element).attr('data-id'),position:$(element).index()});
-	});
-	
-	$.action({
-		action : 'dashboard_dashboardwidget_save_position',
-		dashboard : $('#dashboard-view li[data-selected]').attr('data-id'),
-		positions : positions,
-	},function(r){
-		
-	});
-
-}
-
-
-/** DASHBOARDWIDGETSHARE **/
-//Récuperation d'une liste de dashboardwidgetshare dans le tableau #dashboardwidgetshares
-function dashboard_widget_share_search(callback){
-	$('#dashboard-widget-shares').fill({
-		action: 'dashboard_widget_share_search'
-	},function(response){
-		if(callback!=null) callback();
-	});
-}
-
-//Ajout ou modification d'élément dashboardwidgetshare
-function dashboard_widget_share_save(){
-	var data = $('#dashboard-widget-share-form').toJson();
-	var target = $('#uid').data('values');
-
-	if(target){
-		data.entity = target[0].entity;
-		data.uid = target[0].uid;
-	}
-
-	$.action(data,function(r){
-		$('#dashboard-widget-share-form').attr('data-id','');
-		$('#dashboard-widget-share-form').clear();
-		dashboard_widget_share_search();
-		
-		$.message('success','Enregistré');
-	});
-}
-
-
-//Récuperation ou edition d'élément dashboardwidgetshare
-function dashboard_widget_share_edit(element){
-	var line = $(element).closest('tr');
-
-	$.action({
-		action: 'dashboard_widget_share_edit',
-		id: line.attr('data-id')
-	},function(r){
-		$.setForm('#dashboard-widget-share-form',r);
-		init_components('#dashboard-widget-share-form');
-		$('#dashboard-widget-share-form').attr('data-id',r.id);
-	});
-}
-
-//Suppression d'élement dashboardwidgetshare
-function dashboard_widget_share_delete(element){
-	if(!confirm('Êtes vous sûr de vouloir supprimer cet item ?')) return;
-	var line = $(element).closest('tr');
-	
-	$.action({
-		action: 'dashboard_widget_share_delete',
-		id: line.attr('data-id')
-	},function(r){
-		line.remove();
-		$.message('info','Item supprimé');
-	});
-}

+ 0 - 2433
dashboard/js/progressbar.js

@@ -1,2433 +0,0 @@
-// ProgressBar.js 1.0.1
-// https://kimmobrunfeldt.github.io/progressbar.js
-// License: MIT
-
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ProgressBar = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-/* shifty - v1.5.2 - 2016-02-10 - http://jeremyckahn.github.io/shifty */
-;(function () {
-  var root = this || Function('return this')();
-
-/**
- * Shifty Core
- * By Jeremy Kahn - jeremyckahn@gmail.com
- */
-
-var Tweenable = (function () {
-
-  'use strict';
-
-  // Aliases that get defined later in this function
-  var formula;
-
-  // CONSTANTS
-  var DEFAULT_SCHEDULE_FUNCTION;
-  var DEFAULT_EASING = 'linear';
-  var DEFAULT_DURATION = 500;
-  var UPDATE_TIME = 1000 / 60;
-
-  var _now = Date.now
-       ? Date.now
-       : function () {return +new Date();};
-
-  var now = typeof SHIFTY_DEBUG_NOW !== 'undefined' ? SHIFTY_DEBUG_NOW : _now;
-
-  if (typeof window !== 'undefined') {
-    // requestAnimationFrame() shim by Paul Irish (modified for Shifty)
-    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
-    DEFAULT_SCHEDULE_FUNCTION = window.requestAnimationFrame
-       || window.webkitRequestAnimationFrame
-       || window.oRequestAnimationFrame
-       || window.msRequestAnimationFrame
-       || (window.mozCancelRequestAnimationFrame
-       && window.mozRequestAnimationFrame)
-       || setTimeout;
-  } else {
-    DEFAULT_SCHEDULE_FUNCTION = setTimeout;
-  }
-
-  function noop () {
-    // NOOP!
-  }
-
-  /**
-   * Handy shortcut for doing a for-in loop. This is not a "normal" each
-   * function, it is optimized for Shifty.  The iterator function only receives
-   * the property name, not the value.
-   * @param {Object} obj
-   * @param {Function(string)} fn
-   * @private
-   */
-  function each (obj, fn) {
-    var key;
-    for (key in obj) {
-      if (Object.hasOwnProperty.call(obj, key)) {
-        fn(key);
-      }
-    }
-  }
-
-  /**
-   * Perform a shallow copy of Object properties.
-   * @param {Object} targetObject The object to copy into
-   * @param {Object} srcObject The object to copy from
-   * @return {Object} A reference to the augmented `targetObj` Object
-   * @private
-   */
-  function shallowCopy (targetObj, srcObj) {
-    each(srcObj, function (prop) {
-      targetObj[prop] = srcObj[prop];
-    });
-
-    return targetObj;
-  }
-
-  /**
-   * Copies each property from src onto target, but only if the property to
-   * copy to target is undefined.
-   * @param {Object} target Missing properties in this Object are filled in
-   * @param {Object} src
-   * @private
-   */
-  function defaults (target, src) {
-    each(src, function (prop) {
-      if (typeof target[prop] === 'undefined') {
-        target[prop] = src[prop];
-      }
-    });
-  }
-
-  /**
-   * Calculates the interpolated tween values of an Object for a given
-   * timestamp.
-   * @param {Number} forPosition The position to compute the state for.
-   * @param {Object} currentState Current state properties.
-   * @param {Object} originalState: The original state properties the Object is
-   * tweening from.
-   * @param {Object} targetState: The destination state properties the Object
-   * is tweening to.
-   * @param {number} duration: The length of the tween in milliseconds.
-   * @param {number} timestamp: The UNIX epoch time at which the tween began.
-   * @param {Object} easing: This Object's keys must correspond to the keys in
-   * targetState.
-   * @private
-   */
-  function tweenProps (forPosition, currentState, originalState, targetState,
-    duration, timestamp, easing) {
-    var normalizedPosition =
-        forPosition < timestamp ? 0 : (forPosition - timestamp) / duration;
-
-
-    var prop;
-    var easingObjectProp;
-    var easingFn;
-    for (prop in currentState) {
-      if (currentState.hasOwnProperty(prop)) {
-        easingObjectProp = easing[prop];
-        easingFn = typeof easingObjectProp === 'function'
-          ? easingObjectProp
-          : formula[easingObjectProp];
-
-        currentState[prop] = tweenProp(
-          originalState[prop],
-          targetState[prop],
-          easingFn,
-          normalizedPosition
-        );
-      }
-    }
-
-    return currentState;
-  }
-
-  /**
-   * Tweens a single property.
-   * @param {number} start The value that the tween started from.
-   * @param {number} end The value that the tween should end at.
-   * @param {Function} easingFunc The easing curve to apply to the tween.
-   * @param {number} position The normalized position (between 0.0 and 1.0) to
-   * calculate the midpoint of 'start' and 'end' against.
-   * @return {number} The tweened value.
-   * @private
-   */
-  function tweenProp (start, end, easingFunc, position) {
-    return start + (end - start) * easingFunc(position);
-  }
-
-  /**
-   * Applies a filter to Tweenable instance.
-   * @param {Tweenable} tweenable The `Tweenable` instance to call the filter
-   * upon.
-   * @param {String} filterName The name of the filter to apply.
-   * @private
-   */
-  function applyFilter (tweenable, filterName) {
-    var filters = Tweenable.prototype.filter;
-    var args = tweenable._filterArgs;
-
-    each(filters, function (name) {
-      if (typeof filters[name][filterName] !== 'undefined') {
-        filters[name][filterName].apply(tweenable, args);
-      }
-    });
-  }
-
-  var timeoutHandler_endTime;
-  var timeoutHandler_currentTime;
-  var timeoutHandler_isEnded;
-  var timeoutHandler_offset;
-  /**
-   * Handles the update logic for one step of a tween.
-   * @param {Tweenable} tweenable
-   * @param {number} timestamp
-   * @param {number} delay
-   * @param {number} duration
-   * @param {Object} currentState
-   * @param {Object} originalState
-   * @param {Object} targetState
-   * @param {Object} easing
-   * @param {Function(Object, *, number)} step
-   * @param {Function(Function,number)}} schedule
-   * @param {number=} opt_currentTimeOverride Needed for accurate timestamp in
-   * Tweenable#seek.
-   * @private
-   */
-  function timeoutHandler (tweenable, timestamp, delay, duration, currentState,
-    originalState, targetState, easing, step, schedule,
-    opt_currentTimeOverride) {
-
-    timeoutHandler_endTime = timestamp + delay + duration;
-
-    timeoutHandler_currentTime =
-    Math.min(opt_currentTimeOverride || now(), timeoutHandler_endTime);
-
-    timeoutHandler_isEnded =
-      timeoutHandler_currentTime >= timeoutHandler_endTime;
-
-    timeoutHandler_offset = duration - (
-      timeoutHandler_endTime - timeoutHandler_currentTime);
-
-    if (tweenable.isPlaying()) {
-      if (timeoutHandler_isEnded) {
-        step(targetState, tweenable._attachment, timeoutHandler_offset);
-        tweenable.stop(true);
-      } else {
-        tweenable._scheduleId =
-          schedule(tweenable._timeoutHandler, UPDATE_TIME);
-
-        applyFilter(tweenable, 'beforeTween');
-
-        // If the animation has not yet reached the start point (e.g., there was
-        // delay that has not yet completed), just interpolate the starting
-        // position of the tween.
-        if (timeoutHandler_currentTime < (timestamp + delay)) {
-          tweenProps(1, currentState, originalState, targetState, 1, 1, easing);
-        } else {
-          tweenProps(timeoutHandler_currentTime, currentState, originalState,
-            targetState, duration, timestamp + delay, easing);
-        }
-
-        applyFilter(tweenable, 'afterTween');
-
-        step(currentState, tweenable._attachment, timeoutHandler_offset);
-      }
-    }
-  }
-
-
-  /**
-   * Creates a usable easing Object from a string, a function or another easing
-   * Object.  If `easing` is an Object, then this function clones it and fills
-   * in the missing properties with `"linear"`.
-   * @param {Object.<string|Function>} fromTweenParams
-   * @param {Object|string|Function} easing
-   * @return {Object.<string|Function>}
-   * @private
-   */
-  function composeEasingObject (fromTweenParams, easing) {
-    var composedEasing = {};
-    var typeofEasing = typeof easing;
-
-    if (typeofEasing === 'string' || typeofEasing === 'function') {
-      each(fromTweenParams, function (prop) {
-        composedEasing[prop] = easing;
-      });
-    } else {
-      each(fromTweenParams, function (prop) {
-        if (!composedEasing[prop]) {
-          composedEasing[prop] = easing[prop] || DEFAULT_EASING;
-        }
-      });
-    }
-
-    return composedEasing;
-  }
-
-  /**
-   * Tweenable constructor.
-   * @class Tweenable
-   * @param {Object=} opt_initialState The values that the initial tween should
-   * start at if a `from` object is not provided to `{{#crossLink
-   * "Tweenable/tween:method"}}{{/crossLink}}` or `{{#crossLink
-   * "Tweenable/setConfig:method"}}{{/crossLink}}`.
-   * @param {Object=} opt_config Configuration object to be passed to
-   * `{{#crossLink "Tweenable/setConfig:method"}}{{/crossLink}}`.
-   * @module Tweenable
-   * @constructor
-   */
-  function Tweenable (opt_initialState, opt_config) {
-    this._currentState = opt_initialState || {};
-    this._configured = false;
-    this._scheduleFunction = DEFAULT_SCHEDULE_FUNCTION;
-
-    // To prevent unnecessary calls to setConfig do not set default
-    // configuration here.  Only set default configuration immediately before
-    // tweening if none has been set.
-    if (typeof opt_config !== 'undefined') {
-      this.setConfig(opt_config);
-    }
-  }
-
-  /**
-   * Configure and start a tween.
-   * @method tween
-   * @param {Object=} opt_config Configuration object to be passed to
-   * `{{#crossLink "Tweenable/setConfig:method"}}{{/crossLink}}`.
-   * @chainable
-   */
-  Tweenable.prototype.tween = function (opt_config) {
-    if (this._isTweening) {
-      return this;
-    }
-
-    // Only set default config if no configuration has been set previously and
-    // none is provided now.
-    if (opt_config !== undefined || !this._configured) {
-      this.setConfig(opt_config);
-    }
-
-    this._timestamp = now();
-    this._start(this.get(), this._attachment);
-    return this.resume();
-  };
-
-  /**
-   * Configure a tween that will start at some point in the future.
-   *
-   * @method setConfig
-   * @param {Object} config The following values are valid:
-   * - __from__ (_Object=_): Starting position.  If omitted, `{{#crossLink
-   *   "Tweenable/get:method"}}get(){{/crossLink}}` is used.
-   * - __to__ (_Object=_): Ending position.
-   * - __duration__ (_number=_): How many milliseconds to animate for.
-   * - __delay__ (_delay=_): How many milliseconds to wait before starting the
-   *   tween.
-   * - __start__ (_Function(Object, *)_): Function to execute when the tween
-   *   begins.  Receives the state of the tween as the first parameter and
-   *   `attachment` as the second parameter.
-   * - __step__ (_Function(Object, *, number)_): Function to execute on every
-   *   tick.  Receives `{{#crossLink
-   *   "Tweenable/get:method"}}get(){{/crossLink}}` as the first parameter,
-   *   `attachment` as the second parameter, and the time elapsed since the
-   *   start of the tween as the third. This function is not called on the
-   *   final step of the animation, but `finish` is.
-   * - __finish__ (_Function(Object, *)_): Function to execute upon tween
-   *   completion.  Receives the state of the tween as the first parameter and
-   *   `attachment` as the second parameter.
-   * - __easing__ (_Object.<string|Function>|string|Function=_): Easing curve
-   *   name(s) or function(s) to use for the tween.
-   * - __attachment__ (_*_): Cached value that is passed to the
-   *   `step`/`start`/`finish` methods.
-   * @chainable
-   */
-  Tweenable.prototype.setConfig = function (config) {
-    config = config || {};
-    this._configured = true;
-
-    // Attach something to this Tweenable instance (e.g.: a DOM element, an
-    // object, a string, etc.);
-    this._attachment = config.attachment;
-
-    // Init the internal state
-    this._pausedAtTime = null;
-    this._scheduleId = null;
-    this._delay = config.delay || 0;
-    this._start = config.start || noop;
-    this._step = config.step || noop;
-    this._finish = config.finish || noop;
-    this._duration = config.duration || DEFAULT_DURATION;
-    this._currentState = shallowCopy({}, config.from) || this.get();
-    this._originalState = this.get();
-    this._targetState = shallowCopy({}, config.to) || this.get();
-
-    var self = this;
-    this._timeoutHandler = function () {
-      timeoutHandler(self,
-        self._timestamp,
-        self._delay,
-        self._duration,
-        self._currentState,
-        self._originalState,
-        self._targetState,
-        self._easing,
-        self._step,
-        self._scheduleFunction
-      );
-    };
-
-    // Aliases used below
-    var currentState = this._currentState;
-    var targetState = this._targetState;
-
-    // Ensure that there is always something to tween to.
-    defaults(targetState, currentState);
-
-    this._easing = composeEasingObject(
-      currentState, config.easing || DEFAULT_EASING);
-
-    this._filterArgs =
-      [currentState, this._originalState, targetState, this._easing];
-
-    applyFilter(this, 'tweenCreated');
-    return this;
-  };
-
-  /**
-   * @method get
-   * @return {Object} The current state.
-   */
-  Tweenable.prototype.get = function () {
-    return shallowCopy({}, this._currentState);
-  };
-
-  /**
-   * @method set
-   * @param {Object} state The current state.
-   */
-  Tweenable.prototype.set = function (state) {
-    this._currentState = state;
-  };
-
-  /**
-   * Pause a tween.  Paused tweens can be resumed from the point at which they
-   * were paused.  This is different from `{{#crossLink
-   * "Tweenable/stop:method"}}{{/crossLink}}`, as that method
-   * causes a tween to start over when it is resumed.
-   * @method pause
-   * @chainable
-   */
-  Tweenable.prototype.pause = function () {
-    this._pausedAtTime = now();
-    this._isPaused = true;
-    return this;
-  };
-
-  /**
-   * Resume a paused tween.
-   * @method resume
-   * @chainable
-   */
-  Tweenable.prototype.resume = function () {
-    if (this._isPaused) {
-      this._timestamp += now() - this._pausedAtTime;
-    }
-
-    this._isPaused = false;
-    this._isTweening = true;
-
-    this._timeoutHandler();
-
-    return this;
-  };
-
-  /**
-   * Move the state of the animation to a specific point in the tween's
-   * timeline.  If the animation is not running, this will cause the `step`
-   * handlers to be called.
-   * @method seek
-   * @param {millisecond} millisecond The millisecond of the animation to seek
-   * to.  This must not be less than `0`.
-   * @chainable
-   */
-  Tweenable.prototype.seek = function (millisecond) {
-    millisecond = Math.max(millisecond, 0);
-    var currentTime = now();
-
-    if ((this._timestamp + millisecond) === 0) {
-      return this;
-    }
-
-    this._timestamp = currentTime - millisecond;
-
-    if (!this.isPlaying()) {
-      this._isTweening = true;
-      this._isPaused = false;
-
-      // If the animation is not running, call timeoutHandler to make sure that
-      // any step handlers are run.
-      timeoutHandler(this,
-        this._timestamp,
-        this._delay,
-        this._duration,
-        this._currentState,
-        this._originalState,
-        this._targetState,
-        this._easing,
-        this._step,
-        this._scheduleFunction,
-        currentTime
-      );
-
-      this.pause();
-    }
-
-    return this;
-  };
-
-  /**
-   * Stops and cancels a tween.
-   * @param {boolean=} gotoEnd If `false` or omitted, the tween just stops at
-   * its current state, and the `finish` handler is not invoked.  If `true`,
-   * the tweened object's values are instantly set to the target values, and
-   * `finish` is invoked.
-   * @method stop
-   * @chainable
-   */
-  Tweenable.prototype.stop = function (gotoEnd) {
-    this._isTweening = false;
-    this._isPaused = false;
-    this._timeoutHandler = noop;
-
-    (root.cancelAnimationFrame            ||
-    root.webkitCancelAnimationFrame     ||
-    root.oCancelAnimationFrame          ||
-    root.msCancelAnimationFrame         ||
-    root.mozCancelRequestAnimationFrame ||
-    root.clearTimeout)(this._scheduleId);
-
-    if (gotoEnd) {
-      applyFilter(this, 'beforeTween');
-      tweenProps(
-        1,
-        this._currentState,
-        this._originalState,
-        this._targetState,
-        1,
-        0,
-        this._easing
-      );
-      applyFilter(this, 'afterTween');
-      applyFilter(this, 'afterTweenEnd');
-      this._finish.call(this, this._currentState, this._attachment);
-    }
-
-    return this;
-  };
-
-  /**
-   * @method isPlaying
-   * @return {boolean} Whether or not a tween is running.
-   */
-  Tweenable.prototype.isPlaying = function () {
-    return this._isTweening && !this._isPaused;
-  };
-
-  /**
-   * Set a custom schedule function.
-   *
-   * If a custom function is not set,
-   * [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame)
-   * is used if available, otherwise
-   * [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)
-   * is used.
-   * @method setScheduleFunction
-   * @param {Function(Function,number)} scheduleFunction The function to be
-   * used to schedule the next frame to be rendered.
-   */
-  Tweenable.prototype.setScheduleFunction = function (scheduleFunction) {
-    this._scheduleFunction = scheduleFunction;
-  };
-
-  /**
-   * `delete` all "own" properties.  Call this when the `Tweenable` instance
-   * is no longer needed to free memory.
-   * @method dispose
-   */
-  Tweenable.prototype.dispose = function () {
-    var prop;
-    for (prop in this) {
-      if (this.hasOwnProperty(prop)) {
-        delete this[prop];
-      }
-    }
-  };
-
-  /**
-   * Filters are used for transforming the properties of a tween at various
-   * points in a Tweenable's life cycle.  See the README for more info on this.
-   * @private
-   */
-  Tweenable.prototype.filter = {};
-
-  /**
-   * This object contains all of the tweens available to Shifty.  It is
-   * extensible - simply attach properties to the `Tweenable.prototype.formula`
-   * Object following the same format as `linear`.
-   *
-   * `pos` should be a normalized `number` (between 0 and 1).
-   * @property formula
-   * @type {Object(function)}
-   */
-  Tweenable.prototype.formula = {
-    linear: function (pos) {
-      return pos;
-    }
-  };
-
-  formula = Tweenable.prototype.formula;
-
-  shallowCopy(Tweenable, {
-    'now': now
-    ,'each': each
-    ,'tweenProps': tweenProps
-    ,'tweenProp': tweenProp
-    ,'applyFilter': applyFilter
-    ,'shallowCopy': shallowCopy
-    ,'defaults': defaults
-    ,'composeEasingObject': composeEasingObject
-  });
-
-  // `root` is provided in the intro/outro files.
-
-  // A hook used for unit testing.
-  if (typeof SHIFTY_DEBUG_NOW === 'function') {
-    root.timeoutHandler = timeoutHandler;
-  }
-
-  // Bootstrap Tweenable appropriately for the environment.
-  if (typeof exports === 'object') {
-    // CommonJS
-    module.exports = Tweenable;
-  } else if (typeof define === 'function' && define.amd) {
-    // AMD
-    define(function () {return Tweenable;});
-  } else if (typeof root.Tweenable === 'undefined') {
-    // Browser: Make `Tweenable` globally accessible.
-    root.Tweenable = Tweenable;
-  }
-
-  return Tweenable;
-
-} ());
-
-/*!
- * All equations are adapted from Thomas Fuchs'
- * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js).
- *
- * Based on Easing Equations (c) 2003 [Robert
- * Penner](http://www.robertpenner.com/), all rights reserved. This work is
- * [subject to terms](http://www.robertpenner.com/easing_terms_of_use.html).
- */
-
-/*!
- *  TERMS OF USE - EASING EQUATIONS
- *  Open source under the BSD License.
- *  Easing Equations (c) 2003 Robert Penner, all rights reserved.
- */
-
-;(function () {
-
-  Tweenable.shallowCopy(Tweenable.prototype.formula, {
-    easeInQuad: function (pos) {
-      return Math.pow(pos, 2);
-    },
-
-    easeOutQuad: function (pos) {
-      return -(Math.pow((pos - 1), 2) - 1);
-    },
-
-    easeInOutQuad: function (pos) {
-      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,2);}
-      return -0.5 * ((pos -= 2) * pos - 2);
-    },
-
-    easeInCubic: function (pos) {
-      return Math.pow(pos, 3);
-    },
-
-    easeOutCubic: function (pos) {
-      return (Math.pow((pos - 1), 3) + 1);
-    },
-
-    easeInOutCubic: function (pos) {
-      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,3);}
-      return 0.5 * (Math.pow((pos - 2),3) + 2);
-    },
-
-    easeInQuart: function (pos) {
-      return Math.pow(pos, 4);
-    },
-
-    easeOutQuart: function (pos) {
-      return -(Math.pow((pos - 1), 4) - 1);
-    },
-
-    easeInOutQuart: function (pos) {
-      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);}
-      return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2);
-    },
-
-    easeInQuint: function (pos) {
-      return Math.pow(pos, 5);
-    },
-
-    easeOutQuint: function (pos) {
-      return (Math.pow((pos - 1), 5) + 1);
-    },
-
-    easeInOutQuint: function (pos) {
-      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,5);}
-      return 0.5 * (Math.pow((pos - 2),5) + 2);
-    },
-
-    easeInSine: function (pos) {
-      return -Math.cos(pos * (Math.PI / 2)) + 1;
-    },
-
-    easeOutSine: function (pos) {
-      return Math.sin(pos * (Math.PI / 2));
-    },
-
-    easeInOutSine: function (pos) {
-      return (-0.5 * (Math.cos(Math.PI * pos) - 1));
-    },
-
-    easeInExpo: function (pos) {
-      return (pos === 0) ? 0 : Math.pow(2, 10 * (pos - 1));
-    },
-
-    easeOutExpo: function (pos) {
-      return (pos === 1) ? 1 : -Math.pow(2, -10 * pos) + 1;
-    },
-
-    easeInOutExpo: function (pos) {
-      if (pos === 0) {return 0;}
-      if (pos === 1) {return 1;}
-      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(2,10 * (pos - 1));}
-      return 0.5 * (-Math.pow(2, -10 * --pos) + 2);
-    },
-
-    easeInCirc: function (pos) {
-      return -(Math.sqrt(1 - (pos * pos)) - 1);
-    },
-
-    easeOutCirc: function (pos) {
-      return Math.sqrt(1 - Math.pow((pos - 1), 2));
-    },
-
-    easeInOutCirc: function (pos) {
-      if ((pos /= 0.5) < 1) {return -0.5 * (Math.sqrt(1 - pos * pos) - 1);}
-      return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1);
-    },
-
-    easeOutBounce: function (pos) {
-      if ((pos) < (1 / 2.75)) {
-        return (7.5625 * pos * pos);
-      } else if (pos < (2 / 2.75)) {
-        return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
-      } else if (pos < (2.5 / 2.75)) {
-        return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
-      } else {
-        return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
-      }
-    },
-
-    easeInBack: function (pos) {
-      var s = 1.70158;
-      return (pos) * pos * ((s + 1) * pos - s);
-    },
-
-    easeOutBack: function (pos) {
-      var s = 1.70158;
-      return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1;
-    },
-
-    easeInOutBack: function (pos) {
-      var s = 1.70158;
-      if ((pos /= 0.5) < 1) {
-        return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));
-      }
-      return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
-    },
-
-    elastic: function (pos) {
-      // jshint maxlen:90
-      return -1 * Math.pow(4,-8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;
-    },
-
-    swingFromTo: function (pos) {
-      var s = 1.70158;
-      return ((pos /= 0.5) < 1) ?
-          0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) :
-          0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
-    },
-
-    swingFrom: function (pos) {
-      var s = 1.70158;
-      return pos * pos * ((s + 1) * pos - s);
-    },
-
-    swingTo: function (pos) {
-      var s = 1.70158;
-      return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;
-    },
-
-    bounce: function (pos) {
-      if (pos < (1 / 2.75)) {
-        return (7.5625 * pos * pos);
-      } else if (pos < (2 / 2.75)) {
-        return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
-      } else if (pos < (2.5 / 2.75)) {
-        return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
-      } else {
-        return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
-      }
-    },
-
-    bouncePast: function (pos) {
-      if (pos < (1 / 2.75)) {
-        return (7.5625 * pos * pos);
-      } else if (pos < (2 / 2.75)) {
-        return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
-      } else if (pos < (2.5 / 2.75)) {
-        return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
-      } else {
-        return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
-      }
-    },
-
-    easeFromTo: function (pos) {
-      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);}
-      return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2);
-    },
-
-    easeFrom: function (pos) {
-      return Math.pow(pos,4);
-    },
-
-    easeTo: function (pos) {
-      return Math.pow(pos,0.25);
-    }
-  });
-
-}());
-
-// jshint maxlen:100
-/**
- * The Bezier magic in this file is adapted/copied almost wholesale from
- * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/cubic-bezier.js),
- * which was adapted from Apple code (which probably came from
- * [here](http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h)).
- * Special thanks to Apple and Thomas Fuchs for much of this code.
- */
-
-/**
- *  Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *
- *  1. Redistributions of source code must retain the above copyright notice,
- *  this list of conditions and the following disclaimer.
- *
- *  2. Redistributions in binary form must reproduce the above copyright notice,
- *  this list of conditions and the following disclaimer in the documentation
- *  and/or other materials provided with the distribution.
- *
- *  3. Neither the name of the copyright holder(s) nor the names of any
- *  contributors may be used to endorse or promote products derived from
- *  this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- */
-;(function () {
-  // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/
-  function cubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) {
-    var ax = 0,bx = 0,cx = 0,ay = 0,by = 0,cy = 0;
-    function sampleCurveX(t) {
-      return ((ax * t + bx) * t + cx) * t;
-    }
-    function sampleCurveY(t) {
-      return ((ay * t + by) * t + cy) * t;
-    }
-    function sampleCurveDerivativeX(t) {
-      return (3.0 * ax * t + 2.0 * bx) * t + cx;
-    }
-    function solveEpsilon(duration) {
-      return 1.0 / (200.0 * duration);
-    }
-    function solve(x,epsilon) {
-      return sampleCurveY(solveCurveX(x, epsilon));
-    }
-    function fabs(n) {
-      if (n >= 0) {
-        return n;
-      } else {
-        return 0 - n;
-      }
-    }
-    function solveCurveX(x, epsilon) {
-      var t0,t1,t2,x2,d2,i;
-      for (t2 = x, i = 0; i < 8; i++) {
-        x2 = sampleCurveX(t2) - x;
-        if (fabs(x2) < epsilon) {
-          return t2;
-        }
-        d2 = sampleCurveDerivativeX(t2);
-        if (fabs(d2) < 1e-6) {
-          break;
-        }
-        t2 = t2 - x2 / d2;
-      }
-      t0 = 0.0;
-      t1 = 1.0;
-      t2 = x;
-      if (t2 < t0) {
-        return t0;
-      }
-      if (t2 > t1) {
-        return t1;
-      }
-      while (t0 < t1) {
-        x2 = sampleCurveX(t2);
-        if (fabs(x2 - x) < epsilon) {
-          return t2;
-        }
-        if (x > x2) {
-          t0 = t2;
-        }else {
-          t1 = t2;
-        }
-        t2 = (t1 - t0) * 0.5 + t0;
-      }
-      return t2; // Failure.
-    }
-    cx = 3.0 * p1x;
-    bx = 3.0 * (p2x - p1x) - cx;
-    ax = 1.0 - cx - bx;
-    cy = 3.0 * p1y;
-    by = 3.0 * (p2y - p1y) - cy;
-    ay = 1.0 - cy - by;
-    return solve(t, solveEpsilon(duration));
-  }
-  /**
-   *  getCubicBezierTransition(x1, y1, x2, y2) -> Function
-   *
-   *  Generates a transition easing function that is compatible
-   *  with WebKit's CSS transitions `-webkit-transition-timing-function`
-   *  CSS property.
-   *
-   *  The W3C has more information about CSS3 transition timing functions:
-   *  http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
-   *
-   *  @param {number} x1
-   *  @param {number} y1
-   *  @param {number} x2
-   *  @param {number} y2
-   *  @return {function}
-   *  @private
-   */
-  function getCubicBezierTransition (x1, y1, x2, y2) {
-    return function (pos) {
-      return cubicBezierAtTime(pos,x1,y1,x2,y2,1);
-    };
-  }
-  // End ported code
-
-  /**
-   * Create a Bezier easing function and attach it to `{{#crossLink
-   * "Tweenable/formula:property"}}Tweenable#formula{{/crossLink}}`.  This
-   * function gives you total control over the easing curve.  Matthew Lein's
-   * [Ceaser](http://matthewlein.com/ceaser/) is a useful tool for visualizing
-   * the curves you can make with this function.
-   * @method setBezierFunction
-   * @param {string} name The name of the easing curve.  Overwrites the old
-   * easing function on `{{#crossLink
-   * "Tweenable/formula:property"}}Tweenable#formula{{/crossLink}}` if it
-   * exists.
-   * @param {number} x1
-   * @param {number} y1
-   * @param {number} x2
-   * @param {number} y2
-   * @return {function} The easing function that was attached to
-   * Tweenable.prototype.formula.
-   */
-  Tweenable.setBezierFunction = function (name, x1, y1, x2, y2) {
-    var cubicBezierTransition = getCubicBezierTransition(x1, y1, x2, y2);
-    cubicBezierTransition.displayName = name;
-    cubicBezierTransition.x1 = x1;
-    cubicBezierTransition.y1 = y1;
-    cubicBezierTransition.x2 = x2;
-    cubicBezierTransition.y2 = y2;
-
-    return Tweenable.prototype.formula[name] = cubicBezierTransition;
-  };
-
-
-  /**
-   * `delete` an easing function from `{{#crossLink
-   * "Tweenable/formula:property"}}Tweenable#formula{{/crossLink}}`.  Be
-   * careful with this method, as it `delete`s whatever easing formula matches
-   * `name` (which means you can delete standard Shifty easing functions).
-   * @method unsetBezierFunction
-   * @param {string} name The name of the easing function to delete.
-   * @return {function}
-   */
-  Tweenable.unsetBezierFunction = function (name) {
-    delete Tweenable.prototype.formula[name];
-  };
-
-})();
-
-;(function () {
-
-  function getInterpolatedValues (
-    from, current, targetState, position, easing, delay) {
-    return Tweenable.tweenProps(
-      position, current, from, targetState, 1, delay, easing);
-  }
-
-  // Fake a Tweenable and patch some internals.  This approach allows us to
-  // skip uneccessary processing and object recreation, cutting down on garbage
-  // collection pauses.
-  var mockTweenable = new Tweenable();
-  mockTweenable._filterArgs = [];
-
-  /**
-   * Compute the midpoint of two Objects.  This method effectively calculates a
-   * specific frame of animation that `{{#crossLink
-   * "Tweenable/tween:method"}}{{/crossLink}}` does many times over the course
-   * of a full tween.
-   *
-   *     var interpolatedValues = Tweenable.interpolate({
-   *       width: '100px',
-   *       opacity: 0,
-   *       color: '#fff'
-   *     }, {
-   *       width: '200px',
-   *       opacity: 1,
-   *       color: '#000'
-   *     }, 0.5);
-   *
-   *     // {opacity: 0.5, width: "150px", color: "rgb(127,127,127)"}
-   *
-   * @static
-   * @method interpolate
-   * @param {Object} from The starting values to tween from.
-   * @param {Object} targetState The ending values to tween to.
-   * @param {number} position The normalized position value (between `0.0` and
-   * `1.0`) to interpolate the values between `from` and `to` for.  `from`
-   * represents `0` and `to` represents `1`.
-   * @param {Object.<string|Function>|string|Function} easing The easing
-   * curve(s) to calculate the midpoint against.  You can reference any easing
-   * function attached to `Tweenable.prototype.formula`, or provide the easing
-   * function(s) directly.  If omitted, this defaults to "linear".
-   * @param {number=} opt_delay Optional delay to pad the beginning of the
-   * interpolated tween with.  This increases the range of `position` from (`0`
-   * through `1`) to (`0` through `1 + opt_delay`).  So, a delay of `0.5` would
-   * increase all valid values of `position` to numbers between `0` and `1.5`.
-   * @return {Object}
-   */
-  Tweenable.interpolate = function (
-    from, targetState, position, easing, opt_delay) {
-
-    var current = Tweenable.shallowCopy({}, from);
-    var delay = opt_delay || 0;
-    var easingObject = Tweenable.composeEasingObject(
-      from, easing || 'linear');
-
-    mockTweenable.set({});
-
-    // Alias and reuse the _filterArgs array instead of recreating it.
-    var filterArgs = mockTweenable._filterArgs;
-    filterArgs.length = 0;
-    filterArgs[0] = current;
-    filterArgs[1] = from;
-    filterArgs[2] = targetState;
-    filterArgs[3] = easingObject;
-
-    // Any defined value transformation must be applied
-    Tweenable.applyFilter(mockTweenable, 'tweenCreated');
-    Tweenable.applyFilter(mockTweenable, 'beforeTween');
-
-    var interpolatedValues = getInterpolatedValues(
-      from, current, targetState, position, easingObject, delay);
-
-    // Transform values back into their original format
-    Tweenable.applyFilter(mockTweenable, 'afterTween');
-
-    return interpolatedValues;
-  };
-
-}());
-
-/**
- * This module adds string interpolation support to Shifty.
- *
- * The Token extension allows Shifty to tween numbers inside of strings.  Among
- * other things, this allows you to animate CSS properties.  For example, you
- * can do this:
- *
- *     var tweenable = new Tweenable();
- *     tweenable.tween({
- *       from: { transform: 'translateX(45px)' },
- *       to: { transform: 'translateX(90xp)' }
- *     });
- *
- * `translateX(45)` will be tweened to `translateX(90)`.  To demonstrate:
- *
- *     var tweenable = new Tweenable();
- *     tweenable.tween({
- *       from: { transform: 'translateX(45px)' },
- *       to: { transform: 'translateX(90px)' },
- *       step: function (state) {
- *         console.log(state.transform);
- *       }
- *     });
- *
- * The above snippet will log something like this in the console:
- *
- *     translateX(60.3px)
- *     ...
- *     translateX(76.05px)
- *     ...
- *     translateX(90px)
- *
- * Another use for this is animating colors:
- *
- *     var tweenable = new Tweenable();
- *     tweenable.tween({
- *       from: { color: 'rgb(0,255,0)' },
- *       to: { color: 'rgb(255,0,255)' },
- *       step: function (state) {
- *         console.log(state.color);
- *       }
- *     });
- *
- * The above snippet will log something like this:
- *
- *     rgb(84,170,84)
- *     ...
- *     rgb(170,84,170)
- *     ...
- *     rgb(255,0,255)
- *
- * This extension also supports hexadecimal colors, in both long (`#ff00ff`)
- * and short (`#f0f`) forms.  Be aware that hexadecimal input values will be
- * converted into the equivalent RGB output values.  This is done to optimize
- * for performance.
- *
- *     var tweenable = new Tweenable();
- *     tweenable.tween({
- *       from: { color: '#0f0' },
- *       to: { color: '#f0f' },
- *       step: function (state) {
- *         console.log(state.color);
- *       }
- *     });
- *
- * This snippet will generate the same output as the one before it because
- * equivalent values were supplied (just in hexadecimal form rather than RGB):
- *
- *     rgb(84,170,84)
- *     ...
- *     rgb(170,84,170)
- *     ...
- *     rgb(255,0,255)
- *
- * ## Easing support
- *
- * Easing works somewhat differently in the Token extension.  This is because
- * some CSS properties have multiple values in them, and you might need to
- * tween each value along its own easing curve.  A basic example:
- *
- *     var tweenable = new Tweenable();
- *     tweenable.tween({
- *       from: { transform: 'translateX(0px) translateY(0px)' },
- *       to: { transform:   'translateX(100px) translateY(100px)' },
- *       easing: { transform: 'easeInQuad' },
- *       step: function (state) {
- *         console.log(state.transform);
- *       }
- *     });
- *
- * The above snippet will create values like this:
- *
- *     translateX(11.56px) translateY(11.56px)
- *     ...
- *     translateX(46.24px) translateY(46.24px)
- *     ...
- *     translateX(100px) translateY(100px)
- *
- * In this case, the values for `translateX` and `translateY` are always the
- * same for each step of the tween, because they have the same start and end
- * points and both use the same easing curve.  We can also tween `translateX`
- * and `translateY` along independent curves:
- *
- *     var tweenable = new Tweenable();
- *     tweenable.tween({
- *       from: { transform: 'translateX(0px) translateY(0px)' },
- *       to: { transform:   'translateX(100px) translateY(100px)' },
- *       easing: { transform: 'easeInQuad bounce' },
- *       step: function (state) {
- *         console.log(state.transform);
- *       }
- *     });
- *
- * The above snippet will create values like this:
- *
- *     translateX(10.89px) translateY(82.35px)
- *     ...
- *     translateX(44.89px) translateY(86.73px)
- *     ...
- *     translateX(100px) translateY(100px)
- *
- * `translateX` and `translateY` are not in sync anymore, because `easeInQuad`
- * was specified for `translateX` and `bounce` for `translateY`.  Mixing and
- * matching easing curves can make for some interesting motion in your
- * animations.
- *
- * The order of the space-separated easing curves correspond the token values
- * they apply to.  If there are more token values than easing curves listed,
- * the last easing curve listed is used.
- * @submodule Tweenable.token
- */
-
-// token function is defined above only so that dox-foundation sees it as
-// documentation and renders it.  It is never used, and is optimized away at
-// build time.
-
-;(function (Tweenable) {
-
-  /**
-   * @typedef {{
-   *   formatString: string
-   *   chunkNames: Array.<string>
-   * }}
-   * @private
-   */
-  var formatManifest;
-
-  // CONSTANTS
-
-  var R_NUMBER_COMPONENT = /(\d|\-|\.)/;
-  var R_FORMAT_CHUNKS = /([^\-0-9\.]+)/g;
-  var R_UNFORMATTED_VALUES = /[0-9.\-]+/g;
-  var R_RGB = new RegExp(
-    'rgb\\(' + R_UNFORMATTED_VALUES.source +
-    (/,\s*/.source) + R_UNFORMATTED_VALUES.source +
-    (/,\s*/.source) + R_UNFORMATTED_VALUES.source + '\\)', 'g');
-  var R_RGB_PREFIX = /^.*\(/;
-  var R_HEX = /#([0-9]|[a-f]){3,6}/gi;
-  var VALUE_PLACEHOLDER = 'VAL';
-
-  // HELPERS
-
-  /**
-   * @param {Array.number} rawValues
-   * @param {string} prefix
-   *
-   * @return {Array.<string>}
-   * @private
-   */
-  function getFormatChunksFrom (rawValues, prefix) {
-    var accumulator = [];
-
-    var rawValuesLength = rawValues.length;
-    var i;
-
-    for (i = 0; i < rawValuesLength; i++) {
-      accumulator.push('_' + prefix + '_' + i);
-    }
-
-    return accumulator;
-  }
-
-  /**
-   * @param {string} formattedString
-   *
-   * @return {string}
-   * @private
-   */
-  function getFormatStringFrom (formattedString) {
-    var chunks = formattedString.match(R_FORMAT_CHUNKS);
-
-    if (!chunks) {
-      // chunks will be null if there were no tokens to parse in
-      // formattedString (for example, if formattedString is '2').  Coerce
-      // chunks to be useful here.
-      chunks = ['', ''];
-
-      // If there is only one chunk, assume that the string is a number
-      // followed by a token...
-      // NOTE: This may be an unwise assumption.
-    } else if (chunks.length === 1 ||
-      // ...or if the string starts with a number component (".", "-", or a
-      // digit)...
-    formattedString[0].match(R_NUMBER_COMPONENT)) {
-      // ...prepend an empty string here to make sure that the formatted number
-      // is properly replaced by VALUE_PLACEHOLDER
-      chunks.unshift('');
-    }
-
-    return chunks.join(VALUE_PLACEHOLDER);
-  }
-
-  /**
-   * Convert all hex color values within a string to an rgb string.
-   *
-   * @param {Object} stateObject
-   *
-   * @return {Object} The modified obj
-   * @private
-   */
-  function sanitizeObjectForHexProps (stateObject) {
-    Tweenable.each(stateObject, function (prop) {
-      var currentProp = stateObject[prop];
-
-      if (typeof currentProp === 'string' && currentProp.match(R_HEX)) {
-        stateObject[prop] = sanitizeHexChunksToRGB(currentProp);
-      }
-    });
-  }
-
-  /**
-   * @param {string} str
-   *
-   * @return {string}
-   * @private
-   */
-  function  sanitizeHexChunksToRGB (str) {
-    return filterStringChunks(R_HEX, str, convertHexToRGB);
-  }
-
-  /**
-   * @param {string} hexString
-   *
-   * @return {string}
-   * @private
-   */
-  function convertHexToRGB (hexString) {
-    var rgbArr = hexToRGBArray(hexString);
-    return 'rgb(' + rgbArr[0] + ',' + rgbArr[1] + ',' + rgbArr[2] + ')';
-  }
-
-  var hexToRGBArray_returnArray = [];
-  /**
-   * Convert a hexadecimal string to an array with three items, one each for
-   * the red, blue, and green decimal values.
-   *
-   * @param {string} hex A hexadecimal string.
-   *
-   * @returns {Array.<number>} The converted Array of RGB values if `hex` is a
-   * valid string, or an Array of three 0's.
-   * @private
-   */
-  function hexToRGBArray (hex) {
-
-    hex = hex.replace(/#/, '');
-
-    // If the string is a shorthand three digit hex notation, normalize it to
-    // the standard six digit notation
-    if (hex.length === 3) {
-      hex = hex.split('');
-      hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
-    }
-
-    hexToRGBArray_returnArray[0] = hexToDec(hex.substr(0, 2));
-    hexToRGBArray_returnArray[1] = hexToDec(hex.substr(2, 2));
-    hexToRGBArray_returnArray[2] = hexToDec(hex.substr(4, 2));
-
-    return hexToRGBArray_returnArray;
-  }
-
-  /**
-   * Convert a base-16 number to base-10.
-   *
-   * @param {Number|String} hex The value to convert
-   *
-   * @returns {Number} The base-10 equivalent of `hex`.
-   * @private
-   */
-  function hexToDec (hex) {
-    return parseInt(hex, 16);
-  }
-
-  /**
-   * Runs a filter operation on all chunks of a string that match a RegExp
-   *
-   * @param {RegExp} pattern
-   * @param {string} unfilteredString
-   * @param {function(string)} filter
-   *
-   * @return {string}
-   * @private
-   */
-  function filterStringChunks (pattern, unfilteredString, filter) {
-    var pattenMatches = unfilteredString.match(pattern);
-    var filteredString = unfilteredString.replace(pattern, VALUE_PLACEHOLDER);
-
-    if (pattenMatches) {
-      var pattenMatchesLength = pattenMatches.length;
-      var currentChunk;
-
-      for (var i = 0; i < pattenMatchesLength; i++) {
-        currentChunk = pattenMatches.shift();
-        filteredString = filteredString.replace(
-          VALUE_PLACEHOLDER, filter(currentChunk));
-      }
-    }
-
-    return filteredString;
-  }
-
-  /**
-   * Check for floating point values within rgb strings and rounds them.
-   *
-   * @param {string} formattedString
-   *
-   * @return {string}
-   * @private
-   */
-  function sanitizeRGBChunks (formattedString) {
-    return filterStringChunks(R_RGB, formattedString, sanitizeRGBChunk);
-  }
-
-  /**
-   * @param {string} rgbChunk
-   *
-   * @return {string}
-   * @private
-   */
-  function sanitizeRGBChunk (rgbChunk) {
-    var numbers = rgbChunk.match(R_UNFORMATTED_VALUES);
-    var numbersLength = numbers.length;
-    var sanitizedString = rgbChunk.match(R_RGB_PREFIX)[0];
-
-    for (var i = 0; i < numbersLength; i++) {
-      sanitizedString += parseInt(numbers[i], 10) + ',';
-    }
-
-    sanitizedString = sanitizedString.slice(0, -1) + ')';
-
-    return sanitizedString;
-  }
-
-  /**
-   * @param {Object} stateObject
-   *
-   * @return {Object} An Object of formatManifests that correspond to
-   * the string properties of stateObject
-   * @private
-   */
-  function getFormatManifests (stateObject) {
-    var manifestAccumulator = {};
-
-    Tweenable.each(stateObject, function (prop) {
-      var currentProp = stateObject[prop];
-
-      if (typeof currentProp === 'string') {
-        var rawValues = getValuesFrom(currentProp);
-
-        manifestAccumulator[prop] = {
-          'formatString': getFormatStringFrom(currentProp)
-          ,'chunkNames': getFormatChunksFrom(rawValues, prop)
-        };
-      }
-    });
-
-    return manifestAccumulator;
-  }
-
-  /**
-   * @param {Object} stateObject
-   * @param {Object} formatManifests
-   * @private
-   */
-  function expandFormattedProperties (stateObject, formatManifests) {
-    Tweenable.each(formatManifests, function (prop) {
-      var currentProp = stateObject[prop];
-      var rawValues = getValuesFrom(currentProp);
-      var rawValuesLength = rawValues.length;
-
-      for (var i = 0; i < rawValuesLength; i++) {
-        stateObject[formatManifests[prop].chunkNames[i]] = +rawValues[i];
-      }
-
-      delete stateObject[prop];
-    });
-  }
-
-  /**
-   * @param {Object} stateObject
-   * @param {Object} formatManifests
-   * @private
-   */
-  function collapseFormattedProperties (stateObject, formatManifests) {
-    Tweenable.each(formatManifests, function (prop) {
-      var currentProp = stateObject[prop];
-      var formatChunks = extractPropertyChunks(
-        stateObject, formatManifests[prop].chunkNames);
-      var valuesList = getValuesList(
-        formatChunks, formatManifests[prop].chunkNames);
-      currentProp = getFormattedValues(
-        formatManifests[prop].formatString, valuesList);
-      stateObject[prop] = sanitizeRGBChunks(currentProp);
-    });
-  }
-
-  /**
-   * @param {Object} stateObject
-   * @param {Array.<string>} chunkNames
-   *
-   * @return {Object} The extracted value chunks.
-   * @private
-   */
-  function extractPropertyChunks (stateObject, chunkNames) {
-    var extractedValues = {};
-    var currentChunkName, chunkNamesLength = chunkNames.length;
-
-    for (var i = 0; i < chunkNamesLength; i++) {
-      currentChunkName = chunkNames[i];
-      extractedValues[currentChunkName] = stateObject[currentChunkName];
-      delete stateObject[currentChunkName];
-    }
-
-    return extractedValues;
-  }
-
-  var getValuesList_accumulator = [];
-  /**
-   * @param {Object} stateObject
-   * @param {Array.<string>} chunkNames
-   *
-   * @return {Array.<number>}
-   * @private
-   */
-  function getValuesList (stateObject, chunkNames) {
-    getValuesList_accumulator.length = 0;
-    var chunkNamesLength = chunkNames.length;
-
-    for (var i = 0; i < chunkNamesLength; i++) {
-      getValuesList_accumulator.push(stateObject[chunkNames[i]]);
-    }
-
-    return getValuesList_accumulator;
-  }
-
-  /**
-   * @param {string} formatString
-   * @param {Array.<number>} rawValues
-   *
-   * @return {string}
-   * @private
-   */
-  function getFormattedValues (formatString, rawValues) {
-    var formattedValueString = formatString;
-    var rawValuesLength = rawValues.length;
-
-    for (var i = 0; i < rawValuesLength; i++) {
-      formattedValueString = formattedValueString.replace(
-        VALUE_PLACEHOLDER, +rawValues[i].toFixed(4));
-    }
-
-    return formattedValueString;
-  }
-
-  /**
-   * Note: It's the duty of the caller to convert the Array elements of the
-   * return value into numbers.  This is a performance optimization.
-   *
-   * @param {string} formattedString
-   *
-   * @return {Array.<string>|null}
-   * @private
-   */
-  function getValuesFrom (formattedString) {
-    return formattedString.match(R_UNFORMATTED_VALUES);
-  }
-
-  /**
-   * @param {Object} easingObject
-   * @param {Object} tokenData
-   * @private
-   */
-  function expandEasingObject (easingObject, tokenData) {
-    Tweenable.each(tokenData, function (prop) {
-      var currentProp = tokenData[prop];
-      var chunkNames = currentProp.chunkNames;
-      var chunkLength = chunkNames.length;
-
-      var easing = easingObject[prop];
-      var i;
-
-      if (typeof easing === 'string') {
-        var easingChunks = easing.split(' ');
-        var lastEasingChunk = easingChunks[easingChunks.length - 1];
-
-        for (i = 0; i < chunkLength; i++) {
-          easingObject[chunkNames[i]] = easingChunks[i] || lastEasingChunk;
-        }
-
-      } else {
-        for (i = 0; i < chunkLength; i++) {
-          easingObject[chunkNames[i]] = easing;
-        }
-      }
-
-      delete easingObject[prop];
-    });
-  }
-
-  /**
-   * @param {Object} easingObject
-   * @param {Object} tokenData
-   * @private
-   */
-  function collapseEasingObject (easingObject, tokenData) {
-    Tweenable.each(tokenData, function (prop) {
-      var currentProp = tokenData[prop];
-      var chunkNames = currentProp.chunkNames;
-      var chunkLength = chunkNames.length;
-
-      var firstEasing = easingObject[chunkNames[0]];
-      var typeofEasings = typeof firstEasing;
-
-      if (typeofEasings === 'string') {
-        var composedEasingString = '';
-
-        for (var i = 0; i < chunkLength; i++) {
-          composedEasingString += ' ' + easingObject[chunkNames[i]];
-          delete easingObject[chunkNames[i]];
-        }
-
-        easingObject[prop] = composedEasingString.substr(1);
-      } else {
-        easingObject[prop] = firstEasing;
-      }
-    });
-  }
-
-  Tweenable.prototype.filter.token = {
-    'tweenCreated': function (currentState, fromState, toState, easingObject) {
-      sanitizeObjectForHexProps(currentState);
-      sanitizeObjectForHexProps(fromState);
-      sanitizeObjectForHexProps(toState);
-      this._tokenData = getFormatManifests(currentState);
-    },
-
-    'beforeTween': function (currentState, fromState, toState, easingObject) {
-      expandEasingObject(easingObject, this._tokenData);
-      expandFormattedProperties(currentState, this._tokenData);
-      expandFormattedProperties(fromState, this._tokenData);
-      expandFormattedProperties(toState, this._tokenData);
-    },
-
-    'afterTween': function (currentState, fromState, toState, easingObject) {
-      collapseFormattedProperties(currentState, this._tokenData);
-      collapseFormattedProperties(fromState, this._tokenData);
-      collapseFormattedProperties(toState, this._tokenData);
-      collapseEasingObject(easingObject, this._tokenData);
-    }
-  };
-
-} (Tweenable));
-
-}).call(null);
-
-},{}],2:[function(require,module,exports){
-// Circle shaped progress bar
-
-var Shape = require('./shape');
-var utils = require('./utils');
-
-var Circle = function Circle(container, options) {
-    // Use two arcs to form a circle
-    // See this answer http://stackoverflow.com/a/10477334/1446092
-    this._pathTemplate =
-        'M 50,50 m 0,-{radius}' +
-        ' a {radius},{radius} 0 1 1 0,{2radius}' +
-        ' a {radius},{radius} 0 1 1 0,-{2radius}';
-
-    this.containerAspectRatio = 1;
-
-    Shape.apply(this, arguments);
-};
-
-Circle.prototype = new Shape();
-Circle.prototype.constructor = Circle;
-
-Circle.prototype._pathString = function _pathString(opts) {
-    var widthOfWider = opts.strokeWidth;
-    if (opts.trailWidth && opts.trailWidth > opts.strokeWidth) {
-        widthOfWider = opts.trailWidth;
-    }
-
-    var r = 50 - widthOfWider / 2;
-
-    return utils.render(this._pathTemplate, {
-        radius: r,
-        '2radius': r * 2
-    });
-};
-
-Circle.prototype._trailString = function _trailString(opts) {
-    return this._pathString(opts);
-};
-
-module.exports = Circle;
-
-},{"./shape":7,"./utils":8}],3:[function(require,module,exports){
-// Line shaped progress bar
-
-var Shape = require('./shape');
-var utils = require('./utils');
-
-var Line = function Line(container, options) {
-    this._pathTemplate = 'M 0,{center} L 100,{center}';
-    Shape.apply(this, arguments);
-};
-
-Line.prototype = new Shape();
-Line.prototype.constructor = Line;
-
-Line.prototype._initializeSvg = function _initializeSvg(svg, opts) {
-    svg.setAttribute('viewBox', '0 0 100 ' + opts.strokeWidth);
-    svg.setAttribute('preserveAspectRatio', 'none');
-};
-
-Line.prototype._pathString = function _pathString(opts) {
-    return utils.render(this._pathTemplate, {
-        center: opts.strokeWidth / 2
-    });
-};
-
-Line.prototype._trailString = function _trailString(opts) {
-    return this._pathString(opts);
-};
-
-module.exports = Line;
-
-},{"./shape":7,"./utils":8}],4:[function(require,module,exports){
-module.exports = {
-    // Higher level API, different shaped progress bars
-    Line: require('./line'),
-    Circle: require('./circle'),
-    SemiCircle: require('./semicircle'),
-
-    // Lower level API to use any SVG path
-    Path: require('./path'),
-
-    // Base-class for creating new custom shapes
-    // to be in line with the API of built-in shapes
-    // Undocumented.
-    Shape: require('./shape'),
-
-    // Internal utils, undocumented.
-    utils: require('./utils')
-};
-
-},{"./circle":2,"./line":3,"./path":5,"./semicircle":6,"./shape":7,"./utils":8}],5:[function(require,module,exports){
-// Lower level API to animate any kind of svg path
-
-var Tweenable = require('shifty');
-var utils = require('./utils');
-
-var EASING_ALIASES = {
-    easeIn: 'easeInCubic',
-    easeOut: 'easeOutCubic',
-    easeInOut: 'easeInOutCubic'
-};
-
-var Path = function Path(path, opts) {
-    // Throw a better error if not initialized with `new` keyword
-    if (!(this instanceof Path)) {
-        throw new Error('Constructor was called without new keyword');
-    }
-
-    // Default parameters for animation
-    opts = utils.extend({
-        duration: 800,
-        easing: 'linear',
-        from: {},
-        to: {},
-        step: function() {}
-    }, opts);
-
-    var element;
-    if (utils.isString(path)) {
-        element = document.querySelector(path);
-    } else {
-        element = path;
-    }
-
-    // Reveal .path as public attribute
-    this.path = element;
-    this._opts = opts;
-    this._tweenable = null;
-
-    // Set up the starting positions
-    var length = this.path.getTotalLength();
-    this.path.style.strokeDasharray = length + ' ' + length;
-    this.set(0);
-};
-
-Path.prototype.value = function value() {
-    var offset = this._getComputedDashOffset();
-    var length = this.path.getTotalLength();
-
-    var progress = 1 - offset / length;
-    // Round number to prevent returning very small number like 1e-30, which
-    // is practically 0
-    return parseFloat(progress.toFixed(6), 10);
-};
-
-Path.prototype.set = function set(progress) {
-    this.stop();
-
-    this.path.style.strokeDashoffset = this._progressToOffset(progress);
-
-    var step = this._opts.step;
-    if (utils.isFunction(step)) {
-        var easing = this._easing(this._opts.easing);
-        var values = this._calculateTo(progress, easing);
-        var reference = this._opts.shape || this;
-        step(values, reference, this._opts.attachment);
-    }
-};
-
-Path.prototype.stop = function stop() {
-    this._stopTween();
-    this.path.style.strokeDashoffset = this._getComputedDashOffset();
-};
-
-// Method introduced here:
-// http://jakearchibald.com/2013/animated-line-drawing-svg/
-Path.prototype.animate = function animate(progress, opts, cb) {
-    opts = opts || {};
-
-    if (utils.isFunction(opts)) {
-        cb = opts;
-        opts = {};
-    }
-
-    var passedOpts = utils.extend({}, opts);
-
-    // Copy default opts to new object so defaults are not modified
-    var defaultOpts = utils.extend({}, this._opts);
-    opts = utils.extend(defaultOpts, opts);
-
-    var shiftyEasing = this._easing(opts.easing);
-    var values = this._resolveFromAndTo(progress, shiftyEasing, passedOpts);
-
-    this.stop();
-
-    // Trigger a layout so styles are calculated & the browser
-    // picks up the starting position before animating
-    this.path.getBoundingClientRect();
-
-    var offset = this._getComputedDashOffset();
-    var newOffset = this._progressToOffset(progress);
-
-    var self = this;
-    this._tweenable = new Tweenable();
-    this._tweenable.tween({
-        from: utils.extend({ offset: offset }, values.from),
-        to: utils.extend({ offset: newOffset }, values.to),
-        duration: opts.duration,
-        easing: shiftyEasing,
-        step: function(state) {
-            self.path.style.strokeDashoffset = state.offset;
-            var reference = opts.shape || self;
-            opts.step(state, reference, opts.attachment);
-        },
-        finish: function(state) {
-            if (utils.isFunction(cb)) {
-                cb();
-            }
-        }
-    });
-};
-
-Path.prototype._getComputedDashOffset = function _getComputedDashOffset() {
-    var computedStyle = window.getComputedStyle(this.path, null);
-    return parseFloat(computedStyle.getPropertyValue('stroke-dashoffset'), 10);
-};
-
-Path.prototype._progressToOffset = function _progressToOffset(progress) {
-    var length = this.path.getTotalLength();
-    return length - progress * length;
-};
-
-// Resolves from and to values for animation.
-Path.prototype._resolveFromAndTo = function _resolveFromAndTo(progress, easing, opts) {
-    if (opts.from && opts.to) {
-        return {
-            from: opts.from,
-            to: opts.to
-        };
-    }
-
-    return {
-        from: this._calculateFrom(easing),
-        to: this._calculateTo(progress, easing)
-    };
-};
-
-// Calculate `from` values from options passed at initialization
-Path.prototype._calculateFrom = function _calculateFrom(easing) {
-    return Tweenable.interpolate(this._opts.from, this._opts.to, this.value(), easing);
-};
-
-// Calculate `to` values from options passed at initialization
-Path.prototype._calculateTo = function _calculateTo(progress, easing) {
-    return Tweenable.interpolate(this._opts.from, this._opts.to, progress, easing);
-};
-
-Path.prototype._stopTween = function _stopTween() {
-    if (this._tweenable !== null) {
-        this._tweenable.stop();
-        this._tweenable = null;
-    }
-};
-
-Path.prototype._easing = function _easing(easing) {
-    if (EASING_ALIASES.hasOwnProperty(easing)) {
-        return EASING_ALIASES[easing];
-    }
-
-    return easing;
-};
-
-module.exports = Path;
-
-},{"./utils":8,"shifty":1}],6:[function(require,module,exports){
-// Semi-SemiCircle shaped progress bar
-
-var Shape = require('./shape');
-var Circle = require('./circle');
-var utils = require('./utils');
-
-var SemiCircle = function SemiCircle(container, options) {
-    // Use one arc to form a SemiCircle
-    // See this answer http://stackoverflow.com/a/10477334/1446092
-    this._pathTemplate =
-        'M 50,50 m -{radius},0' +
-        ' a {radius},{radius} 0 1 1 {2radius},0';
-
-    this.containerAspectRatio = 2;
-
-    Shape.apply(this, arguments);
-};
-
-SemiCircle.prototype = new Shape();
-SemiCircle.prototype.constructor = SemiCircle;
-
-SemiCircle.prototype._initializeSvg = function _initializeSvg(svg, opts) {
-    svg.setAttribute('viewBox', '0 0 100 50');
-};
-
-SemiCircle.prototype._initializeTextContainer = function _initializeTextContainer(
-    opts,
-    container,
-    textContainer
-) {
-    if (opts.text.style) {
-        // Reset top style
-        textContainer.style.top = 'auto';
-        textContainer.style.bottom = '0';
-
-        if (opts.text.alignToBottom) {
-            utils.setStyle(textContainer, 'transform', 'translate(-50%, 0)');
-        } else {
-            utils.setStyle(textContainer, 'transform', 'translate(-50%, 50%)');
-        }
-    }
-};
-
-// Share functionality with Circle, just have different path
-SemiCircle.prototype._pathString = Circle.prototype._pathString;
-SemiCircle.prototype._trailString = Circle.prototype._trailString;
-
-module.exports = SemiCircle;
-
-},{"./circle":2,"./shape":7,"./utils":8}],7:[function(require,module,exports){
-// Base object for different progress bar shapes
-
-var Path = require('./path');
-var utils = require('./utils');
-
-var DESTROYED_ERROR = 'Object is destroyed';
-
-var Shape = function Shape(container, opts) {
-    // Throw a better error if progress bars are not initialized with `new`
-    // keyword
-    if (!(this instanceof Shape)) {
-        throw new Error('Constructor was called without new keyword');
-    }
-
-    // Prevent calling constructor without parameters so inheritance
-    // works correctly. To understand, this is how Shape is inherited:
-    //
-    //   Line.prototype = new Shape();
-    //
-    // We just want to set the prototype for Line.
-    if (arguments.length === 0) {
-        return;
-    }
-
-    // Default parameters for progress bar creation
-    this._opts = utils.extend({
-        color: '#555',
-        strokeWidth: 1.0,
-        trailColor: null,
-        trailWidth: null,
-        fill: null,
-        text: {
-            style: {
-                color: null,
-                position: 'absolute',
-                left: '50%',
-                top: '50%',
-                padding: 0,
-                margin: 0,
-                transform: {
-                    prefix: true,
-                    value: 'translate(-50%, -50%)'
-                }
-            },
-            autoStyleContainer: true,
-            alignToBottom: true,
-            value: null,
-            className: 'progressbar-text'
-        },
-        svgStyle: {
-            display: 'block',
-            width: '100%'
-        },
-        warnings: false
-    }, opts, true);  // Use recursive extend
-
-    // If user specifies e.g. svgStyle or text style, the whole object
-    // should replace the defaults to make working with styles easier
-    if (utils.isObject(opts) && opts.svgStyle !== undefined) {
-        this._opts.svgStyle = opts.svgStyle;
-    }
-    if (utils.isObject(opts) && utils.isObject(opts.text) && opts.text.style !== undefined) {
-        this._opts.text.style = opts.text.style;
-    }
-
-    var svgView = this._createSvgView(this._opts);
-
-    var element;
-    if (utils.isString(container)) {
-        element = document.querySelector(container);
-    } else {
-        element = container;
-    }
-
-    if (!element) {
-        throw new Error('Container does not exist: ' + container);
-    }
-
-    this._container = element;
-    this._container.appendChild(svgView.svg);
-    if (this._opts.warnings) {
-        this._warnContainerAspectRatio(this._container);
-    }
-
-    if (this._opts.svgStyle) {
-        utils.setStyles(svgView.svg, this._opts.svgStyle);
-    }
-
-    // Expose public attributes before Path initialization
-    this.svg = svgView.svg;
-    this.path = svgView.path;
-    this.trail = svgView.trail;
-    this.text = null;
-
-    var newOpts = utils.extend({
-        attachment: undefined,
-        shape: this
-    }, this._opts);
-    this._progressPath = new Path(svgView.path, newOpts);
-
-    if (utils.isObject(this._opts.text) && this._opts.text.value !== null) {
-        this.setText(this._opts.text.value);
-    }
-};
-
-Shape.prototype.animate = function animate(progress, opts, cb) {
-    if (this._progressPath === null) {
-        throw new Error(DESTROYED_ERROR);
-    }
-
-    this._progressPath.animate(progress, opts, cb);
-};
-
-Shape.prototype.stop = function stop() {
-    if (this._progressPath === null) {
-        throw new Error(DESTROYED_ERROR);
-    }
-
-    // Don't crash if stop is called inside step function
-    if (this._progressPath === undefined) {
-        return;
-    }
-
-    this._progressPath.stop();
-};
-
-Shape.prototype.destroy = function destroy() {
-    if (this._progressPath === null) {
-        throw new Error(DESTROYED_ERROR);
-    }
-
-    this.stop();
-    this.svg.parentNode.removeChild(this.svg);
-    this.svg = null;
-    this.path = null;
-    this.trail = null;
-    this._progressPath = null;
-
-    if (this.text !== null) {
-        this.text.parentNode.removeChild(this.text);
-        this.text = null;
-    }
-};
-
-Shape.prototype.set = function set(progress) {
-    if (this._progressPath === null) {
-        throw new Error(DESTROYED_ERROR);
-    }
-
-    this._progressPath.set(progress);
-};
-
-Shape.prototype.value = function value() {
-    if (this._progressPath === null) {
-        throw new Error(DESTROYED_ERROR);
-    }
-
-    if (this._progressPath === undefined) {
-        return 0;
-    }
-
-    return this._progressPath.value();
-};
-
-Shape.prototype.setText = function setText(newText) {
-    if (this._progressPath === null) {
-        throw new Error(DESTROYED_ERROR);
-    }
-
-    if (this.text === null) {
-        // Create new text node
-        this.text = this._createTextContainer(this._opts, this._container);
-        this._container.appendChild(this.text);
-    }
-
-    // Remove previous text and add new
-    if (utils.isObject(newText)) {
-        utils.removeChildren(this.text);
-        this.text.appendChild(newText);
-    } else {
-        this.text.innerHTML = newText;
-    }
-};
-
-Shape.prototype._createSvgView = function _createSvgView(opts) {
-    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
-    this._initializeSvg(svg, opts);
-
-    var trailPath = null;
-    // Each option listed in the if condition are 'triggers' for creating
-    // the trail path
-    if (opts.trailColor || opts.trailWidth) {
-        trailPath = this._createTrail(opts);
-        svg.appendChild(trailPath);
-    }
-
-    var path = this._createPath(opts);
-    svg.appendChild(path);
-
-    return {
-        svg: svg,
-        path: path,
-        trail: trailPath
-    };
-};
-
-Shape.prototype._initializeSvg = function _initializeSvg(svg, opts) {
-    svg.setAttribute('viewBox', '0 0 100 100');
-};
-
-Shape.prototype._createPath = function _createPath(opts) {
-    var pathString = this._pathString(opts);
-    return this._createPathElement(pathString, opts);
-};
-
-Shape.prototype._createTrail = function _createTrail(opts) {
-    // Create path string with original passed options
-    var pathString = this._trailString(opts);
-
-    // Prevent modifying original
-    var newOpts = utils.extend({}, opts);
-
-    // Defaults for parameters which modify trail path
-    if (!newOpts.trailColor) {
-        newOpts.trailColor = '#eee';
-    }
-    if (!newOpts.trailWidth) {
-        newOpts.trailWidth = newOpts.strokeWidth;
-    }
-
-    newOpts.color = newOpts.trailColor;
-    newOpts.strokeWidth = newOpts.trailWidth;
-
-    // When trail path is set, fill must be set for it instead of the
-    // actual path to prevent trail stroke from clipping
-    newOpts.fill = null;
-
-    return this._createPathElement(pathString, newOpts);
-};
-
-Shape.prototype._createPathElement = function _createPathElement(pathString, opts) {
-    var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
-    path.setAttribute('d', pathString);
-    path.setAttribute('stroke', opts.color);
-    path.setAttribute('stroke-width', opts.strokeWidth);
-
-    if (opts.fill) {
-        path.setAttribute('fill', opts.fill);
-    } else {
-        path.setAttribute('fill-opacity', '0');
-    }
-
-    return path;
-};
-
-Shape.prototype._createTextContainer = function _createTextContainer(opts, container) {
-    var textContainer = document.createElement('div');
-    textContainer.className = opts.text.className;
-
-    var textStyle = opts.text.style;
-    if (textStyle) {
-        if (opts.text.autoStyleContainer) {
-            container.style.position = 'relative';
-        }
-
-        utils.setStyles(textContainer, textStyle);
-        // Default text color to progress bar's color
-        if (!textStyle.color) {
-            textContainer.style.color = opts.color;
-        }
-    }
-
-    this._initializeTextContainer(opts, container, textContainer);
-    return textContainer;
-};
-
-// Give custom shapes possibility to modify text element
-Shape.prototype._initializeTextContainer = function(opts, container, element) {
-    // By default, no-op
-    // Custom shapes should respect API options, such as text.style
-};
-
-Shape.prototype._pathString = function _pathString(opts) {
-    throw new Error('Override this function for each progress bar');
-};
-
-Shape.prototype._trailString = function _trailString(opts) {
-    throw new Error('Override this function for each progress bar');
-};
-
-Shape.prototype._warnContainerAspectRatio = function _warnContainerAspectRatio(container) {
-    if (!this.containerAspectRatio) {
-        return;
-    }
-
-    var computedStyle = window.getComputedStyle(container, null);
-    var width = parseFloat(computedStyle.getPropertyValue('width'), 10);
-    var height = parseFloat(computedStyle.getPropertyValue('height'), 10);
-    if (!utils.floatEquals(this.containerAspectRatio, width / height)) {
-        console.warn(
-            'Incorrect aspect ratio of container',
-            '#' + container.id,
-            'detected:',
-            computedStyle.getPropertyValue('width') + '(width)',
-            '/',
-            computedStyle.getPropertyValue('height') + '(height)',
-            '=',
-            width / height
-        );
-
-        console.warn(
-            'Aspect ratio of should be',
-            this.containerAspectRatio
-        );
-    }
-};
-
-module.exports = Shape;
-
-},{"./path":5,"./utils":8}],8:[function(require,module,exports){
-// Utility functions
-
-var PREFIXES = 'Webkit Moz O ms'.split(' ');
-var FLOAT_COMPARISON_EPSILON = 0.001;
-
-// Copy all attributes from source object to destination object.
-// destination object is mutated.
-function extend(destination, source, recursive) {
-    destination = destination || {};
-    source = source || {};
-    recursive = recursive || false;
-
-    for (var attrName in source) {
-        if (source.hasOwnProperty(attrName)) {
-            var destVal = destination[attrName];
-            var sourceVal = source[attrName];
-            if (recursive && isObject(destVal) && isObject(sourceVal)) {
-                destination[attrName] = extend(destVal, sourceVal, recursive);
-            } else {
-                destination[attrName] = sourceVal;
-            }
-        }
-    }
-
-    return destination;
-}
-
-// Renders templates with given variables. Variables must be surrounded with
-// braces without any spaces, e.g. {variable}
-// All instances of variable placeholders will be replaced with given content
-// Example:
-// render('Hello, {message}!', {message: 'world'})
-function render(template, vars) {
-    var rendered = template;
-
-    for (var key in vars) {
-        if (vars.hasOwnProperty(key)) {
-            var val = vars[key];
-            var regExpString = '\\{' + key + '\\}';
-            var regExp = new RegExp(regExpString, 'g');
-
-            rendered = rendered.replace(regExp, val);
-        }
-    }
-
-    return rendered;
-}
-
-function setStyle(element, style, value) {
-    var elStyle = element.style;  // cache for performance
-
-    for (var i = 0; i < PREFIXES.length; ++i) {
-        var prefix = PREFIXES[i];
-        elStyle[prefix + capitalize(style)] = value;
-    }
-
-    elStyle[style] = value;
-}
-
-function setStyles(element, styles) {
-    forEachObject(styles, function(styleValue, styleName) {
-        // Allow disabling some individual styles by setting them
-        // to null or undefined
-        if (styleValue === null || styleValue === undefined) {
-            return;
-        }
-
-        // If style's value is {prefix: true, value: '50%'},
-        // Set also browser prefixed styles
-        if (isObject(styleValue) && styleValue.prefix === true) {
-            setStyle(element, styleName, styleValue.value);
-        } else {
-            element.style[styleName] = styleValue;
-        }
-    });
-}
-
-function capitalize(text) {
-    return text.charAt(0).toUpperCase() + text.slice(1);
-}
-
-function isString(obj) {
-    return typeof obj === 'string' || obj instanceof String;
-}
-
-function isFunction(obj) {
-    return typeof obj === 'function';
-}
-
-function isArray(obj) {
-    return Object.prototype.toString.call(obj) === '[object Array]';
-}
-
-// Returns true if `obj` is object as in {a: 1, b: 2}, not if it's function or
-// array
-function isObject(obj) {
-    if (isArray(obj)) {
-        return false;
-    }
-
-    var type = typeof obj;
-    return type === 'object' && !!obj;
-}
-
-function forEachObject(object, callback) {
-    for (var key in object) {
-        if (object.hasOwnProperty(key)) {
-            var val = object[key];
-            callback(val, key);
-        }
-    }
-}
-
-function floatEquals(a, b) {
-    return Math.abs(a - b) < FLOAT_COMPARISON_EPSILON;
-}
-
-// https://coderwall.com/p/nygghw/don-t-use-innerhtml-to-empty-dom-elements
-function removeChildren(el) {
-    while (el.firstChild) {
-        el.removeChild(el.firstChild);
-    }
-}
-
-module.exports = {
-    extend: extend,
-    render: render,
-    setStyle: setStyle,
-    setStyles: setStyles,
-    capitalize: capitalize,
-    isString: isString,
-    isFunction: isFunction,
-    isObject: isObject,
-    forEachObject: forEachObject,
-    floatEquals: floatEquals,
-    removeChildren: removeChildren
-};
-
-},{}]},{},[4])(4)
-});

File diff suppressed because it is too large
+ 0 - 0
dashboard/js/progressbar.min.js


+ 0 - 60
dashboard/js/widget.js

@@ -1,60 +0,0 @@
-/* CLOCK */
-var circle;
-function widget_clock_init(){
-	circle = new ProgressBar.Circle('#clock', {
-		color: '#50C8FB',
-		duration: 3000,
-		easing: 'easeInOut',
-		text: {
-		style : { fontSize : '38px'},
-		value : '00:00:00'
-		}
-	});
-
-	refresh_clock();
-	setInterval(function(){
-		refresh_clock();
-	},1000);
-}
-
-function refresh_clock(){
-	var d = new Date();
-	var hour = d.getHours(); 
-	var minut = ("00" + d.getMinutes()).slice(-2) ; 
-	var second = ("00" + d.getSeconds()).slice(-2) ; 
-	var year = d.getFullYear() ; 
-	var month = ("00" + (d.getMonth()+1)).slice(-2) ; 
-	var day = ("00" + d.getDate()).slice(-2) ; 
-	var days = ["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"];
-	var monthName = ["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Aout","Septembre","Octobre","Novembre","Décembre"];
-
-	var dayName = days[d.getDay()];
-	circle.setText(hour+':'+minut+':'+second+'<div class="dayName">'+dayName+'</div><div class="dayDate">'+day+' '+monthName[d.getMonth()]+' '+year+'</div>');
-	circle.set(second/60);
-}
-
-
-/* PROFILE */
-function dashboard_widget_profile_configure_save(widget,modal){
-	var data = $('#dashboard-widget-profile-form').toJson();
-	data.action = 'dashboard_widget_profile_configure_save';
-	data.id = modal.attr('data-widget');
-
-	$.action(data,function(){
-		$.message('success','Configuration enregistrée');
-		dashboard_dashboardwidget_search();
-	});
-}
-
-
-/* HTML */
-function dashboard_widget_html_configure_save(widget,modal){
-	var data = $('#dashboard-widget-html-form').toJson();
-	data.action = 'dashboard_widget_html_configure_save';
-	data.id = modal.attr('data-widget');
-
-	$.action(data,function(){
-		$.message('success','Configuration enregistrée');
-		dashboard_dashboardwidget_search();
-	});
-}

+ 0 - 126
dashboard/page.home.php

@@ -1,126 +0,0 @@
-<?php 
-global $myUser,$conf; 
-require_once(__DIR__.SLASH.'Dashboard.class.php');
-require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-$mandatoryDashboard = Dashboard::load(array('mandatory'=>'1'));
-$readonly = false;
-if($mandatoryDashboard){
-	$readonly = !$myUser->can('dashboard','configure');
-	$dashboards =  array($mandatoryDashboard);
-}else{
-	$dashboards = Dashboard::loadAll(array('user'=>$myUser->login));
-} ?>
-<div class="dashboard-container <?php echo $readonly?'readonly':'' ?>" style="<?php echo count($dashboards)==1 ? 'padding-left: 0px;' : ''; ?>">
-	<?php if($myUser->connected()): ?>
-		<ul id="dashboard-view" class="<?php echo count($dashboards)>1?'':'hidden' ?>" >
-			<li class="dashboard-view-title">DASH</li>
-			<?php 
-			
-			if(count($dashboards)==0){
-				$defaultDash = Dashboard::provide();
-				$defaultDash->user = $myUser->login;
-				$defaultDash->label = 'Général';
-				$defaultDash->icon = 'far fa-bookmark';
-				$defaultDash->default = true;
-				$defaultDash->save();
-				$dashboards[] = $defaultDash;
-
-				foreach(array('profile','clock','log') as $i=>$widget){
-					$item = new DashboardWidget();
-					$item->model = $widget;
-					$item->position = $i;
-					$item->dashboard = $defaultDash->id;
-					$item->save();
-				}
-			}
-			foreach($dashboards as $dashboard): ?>
-				<li class="dashboard-item" <?php echo $dashboard->default?'data-selected="1"':''; ?> data-id="<?php echo $dashboard->id; ?>"  title="<?php echo $dashboard->label; ?>"><span><?php echo $dashboard->label; ?></span><div><i class="<?php echo $dashboard->icon; ?>"></i></div></li>
-			<?php endforeach; ?>
-		</ul>
-		<div class="clear"></div>
-
-		<ul class="dashboard-widget-menu">
-		<li data-toggle="modal" data-target="#addWidgetModal">
-			<div title="Ajouter un widget"><i class="fas fa-plus"></i> <span>WIDGET</span></div>
-		</li>
-	</ul>
-	
-	<div class="row" id="dashboard">
-		<!-- MODEL WIDGET -->
-		<div class="widget hidden" data-width="4" data-id="" >
-			<div class="widget_window">
-				<div class="widget_header pl-2">
-					<i class="fa fa-caret"></i> <span></span>
-					<ul class="widget_options"></ul>
-				</div>
-				<div class="widget_content"></div>
-				<div class="widget_footer"></div>
-				<div class="widget_resize"></div>
-			</div>
-		</div>
-		<!-- Add wiget modal -->
-		<div class="modal fade" id="addWidgetModal" tabindex="-1" role="dialog" aria-labelledby="widget-add-label" aria-hidden="true">
-			<div class="modal-dialog modal-lg" role="document">
-				<div class="modal-content">
-					<div class="modal-header">
-						<h5 class="modal-title" id="widget-add-label">Ajout d'un widget</h5>
-						<button type="button" class="close" data-dismiss="modal" aria-label="Close">
-					    	<span aria-hidden="true">&times;</span>
-						</button>
-					</div>
-					<div class="modal-body">
-						<div class="row">
-							<div class="col-md-4">
-							<?php
-								$models = array();
-								Plugin::callHook('widget',array(&$models));
-							?>
-								<select class="form-control" id="widget-list" class="left" size="8">
-									<option data-description="Sélectionnez le widget que vous souhaitez ajouter" data-width="" data-background="" value="" data-icon="fas fa-plus"> - </option>
-									<?php
-									foreach($models as $model): ?>
-									<option data-description="<?php echo $model->description; ?>" data-width="<?php echo !empty($model->width)?$model->width:1; ?>"  data-background="<?php echo $model->background; ?>" data-icon="<?php echo $model->icon; ?>" value="<?php echo $model->model; ?>"><?php echo $model->title; ?></option>
-								<?php endforeach; ?>
-								</select>
-							</div>
-							<div class="widgetDescription col-md-6">
-								<h3><i class='fas fa-plus'></i> <span>Sélectionnez un widget</span></h3>
-								<p>Sélectionnez le widget que vous souhaitez ajouter</p> 
-								<div class="widgetWidth"></div>
-								<div class='widgetColor'></div>
-							</div>
-						</div>
-				  	</div>
-				<div class="modal-footer">
-				    <button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
-					<button type="button" class="btn btn-primary" onclick="dashboard_dashboardwidget_add();"><i class="fas fa-plus"></i> Ajouter</button>
-				</div>
-				</div>
-			</div>
-		</div>
-		<!-- Configure wiget modal -->
-		<div class="modal fade" id="configureWidgetModal" tabindex="-1" role="dialog" aria-labelledby="widget-configure-label" aria-hidden="true">
-			<div class="modal-dialog modal-lg" role="document">
-				<div class="modal-content">
-					<div class="modal-header">
-						<h5 class="modal-title" id="widget-configure-label">Configuration d'un widget</h5>
-						<button type="button" class="close" data-dismiss="modal" aria-label="Close">
-							<span aria-hidden="true">&times;</span>
-						</button>
-					</div>
-					<div class="modal-body">
-						<div class="pluginContent">
-							<!-- Configuration plugin ici -->
-						</div>
-					</div>
-					<div class="modal-footer">
-					 	<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
-						<button type="button" class="btn btn-primary" onclick="dashboard_dashboardwidget_save_configuration();"><i class="fas fa-check"></i> Enregistrer</button>
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-	<?php endif; ?>
-</div> 

+ 0 - 141
dashboard/setting.dashboard.php

@@ -1,141 +0,0 @@
-<?php
-global $myUser;
-User::check_access('dashboard','configure');
-require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-require_once(__DIR__.SLASH.'Dashboard.class.php');
-
-$widgets = array();
-foreach (Dashboard::loadAll(array('user'=>$myUser->login)) as $dashboard) {
-    foreach (DashboardWidget::loadAll(array('dashboard'=>$dashboard->id)) as $widget) {
-        $widgets[] = $widget;
-    }
-}
-usort($widgets, function($a,$b){
-    if($a > $b) return 1;
-    if($a < $b) return -1;
-    if($a == $b) return 0;
-});
-?>
-
-<div class="row">
-    <div class="col-md-12"><br>
-        <h3>Réglages Dashboard</h3>
-        <div class="clear"></div>
-        <hr>
-    </div>
-</div>
-
-<div class="row">
-    <!-- search results -->
-    <div class="col-xl-12">
-        <div class="tab-container mb-0 noPrint">
-            <ul class="nav nav-tabs" role="tablist">
-                <li class="nav-item"><a data-toggle="tab" class="nav-link active" href="#tab-dashboards" aria-controls="tab-dashboards" aria-selected="false">Liste Dashboards</a></li>
-                <li class="nav-item"><a data-toggle="tab" class="nav-link" href="#tab-shared-widgets" aria-controls="tab-shared-widgets" aria-selected="false">Widgets communs</a></li>
-            </ul>
-        </div>
-
-        <div class="tab-content">
-            <!-- Onglet Dashboards -->
-            <div class="tab-pane show active in" id="tab-dashboards" role="tabpanel" aria-labelledby="tab-dashboards">
-                <div class="alert alert-info my-3"><strong>NB :</strong> Marquer une dashboard comme obligatoire imposera celle-ci à l'ensemble des utilisateurs (sans possibilité de modification)</div>
-                <legend>Dashboard disponibles :</legend>
-                <table id="dashboards" class="table table-striped table-dashboard" data-entity-search="dashboard_search">
-                     <thead class="bg-secondary text-light">
-                         <tr>
-                             <th data-sortable="label">Libellé</th>
-                             <?php if($myUser->can('dashboard','configure')): ?>
-                             <th data-sortable="creator">Utilisateur</th>
-                             <?php endif; ?>
-                             <th data-sortable="icon">Icône</th>
-                             <th data-sortable="default" class="text-center">Par défaut</th>
-                             <th data-sortable="mandatory" class="text-center">Obligatoire</th>
-                             <th></th>
-                         </tr>
-                         <tr id="dashboard-form" data-action="dashboard_dashboard_save" data-id="">
-                             <th class="align-middle"><input id="label" name="label" class="form-control" placeholder="eg. Metrics..." type="text"></th>
-                             <?php if($myUser->can('dashboard','configure')): ?>
-                             <th class="align-middle position-relative"><input id="user" name="user" data-type="user" class="form-control" placeholder="eg. John Doe..."></th>
-                             <?php endif; ?>
-                             <th class="align-middle position-relative"><input id="icon" name="icon" data-type="icon" class="form-control w-100" value="far fa-bookmark" type="text"></th>
-                             <th class="align-middle text-center"><input id="default" name="default" class="" data-type="checkbox" type="checkbox"></th>
-                             <th class="align-middle text-center"><input id="mandatory" name="mandatory" class="" data-type="checkbox" type="checkbox"></th>
-                             <th class="align-middle text-right"><div onclick="dashboard_dashboard_save();" class="btn btn-success"><i class="fas fa-check"></i></div></th>
-                         </tr>
-                     </thead>
-                     
-                     <tbody>
-                         <tr data-id="{{id}}" class="hidden">
-                             <td>{{label}}</td>
-                             <?php if($myUser->can('dashboard','configure')): ?>
-                             <td>{{user}}</td>
-                             <?php endif; ?>
-                             <td><i class="{{icon}}"></i> {{icon}}</td>
-                             <td class="text-center">
-                                 {{#default}}<i class="fas fa-check text-success"></i>{{/default}}
-                                 {{^default}}<i class="fas fa-times text-danger"></i>{{/default}}
-                             </td>
-                             <td class="text-center">
-                                 {{#mandatory}}<i class="fas fa-check text-success"></i>{{/mandatory}}
-                                 {{^mandatory}}<i class="fas fa-times text-danger"></i>{{/mandatory}}
-                             </td>
-                             <td class="text-right">
-                                 <div class="btn btn-info btn-mini btn-squarred" onclick="dashboard_dashboard_edit(this);"><i class="fas fa-pencil-alt"></i></div>
-                                 <div class="btn btn-danger btn-mini btn-squarred" onclick="dashboard_dashboard_delete(this);"><i class="far fa-trash-alt"></i></div>
-                             </td>
-                         </tr>
-                    </tbody>
-                </table>
-
-                <!-- Pagination -->
-                <ul class="pagination">
-                    <li class="page-item hidden" data-value="{{value}}" title="Voir la page {{label}}" onclick="$(this).parent().find('li').removeClass('active');$(this).addClass('active');dashboard_dashboard_search();">
-                        <a class="page-link" href="#">{{label}}</a>
-                    </li>
-                </ul>
-            </div>
-
-            <div class="tab-pane" id="tab-shared-widgets" role="tabpanel" aria-labelledby="tab-shared-widgets"><br>
-                <legend>Gestion des widgets communs :</legend>
-                <table id="dashboard-widget-shares" class="table table-striped " data-entity-search="dashboard_widget_share_search">
-                    <thead class="bg-secondary text-light">
-                        <tr>
-                            <th>ID Widget</th>
-                            <th class="text-center">Obligatoire</th>
-                            <th>Afficher pour <small class="text-muted">(Laisser vide pour tout le monde)</small></th>
-                            <th>Ordre par défaut</th>
-                            <th></th>
-                        </tr>
-                        <tr id="dashboard-widget-share-form" data-action="dashboard_widget_share_save" data-id="">
-                            <th>
-                                <select id="widget" name="widget" class="form-control">
-                                    <option value="">-</option>
-                                <?php foreach ($widgets as $widget) : ?>
-                                   <option value="<?php echo $widget->id; ?>">Widget type <?php echo $widget->model ?> en position <?php echo $widget->position ?></option> 
-                                <?php endforeach; ?>
-                                </select>
-                            </th>
-                            <th class="text-center align-middle"><input id="mandatory" data-type="checkbox" name="mandatory" class="" placeholder="" value="" type="checkbox"></th>
-                            <th style="position:relative;"><input id="uid" name="uid" class="form-control" placeholder="" value="" type="text" data-type="user"  data-types="user,rank"></th>
-                            <th><input id="sort" name="sort" class="form-control" placeholder="" value="" type="text"></th>
-                            <th class="text-center"><div onclick="dashboard_widget_share_save();" class="btn btn-success"><i class="fas fa-check"></i></div></th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                        <tr data-id="{{id}}" class="hidden">
-                            <td>{{widget.model}} (#{{widget.id}}) en position {{widget.position}}</td>
-                            <td>{{mandatory}}</td>
-                            <td>{{for}}</td>
-                            <td>{{sort}}</td>
-                            <td class="text-right">
-                                <div class="btn btn-info btn-mini btn-squarred " onclick="dashboard_widget_share_edit(this);"><i class="fas fa-pencil-alt"></i></div>
-                                <div class="btn btn-danger btn-mini btn-squarred " onclick="dashboard_widget_share_delete(this);"><i class="far fa-trash-alt"></i></div>
-                            </td>
-                        </tr>
-                   </tbody>
-                </table>
-            </div>
-       </div>
-    </div>
-</div>

+ 0 - 6
dashboard/widget.clock.php

@@ -1,6 +0,0 @@
-<?php 
-global $myUser;
-?>
-<div class="clockContainer">
-	<div class="clock" id="clock"></div>
-</div>

+ 0 - 20
dashboard/widget.html.configure.php

@@ -1,20 +0,0 @@
-<?php
-$html = empty( $widget->data('html')) ? '<div class="p-3">Votre texte ici</div>':  $widget->data('html');
-
-?>
-
-<div id="dashboard-widget-html-form">
-	<div>
-		<label class="m-0">Titre / couleur de la fenetre :</label>
-		<div class="input-group mb-2">
-			<input class="form-control" type="text" value="<?php echo $widget->data('title'); ?>" id="widget-html-title">
-			
-			<input class="form-control" data-type="color" type="text" value="<?php echo $widget->data('color'); ?>" id="widget-html-color">
-			
-		</div>
-	</div>
-	<div>
-		<label class="m-0">Code html à afficher :</label>
-		<textarea data-type="wysiwyg" data-script-allow="true" class="mt-0 mb-2" id="widget-html-content" style="height:400px;"><?php echo $html; ?></textarea>
-	</div>
-</div> 

+ 0 - 11
dashboard/widget.html.php

@@ -1,11 +0,0 @@
-<?php 
-global $myUser;
-
-
-$html = $widget->data('html');
-
-if(empty($html)) $html = '<h4 class="noContent"><i class="fas fa-code"></i> Aucun code spécifié</h4>';
-?>
-<div class="widgetHtmlContainer">
-	<?php echo  $html; ?>
-</div>

+ 0 - 17
dashboard/widget.logs.php

@@ -1,17 +0,0 @@
-<?php 
-$logs = Log::loadAll(array(),array('created DESC'),array(30));
-$lastDate = '';
-?>
-
-<ul class="dashboard-widget-log">
-<?php foreach($logs as $log): ?>
-	<li>
-		<?php if($lastDate!=date('d-m-y',$log->created)): 
-			$lastDate = date('d-m-y',$log->created); ?>
-			<h2 class="text-muted"><i class="far fa-calendar-alt"></i> <?php echo day_name(date('N',$log->created)).' '.date('d ',$log->created).' '.month_name(date('m',$log->created)).' '.date('Y',$log->created); ?></h2>
-		<?php endif; ?>
-		<span class="font-weight-bold"><i class="far fa-clock"></i> <?php echo date('H:i:s',$log->created); ?></span> | <small class="text-primary pr-1"><i class="far fa-meh-blank"></i> <?php echo $log->creator; ?></small>
-		<?php echo $log->label(); ?>
-	</li>
-<?php endforeach; ?>
-</ul>

+ 0 - 11
dashboard/widget.profile.configure.php

@@ -1,11 +0,0 @@
-<?php
-
-?>
-<div id="dashboard-widget-profile-form">
-	<div class="input-group">
-		<div class="input-group-prepend">
-			<label for="widget-profile-background-color" class="input-group-text">Couleur de bannière :</label>
-		</div>
-		<input class="form-control" name="widget-profile-background-color" type="text" data-type="color" value="<?php echo $widget->data('background-color'); ?>" id="widget-profile-background-color">
-	</div>
-</div> 

+ 0 - 24
dashboard/widget.profile.php

@@ -1,24 +0,0 @@
-<?php 
-global $myUser;
-
-$function = !empty($myUser->function) ? $myUser->function : 'Employé';
-$phone = !empty($myUser->phone) ? $myUser->phone : '';
-$mail = !empty($myUser->mail) ? $myUser->mail : '';
-?>
-<div class="profileContainer">
-	<div class="profileHeader" style="<?php echo 'background-color:'.$widget->data('background-color'); ?>"></div>
-	<div class="profileImage">
-		<a href="account.php"><img class="avatar-mini" src="<?php echo $myUser->getAvatar(); ?>"><div title="Éditer mon profil" class="edit-overlay"></div></a>
-	</div>
-	<div class="profile-content">
-		<h3 class="w-100"><?php echo $myUser->fullname(); ?></h3>
-		<small><?php echo $function; ?></small><br>
-		<small><?php echo $phone; ?> <a href="mailto:'.$mail.'"><?php echo $mail; ?></a></small>
-	</div>
-	<div class="profile-buttons">
-		<a href="account.php" class="btn text-uppercase"><i class="far fa-meh-blank"></i> Profil</a>
-		<a href="account.php?section=notification" class="btn text-uppercase"><i class="fas fa-bell"></i> Notifications</a>
-		<a onclick="core_logout();" class="btn text-danger text-uppercase"><i class="fas fa-sign-out-alt"></i> Déconnexion</a>
-		<div class="clear"></div>
-	</div>
-</div>

Some files were not shown because too many files changed in this diff