├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── lib ├── default.js ├── logic.js ├── mysql.js └── rbac.js ├── package.json └── test ├── README.md ├── app.js ├── bin └── www ├── database ├── config.js └── mysql.js ├── package.json ├── public ├── assets │ ├── css │ │ ├── 4095-rtl.min.css │ │ ├── animate.min.css │ │ ├── beyond-rtl.min.css │ │ ├── beyond.min.css │ │ ├── bootstrap-rtl.min.css │ │ ├── bootstrap.min.css │ │ ├── dataTables.bootstrap.css │ │ ├── demo.min.css │ │ ├── font-awesome.min.css │ │ ├── skins │ │ │ ├── azure.min.css │ │ │ ├── black.min.css │ │ │ ├── blue.min.css │ │ │ ├── darkblue.min.css │ │ │ ├── darkred.min.css │ │ │ ├── deepblue.min.css │ │ │ ├── gray.min.css │ │ │ ├── green.min.css │ │ │ ├── orange.min.css │ │ │ ├── pink.min.css │ │ │ ├── purple.min.css │ │ │ └── teal.min.css │ │ ├── typicons.min.css │ │ └── weather-icons.min.css │ ├── fonts │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ ├── typicons.eot │ │ ├── typicons.svg │ │ ├── typicons.ttf │ │ ├── typicons.woff │ │ ├── weathericons-regular-webfont.eot │ │ ├── weathericons-regular-webfont.svg │ │ ├── weathericons-regular-webfont.ttf │ │ └── weathericons-regular-webfont.woff │ ├── img │ │ ├── attach-blue.png │ │ ├── attach-green.png │ │ ├── attach-red.png │ │ ├── attach-yellow.png │ │ ├── avatars │ │ │ ├── Javi-Jimenez.jpg │ │ │ ├── John-Smith.jpg │ │ │ ├── Matt-Cheuvront.jpg │ │ │ ├── Nicolai-Larson.jpg │ │ │ ├── Osvaldus-Valutis.jpg │ │ │ ├── Sergey-Azovskiy.jpg │ │ │ ├── Stephanie-Walter.jpg │ │ │ ├── adam-jansen.jpg │ │ │ ├── bing.png │ │ │ └── divyia.jpg │ │ ├── favicon.png │ │ ├── jquery.minicolors.png │ │ ├── logo-inverted.png │ │ ├── logo-rtl.png │ │ ├── logo.png │ │ ├── sort_asc.png │ │ ├── sort_asc_disabled.png │ │ ├── sort_both.png │ │ ├── sort_desc.png │ │ ├── sort_desc_disabled.png │ │ └── temp1.png │ └── js │ │ ├── beyond.js │ │ ├── beyond.min.js │ │ ├── bootbox │ │ └── bootbox.js │ │ ├── bootstrap.min.js │ │ ├── charts │ │ ├── chartjs │ │ │ ├── Chart.js │ │ │ └── chartjs-init.js │ │ ├── easypiechart │ │ │ ├── easypiechart-init.js │ │ │ └── jquery.easypiechart.js │ │ ├── flot │ │ │ ├── flot-init.js │ │ │ ├── jquery.flot.crosshair.js │ │ │ ├── jquery.flot.js │ │ │ ├── jquery.flot.orderBars.js │ │ │ ├── jquery.flot.pie.js │ │ │ ├── jquery.flot.resize.js │ │ │ ├── jquery.flot.selection.js │ │ │ ├── jquery.flot.stack.js │ │ │ ├── jquery.flot.time.js │ │ │ └── jquery.flot.tooltip.js │ │ ├── morris │ │ │ ├── morris-init.js │ │ │ ├── morris.js │ │ │ └── raphael-2.0.2.min.js │ │ └── sparkline │ │ │ ├── jquery.sparkline.js │ │ │ └── sparkline-init.js │ │ ├── colorpicker │ │ └── jquery.minicolors.js │ │ ├── datatable │ │ ├── ZeroClipboard.js │ │ ├── assets │ │ │ └── swf │ │ │ │ └── copy_csv_xls_pdf.swf │ │ ├── dataTables.bootstrap.min.js │ │ ├── dataTables.tableTools.min.js │ │ ├── datatables-init.js │ │ └── jquery.dataTables.min.js │ │ ├── datetime │ │ ├── bootstrap-datepicker.js │ │ ├── bootstrap-timepicker.js │ │ ├── daterangepicker.js │ │ └── moment.js │ │ ├── editors │ │ ├── summernote │ │ │ └── summernote.js │ │ └── wysiwyg │ │ │ ├── bootstrap-wysiwyg.js │ │ │ ├── jquery.hotkeys.js │ │ │ └── prettify.js │ │ ├── fuelux │ │ ├── spinner │ │ │ └── fuelux.spinner.min.js │ │ ├── treeview │ │ │ ├── tree-custom.min.js │ │ │ └── treeview-init.js │ │ └── wizard │ │ │ └── wizard-custom.js │ │ ├── fullcalendar │ │ └── fullcalendar.js │ │ ├── jquery-2.0.3.min.js │ │ ├── jquery-ui-1.10.4.custom.js │ │ ├── knob │ │ └── jquery.knob.js │ │ ├── nestable │ │ └── jquery.nestable.min.js │ │ ├── select2 │ │ └── select2.js │ │ ├── skins.min.js │ │ ├── slider │ │ ├── jQRangeSlider │ │ │ └── jQAllRangeSliders-withRuler-min.js │ │ └── jquery.nouislider.js │ │ ├── swf │ │ └── copy_csv_xls_pdf.swf │ │ ├── tagsinput │ │ └── bootstrap-tagsinput.js │ │ ├── textarea │ │ └── jquery.autosize.js │ │ ├── toastr │ │ └── toastr.js │ │ └── validation │ │ └── bootstrapValidator.js ├── images │ ├── cover.png │ └── logo.jpg └── module │ ├── bootstrap-3.3.7 │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── npm.js │ └── jQuery │ └── jquery.js ├── rbac.sql ├── routes ├── admin.js ├── index.js ├── logic │ └── fn.js └── users.js └── views ├── admin ├── index.pug ├── lib │ ├── info.pug │ ├── javascripts.pug │ ├── layout.pug │ ├── navbar.pug │ ├── readme │ ├── sidebar.pug │ └── styleJs.pug ├── purview │ ├── add_node.pug │ ├── add_node_tag.pug │ ├── add_role.pug │ ├── add_user.pug │ ├── node_list.pug │ ├── node_tag.pug │ ├── readme │ ├── role_list.pug │ ├── role_node_edit.pug │ └── user_list.pug └── readme ├── error.pug ├── material ├── content.pug ├── index.pug ├── lib │ ├── header.pug │ ├── layout.pug │ ├── mixins.pug │ ├── readme │ └── styleJS.pug ├── login.pug └── readme └── module ├── mixins.pug └── readme /.gitignore: -------------------------------------------------------------------------------- 1 | # Node Files # 2 | node_modules 3 | npm-debug.log 4 | 5 | package-lock.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Node Files # 2 | node_modules 3 | npm-debug.log 4 | 5 | package-lock.json 6 | 7 | test/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 版权所有(C)2012-2016 由贡献者邓登攀拥有 2 | 3 | 特此授予任何获得副本的人免费的免费许可 4 | 的这个软件和相关的文档文件(“软件”),来处理 5 | 在软件中没有限制,包括但不限于权利 6 | 使用,复制,修改,合并,发布,分发,再许可和/或销售 7 | 软件副本,以及允许软件所属的人员 8 | 在符合以下条件的情况下: 9 | 10 | 以上版权声明和本许可声明应包含在 11 | 软件的所有副本或重要部分。 12 | 13 | 本软件“按原样”提供,不提供任何种类的明示或明示担保 14 | 暗示,包括但不限于适销性的保证, 15 | 适用于特定用途和非侵权。在任何情况下 16 | 作者或版权持有者对任何索赔,损害或其他责任 17 | 责任,无论在合同,侵权或其他方面的行为, 18 | 超出或与软件或使用或其他交易有关 19 | 软件。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mysql_rbac 2 | 3 | 一个基于node+mysql+express的rbac权限管理模块 4 | 5 | 6 | ### 依赖模块. 7 | - express 8 | - express-session 9 | - mysql 10 | 11 | 12 | ### 快速安装 13 | 14 | mysql_rbac 需要 [Node.js](https://nodejs.org/) v4+ 才能运行. 15 | 16 | 17 | ```sh 18 | 19 | $ cd 你的项目路径 20 | 21 | $ npm install mysql_rbac --save 22 | 23 | ``` 24 | 25 | ### 快速上手 26 | 27 | #### 1、在数据库创建必要表及字段 28 | 29 | 用户表(可自定义表名) 30 | 31 | ```sh 32 | 33 | CREATE TABLE `user` ( 34 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 35 | `username` char(20) DEFAULT '', 36 | `password` char(32) DEFAULT '', 37 | `logintime` int(10) unsigned DEFAULT '0', 38 | `loginip` varchar(30) DEFAULT '', 39 | `loginlock` tinyint(1) unsigned DEFAULT '0', 40 | `role_id` text COMMENT '所属角色_id *必要', 41 | PRIMARY KEY (`id`) 42 | ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户表'; 43 | 44 | 注意:所属角色id 是储存角色表ID的值 并以 " 1,2,3 " 形式储存 (所属角色字段名可自定义) 45 | 46 | ``` 47 | 角色表(可自定义表名) 48 | 49 | ```sh 50 | 51 | CREATE TABLE `role` ( 52 | `id` int(5) unsigned NOT NULL AUTO_INCREMENT, 53 | `name` varchar(20) NOT NULL, 54 | `remark` varchar(255) DEFAULT NULL, 55 | `node_id` text COMMENT '所属权限id *必要', 56 | PRIMARY KEY (`id`) 57 | ) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='角色表'; 58 | 59 | 注意:所属权限id 是储存权限表ID的值 并以 " 1,2,3 " 形式储存 (所属权限字段名可自定义) 60 | 61 | ``` 62 | 权限表(可自定义表名) 63 | 64 | ```sh 65 | 66 | CREATE TABLE `node` ( 67 | `id` int(6) unsigned NOT NULL AUTO_INCREMENT, 68 | `name` varchar(20) NOT NULL, 69 | `route` text COMMENT '所属路由 *必要', 70 | `method` varchar(10) COMMENT '所属路由方法 GET POST GET/POST *必要', 71 | `tag` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '权限分类', 72 | PRIMARY KEY (`id`), 73 | KEY `name` (`name`) 74 | ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='权限表'; 75 | 76 | 注意:所属路由 是储存URL的值 并以 "admin/路由1,路由2/admin, user/路由3/edit" 形式储存 (所属路由字段名可自定义) 77 | 78 | ``` 79 | 80 | #### 2,引入mysql_rbac模块并初始化参数 81 | 82 | 83 | ```sh 84 | 85 | var rbac = require('mysql_rbac'); 86 | 87 | app.use(rbac({ 88 | rbac: { 89 | 'rbac_type': 1, //验证类型(1:登录验证, 2:时时验证) *可选 默认为1 90 | 'user_key': 'uid', //用户认证识别号 *可选 默认为uid 91 | 'role': 'role', //角色表名称 *可选 默认为role 92 | 'node': 'node', //权限表名称 *可选 默认为node 93 | 'user': 'user', //用户表名称 *可选 默认为user 94 | 'userTrole': 'role_id', //在用户表储存角色表id的字段 *可选 默认为role_id 95 | 'roleTnode': 'node_id', //在角色表储存权限表id的字段 *可选 默认为node_id 96 | 'nodeTroute': 'route', //在权限表储存判断权限路由的字段 *可选 默认为route 97 | 'nodeTmethod': 'method', //在权限表储存判断权限路由方法的字段 *可选 默认为method , 98 | 'userName': 'username', //用户表的用户名字段 *可选 默认为username , 99 | 'superUser': 'admin' //用户表的用户名,该用户拥有最高权限 *可选 默认为空 100 | }, 101 | mysql: { 102 | 'host': '127.0.0.1', //IP/域名 *可选 默认为127.0.0.1 103 | 'user': 'root', //数据库账号 *可选 默认为root 104 | 'password': 'root', //数据库密码 *可选 默认为root 105 | 'database': 'mysql_rbac', //数据库库名 *可选 默认为mysq_rbac 106 | 'port': 3306 // 端口 *可选 默认为3306 107 | }, 108 | hook: { 109 | // 在req参数挂载权限状态 如: req.is_root *可选 默认为is_root 110 | root: 'is_root', 111 | // 在session参数挂载权限, 区分是否(1:登录验证, 2:时时验证) 状态 如: req.session.rbac_route *可选 默认为rbac_route 112 | rbac_route: 'rbac_route' 113 | } 114 | })); 115 | 116 | 注意:要在express-session配置参数之后初始化 117 | 118 | 如: 119 | var http = require('http'); 120 | var express = require('express'); 121 | var session = require('express-session'); 122 | var rbac = require('mysql_rbac'); 123 | var app = express(); 124 | 125 | app.use(session({ 126 | secret: 'mysql_rbac', 127 | cookie: { maxAge: 60 * 60 * 24 * 1000 }, 128 | name: 'NODESESSID' 129 | })); 130 | 131 | 132 | app.use(rbac({ 133 | // 参数 134 | })); 135 | 136 | 以下挂载你的路由 137 | app.use('/', index); 138 | router.get('/rolelist', function(req, res, next) { 139 | 140 | req.is_root(function(status){ 141 | if( !status ){ 142 | 143 | return res.end('没有权限!'); 144 | } 145 | 146 | res.end('正常逻辑业务'); 147 | 148 | 149 | }); 150 | }); 151 | http.createServer(app).listen('3000', function() { 152 | console.log(`NodePress Run!port at 3000`) 153 | }); 154 | ``` 155 | 156 | #### 3,使用 157 | 158 | 159 | ```sh 160 | 161 | router.get('/rolelist', function(req, res, next) { 162 | 163 | req.is_root(function(status){ 164 | if( !status ){ 165 | 166 | return res.end('没有权限!'); 167 | } 168 | 169 | 170 | 171 | 172 | }); 173 | }); 174 | 175 | ``` 176 | 177 | 或者 178 | 179 | 180 | ```sh 181 | 182 | router.get('/rolelist', function(req, res, next) { 183 | 184 | req.is_root(function(status){ 185 | if( !status ){ 186 | 187 | return res.end('没有权限!'); 188 | } 189 | 190 | next(); 191 | }); 192 | }, function(req, res, next) { 193 | 194 | 195 | }); 196 | }); 197 | 198 | ``` 199 | 200 | 或者 201 | 202 | 203 | ```sh 204 | 205 | var is_root = function(req, res, next) { 206 | 207 | req.is_root(function(status){ 208 | if( !status ){ 209 | 210 | return res.end('没有权限!'); 211 | } 212 | 213 | next(); 214 | }); 215 | } 216 | 217 | router.get('/rolelist', is_root, function(req, res, next) { 218 | 219 | 220 | }); 221 | }); 222 | 223 | ``` 224 | 225 | ### 日志 226 | 227 | 2018-04-02 增加路由表对method的支持,并增加最高权限的字段分配,分别对应`nodeTmethod`,`userName`, `superUser`三个参数 228 | 229 | ### 许可证 230 | 231 | MIT 232 | 233 | ### 支持 234 | 235 | 如果觉得对自己有用,记得在[https://github.com/pandashuai/mysql_rbac](https://github.com/pandashuai/mysql_rbac) 点 star 支持一下,你的支持是本人的无限动力! 236 | -------------------------------------------------------------------------------- /lib/default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rbac: { 3 | 'rbac_type': 1, //验证类型(1:登录验证, 2:时时验证) *可选 默认为1 4 | 'user_key': 'uid', //用户认证识别号 *可选 默认为uid 5 | 'role': 'role', //角色表名称 *可选 默认为role 6 | 'node': 'node', //权限表名称 *可选 默认为node 7 | 'user': 'user', //用户表名称 *可选 默认为user 8 | 'userTrole': 'role_id', //在用户表储存角色表id的字段 *可选 默认为role_id 9 | 'roleTnode': 'node_id', //在角色表储存权限表id的字段 *可选 默认为node_id 10 | 'nodeTroute': 'route', //在权限表储存判断权限路由的字段 *可选 默认为route 11 | 'nodeTmethod': 'method', //在权限表储存判断权限路由方法的字段 *可选 默认为method , 12 | 'userName': 'username', //用户表的用户名字段 *可选 默认为username , 13 | 'superUser': '' //用户表的用户名,该用户拥有最高权限 *可选 默认为空 14 | }, 15 | mysql: { 16 | 'host': '127.0.0.1', //IP/域名 *可选 默认为127.0.0.1 17 | 'user': 'root', //数据库账号 *可选 默认为root 18 | 'password': 'root', //数据库密码 *可选 默认为root 19 | 'database': 'mysql_rbac', //数据库库名 *可选 默认为mysq_rbac 20 | 'port': 3306 // 端口 *可选 默认为3306 21 | }, 22 | hook: { 23 | // 在req参数挂载权限状态 如: req.is_root *可选 默认为is_root 24 | root: 'is_root', 25 | // 在session参数挂载权限, 区分是否(1:登录验证, 2:时时验证) 状态 如: req.session.rbac_route *可选 默认为rbac_route 26 | rbac_route: 'rbac_route' 27 | } 28 | } -------------------------------------------------------------------------------- /lib/logic.js: -------------------------------------------------------------------------------- 1 | // 数组去重 2 | var unique = function(arr) { 3 | var res = []; 4 | var json = {}; 5 | for (var i = 0, el; 6 | (el = arr[i]), el != null; i++) { 7 | if (arr[i] && !json[arr[i]]) { 8 | res.push(arr[i]); 9 | json[arr[i]] = 1; 10 | } 11 | } 12 | return res; 13 | } 14 | 15 | var unObj = function(arr) { 16 | var res = []; 17 | var json = {}; 18 | for (var i = 0, el; 19 | (el = arr[i]), el != null; i++) { 20 | var key = el.route + el.method 21 | if (key && !json[key]) { 22 | res.push(el); 23 | json[key] = 1; 24 | } 25 | } 26 | return res; 27 | } 28 | module.exports.unique = unique; 29 | module.exports.unObj = unObj; -------------------------------------------------------------------------------- /lib/mysql.js: -------------------------------------------------------------------------------- 1 | // 引入mysql数据库模块 2 | var mysql = require('mysql'); 3 | 4 | var logic = require('./logic'); 5 | // 引入异步库 6 | var Q = require('q'); 7 | 8 | var username = ''; 9 | // 数据库封装 10 | module.exports = function(config, rbac) { 11 | var _this = this; 12 | _this.poolConn = mysql.createPool(config); 13 | 14 | _this.query = function(sql, param) { 15 | var deferred = Q.defer(); 16 | param = param || []; 17 | _this.poolConn.getConnection(function(error, conn) { 18 | if (error) { 19 | deferred.reject({ 20 | errCode: error.sqlState, 21 | errMag: error.code 22 | }); 23 | } else { 24 | 25 | conn.query(sql, param, function(error, results, fields) { 26 | if (error) { 27 | deferred.reject({ 28 | errCode: error.sqlState, 29 | errMag: error.code 30 | }); 31 | } else { 32 | deferred.resolve({ 33 | error: error, 34 | results: results, 35 | fields: fields 36 | }); 37 | } 38 | 39 | }); 40 | //释放连接 41 | conn.release(); 42 | } 43 | 44 | }); 45 | return deferred.promise; 46 | }; 47 | 48 | 49 | // 查询用户对应的角色id 50 | _this.queryuser = function(id) { 51 | var deferred = Q.defer(); 52 | if (!id) { 53 | throw new Error('缺少配置参数 : user_key! '); 54 | } else { 55 | _this.query('select ' + rbac.userTrole + ', ' + rbac.userName + ' from ' + rbac.user + ' where id = ' + id).then(function(data) { 56 | deferred.resolve(data.results); 57 | }, function(error) { 58 | deferred.reject(error); 59 | }); 60 | } 61 | return deferred.promise; 62 | } 63 | 64 | // 查询用户对应的角色id 65 | _this.queryrole = function(idarr) { 66 | var deferred = Q.defer(); 67 | var idparam = []; 68 | for (var i = 0; i < idarr.length; i++) { 69 | idparam.push(idarr[i][rbac.userTrole]); 70 | username = idarr[i][rbac.userName]; 71 | } 72 | if (idparam.length <= 0) { 73 | deferred.resolve(idparam); 74 | } else { 75 | // 去重 76 | idparam = logic.unique(idparam.join(',').split(',')).join(','); 77 | _this.query('select ' + rbac.roleTnode + ' from ' + rbac.role + ' where id in (' + idparam + ')').then(function(data) { 78 | deferred.resolve(data.results); 79 | }, function(error) { 80 | deferred.reject(error); 81 | }); 82 | } 83 | return deferred.promise; 84 | } 85 | 86 | // 查询角色对应的权限路由 87 | _this.querynode = function(idarr) { 88 | var deferred = Q.defer(); 89 | var idparam = []; 90 | for (var i = 0; i < idarr.length; i++) { 91 | idparam.push(idarr[i][rbac.roleTnode]); 92 | } 93 | if (idparam.length <= 0) { 94 | deferred.resolve(idparam); 95 | } else { 96 | 97 | idparam = logic.unique(idparam.join(',').split(',')).join(','); 98 | var sql = 'select ' + rbac.nodeTroute + ', ' + rbac.nodeTmethod + ' from ' + rbac.node + ' where id in (' + idparam + ')'; 99 | _this.query(sql).then(function(data) { 100 | deferred.resolve(data.results); 101 | }, function(error) { 102 | deferred.reject(error); 103 | }); 104 | 105 | } 106 | 107 | return deferred.promise; 108 | } 109 | 110 | // 导出权限路由 111 | _this.onlyRoot = function(userid) { 112 | var deferred = Q.defer(); 113 | _this.queryuser(userid) 114 | .then(_this.queryrole) 115 | .then(_this.querynode) 116 | .then(function(data) { 117 | var idparam = []; 118 | for (var i = 0; i < data.length; i++) { 119 | idparam.push({ 120 | route: data[i][rbac.nodeTroute], 121 | method: data[i][rbac.nodeTmethod] || 'GET/POST', 122 | }); 123 | } 124 | if (idparam.length > 0) { 125 | // 去重 126 | idparam = logic.unObj(idparam); 127 | 128 | } 129 | deferred.resolve({ user: username, route: idparam }); 130 | }, function(error) { 131 | deferred.reject(error); 132 | }); 133 | return deferred.promise; 134 | } 135 | 136 | return { 137 | onlyRoot: _this.onlyRoot 138 | } 139 | } -------------------------------------------------------------------------------- /lib/rbac.js: -------------------------------------------------------------------------------- 1 | // 数据库封装 2 | var mysql = require('./mysql'); 3 | 4 | // 默认配置 5 | var config = require('./default'); 6 | 7 | 8 | 9 | 10 | module.exports = function(param) { 11 | param = param || {}; 12 | var _this = this; 13 | // 合并默认参数 14 | _this.default = Object.assign(config, param); 15 | // 配置数据库参数 16 | _this.mysql = mysql(_this.default.mysql, _this.default.rbac); 17 | return function(req, res, next) { 18 | // 检测express-session 是否存在 19 | if (!req.session) { 20 | throw new Error("Cannot find module 'express-session'!"); 21 | } 22 | req.session[_this.default.hook.rbac_route] = req.session[_this.default.hook.rbac_route] || {}; 23 | // 检测是否处于登录状态 24 | if (!req.session[_this.default.rbac.user_key]) { 25 | req[_this.default.hook.root] = function() { 26 | req.session[_this.default.hook.rbac_route] = {}; 27 | return false; 28 | } 29 | req.session[_this.default.hook.rbac_route] = {}; 30 | return next(); 31 | } 32 | // 将权限状态挂载到req参数中 33 | req[_this.default.hook.root] = function(callbask) { 34 | // 获取当前路由 end 35 | var ddpBaseUrl = req.baseUrl; 36 | var ddpPath = (ddpBaseUrl || '') + req.route.path; 37 | var ddpMethod = req.method; 38 | // 获取当前路由 end 39 | // 在session参数挂载权限, 区分是否(1:登录验证, 2:时时验证) 状态 40 | if (req.session[_this.default.hook.rbac_route].route && _this.default.rbac.rbac_type == 1) { 41 | if (_this.default.rbac.superUser && req.session[_this.default.hook.rbac_route].user === _this.default.rbac.superUser) { 42 | return callbask(true); 43 | } 44 | for (var i = 0, el; 45 | (el = req.session[_this.default.hook.rbac_route].route[i]), el != null; i++) { 46 | if (el.method.split('/').indexOf(ddpMethod) != '-1' && el.route === ddpPath) { 47 | return callbask(true); 48 | } 49 | } 50 | return callbask(false); 51 | } 52 | // 从数据库获取路由数组 53 | _this.mysql.onlyRoot(req.session[_this.default.rbac.user_key]).then(function(data) { 54 | req.session[_this.default.hook.rbac_route] = data; 55 | if (_this.default.rbac.superUser && data.user === _this.default.rbac.superUser) { 56 | return callbask(true); 57 | } 58 | // 匹配权限状态 59 | for (var i = 0, el; 60 | (el = data.route[i]), el != null; i++) { 61 | if (el.method.split('/').indexOf(ddpMethod) != '-1' && el.route === ddpPath) { 62 | return callbask(true); 63 | } 64 | } 65 | return callbask(false); 66 | }, function(err) { 67 | console.error(err); 68 | req.session[_this.default.hook.rbac_route] = {}; 69 | return callbask(false); 70 | }); 71 | } 72 | next(); 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql_rbac", 3 | "version": "1.4.0", 4 | "description": "", 5 | "main": "lib/rbac.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "rbac" 11 | ], 12 | "author": "邓登攀", 13 | "license": "ISC", 14 | "dependencies": { 15 | "mysql": "^2.13.0", 16 | "q": "^1.4.1" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/pandashuai/mysql_rbac.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/pandashuai/mysql_rbac/issues" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # 一个测试mysql_rbac 模块的小案例 2 | 3 | ### 第一步 4 | 5 | ```sh 6 | 7 | npm install 8 | 9 | ``` 10 | 11 | ### 第二步 12 | 13 | ```sh 14 | 15 | 在根目录找到rbac.sql数据库文件并导入mysql数据库 16 | 17 | ``` 18 | 19 | ### 第三步 20 | 21 | ```sh 22 | 23 | 在database目录找到config.js文件 配置数据库参数 24 | 25 | ``` 26 | 27 | ### 第四步启动服务器 28 | 29 | ```sh 30 | 31 | node ./www/bin 32 | 33 | ``` 34 | 35 | ### 最后访问 36 | 37 | ```sh 38 | 39 | http://localhost:3000/ 40 | 41 | ``` 42 | 43 | 44 | ### 后台密码 45 | 46 | ```sh 47 | 48 | 管理员: U: admin P: 123456 49 | 50 | 还有几个账号密码可在用户列表查看, 51 | 注意: 由于是只是测试,所以并没有加密密码,现密码处于明文状态 52 | ``` -------------------------------------------------------------------------------- /test/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | // ------------------------------------------------- 9 | // 引入模块 10 | var session = require('express-session'); 11 | var rbac = require('../lib/rbac'); 12 | var mysqyconfig = require('./database/config'); 13 | // ------------------------------------------------- 14 | 15 | var index = require('./routes/index'); 16 | // var users = require('./routes/users'); 17 | var admin = require('./routes/admin'); 18 | 19 | var app = express(); 20 | 21 | // view engine setup 22 | app.set('views', path.join(__dirname, 'views')); 23 | app.set('view engine', 'pug'); 24 | 25 | // uncomment after placing your favicon in /public 26 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 27 | app.use(logger('dev')); 28 | app.use(bodyParser.json()); 29 | app.use(bodyParser.urlencoded({ extended: false })); 30 | app.use(cookieParser()); 31 | app.use(express.static(path.join(__dirname, 'public'))); 32 | 33 | // ------------------------------------------------- 34 | // 设置并配置sessions 35 | app.use(session({ 36 | secret: 'mysql_rbac@', 37 | cookie: { maxAge: 60 * 60 * 24 * 1000 }, 38 | name: 'NODESESSID' 39 | })); 40 | 41 | // 设置并配置rbac 42 | app.use(rbac({ 43 | rbac: { 44 | 'rbac_type': 1, //验证类型(1:登录验证, 2:时时验证) *可选 默认为1 45 | 'user_key': 'uid', //用户认证识别号 *可选 默认为uid 46 | 'role': 'role', //角色表名称 *可选 默认为role 47 | 'node': 'node', //权限表名称 *可选 默认为node 48 | 'user': 'user', //用户表名称 *可选 默认为user 49 | 'userTrole': 'role_id', //在用户表储存角色表id的字段 *可选 默认为role_id 50 | 'roleTnode': 'node_id', //在角色表储存权限表id的字段 *可选 默认为node_id 51 | 'nodeTroute': 'route', //在权限表储存判断权限路由的字段 *可选 默认为route 52 | 'nodeTmethod': 'method', //在权限表储存判断权限路由方法的字段 *可选 默认为method , 53 | 'userName': 'username', //用户表的用户名字段 *可选 默认为username , 54 | 'superUser': 'admin' //用户表的用户名,该用户拥有最高权限 *可选 默认为空 55 | }, 56 | mysql: { 57 | 'host': mysqyconfig.host, //IP/域名 *可选 默认为127.0.0.1 58 | 'user': mysqyconfig.user, //数据库账号 *可选 默认为root 59 | 'password': mysqyconfig.password, //数据库密码 *可选 默认为root 60 | 'database': mysqyconfig.database, //数据库库名 *可选 默认为mysq_rbac 61 | 'port': mysqyconfig.port // 端口 *可选 默认为3306 62 | }, 63 | hook: { 64 | // 在req参数挂载权限状态 如: req.is_root *可选 默认为is_root 65 | root: 'is_root', 66 | // 在session参数挂载权限, 区分是否(1:登录验证, 2:时时验证) 状态 如: req.session.rbac_route *可选 默认为rbac_route 67 | rbac_route: 'rbac_route' 68 | } 69 | })); 70 | // ------------------------------------------------- 71 | app.use((req, res, next) => { 72 | // 索引值 73 | res.locals.indexType = req.query.indextype || 'null'; 74 | res.setHeader('Content-Type', 'text/html;charset=utf-8'); 75 | next(); 76 | }); 77 | app.use('/', index); 78 | 79 | app.use('/admin', function(req, res, next) { 80 | // 此req.session.uid 要配置在rbac.rbac.user_key 81 | if (!req.session.uid) { 82 | return res.redirect('/login'); 83 | } 84 | next(); 85 | }); 86 | 87 | // app.use('/users', users); 88 | // 89 | app.use('/admin', admin); 90 | 91 | // catch 404 and forward to error handler 92 | app.use(function(req, res, next) { 93 | var err = new Error('Not Found'); 94 | err.status = 404; 95 | next(err); 96 | }); 97 | 98 | // error handler 99 | app.use(function(err, req, res, next) { 100 | // set locals, only providing error in development 101 | res.locals.message = err.message; 102 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 103 | 104 | // render the error page 105 | res.status(err.status || 500); 106 | res.render('error'); 107 | }); 108 | 109 | console.log('访问: http://localhost:3000'); 110 | module.exports = app; -------------------------------------------------------------------------------- /test/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('test:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /test/database/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | host: '127.0.0.1', 3 | user: 'root', 4 | password: 'root', 5 | database: 'mysql_rabc', 6 | port: 3306, 7 | multipleStatements: true 8 | } -------------------------------------------------------------------------------- /test/database/mysql.js: -------------------------------------------------------------------------------- 1 | var mysql = require('mysql'); 2 | var mysql_config = require('./config'); 3 | 4 | //使用连接池,提升性能 5 | var poolConn = mysql.createPool(mysql_config); 6 | 7 | // 连接池查询 8 | var query = function(sql, params, callback) { 9 | if (typeof(params) == 'function') { 10 | callback = params; 11 | params = []; 12 | } 13 | poolConn.getConnection(function(err, conn) { 14 | if (err) { 15 | callback(err, null, null); 16 | } else { 17 | 18 | var query = conn.query(sql, params, callback); 19 | //释放连接 20 | conn.release(); 21 | } 22 | 23 | }); 24 | 25 | }; 26 | 27 | 28 | 29 | // 添加用户 30 | var adduser = function(param, callback) { 31 | query('insert into user(username, password, logintime, loginip, role_id) values(?, ?, ?, ?, ?)', param, function(error, results, fields) { 32 | if (error) { 33 | throw error; 34 | } else { 35 | callback(true); 36 | } 37 | }); 38 | }; 39 | 40 | // 添加角色 41 | var addrole = function(param, callback) { 42 | query('insert into role(name, status, remark) values(?, ?, ?)', param, function(error, results, fields) { 43 | if (error) { 44 | throw error; 45 | } 46 | if (callback) { 47 | return callback(true); 48 | } 49 | }); 50 | } 51 | 52 | 53 | // 添加节点分类 54 | var addnodetag = function(param, callback) { 55 | query('insert into node_tag(name) values(?)', param, function(error, results, fields) { 56 | if (error) { 57 | throw error; 58 | } 59 | if (callback) { 60 | return callback(true); 61 | } 62 | }); 63 | } 64 | 65 | // 添加节点 66 | var addnode = function(param, callback) { 67 | query('insert into node(name, route, method, tag) values(?, ?,?, ?)', param, function(error, results, fields) { 68 | if (error) { 69 | throw error; 70 | } 71 | if (callback) { 72 | return callback(true); 73 | } 74 | }); 75 | } 76 | 77 | // 更新角色权限 78 | var updaterole = function(param, callback) { 79 | query('update role set node_id = ? where id = ? ', param, function(error, results, fields) { 80 | if (error) { 81 | throw error; 82 | } 83 | if (callback) { 84 | return callback(true); 85 | } 86 | }); 87 | } 88 | 89 | // 遍历角色 90 | var eachrole = function(param, callback) { 91 | if (typeof(param) == 'function') { 92 | callback = param; 93 | param = ''; 94 | } else { 95 | param = 'where id = ' + param; 96 | } 97 | query('select * from role ' + param, function(error, results, fields) { 98 | if (error) { 99 | throw error; 100 | } 101 | 102 | return callback(results); 103 | }); 104 | } 105 | 106 | // 遍历用户,user.id as user_id, user.loginlock as loginlock, user.loginip as loginip, user.username as username, user.logintime as logintime, role_user.role_id as role_id, role.name as role_name 107 | var eachuser = function(callback) { 108 | query('select id, loginlock, loginip, username, logintime, role_id from user', function(error, results, fields) { 109 | if (error) { 110 | throw error; 111 | } 112 | return callback(results); 113 | }); 114 | } 115 | // 遍历节点分类 116 | var eachnodetag = function(callback) { 117 | query('select * from node_tag', function(error, results, fields) { 118 | if (error) { 119 | throw error; 120 | } 121 | return callback(results); 122 | }); 123 | } 124 | // 遍历节点 125 | var eachnode = function(callback) { 126 | query('select node.id as id, node.name as name, node.route as route, node.method as method, node_tag.name as tag_name from node left join node_tag on node.tag = node_tag.id', function(error, results, fields) { 127 | if (error) { 128 | throw error; 129 | } 130 | return callback(results); 131 | }); 132 | } 133 | 134 | module.exports.adduser = adduser; 135 | module.exports.addrole = addrole; 136 | module.exports.addnodetag = addnodetag; 137 | module.exports.addnode = addnode; 138 | module.exports.updaterole = updaterole; 139 | module.exports.eachrole = eachrole; 140 | module.exports.eachuser = eachuser; 141 | module.exports.eachnodetag = eachnodetag; 142 | module.exports.eachnode = eachnode; 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | // material 159 | var isUser = function(param, callback) { 160 | query('select * from user where username = ? and password = ?', param, function(error, results, fields) { 161 | if (error) { 162 | throw error; 163 | } 164 | if (results.length > 0) { 165 | return callback(results[0].id); 166 | } 167 | 168 | return callback(false); 169 | }); 170 | } 171 | module.exports.isUser = isUser; -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.16.0", 10 | "cookie-parser": "~1.4.3", 11 | "debug": "~2.6.0", 12 | "express": "~4.14.1", 13 | "express-session": "^1.15.1", 14 | "moment": "^2.17.1", 15 | "morgan": "~1.7.0", 16 | "mysql": "^2.13.0", 17 | "pug": "~2.0.0-beta10", 18 | "serve-favicon": "~2.3.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/public/assets/css/dataTables.bootstrap.css: -------------------------------------------------------------------------------- 1 | .DTTTFooter { 2 | margin: 0; 3 | background: #fff; 4 | overflow: hidden; 5 | padding: 5px 5px 2px 10px; 6 | border: 1px solid #ddd; 7 | border-top: 0px; 8 | background-color: #eee; 9 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0d…0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2xlc3NoYXQtZ2VuZXJhdGVkKSIgLz48L3N2Zz4=); 10 | background-image: -webkit-linear-gradient(top, #f2f2f2 0, #fafafa 100%); 11 | background-image: -moz-linear-gradient(top, #f2f2f2 0, #fafafa 100%); 12 | background-image: linear-gradient(to bottom, #f2f2f2 0, #fafafa 100%); 13 | } 14 | 15 | .DTTTFooter .col-sm-6 { 16 | padding: 0px; 17 | } 18 | 19 | .dataTables_wrapper { 20 | position: relative; 21 | } 22 | 23 | div.dataTables_length { 24 | position: absolute; 25 | top: 0px; 26 | right: 0px; 27 | } 28 | 29 | 30 | div.dataTables_length select { 31 | width: 75px; 32 | } 33 | 34 | div.dataTables_filter label { 35 | font-weight: normal; 36 | float: left; 37 | margin-bottom: 10px; 38 | position: relative; 39 | } 40 | 41 | .dataTables_filter label:before { 42 | font-family: "FontAwesome"; 43 | content: "\f002"; 44 | display: block; 45 | position: absolute; 46 | top: 0; 47 | bottom: 0; 48 | left: 0px; 49 | width: 30px; 50 | max-width: 30px; 51 | overflow: hidden; 52 | color: #5db2ff; 53 | text-align: center; 54 | padding-top: 6px; 55 | } 56 | 57 | .dataTables_filter input { 58 | width: 16em; 59 | padding-left: 28px; 60 | } 61 | 62 | 63 | 64 | div.dataTables_info { 65 | padding-top: 8px; 66 | } 67 | 68 | div.dataTables_paginate { 69 | float: right; 70 | margin: 0; 71 | } 72 | 73 | div.dataTables_paginate ul.pagination { 74 | margin: 2px; 75 | } 76 | 77 | table.table { 78 | clear: both; 79 | max-width: none !important; 80 | } 81 | 82 | table.table thead .sorting, 83 | table.table thead .sorting_asc, 84 | table.table thead .sorting_desc, 85 | table.table thead .sorting_asc_disabled, 86 | table.table thead .sorting_desc_disabled { 87 | cursor: pointer; 88 | } 89 | 90 | table.table thead .sorting { 91 | background: url('../img/sort_both.png') no-repeat center right; 92 | } 93 | 94 | table.table thead .sorting_asc { 95 | background: url('../img/sort_asc.png') no-repeat center right; 96 | } 97 | 98 | table.table thead .sorting_desc { 99 | background: url('../img/sort_desc.png') no-repeat center right; 100 | } 101 | 102 | table.table thead .sorting_asc_disabled { 103 | background: url('../img/sort_asc_disabled.png') no-repeat center right; 104 | } 105 | 106 | table.table thead .sorting_desc_disabled { 107 | background: url('../img/sort_desc_disabled.png') no-repeat center right; 108 | } 109 | 110 | table.dataTable th:active { 111 | outline: none; 112 | } 113 | 114 | /* Scrolling */ 115 | div.dataTables_scrollHead table { 116 | margin-bottom: 0 !important; 117 | border-bottom-left-radius: 0; 118 | border-bottom-right-radius: 0; 119 | } 120 | 121 | div.dataTables_scrollHead table thead tr:last-child th:first-child, 122 | div.dataTables_scrollHead table thead tr:last-child td:first-child { 123 | border-bottom-left-radius: 0 !important; 124 | border-bottom-right-radius: 0 !important; 125 | } 126 | 127 | div.dataTables_scrollBody table { 128 | border-top: none; 129 | margin-bottom: 0 !important; 130 | } 131 | 132 | div.dataTables_scrollBody tbody tr:first-child th, 133 | div.dataTables_scrollBody tbody tr:first-child td { 134 | border-top: none; 135 | } 136 | 137 | div.dataTables_scrollFoot table { 138 | border-top: none; 139 | } 140 | 141 | /* 142 | * TableTools styles 143 | */ 144 | table.DTTT_selectable tbody tr { 145 | cursor: pointer; 146 | } 147 | 148 | .DTTT.btn-group { 149 | position: absolute; 150 | right: 70px; 151 | top: 0px; 152 | } 153 | 154 | div.DTTT .btn { 155 | color: #333 !important; 156 | font-size: 12px; 157 | } 158 | 159 | div.DTTT .btn:hover { 160 | text-decoration: none !important; 161 | } 162 | 163 | ul.DTTT_dropdown.dropdown-menu { 164 | z-index: 2003; 165 | } 166 | 167 | ul.DTTT_dropdown.dropdown-menu a { 168 | color: #333 !important; /* needed only when demo_page.css is included */ 169 | } 170 | 171 | ul.DTTT_dropdown.dropdown-menu li { 172 | position: relative; 173 | } 174 | 175 | ul.DTTT_dropdown.dropdown-menu li:hover a { 176 | background-color: #0088cc; 177 | color: white !important; 178 | } 179 | 180 | /* TableTools information display */ 181 | div.DTTT_print_info.modal { 182 | height: 150px; 183 | margin-top: -75px; 184 | text-align: center; 185 | } 186 | 187 | div.DTTT_print_info h6 { 188 | font-weight: normal; 189 | font-size: 28px; 190 | line-height: 28px; 191 | margin: 1em; 192 | } 193 | 194 | div.DTTT_print_info p { 195 | font-size: 14px; 196 | line-height: 20px; 197 | } 198 | 199 | 200 | 201 | /* 202 | * FixedColumns styles 203 | */ 204 | div.DTFC_LeftHeadWrapper table, 205 | div.DTFC_LeftFootWrapper table, 206 | div.DTFC_RightHeadWrapper table, 207 | div.DTFC_RightFootWrapper table, 208 | table.DTFC_Cloned tr.even { 209 | background-color: white; 210 | } 211 | 212 | div.DTFC_RightHeadWrapper table, 213 | div.DTFC_LeftHeadWrapper table { 214 | margin-bottom: 0 !important; 215 | border-top-right-radius: 0 !important; 216 | border-bottom-left-radius: 0 !important; 217 | border-bottom-right-radius: 0 !important; 218 | } 219 | 220 | div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child, 221 | div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child, 222 | div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child, 223 | div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child { 224 | border-bottom-left-radius: 0 !important; 225 | border-bottom-right-radius: 0 !important; 226 | } 227 | 228 | div.DTFC_RightBodyWrapper table, 229 | div.DTFC_LeftBodyWrapper table { 230 | border-top: none; 231 | margin-bottom: 0 !important; 232 | } 233 | 234 | div.DTFC_RightBodyWrapper tbody tr:first-child th, 235 | div.DTFC_RightBodyWrapper tbody tr:first-child td, 236 | div.DTFC_LeftBodyWrapper tbody tr:first-child th, 237 | div.DTFC_LeftBodyWrapper tbody tr:first-child td { 238 | border-top: none; 239 | } 240 | 241 | div.DTFC_RightFootWrapper table, 242 | div.DTFC_LeftFootWrapper table { 243 | border-top: none; 244 | } 245 | 246 | 247 | .dataTable .row-details { 248 | margin-top: 3px; 249 | display: inline-block; 250 | cursor: pointer; 251 | width: 10px; 252 | font-size:14px; 253 | height: 14px; 254 | } 255 | 256 | .dataTable .details { 257 | background-color: #f5f5f5; 258 | } 259 | 260 | .dataTable .details td, 261 | .dataTable .details th { 262 | padding: 4px; 263 | background-color: none; 264 | border: 0; 265 | } 266 | 267 | .dataTable .details tr:hover td, 268 | .dataTable .details tr:hover th { 269 | background-color: none; 270 | } 271 | 272 | .dataTable .details tr:nth-child(odd) td, 273 | .dataTable .details tr:nth-child(odd) th { 274 | background-color: #f5f5f5; 275 | } 276 | 277 | .dataTable .details tr:nth-child(even) td, 278 | .dataTable .details tr:nth-child(even) th { 279 | background-color: #f5f5f5; 280 | } 281 | -------------------------------------------------------------------------------- /test/public/assets/css/demo.min.css: -------------------------------------------------------------------------------- 1 | .fontawesome-icon-list{margin:22px 0 0 0!important}.fontawesome-icon-list .fa-hover{color:#262626;display:block;height:36px;line-height:32px;padding-left:10px;padding:2px 0}.fontawesome-icon-list .fa-hover .fa{display:inline-block;font-size:14px;margin-right:10px;text-align:right;width:32px}.fontawesome-icon-list .fa-hover:hover{background-color:#eee;color:#000;text-decoration:none}.fontawesome-icon-list .fa-hover:hover .fa{font-size:28px;vertical-align:-6px}.bs-glyphicons{overflow:hidden}.bs-glyphicons li{float:left;width:25%;height:115px;padding:10px;font-size:10px;line-height:1.4;text-align:center;border:1px solid #fff;background-color:#f9f9f9}.bs-glyphicons li:hover{color:#fff;background-color:#e46f61}.bs-glyphicons .glyphicon{margin-top:5px;margin-bottom:10px;font-size:24px}.bs-glyphicons .glyphicon-class{display:block;text-align:center;word-wrap:break-word}.bs-glyphicons-list{padding-left:0;list-style:none}@media(min-width:768px){.bs-glyphicons{margin-left:0;margin-right:0}.bs-glyphicons li{width:12.5%;font-size:12px}}.weathericons{padding:5px 10px;border-radius:4px}.weathericons:hover{background-color:#a0d468;color:#fff}.weathericons .icon,.weathericons .class{display:inline-block}.weathericons .icon{margin-right:5px;font-size:24px}#typicon-preview{margin:0 auto;position:relative;text-align:center}#typicon-preview .icon{float:left;padding:6px;display:inline-block;cursor:pointer;width:48px;height:48px;text-align:center;vertical-align:middle;-webkit-border-radius:6px;-webkit-background-clip:padding-box;-moz-border-radius:6px;-moz-background-clip:padding;border-radius:6px;background-clip:padding-box;color:#444}#typicon-preview .icon .typcn:before{font-size:24px}#typicon-preview .icon:hover{background-color:#ffce55;line-height:38px;color:#fff}#typicon-preview .icon:hover .typcn:before{font-size:32px}.chartcontainer{width:100%;text-align:center}.easy-pie-chart-preview .well{width:100%;height:250px;text-align:center;position:relative;padding-top:50px}.easy-pie-chart-preview .well .easyPieChart{margin:0 auto}.sparkline-preview .well{text-align:center;position:relative}.buttons-preview .btn,.buttons-preview .btn-group{margin-bottom:10px;margin-right:10px}.dropdown-container{margin:0 auto;text-align:center}.dropdown-container .dropdown-preview{display:inline-block;text-align:left}.dropdown-container .dropdown-preview>.dropdown-menu{display:block;position:static;margin-bottom:5px}#dropdownbuttons .btn{margin-top:10px}.labels-container .label{margin:0 10px 10px 0}.popover-container{overflow:auto}.popoverexample .popover{position:relative;display:block;width:260px;margin:20px}.modal-preview .modal{position:relative;top:auto;right:auto;left:auto;bottom:auto;z-index:1;display:block;width:auto;overflow:hidden;max-width:600px}.modal-preview .modal .modal-dialog{width:90%}.bordered-well-container .well{margin-bottom:0}.knob-container{text-align:center}#red,#green,#blue{margin:10px;display:inline-block;height:200px}#colorpicker{height:240px;width:100%;margin:20px auto;padding:10px;border:1px solid #bfbfbf}#colorpicker .result{margin:60px 30px;height:100px;width:100px;display:inline-block;vertical-align:top;color:#7f7f7f;background:#7f7f7f;border:1px solid #fff;box-shadow:0 0 10px}#colors .colored-slider{margin-bottom:20px}#sizes .sized-slider{margin-bottom:20px}.grid-example .row{margin-bottom:15px;padding:0 15px}.grid-example .row [class^=col-]{padding-top:10px;padding-bottom:10px;background-color:#f5f5f5;border:1px solid #ddd} -------------------------------------------------------------------------------- /test/public/assets/css/weather-icons.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:'weather';src:url('../fonts/weathericons-regular-webfont.eot');src:url('../fonts/weathericons-regular-webfont.eot?#iefix') format('embedded-opentype'),url('../fonts/weathericons-regular-webfont.woff') format('woff'),url('../fonts/weathericons-regular-webfont.ttf') format('truetype'),url('../fonts/weathericons-regular-webfont.svg#weathericons-regular-webfontRg') format('svg');font-weight:normal;font-style:normal}[class^="wi-"],[class*=" wi-"]{font-family:weather;font-weight:normal;font-style:normal;text-decoration:inherit;text-transform:none;-webkit-font-smoothing:antialiased;*margin-right:.3em}[class^="wi-"]:before,[class*=" wi-"]:before{text-decoration:inherit;display:inline-block;speak:none}.wi-day-cloudy-gusts:before{content:""}.wi-day-cloudy-windy:before{content:""}.wi-day-cloudy:before{content:""}.wi-day-fog:before{content:""}.wi-day-hail:before{content:""}.wi-day-lightning:before{content:""}.wi-day-rain-mix:before{content:""}.wi-day-rain-wind:before{content:""}.wi-day-rain:before{content:""}.wi-day-showers:before{content:""}.wi-day-snow:before{content:""}.wi-day-sprinkle:before{content:""}.wi-day-sunny-overcast:before{content:""}.wi-day-sunny:before{content:""}.wi-day-storm-showers:before{content:""}.wi-day-thunderstorm:before{content:""}.wi-cloudy-gusts:before{content:""}.wi-cloudy-windy:before{content:""}.wi-cloudy:before{content:""}.wi-fog:before{content:""}.wi-hail:before{content:""}.wi-lightning:before{content:""}.wi-rain-mix:before{content:""}.wi-rain-wind:before{content:""}.wi-rain:before{content:""}.wi-showers:before{content:""}.wi-snow:before{content:""}.wi-sprinkle:before{content:""}.wi-storm-showers:before{content:""}.wi-thunderstorm:before{content:""}.wi-windy:before{content:""}.wi-night-alt-cloudy-gusts:before{content:""}.wi-night-alt-cloudy-windy:before{content:""}.wi-night-alt-hail:before{content:""}.wi-night-alt-lightning:before{content:""}.wi-night-alt-rain-mix:before{content:""}.wi-night-alt-rain-wind:before{content:""}.wi-night-alt-rain:before{content:""}.wi-night-alt-showers:before{content:""}.wi-night-alt-snow:before{content:""}.wi-night-alt-sprinkle:before{content:""}.wi-night-alt-storm-showers:before{content:""}.wi-night-alt-thunderstorm:before{content:""}.wi-night-clear:before{content:""}.wi-night-cloudy-gusts:before{content:""}.wi-night-cloudy-windy:before{content:""}.wi-night-cloudy:before{content:""}.wi-night-hail:before{content:""}.wi-night-lightning:before{content:""}.wi-night-rain-mix:before{content:""}.wi-night-rain-wind:before{content:""}.wi-night-rain:before{content:""}.wi-night-showers:before{content:""}.wi-night-snow:before{content:""}.wi-night-sprinkle:before{content:""}.wi-night-storm-showers:before{content:""}.wi-night-thunderstorm:before{content:""}.wi-celcius:before{content:""}.wi-cloud-down:before{content:""}.wi-cloud-refresh:before{content:""}.wi-cloud-up:before{content:""}.wi-cloud:before{content:""}.wi-degrees:before{content:""}.wi-down-left:before{content:""}.wi-down:before{content:""}.wi-fahrenheit:before{content:""}.wi-horizon-alt:before{content:""}.wi-horizon:before{content:""}.wi-left:before{content:""}.wi-night-fog:before{content:""}.wi-refresh-alt:before{content:""}.wi-refresh:before{content:""}.wi-right:before{content:""}.wi-sprinkles:before{content:""}.wi-strong-wind:before{content:""}.wi-sunrise:before{content:""}.wi-sunset:before{content:""}.wi-thermometer-exterior:before{content:""}.wi-thermometer-internal:before{content:""}.wi-thermometer:before{content:""}.wi-tornado:before{content:""}.wi-up-right:before{content:""}.wi-up:before{content:""}.wi-wind-east:before{content:""}.wi-wind-north-east:before{content:""}.wi-wind-north-west:before{content:""}.wi-wind-north:before{content:""}.wi-wind-south-east:before{content:""}.wi-wind-south-west:before{content:""}.wi-wind-south:before{content:""}.wi-wind-west:before{content:""} -------------------------------------------------------------------------------- /test/public/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /test/public/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /test/public/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /test/public/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /test/public/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /test/public/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /test/public/assets/fonts/typicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/typicons.eot -------------------------------------------------------------------------------- /test/public/assets/fonts/typicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/typicons.ttf -------------------------------------------------------------------------------- /test/public/assets/fonts/typicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/typicons.woff -------------------------------------------------------------------------------- /test/public/assets/fonts/weathericons-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/weathericons-regular-webfont.eot -------------------------------------------------------------------------------- /test/public/assets/fonts/weathericons-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/weathericons-regular-webfont.ttf -------------------------------------------------------------------------------- /test/public/assets/fonts/weathericons-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/fonts/weathericons-regular-webfont.woff -------------------------------------------------------------------------------- /test/public/assets/img/attach-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/attach-blue.png -------------------------------------------------------------------------------- /test/public/assets/img/attach-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/attach-green.png -------------------------------------------------------------------------------- /test/public/assets/img/attach-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/attach-red.png -------------------------------------------------------------------------------- /test/public/assets/img/attach-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/attach-yellow.png -------------------------------------------------------------------------------- /test/public/assets/img/avatars/Javi-Jimenez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/Javi-Jimenez.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/John-Smith.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/John-Smith.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/Matt-Cheuvront.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/Matt-Cheuvront.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/Nicolai-Larson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/Nicolai-Larson.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/Osvaldus-Valutis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/Osvaldus-Valutis.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/Sergey-Azovskiy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/Sergey-Azovskiy.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/Stephanie-Walter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/Stephanie-Walter.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/adam-jansen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/adam-jansen.jpg -------------------------------------------------------------------------------- /test/public/assets/img/avatars/bing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/bing.png -------------------------------------------------------------------------------- /test/public/assets/img/avatars/divyia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/avatars/divyia.jpg -------------------------------------------------------------------------------- /test/public/assets/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/favicon.png -------------------------------------------------------------------------------- /test/public/assets/img/jquery.minicolors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/jquery.minicolors.png -------------------------------------------------------------------------------- /test/public/assets/img/logo-inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/logo-inverted.png -------------------------------------------------------------------------------- /test/public/assets/img/logo-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/logo-rtl.png -------------------------------------------------------------------------------- /test/public/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/logo.png -------------------------------------------------------------------------------- /test/public/assets/img/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/sort_asc.png -------------------------------------------------------------------------------- /test/public/assets/img/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/sort_asc_disabled.png -------------------------------------------------------------------------------- /test/public/assets/img/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/sort_both.png -------------------------------------------------------------------------------- /test/public/assets/img/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/sort_desc.png -------------------------------------------------------------------------------- /test/public/assets/img/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/sort_desc_disabled.png -------------------------------------------------------------------------------- /test/public/assets/img/temp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandashuai/mysql_rbac/e8cf4cc337e56d5dcfacb93a9b6a6f82b089f3c8/test/public/assets/img/temp1.png -------------------------------------------------------------------------------- /test/public/assets/js/beyond.js: -------------------------------------------------------------------------------- 1 | 2 | 404 Not Found 3 | 4 |

