From 2e18b36a287ad9b25619f9e2a073dcedf6d620ee Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 18 May 2016 18:04:56 +0200 Subject: MORE WMORK --- apis/update.inc.php | 7 +- config.php.example | 2 +- inc/dictionary.inc.php | 7 +- inc/message.inc.php | 85 +++++++-- inc/module.inc.php | 21 ++- inc/property.inc.php | 6 + inc/render.inc.php | 39 +++-- inc/user.inc.php | 2 +- index.php | 2 +- modules-available/backup/page.inc.php | 1 - modules-available/baseconfig/config.json | 3 +- modules-available/baseconfig/templates/_page.html | 2 +- .../baseconfig_partitions_cdn/config.json | 4 + .../baseconfig_partitions_cdn/page.inc.php | 133 ++++++++++++++ .../baseconfig_partitions_cdn/templates/_page.html | 74 ++++++++ .../dozmod/hooks/main-warning.inc.php | 11 ++ modules-available/dozmod/lang/de/messages.json | 1 + modules-available/dozmod/lang/en/messages.json | 1 + modules-available/js_chart/clientscript.js | 11 ++ modules-available/js_chart/config.json | 1 + modules-available/js_circles/clientscript.js | 7 + modules-available/js_circles/config.json | 1 + modules-available/main/lang/de/global-tags.json | 2 + modules-available/main/lang/de/template-tags.json | 8 +- modules-available/main/lang/en/global-tags.json | 2 + modules-available/main/lang/en/template-tags.json | 8 +- modules-available/main/page.inc.php | 44 ++--- .../main/templates/messagebox-error.html | 1 - .../main/templates/messagebox-info.html | 1 - .../main/templates/messagebox-success.html | 1 - .../main/templates/messagebox-warning.html | 1 - modules-available/main/templates/messagebox.html | 7 + modules-available/main/templates/page-main.html | 31 ---- .../minilinux/hooks/main-warning.inc.php | 6 + modules-available/minilinux/lang/de/messages.json | 3 + modules-available/minilinux/lang/en/messages.json | 3 + modules-available/serversetup-bwlp/config.json | 4 + .../serversetup-bwlp/lang/de/messages.json | 3 + .../serversetup-bwlp/lang/de/module.json | 4 + .../serversetup-bwlp/lang/de/template-tags.json | 26 +++ .../serversetup-bwlp/lang/en/messages.json | 3 + .../serversetup-bwlp/lang/en/module.json | 3 + .../serversetup-bwlp/lang/en/template-tags.json | 38 ++++ .../serversetup-bwlp/lang/pt/messages.json | 3 + .../serversetup-bwlp/lang/pt/module.json | 3 + .../serversetup-bwlp/lang/pt/template-tags.json | 39 +++++ modules-available/serversetup-bwlp/page.inc.php | 140 +++++++++++++++ .../serversetup-bwlp/templates/ipaddress.html | 34 ++++ .../serversetup-bwlp/templates/ipxe.html | 70 ++++++++ .../serversetup-bwlp/templates/ipxe_update.html | 20 +++ modules-available/serversetup/config.json | 4 - .../serversetup/lang/de/messages.json | 3 - modules-available/serversetup/lang/de/module.json | 4 - .../serversetup/lang/de/template-tags.json | 26 --- .../serversetup/lang/en/messages.json | 3 - modules-available/serversetup/lang/en/module.json | 3 - .../serversetup/lang/en/template-tags.json | 38 ---- .../serversetup/lang/pt/messages.json | 3 - modules-available/serversetup/lang/pt/module.json | 3 - .../serversetup/lang/pt/template-tags.json | 39 ----- modules-available/serversetup/page.inc.php | 194 --------------------- .../serversetup/templates/ipaddress.html | 35 ---- .../serversetup/templates/ipxe-adv.html | 149 ---------------- .../serversetup/templates/ipxe-smp.html | 62 ------- .../serversetup/templates/ipxe_update.html | 20 --- modules-available/statistics/config.json | 2 +- modules-available/statistics/page.inc.php | 2 - .../sysconfig/addmodule_branding.inc.php | 1 - .../sysconfig/addmodule_custommodule.inc.php | 1 - modules-available/sysconfig/clientscript.js | 21 +++ .../sysconfig/hooks/main-warning.inc.php | 6 + .../sysconfig/inc/configmodule.inc.php | 2 +- modules-available/sysconfig/lang/de/messages.json | 27 +-- modules-available/sysconfig/lang/en/messages.json | 27 +-- modules-available/sysconfig/page.inc.php | 1 - modules-available/syslog/clientscript.js | 8 + modules-available/syslog/page.inc.php | 3 - modules-available/syslog/style.css | 45 +++++ modules-available/systemstatus/config.json | 3 +- modules-available/systemstatus/page.inc.php | 4 +- modules-available/translation/page.inc.php | 3 + .../vmstore/hooks/main-warning.inc.php | 10 ++ modules-available/vmstore/lang/de/messages.json | 3 + modules-available/vmstore/lang/en/messages.json | 3 + script/bootstrap-tagsinput.min.js | 8 - script/chart.min.js | 11 -- script/circles.min.js | 7 - script/custom.js | 32 ---- script/fileselect.js | 6 - style/bootstrap-tagsinput.css | 45 ----- 90 files changed, 930 insertions(+), 866 deletions(-) create mode 100644 modules-available/baseconfig_partitions_cdn/config.json create mode 100644 modules-available/baseconfig_partitions_cdn/page.inc.php create mode 100644 modules-available/baseconfig_partitions_cdn/templates/_page.html create mode 100644 modules-available/dozmod/hooks/main-warning.inc.php create mode 100644 modules-available/js_chart/clientscript.js create mode 100644 modules-available/js_chart/config.json create mode 100644 modules-available/js_circles/clientscript.js create mode 100644 modules-available/js_circles/config.json delete mode 100644 modules-available/main/templates/messagebox-error.html delete mode 100644 modules-available/main/templates/messagebox-info.html delete mode 100644 modules-available/main/templates/messagebox-success.html delete mode 100644 modules-available/main/templates/messagebox-warning.html create mode 100644 modules-available/main/templates/messagebox.html create mode 100644 modules-available/minilinux/hooks/main-warning.inc.php create mode 100644 modules-available/minilinux/lang/de/messages.json create mode 100644 modules-available/minilinux/lang/en/messages.json create mode 100644 modules-available/serversetup-bwlp/config.json create mode 100644 modules-available/serversetup-bwlp/lang/de/messages.json create mode 100644 modules-available/serversetup-bwlp/lang/de/module.json create mode 100644 modules-available/serversetup-bwlp/lang/de/template-tags.json create mode 100644 modules-available/serversetup-bwlp/lang/en/messages.json create mode 100644 modules-available/serversetup-bwlp/lang/en/module.json create mode 100644 modules-available/serversetup-bwlp/lang/en/template-tags.json create mode 100644 modules-available/serversetup-bwlp/lang/pt/messages.json create mode 100644 modules-available/serversetup-bwlp/lang/pt/module.json create mode 100644 modules-available/serversetup-bwlp/lang/pt/template-tags.json create mode 100644 modules-available/serversetup-bwlp/page.inc.php create mode 100644 modules-available/serversetup-bwlp/templates/ipaddress.html create mode 100644 modules-available/serversetup-bwlp/templates/ipxe.html create mode 100644 modules-available/serversetup-bwlp/templates/ipxe_update.html delete mode 100644 modules-available/serversetup/config.json delete mode 100644 modules-available/serversetup/lang/de/messages.json delete mode 100644 modules-available/serversetup/lang/de/module.json delete mode 100644 modules-available/serversetup/lang/de/template-tags.json delete mode 100644 modules-available/serversetup/lang/en/messages.json delete mode 100644 modules-available/serversetup/lang/en/module.json delete mode 100644 modules-available/serversetup/lang/en/template-tags.json delete mode 100644 modules-available/serversetup/lang/pt/messages.json delete mode 100644 modules-available/serversetup/lang/pt/module.json delete mode 100644 modules-available/serversetup/lang/pt/template-tags.json delete mode 100644 modules-available/serversetup/page.inc.php delete mode 100644 modules-available/serversetup/templates/ipaddress.html delete mode 100644 modules-available/serversetup/templates/ipxe-adv.html delete mode 100644 modules-available/serversetup/templates/ipxe-smp.html delete mode 100644 modules-available/serversetup/templates/ipxe_update.html create mode 100644 modules-available/sysconfig/clientscript.js create mode 100644 modules-available/sysconfig/hooks/main-warning.inc.php create mode 100644 modules-available/syslog/clientscript.js create mode 100644 modules-available/syslog/style.css create mode 100644 modules-available/vmstore/hooks/main-warning.inc.php create mode 100644 modules-available/vmstore/lang/de/messages.json create mode 100644 modules-available/vmstore/lang/en/messages.json delete mode 100644 script/bootstrap-tagsinput.min.js delete mode 100644 script/chart.min.js delete mode 100644 script/circles.min.js delete mode 100644 script/custom.js delete mode 100644 style/bootstrap-tagsinput.css diff --git a/apis/update.inc.php b/apis/update.inc.php index 3ba7f9a0..fb5af7d6 100644 --- a/apis/update.inc.php +++ b/apis/update.inc.php @@ -1,5 +1,9 @@ 0, 'main.settings' => 1, 'main.status' => 2, 'main.users' => 3); $MENU_SETTING_SORT_ORDER = array( 'news' => 0, 'sysconfig' => 1, 'baseconfig' => 2, 'locations' => 3, // main.content diff --git a/inc/dictionary.inc.php b/inc/dictionary.inc.php index 0dafe9d9..5679c52d 100644 --- a/inc/dictionary.inc.php +++ b/inc/dictionary.inc.php @@ -90,12 +90,9 @@ class Dictionary return self::translateFileModule('main', 'global-tags', $tag); } - public static function getMessage($id) + public static function getMessage($module, $id) { - if (!preg_match('/^(\w+)\.(.+)$/', $id, $out)) { - return 'Invalid Message ID format: ' . $id; - } - $string = self::translateFileModule($out[1], 'messages', $out[2]); + $string = self::translateFileModule($module, 'messages', $id); if ($string === false) { return "($id) ({{0}}, {{1}}, {{2}}, {{3}})"; } diff --git a/inc/message.inc.php b/inc/message.inc.php index 15e89041..9197e4c2 100644 --- a/inc/message.inc.php +++ b/inc/message.inc.php @@ -13,7 +13,7 @@ class Message */ public static function addError($id) { - self::add('error', $id, func_get_args()); + self::add('danger', $id, func_get_args()); } public static function addWarning($id) @@ -40,10 +40,35 @@ class Message if (strstr($id, '.') === false) { $id = Page::getModule()->getIdentifier() . '.' . $id; } + if (count($params) > 1 && $params[1] === true) { + $params = array_slice($params, 2); + $linkModule = true; + } else { + $params = array_slice($params, 1); + $linkModule = false; + } + switch ($type) { + case 'danger': + $icon = 'exclamation-sign'; + break; + case 'warning': + $icon = 'warning'; + break; + case 'info': + $icon = 'info-sign'; + break; + case 'success': + $icon = 'ok'; + break; + default: + $icon = ''; + } self::$list[] = array( 'type' => $type, + 'icon' => $icon, 'id' => $id, - 'params' => array_slice($params, 1) + 'params' => $params, + 'link' => $linkModule ); if (self::$flushed) self::renderList(); } @@ -59,25 +84,36 @@ class Message if (empty(self::$list)) return; // Ajax - if (AJAX) { - foreach (self::$list as $item) { - $message = Dictionary::getMessage($item['id']); - foreach ($item['params'] as $index => $text) { - $message = str_replace('{{' . $index . '}}', '' . htmlspecialchars($text) . '', $message); - } - echo Render::parse('messagebox-' . $item['type'], array('message' => $message), 'main'); - } - self::$list = array(); - return; - } - // Non-Ajax + $mangled = array(); foreach (self::$list as $item) { - $message = Dictionary::getMessage($item['id']); + if (!preg_match('/^(\w+)\.(.+)$/', $item['id'], $out)) { + $message = 'Invalid Message ID format: ' . $item['id']; + } else { + $message = Dictionary::getMessage($out[1], $out[2]); + } foreach ($item['params'] as $index => $text) { $message = str_replace('{{' . $index . '}}', '' . htmlspecialchars($text) . '', $message); } - Render::addTemplate('messagebox-' . $item['type'], array('message' => $message), 'main'); - self::$alreadyDisplayed[] = $item; + if ($item['link'] && isset($out[1])) { + $item['link'] = $out[1]; + } + $mangled[] = array( + 'type' => $item['type'], + 'icon' => $item['icon'], + 'message' => $message, + 'link' => $item['link'] + ); + } + if (AJAX) { + foreach ($mangled as $entry) { + echo Render::parse('messagebox', $entry, 'main'); + } + } else { + // Non-Ajax + foreach ($mangled as $entry) { + Render::addTemplate('messagebox', $entry, 'main'); + } + self::$alreadyDisplayed = array_merge(self::$alreadyDisplayed, self::$list); } self::$list = array(); } @@ -90,7 +126,11 @@ class Message { $return = ''; foreach (self::$list as $item) { - $message = Dictionary::getMessage($item['id']); + if (!preg_match('/^(\w+)\.(.+)$/', $item['id'], $out)) { + $message = 'Invalid Message ID format: ' . $item['id']; + } else { + $message = Dictionary::getMessage($out[1], $out[2]); + } foreach ($item['params'] as $index => $text) { $message = str_replace('{{' . $index . '}}', $text, $message); } @@ -110,7 +150,11 @@ class Message $messages = is_array($_REQUEST['message']) ? $_REQUEST['message'] : array($_REQUEST['message']); foreach ($messages as $message) { $data = explode('|', $message); - if (count($data) < 2 || !preg_match('/^(error|warning|info|success)$/', $data[0])) continue; + if (substr($data[0], -1) === '@') { + $data[0] = substr($data[0], 0, -1); + array_splice($data, 1, 0, true); + } + if (count($data) < 2 || !preg_match('/^(danger|warning|info|success)$/', $data[0])) continue; self::add($data[0], $data[1], array_slice($data, 1)); } } @@ -123,6 +167,9 @@ class Message { $parts = array(); foreach (array_merge(self::$list, self::$alreadyDisplayed) as $item) { + if (isset($item['link']) && $item['link']) { + $item['type'] .= '@'; + } $str = 'message[]=' . urlencode($item['type'] . '|' .$item['id']); if (!empty($item['params'])) { $str .= '|' . urlencode(implode('|', $item['params'])); diff --git a/inc/module.inc.php b/inc/module.inc.php index 246505b5..13d9c1e4 100644 --- a/inc/module.inc.php +++ b/inc/module.inc.php @@ -22,8 +22,9 @@ class Module /** * Check whether given module is available, that is, all dependencies are - * met. If the module is available, it will be activated, so all it's classes - * are available through the auto-loader. + * met. If the module is available, it will be activated, so all its classes + * are available through the auto-loader, and any js or css is added to the + * final page output. * * @param string $moduleId module to check * @return bool true if module is available and activated @@ -88,6 +89,20 @@ class Module return self::$modules; } + /** + * @return \Module[] List of modules that have been activated + */ + public static function getActivated() + { + $ret = array(); + foreach (self::$modules as $module) { + if ($module->activated) { + $ret[] = $module; + } + } + return $ret; + } + public static function init() { if (self::$modules !== false) @@ -97,7 +112,7 @@ class Module return; self::$modules = array(); while (($dir = readdir($dh)) !== false) { - if (empty($dir) || preg_match('/[^a-zA-Z0-9]/', $dir)) + if (empty($dir) || preg_match('/[^a-zA-Z0-9_]/', $dir)) continue; if (!is_file('modules/' . $dir . '/config.json')) continue; diff --git a/inc/property.inc.php b/inc/property.inc.php index 13e3c66d..eae5033c 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -185,4 +185,10 @@ class Property return self::get('password-type', 'password'); } + + public static function getIpxeDefault() + { + return self::get('default-ipxe'); + } + } diff --git a/inc/render.inc.php b/inc/render.inc.php index 5fc5be92..b422d7f9 100644 --- a/inc/render.inc.php +++ b/inc/render.inc.php @@ -46,9 +46,8 @@ class Render public static function output() { Header('Content-Type: text/html; charset=utf-8'); - $zip = isset($_SERVER['HTTP_ACCEPT_ENCODING']) && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false); - if ($zip) - ob_start(); + $modules = Module::getActivated(); + ob_start('ob_gzhandler'); echo ' @@ -59,9 +58,16 @@ class Render - + '; + // Include any module specific styles + foreach ($modules as $module) { + $file = $module->getDir() . '/style.css'; + if (file_exists($file)) { + echo ''; + } + } + echo ' - @@ -80,20 +86,21 @@ class Render - ', + + '; + foreach ($modules as $module) { + $file = $module->getDir() . '/clientscript.js'; + if (file_exists($file)) { + echo ''; + } + } + echo self::$footer , ' ' ; - if ($zip) { - Header('Content-Encoding: gzip'); - ob_implicit_flush(false); - $gzip_contents = ob_get_contents(); - ob_end_clean(); - echo "\x1f\x8b\x08\x00\x00\x00\x00\x00"; - echo substr(gzcompress($gzip_contents, 5), 0, -4); - } + ob_end_flush(); } /** @@ -127,7 +134,7 @@ class Render */ public static function addScriptTop($file) { - self::addHeader(''); + trigger_error('Ignoring addScriptTop for ' . $file . ': Deprecated, use module-specific clientscript.js', E_USER_WARNING); } /** @@ -137,7 +144,7 @@ class Render */ public static function addScriptBottom($file) { - self::addFooter(''); + trigger_error('Ignoring addScriptBottom for ' . $file . ': Deprecated, use module-specific clientscript.js', E_USER_WARNING); } /** diff --git a/inc/user.inc.php b/inc/user.inc.php index d3cdc65a..595f4745 100644 --- a/inc/user.inc.php +++ b/inc/user.inc.php @@ -30,7 +30,7 @@ class User { if (!self::isLoggedIn()) return false; - return (self::$user['permissions'] & Permission::get($permission)) != 0; + return (self::$user['permissions'] & (Permission::get($permission) | Permission::get('superadmin'))) != 0; } public static function load() diff --git a/index.php b/index.php index a6cfccf2..d9b7c371 100644 --- a/index.php +++ b/index.php @@ -70,7 +70,7 @@ abstract class Page public static function init() { $name = empty($_REQUEST['do']) ? 'Main' : $_REQUEST['do']; - $name = preg_replace('/[^A-Za-z]/', '', $name); + $name = preg_replace('/[^A-Za-z_]/', '', $name); $name = strtolower($name); Module::init(); self::$module = Module::get($name); diff --git a/modules-available/backup/page.inc.php b/modules-available/backup/page.inc.php index 9d253a1e..3f2388a5 100644 --- a/modules-available/backup/page.inc.php +++ b/modules-available/backup/page.inc.php @@ -27,7 +27,6 @@ class Page_Backup extends Page if ($this->action === 'restore') { Render::addTemplate('restore', $this->templateData); } else { - Render::addScriptBottom('fileselect'); Render::addTemplate('_page'); } } diff --git a/modules-available/baseconfig/config.json b/modules-available/baseconfig/config.json index b72e9c23..9ce17b0d 100644 --- a/modules-available/baseconfig/config.json +++ b/modules-available/baseconfig/config.json @@ -1,4 +1,3 @@ { - "category": "main.settings", - "enabled": true + "category": "main.settings" } diff --git a/modules-available/baseconfig/templates/_page.html b/modules-available/baseconfig/templates/_page.html index e8b85dd3..093cb10f 100644 --- a/modules-available/baseconfig/templates/_page.html +++ b/modules-available/baseconfig/templates/_page.html @@ -63,5 +63,5 @@ - Download + Download diff --git a/modules-available/baseconfig_partitions_cdn/config.json b/modules-available/baseconfig_partitions_cdn/config.json new file mode 100644 index 00000000..a3036a56 --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/config.json @@ -0,0 +1,4 @@ +{ + "category": "main.settings", + "dependencies": [ "baseconfig" ] +} \ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/page.inc.php b/modules-available/baseconfig_partitions_cdn/page.inc.php new file mode 100644 index 00000000..b6ea869a --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/page.inc.php @@ -0,0 +1,133 @@ +addPartition(); + } + if($action == 'reset') { + $this->resetConfig(); + } + + $deletePartition = Request::get('deletePartition'); + if($deletePartition !== false) { // TODO: CSRF: Actions that change/update/delete anything should be POST + $this->deletePartition($deletePartition); + } + + $this->updatePartitions(); + } + + protected function doRender() + { + if (!User::hasPermission('baseconfig_local')) { + Message::addError('main.no-permission'); + Util::redirect('?do=Main'); + } + + //loads partition settings + $partitions = array(); + $res = Database::simpleQuery('SELECT id, partition_id, size, mount_point, options FROM setting_partition WHERE user=:user', + array( 'user' => User::getId() )); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $partition = array( + 'id' => $row['id'], + 'partition_id' => $row['partition_id'], + 'size' => $row['size'], + 'mount_point' => $row['mount_point'], + 'options' => $row['options'] + ); + $partitions[] = $partition; + } + + Render::addTemplate('_page', array( + 'partitions' => $partitions, + 'user' => User::getId() + )); + } + + private function addPartition() { + $partId = Request::post('new-partition-id'); + $partSize = Request::post('new-partition-size'); + $partMountPoint = Request::post('new-partition-mount-point'); + $partOptions = Request::post('new-partition-options'); + + if(strlen($partId) < 1 || strlen($partSize) < 1){ + Message::addError('main.empty-field'); + }else{ + $data = array( + 'partition_id' => $partId, + 'size' => $partSize, + 'mount_point' => $partMountPoint, + 'options' => $partOptions, + 'user' => User::getId() + ); + if (Database::exec('INSERT INTO setting_partition SET partition_id = :partition_id, size = :size, + mount_point = :mount_point, options = :options, user = :user ', $data) != 1) { + Util::traceError('Could not create new partition in DB'); + } + } + Util::redirect('?do=BaseConfig'); + } + + private function deletePartition($id){ + if(is_numeric($id)){ + $data = array( + 'id' => $id, + 'user' => User::getId() + ); + if (Database::exec('DELETE FROM setting_partition WHERE id = :id AND user = :user', $data) != 1) { + Util::traceError('Could not delete partition in DB'); + } + } + Util::redirect('?do=BaseConfig'); + } + + private function updatePartitions(){ + $partitions = array(); + foreach($_POST as $key => $value){ + if(substr($key,0,9) == 'partition'){ + $id = substr($key,10,1); + $type = substr($key,12); + $partitions[$id][$type] = $value; + } + } + + foreach($partitions as $key => $data){ + $data = array( + 'id' => $key, + 'partition_id' => $data['partition_id'], + 'size' => $data['size'], + 'mount_point' => $data['mount_point'], + 'options' => $data['options'], + 'user' => User::getId() + ); + Database::exec('UPDATE setting_partition SET partition_id=:partition_id, size=:size, mount_point=:mount_point, + options=:options WHERE id=:id AND user=:user;', $data); + } + if (!empty($partitions)) { + Message::addSuccess('partitions-updated'); + Util::redirect('?do=BaseConfig'); + } + } + + private function resetConfig(){ + $data = array( + 'user' => User::getId() + ); + //Delete all config values + Database::exec('DELETE FROM setting_partition WHERE user = :user', $data); + //Create default partition values + Database::exec ( "INSERT INTO setting_partition SET partition_id = '44', size = '5G', mount_point = '/tmp', user = :user", $data ); + Database::exec ( "INSERT INTO setting_partition SET partition_id = '43', size = '20G', mount_point = '/boot', options = 'bootable', user = :user", $data ); + Database::exec ( "INSERT INTO setting_partition SET partition_id = '40', size = '20G', mount_point = '/cache/export/dnbd3', user = :user", $data ); + Database::exec ( "INSERT INTO setting_partition SET partition_id = '41', size = '5G', mount_point = '/home', user = :user", $data ); + Database::exec ( "INSERT INTO setting_partition SET partition_id = '82', size = '1G', user = :user", $data ); + } +} \ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/templates/_page.html b/modules-available/baseconfig_partitions_cdn/templates/_page.html new file mode 100644 index 00000000..ee764e37 --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/templates/_page.html @@ -0,0 +1,74 @@ +

{{lang_partitioningManagement}}

+ +
+ + + + Download +
+
+
+ + + +
+
+ + +
+ + + +
+ \ No newline at end of file diff --git a/modules-available/dozmod/hooks/main-warning.inc.php b/modules-available/dozmod/hooks/main-warning.inc.php new file mode 100644 index 00000000..ffa87692 --- /dev/null +++ b/modules-available/dozmod/hooks/main-warning.inc.php @@ -0,0 +1,11 @@ + 0) { + Message::addInfo('dozmod.images-pending-delete-exist', true, $res['cnt']); +} +unset($res); diff --git a/modules-available/dozmod/lang/de/messages.json b/modules-available/dozmod/lang/de/messages.json index d6e39cbf..7944ffae 100644 --- a/modules-available/dozmod/lang/de/messages.json +++ b/modules-available/dozmod/lang/de/messages.json @@ -1,4 +1,5 @@ { "delete-images": "L\u00f6schung: {{0}}", + "images-pending-delete-exist": "Zur L\u00f6schung markierte Abbilder: {{0}}", "mail-config-saved": "Mail-Konfiguration gespeichert" } \ No newline at end of file diff --git a/modules-available/dozmod/lang/en/messages.json b/modules-available/dozmod/lang/en/messages.json index a3c94a56..6651e32e 100644 --- a/modules-available/dozmod/lang/en/messages.json +++ b/modules-available/dozmod/lang/en/messages.json @@ -1,4 +1,5 @@ { "delete-images": "Delete: {{0}}", + "images-pending-delete-exist": "Images marked for deletion: {{0}}", "mail-config-saved": "Mail config saved" } \ No newline at end of file diff --git a/modules-available/js_chart/clientscript.js b/modules-available/js_chart/clientscript.js new file mode 100644 index 00000000..3a0a2c87 --- /dev/null +++ b/modules-available/js_chart/clientscript.js @@ -0,0 +1,11 @@ +/*! + * Chart.js + * http://chartjs.org/ + * Version: 1.0.2 + * + * Copyright 2015 Nick Downie + * Released under the MIT license + * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md + */ +(function(){"use strict";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t["offset"+i]?t["offset"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,"Width"),n=this.height=i(t.canvas,"Height");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=s.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=s.amd="function"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){return t%1!==0&&f(t)?t.toString().split(".")[1].length:0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),y=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},s.template=function(t,i){function e(t,i){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),st?-.5*s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*t*t*(((i*=1.525)+1)*t-i):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=b(l):n.apply(o)};b(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent("on"+i,e):t["on"+i]=e}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+"px",i.canvas.style.height=s+"px",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+" "+t+"px "+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,i){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:C(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin="bevel",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-n<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),tthis.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;ip&&(p=t.x+s,n=i),t.x-sp&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a=0;i--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?"center":i===a?"center":a>i?"left":"right",t.textBaseline=r?"middle":l?"bottom":"top",t.fillText(this.labels[i],s.x,s.y)}}}}}),s.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define(function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'
    <% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
'};i.Type.extend({name:"Bar",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing},calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<% for (var i=0; i
  • <%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>'};i.Type.extend({name:"Doughnut",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>'};i.Type.extend({name:"Line",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)0&&ithis.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.ythis.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'
      <% for (var i=0; i
    • <%if(segments[i].label){%><%=segments[i].label%><%}%>
    • <%}%>
    '};i.Type.extend({name:"PolarArea",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this); \ No newline at end of file diff --git a/modules-available/js_chart/config.json b/modules-available/js_chart/config.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/modules-available/js_chart/config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/modules-available/js_circles/clientscript.js b/modules-available/js_circles/clientscript.js new file mode 100644 index 00000000..0fc701eb --- /dev/null +++ b/modules-available/js_circles/clientscript.js @@ -0,0 +1,7 @@ +/** + * circles - v0.0.6 - 2015-05-27 + * + * Copyright (c) 2015 lugolabs + * Licensed + */ +!function(){"use strict";var a=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,1e3/60)},b=window.Circles=function(a){var b=a.id;if(this._el=document.getElementById(b),null!==this._el){this._radius=a.radius||10,this._duration=void 0===a.duration?500:a.duration,this._value=0,this._maxValue=a.maxValue||100,this._text=void 0===a.text?function(a){return this.htmlifyNumber(a)}:a.text,this._strokeWidth=a.width||10,this._colors=a.colors||["#EEE","#F00"],this._svg=null,this._movingPath=null,this._wrapContainer=null,this._textContainer=null,this._wrpClass=a.wrpClass||"circles-wrp",this._textClass=a.textClass||"circles-text",this._valClass=a.valueStrokeClass||"circles-valueStroke",this._maxValClass=a.maxValueStrokeClass||"circles-maxValueStroke",this._styleWrapper=a.styleWrapper===!1?!1:!0,this._styleText=a.styleText===!1?!1:!0;var c=Math.PI/180*270;this._start=-Math.PI/180*90,this._startPrecise=this._precise(this._start),this._circ=c-this._start,this._generate().update(a.value||0)}};b.prototype={VERSION:"0.0.6",_generate:function(){return this._svgSize=2*this._radius,this._radiusAdjusted=this._radius-this._strokeWidth/2,this._generateSvg()._generateText()._generateWrapper(),this._el.innerHTML="",this._el.appendChild(this._wrapContainer),this},_setPercentage:function(a){this._movingPath.setAttribute("d",this._calculatePath(a,!0)),this._textContainer.innerHTML=this._getText(this.getValueFromPercent(a))},_generateWrapper:function(){return this._wrapContainer=document.createElement("div"),this._wrapContainer.className=this._wrpClass,this._styleWrapper&&(this._wrapContainer.style.position="relative",this._wrapContainer.style.display="inline-block"),this._wrapContainer.appendChild(this._svg),this._wrapContainer.appendChild(this._textContainer),this},_generateText:function(){if(this._textContainer=document.createElement("div"),this._textContainer.className=this._textClass,this._styleText){var a={position:"absolute",top:0,left:0,textAlign:"center",width:"100%",fontSize:.7*this._radius+"px",height:this._svgSize+"px",lineHeight:this._svgSize+"px"};for(var b in a)this._textContainer.style[b]=a[b]}return this._textContainer.innerHTML=this._getText(0),this},_getText:function(a){return this._text?(void 0===a&&(a=this._value),a=parseFloat(a.toFixed(2)),"function"==typeof this._text?this._text.call(this,a):this._text):""},_generateSvg:function(){return this._svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this._svg.setAttribute("xmlns","http://www.w3.org/2000/svg"),this._svg.setAttribute("width",this._svgSize),this._svg.setAttribute("height",this._svgSize),this._generatePath(100,!1,this._colors[0],this._maxValClass)._generatePath(1,!0,this._colors[1],this._valClass),this._movingPath=this._svg.getElementsByTagName("path")[1],this},_generatePath:function(a,b,c,d){var e=document.createElementNS("http://www.w3.org/2000/svg","path");return e.setAttribute("fill","transparent"),e.setAttribute("stroke",c),e.setAttribute("stroke-width",this._strokeWidth),e.setAttribute("d",this._calculatePath(a,b)),e.setAttribute("class",d),this._svg.appendChild(e),this},_calculatePath:function(a,b){var c=this._start+a/100*this._circ,d=this._precise(c);return this._arc(d,b)},_arc:function(a,b){var c=a-.001,d=a-this._startPrecise'+d[0]+"";return d.length>1&&(e+='.'+d[1].substring(0,2)+""),e},updateRadius:function(a){return this._radius=a,this._generate().update(!0)},updateWidth:function(a){return this._strokeWidth=a,this._generate().update(!0)},updateColors:function(a){this._colors=a;var b=this._svg.getElementsByTagName("path");return b[0].setAttribute("stroke",a[0]),b[1].setAttribute("stroke",a[1]),this},getPercent:function(){return 100*this._value/this._maxValue},getValueFromPercent:function(a){return this._maxValue*a/100},getValue:function(){return this._value},getMaxValue:function(){return this._maxValue},update:function(b,c){if(b===!0)return this._setPercentage(this.getPercent()),this;if(this._value==b||isNaN(b))return this;void 0===c&&(c=this._duration);var d,e,f,g,h=this,i=h.getPercent(),j=1;return this._value=Math.min(this._maxValue,Math.max(0,b)),c?(d=h.getPercent(),e=d>i,j+=d%1,f=Math.floor(Math.abs(d-i)/j),g=c/f,function k(b){if(e?i+=j:i-=j,e&&i>=d||!e&&d>=i)return void a(function(){h._setPercentage(d)});a(function(){h._setPercentage(i)});var c=Date.now(),f=c-b;f>=g?k(c):setTimeout(function(){k(Date.now())},g-f)}(Date.now()),this):(this._setPercentage(this.getPercent()),this)}},b.create=function(a){return new b(a)}}(); \ No newline at end of file diff --git a/modules-available/js_circles/config.json b/modules-available/js_circles/config.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/modules-available/js_circles/config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/modules-available/main/lang/de/global-tags.json b/modules-available/main/lang/de/global-tags.json index 39236fd4..a8fa0034 100644 --- a/modules-available/main/lang/de/global-tags.json +++ b/modules-available/main/lang/de/global-tags.json @@ -2,8 +2,10 @@ "lang_back": "Zur\u00fcck", "lang_cancel": "Abbrechen", "lang_close": "Schlie\u00dfen", + "lang_days": "Tag(e)", "lang_delete": "L\u00f6schen", "lang_hint": "Hinweis", + "lang_hours": "Stunde(n)", "lang_next": "Weiter", "lang_save": "Speichern", "lang_today": "Heute", diff --git a/modules-available/main/lang/de/template-tags.json b/modules-available/main/lang/de/template-tags.json index b299cbad..c11843a0 100644 --- a/modules-available/main/lang/de/template-tags.json +++ b/modules-available/main/lang/de/template-tags.json @@ -1,6 +1,5 @@ { - "lang_bootMenuWarning": "Das Bootmen\u00fc ist veraltet oder wurde noch nicht generiert.", - "lang_configure": "Konfigurieren", + "lang_goTo": "Gehe zu", "lang_intro": "Dies ist die bwLehrpool Konfigurationsoberfl\u00e4che.", "lang_introGuest": "Dies ist das Administrations-Interface der lokalen bwLehrpool-Installation. Bitte authentifizieren Sie sich, um Einstellungen vorzunehmen.", "lang_language": "Sprachen", @@ -8,16 +7,11 @@ "lang_loggedInSuffix": " ", "lang_login": "Anmelden", "lang_logout": "Abmelden", - "lang_minilinuxMissing": "Wichtige Dateien der MiniLinux-Installation fehlen.", "lang_needsSetup": "Einrichtung unvollst\u00e4ndig", "lang_noExistingAccount": "Es existiert noch kein Administrator-Zugang f\u00fcr diesen Satelliten-Server.", - "lang_numerOfImagesMarkedForDeletion": "Zur L\u00f6schung markierte Abbilder", "lang_register": "Registrieren", - "lang_systemConfiguration": "Systemkonfiguration", - "lang_systemConfigurationNotChosen": "Es wurde noch keine Systemkonfiguration ausgew\u00e4hlt.", "lang_toggleNavigation": "Navigation ein\/ausblenden", "lang_translations": "\u00dcbersetzungen", - "lang_vmLocationNotSet": "Es ist noch kein Speicherort f\u00fcr die Virtuellen Maschinen festgelegt.", "lang_warning": "Warnung", "lang_warningDebug": "Debugmodus aktiv!", "lang_welcome": "Willkommen" diff --git a/modules-available/main/lang/en/global-tags.json b/modules-available/main/lang/en/global-tags.json index 10581ae2..181f600a 100644 --- a/modules-available/main/lang/en/global-tags.json +++ b/modules-available/main/lang/en/global-tags.json @@ -2,8 +2,10 @@ "lang_back": "Back", "lang_cancel": "Cancel", "lang_close": "Close", + "lang_days": "day(s)", "lang_delete": "Delete", "lang_hint": "Hint", + "lang_hours": "hour(s)", "lang_next": "Next", "lang_save": "Save", "lang_today": "Today", diff --git a/modules-available/main/lang/en/template-tags.json b/modules-available/main/lang/en/template-tags.json index be03e53e..fcb34031 100644 --- a/modules-available/main/lang/en/template-tags.json +++ b/modules-available/main/lang/en/template-tags.json @@ -1,6 +1,5 @@ { - "lang_bootMenuWarning": "The boot menu is outdated or has not been generated.", - "lang_configure": "Configure", + "lang_goTo": "Gehe zu", "lang_intro": "This is the bwLehrpool configuration interface.", "lang_introGuest": "This is the administration interface of the local bwLehrpool intallation. Please authenticate yourself to adjust settings.", "lang_language": "Language", @@ -8,16 +7,11 @@ "lang_loggedInSuffix": " ", "lang_login": "Login", "lang_logout": "Logout", - "lang_minilinuxMissing": "Important files from the mini Linux installation are missing.", "lang_needsSetup": "Setup incomplete", "lang_noExistingAccount": "No account has been created yet. Sign up to become the administrator.", - "lang_numerOfImagesMarkedForDeletion": "Images marked for deletion", "lang_register": "Register", - "lang_systemConfiguration": "System Configuration", - "lang_systemConfigurationNotChosen": "A system configuration has not been chosen yet.", "lang_toggleNavigation": "toggle navigation", "lang_translations": "Translations", - "lang_vmLocationNotSet": "A location for the virtual machine is not set yet.", "lang_warning": "Warning", "lang_warningDebug": "Debug mode active!", "lang_welcome": "Welcome" diff --git a/modules-available/main/page.inc.php b/modules-available/main/page.inc.php index 0a9acd81..bd50a5d1 100644 --- a/modules-available/main/page.inc.php +++ b/modules-available/main/page.inc.php @@ -3,24 +3,9 @@ class Page_Main extends Page { - private $sysconfig; - private $minilinux; - private $vmstore; - private $ipxe; - private $delPending; - protected function doPreprocess() { User::load(); - if (User::isLoggedIn()) { - $this->sysconfig = !file_exists(CONFIG_HTTP_DIR . '/default/config.tgz'); - $this->minilinux = !file_exists(CONFIG_HTTP_DIR . '/default/kernel') || !file_exists(CONFIG_HTTP_DIR . '/default/initramfs-stage31') || !file_exists(CONFIG_HTTP_DIR . '/default/stage32.sqfs'); - $this->vmstore = !is_array(Property::getVmStoreConfig()); - $this->ipxe = !preg_match('/^\d+\.\d+\.\d+\.\d+$/', Property::getServerIp()); - Property::setNeedsSetup(($this->sysconfig || $this->minilinux || $this->vmstore || $this->ipxe) ? 1 : 0); - $res = Database::queryFirst("SELECT Count(*) AS cnt FROM sat.imageversion WHERE deletestate = 'SHOULD_DELETE'", array(), true); - $this->delPending = isset($res['cnt']) ? $res['cnt'] : 0; - } } protected function doRender() @@ -33,24 +18,21 @@ class Page_Main extends Page } // Logged in here - // Load news - $lines = array(); - $paginate = new Paginate("SELECT newsid, dateline, title, content FROM news ORDER BY dateline DESC", 10); - $res = $paginate->exec(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - if(count($lines) >= 3) break; - $lines[] = $row; - } - Render::addTemplate('page-main', array( - 'user' => User::getName(), - 'sysconfig' => $this->sysconfig, - 'minilinux' => $this->minilinux, - 'vmstore' => $this->vmstore, - 'ipxe' => $this->ipxe, - 'delpending' => $this->delPending, - 'news' => $lines + 'user' => User::getName() )); + + // Warnings + $needSetup = false; + foreach (glob('modules/*/hooks/main-warning.inc.php') as $file) { + preg_match('#^modules/([^/]+)/#', $file, $out); + if (!Module::isAvailable($out[1])) + continue; + include $file; + } + + // Update warning state + Property::setNeedsSetup($needSetup ? 1 : 0); } protected function doAjax() diff --git a/modules-available/main/templates/messagebox-error.html b/modules-available/main/templates/messagebox-error.html deleted file mode 100644 index 873716c9..00000000 --- a/modules-available/main/templates/messagebox-error.html +++ /dev/null @@ -1 +0,0 @@ -
    {{{message}}}
    diff --git a/modules-available/main/templates/messagebox-info.html b/modules-available/main/templates/messagebox-info.html deleted file mode 100644 index eb9d518a..00000000 --- a/modules-available/main/templates/messagebox-info.html +++ /dev/null @@ -1 +0,0 @@ -
    {{{message}}}
    diff --git a/modules-available/main/templates/messagebox-success.html b/modules-available/main/templates/messagebox-success.html deleted file mode 100644 index 93674d69..00000000 --- a/modules-available/main/templates/messagebox-success.html +++ /dev/null @@ -1 +0,0 @@ -
    {{{message}}}
    diff --git a/modules-available/main/templates/messagebox-warning.html b/modules-available/main/templates/messagebox-warning.html deleted file mode 100644 index b02e2e8a..00000000 --- a/modules-available/main/templates/messagebox-warning.html +++ /dev/null @@ -1 +0,0 @@ -
    {{{message}}}
    diff --git a/modules-available/main/templates/messagebox.html b/modules-available/main/templates/messagebox.html new file mode 100644 index 00000000..45d5d8f6 --- /dev/null +++ b/modules-available/main/templates/messagebox.html @@ -0,0 +1,7 @@ +
    + + {{#link}} + {{lang_goTo}} » + {{/link}} + {{{message}}} +
    diff --git a/modules-available/main/templates/page-main.html b/modules-available/main/templates/page-main.html index 39e4e74e..a0b2d3b0 100644 --- a/modules-available/main/templates/page-main.html +++ b/modules-available/main/templates/page-main.html @@ -3,34 +3,3 @@

    {{lang_intro}}

    - diff --git a/modules-available/minilinux/hooks/main-warning.inc.php b/modules-available/minilinux/hooks/main-warning.inc.php new file mode 100644 index 00000000..2056bbbf --- /dev/null +++ b/modules-available/minilinux/hooks/main-warning.inc.php @@ -0,0 +1,6 @@ +currentMenu = Property::getBootMenu(); + + $action = Request::post('action'); + + if ($action === false) { + $this->currentAddress = Property::getServerIp(); + $this->getLocalAddresses(); + } + + if ($action === 'ip') { + // New address is to be set + $this->getLocalAddresses(); + $this->updateLocalAddress(); + } + + if ($action === 'ipxe') { + // iPXE stuff changes + $this->updatePxeMenu(); + } + } + + protected function doRender() + { + + $taskid = Request::any('taskid'); + if ($taskid !== false && Taskmanager::isTask($taskid)) { + Render::addTemplate('ipxe_update', array('taskid' => $taskid)); + } + + Render::addTemplate('ipaddress', array( + 'ips' => $this->taskStatus['data']['addresses'], + 'chooseHintClass' => $this->hasIpSet ? '' : 'alert alert-danger' + )); + $data = $this->currentMenu; + if (!isset($data['defaultentry'])) + $data['defaultentry'] = 'net'; + if ($data['defaultentry'] === 'net') + $data['active-net'] = 'checked'; + if ($data['defaultentry'] === 'hdd') + $data['active-hdd'] = 'checked'; + if ($data['defaultentry'] === 'custom') + $data['active-custom'] = 'checked'; + Render::addTemplate('ipxe', $data); + } + + // ----------------------------------------------------------------------------------------------- + + private function getLocalAddresses() + { + $this->taskStatus = Taskmanager::submit('LocalAddressesList', array()); + + if ($this->taskStatus === false) { + $this->taskStatus['data']['addresses'] = false; + return false; + } + + if ($this->taskStatus['statusCode'] === TASK_WAITING) { // TODO: Async if just displaying + $this->taskStatus = Taskmanager::waitComplete($this->taskStatus['id']); + } + + $sortIp = array(); + foreach (array_keys($this->taskStatus['data']['addresses']) as $key) { + $item = & $this->taskStatus['data']['addresses'][$key]; + if (!isset($item['ip']) || !preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $item['ip']) || substr($item['ip'], 0, 4) === '127.') { + unset($this->taskStatus['data']['addresses'][$key]); + continue; + } + if ($this->currentAddress === $item['ip']) { + $item['default'] = true; + $this->hasIpSet = true; + } + $sortIp[] = $item['ip']; + } + unset($item); + array_multisort($sortIp, SORT_STRING, $this->taskStatus['data']['addresses']); + return true; + } + + private function updateLocalAddress() + { + $newAddress = Request::post('ip', 'none'); + $valid = false; + foreach ($this->taskStatus['data']['addresses'] as $item) { + if ($item['ip'] !== $newAddress) + continue; + $valid = true; + break; + } + if ($valid) { + Property::setServerIp($newAddress); + global $tidIpxe; + if (isset($tidIpxe) && $tidIpxe !== false) + Util::redirect('?do=ServerSetup&taskid=' . $tidIpxe); + } else { + Message::addError('invalid-ip', $newAddress); + } + Util::redirect(); + } + + private function updatePxeMenu() + { + $timeout = Request::post('timeout', 10); + if ($timeout === '') + $timeout = 0; + if (!is_numeric($timeout) || $timeout < 0) { + Message::addError('main.value-invalid', 'timeout', $timeout); + } + $this->currentMenu['defaultentry'] = Request::post('defaultentry', 'net'); + $this->currentMenu['timeout'] = $timeout; + $this->currentMenu['custom'] = Request::post('custom', ''); + $this->currentMenu['masterpasswordclear'] = Request::post('masterpassword', ''); + if (empty($this->currentMenu['masterpasswordclear'])) + $this->currentMenu['masterpassword'] = 'invalid'; + else + $this->currentMenu['masterpassword'] = Crypto::hash6($this->currentMenu['masterpasswordclear']); + Property::setBootMenu($this->currentMenu); + $id = Trigger::ipxe(); + Util::redirect('?do=ServerSetup&taskid=' . $id); + } + +} diff --git a/modules-available/serversetup-bwlp/templates/ipaddress.html b/modules-available/serversetup-bwlp/templates/ipaddress.html new file mode 100644 index 00000000..0b3b2ed7 --- /dev/null +++ b/modules-available/serversetup-bwlp/templates/ipaddress.html @@ -0,0 +1,34 @@ +
    +
    + {{lang_bootAddress}} +
    +
    +
    + {{lang_chooseIP}} +
    +
    + + + + {{#ips}} + + + {{#default}} + + {{/default}} + {{^default}} + + {{/default}} + + {{/ips}} +
    {{ip}} + {{lang_active}} + + +
    +

    + {{lang_bootHint}} +

    +
    +
    +
    \ No newline at end of file diff --git a/modules-available/serversetup-bwlp/templates/ipxe.html b/modules-available/serversetup-bwlp/templates/ipxe.html new file mode 100644 index 00000000..4539624b --- /dev/null +++ b/modules-available/serversetup-bwlp/templates/ipxe.html @@ -0,0 +1,70 @@ +
    + + + + +
    +
    + {{lang_bootMenu}} +
    +
    +

    + {{lang_bootInfo}} +

    +
    + +
    + {{lang_bootBehavior}} +
    +
    +
    +
    + +
    + {{lang_menuDisplayTime}} +
    + + {{lang_seconds}} +
    +
    + +
    + {{lang_masterPassword}} +
    + +
    + {{lang_masterPasswordHelp}} +
    + +
    + {{lang_menuCustom}} + +
    +
    + + +
    +
    + + diff --git a/modules-available/serversetup-bwlp/templates/ipxe_update.html b/modules-available/serversetup-bwlp/templates/ipxe_update.html new file mode 100644 index 00000000..9c598667 --- /dev/null +++ b/modules-available/serversetup-bwlp/templates/ipxe_update.html @@ -0,0 +1,20 @@ +
    +
    {{lang_menuGeneration}}
    +
    +
    {{lang_menuGeneration}}
    + +
    +
    + + diff --git a/modules-available/serversetup/config.json b/modules-available/serversetup/config.json deleted file mode 100644 index f2abe27c..00000000 --- a/modules-available/serversetup/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "category":"main.settings", - "enabled":"true" -} diff --git a/modules-available/serversetup/lang/de/messages.json b/modules-available/serversetup/lang/de/messages.json deleted file mode 100644 index cb0b229d..00000000 --- a/modules-available/serversetup/lang/de/messages.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "invalid-ip": "Kein Interface ist auf die Adresse {{0}} konfiguriert" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/de/module.json b/modules-available/serversetup/lang/de/module.json deleted file mode 100644 index eb777343..00000000 --- a/modules-available/serversetup/lang/de/module.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "module_name": "PXE\/Boot", - "page_title": "PXE- und Boot-Einstellungen" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/de/template-tags.json b/modules-available/serversetup/lang/de/template-tags.json deleted file mode 100644 index bdbcb1ec..00000000 --- a/modules-available/serversetup/lang/de/template-tags.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "lang_active": "Aktiv", - "lang_bootAddress": "Boot-Adresse des Servers", - "lang_bootBehavior": "Standard-Bootverhalten", - "lang_bootHint": "Das Bootmen\u00fc muss nach einer \u00c4nderung der IP-Adresse neu generiert werden. In der Regel geschieht dies automatisch, der Vorgang kann in der Sektion Bootmen\u00fc allerdings auch manuell ausgel\u00f6st werden.", - "lang_bootInfo": "Hier k\u00f6nnen Anpassungen am Erscheinungsbild des Bootmen\u00fcs vorgenommen werden.", - "lang_bootMenu": "Bootmen\u00fc", - "lang_bootMenuCreate": "Bootmen\u00fc erzeugen", - "lang_chooseIP": "Bitte w\u00e4hlen Sie die IP-Adresse, \u00fcber die der Server von den Clients zum Booten angesprochen werden soll.", - "lang_close": "Schlie\u00dfen", - "lang_compile": "Kompilieren", - "lang_customEntry": "Eigener Eintrag", - "lang_example": "Beispiel", - "lang_generationFailed": "Erzeugen des Bootmen\u00fcs fehlgeschlagen. Der Netzwerkboot von bwLehrpool wird wahrscheinlich nicht funktionieren. Wenn Sie den Fehler nicht selbst beheben k\u00f6nnen, melden Sie bitte obenstehende Fehlermeldung an das bwLehrpool-Projekt.", - "lang_localHDD": "Lokale HDD", - "lang_masterPassword": "Master-Passwort", - "lang_masterPasswordHelp": "Das Master-Passwort wird ben\u00f6tigt, um einen Booteintrag direkt am Client tempor\u00e4r durch Dr\u00fccken der Tab-Taste zu editieren. Da dies f\u00fcr Manipulation am Client genutzt werden kann, sollte diese Funktion unbedingt mit einem Passwort gesch\u00fctzt werden.", - "lang_menuCustom": "Benutzerdefinierter Men\u00fczusatz", - "lang_menuCustomHint1": "Hier haben Sie die M\u00f6glichkeit, eigenen Men\u00fc-Code zum angezeigten PXE-Men\u00fc hinzuzuf\u00fcgen, um z.B. auf weitere PXE-Server zu verweisen. Das Format entspricht dem syslinux Men\u00fcformat.", - "lang_menuCustomHint2": "Sie k\u00f6nnen ein oder mehrere Eintr\u00e4ge erzeugen. Wenn Sie einen Eintrag erzeugen m\u00f6chten, der automatisch gestartet wird, wenn der Benutzer keine Auswahl t\u00e4tigt, vergeben Sie als", - "lang_menuCustomHint3": "und w\u00e4hlen Sie als Standard-Bootverhalten ebenfalls custom.", - "lang_menuDisplayTime": "Anzeigedauer des Men\u00fcs", - "lang_menuGeneration": "Erzeugen des Bootmen\u00fcs", - "lang_seconds": "Sekunden", - "lang_set": "Setzen" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/en/messages.json b/modules-available/serversetup/lang/en/messages.json deleted file mode 100644 index d96be232..00000000 --- a/modules-available/serversetup/lang/en/messages.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "invalid-ip": "No interface is configured with the address {{0}}" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/en/module.json b/modules-available/serversetup/lang/en/module.json deleted file mode 100644 index aeea610c..00000000 --- a/modules-available/serversetup/lang/en/module.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "module_name": "iPXE \/ Boot Menu" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/en/template-tags.json b/modules-available/serversetup/lang/en/template-tags.json deleted file mode 100644 index af22081a..00000000 --- a/modules-available/serversetup/lang/en/template-tags.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "lang_active": "Active", - "lang_bootAddress": "Boot Address of the Server", - "lang_bootBehavior": "Default Boot Behavior", - "lang_bootHint": "The Boot menu must be recreated after changing the IP address. Usually this is done automatically, but the process can also be triggered manually in the section of the boot menu.", - "lang_bootInfo": "Here adjustments can be made to the appearance of the boot menu.", - "lang_bootMenu": "Boot Menu", - "lang_bootMenuCreate": "Create Boot Menu", - "lang_cancel": "Cancel", - "lang_chooseIP": "Please select the IP address that the client server will use to boot.", - "lang_close": "Close", - "lang_compile": "Compile", - "lang_compilingIpxe": "Compiling iPXE", - "lang_customEntry": "Custom entry", - "lang_customScript": "Custom script", - "lang_download": "Download", - "lang_example": "Example", - "lang_extension": "Extension", - "lang_generationFailed": "Could not generate boot menu. The bwLehrpool-System might not work properly. If you can't fix the problem, please report the error message above to the bwLehrpool project.", - "lang_ipxeInfo": "Here it is possible to compile iPXE using a custom script.", - "lang_ipxeWarning": "If this is your first time compiling, it may take 1 to 4 minutes to finish.", - "lang_loading": "Loading", - "lang_localHDD": "Local HDD", - "lang_masterPassword": "Master password", - "lang_masterPasswordHelp": "The master password is required to edit a boot menu entry. This should be set for security reasons.", - "lang_menuCustom": "Custom Extra Menu", - "lang_menuCustomHint1": "Here you have the opportunity to add your own menu code to the displayed PXE menu, eg to refer to other PXE server. The format corresponds to the syslinux menu format.", - "lang_menuCustomHint2": "You can create one or more entries. If you want to create an entry that starts automatically when the user makes a selection, assign as", - "lang_menuCustomHint3": "and select as the default boot behavior custom as well.", - "lang_menuDisplayTime": "Menu Display Time", - "lang_menuGeneration": "Generating boot menu...", - "lang_mountIpxe": "Mount iPXE", - "lang_restoreDefault": "Restore Default", - "lang_saveScript": "Save Script", - "lang_seconds": "Seconds", - "lang_set": "Set", - "lang_success": "Successfully create file:" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/pt/messages.json b/modules-available/serversetup/lang/pt/messages.json deleted file mode 100644 index 65745768..00000000 --- a/modules-available/serversetup/lang/pt/messages.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "invalid-ip": "Nenhuma interface est\u00e1 configurada com o endere\u00e7o {{0}}" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/pt/module.json b/modules-available/serversetup/lang/pt/module.json deleted file mode 100644 index aeea610c..00000000 --- a/modules-available/serversetup/lang/pt/module.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "module_name": "iPXE \/ Boot Menu" -} \ No newline at end of file diff --git a/modules-available/serversetup/lang/pt/template-tags.json b/modules-available/serversetup/lang/pt/template-tags.json deleted file mode 100644 index 3120c58c..00000000 --- a/modules-available/serversetup/lang/pt/template-tags.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "lang_active": "Ativo", - "lang_bootAddress": "Endere\u00e7o Boot do Servidor", - "lang_bootBehavior": "Comportamento Padr\u00e3o de Boot", - "lang_bootHint": "O menu de boot deve ser recriado ap\u00f3s alterar o endere\u00e7o IP. Geralmente isso \u00e9 feito automaticamente, mas o processo tamb\u00e9m pode ser acionado manualmente na se\u00e7\u00e3o do menu de boot.", - "lang_bootInfo": "Aqui ajustes podem ser feitos na apar\u00eancia do menu de boot.", - "lang_bootMenu": "Menu de Boot", - "lang_bootMenuCreate": "Criar Menu de Boot", - "lang_cancel": "Cancelar", - "lang_chooseIP": "Por favor, selecione o endere\u00e7o IP que o servidor do cliente utilizar\u00e1 realizar o boot.", - "lang_close": "Fechar", - "lang_compile": "Compilar", - "lang_compileIso": "Compilar .iso", - "lang_compileKkpxe": "Compilar .kkpxe", - "lang_compileUsb": "Compilar .usb", - "lang_compilingIpxe": "Compilando iPXE", - "lang_customScript": "Script Customizado", - "lang_download": "Baixar", - "lang_example": "Exemplo", - "lang_extension": "Extens\u00e3o", - "lang_ipxeAdv": "Gerar iPXE no Modo Avan\u00e7ado", - "lang_ipxeInfo": "Aqui \u00e9 poss\u00edvel compilar e baixar o iPXE utilizando um script customiz\u00e1vel.", - "lang_ipxeSmp": "Gerar iPXE no Modo Simples", - "lang_ipxeSmpInfo": "Aqui voc\u00ea pode escolher gerar o iPXE escolhendo apenas uma das extens\u00f5es abaixo", - "lang_ipxeWarning": "Se esta for a primeira vez compilando, poder\u00e1 levar entre 1 e 4 minutos para que termine.", - "lang_loading": "Carregando", - "lang_localHDD": "HDD Local", - "lang_menuCustom": "Menu Adicional Customizado", - "lang_menuCustomHint1": "Aqui voc\u00ea tem a oportunidade de adicionar seu pr\u00f3prio c\u00f3digo de menu para o menu PXE exibido, por exemplo, para se referir a outro servidor PXE. O formato corresponde ao formato de menu syslinux.", - "lang_menuCustomHint2": "Voc\u00ea pode criar uma ou mais entradas. Se voc\u00ea quiser criar uma entrada que \u00e9 iniciada automaticamente quando o usu\u00e1rio faz uma sele\u00e7\u00e3o, atribua como", - "lang_menuCustomHint3": "e selecione como o comportamento de boot padr\u00e3o tamb\u00e9m my-entry.", - "lang_menuDisplayTime": "Tempo de Exibi\u00e7\u00e3o do Menu", - "lang_mountIpxe": "Montar iPXE", - "lang_restoreDefault": "Restaurar Padr\u00e3o", - "lang_saveScript": "Salvar Script", - "lang_seconds": "Segundos", - "lang_set": "Definir", - "lang_success": "Arquivo criado com sucesso:" -} \ No newline at end of file diff --git a/modules-available/serversetup/page.inc.php b/modules-available/serversetup/page.inc.php deleted file mode 100644 index c48ccd3d..00000000 --- a/modules-available/serversetup/page.inc.php +++ /dev/null @@ -1,194 +0,0 @@ -currentMenu = Property::getBootMenu(); - - if(Request::get('download') !== false){ - $this->downloadIpxe(Request::get('download')); - } - - if(Request::get('defaultIpxe') !== false){ - $this->defaultIpxe(Request::get('defaultIpxe')); - } - - $action = Request::post('action'); - - if ($action === false) { - $this->currentAddress = Property::getServerIp(); - $this->getLocalAddresses(); - } - - if ($action === 'ip') { - // New address is to be set - $this->getLocalAddresses(); - $this->updateLocalAddress(); - } - - if ($action === 'ipxe') { - // iPXE stuff changes - $this->updatePxeMenu(); - } - - if($action === 'save-script') { - // Save new iPXE script - $this->updateIpxeScript(); - } - - if($action === 'default-script') { - // Restore iPXE script to default - $this->defaultIpxe(); - } - } - - protected function doRender() - { - Render::setTitle(Dictionary::translate('lang_serverConfiguration')); - - $taskid = Request::any('taskid'); - if ($taskid !== false && Taskmanager::isTask($taskid)) { - Render::addTemplate('ipxe_update', array('taskid' => $taskid)); - } - - if (Request::get('advanced', 'false', 'string') === 'false') { - Render::addTemplate('ipxe-smp'); - } else { - Render::addTemplate('ipaddress', array( - 'ips' => $this->taskStatus['data']['addresses'] - )); - $data = $this->currentMenu; - if (!isset($data['defaultentry'])) - $data['defaultentry'] = 'net'; - if ($data['defaultentry'] === 'net') - $data['active-net'] = 'checked'; - if ($data['defaultentry'] === 'hdd') - $data['active-hdd'] = 'checked'; - if ($data['defaultentry'] === 'custom') - $data['active-custom'] = 'checked'; - //There is no $this->username and no pxe.embed, why do we need this? - //Page won't load with lines below uncommented - //$data['username'] = $this->username; - //$data['script'] = file_get_contents("/opt/taskmanager/data/pxe.embed"); - Render::addTemplate('ipxe-adv', $data); - } - } - - // ----------------------------------------------------------------------------------------------- - - private function getLocalAddresses() - { - $this->taskStatus = Taskmanager::submit('LocalAddressesList', array()); - - if ($this->taskStatus === false) { - $this->taskStatus['data']['addresses'] = false; - return false; - } - - if ($this->taskStatus['statusCode'] === TASK_WAITING) { // TODO: Async if just displaying - $this->taskStatus = Taskmanager::waitComplete($this->taskStatus['id']); - } - - $sortIp = array(); - foreach (array_keys($this->taskStatus['data']['addresses']) as $key) { - $item = & $this->taskStatus['data']['addresses'][$key]; - if (!isset($item['ip']) || !preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $item['ip']) || substr($item['ip'], 0, 4) === '127.') { - unset($this->taskStatus['data']['addresses'][$key]); - continue; - } - if ($this->currentAddress === $item['ip']) { - $item['default'] = true; - } - $sortIp[] = $item['ip']; - } - unset($item); - array_multisort($sortIp, SORT_STRING, $this->taskStatus['data']['addresses']); - return true; - } - - private function updateLocalAddress() - { - $newAddress = Request::post('ip', 'none'); - $valid = false; - foreach ($this->taskStatus['data']['addresses'] as $item) { - if ($item['ip'] !== $newAddress) - continue; - $valid = true; - break; - } - if ($valid) { - Property::setServerIp($newAddress); - global $tidIpxe; - if (isset($tidIpxe) && $tidIpxe !== false) - Util::redirect('?do=ServerSetup&taskid=' . $tidIpxe); - } else { - Message::addError('invalid-ip', $newAddress); - } - Util::redirect(); - } - - private function updatePxeMenu() - { - $timeout = Request::post('timeout', 10); - if ($timeout === '') - $timeout = 0; - if (!is_numeric($timeout) || $timeout < 0) { - Message::addError('main.value-invalid', 'timeout', $timeout); - } - $this->currentMenu['defaultentry'] = Request::post('defaultentry', 'net'); - $this->currentMenu['timeout'] = $timeout; - $this->currentMenu['custom'] = Request::post('custom', ''); - $this->currentMenu['masterpasswordclear'] = Request::post('masterpassword', ''); - if (empty($this->currentMenu['masterpasswordclear'])) - $this->currentMenu['masterpassword'] = 'invalid'; - else - $this->currentMenu['masterpassword'] = Crypto::hash6($this->currentMenu['masterpasswordclear']); - Property::setBootMenu($this->currentMenu); - $id = Trigger::ipxe(); - Util::redirect('?do=ServerSetup&taskid=' . $id); - } - - private function downloadIpxe($ipxe){ - $file = '/opt/taskmanager/data/ipxe/src/bin/ipxe.' . $ipxe; - if (file_exists($file)) { - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename='.basename($file)); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . filesize($file)); - ob_clean(); - flush(); - readfile($file); - exit(); - } - } - - private function updateIpxeScript(){ - $newScript = Request::post('custom-script'); - file_put_contents("/opt/taskmanager/data/pxe.embed",$newScript); - Util::redirect('?do=ServerSetup'); - } - - private function defaultIpxe(){ - $default = file_get_contents("/opt/taskmanager/data/pxe_default.embed"); - $default = str_replace("{{ip}}", "http://" . Property::getServerIp(), $default); - file_put_contents("/opt/taskmanager/data/pxe.embed",$default); - Util::redirect('?do=ServerSetup'); - } -} diff --git a/modules-available/serversetup/templates/ipaddress.html b/modules-available/serversetup/templates/ipaddress.html deleted file mode 100644 index e4c1fba9..00000000 --- a/modules-available/serversetup/templates/ipaddress.html +++ /dev/null @@ -1,35 +0,0 @@ -{{lang_ipxeSmp}}

    -
    -
    - {{lang_bootAddress}} -
    -
    -

    - {{lang_chooseIP}} -

    -
    - - - - {{#ips}} - - - {{#default}} - - {{/default}} - {{^default}} - - {{/default}} - - {{/ips}} -
    {{ip}} - {{lang_active}} - - -
    -

    - {{lang_bootHint}} -

    -
    -
    -
    diff --git a/modules-available/serversetup/templates/ipxe-adv.html b/modules-available/serversetup/templates/ipxe-adv.html deleted file mode 100644 index 00e9fd3a..00000000 --- a/modules-available/serversetup/templates/ipxe-adv.html +++ /dev/null @@ -1,149 +0,0 @@ -
    -
    - {{lang_mountIpxe}} -
    -
    -

    {{lang_ipxeInfo}}

    - - -
    -
    - - - - - -
    - -
    -
    - - - -
    -
    - -
    - -
    - - - - -
    -
    - {{lang_bootMenu}} -
    -
    -

    - {{lang_bootInfo}} -

    -
    - -
    - {{lang_bootBehavior}} -
    -
    -
    -
    - -
    - {{lang_menuDisplayTime}} -
    - - {{lang_seconds}} -
    -
    - -
    - {{lang_masterPassword}} -
    - -
    - {{lang_masterPasswordHelp}} -
    - -
    - {{lang_menuCustom}} - -
    -
    - - -
    -
    - - - - - - diff --git a/modules-available/serversetup/templates/ipxe-smp.html b/modules-available/serversetup/templates/ipxe-smp.html deleted file mode 100644 index d126710c..00000000 --- a/modules-available/serversetup/templates/ipxe-smp.html +++ /dev/null @@ -1,62 +0,0 @@ -{{lang_ipxeAdv}}

    -
    -
    - {{lang_mountIpxe}} -
    -
    -

    {{lang_ipxeSmpInfo}}

    - - -
    -
    -
    - - - - - diff --git a/modules-available/serversetup/templates/ipxe_update.html b/modules-available/serversetup/templates/ipxe_update.html deleted file mode 100644 index 9c598667..00000000 --- a/modules-available/serversetup/templates/ipxe_update.html +++ /dev/null @@ -1,20 +0,0 @@ -
    -
    {{lang_menuGeneration}}
    -
    -
    {{lang_menuGeneration}}
    - -
    -
    - - diff --git a/modules-available/statistics/config.json b/modules-available/statistics/config.json index b0123727..ab71ddbd 100644 --- a/modules-available/statistics/config.json +++ b/modules-available/statistics/config.json @@ -1,5 +1,5 @@ { "category":"main.status", - "enabled":"true", + "dependencies": [ "js_chart" ], "permission":"0" } diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php index f21f0db9..a896b7a6 100644 --- a/modules-available/statistics/page.inc.php +++ b/modules-available/statistics/page.inc.php @@ -49,7 +49,6 @@ class Page_Statistics extends Page $this->showMachineList($filter, $argument); return; } - Render::addScriptBottom('chart.min'); Render::openTag('div', array('class' => 'row')); $this->showSummary(); $this->showMemory(); @@ -548,7 +547,6 @@ class Page_Statistics extends Page Render::addTemplate('machine-usage', $spans); // Any hdds? if (!empty($hdds['hdds'])) { - Render::addScriptBottom('chart.min'); Render::addTemplate('machine-hdds', $hdds); } // Client log diff --git a/modules-available/sysconfig/addmodule_branding.inc.php b/modules-available/sysconfig/addmodule_branding.inc.php index cb5609e6..84602614 100644 --- a/modules-available/sysconfig/addmodule_branding.inc.php +++ b/modules-available/sysconfig/addmodule_branding.inc.php @@ -9,7 +9,6 @@ class Branding_Start extends AddModule_Base protected function renderInternal() { - Render::addScriptBottom('fileselect'); Render::addDialog(Dictionary::translate('config-module', 'branding_title'), false, 'branding-start', array( 'step' => 'Branding_ProcessFile', 'edit' => $this->edit ? $this->edit->id() : false diff --git a/modules-available/sysconfig/addmodule_custommodule.inc.php b/modules-available/sysconfig/addmodule_custommodule.inc.php index d08cc5fb..3f112c95 100644 --- a/modules-available/sysconfig/addmodule_custommodule.inc.php +++ b/modules-available/sysconfig/addmodule_custommodule.inc.php @@ -12,7 +12,6 @@ class CustomModule_Start extends AddModule_Base protected function renderInternal() { Session::set('mod_temp', false); - Render::addScriptBottom('fileselect'); Render::addDialog(Dictionary::translate('config-module', 'custom_title'), false, 'custom-upload', array( 'step' => 'CustomModule_ProcessUpload', 'edit' => $this->edit ? $this->edit->id() : false diff --git a/modules-available/sysconfig/clientscript.js b/modules-available/sysconfig/clientscript.js new file mode 100644 index 00000000..2a133353 --- /dev/null +++ b/modules-available/sysconfig/clientscript.js @@ -0,0 +1,21 @@ + +function forceTable(t) +{ + var pwidth = t.parent().innerWidth(); + var rows = t.find('tr'); + var row = rows.first(); + pwidth = Math.round(pwidth); + t.width(pwidth); + var sum = 0; + row.find('td').each(function() { + if (!$(this).hasClass('slx-width-ignore')) + sum += $(this).outerWidth(true); + }); + var w = Math.round(pwidth - sum); + do { + rows.find('.slx-dyn-ellipsis').each(function() { + $(this).width(w).css('width', w + 'px').css('max-width', w + 'px'); + }); + w -= 3; + } while (t.width() > pwidth); +} diff --git a/modules-available/sysconfig/hooks/main-warning.inc.php b/modules-available/sysconfig/hooks/main-warning.inc.php new file mode 100644 index 00000000..e5bc592f --- /dev/null +++ b/modules-available/sysconfig/hooks/main-warning.inc.php @@ -0,0 +1,6 @@ + $modules, 'havemodules' => (count($modules) > 0) )); - Render::addScriptTop('custom'); Render::addFooter('