404 Not Found

5 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /test/public/assets/js/beyond.min.js: -------------------------------------------------------------------------------- 1 | function getThemeColorFromCss(n){var t=$("<\/span>").hide().appendTo("body"),i;return t.addClass(n),i=t.css("color"),t.remove(),i}function InitiateSideMenu(){$(".sidebar-toggler").on("click",function(){return $("#sidebar").toggleClass("hide"),$(".sidebar-toggler").toggleClass("active"),!1});var n=$("#sidebar").hasClass("menu-compact");$("#sidebar-collapse").on("click",function(){$("#sidebar").is(":visible")||$("#sidebar").toggleClass("hide");$("#sidebar").toggleClass("menu-compact");$(".sidebar-collapse").toggleClass("active");n=$("#sidebar").hasClass("menu-compact");n&&$(".open > .submenu").removeClass("open")});$(".sidebar-menu").on("click",function(t){var i=$(t.target).closest("a"),u,r,f;if(i&&i.length!=0){if(!i.hasClass("menu-dropdown"))return n&&i.get(0).parentNode.parentNode==this&&(u=i.find(".menu-text").get(0),t.target!=u&&!$.contains(u,t.target))?!1:void 0;if(r=i.next().get(0),!$(r).is(":visible")){if(f=$(r.parentNode).closest("ul"),n&&f.hasClass("sidebar-menu"))return;f.find("> .open > .submenu").each(function(){this==r||$(this.parentNode).hasClass("active")||$(this).slideUp(200).parent().removeClass("open")})}return n&&$(r.parentNode.parentNode).hasClass("sidebar-menu")?!1:($(r).slideToggle(200).parent().toggleClass("open"),!1)}})}function InitiateWidgets(){$('.widget-buttons *[data-toggle="maximize"]').on("click",function(n){n.preventDefault();var t=$(this).parents(".widget").eq(0),i=$(this).find("i").eq(0),r="fa-compress",u="fa-expand";t.hasClass("maximized")?(i&&i.addClass(u).removeClass(r),t.removeClass("maximized"),t.find(".widget-body").css("height","auto")):(i&&i.addClass(r).removeClass(u),t.addClass("maximized"),maximize(t))});$('.widget-buttons *[data-toggle="collapse"]').on("click",function(n){n.preventDefault();var t=$(this).parents(".widget").eq(0),r=t.find(".widget-body"),i=$(this).find("i"),u="fa-plus",f="fa-minus",e=300;t.hasClass("collapsed")?(i&&i.addClass(f).removeClass(u),t.removeClass("collapsed"),r.slideUp(0,function(){r.slideDown(e)})):(i&&i.addClass(u).removeClass(f),r.slideUp(200,function(){t.addClass("collapsed")}))});$('.widget-buttons *[data-toggle="dispose"]').on("click",function(n){n.preventDefault();var i=$(this),t=i.parents(".widget").eq(0);t.hide(300,function(){t.remove()})})}function maximize(n){if(n){var t=$(window).height(),i=n.find(".widget-header").height();n.find(".widget-body").height(t-i)}}function scrollTo(n,t){var i=n&&n.size()>0?n.offset().top:0;jQuery("html,body").animate({scrollTop:i+(t?t:0)},"slow")}function Notify(n,t,i,r,u,f){toastr.options.positionClass="toast-"+t;toastr.options.extendedTimeOut=0;toastr.options.timeOut=i;toastr.options.closeButton=f;toastr.options.iconClass=u+" toast-"+r;toastr.custom(n)}function InitiateSettings(){readCookie("navbar-fixed-top")!=null&&readCookie("navbar-fixed-top")=="true"&&($("#checkbox_fixednavbar").prop("checked",!0),$(".navbar").addClass("navbar-fixed-top"));readCookie("sidebar-fixed")!=null&&readCookie("sidebar-fixed")=="true"&&($("#checkbox_fixedsidebar").prop("checked",!0),$(".page-sidebar").addClass("sidebar-fixed"));readCookie("breadcrumbs-fixed")!=null&&readCookie("breadcrumbs-fixed")=="true"&&($("#checkbox_fixedbreadcrumbs").prop("checked",!0),$(".page-breadcrumbs").addClass("breadcrumbs-fixed"));readCookie("page-header-fixed")!=null&&readCookie("page-header-fixed")=="true"&&($("#checkbox_fixedheader").prop("checked",!0),$(".page-header").addClass("page-header-fixed"));$("#checkbox_fixednavbar").change(function(){$(".navbar").toggleClass("navbar-fixed-top");$("#checkbox_fixedsidebar").is(":checked")&&($("#checkbox_fixedsidebar").prop("checked",!1),$(".page-sidebar").toggleClass("sidebar-fixed"));$("#checkbox_fixedbreadcrumbs").is(":checked")&&!$(this).is(":checked")&&($("#checkbox_fixedbreadcrumbs").prop("checked",!1),$(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));$("#checkbox_fixedheader").is(":checked")&&!$(this).is(":checked")&&($("#checkbox_fixedheader").prop("checked",!1),$(".page-header").toggleClass("page-header-fixed"));setCookiesForFixedSettings()});$("#checkbox_fixedsidebar").change(function(){$(".page-sidebar").toggleClass("sidebar-fixed");$("#checkbox_fixednavbar").is(":checked")||($("#checkbox_fixednavbar").prop("checked",!0),$(".navbar").toggleClass("navbar-fixed-top"));$("#checkbox_fixedbreadcrumbs").is(":checked")&&!$(this).is(":checked")&&($("#checkbox_fixedbreadcrumbs").prop("checked",!1),$(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));$("#checkbox_fixedheader").is(":checked")&&!$(this).is(":checked")&&($("#checkbox_fixedheader").prop("checked",!1),$(".page-header").toggleClass("page-header-fixed"));setCookiesForFixedSettings()});$("#checkbox_fixedbreadcrumbs").change(function(){$(".page-breadcrumbs").toggleClass("breadcrumbs-fixed");$("#checkbox_fixedsidebar").is(":checked")||($("#checkbox_fixedsidebar").prop("checked",!0),$(".page-sidebar").toggleClass("sidebar-fixed"));$("#checkbox_fixednavbar").is(":checked")||($("#checkbox_fixednavbar").prop("checked",!0),$(".navbar").toggleClass("navbar-fixed-top"));$("#checkbox_fixedheader").is(":checked")&&!$(this).is(":checked")&&($("#checkbox_fixedheader").prop("checked",!1),$(".page-header").toggleClass("page-header-fixed"));setCookiesForFixedSettings()});$("#checkbox_fixedheader").change(function(){$(".page-header").toggleClass("page-header-fixed");$("#checkbox_fixedbreadcrumbs").is(":checked")||($("#checkbox_fixedbreadcrumbs").prop("checked",!0),$(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));$("#checkbox_fixedsidebar").is(":checked")||($("#checkbox_fixedsidebar").prop("checked",!0),$(".page-sidebar").toggleClass("sidebar-fixed"));$("#checkbox_fixednavbar").is(":checked")||($("#checkbox_fixednavbar").prop("checked",!0),$(".navbar").toggleClass("navbar-fixed-top"));setCookiesForFixedSettings()})}function setCookiesForFixedSettings(){createCookie("navbar-fixed-top",$("#checkbox_fixednavbar").is(":checked"),100);createCookie("sidebar-fixed",$("#checkbox_fixedsidebar").is(":checked"),100);createCookie("breadcrumbs-fixed",$("#checkbox_fixedbreadcrumbs").is(":checked"),100);createCookie("page-header-fixed",$("#checkbox_fixedheader").is(":checked"),100)}function getcolor(n){switch(n){case"themeprimary":return themeprimary;case"themesecondary":return themesecondary;case"themethirdcolor":return themethirdcolor;case"themefourthcolor":return themefourthcolor;case"themefifthcolor":return themefifthcolor;default:return n}}function switchClasses(n,t){var u=document.getElementsByClassName(n),r;for(i=u.length-1;i>=0;i--)hasClass(u[i],"dropdown-menu")||(addClass(u[i],n+"-temp"),removeClass(u[i],n));for(r=document.getElementsByClassName(t),i=r.length-1;i>=0;i--)hasClass(r[i],"dropdown-menu")||(addClass(r[i],n),removeClass(r[i],t));for(tempClasses=document.getElementsByClassName(n+"-temp"),i=tempClasses.length-1;i>=0;i--)hasClass(tempClasses[i],"dropdown-menu")||(addClass(tempClasses[i],t),removeClass(tempClasses[i],n+"-temp"))}function addClass(n,t){var i=n.className;i&&(i+=" ");n.className=i+t}function removeClass(n,t){var i=" "+n.className+" ";n.className=i.replace(" "+t,"").replace(/^\s+/g,"").replace(/\s+$/g,"")}function hasClass(n,t){var i=" "+n.className+" ",r=" "+t+" ";return i.indexOf(r)!=-1}var themeprimary=getThemeColorFromCss("themeprimary"),themesecondary=getThemeColorFromCss("themesecondary"),themethirdcolor=getThemeColorFromCss("themethirdcolor"),themefourthcolor=getThemeColorFromCss("themefourthcolor"),themefifthcolor=getThemeColorFromCss("themefifthcolor"),rtlchanger,popovers,hoverpopovers;$("#skin-changer li a").click(function(){createCookie("current-skin",$(this).attr("rel"),10);window.location.reload()});rtlchanger=document.getElementById("rtl-changer");location.pathname!="/index-rtl-fa.html"&&location.pathname!="/index-rtl-ar.html"&&(readCookie("rtl-support")?(switchClasses("pull-right","pull-left"),switchClasses("databox-right","databox-left"),switchClasses("item-right","item-left"),$(".navbar-brand small img").attr("src","assets/img/logo-rtl.png"),rtlchanger!=null&&(document.getElementById("rtl-changer").checked=!0)):rtlchanger!=null&&(rtlchanger.checked=!1),rtlchanger!=null&&(rtlchanger.onchange=function(){this.checked?createCookie("rtl-support","true",10):eraseCookie("rtl-support");setTimeout(function(){window.location.reload()},600)}));$(window).load(function(){setTimeout(function(){$(".loading-container").addClass("loading-inactive")},0)});$("#btn-setting").on("click",function(){$(".navbar-account").toggleClass("setting-open")});$("#fullscreen-toggler").on("click",function(){var n=document.documentElement;$("body").hasClass("full-screen")?($("body").removeClass("full-screen"),$("#fullscreen-toggler").removeClass("active"),document.exitFullscreen?document.exitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.webkitExitFullscreen&&document.webkitExitFullscreen()):($("body").addClass("full-screen"),$("#fullscreen-toggler").addClass("active"),n.requestFullscreen?n.requestFullscreen():n.mozRequestFullScreen?n.mozRequestFullScreen():n.webkitRequestFullscreen?n.webkitRequestFullscreen():n.msRequestFullscreen&&n.msRequestFullscreen())});popovers=$("[data-toggle=popover]");$.each(popovers,function(){$(this).popover({html:!0,template:'
<\/div>

Popover right<\/h3>
<\/div><\/div>'})});hoverpopovers=$("[data-toggle=popover-hover]");$.each(hoverpopovers,function(){$(this).popover({html:!0,template:'
<\/div>

Popover right<\/h3>
<\/div><\/div>',trigger:"hover"})});$("[data-toggle=tooltip]").tooltip({html:!0});InitiateSideMenu();InitiateSettings();InitiateWidgets(); 2 | /* 3 | //# sourceMappingURL=beyond.min.js.map 4 | */ -------------------------------------------------------------------------------- /test/public/assets/js/charts/chartjs/chartjs-init.js: -------------------------------------------------------------------------------- 1 | var gridbordercolor = "#eee"; 2 | 3 | var InitiateChartJS = function () { 4 | return { 5 | init: function () { 6 | 7 | var doughnutData = [ 8 | { 9 | value: 30, 10 | color: themeprimary 11 | }, 12 | { 13 | value: 50, 14 | color: themesecondary 15 | }, 16 | { 17 | value: 100, 18 | color: themethirdcolor 19 | }, 20 | { 21 | value: 40, 22 | color: themefourthcolor 23 | }, 24 | { 25 | value: 120, 26 | color: themefifthcolor 27 | } 28 | 29 | ]; 30 | var lineChartData = { 31 | labels: ["", "", "", "", "", "", ""], 32 | datasets: [ 33 | { 34 | fillColor: "rgba(93, 178, 255,.4)", 35 | strokeColor: "rgba(93, 178, 255,.7)", 36 | pointColor: "rgba(93, 178, 255,.7)", 37 | pointStrokeColor: "#fff", 38 | data: [65, 59, 90, 81, 56, 55, 40] 39 | }, 40 | { 41 | fillColor: "rgba(215, 61, 50,.4)", 42 | strokeColor: "rgba(215, 61, 50,.6)", 43 | pointColor: "rgba(215, 61, 50,.6)", 44 | pointStrokeColor: "#fff", 45 | data: [28, 48, 40, 19, 96, 27, 100] 46 | } 47 | ] 48 | 49 | }; 50 | var pieData = [ 51 | { 52 | value: 30, 53 | color: themeprimary 54 | }, 55 | { 56 | value: 50, 57 | color: themesecondary 58 | }, 59 | { 60 | value: 100, 61 | color: themefourthcolor 62 | } 63 | 64 | ]; 65 | var barChartData = { 66 | labels: ["January", "February", "March", "April", "May", "June", "July"], 67 | datasets: [ 68 | { 69 | fillColor: themeprimary, 70 | strokeColor: themeprimary, 71 | data: [65, 59, 90, 81, 56, 55, 40] 72 | }, 73 | { 74 | fillColor: themethirdcolor, 75 | strokeColor: themethirdcolor, 76 | data: [28, 48, 40, 19, 96, 27, 100] 77 | } 78 | ] 79 | 80 | }; 81 | var chartData = [ 82 | { 83 | value: Math.random(), 84 | color: themeprimary 85 | }, 86 | { 87 | value: Math.random(), 88 | color: themesecondary 89 | }, 90 | { 91 | value: Math.random(), 92 | color: themethirdcolor 93 | }, 94 | { 95 | value: Math.random(), 96 | color: themefourthcolor 97 | }, 98 | { 99 | value: Math.random(), 100 | color: themefifthcolor 101 | }, 102 | { 103 | value: Math.random(), 104 | color: "#ed4e2a" 105 | } 106 | ]; 107 | var radarChartData = { 108 | labels: ["", "", "", "", "", "", ""], 109 | datasets: [ 110 | { 111 | fillColor: "rgba(140,196,116,0.5)", 112 | strokeColor: "rgba(140,196,116,.7)", 113 | pointColor: "rgba(140,196,116,.7)", 114 | pointStrokeColor: "#fff", 115 | data: [65, 59, 90, 81, 56, 55, 40] 116 | }, 117 | { 118 | fillColor: "rgba(215,61,50,0.5)", 119 | strokeColor: "rgba(215,61,50,.7)", 120 | pointColor: "rgba(215,61,50,.7)", 121 | pointStrokeColor: "#fff", 122 | data: [28, 48, 40, 19, 96, 27, 100] 123 | } 124 | ] 125 | 126 | }; 127 | new Chart(document.getElementById("doughnut").getContext("2d")).Doughnut(doughnutData); 128 | new Chart(document.getElementById("line").getContext("2d")).Line(lineChartData); 129 | new Chart(document.getElementById("radar").getContext("2d")).Radar(radarChartData); 130 | new Chart(document.getElementById("polarArea").getContext("2d")).PolarArea(chartData); 131 | new Chart(document.getElementById("bar").getContext("2d")).Bar(barChartData); 132 | new Chart(document.getElementById("pie").getContext("2d")).Pie(pieData); 133 | 134 | } 135 | }; 136 | }(); 137 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/easypiechart/easypiechart-init.js: -------------------------------------------------------------------------------- 1 |  2 | var gridbordercolor = "#eee"; 3 | 4 | var InitiateEasyPieChart = function () { 5 | return { 6 | init: function () { 7 | var easypiecharts = $('[data-toggle=easypiechart]'); 8 | $.each(easypiecharts, function () { 9 | var barColor = getcolor($(this).data('barcolor')) || themeprimary, 10 | trackColor = getcolor($(this).data('trackcolor')) || false, 11 | scaleColor = getcolor($(this).data('scalecolor')) || false, 12 | lineCap = $(this).data('linecap') || "round", 13 | lineWidth = $(this).data('linewidth') || 3, 14 | size = $(this).data('size') || 110, 15 | animate = $(this).data('animate') || false; 16 | 17 | $(this).easyPieChart({ 18 | barColor: barColor, 19 | trackColor: trackColor, 20 | scaleColor: scaleColor, 21 | lineCap: lineCap, 22 | lineWidth: lineWidth, 23 | size: size, 24 | animate : animate 25 | }); 26 | }); 27 | } 28 | }; 29 | }(); 30 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/easypiechart/jquery.easypiechart.js: -------------------------------------------------------------------------------- 1 | (function (a) { 2 | a.easyPieChart = function (d, l) { 3 | var f, g, i, j, c, k, e, b, h = this; 4 | this.el = d; 5 | this.$el = a(d); 6 | this.$el.data("easyPieChart", this); 7 | this.init = function () { 8 | var n, m; 9 | h.options = a.extend({}, a.easyPieChart.defaultOptions, l); 10 | n = parseInt(h.$el.data("percent"), 10); 11 | h.percentage = 0; 12 | h.canvas = a("").get(0); 13 | h.$el.append(h.canvas); 14 | if (typeof G_vmlCanvasManager !== "undefined" && G_vmlCanvasManager !== null) { 15 | G_vmlCanvasManager.initElement(h.canvas) 16 | } 17 | h.ctx = h.canvas.getContext("2d"); 18 | if (window.devicePixelRatio > 1) { 19 | m = window.devicePixelRatio; 20 | a(h.canvas).css({ 21 | width: h.options.size, 22 | height: h.options.size 23 | }); 24 | h.canvas.width *= m; 25 | h.canvas.height *= m; 26 | h.ctx.scale(m, m) 27 | } 28 | h.ctx.translate(h.options.size / 2, h.options.size / 2); 29 | h.ctx.rotate(h.options.rotate * Math.PI / 180); 30 | h.$el.addClass("easyPieChart"); 31 | h.$el.css({ 32 | width: h.options.size, 33 | height: h.options.size, 34 | lineHeight: "" + h.options.size + "px" 35 | }); 36 | h.update(n); 37 | return h 38 | }; 39 | this.update = function (m) { 40 | m = parseFloat(m) || 0; 41 | if (h.options.animate === false) { 42 | i(m) 43 | } else { 44 | g(h.percentage, m) 45 | } 46 | return h 47 | }; 48 | e = function () { 49 | var n, o, m; 50 | h.ctx.fillStyle = h.options.scaleColor; 51 | h.ctx.lineWidth = 1; 52 | m = []; 53 | for (n = o = 0; o <= 24; n = ++o) { 54 | m.push(f(n)) 55 | } 56 | return m 57 | }; 58 | f = function (m) { 59 | var n; 60 | n = m % 6 === 0 ? 0 : h.options.size * 0.017; 61 | h.ctx.save(); 62 | h.ctx.rotate(m * Math.PI / 12); 63 | h.ctx.fillRect(h.options.size / 2 - n, 0, -h.options.size * 0.05 + n, 1); 64 | h.ctx.restore() 65 | }; 66 | b = function () { 67 | var m; 68 | m = h.options.size / 2 - h.options.lineWidth / 2; 69 | if (h.options.scaleColor !== false) { 70 | m -= h.options.size * 0.08 71 | } 72 | h.ctx.beginPath(); 73 | h.ctx.arc(0, 0, m, 0, Math.PI * 2, true); 74 | h.ctx.closePath(); 75 | h.ctx.strokeStyle = h.options.trackColor; 76 | h.ctx.lineWidth = h.options.lineWidth; 77 | h.ctx.stroke() 78 | }; 79 | k = function () { 80 | if (h.options.scaleColor !== false) { 81 | e() 82 | } 83 | if (h.options.trackColor !== false) { 84 | b() 85 | } 86 | }; 87 | i = function (m) { 88 | var n; 89 | k(); 90 | h.ctx.strokeStyle = a.isFunction(h.options.barColor) ? h.options.barColor(m) : h.options.barColor; 91 | h.ctx.lineCap = h.options.lineCap; 92 | h.ctx.lineWidth = h.options.lineWidth; 93 | n = h.options.size / 2 - h.options.lineWidth / 2; 94 | if (h.options.scaleColor !== false) { 95 | n -= h.options.size * 0.08 96 | } 97 | h.ctx.save(); 98 | h.ctx.rotate(-Math.PI / 2); 99 | h.ctx.beginPath(); 100 | h.ctx.arc(0, 0, n, 0, Math.PI * 2 * m / 100, false); 101 | h.ctx.stroke(); 102 | h.ctx.restore() 103 | }; 104 | c = (function () { 105 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (m) { 106 | return window.setTimeout(m, 1000 / 60) 107 | } 108 | })(); 109 | g = function (p, o) { 110 | var n, m; 111 | h.options.onStart.call(h); 112 | h.percentage = o; 113 | m = Date.now(); 114 | n = function () { 115 | var q, r; 116 | r = Date.now() - m; 117 | if (r < h.options.animate) { 118 | c(n) 119 | } 120 | h.ctx.clearRect(-h.options.size / 2, -h.options.size / 2, h.options.size, h.options.size); 121 | k.call(h); 122 | q = [j(r, p, o - p, h.options.animate)]; 123 | h.options.onStep.call(h, q); 124 | i.call(h, q); 125 | if (r >= h.options.animate) { 126 | return h.options.onStop.call(h) 127 | } 128 | }; 129 | c(n) 130 | }; 131 | j = function (o, n, r, p) { 132 | var m, q; 133 | m = function (s) { 134 | return Math.pow(s, 2) 135 | }; 136 | q = function (s) { 137 | if (s < 1) { 138 | return m(s) 139 | } else { 140 | return 2 - m((s / 2) * -2 + 2) 141 | } 142 | }; 143 | o /= p / 2; 144 | return r / 2 * q(o) + n 145 | }; 146 | return this.init() 147 | }; 148 | a.easyPieChart.defaultOptions = { 149 | barColor: "#ef1e25", 150 | trackColor: "#f2f2f2", 151 | scaleColor: "#dfe0e0", 152 | lineCap: "round", 153 | rotate: 0, 154 | size: 110, 155 | lineWidth: 3, 156 | animate: false, 157 | onStart: a.noop, 158 | onStop: a.noop, 159 | onStep: a.noop 160 | }; 161 | a.fn.easyPieChart = function (b) { 162 | return a.each(this, function (d, e) { 163 | var c, f; 164 | c = a(e); 165 | if (!c.data("easyPieChart")) { 166 | f = a.extend({}, b, c.data()); 167 | return c.data("easyPieChart", new a.easyPieChart(e, f)) 168 | } 169 | }) 170 | }; 171 | return void 0 172 | })(jQuery); -------------------------------------------------------------------------------- /test/public/assets/js/charts/flot/jquery.flot.crosshair.js: -------------------------------------------------------------------------------- 1 | /* Flot plugin for showing crosshairs when the mouse hovers over the plot. 2 | 3 | Copyright (c) 2007-2013 IOLA and Ole Laursen. 4 | Licensed under the MIT license. 5 | 6 | The plugin supports these options: 7 | 8 | crosshair: { 9 | mode: null or "x" or "y" or "xy" 10 | color: color 11 | lineWidth: number 12 | } 13 | 14 | Set the mode to one of "x", "y" or "xy". The "x" mode enables a vertical 15 | crosshair that lets you trace the values on the x axis, "y" enables a 16 | horizontal crosshair and "xy" enables them both. "color" is the color of the 17 | crosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of 18 | the drawn lines (default is 1). 19 | 20 | The plugin also adds four public methods: 21 | 22 | - setCrosshair( pos ) 23 | 24 | Set the position of the crosshair. Note that this is cleared if the user 25 | moves the mouse. "pos" is in coordinates of the plot and should be on the 26 | form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple 27 | axes), which is coincidentally the same format as what you get from a 28 | "plothover" event. If "pos" is null, the crosshair is cleared. 29 | 30 | - clearCrosshair() 31 | 32 | Clear the crosshair. 33 | 34 | - lockCrosshair(pos) 35 | 36 | Cause the crosshair to lock to the current location, no longer updating if 37 | the user moves the mouse. Optionally supply a position (passed on to 38 | setCrosshair()) to move it to. 39 | 40 | Example usage: 41 | 42 | var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; 43 | $("#graph").bind( "plothover", function ( evt, position, item ) { 44 | if ( item ) { 45 | // Lock the crosshair to the data point being hovered 46 | myFlot.lockCrosshair({ 47 | x: item.datapoint[ 0 ], 48 | y: item.datapoint[ 1 ] 49 | }); 50 | } else { 51 | // Return normal crosshair operation 52 | myFlot.unlockCrosshair(); 53 | } 54 | }); 55 | 56 | - unlockCrosshair() 57 | 58 | Free the crosshair to move again after locking it. 59 | */ 60 | 61 | (function ($) { 62 | var options = { 63 | crosshair: { 64 | mode: null, // one of null, "x", "y" or "xy", 65 | color: "rgba(170, 0, 0, 0.80)", 66 | lineWidth: 1 67 | } 68 | }; 69 | 70 | function init(plot) { 71 | // position of crosshair in pixels 72 | var crosshair = { x: -1, y: -1, locked: false }; 73 | 74 | plot.setCrosshair = function setCrosshair(pos) { 75 | if (!pos) 76 | crosshair.x = -1; 77 | else { 78 | var o = plot.p2c(pos); 79 | crosshair.x = Math.max(0, Math.min(o.left, plot.width())); 80 | crosshair.y = Math.max(0, Math.min(o.top, plot.height())); 81 | } 82 | 83 | plot.triggerRedrawOverlay(); 84 | }; 85 | 86 | plot.clearCrosshair = plot.setCrosshair; // passes null for pos 87 | 88 | plot.lockCrosshair = function lockCrosshair(pos) { 89 | if (pos) 90 | plot.setCrosshair(pos); 91 | crosshair.locked = true; 92 | }; 93 | 94 | plot.unlockCrosshair = function unlockCrosshair() { 95 | crosshair.locked = false; 96 | }; 97 | 98 | function onMouseOut(e) { 99 | if (crosshair.locked) 100 | return; 101 | 102 | if (crosshair.x != -1) { 103 | crosshair.x = -1; 104 | plot.triggerRedrawOverlay(); 105 | } 106 | } 107 | 108 | function onMouseMove(e) { 109 | if (crosshair.locked) 110 | return; 111 | 112 | if (plot.getSelection && plot.getSelection()) { 113 | crosshair.x = -1; // hide the crosshair while selecting 114 | return; 115 | } 116 | 117 | var offset = plot.offset(); 118 | crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); 119 | crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); 120 | plot.triggerRedrawOverlay(); 121 | } 122 | 123 | plot.hooks.bindEvents.push(function (plot, eventHolder) { 124 | if (!plot.getOptions().crosshair.mode) 125 | return; 126 | 127 | eventHolder.mouseout(onMouseOut); 128 | eventHolder.mousemove(onMouseMove); 129 | }); 130 | 131 | plot.hooks.drawOverlay.push(function (plot, ctx) { 132 | var c = plot.getOptions().crosshair; 133 | if (!c.mode) 134 | return; 135 | 136 | var plotOffset = plot.getPlotOffset(); 137 | 138 | ctx.save(); 139 | ctx.translate(plotOffset.left, plotOffset.top); 140 | 141 | if (crosshair.x != -1) { 142 | var adj = plot.getOptions().crosshair.lineWidth % 2 === 0 ? 0 : 0.5; 143 | 144 | ctx.strokeStyle = c.color; 145 | ctx.lineWidth = c.lineWidth; 146 | ctx.lineJoin = "round"; 147 | 148 | ctx.beginPath(); 149 | if (c.mode.indexOf("x") != -1) { 150 | var drawX = Math.round(crosshair.x) + adj; 151 | ctx.moveTo(drawX, 0); 152 | ctx.lineTo(drawX, plot.height()); 153 | } 154 | if (c.mode.indexOf("y") != -1) { 155 | var drawY = Math.round(crosshair.y) + adj; 156 | ctx.moveTo(0, drawY); 157 | ctx.lineTo(plot.width(), drawY); 158 | } 159 | ctx.stroke(); 160 | } 161 | ctx.restore(); 162 | }); 163 | 164 | plot.hooks.shutdown.push(function (plot, eventHolder) { 165 | eventHolder.unbind("mouseout", onMouseOut); 166 | eventHolder.unbind("mousemove", onMouseMove); 167 | }); 168 | } 169 | 170 | $.plot.plugins.push({ 171 | init: init, 172 | options: options, 173 | name: 'crosshair', 174 | version: '1.0' 175 | }); 176 | })(jQuery); 177 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/flot/jquery.flot.orderBars.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Flot plugin to order bars side by side. 3 | * 4 | * Released under the MIT license by Benjamin BUFFET, 20-Sep-2010. 5 | * Modifications made by Steven Hall , 01-May-2013. 6 | * 7 | * This plugin is an alpha version. 8 | * 9 | * To activate the plugin you must specify the parameter "order" for the specific serie : 10 | * 11 | * $.plot($("#placeholder"), [{ data: [ ... ], bars :{ order = null or integer }]) 12 | * 13 | * If 2 series have the same order param, they are ordered by the position in the array; 14 | * 15 | * The plugin adjust the point by adding a value depanding of the barwidth 16 | * Exemple for 3 series (barwidth : 0.1) : 17 | * 18 | * first bar décalage : -0.15 19 | * second bar décalage : -0.05 20 | * third bar décalage : 0.05 21 | * 22 | */ 23 | 24 | // INFO: decalage/decallage is French for gap. It's used to denote the spacing applied to each 25 | // bar. 26 | (function($){ 27 | function init(plot){ 28 | var orderedBarSeries; 29 | var nbOfBarsToOrder; 30 | var borderWidth; 31 | var borderWidthInXabsWidth; 32 | var pixelInXWidthEquivalent = 1; 33 | var isHorizontal = false; 34 | 35 | // A mapping of order integers to decallage. 36 | var decallageByOrder = {}; 37 | 38 | /* 39 | * This method add shift to x values 40 | */ 41 | function reOrderBars(plot, serie, datapoints){ 42 | var shiftedPoints = null; 43 | 44 | if(serieNeedToBeReordered(serie)){ 45 | checkIfGraphIsHorizontal(serie); 46 | calculPixel2XWidthConvert(plot); 47 | retrieveBarSeries(plot); 48 | calculBorderAndBarWidth(serie); 49 | 50 | if(nbOfBarsToOrder >= 2){ 51 | var position = findPosition(serie); 52 | var decallage = 0; 53 | 54 | var centerBarShift = calculCenterBarShift(); 55 | 56 | // If we haven't already calculated the decallage for this order value, do it. 57 | if(typeof decallageByOrder[serie.bars.order] === 'undefined') { 58 | if (isBarAtLeftOfCenter(position)){ 59 | decallageByOrder[serie.bars.order] = -1*(sumWidth(orderedBarSeries,position-1,Math.floor(nbOfBarsToOrder / 2)-1)) - centerBarShift; 60 | }else{ 61 | decallageByOrder[serie.bars.order] = sumWidth(orderedBarSeries,Math.ceil(nbOfBarsToOrder / 2),position-2) + centerBarShift + borderWidthInXabsWidth*2; 62 | } 63 | } 64 | 65 | // Lookup the decallage based on the series' order value. 66 | decallage = decallageByOrder[serie.bars.order]; 67 | 68 | shiftedPoints = shiftPoints(datapoints,serie,decallage); 69 | datapoints.points = shiftedPoints; 70 | } 71 | } 72 | return shiftedPoints; 73 | } 74 | 75 | function serieNeedToBeReordered(serie){ 76 | return serie.bars != null 77 | && serie.bars.show 78 | && serie.bars.order != null; 79 | } 80 | 81 | function calculPixel2XWidthConvert(plot){ 82 | var gridDimSize = isHorizontal ? plot.getPlaceholder().innerHeight() : plot.getPlaceholder().innerWidth(); 83 | var minMaxValues = isHorizontal ? getAxeMinMaxValues(plot.getData(),1) : getAxeMinMaxValues(plot.getData(),0); 84 | var AxeSize = minMaxValues[1] - minMaxValues[0]; 85 | pixelInXWidthEquivalent = AxeSize / gridDimSize; 86 | } 87 | 88 | function getAxeMinMaxValues(series,AxeIdx){ 89 | var minMaxValues = new Array(); 90 | for(var i = 0; i < series.length; i++){ 91 | minMaxValues[0] = series[i].data[0][AxeIdx]; 92 | minMaxValues[1] = series[i].data[series[i].data.length - 1][AxeIdx]; 93 | } 94 | return minMaxValues; 95 | } 96 | 97 | function retrieveBarSeries(plot){ 98 | orderedBarSeries = findOthersBarsToReOrders(plot.getData()); 99 | nbOfBarsToOrder = orderedBarSeries.length; 100 | } 101 | 102 | function findOthersBarsToReOrders(series){ 103 | var retSeries = new Array(); 104 | var orderValuesSeen = []; 105 | 106 | for(var i = 0; i < series.length; i++){ 107 | if(series[i].bars.order != null && series[i].bars.show && 108 | orderValuesSeen.indexOf(series[i].bars.order) < 0){ 109 | 110 | orderValuesSeen.push(series[i].bars.order); 111 | retSeries.push(series[i]); 112 | } 113 | } 114 | return retSeries.sort(sortByOrder); 115 | } 116 | 117 | function sortByOrder(serie1,serie2){ 118 | var x = serie1.bars.order; 119 | var y = serie2.bars.order; 120 | return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 121 | } 122 | 123 | function calculBorderAndBarWidth(serie){ 124 | borderWidth = typeof serie.bars.lineWidth !== 'undefined' ? serie.bars.lineWidth : 2; 125 | borderWidthInXabsWidth = borderWidth * pixelInXWidthEquivalent; 126 | } 127 | 128 | function checkIfGraphIsHorizontal(serie){ 129 | if(serie.bars.horizontal){ 130 | isHorizontal = true; 131 | } 132 | } 133 | 134 | function findPosition(serie){ 135 | var pos = 0 136 | for (var i = 0; i < orderedBarSeries.length; ++i) { 137 | if (serie == orderedBarSeries[i]){ 138 | pos = i; 139 | break; 140 | } 141 | } 142 | 143 | return pos+1; 144 | } 145 | 146 | function calculCenterBarShift(){ 147 | var width = 0; 148 | 149 | if(nbOfBarsToOrder%2 != 0) 150 | width = (orderedBarSeries[Math.ceil(nbOfBarsToOrder / 2)].bars.barWidth)/2; 151 | 152 | return width; 153 | } 154 | 155 | function isBarAtLeftOfCenter(position){ 156 | return position <= Math.ceil(nbOfBarsToOrder / 2); 157 | } 158 | 159 | function sumWidth(series,start,end){ 160 | var totalWidth = 0; 161 | 162 | for(var i = start; i <= end; i++){ 163 | totalWidth += series[i].bars.barWidth+borderWidthInXabsWidth*2; 164 | } 165 | 166 | return totalWidth; 167 | } 168 | 169 | function shiftPoints(datapoints,serie,dx){ 170 | var ps = datapoints.pointsize; 171 | var points = datapoints.points; 172 | var j = 0; 173 | for(var i = isHorizontal ? 1 : 0;i < points.length; i += ps){ 174 | points[i] += dx; 175 | //Adding the new x value in the serie to be abble to display the right tooltip value, 176 | //using the index 3 to not overide the third index. 177 | serie.data[j][3] = points[i]; 178 | j++; 179 | } 180 | 181 | return points; 182 | } 183 | 184 | plot.hooks.processDatapoints.push(reOrderBars); 185 | 186 | } 187 | 188 | var options = { 189 | series : { 190 | bars: {order: null} // or number/string 191 | } 192 | }; 193 | 194 | $.plot.plugins.push({ 195 | init: init, 196 | options: options, 197 | name: "orderBars", 198 | version: "0.2" 199 | }); 200 | 201 | })(jQuery); -------------------------------------------------------------------------------- /test/public/assets/js/charts/flot/jquery.flot.resize.js: -------------------------------------------------------------------------------- 1 | /* Flot plugin for automatically redrawing plots as the placeholder resizes. 2 | 3 | Copyright (c) 2007-2013 IOLA and Ole Laursen. 4 | Licensed under the MIT license. 5 | 6 | It works by listening for changes on the placeholder div (through the jQuery 7 | resize event plugin) - if the size changes, it will redraw the plot. 8 | 9 | There are no options. If you need to disable the plugin for some plots, you 10 | can just fix the size of their placeholders. 11 | 12 | */ 13 | 14 | /* Inline dependency: 15 | * jQuery resize event - v1.1 - 3/14/2010 16 | * http://benalman.com/projects/jquery-resize-plugin/ 17 | * 18 | * Copyright (c) 2010 "Cowboy" Ben Alman 19 | * Dual licensed under the MIT and GPL licenses. 20 | * http://benalman.com/about/license/ 21 | */ 22 | 23 | (function($,t,n){function p(){for(var n=r.length-1;n>=0;n--){var o=$(r[n]);if(o[0]==t||o.is(":visible")){var h=o.width(),d=o.height(),v=o.data(a);!v||h===v.w&&d===v.h?i[f]=i[l]:(i[f]=i[c],o.trigger(u,[v.w=h,v.h=d]))}else v=o.data(a),v.w=0,v.h=0}s!==null&&(s=t.requestAnimationFrame(p))}var r=[],i=$.resize=$.extend($.resize,{}),s,o="setTimeout",u="resize",a=u+"-special-event",f="delay",l="pendingDelay",c="activeDelay",h="throttleWindow";i[l]=250,i[c]=20,i[f]=i[l],i[h]=!0,$.event.special[u]={setup:function(){if(!i[h]&&this[o])return!1;var t=$(this);r.push(this),t.data(a,{w:t.width(),h:t.height()}),r.length===1&&(s=n,p())},teardown:function(){if(!i[h]&&this[o])return!1;var t=$(this);for(var n=r.length-1;n>=0;n--)if(r[n]==this){r.splice(n,1);break}t.removeData(a),r.length||(cancelAnimationFrame(s),s=null)},add:function(t){function s(t,i,s){var o=$(this),u=o.data(a);u.w=i!==n?i:o.width(),u.h=s!==n?s:o.height(),r.apply(this,arguments)}if(!i[h]&&this[o])return!1;var r;if($.isFunction(t))return r=t,s;r=t.handler,t.handler=s}},t.requestAnimationFrame||(t.requestAnimationFrame=function(){return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||t.msRequestAnimationFrame||function(e,n){return t.setTimeout(e,i[f])}}()),t.cancelAnimationFrame||(t.cancelAnimationFrame=function(){return t.webkitCancelRequestAnimationFrame||t.mozCancelRequestAnimationFrame||t.oCancelRequestAnimationFrame||t.msCancelRequestAnimationFrame||clearTimeout}())})(jQuery,this); 24 | 25 | (function ($) { 26 | var options = { }; // no options 27 | 28 | function init(plot) { 29 | function onResize() { 30 | var placeholder = plot.getPlaceholder(); 31 | 32 | // somebody might have hidden us and we can't plot 33 | // when we don't have the dimensions 34 | if (placeholder.width() == 0 || placeholder.height() == 0) 35 | return; 36 | 37 | plot.resize(); 38 | plot.setupGrid(); 39 | plot.draw(); 40 | } 41 | 42 | function bindEvents(plot, eventHolder) { 43 | plot.getPlaceholder().resize(onResize); 44 | } 45 | 46 | function shutdown(plot, eventHolder) { 47 | plot.getPlaceholder().unbind("resize", onResize); 48 | } 49 | 50 | plot.hooks.bindEvents.push(bindEvents); 51 | plot.hooks.shutdown.push(shutdown); 52 | } 53 | 54 | $.plot.plugins.push({ 55 | init: init, 56 | options: options, 57 | name: 'resize', 58 | version: '1.0' 59 | }); 60 | })(jQuery); 61 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/flot/jquery.flot.stack.js: -------------------------------------------------------------------------------- 1 | /* Flot plugin for stacking data sets rather than overlyaing them. 2 | 3 | Copyright (c) 2007-2013 IOLA and Ole Laursen. 4 | Licensed under the MIT license. 5 | 6 | The plugin assumes the data is sorted on x (or y if stacking horizontally). 7 | For line charts, it is assumed that if a line has an undefined gap (from a 8 | null point), then the line above it should have the same gap - insert zeros 9 | instead of "null" if you want another behaviour. This also holds for the start 10 | and end of the chart. Note that stacking a mix of positive and negative values 11 | in most instances doesn't make sense (so it looks weird). 12 | 13 | Two or more series are stacked when their "stack" attribute is set to the same 14 | key (which can be any number or string or just "true"). To specify the default 15 | stack, you can set the stack option like this: 16 | 17 | series: { 18 | stack: null/false, true, or a key (number/string) 19 | } 20 | 21 | You can also specify it for a single series, like this: 22 | 23 | $.plot( $("#placeholder"), [{ 24 | data: [ ... ], 25 | stack: true 26 | }]) 27 | 28 | The stacking order is determined by the order of the data series in the array 29 | (later series end up on top of the previous). 30 | 31 | Internally, the plugin modifies the datapoints in each series, adding an 32 | offset to the y value. For line series, extra data points are inserted through 33 | interpolation. If there's a second y value, it's also adjusted (e.g for bar 34 | charts or filled areas). 35 | 36 | */ 37 | 38 | (function ($) { 39 | var options = { 40 | series: { stack: null } // or number/string 41 | }; 42 | 43 | function init(plot) { 44 | function findMatchingSeries(s, allseries) { 45 | var res = null; 46 | for (var i = 0; i < allseries.length; ++i) { 47 | if (s == allseries[i]) 48 | break; 49 | 50 | if (allseries[i].stack == s.stack) 51 | res = allseries[i]; 52 | } 53 | 54 | return res; 55 | } 56 | 57 | function stackData(plot, s, datapoints) { 58 | if (s.stack == null || s.stack === false) 59 | return; 60 | 61 | var other = findMatchingSeries(s, plot.getData()); 62 | if (!other) 63 | return; 64 | 65 | var ps = datapoints.pointsize, 66 | points = datapoints.points, 67 | otherps = other.datapoints.pointsize, 68 | otherpoints = other.datapoints.points, 69 | newpoints = [], 70 | px, py, intery, qx, qy, bottom, 71 | withlines = s.lines.show, 72 | horizontal = s.bars.horizontal, 73 | withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y), 74 | withsteps = withlines && s.lines.steps, 75 | fromgap = true, 76 | keyOffset = horizontal ? 1 : 0, 77 | accumulateOffset = horizontal ? 0 : 1, 78 | i = 0, j = 0, l, m; 79 | 80 | while (true) { 81 | if (i >= points.length) 82 | break; 83 | 84 | l = newpoints.length; 85 | 86 | if (points[i] == null) { 87 | // copy gaps 88 | for (m = 0; m < ps; ++m) 89 | newpoints.push(points[i + m]); 90 | i += ps; 91 | } 92 | else if (j >= otherpoints.length) { 93 | // for lines, we can't use the rest of the points 94 | if (!withlines) { 95 | for (m = 0; m < ps; ++m) 96 | newpoints.push(points[i + m]); 97 | } 98 | i += ps; 99 | } 100 | else if (otherpoints[j] == null) { 101 | // oops, got a gap 102 | for (m = 0; m < ps; ++m) 103 | newpoints.push(null); 104 | fromgap = true; 105 | j += otherps; 106 | } 107 | else { 108 | // cases where we actually got two points 109 | px = points[i + keyOffset]; 110 | py = points[i + accumulateOffset]; 111 | qx = otherpoints[j + keyOffset]; 112 | qy = otherpoints[j + accumulateOffset]; 113 | bottom = 0; 114 | 115 | if (px == qx) { 116 | for (m = 0; m < ps; ++m) 117 | newpoints.push(points[i + m]); 118 | 119 | newpoints[l + accumulateOffset] += qy; 120 | bottom = qy; 121 | 122 | i += ps; 123 | j += otherps; 124 | } 125 | else if (px > qx) { 126 | // we got past point below, might need to 127 | // insert interpolated extra point 128 | if (withlines && i > 0 && points[i - ps] != null) { 129 | intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); 130 | newpoints.push(qx); 131 | newpoints.push(intery + qy); 132 | for (m = 2; m < ps; ++m) 133 | newpoints.push(points[i + m]); 134 | bottom = qy; 135 | } 136 | 137 | j += otherps; 138 | } 139 | else { // px < qx 140 | if (fromgap && withlines) { 141 | // if we come from a gap, we just skip this point 142 | i += ps; 143 | continue; 144 | } 145 | 146 | for (m = 0; m < ps; ++m) 147 | newpoints.push(points[i + m]); 148 | 149 | // we might be able to interpolate a point below, 150 | // this can give us a better y 151 | if (withlines && j > 0 && otherpoints[j - otherps] != null) 152 | bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx); 153 | 154 | newpoints[l + accumulateOffset] += bottom; 155 | 156 | i += ps; 157 | } 158 | 159 | fromgap = false; 160 | 161 | if (l != newpoints.length && withbottom) 162 | newpoints[l + 2] += bottom; 163 | } 164 | 165 | // maintain the line steps invariant 166 | if (withsteps && l != newpoints.length && l > 0 167 | && newpoints[l] != null 168 | && newpoints[l] != newpoints[l - ps] 169 | && newpoints[l + 1] != newpoints[l - ps + 1]) { 170 | for (m = 0; m < ps; ++m) 171 | newpoints[l + ps + m] = newpoints[l + m]; 172 | newpoints[l + 1] = newpoints[l - ps + 1]; 173 | } 174 | } 175 | 176 | datapoints.points = newpoints; 177 | } 178 | 179 | plot.hooks.processDatapoints.push(stackData); 180 | } 181 | 182 | $.plot.plugins.push({ 183 | init: init, 184 | options: options, 185 | name: 'stack', 186 | version: '1.2' 187 | }); 188 | })(jQuery); 189 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/flot/jquery.flot.tooltip.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jquery.flot.tooltip 3 | * 4 | * desc: create tooltip with values of hovered point on the graph, 5 | support many series, time mode, stacking and pie charts 6 | you can set custom tip content (also with use of HTML tags) and precision of values 7 | * version: 0.4.4 8 | * author: Krzysztof Urbas @krzysu [myviews.pl] with help of @ismyrnow 9 | * website: https://github.com/krzysu/flot.tooltip 10 | * 11 | * released under MIT License, 2012 12 | */ 13 | 14 | (function ($) { 15 | var options = { 16 | tooltip: false, //boolean 17 | tooltipOpts: { 18 | content: "%s | X: %x | Y: %y.2", //%s -> series label, %x -> X value, %y -> Y value, %x.2 -> precision of X value, %p -> percent 19 | dateFormat: "%y-%0m-%0d", 20 | shifts: { 21 | x: 10, 22 | y: 20 23 | }, 24 | defaultTheme: true 25 | } 26 | }; 27 | 28 | var init = function (plot) { 29 | 30 | var tipPosition = { x: 0, y: 0 }; 31 | var opts = plot.getOptions(); 32 | 33 | var updateTooltipPosition = function (pos) { 34 | tipPosition.x = pos.x; 35 | tipPosition.y = pos.y; 36 | }; 37 | 38 | var onMouseMove = function (e) { 39 | 40 | var pos = { x: 0, y: 0 }; 41 | 42 | pos.x = e.pageX; 43 | pos.y = e.pageY; 44 | 45 | updateTooltipPosition(pos); 46 | }; 47 | 48 | var timestampToDate = function (tmst) { 49 | 50 | var theDate = new Date(tmst); 51 | 52 | return $.plot.formatDate(theDate, opts.tooltipOpts.dateFormat); 53 | }; 54 | 55 | plot.hooks.bindEvents.push(function (plot, eventHolder) { 56 | 57 | var to = opts.tooltipOpts; 58 | var placeholder = plot.getPlaceholder(); 59 | var $tip; 60 | 61 | if (opts.tooltip === false) return; 62 | 63 | if ($('#flotTip').length > 0) { 64 | $tip = $('#flotTip'); 65 | } 66 | else { 67 | $tip = $('
').attr('id', 'flotTip'); 68 | $tip.appendTo('body').hide().css({ position: 'absolute' }); 69 | 70 | if (to.defaultTheme) { 71 | $tip.css({ 72 | 'background': '#fff', 73 | 'z-index': '100', 74 | 'padding': '0.4em 0.6em', 75 | 'border-radius': '0.5em', 76 | 'font-size': '0.8em', 77 | 'border': '1px solid #111' 78 | }); 79 | } 80 | } 81 | 82 | $(placeholder).bind("plothover", function (event, pos, item) { 83 | if (item) { 84 | var tipText; 85 | 86 | if (opts.xaxis.mode === "time" || opts.xaxes[0].mode === "time") { 87 | tipText = stringFormat(to.content, item, timestampToDate); 88 | } 89 | else { 90 | tipText = stringFormat(to.content, item); 91 | } 92 | 93 | $tip.html(tipText).css({ left: tipPosition.x + to.shifts.x, top: tipPosition.y + to.shifts.y }).show(); 94 | } 95 | else { 96 | $tip.hide().html(''); 97 | } 98 | }); 99 | 100 | eventHolder.mousemove(onMouseMove); 101 | }); 102 | 103 | var stringFormat = function (content, item, fnct) { 104 | 105 | var percentPattern = /%p\.{0,1}(\d{0,})/; 106 | var seriesPattern = /%s/; 107 | var xPattern = /%x\.{0,1}(\d{0,})/; 108 | var yPattern = /%y\.{0,1}(\d{0,})/; 109 | 110 | //percent match 111 | if (typeof (item.series.percent) !== 'undefined') { 112 | content = adjustValPrecision(percentPattern, content, item.series.percent); 113 | } 114 | //series match 115 | if (typeof (item.series.label) !== 'undefined') { 116 | content = content.replace(seriesPattern, item.series.label); 117 | } 118 | // xVal match 119 | if (typeof (fnct) === 'function') { 120 | content = content.replace(xPattern, fnct(item.series.data[item.dataIndex][0])); 121 | } 122 | else if (typeof item.series.data[item.dataIndex][0] === 'number') { 123 | content = adjustValPrecision(xPattern, content, item.series.data[item.dataIndex][0]); 124 | } 125 | // yVal match 126 | if (typeof item.series.data[item.dataIndex][1] === 'number') { 127 | content = adjustValPrecision(yPattern, content, item.series.data[item.dataIndex][1]); 128 | } 129 | 130 | return content; 131 | }; 132 | 133 | var adjustValPrecision = function (pattern, content, value) { 134 | 135 | var precision; 136 | if (content.match(pattern) !== 'null') { 137 | if (RegExp.$1 !== '') { 138 | precision = RegExp.$1; 139 | value = value.toFixed(precision) 140 | } 141 | content = content.replace(pattern, value); 142 | } 143 | 144 | return content; 145 | }; 146 | } 147 | 148 | $.plot.plugins.push({ 149 | init: init, 150 | options: options, 151 | name: 'tooltip', 152 | version: '0.4.4' 153 | }); 154 | })(jQuery); 155 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/morris/morris-init.js: -------------------------------------------------------------------------------- 1 | var gridbordercolor = "#eee"; 2 | 3 | var tax_data = [ 4 | { "period": "2011 Q3", "licensed": 3407, "sorned": 660 }, 5 | { "period": "2011 Q2", "licensed": 3351, "sorned": 629 }, 6 | { "period": "2011 Q1", "licensed": 3269, "sorned": 618 }, 7 | { "period": "2010 Q4", "licensed": 3246, "sorned": 661 }, 8 | { "period": "2009 Q4", "licensed": 3171, "sorned": 676 }, 9 | { "period": "2008 Q4", "licensed": 3155, "sorned": 681 }, 10 | { "period": "2007 Q4", "licensed": 3226, "sorned": 620 }, 11 | { "period": "2006 Q4", "licensed": 3245, "sorned": null }, 12 | { "period": "2005 Q4", "licensed": 3289, "sorned": null } 13 | ]; 14 | 15 | var InitiateAreaChart = function () { 16 | return { 17 | init: function () { 18 | Morris.Area({ 19 | element: 'area-chart', 20 | data: [ 21 | { period: '2010 Q1', iphone: 2666, ipad: null, itouch: 2647 }, 22 | { period: '2010 Q2', iphone: 2778, ipad: 2294, itouch: 2441 }, 23 | { period: '2010 Q3', iphone: 4912, ipad: 1969, itouch: 2501 }, 24 | { period: '2010 Q4', iphone: 3767, ipad: 3597, itouch: 5689 }, 25 | { period: '2011 Q1', iphone: 6810, ipad: 1914, itouch: 2293 }, 26 | { period: '2011 Q2', iphone: 5670, ipad: 4293, itouch: 1881 }, 27 | { period: '2011 Q3', iphone: 4820, ipad: 3795, itouch: 1588 }, 28 | { period: '2011 Q4', iphone: 15073, ipad: 5967, itouch: 5175 }, 29 | { period: '2012 Q1', iphone: 10687, ipad: 4460, itouch: 2028 }, 30 | { period: '2012 Q2', iphone: 8432, ipad: 5713, itouch: 1791 } 31 | ], 32 | xkey: 'period', 33 | ykeys: ['iphone', 'ipad', 'itouch'], 34 | labels: ['iPhone', 'iPad', 'iPod Touch'], 35 | pointSize: 2, 36 | hideHover: 'auto', 37 | lineColors: [themethirdcolor, themesecondary, themeprimary] 38 | }); 39 | } 40 | }; 41 | }(); 42 | 43 | var InitiateBarChart = function () { 44 | return { 45 | init: function () { 46 | Morris.Bar({ 47 | element: 'bar-chart', 48 | data: [ 49 | { y: '2006', a: 100, b: 90, c:80 }, 50 | { y: '2007', a: 75, b: 65 , c:25}, 51 | { y: '2008', a: 50, b: 40 , c:90}, 52 | { y: '2009', a: 75, b: 65 , c:15}, 53 | { y: '2010', a: 50, b: 40 , c:50}, 54 | { y: '2011', a: 75, b: 65 ,c:10}, 55 | { y: '2012', a: 100, b: 90 ,c:90} 56 | ], 57 | xkey: 'y', 58 | ykeys: ['a', 'b', 'c'], 59 | labels: ['Series A', 'Series B', 'Series C'], 60 | hideHover: 'auto', 61 | barColors: [themeprimary, themesecondary, themethirdcolor] 62 | }); 63 | } 64 | }; 65 | }(); 66 | 67 | var InitiateLineChart = function () { 68 | return { 69 | init: function () { 70 | Morris.Line({ 71 | element: 'line-chart', 72 | data: tax_data, 73 | xkey: 'period', 74 | ykeys: ['licensed', 'sorned'], 75 | labels: ['Licensed', 'Off the road'], 76 | lineColors: [themeprimary, themethirdcolor] 77 | }); 78 | 79 | } 80 | }; 81 | }(); 82 | 83 | var InitiateLineChart2 = function () { 84 | return { 85 | init: function () { 86 | Morris.Line({ 87 | element: 'line-chart-2', 88 | data: [ 89 | { y: '2006', a: 100, b: 90 }, 90 | { y: '2007', a: 75, b: 65 }, 91 | { y: '2008', a: 50, b: 40 }, 92 | { y: '2009', a: 75, b: 65 }, 93 | { y: '2010', a: 50, b: 40 }, 94 | { y: '2011', a: 75, b: 65 }, 95 | { y: '2012', a: 100, b: 90 } 96 | ], 97 | xkey: 'y', 98 | ykeys: ['a', 'b'], 99 | labels: ['Series A', 'Series B'], 100 | lineColors: [themeprimary, themethirdcolor] 101 | }); 102 | 103 | } 104 | }; 105 | }(); 106 | 107 | var InitiateDonutChart = function () { 108 | return { 109 | init: function () { 110 | Morris.Donut({ 111 | element: 'donut-chart', 112 | data: [ 113 | { label: 'IOS', value: 40 , }, 114 | { label: 'Win', value: 30 }, 115 | { label: 'Android', value: 25 }, 116 | { label: 'Java', value: 5 } 117 | ], 118 | colors: [themeprimary, themesecondary, themethirdcolor, themefourthcolor], 119 | formatter: function (y) { return y + "%" } 120 | }); 121 | } 122 | }; 123 | }(); 124 | -------------------------------------------------------------------------------- /test/public/assets/js/charts/sparkline/sparkline-init.js: -------------------------------------------------------------------------------- 1 | var gridbordercolor = "#eee"; 2 | 3 | 4 | var InitiateSparklineCharts = function () { 5 | return { 6 | init: function () { 7 | 8 | /*Bar*/ 9 | var sparklinebars = $('[data-sparkline=bar]'); 10 | $.each(sparklinebars, function () { 11 | $(this).sparkline('html', { 12 | type: 'bar', 13 | disableHiddenCheck: true, 14 | height: $(this).data('height'), 15 | width: $(this).data('width'), 16 | barColor: getcolor($(this).data('barcolor')), 17 | negBarColor: getcolor($(this).data('negbarcolor')), 18 | zeroColor: getcolor($(this).data('zerocolor')), 19 | barWidth: $(this).data('barwidth'), 20 | barSpacing: $(this).data('barspacing'), 21 | stackedBarColor: $(this).data('stackedbarcolor') 22 | }); 23 | }); 24 | 25 | /*Line*/ 26 | var sparklinelines = $('[data-sparkline=line]'); 27 | $.each(sparklinelines, function () { 28 | $(this).sparkline('html', { 29 | type: 'line', 30 | disableHiddenCheck: true, 31 | height: $(this).data('height'), 32 | width: $(this).data('width'), 33 | fillColor: getcolor($(this).data('fillcolor')), 34 | lineColor: getcolor($(this).data('linecolor')), 35 | spotRadius: $(this).data('spotradius'), 36 | lineWidth: $(this).data('linewidth'), 37 | spotColor: getcolor($(this).data('spotcolor')), 38 | minSpotColor: getcolor($(this).data('minspotcolor')), 39 | maxSpotColor: getcolor($(this).data('maxspotcolor')), 40 | highlightSpotColor: getcolor($(this).data('highlightspotcolor')), 41 | highlightLineColor: getcolor($(this).data('highlightlinecolor')) 42 | }); 43 | }); 44 | /*Composite Line*/ 45 | var sparklinecompositelines = $('[data-sparkline=compositeline]'); 46 | $.each(sparklinecompositelines, function () { 47 | $(this).sparkline('html', { 48 | type: 'line', 49 | disableHiddenCheck: true, 50 | height: $(this).data('height'), 51 | width: $(this).data('width'), 52 | lineColor: getcolor($(this).data('linecolor')), 53 | fillColor: getcolor($(this).data('fillcolor')), 54 | spotRadius: $(this).data('spotradius'), 55 | lineWidth: $(this).data('linewidth'), 56 | spotColor: getcolor($(this).data('spotcolor')), 57 | minSpotColor: getcolor($(this).data('minspotcolor')), 58 | maxSpotColor: getcolor($(this).data('maxspotcolor')), 59 | highlightSpotColor: getcolor($(this).data('highlightspotcolor')), 60 | highlightLineColor: getcolor($(this).data('highlightlinecolor')) 61 | }); 62 | $(this).sparkline(stringtoarray($(this).attr("data-composite")), { 63 | type: 'line', 64 | disableHiddenCheck: true, 65 | height: $(this).data('height'), 66 | width: $(this).data('width'), 67 | lineColor: getcolor($(this).data('secondlinecolor')), 68 | fillColor: getcolor($(this).data('secondfillcolor')), 69 | lineWidth: $(this).data('secondlinewidth'), 70 | spotRadius: $(this).data('spotradius'), 71 | spotColor: getcolor($(this).data('spotcolor')), 72 | minSpotColor: getcolor($(this).data('minspotcolor')), 73 | maxSpotColor: getcolor($(this).data('maxspotcolor')), 74 | highlightSpotColor: getcolor($(this).data('highlightspotcolor')), 75 | highlightLineColor: getcolor($(this).data('highlightlinecolor')), 76 | composite: true 77 | }); 78 | }); 79 | 80 | /*Composite Bar*/ 81 | var sparklinecompositebars = $('[data-sparkline=compositebar]'); 82 | $.each(sparklinecompositebars, function () { 83 | $(this).sparkline('html', { 84 | type: 'bar', 85 | disableHiddenCheck: true, 86 | height: $(this).data('height'), 87 | width: $(this).data('width'), 88 | barColor: getcolor($(this).data('barcolor')), 89 | negBarColor: getcolor($(this).data('negbarcolor')), 90 | zeroColor: getcolor($(this).data('zerocolor')), 91 | barWidth: $(this).data('barwidth'), 92 | barSpacing: $(this).data('barspacing'), 93 | stackedBarColor: getcolor($(this).data('stackedbarcolor')) 94 | }); 95 | $(this).sparkline(stringtoarray($(this).attr("data-composite")), { 96 | type: 'line', 97 | height: $(this).data('height'), 98 | disableHiddenCheck: true, 99 | width: $(this).data('width'), 100 | lineColor: getcolor($(this).data('linecolor')), 101 | fillColor: getcolor($(this).data('fillcolor')), 102 | spotRadius: $(this).data('spotradius'), 103 | lineWidth: $(this).data('linewidth'), 104 | spotRadius: $(this).data('spotradius'), 105 | spotColor: getcolor($(this).data('spotcolor')), 106 | minSpotColor: getcolor($(this).data('minspotcolor')), 107 | maxSpotColor: getcolor($(this).data('maxspotcolor')), 108 | highlightSpotColor: getcolor($(this).data('highlightspotcolor')), 109 | highlightLineColor: getcolor($(this).data('highlightlinecolor')), 110 | composite: true 111 | }); 112 | 113 | }); 114 | 115 | /*Tristate*/ 116 | var sparklinetristates = $('[data-sparkline=tristate]'); 117 | $.each(sparklinetristates, function () { 118 | $(this).sparkline('html', { 119 | type: 'tristate', 120 | disableHiddenCheck: true, 121 | height: $(this).data('height'), 122 | width: $(this).data('width'), 123 | posBarColor: getcolor($(this).data('posbarcolor')), 124 | negBarColor: getcolor($(this).data('negbarcolor')), 125 | zeroBarColor: getcolor($(this).data('zerobarcolor')), 126 | barWidth: $(this).data('barwidth'), 127 | barSpacing: $(this).data('barspacing'), 128 | zeroAxis: $(this).data('zeroaxis') 129 | }); 130 | }); 131 | 132 | /*Descrete*/ 133 | var sparklinediscretes = $('[data-sparkline=discrete]'); 134 | $.each(sparklinediscretes, function () { 135 | $(this).sparkline('html', { 136 | type: 'discrete', 137 | disableHiddenCheck: true, 138 | lineHeight: $(this).data('lineheight'), 139 | lineColor: getcolor($(this).data('linecolor')), 140 | thresholdValue: $(this).data('thresholdvalue'), 141 | thresholdColor: $(this).data('thresholdcolor') 142 | }); 143 | }); 144 | 145 | /*Bullet*/ 146 | var sparklinebullets = $('[data-sparkline=bullet]'); 147 | $.each(sparklinebullets, function () { 148 | $(this).sparkline('html', { 149 | type: 'bullet', 150 | disableHiddenCheck: true, 151 | targetColor: $(this).data('targetcolor'), 152 | performanceColor: $(this).data('performancecolor'), 153 | rangeColors: $(this).data('rangecolors') 154 | }); 155 | }); 156 | 157 | /*Box Plot*/ 158 | var sparklinebox = $('[data-sparkline=box]'); 159 | $.each(sparklinebox, function () { 160 | $(this).sparkline('html', { 161 | type: 'box', 162 | disableHiddenCheck: true, 163 | }); 164 | }); 165 | 166 | /*Pie*/ 167 | var sparklinepie = $('[data-sparkline=pie]'); 168 | $.each(sparklinepie, function () { 169 | $(this).sparkline('html', { 170 | type: 'pie', 171 | disableHiddenCheck: true, 172 | width: $(this).data('width'), 173 | height: $(this).data('height'), 174 | sliceColors: $(this).data('slicecolors'), 175 | borderColor: getcolor($(this).data('bordercolor')) 176 | }); 177 | }); 178 | 179 | 180 | } 181 | }; 182 | }(); 183 | 184 | function stringtoarray(str) { 185 | var myArray = str.split(","); 186 | for (var i = 0; i < myArray.length; i++) { 187 | myArray[i] = +myArray[i]; 188 | } 189 | for (var i = 0; i < myArray.length; i++) { 190 | myArray[i] = parseInt(myArray[i], 10); 191 | } 192 | return myArray; 193 | } 194 | 195 | -------------------------------------------------------------------------------- /test/public/assets/js/datatable/assets/swf/copy_csv_xls_pdf.swf: -------------------------------------------------------------------------------- 1 | 2 | 404 Not Found 3 | 4 |

404 Not Found

5 |
    6 |
  • Code: NoSuchKey
  • 7 |
  • Message: The specified key does not exist.
  • 8 |
  • Key: assets/js/datatable/assets/swf/copy_csv_xls_pdf.swf
  • 9 |
  • RequestId: A23A7738AF6C3194
  • 10 |
  • HostId: 3uTw2i05sOiHisnP3J4yNS48sFNVIAjJf6WmEMO606Rkvp2HML6R6m5QontOi8Ov
  • 11 |
12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /test/public/assets/js/datatable/dataTables.bootstrap.min.js: -------------------------------------------------------------------------------- 1 | $.extend(!0,$.fn.dataTable.defaults,{sDom:"<'row'<'col-xs-6'l><'col-xs-6'f>r>t<'row'<'col-xs-6'i><'col-xs-6'p>>",sPaginationType:"bootstrap",oLanguage:{sLengthMenu:"_MENU_ records per page"}});$.extend($.fn.dataTableExt.oStdClasses,{sWrapper:"dataTables_wrapper form-inline",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm"});$.fn.dataTableExt.oApi.fnPagingInfo=function(n){return{iStart:n._iDisplayStart,iEnd:n.fnDisplayEnd(),iLength:n._iDisplayLength,iTotal:n.fnRecordsTotal(),iFilteredTotal:n.fnRecordsDisplay(),iPage:n._iDisplayLength===-1?0:Math.ceil(n._iDisplayStart/n._iDisplayLength),iTotalPages:n._iDisplayLength===-1?0:Math.ceil(n.fnRecordsDisplay()/n._iDisplayLength)}};$.extend($.fn.dataTableExt.oPagination,{bootstrap:{fnInit:function(n,t,i){var u=n.oLanguage.oPaginate,f=function(t){t.preventDefault();n.oApi._fnPageChange(n,t.data.action)&&i(n)},r;$(t).append('