├── .gitignore
├── README.md
├── about.php
├── activetriggers.php
├── class_zabbix.php
├── config-core.php
├── config-demo.php
├── config.inc.php
├── cookies.php
├── css
├── bootstrap-responsive.css
├── bootstrap-responsive.min.css
├── bootstrap.css
└── bootstrap.min.css
├── dot.htaccess
├── feedback.php
├── functions.php
├── graph.php
├── graph_img.php
├── host.php
├── hostgroups.php
├── hostitems.php
├── hosts.php
├── images
└── hosts.png
├── img
├── glyphicons-halflings-white.png
└── glyphicons-halflings.png
├── index.php
├── js
├── bootstrap.js
└── bootstrap.min.js
├── logout.php
├── template
├── footer.php
└── header.php
├── trigger_ack.php
└── trigger_info.php
/.gitignore:
--------------------------------------------------------------------------------
1 | # Don't track the config.php, that's custom for each user
2 | config.php
3 |
4 | # Just in case you have custom .htaccess files
5 | .htaccess
6 |
7 | # Don't track phpstorm configs
8 | .idea
9 |
10 | # The debuglog for JSON
11 | json.log
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction: Mobile Zabbix
2 |
3 | This project is intended as an extra application, built on top of your current [Zabbix](http://www.zabbix.com) set-up.
4 |
5 | It connects to your Zabbix API URL, using your Zabbix credentials. Afterwards, all settings are pulled from your Zabbix.
6 | This means any change you make in your Zabbix, will be transported to the Mobile ZBX application.
7 |
8 | If you're worried about security implications, please read more on the FAQ at http://www.mozbx.net.
9 |
10 | For more install guides (on your phone, or on your own servers), please see http://www.mozbx.net/install.html.
11 |
12 | ### About the configuration file
13 |
14 | There's a file called "config-core.php" included. Copy that to "config.php" and modify it as you see fit. That file is unique to you, and won't change with future updates.
15 |
16 | ### Installation instructions
17 |
18 | If you have a working webserver with PHP support, it's as easy as cloning the repository and browsing to the URL. By default, no special configs are needed.
19 | You can edit the config.php (a copy of config-core.php) to substitute some variables that suite your own environment.
20 |
21 | ### About the author
22 |
23 | - Built by [Mattias Geniar](http://mattiasgeniar.be) (twitter: [@mattiasgeniar](https://twitter.com/#!/mattiasgeniar) )
24 | - Submit your issues using [the Github issue tracker](https://github.com/mattiasgeniar/MoZBX/issues)
25 |
--------------------------------------------------------------------------------
/about.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
13 | $zabbix->setPassword($zabbixPass);
14 | $zabbix->setZabbixApiUrl($zabbixApi);
15 |
16 | // Login
17 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
18 | // Try it with the authentication hash we have
19 | $zabbix->setAuthToken($zabbixAuthHash);
20 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
21 | // Or try it with our info from the cookies
22 | $zabbix->login();
23 | }
24 |
25 | if (!$zabbix->isLoggedIn()) {
26 | header("Location: index.php");
27 | exit();
28 | }
29 |
30 | require_once("template/header.php");
31 |
32 | if ($zabbix->isLoggedIn()) {
33 | // Retrieve the data in one go
34 | $zabbix_auth = $zabbix->getAuthToken();
35 | $zabbix_version = $zabbix->getVersion();
36 | }
37 | ?>
38 |
39 |
40 |
41 |
42 |
43 | Home /
44 |
45 |
46 | About
47 |
48 |
49 |
50 |
51 |
52 |
53 |
Mobile Zabbix
54 |
55 | Mobile Zabbix version
56 | In development by Mattias Geniar
57 |
58 |
59 |
Changelog: version 0.5
60 |
61 | Improved Zabbix 2.0 compatibility
62 | Introduced entirely new layout (based on Twitter Bootstrap)
63 | Fix #33: SSL tracker image
64 | Fix #32: Home button not working
65 | Fix #31: Windows CRLF
66 | Fix #30: API URL: detect trailing slashes
67 | Fix #29: Automatically determine Zabbix Version (1.8/2.0)
68 | Fix #28: Active Triggers empty on Zabbix 2.0
69 |
70 |
71 |
Changelog: version 0.4
72 |
73 | Changes for Zabbix 2.0 compatibility introduced
74 | Updated jqTouch, using Zepto instead of jqTouch
75 | Performance: default to not showing host-counts per hostgroup
76 |
77 |
78 |
Zabbix Server info
79 |
80 | Zabbix API version on the server.
81 | Retrieved data from .
82 | You are logged in as getUsername()?> .
83 | Your current session-id is getAuthToken()?>
84 |
85 |
86 |
89 |
--------------------------------------------------------------------------------
/activetriggers.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
13 | $zabbix->setPassword($zabbixPass);
14 | $zabbix->setZabbixApiUrl($zabbixApi);
15 |
16 | // Login
17 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
18 | // Try it with the authentication hash we have
19 | $zabbix->setAuthToken($zabbixAuthHash);
20 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
21 | // Or try it with our info from the cookies
22 | $zabbix->login();
23 | }
24 |
25 | if (!$zabbix->isLoggedIn()) {
26 | header("Location: index.php");
27 | exit();
28 | }
29 |
30 | require_once("template/header.php");
31 |
32 | // Get all active triggers (for the counter on homepage);
33 | $triggersActive = $zabbix->getTriggersActive($arrSettings["minimalSeverity"]);
34 | if (!is_array($triggersActive))
35 | $triggersActive = array();
36 | ?>
37 |
38 |
39 |
40 |
41 | Home /
42 |
43 |
44 | Active Triggers
45 |
46 |
47 |
48 |
49 |
50 |
51 | 0) {
53 | // First, group our active triggers per host
54 | $arrSortedTriggers = array();
55 |
56 | foreach ($triggersActive as $triggerActive) {
57 | if (array_key_exists("hosts", $triggerActive) && array_key_exists(0, $triggerActive["hosts"])) {
58 | $arrSortedTriggers[$triggerActive["hosts"][0]->hostid]["host"] = $triggerActive["hosts"][0]->host;
59 | $arrSortedTriggers[$triggerActive["hosts"][0]->hostid]["triggers"][] =
60 | array(
61 | "description" => $triggerActive["description"],
62 | "comments" => $triggerActive["comments"],
63 | "lastchange" => $triggerActive["lastchange"],
64 | "priority" => $triggerActive["priority"],
65 | "triggerid" => $triggerActive["triggerid"],
66 | );
67 | }
68 | }
69 |
70 | asort($arrSortedTriggers);
71 | ?>
72 |
96 |
99 |
100 |
101 | There don't seem to be any active triggers.
102 |
103 |
104 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/class_zabbix.php:
--------------------------------------------------------------------------------
1 | true,
34 | /*CURLOPT_HEADER => true, */
35 | CURLOPT_TIMEOUT => 30,
36 | CURLOPT_CONNECTTIMEOUT => 5,
37 | CURLOPT_SSL_VERIFYHOST => false,
38 | CURLOPT_SSL_VERIFYPEER => false,
39 | CURLOPT_FOLLOWLOCATION => true,
40 | CURLOPT_FRESH_CONNECT => true
41 | );
42 | private $json_debug = null;
43 | private $curl_verbose = false;
44 | private $zabbix_tmp_cookies = "";
45 | private $zabbix_url_graph = "";
46 | private $zabbix_url_index = "";
47 | private $http_auth = false;
48 |
49 | /* ##########################################################
50 | ##
51 | ##
52 | ## VARIABLES: generic
53 | ##
54 | ##
55 | ############################################################*/
56 |
57 | private $auth_token = null;
58 | private $last_error_message = "";
59 | private $last_error_data = "";
60 | private $last_error_code = "";
61 |
62 | /* ##########################################################
63 | ##
64 | ##
65 | ## Construct
66 | ##
67 | ##
68 | ############################################################*/
69 |
70 | public function __construct($arrSettings)
71 | {
72 | $this->zabbix_url = $arrSettings["zabbixApiUrl"] . "api_jsonrpc.php";
73 | $this->zabbix_hostname = $arrSettings["zabbixHostname"];
74 | $this->zabbix_username = $arrSettings["zabbixUsername"];
75 | $this->zabbix_password = $arrSettings["zabbixPassword"];
76 | $this->zabbix_hostname = $arrSettings["zabbixHostname"];
77 | $this->zabbix_tmp_cookies = $arrSettings["pathCookiesStorage"];
78 | $this->zabbix_url_graph = $arrSettings["zabbixApiUrl"] . "chart2.php";
79 | $this->zabbix_url_index = $arrSettings["zabbixApiUrl"] . "index.php";
80 | $this->json_debug = $arrSettings["jsonDebug"];
81 | $this->json_debug_path = $arrSettings["jsonDebug_path"];
82 | $this->curl_verbose = $arrSettings["curlVerbose"];
83 | $this->http_auth = $arrSettings["useHttpAuth"];
84 | }
85 |
86 |
87 | /* ##########################################################
88 | ##
89 | ##
90 | ## METHODS: public interface for accessing data
91 | ##
92 | ##
93 | ############################################################*/
94 |
95 | public function getAuthToken()
96 | {
97 | return $this->auth_token;
98 | }
99 |
100 | public function setAuthToken($data)
101 | {
102 | $this->auth_token = $data;
103 | }
104 |
105 | public function getZabbixApiUrl()
106 | {
107 | return $this->zabbix_url;
108 | }
109 |
110 | public function setZabbixApiUrl($data)
111 | {
112 | $this->zabbix_url = $data;
113 |
114 | /* Check if the zabbix_url even contains valid data or not */
115 | if (strpos($this->zabbix_url, 'api_jsonrpc.php') === false) {
116 | /* The specific PHP page for the API is not in the zabbix_url, add it ourselves */
117 | if ($this->zabbix_url[strlen($this->zabbix_url) - 1] == "/")
118 | $this->zabbix_url .= "api_jsonrpc.php";
119 | else
120 | $this->zabbix_url .= "/api_jsonrpc.php";
121 | }
122 | }
123 |
124 | public function getUsername()
125 | {
126 | return $this->zabbix_username;
127 | }
128 |
129 | public function setUsername($data)
130 | {
131 | $this->zabbix_username = $data;
132 | }
133 |
134 | public function getPassword()
135 | {
136 | return $this->zabbix_password;
137 | }
138 |
139 | public function setPassword($data)
140 | {
141 | $this->zabbix_password = $data;
142 | }
143 |
144 | public function setLastError($code, $message, $data)
145 | {
146 | $this->last_error_code = $code;
147 | $this->last_error_data = $data;
148 | $this->last_error_message = $message;
149 | }
150 |
151 | public function getLastError()
152 | {
153 | return array("code" => $this->last_error_code,
154 | "data" => $this->last_error_data,
155 | "message" => $this->last_error_message,
156 | );
157 | }
158 |
159 | public function Login()
160 | {
161 | $result = $this->sendRequest("user.authenticate", array("user" => $this->getUsername(), "password" => $this->getPassword()));
162 |
163 | //$result = $this->decodeJson($json_login);
164 | if (isset($result->result))
165 | $this->auth_token = $result->result;
166 | }
167 |
168 | public function isLoggedIn()
169 | {
170 | return (bool)$this->auth_token;
171 | }
172 |
173 | public function getVersion()
174 | {
175 | // Retrieve Zabbix Version
176 | if (!isset($zabbix_version) || strlen($zabbix_version) == 0) {
177 | $result = $this->sendRequest("apiinfo.version");
178 | if (isset($result->result))
179 | $this->zabbix_version = $result->result;
180 | else
181 | $this->zabbix_version = 'unknown';
182 | }
183 |
184 | return $this->zabbix_version;
185 | }
186 |
187 | public function getHostgroups()
188 | {
189 | // Retrieve all hostgroups for which you have access
190 | $result = $this->sendRequest("hostgroup.get", array("output" => "extend"));
191 | //$result = $this->decodeJson($json_hostgroups);
192 |
193 | if (isset($result->result)) {
194 | $group_objects = $result->result;
195 | if (is_array($group_objects) && count($group_objects) > 0) {
196 | $arrGroups = array();
197 | foreach ($group_objects as $object) {
198 | $arrGroups[] = array("groupid" => $object->groupid,
199 | "name" => $object->name,
200 | "internal" => $object->internal
201 | );
202 | }
203 |
204 | return $arrGroups;
205 | } else {
206 | return false;
207 | }
208 | } else {
209 | return false;
210 | }
211 | }
212 |
213 | public function getHostgroupById($hostgroupid)
214 | {
215 | $result = $this->sendRequest("hostgroup.get",
216 | array("output" => "extend",
217 | "groupids" => array($hostgroupid)
218 | )
219 | );
220 | if (isset($result->result)) {
221 | $hostgroup_objects = $result->result;
222 |
223 | if (array_key_exists(0, $hostgroup_objects))
224 | return $hostgroup_objects[0];
225 | else
226 | return false;
227 | } else {
228 | return false;
229 | }
230 | }
231 |
232 | public function getHostsByGroupId($groupid)
233 | {
234 | $result = $this->sendRequest("host.get",
235 | array(
236 | "output" => "extend",
237 | "groupids" => array($groupid)
238 | )
239 | );
240 |
241 | if (isset($result->result)) {
242 | $host_objects = $result->result;
243 |
244 | if (is_array($host_objects) && count($host_objects) > 0) {
245 | $arrHosts = array();
246 | foreach ($host_objects as $object) {
247 | $arrHosts[$object->hostid] =
248 | array(
249 | "hostid" => $object->hostid,
250 | "host" => $object->host,
251 | "dns" => @isset($object->dns) ? $object->dns : '',
252 | "ip" => @isset($object->ip) ? $object->ip : '',
253 | "useip" => @isset($object->useip) ? $object->useip : '',
254 | "status" => $object->status, /* Enabled or not */
255 | "available" => $object->available,
256 | "disable_until" => $object->disable_until,
257 | "error" => $object->error,
258 |
259 | );
260 | }
261 | return $arrHosts;
262 | } else {
263 | return false;
264 | }
265 | } else {
266 | return false;
267 | }
268 | }
269 |
270 | public function getHostById($hostid)
271 | {
272 | if (in_array(substr($this->getVersion(), 0, 3), array('2.2', '2.0', '1.4'))) {
273 | /* Zabbix 2.x compatible: API version 2.0 or 1.4 */
274 | $result = $this->sendRequest("host.get",
275 | array(
276 | "output" => "extend",
277 | "hostids" => array($hostid),
278 | "selectInterfaces" => "extend",
279 | )
280 | );
281 | } else {
282 | /* Zabbix 1.8 compatible */
283 | $result = $this->sendRequest("host.get",
284 | array(
285 | "output" => "extend",
286 | "hostids" => array($hostid),
287 | )
288 | );
289 | }
290 |
291 | if (isset($result->result)) {
292 | $host_object = $result->result;
293 |
294 | if (array_key_exists(0, $host_object))
295 | return $host_object[0];
296 | else
297 | return false;
298 | }
299 | }
300 |
301 | public function getTriggersByHostId($hostid)
302 | {
303 | $result = $this->sendRequest("trigger.get",
304 | array("hostids" => array($hostid),
305 | "output" => "extend",
306 | /*"only_true" => 1,*/
307 | /*"monitored" => 1*/
308 | )
309 | );
310 |
311 | if (isset($result->result)) {
312 | $trigger_objects = $result->result;
313 |
314 | if (is_array($trigger_objects) && count($trigger_objects) > 0) {
315 | $arrTriggers = array();
316 | foreach ($trigger_objects as $object) {
317 | $arrTriggers[$object->triggerid] = $this->convertTriggerJson($object);
318 | }
319 | return $arrTriggers;
320 | } else {
321 | return false;
322 | }
323 | }
324 | }
325 |
326 | public function getTriggersActive($minimalSeverity)
327 | {
328 | if (in_array(substr($this->getVersion(), 0, 3), array('2.2', '2.0', '1.4'))) {
329 | /* API version 1.4 = zabbix 2.0+ */
330 | $selectHosts = "selectHosts";
331 | } else {
332 | $selectHosts = "select_hosts";
333 | }
334 |
335 | $result = $this->sendRequest("trigger.get",
336 | array(
337 | "monitored" => 1, /* Checks trigger, item and host status (all need to be active/enabled) */
338 | "output" => "extend",
339 | $selectHosts => "extend",
340 | "min_severity" => $minimalSeverity,
341 | "filter" => array(
342 | "value" => 1, /* Filter by trigger state: 1 = problem */
343 | ),
344 | "expandDescription" => 1, /* Expand macros in the description. Triggers with macros don't get listed at all, if not enabled. */
345 | "withLastEventUnacknowledged" => 1, /* Only the unacknowledged triggers */
346 | )
347 | );
348 |
349 | if (isset($result->result)) {
350 | $trigger_objects = $result->result;
351 |
352 | if (is_array($trigger_objects) && count($trigger_objects) > 0) {
353 | $arrTriggers = array();
354 | foreach ($trigger_objects as $object) {
355 | $arrTriggers[$object->triggerid] = $this->convertTriggerJson($object);
356 | }
357 | return $arrTriggers;
358 | } else {
359 | return false;
360 | }
361 | }
362 | }
363 |
364 | public function getTriggerByTriggerAndHostId($triggerid, $hostid)
365 | {
366 | $result = $this->sendRequest("trigger.get",
367 | array("output" => "extend",
368 | "triggerids" => array($triggerid),
369 | "hostids" => array($hostid),
370 | "expandDescription" => 1, /* expand macros in the description */
371 | )
372 | );
373 |
374 | if (isset($result->result)) {
375 | $trigger_objects = $result->result;
376 |
377 | if (is_array($trigger_objects) && count($trigger_objects) == 1) {
378 | return $this->convertTriggerJson($trigger_objects[0]);
379 | } else {
380 | return false;
381 | }
382 | }
383 | }
384 |
385 | private function convertTriggerJson($object)
386 | {
387 | $arrTrigger = array("triggerid" => $object->triggerid,
388 | "expression" => $object->expression,
389 | "description" => $object->description,
390 | "url" => $object->url,
391 | "status" => $object->status,
392 | "value" => $object->value,
393 | "priority" => $object->priority,
394 | "lastchange" => $object->lastchange,
395 | "dep_level" => @isset($object->dep_level) ? $object->dep_level : '',
396 | "comments" => $object->comments,
397 | "error" => $object->error,
398 | "templateid" => $object->templateid,
399 | "type" => $object->type,
400 | );
401 | if (isset($object->hosts))
402 | $arrTrigger["hosts"] = $object->hosts;
403 |
404 | return $arrTrigger;
405 | }
406 |
407 | public function getEventsByTriggerAndHostId($triggerid, $hostid)
408 | {
409 | $result = $this->sendRequest("event.get",
410 | array("triggerids" => $triggerid,
411 | "hostids" => $hostid,
412 | "limit" => 10,
413 | "output" => "extend",
414 | "sortfield" => "clock",
415 | "sortorder" => "DESC")
416 | );
417 |
418 | if (isset($result->result)) {
419 | $event_objects = $result->result;
420 |
421 | if (is_array($event_objects) && count($event_objects) > 0) {
422 | $arrEvents = array();
423 | foreach ($event_objects as $event) {
424 | $arrEvents[] = $event;
425 | }
426 | return $arrEvents;
427 | } else {
428 | return false;
429 | }
430 | }
431 | }
432 |
433 | public function acknowledgeEvent($eventid, $comment)
434 | {
435 | $result = $this->sendRequest("event.acknowledge",
436 | array("eventids" => $eventid,
437 | "message" => $comment)
438 | );
439 | return true;
440 | }
441 |
442 |
443 | public function getGraphsByHostId($hostid)
444 | {
445 | $result = $this->sendRequest("graph.get",
446 | array("hostids" => array($hostid),
447 | "output" => "extend",
448 | /*"only_true" => 1,*/
449 | /*"monitored" => 1*/
450 | )
451 | );
452 | if (isset($result->result)) {
453 | $graph_objects = $result->result;
454 |
455 | if (is_array($graph_objects) && count($graph_objects) > 0) {
456 | $arrGraphs = array();
457 | foreach ($graph_objects as $object) {
458 | $arrGraphs[$object->graphid] =
459 | array("graphid" => $object->graphid,
460 | "name" => $object->name,
461 | "width" => $object->width,
462 | "height" => $object->height,
463 | "yaxismin" => $object->yaxismin,
464 | "yaxismax" => $object->yaxismax,
465 | "graphtype" => $object->graphtype,
466 | "show_legend" => $object->show_legend,
467 | "show_3d" => $object->show_3d,
468 | );
469 | }
470 | return $arrGraphs;
471 | } else {
472 | return false;
473 | }
474 | } else {
475 | return false;
476 | }
477 | }
478 |
479 | public function getGraphById($graphid)
480 | {
481 | $result = $this->sendRequest("graph.get",
482 | array("output" => "extend",
483 | "graphids" => array($graphid)
484 | )
485 | );
486 |
487 | if (isset($result->result)) {
488 | $graph_object = $result->result;
489 |
490 | if (array_key_exists(0, $graph_object))
491 | return $graph_object[0];
492 | else
493 | return false;
494 | } else {
495 | return false;
496 | }
497 |
498 | }
499 |
500 | public function getGraphImageById($graphid, $period = 3600)
501 | {
502 | global $arrSettings;
503 |
504 | // Cookiename
505 | $filename_cookie = $this->zabbix_tmp_cookies . "zabbix_cookie_" . $graphid . ".txt";
506 |
507 | $ch = curl_init();
508 | // Add the URL of Zabbix to perform the login to
509 | curl_setopt($ch, CURLOPT_URL, $this->zabbix_url_index);
510 | // Get the value returned from our curl-call, don't default to stdout
511 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
512 | // Send a POST request
513 | curl_setopt($ch, CURLOPT_POST, true);
514 | // Increase verbosity for debugging
515 | curl_setopt($ch, CURLOPT_VERBOSE, $this->curl_verbose);
516 | // Don't validate SSL certs as must Zabbix installs that have an SSL connection are self-signed
517 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
518 | // Lighttpd expects this header
519 | curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
520 |
521 | if (in_array(substr($this->getVersion(), 0, 3), array('2.2', '2.0', '1.4'))) {
522 | /* API Version 1.4 = Zabbix 2.0+ */
523 | $post_data = array(
524 | 'name' => $this->getUsername(),
525 | 'password' => $this->getPassword(),
526 | 'autologin' => 1,
527 | 'request' => '', /* Why is this empty? Zabbix requires it? */
528 | 'enter' => 'Sign in', /* Zabbix also checks the value of this string ... */
529 | );
530 | } else {
531 | $post_data = array(
532 | 'name' => $this->getUsername(),
533 | 'password' => $this->getPassword(),
534 | 'enter' => 'Enter',
535 | );
536 | }
537 | // Add the POST-data
538 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
539 | curl_setopt($ch, CURLOPT_COOKIEJAR, $filename_cookie);
540 | curl_setopt($ch, CURLOPT_COOKIEFILE, $filename_cookie);
541 |
542 | if ($this->http_auth) {
543 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
544 | curl_setopt($ch, CURLOPT_USERPWD, $this->zabbix_username . ':' . $this->zabbix_password);
545 | }
546 |
547 | // Login
548 | curl_exec($ch);
549 |
550 | // To debug this call, comment out the Header-set in graph_img.php on line 32
551 | // that way, you'll just return plain text data and no image
552 | //curl_close($ch);
553 |
554 | // Fetch image
555 | // &period= the time, in seconds, of the graph (so: value of 7200 = a 2 hour graph to be shown)
556 | // &stime= the time, in PHP's time() format, from when the graph should begin
557 | // &width= the width of the graph, small enough to fit on mobile devices
558 | curl_setopt($ch, CURLOPT_URL, $this->zabbix_url_graph . "?graphid=" . $graphid . "&width=450&period=" . $period);
559 | $output = curl_exec($ch);
560 |
561 | // Close session
562 | curl_close($ch);
563 |
564 | // Delete our cookie
565 | unlink($filename_cookie);
566 |
567 | // Return the image
568 | return $output;
569 | }
570 |
571 |
572 | /* ##########################################################
573 | ##
574 | ##
575 | ## "Data conversion", make Zabbix Output readable
576 | ##
577 | ##
578 | ############################################################*/
579 |
580 | public function getTriggerSeverity($priority)
581 | {
582 | switch ($priority) {
583 | case 5:
584 | return "Disaster";
585 | break;
586 | case 4:
587 | return "High";
588 | break;
589 | case 3:
590 | return "Average";
591 | break;
592 | case 2:
593 | return "Warning";
594 | break;
595 | case 1:
596 | return "Information";
597 | break;
598 | default:
599 | return "Not classified";
600 | }
601 | }
602 |
603 | public function getAvailability($available)
604 | {
605 | switch ($available) {
606 | case 2:
607 | return "Zabbix Agent offline";
608 | break;
609 | case 1:
610 | return "Zabbix Agent online";
611 | break;
612 | case 0:
613 | return "Zabbix Agent not needed";
614 | break;
615 | default:
616 | return "unknown";
617 | break;
618 | }
619 | }
620 |
621 | public function shortTriggerDisplay($arrSeverity)
622 | {
623 | $arrOutput = array();
624 | asort($arrSeverity);
625 |
626 | foreach ($arrSeverity as $priority => $count) {
627 | if ($count > 0) {
628 | // This is worth mentioning
629 | $arrOutput[] = "" . $count . " " . $this->getTriggerSeverity($priority);
630 | }
631 | }
632 |
633 | if (count($arrOutput) > 0)
634 | return ": " . implode(", ", $arrOutput);
635 | else
636 | return false;
637 | }
638 |
639 | public function sortHostgroupsByName($arrHostgroups)
640 | {
641 | if (is_array($arrHostgroups))
642 | uasort($arrHostgroups, "arrSortFunctionHostgroupsName");
643 |
644 | return $arrHostgroups;
645 | }
646 |
647 | public function sortHostsByName($arrHosts)
648 | {
649 | if (is_array($arrHosts))
650 | uasort($arrHosts, "arrSortFunctionHostsName");
651 | return $arrHosts;
652 | }
653 |
654 | public function sortGraphsByName($arrGraphs)
655 | {
656 | if (is_array($arrGraphs))
657 | uasort($arrGraphs, "arrSortFunctionHostgroupsName");
658 | return $arrGraphs;
659 | }
660 |
661 | public function filterActiveHosts($arrHosts)
662 | {
663 | // Input: array of hosts
664 | // Output: only the active hosts
665 | $arrActiveHosts = array();
666 |
667 | if (is_array($arrHosts) && count($arrHosts) > 0) {
668 | foreach ($arrHosts as $host) {
669 | if (array_key_exists("status", $host) && $host["status"] == 0)
670 | $arrActiveHosts[] = $host;
671 | }
672 |
673 | return $arrActiveHosts;
674 | } else
675 | return false;
676 | }
677 |
678 |
679 | /* ##########################################################
680 | ##
681 | ##
682 | ## The "core" functions
683 | ## - Send JSON requests to the API
684 | ## - Retrieving & Parsing JSON requests
685 | ##
686 | ##
687 | ############################################################*/
688 |
689 | public function sendRequest($action, $parameters = '')
690 | {
691 | $curl_init = curl_init($this->zabbix_url);
692 |
693 | // Get our "config" variables
694 | $curl_opts = $this->zabbix_curl_options;
695 | $json_headers = $this->zabbix_json_headers;
696 |
697 | // Build our encoded JSON
698 | $json_data = $this->genericJSONPost($action, $parameters);
699 |
700 | if ($this->http_auth) {
701 | $curl_opts[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
702 | $curl_opts[CURLOPT_USERPWD] = $this->zabbix_username . ':' . $this->zabbix_password;
703 | }
704 |
705 | $curl_opts[CURLOPT_VERBOSE] = $this->curl_verbose;
706 | $curl_opts[CURLOPT_HTTPHEADER] = $json_headers;
707 | $curl_opts[CURLOPT_CUSTOMREQUEST] = "POST";
708 | $curl_opts[CURLOPT_POSTFIELDS] = is_array($json_data) ? http_build_query($json_data) : $json_data;
709 |
710 | curl_setopt_array($curl_init, $curl_opts);
711 | $ret = curl_exec($curl_init);
712 | $http_status = curl_getinfo($curl_init, CURLINFO_HTTP_CODE);
713 | curl_close($curl_init);
714 |
715 | if ($this->json_debug) {
716 | // output to the screen
717 | /*echo "Json Answer ";
718 | echo "";
719 | echo var_dump($ret, true);
720 | echo " ";*/
721 |
722 | // log it
723 | $handle = fopen($this->json_debug_path . "json.log", "a");
724 | fwrite($handle, "\n======= " . date("Y/m/d, H:i:s") . " =======\n");
725 | fwrite($handle, "Source IP: " . getVisitorIP() . "\n");
726 | fwrite($handle, "API URL: " . $this->zabbix_url . "\n");
727 | fwrite($handle, "Action: " . $action . "\n");
728 | fwrite($handle, "Request: \n");
729 | fwrite($handle, var_export($json_data, true));
730 | fwrite($handle, "\n\n");
731 | fwrite($handle, "Response: \n");
732 | fwrite($handle, var_export($ret, true));
733 | fwrite($handle, "\n=======\n");
734 | fclose($handle);
735 | }
736 |
737 | // Make the output "readable"
738 | $result = $this->decodeJson($ret);
739 |
740 | if (isset($result->error)) {
741 | $this->setLastError($result->error->code, $result->error->message, $result->error->data);
742 | return false;
743 | } else if ($http_status != 200) {
744 | switch ($http_status) {
745 | case 401:
746 | $this->setLastError($http_status, 'Unable to authenticate with server.', 'Unable to authenticate with server.');
747 | break;
748 | default:
749 | $this->setLastError($http_status, 'Unhandled error code: '.$http_status, 'Unhandled error code: '.$http_status);
750 | }
751 | } else {
752 | return $result;
753 | }
754 | }
755 |
756 | private function genericJSONPost($action, $parameters = '')
757 | {
758 | $json_request = array(
759 | 'auth' => $this->auth_token,
760 | 'method' => $action,
761 | 'id' => 1,
762 | 'params' => is_array($parameters) ? $parameters : array(),
763 | 'jsonrpc' => '2.0'
764 | );
765 |
766 | return json_encode($json_request);
767 | }
768 |
769 | private function decodeJson($json)
770 | {
771 | $decoded = json_decode($json);
772 | return $decoded;
773 | }
774 | }
775 |
776 | ?>
777 |
--------------------------------------------------------------------------------
/config-core.php:
--------------------------------------------------------------------------------
1 | =
83 |
84 | /* Google Analytics */
85 | $arrSettings["googleAnalytics"] = "";
98 | ?>
99 |
--------------------------------------------------------------------------------
/config-demo.php:
--------------------------------------------------------------------------------
1 | =
76 |
77 | /* Styling for the textfields? */
78 | //$arrSettings["cssStyleTextfield"] = "border: 1px solid gray; padding: 3px 0px 3px 0px; color: white; "; // For JQT theme
79 | $arrSettings["cssStyleTextfield"] = "border: 1px solid gray; padding: 3px 0px 3px 0px; color: black; "; // For APPLE theme
80 |
81 | /* Styling for the (submit) buttons? */
82 | $arrSettings["cssStyleButton"] = "border-width: 0 12px; display: block; padding 10px; text-align: center; font-size: 20px;";
83 |
84 | /* What theme should we use for the app? Options: jqt || apple */
85 | $arrSettings["appTheme"] = "apple";
86 |
87 | /* What color should our statusbar be? This should match our theme (jqt = black, apple = white) */
88 | $arrSettings["appStatusbarColor"] = "white";
89 |
90 | /* Google Analytics */
91 | $arrSettings["googleAnalytics"] ="";
104 | ?>
--------------------------------------------------------------------------------
/config.inc.php:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/cookies.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/css/bootstrap-responsive.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.0.4
3 | *
4 | * Copyright 2012 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | */
10 |
11 | .clearfix {
12 | *zoom: 1;
13 | }
14 |
15 | .clearfix:before,
16 | .clearfix:after {
17 | display: table;
18 | content: "";
19 | }
20 |
21 | .clearfix:after {
22 | clear: both;
23 | }
24 |
25 | .hide-text {
26 | font: 0/0 a;
27 | color: transparent;
28 | text-shadow: none;
29 | background-color: transparent;
30 | border: 0;
31 | }
32 |
33 | .input-block-level {
34 | display: block;
35 | width: 100%;
36 | min-height: 28px;
37 | -webkit-box-sizing: border-box;
38 | -moz-box-sizing: border-box;
39 | -ms-box-sizing: border-box;
40 | box-sizing: border-box;
41 | }
42 |
43 | .hidden {
44 | display: none;
45 | visibility: hidden;
46 | }
47 |
48 | .visible-phone {
49 | display: none !important;
50 | }
51 |
52 | .visible-tablet {
53 | display: none !important;
54 | }
55 |
56 | .hidden-desktop {
57 | display: none !important;
58 | }
59 |
60 | @media (max-width: 767px) {
61 | .visible-phone {
62 | display: inherit !important;
63 | }
64 | .hidden-phone {
65 | display: none !important;
66 | }
67 | .hidden-desktop {
68 | display: inherit !important;
69 | }
70 | .visible-desktop {
71 | display: none !important;
72 | }
73 | }
74 |
75 | @media (min-width: 768px) and (max-width: 979px) {
76 | .visible-tablet {
77 | display: inherit !important;
78 | }
79 | .hidden-tablet {
80 | display: none !important;
81 | }
82 | .hidden-desktop {
83 | display: inherit !important;
84 | }
85 | .visible-desktop {
86 | display: none !important ;
87 | }
88 | }
89 |
90 | @media (max-width: 480px) {
91 | .nav-collapse {
92 | -webkit-transform: translate3d(0, 0, 0);
93 | }
94 | .page-header h1 small {
95 | display: block;
96 | line-height: 18px;
97 | }
98 | input[type="checkbox"],
99 | input[type="radio"] {
100 | border: 1px solid #ccc;
101 | }
102 | .form-horizontal .control-group > label {
103 | float: none;
104 | width: auto;
105 | padding-top: 0;
106 | text-align: left;
107 | }
108 | .form-horizontal .controls {
109 | margin-left: 0;
110 | }
111 | .form-horizontal .control-list {
112 | padding-top: 0;
113 | }
114 | .form-horizontal .form-actions {
115 | padding-right: 10px;
116 | padding-left: 10px;
117 | }
118 | .modal {
119 | position: absolute;
120 | top: 10px;
121 | right: 10px;
122 | left: 10px;
123 | width: auto;
124 | margin: 0;
125 | }
126 | .modal.fade.in {
127 | top: auto;
128 | }
129 | .modal-header .close {
130 | padding: 10px;
131 | margin: -10px;
132 | }
133 | .carousel-caption {
134 | position: static;
135 | }
136 | }
137 |
138 | @media (max-width: 767px) {
139 | body {
140 | padding-right: 20px;
141 | padding-left: 20px;
142 | }
143 | .navbar-fixed-top,
144 | .navbar-fixed-bottom {
145 | margin-right: -20px;
146 | margin-left: -20px;
147 | }
148 | .container-fluid {
149 | padding: 0;
150 | }
151 | .dl-horizontal dt {
152 | float: none;
153 | width: auto;
154 | clear: none;
155 | text-align: left;
156 | }
157 | .dl-horizontal dd {
158 | margin-left: 0;
159 | }
160 | .container {
161 | width: auto;
162 | }
163 | .row-fluid {
164 | width: 100%;
165 | }
166 | .row,
167 | .thumbnails {
168 | margin-left: 0;
169 | }
170 | [class*="span"],
171 | .row-fluid [class*="span"] {
172 | display: block;
173 | float: none;
174 | width: auto;
175 | margin-left: 0;
176 | }
177 | .input-large,
178 | .input-xlarge,
179 | .input-xxlarge,
180 | input[class*="span"],
181 | select[class*="span"],
182 | textarea[class*="span"],
183 | .uneditable-input {
184 | display: block;
185 | width: 100%;
186 | min-height: 28px;
187 | -webkit-box-sizing: border-box;
188 | -moz-box-sizing: border-box;
189 | -ms-box-sizing: border-box;
190 | box-sizing: border-box;
191 | }
192 | .input-prepend input,
193 | .input-append input,
194 | .input-prepend input[class*="span"],
195 | .input-append input[class*="span"] {
196 | display: inline-block;
197 | width: auto;
198 | }
199 | }
200 |
201 | @media (min-width: 768px) and (max-width: 979px) {
202 | .row {
203 | margin-left: -20px;
204 | *zoom: 1;
205 | }
206 | .row:before,
207 | .row:after {
208 | display: table;
209 | content: "";
210 | }
211 | .row:after {
212 | clear: both;
213 | }
214 | [class*="span"] {
215 | float: left;
216 | margin-left: 20px;
217 | }
218 | .container,
219 | .navbar-fixed-top .container,
220 | .navbar-fixed-bottom .container {
221 | width: 724px;
222 | }
223 | .span12 {
224 | width: 724px;
225 | }
226 | .span11 {
227 | width: 662px;
228 | }
229 | .span10 {
230 | width: 600px;
231 | }
232 | .span9 {
233 | width: 538px;
234 | }
235 | .span8 {
236 | width: 476px;
237 | }
238 | .span7 {
239 | width: 414px;
240 | }
241 | .span6 {
242 | width: 352px;
243 | }
244 | .span5 {
245 | width: 290px;
246 | }
247 | .span4 {
248 | width: 228px;
249 | }
250 | .span3 {
251 | width: 166px;
252 | }
253 | .span2 {
254 | width: 104px;
255 | }
256 | .span1 {
257 | width: 42px;
258 | }
259 | .offset12 {
260 | margin-left: 764px;
261 | }
262 | .offset11 {
263 | margin-left: 702px;
264 | }
265 | .offset10 {
266 | margin-left: 640px;
267 | }
268 | .offset9 {
269 | margin-left: 578px;
270 | }
271 | .offset8 {
272 | margin-left: 516px;
273 | }
274 | .offset7 {
275 | margin-left: 454px;
276 | }
277 | .offset6 {
278 | margin-left: 392px;
279 | }
280 | .offset5 {
281 | margin-left: 330px;
282 | }
283 | .offset4 {
284 | margin-left: 268px;
285 | }
286 | .offset3 {
287 | margin-left: 206px;
288 | }
289 | .offset2 {
290 | margin-left: 144px;
291 | }
292 | .offset1 {
293 | margin-left: 82px;
294 | }
295 | .row-fluid {
296 | width: 100%;
297 | *zoom: 1;
298 | }
299 | .row-fluid:before,
300 | .row-fluid:after {
301 | display: table;
302 | content: "";
303 | }
304 | .row-fluid:after {
305 | clear: both;
306 | }
307 | .row-fluid [class*="span"] {
308 | display: block;
309 | float: left;
310 | width: 100%;
311 | min-height: 28px;
312 | margin-left: 2.762430939%;
313 | *margin-left: 2.709239449638298%;
314 | -webkit-box-sizing: border-box;
315 | -moz-box-sizing: border-box;
316 | -ms-box-sizing: border-box;
317 | box-sizing: border-box;
318 | }
319 | .row-fluid [class*="span"]:first-child {
320 | margin-left: 0;
321 | }
322 | .row-fluid .span12 {
323 | width: 99.999999993%;
324 | *width: 99.9468085036383%;
325 | }
326 | .row-fluid .span11 {
327 | width: 91.436464082%;
328 | *width: 91.38327259263829%;
329 | }
330 | .row-fluid .span10 {
331 | width: 82.87292817100001%;
332 | *width: 82.8197366816383%;
333 | }
334 | .row-fluid .span9 {
335 | width: 74.30939226%;
336 | *width: 74.25620077063829%;
337 | }
338 | .row-fluid .span8 {
339 | width: 65.74585634900001%;
340 | *width: 65.6926648596383%;
341 | }
342 | .row-fluid .span7 {
343 | width: 57.182320438000005%;
344 | *width: 57.129128948638304%;
345 | }
346 | .row-fluid .span6 {
347 | width: 48.618784527%;
348 | *width: 48.5655930376383%;
349 | }
350 | .row-fluid .span5 {
351 | width: 40.055248616%;
352 | *width: 40.0020571266383%;
353 | }
354 | .row-fluid .span4 {
355 | width: 31.491712705%;
356 | *width: 31.4385212156383%;
357 | }
358 | .row-fluid .span3 {
359 | width: 22.928176794%;
360 | *width: 22.874985304638297%;
361 | }
362 | .row-fluid .span2 {
363 | width: 14.364640883%;
364 | *width: 14.311449393638298%;
365 | }
366 | .row-fluid .span1 {
367 | width: 5.801104972%;
368 | *width: 5.747913482638298%;
369 | }
370 | input,
371 | textarea,
372 | .uneditable-input {
373 | margin-left: 0;
374 | }
375 | input.span12,
376 | textarea.span12,
377 | .uneditable-input.span12 {
378 | width: 714px;
379 | }
380 | input.span11,
381 | textarea.span11,
382 | .uneditable-input.span11 {
383 | width: 652px;
384 | }
385 | input.span10,
386 | textarea.span10,
387 | .uneditable-input.span10 {
388 | width: 590px;
389 | }
390 | input.span9,
391 | textarea.span9,
392 | .uneditable-input.span9 {
393 | width: 528px;
394 | }
395 | input.span8,
396 | textarea.span8,
397 | .uneditable-input.span8 {
398 | width: 466px;
399 | }
400 | input.span7,
401 | textarea.span7,
402 | .uneditable-input.span7 {
403 | width: 404px;
404 | }
405 | input.span6,
406 | textarea.span6,
407 | .uneditable-input.span6 {
408 | width: 342px;
409 | }
410 | input.span5,
411 | textarea.span5,
412 | .uneditable-input.span5 {
413 | width: 280px;
414 | }
415 | input.span4,
416 | textarea.span4,
417 | .uneditable-input.span4 {
418 | width: 218px;
419 | }
420 | input.span3,
421 | textarea.span3,
422 | .uneditable-input.span3 {
423 | width: 156px;
424 | }
425 | input.span2,
426 | textarea.span2,
427 | .uneditable-input.span2 {
428 | width: 94px;
429 | }
430 | input.span1,
431 | textarea.span1,
432 | .uneditable-input.span1 {
433 | width: 32px;
434 | }
435 | }
436 |
437 | @media (min-width: 1200px) {
438 | .row {
439 | margin-left: -30px;
440 | *zoom: 1;
441 | }
442 | .row:before,
443 | .row:after {
444 | display: table;
445 | content: "";
446 | }
447 | .row:after {
448 | clear: both;
449 | }
450 | [class*="span"] {
451 | float: left;
452 | margin-left: 30px;
453 | }
454 | .container,
455 | .navbar-fixed-top .container,
456 | .navbar-fixed-bottom .container {
457 | width: 1170px;
458 | }
459 | .span12 {
460 | width: 1170px;
461 | }
462 | .span11 {
463 | width: 1070px;
464 | }
465 | .span10 {
466 | width: 970px;
467 | }
468 | .span9 {
469 | width: 870px;
470 | }
471 | .span8 {
472 | width: 770px;
473 | }
474 | .span7 {
475 | width: 670px;
476 | }
477 | .span6 {
478 | width: 570px;
479 | }
480 | .span5 {
481 | width: 470px;
482 | }
483 | .span4 {
484 | width: 370px;
485 | }
486 | .span3 {
487 | width: 270px;
488 | }
489 | .span2 {
490 | width: 170px;
491 | }
492 | .span1 {
493 | width: 70px;
494 | }
495 | .offset12 {
496 | margin-left: 1230px;
497 | }
498 | .offset11 {
499 | margin-left: 1130px;
500 | }
501 | .offset10 {
502 | margin-left: 1030px;
503 | }
504 | .offset9 {
505 | margin-left: 930px;
506 | }
507 | .offset8 {
508 | margin-left: 830px;
509 | }
510 | .offset7 {
511 | margin-left: 730px;
512 | }
513 | .offset6 {
514 | margin-left: 630px;
515 | }
516 | .offset5 {
517 | margin-left: 530px;
518 | }
519 | .offset4 {
520 | margin-left: 430px;
521 | }
522 | .offset3 {
523 | margin-left: 330px;
524 | }
525 | .offset2 {
526 | margin-left: 230px;
527 | }
528 | .offset1 {
529 | margin-left: 130px;
530 | }
531 | .row-fluid {
532 | width: 100%;
533 | *zoom: 1;
534 | }
535 | .row-fluid:before,
536 | .row-fluid:after {
537 | display: table;
538 | content: "";
539 | }
540 | .row-fluid:after {
541 | clear: both;
542 | }
543 | .row-fluid [class*="span"] {
544 | display: block;
545 | float: left;
546 | width: 100%;
547 | min-height: 28px;
548 | margin-left: 2.564102564%;
549 | *margin-left: 2.510911074638298%;
550 | -webkit-box-sizing: border-box;
551 | -moz-box-sizing: border-box;
552 | -ms-box-sizing: border-box;
553 | box-sizing: border-box;
554 | }
555 | .row-fluid [class*="span"]:first-child {
556 | margin-left: 0;
557 | }
558 | .row-fluid .span12 {
559 | width: 100%;
560 | *width: 99.94680851063829%;
561 | }
562 | .row-fluid .span11 {
563 | width: 91.45299145300001%;
564 | *width: 91.3997999636383%;
565 | }
566 | .row-fluid .span10 {
567 | width: 82.905982906%;
568 | *width: 82.8527914166383%;
569 | }
570 | .row-fluid .span9 {
571 | width: 74.358974359%;
572 | *width: 74.30578286963829%;
573 | }
574 | .row-fluid .span8 {
575 | width: 65.81196581200001%;
576 | *width: 65.7587743226383%;
577 | }
578 | .row-fluid .span7 {
579 | width: 57.264957265%;
580 | *width: 57.2117657756383%;
581 | }
582 | .row-fluid .span6 {
583 | width: 48.717948718%;
584 | *width: 48.6647572286383%;
585 | }
586 | .row-fluid .span5 {
587 | width: 40.170940171000005%;
588 | *width: 40.117748681638304%;
589 | }
590 | .row-fluid .span4 {
591 | width: 31.623931624%;
592 | *width: 31.5707401346383%;
593 | }
594 | .row-fluid .span3 {
595 | width: 23.076923077%;
596 | *width: 23.0237315876383%;
597 | }
598 | .row-fluid .span2 {
599 | width: 14.529914530000001%;
600 | *width: 14.4767230406383%;
601 | }
602 | .row-fluid .span1 {
603 | width: 5.982905983%;
604 | *width: 5.929714493638298%;
605 | }
606 | input,
607 | textarea,
608 | .uneditable-input {
609 | margin-left: 0;
610 | }
611 | input.span12,
612 | textarea.span12,
613 | .uneditable-input.span12 {
614 | width: 1160px;
615 | }
616 | input.span11,
617 | textarea.span11,
618 | .uneditable-input.span11 {
619 | width: 1060px;
620 | }
621 | input.span10,
622 | textarea.span10,
623 | .uneditable-input.span10 {
624 | width: 960px;
625 | }
626 | input.span9,
627 | textarea.span9,
628 | .uneditable-input.span9 {
629 | width: 860px;
630 | }
631 | input.span8,
632 | textarea.span8,
633 | .uneditable-input.span8 {
634 | width: 760px;
635 | }
636 | input.span7,
637 | textarea.span7,
638 | .uneditable-input.span7 {
639 | width: 660px;
640 | }
641 | input.span6,
642 | textarea.span6,
643 | .uneditable-input.span6 {
644 | width: 560px;
645 | }
646 | input.span5,
647 | textarea.span5,
648 | .uneditable-input.span5 {
649 | width: 460px;
650 | }
651 | input.span4,
652 | textarea.span4,
653 | .uneditable-input.span4 {
654 | width: 360px;
655 | }
656 | input.span3,
657 | textarea.span3,
658 | .uneditable-input.span3 {
659 | width: 260px;
660 | }
661 | input.span2,
662 | textarea.span2,
663 | .uneditable-input.span2 {
664 | width: 160px;
665 | }
666 | input.span1,
667 | textarea.span1,
668 | .uneditable-input.span1 {
669 | width: 60px;
670 | }
671 | .thumbnails {
672 | margin-left: -30px;
673 | }
674 | .thumbnails > li {
675 | margin-left: 30px;
676 | }
677 | .row-fluid .thumbnails {
678 | margin-left: 0;
679 | }
680 | }
681 |
682 | @media (max-width: 979px) {
683 | body {
684 | padding-top: 0;
685 | }
686 | .navbar-fixed-top,
687 | .navbar-fixed-bottom {
688 | position: static;
689 | }
690 | .navbar-fixed-top {
691 | margin-bottom: 18px;
692 | }
693 | .navbar-fixed-bottom {
694 | margin-top: 18px;
695 | }
696 | .navbar-fixed-top .navbar-inner,
697 | .navbar-fixed-bottom .navbar-inner {
698 | padding: 5px;
699 | }
700 | .navbar .container {
701 | width: auto;
702 | padding: 0;
703 | }
704 | .navbar .brand {
705 | padding-right: 10px;
706 | padding-left: 10px;
707 | margin: 0 0 0 -5px;
708 | }
709 | .nav-collapse {
710 | clear: both;
711 | }
712 | .nav-collapse .nav {
713 | float: none;
714 | margin: 0 0 9px;
715 | }
716 | .nav-collapse .nav > li {
717 | float: none;
718 | }
719 | .nav-collapse .nav > li > a {
720 | margin-bottom: 2px;
721 | }
722 | .nav-collapse .nav > .divider-vertical {
723 | display: none;
724 | }
725 | .nav-collapse .nav .nav-header {
726 | color: #999999;
727 | text-shadow: none;
728 | }
729 | .nav-collapse .nav > li > a,
730 | .nav-collapse .dropdown-menu a {
731 | padding: 6px 15px;
732 | font-weight: bold;
733 | color: #999999;
734 | -webkit-border-radius: 3px;
735 | -moz-border-radius: 3px;
736 | border-radius: 3px;
737 | }
738 | .nav-collapse .btn {
739 | padding: 4px 10px 4px;
740 | font-weight: normal;
741 | -webkit-border-radius: 4px;
742 | -moz-border-radius: 4px;
743 | border-radius: 4px;
744 | }
745 | .nav-collapse .dropdown-menu li + li a {
746 | margin-bottom: 2px;
747 | }
748 | .nav-collapse .nav > li > a:hover,
749 | .nav-collapse .dropdown-menu a:hover {
750 | background-color: #222222;
751 | }
752 | .nav-collapse.in .btn-group {
753 | padding: 0;
754 | margin-top: 5px;
755 | }
756 | .nav-collapse .dropdown-menu {
757 | position: static;
758 | top: auto;
759 | left: auto;
760 | display: block;
761 | float: none;
762 | max-width: none;
763 | padding: 0;
764 | margin: 0 15px;
765 | background-color: transparent;
766 | border: none;
767 | -webkit-border-radius: 0;
768 | -moz-border-radius: 0;
769 | border-radius: 0;
770 | -webkit-box-shadow: none;
771 | -moz-box-shadow: none;
772 | box-shadow: none;
773 | }
774 | .nav-collapse .dropdown-menu:before,
775 | .nav-collapse .dropdown-menu:after {
776 | display: none;
777 | }
778 | .nav-collapse .dropdown-menu .divider {
779 | display: none;
780 | }
781 | .nav-collapse .navbar-form,
782 | .nav-collapse .navbar-search {
783 | float: none;
784 | padding: 9px 15px;
785 | margin: 9px 0;
786 | border-top: 1px solid #222222;
787 | border-bottom: 1px solid #222222;
788 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
789 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
790 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
791 | }
792 | .navbar .nav-collapse .nav.pull-right {
793 | float: none;
794 | margin-left: 0;
795 | }
796 | .nav-collapse,
797 | .nav-collapse.collapse {
798 | height: 0;
799 | overflow: hidden;
800 | }
801 | .navbar .btn-navbar {
802 | display: block;
803 | }
804 | .navbar-static .navbar-inner {
805 | padding-right: 10px;
806 | padding-left: 10px;
807 | }
808 | }
809 |
810 | @media (min-width: 980px) {
811 | .nav-collapse.collapse {
812 | height: auto !important;
813 | overflow: visible !important;
814 | }
815 | }
816 |
--------------------------------------------------------------------------------
/css/bootstrap-responsive.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.0.4
3 | *
4 | * Copyright 2012 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}@media(max-width:767px){.visible-phone{display:inherit!important}.hidden-phone{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(min-width:768px) and (max-width:979px){.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:18px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{position:absolute;top:10px;right:10px;left:10px;width:auto;margin:0}.modal.fade.in{top:auto}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.762430939%;*margin-left:2.709239449638298%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:99.999999993%;*width:99.9468085036383%}.row-fluid .span11{width:91.436464082%;*width:91.38327259263829%}.row-fluid .span10{width:82.87292817100001%;*width:82.8197366816383%}.row-fluid .span9{width:74.30939226%;*width:74.25620077063829%}.row-fluid .span8{width:65.74585634900001%;*width:65.6926648596383%}.row-fluid .span7{width:57.182320438000005%;*width:57.129128948638304%}.row-fluid .span6{width:48.618784527%;*width:48.5655930376383%}.row-fluid .span5{width:40.055248616%;*width:40.0020571266383%}.row-fluid .span4{width:31.491712705%;*width:31.4385212156383%}.row-fluid .span3{width:22.928176794%;*width:22.874985304638297%}.row-fluid .span2{width:14.364640883%;*width:14.311449393638298%}.row-fluid .span1{width:5.801104972%;*width:5.747913482638298%}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:714px}input.span11,textarea.span11,.uneditable-input.span11{width:652px}input.span10,textarea.span10,.uneditable-input.span10{width:590px}input.span9,textarea.span9,.uneditable-input.span9{width:528px}input.span8,textarea.span8,.uneditable-input.span8{width:466px}input.span7,textarea.span7,.uneditable-input.span7{width:404px}input.span6,textarea.span6,.uneditable-input.span6{width:342px}input.span5,textarea.span5,.uneditable-input.span5{width:280px}input.span4,textarea.span4,.uneditable-input.span4{width:218px}input.span3,textarea.span3,.uneditable-input.span3{width:156px}input.span2,textarea.span2,.uneditable-input.span2{width:94px}input.span1,textarea.span1,.uneditable-input.span1{width:32px}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.564102564%;*margin-left:2.510911074638298%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145300001%;*width:91.3997999636383%}.row-fluid .span10{width:82.905982906%;*width:82.8527914166383%}.row-fluid .span9{width:74.358974359%;*width:74.30578286963829%}.row-fluid .span8{width:65.81196581200001%;*width:65.7587743226383%}.row-fluid .span7{width:57.264957265%;*width:57.2117657756383%}.row-fluid .span6{width:48.717948718%;*width:48.6647572286383%}.row-fluid .span5{width:40.170940171000005%;*width:40.117748681638304%}.row-fluid .span4{width:31.623931624%;*width:31.5707401346383%}.row-fluid .span3{width:23.076923077%;*width:23.0237315876383%}.row-fluid .span2{width:14.529914530000001%;*width:14.4767230406383%}.row-fluid .span1{width:5.982905983%;*width:5.929714493638298%}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:1160px}input.span11,textarea.span11,.uneditable-input.span11{width:1060px}input.span10,textarea.span10,.uneditable-input.span10{width:960px}input.span9,textarea.span9,.uneditable-input.span9{width:860px}input.span8,textarea.span8,.uneditable-input.span8{width:760px}input.span7,textarea.span7,.uneditable-input.span7{width:660px}input.span6,textarea.span6,.uneditable-input.span6{width:560px}input.span5,textarea.span5,.uneditable-input.span5{width:460px}input.span4,textarea.span4,.uneditable-input.span4{width:360px}input.span3,textarea.span3,.uneditable-input.span3{width:260px}input.span2,textarea.span2,.uneditable-input.span2{width:160px}input.span1,textarea.span1,.uneditable-input.span1{width:60px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:18px}.navbar-fixed-bottom{margin-top:18px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 9px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#999;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#222}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222;border-bottom:1px solid #222;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
10 |
--------------------------------------------------------------------------------
/dot.htaccess:
--------------------------------------------------------------------------------
1 | # A .htaccess file is a hidden file which runs on Unix servers
2 | # and provides directives. Renaming this file to .htaccess and
3 | # placing in your root directory _should_ enable GZip compression,
4 | # reducing the weight of pages/scripts being served.
5 |
6 |
7 | mod_gzip_on Yes
8 | mod_gzip_dechunk Yes
9 | mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
10 | mod_gzip_item_include handler ^cgi-script$
11 | mod_gzip_item_include mime ^text/.*
12 | mod_gzip_item_include mime ^application/x-javascript.*
13 | mod_gzip_item_exclude mime ^image/.*
14 | mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
15 |
16 |
17 |
18 | AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript
19 |
20 |
21 |
22 | ExpiresActive On
23 | ExpiresDefault "access plus 1 seconds"
24 | ExpiresByType text/html "access plus 1 seconds"
25 | ExpiresByType image/gif "access plus 2592000 seconds"
26 | ExpiresByType image/jpeg "access plus 2592000 seconds"
27 | ExpiresByType image/png "access plus 2592000 seconds"
28 | ExpiresByType text/css "access plus 604800 seconds"
29 | ExpiresByType text/javascript "access plus 216000 seconds"
30 | ExpiresByType application/x-javascript "access plus 216000 seconds"
31 |
32 |
33 |
34 | Header unset ETag
35 |
36 |
37 | FileETag None
38 |
39 |
40 | Header unset Last-Modified
41 |
42 |
43 | AddType text/cache-manifest .manifest
44 |
45 | php_flag short_open_tag on
--------------------------------------------------------------------------------
/feedback.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
11 | $zabbix->setPassword($zabbixPass);
12 | $zabbix->setZabbixApiUrl($zabbixApi);
13 |
14 | // Login
15 | if (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
16 | $zabbix->login();
17 | }
18 |
19 | if (!$zabbix->isLoggedIn()) {
20 | header("Location: index.php");
21 | exit();
22 | }
23 |
24 | $boolShowThankyou = false;
25 | $boolShowFeedbackForm = true;
26 | $boolShowTextlengthWarn = false;
27 |
28 | if (isset($_POST['mZabbixFeedback'])) {
29 | // Process feedback
30 | $txtFeedback = htmlentities($_POST['txtFeedback']);
31 | if (strlen($txtFeedback) < 30) {
32 | // Don't bother, type more
33 | $boolShowTextlengthWarn = true;
34 | $boolShowThankyou = false;
35 | $boolShowFeedbackForm = true;
36 | } else {
37 | // Mail me
38 | $source_ip = getVisitorIP();
39 | $server_variables = $_SERVER;
40 |
41 | // I'll mail myself in HTML, thankyouverymuchkbye
42 | $mailHtml = array();
43 | $mailHtml[] = "Source: " . $source_ip . " ";
44 | $mailHtml[] = "Date: " . date("Y-m-d, H:i:s") . " ";
45 | $mailHtml[] = "Feedback: ";
46 | $mailHtml[] = "" . $txtFeedback . " ";
47 | $mailHtml[] = "";
48 | $mailHtml[] = " ";
49 | $mailHtml[] = "_SERVER variables";
50 | foreach ($server_variables as $argument => $value) {
51 | $mailHtml[] = "- " . $argument . ": " . $value;
52 | }
53 | $mailHtml = implode(" ", $mailHtml);
54 |
55 | // Content-type for my HTML
56 | $headers = 'MIME-Version: 1.0' . "\r\n";
57 | $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
58 |
59 | // Additional headers
60 | $headers .= 'To: Mattias Geniar ' . "\r\n";
61 | $headers .= 'From: mZabbix Feedback ' . "\r\n";
62 |
63 | // Send it
64 | mail("mattias.geniar@gmail.com", "mZabbix Feedback from " . $source_ip, $mailHtml, $headers);
65 |
66 | // Show some output
67 | $boolShowThankyou = true;
68 | $boolShowFeedbackForm = false;
69 | }
70 |
71 | } else {
72 | $boolShowFeedbackForm = true;
73 | }
74 |
75 | // "templates"
76 | require_once("template/header.php");
77 | ?>
78 |
79 |
80 |
84 |
85 |
88 |
110 |
111 |
116 |
120 |
123 |
124 |
127 |
--------------------------------------------------------------------------------
/functions.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/graph.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
12 | $zabbix->setPassword($zabbixPass);
13 | $zabbix->setZabbixApiUrl($zabbixApi);
14 |
15 | // Login
16 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
17 | // Try it with the authentication hash we have
18 | $zabbix->setAuthToken($zabbixAuthHash);
19 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
20 | $zabbix->login();
21 | }
22 |
23 | if (!$zabbix->isLoggedIn()) {
24 | header("Location: index.php");
25 | exit();
26 | }
27 |
28 | require_once("template/header.php");
29 |
30 | $zabbixGraphId = (string) $_GET['graphid'];
31 | $zabbixGraphPeriod = (string) $_GET['period'];
32 | $zabbixHostId = (string) $_GET['hostid'];
33 | $zabbixHostGroupId = (string) $_GET['groupid'];
34 | $zabbixHostGroupName = (string) urldecode($_GET['groupname']);
35 | $zabbixHostName = (string) urldecode($_GET['hostname']);
36 |
37 | $urlParameters = "hostid=". $zabbixHostId ."&hostname=". $zabbixHostName ."&groupid=". $zabbixHostGroupId ."&groupname=". urlencode($zabbixHostGroupName);
38 |
39 | if ($zabbixGraphId > 0) {
40 | $graph = $zabbix->getGraphById($zabbixGraphId);
41 | } else {
42 | $graph = null;
43 | }
44 | ?>
45 |
74 |
75 |
76 |
77 |
78 |
81 |
name?>
82 |
83 | Now showing a hour period.
84 |
85 |
86 |
87 |
114 |
115 |
118 |
119 | Invalid graph specified.
120 |
121 |
124 |
--------------------------------------------------------------------------------
/graph_img.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
12 | $zabbix->setPassword($zabbixPass);
13 | $zabbix->setZabbixApiUrl($zabbixApi);
14 |
15 | // Login
16 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
17 | // Try it with the authentication hash we have
18 | $zabbix->setAuthToken($zabbixAuthHash);
19 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
20 | $zabbix->login();
21 | }
22 |
23 | if (!$zabbix->isLoggedIn()) {
24 | header("Location: index.php");
25 | exit();
26 | }
27 |
28 | $graphid = (string) $_GET['graphid'];
29 | $graphperiod = (string) $_GET['period'];
30 |
31 | // Set correct header
32 | header("Content-Type: image/jpg");
33 |
34 | // Read the file & output
35 | print $zabbix->getGraphImageById($graphid, $graphperiod);
36 | ?>
37 |
--------------------------------------------------------------------------------
/host.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
11 | $zabbix->setPassword($zabbixPass);
12 | $zabbix->setZabbixApiUrl($zabbixApi);
13 |
14 | // Login
15 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
16 | // Try it with the authentication hash we have
17 | $zabbix->setAuthToken($zabbixAuthHash);
18 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
19 | $zabbix->login();
20 | }
21 |
22 | if (!$zabbix->isLoggedIn()) {
23 | header("Location: index.php");
24 | exit();
25 | }
26 |
27 | require_once("template/header.php");
28 |
29 | $zabbixHostId = (string) $_GET['hostid'];
30 | $zabbixHostGroupId = (string) $_GET['groupid'];
31 | $zabbixHostGroupName = (string) urldecode($_GET['groupname']);
32 | if ($zabbixHostId > 0) {
33 | $host = $zabbix->getHostById($zabbixHostId);
34 |
35 | // Graphs
36 | $graphs = $zabbix->getGraphsByHostId($zabbixHostId);
37 | $graphs = $zabbix->sortGraphsByName($graphs);
38 |
39 | // Triggers
40 | $triggers = $zabbix->getTriggersByHostId($zabbixHostId);
41 | ?>
42 |
43 |
63 |
64 |
65 |
host?>
66 |
67 |
Host details
68 |
69 | Host: host?>
70 | getVersion() == '1.4') {
72 | /* Zabbix 2.x compatible */
73 | echo "Name: ". $host->name ." ";
74 |
75 | echo "
Interfaces ";
76 | $interfaces = (array) $host->interfaces;
77 | if (is_array($interfaces) && count($interfaces) > 0) {
78 | foreach ($host->interfaces as $interfaceId => $interfaceValue) {
79 | echo "DNS: ". $interfaceValue->dns ."
";
80 | echo "IP: ". $interfaceValue->ip ."
";
81 | echo "Zabbix Agent Port: ". $interfaceValue->port ."
";
82 | }
83 | } else {
84 | echo '
This host does not have any configured interfaces.
';
85 | }
86 | } else {
87 | /* Zabbix 1.8 compatible */
88 | ?>
89 | DNS: dns) ? $host->dns : '' ?>
90 | IP: ip) ? $host->ip : '' ?>
91 |
94 |
95 |
96 | 0) {
98 | ?>
99 |
Graphs
100 |
113 |
116 |
117 |
This host does not have any available graphs to display. As soon as you add a graph in Zabbix, it will show up here.
118 |
119 |
122 |
123 |
126 |
127 | Invalid hostgroup specified.
128 |
129 |
132 |
--------------------------------------------------------------------------------
/hostgroups.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
13 | $zabbix->setPassword($zabbixPass);
14 | $zabbix->setZabbixApiUrl($zabbixApi);
15 |
16 | // Login
17 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
18 | // Try it with the authentication hash we have
19 | $zabbix->setAuthToken($zabbixAuthHash);
20 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
21 | // Or try it with our info from the cookies
22 | $zabbix->login();
23 | }
24 |
25 | if (!$zabbix->isLoggedIn()) {
26 | header("Location: index.php");
27 | exit();
28 | }
29 |
30 | require_once("template/header.php");
31 | ?>
32 |
33 |
34 |
35 |
36 | Home /
37 |
38 |
39 | Hostgroups
40 |
41 |
42 |
43 |
44 |
45 |
46 | getHostgroups();
48 | $zabbixHostgroups = $zabbix->sortHostgroupsByName($zabbixHostgroups);
49 |
50 | if (is_array($zabbixHostgroups) && count($zabbixHostgroups) > 0) {
51 | ?>
52 |
53 | getHostsByGroupId ($groupobject["groupid"]);
59 | $hosts = $zabbix->filterActiveHosts($hosts);
60 | $hostCount = is_array($hosts) ? count($hosts) : 0;
61 | } else {
62 | // Assume this hostgroup has hosts in them
63 | $hostCount = 1;
64 | }
65 |
66 | if ($arrSettings["showEmptyHostgroups"] || $hostCount > 0) {
67 | ?>
68 |
69 |
70 |
71 |
72 |
73 |
77 |
78 |
81 |
82 |
Access Denied
83 |
84 | Sorry, you don't seem have access to any hostgroups.
85 |
86 | Does the user with which you login, have API Access enabled in the Zabbix User Administration screen?
87 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/hostitems.php:
--------------------------------------------------------------------------------
1 | 0) {
4 | foreach ($arrZabbixItems["hostgroups"] as $hostgroupid => $hostgroup) {
5 | echo "";
6 | if (key_exists("hosts", $hostgroup) && is_array($hostgroup["hosts"]) && count($hostgroup["hosts"]) > 0) {
7 | $hosts = $hostgroup["hosts"];
8 |
9 | foreach ($hosts as $hostid => $host) {
10 | echo "". $host["host"]["host"] ." ";
11 | }
12 | }
13 | echo " ";
14 | }
15 | }
16 |
17 | // Second list: detail view of each host
18 | if (is_array($arrZabbixItems["hostgroups"]) && count($arrZabbixItems["hostgroups"]) > 0) {
19 | foreach ($arrZabbixItems["hostgroups"] as $hostgroupid => $hostgroup) {
20 | if (key_exists("hosts", $hostgroup) && is_array($hostgroup["hosts"]) && count($hostgroup["hosts"]) > 0) {
21 | $hosts = $hostgroup["hosts"];
22 |
23 | foreach ($hosts as $hostid => $host) {
24 | $host_object = $host["host"];
25 | $trigger = key_exists("triggers", $host) && is_array($host["triggers"]) ? $host["triggers"] : array();;
26 |
27 | //print_r($host_object);
28 |
29 | // Start our detailed list
30 | echo "";
31 | echo "General info ";
32 |
33 | // Give a small overview of this host
34 | echo "";
35 | echo " DNS: ". $host_object["dns"] ." ";
36 | echo " IP: ". $host_object["ip"] ." ";
37 | echo " Availability: ". $zabbix->getAvailability($host_object["available"]) ." ";
38 | if ($host_object["available"] != 1)
39 | echo "Error: ". $host_object["error"] ." ";
40 | echo " ";
41 |
42 | // Show possible graphs
43 | echo "Graphs ";
44 | if (key_exists("graphs", $host) && is_array($host["graphs"]) && count($host["graphs"]) > 0) {
45 |
46 | echo "";
47 | foreach ($host["graphs"] as $graphid => $graph) {
48 | echo " ". $graph["name"] ." ";
49 | }
50 | echo " ";
51 | } else {
52 | echo "No graphs available ";
53 | }
54 |
55 | echo " ";
56 | }
57 | }
58 | }
59 | }
60 | ?>
--------------------------------------------------------------------------------
/hosts.php:
--------------------------------------------------------------------------------
1 | setUsername($zabbixUser);
13 | $zabbix->setPassword($zabbixPass);
14 | $zabbix->setZabbixApiUrl($zabbixApi);
15 |
16 | // Login
17 | if (isset($zabbixAuthHash) && strlen($zabbixAuthHash) > 0) {
18 | // Try it with the authentication hash we have
19 | $zabbix->setAuthToken($zabbixAuthHash);
20 | } elseif (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
21 | // Or try it with our info from the cookies
22 | $zabbix->login();
23 | }
24 |
25 | if (!$zabbix->isLoggedIn()) {
26 | header("Location: index.php");
27 | exit();
28 | }
29 |
30 | require_once("template/header.php");
31 |
32 | $zabbixHostgroupId = (string) $_GET['hostgroupid'];
33 | if ($zabbixHostgroupId > 0) {
34 | $hostgroup = $zabbix->getHostgroupById($zabbixHostgroupId);
35 | $hosts = $zabbix->getHostsByGroupId ($zabbixHostgroupId);
36 | $hosts = $zabbix->filterActiveHosts($hosts);
37 | $hosts = $zabbix->sortHostsByName($hosts);
38 |
39 | ?>
40 |
41 |
42 |
43 |
44 | Home /
45 |
46 |
47 | Hostgroups /
48 |
49 |
50 | name; ?>
51 |
52 |
53 |
54 |
55 |
56 |
57 |
70 |
73 |
74 | Invalid hostgroup, aborting request.
75 |
76 |
77 |
80 |
81 |
82 |
83 |
86 |
--------------------------------------------------------------------------------
/images/hosts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattiasgeniar/MoZBX/1dcb90834b1e1c50c7186f54af924bcfc1b603a1/images/hosts.png
--------------------------------------------------------------------------------
/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattiasgeniar/MoZBX/1dcb90834b1e1c50c7186f54af924bcfc1b603a1/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattiasgeniar/MoZBX/1dcb90834b1e1c50c7186f54af924bcfc1b603a1/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | login();
16 | }else {
17 | // It's a hosted version, perhaps we can recover username & password from cookies?
18 | $zabbixApi = "";
19 | $zabbixUser = "";
20 | $zabbixPass = "";
21 |
22 | // Get the values
23 | require_once("cookies.php");
24 |
25 | // Populate our class
26 | $zabbix->setUsername($zabbixUser);
27 | $zabbix->setPassword($zabbixPass);
28 | $zabbix->setZabbixApiUrl($zabbixApi);
29 |
30 | // Login
31 | if (strlen($zabbix->getUsername()) > 0 && strlen($zabbix->getPassword()) > 0 && strlen($zabbix->getZabbixApiUrl()) > 0) {
32 | $zabbix->login();
33 | }
34 | }
35 |
36 | //$zabbix->Login("mattias_api", "test");
37 |
38 |
39 | if ($zabbix->isLoggedIn()) {
40 | // Authenticated, save cookie
41 | setcookie("zabbixUsername", $zabbix->getUsername(), $arrSettings["cookieExpire"]);
42 | setcookie("zabbixPassword", $zabbix->getPassword(), $arrSettings["cookieExpire"]);
43 | setcookie("zabbixApi", $zabbix->getZabbixApiUrl(), $arrSettings["cookieExpire"]);
44 | setcookie("zabbixAuthHash", $zabbix->getAuthToken(), $arrSettings["cookieExpire"]);
45 | }
46 |
47 | // "templates"
48 | require_once("template/header.php");
49 |
50 | if ($zabbix->isLoggedIn()) {
51 |
52 | // Retrieve the data in one go
53 | $zabbix_auth = $zabbix->getAuthToken();
54 |
55 | // Get all active triggers (for the counter on homepage);
56 | $triggersActive = $zabbix->getTriggersActive($arrSettings["minimalSeverity"]);
57 | if (!is_array($triggersActive))
58 | $triggersActive = array();
59 | ?>
60 |
67 |
68 |
83 | 0 ? $_GET['username'] : $zabbixUser;
87 | $zabbixApi = isset($_GET['api_url']) && strlen($_GET['api_url']) > 0 ? $_GET['api_url'] : $zabbixApi;
88 | if (strpos($zabbixApi, 'api_jsonrpc.php') === false)
89 | $zabbixApi .= "api_jsonrpc.php";
90 | $zabbixHideApi = isset($_GET['hideapi']) ? 'hideapi' : 'donthideapi';
91 | $zabbixPass = isset($_GET['password']) ? $_GET['password'] : $arrSettings["zabbixPassword"];
92 | ?>
93 |
100 |
101 |
102 |
Login
103 |
104 |
105 | getLastError()) > 0) {
109 | $arrError = $zabbix->getLastError();
110 | $errormsg = $arrError["data"];
111 | } else {
112 | $errormsg = "invalid combination";
113 | }
114 | ?>
115 |
116 |
117 |
118 |
123 |
124 |
API URL
125 |
126 |
127 |
The URL of your public Zabbix web interface.
128 |
129 |
130 |
134 |
135 |
138 |
139 |
140 |
Username
141 |
142 |
143 |
144 |
145 |
146 |
147 |
Password
148 |
149 |
150 |
151 |
152 |
153 |
154 | Login
155 |
156 |
157 |
158 |
161 |
162 |
165 |
--------------------------------------------------------------------------------
/js/bootstrap.js:
--------------------------------------------------------------------------------
1 | /* ===================================================
2 | * bootstrap-transition.js v2.0.4
3 | * http://twitter.github.com/bootstrap/javascript.html#transitions
4 | * ===================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | $(function () {
24 |
25 | "use strict"; // jshint ;_;
26 |
27 |
28 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
29 | * ======================================================= */
30 |
31 | $.support.transition = (function () {
32 |
33 | var transitionEnd = (function () {
34 |
35 | var el = document.createElement('bootstrap')
36 | , transEndEventNames = {
37 | 'WebkitTransition' : 'webkitTransitionEnd'
38 | , 'MozTransition' : 'transitionend'
39 | , 'OTransition' : 'oTransitionEnd'
40 | , 'msTransition' : 'MSTransitionEnd'
41 | , 'transition' : 'transitionend'
42 | }
43 | , name
44 |
45 | for (name in transEndEventNames){
46 | if (el.style[name] !== undefined) {
47 | return transEndEventNames[name]
48 | }
49 | }
50 |
51 | }())
52 |
53 | return transitionEnd && {
54 | end: transitionEnd
55 | }
56 |
57 | })()
58 |
59 | })
60 |
61 | }(window.jQuery);/* ==========================================================
62 | * bootstrap-alert.js v2.0.4
63 | * http://twitter.github.com/bootstrap/javascript.html#alerts
64 | * ==========================================================
65 | * Copyright 2012 Twitter, Inc.
66 | *
67 | * Licensed under the Apache License, Version 2.0 (the "License");
68 | * you may not use this file except in compliance with the License.
69 | * You may obtain a copy of the License at
70 | *
71 | * http://www.apache.org/licenses/LICENSE-2.0
72 | *
73 | * Unless required by applicable law or agreed to in writing, software
74 | * distributed under the License is distributed on an "AS IS" BASIS,
75 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
76 | * See the License for the specific language governing permissions and
77 | * limitations under the License.
78 | * ========================================================== */
79 |
80 |
81 | !function ($) {
82 |
83 | "use strict"; // jshint ;_;
84 |
85 |
86 | /* ALERT CLASS DEFINITION
87 | * ====================== */
88 |
89 | var dismiss = '[data-dismiss="alert"]'
90 | , Alert = function (el) {
91 | $(el).on('click', dismiss, this.close)
92 | }
93 |
94 | Alert.prototype.close = function (e) {
95 | var $this = $(this)
96 | , selector = $this.attr('data-target')
97 | , $parent
98 |
99 | if (!selector) {
100 | selector = $this.attr('href')
101 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
102 | }
103 |
104 | $parent = $(selector)
105 |
106 | e && e.preventDefault()
107 |
108 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
109 |
110 | $parent.trigger(e = $.Event('close'))
111 |
112 | if (e.isDefaultPrevented()) return
113 |
114 | $parent.removeClass('in')
115 |
116 | function removeElement() {
117 | $parent
118 | .trigger('closed')
119 | .remove()
120 | }
121 |
122 | $.support.transition && $parent.hasClass('fade') ?
123 | $parent.on($.support.transition.end, removeElement) :
124 | removeElement()
125 | }
126 |
127 |
128 | /* ALERT PLUGIN DEFINITION
129 | * ======================= */
130 |
131 | $.fn.alert = function (option) {
132 | return this.each(function () {
133 | var $this = $(this)
134 | , data = $this.data('alert')
135 | if (!data) $this.data('alert', (data = new Alert(this)))
136 | if (typeof option == 'string') data[option].call($this)
137 | })
138 | }
139 |
140 | $.fn.alert.Constructor = Alert
141 |
142 |
143 | /* ALERT DATA-API
144 | * ============== */
145 |
146 | $(function () {
147 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
148 | })
149 |
150 | }(window.jQuery);/* ============================================================
151 | * bootstrap-button.js v2.0.4
152 | * http://twitter.github.com/bootstrap/javascript.html#buttons
153 | * ============================================================
154 | * Copyright 2012 Twitter, Inc.
155 | *
156 | * Licensed under the Apache License, Version 2.0 (the "License");
157 | * you may not use this file except in compliance with the License.
158 | * You may obtain a copy of the License at
159 | *
160 | * http://www.apache.org/licenses/LICENSE-2.0
161 | *
162 | * Unless required by applicable law or agreed to in writing, software
163 | * distributed under the License is distributed on an "AS IS" BASIS,
164 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
165 | * See the License for the specific language governing permissions and
166 | * limitations under the License.
167 | * ============================================================ */
168 |
169 |
170 | !function ($) {
171 |
172 | "use strict"; // jshint ;_;
173 |
174 |
175 | /* BUTTON PUBLIC CLASS DEFINITION
176 | * ============================== */
177 |
178 | var Button = function (element, options) {
179 | this.$element = $(element)
180 | this.options = $.extend({}, $.fn.button.defaults, options)
181 | }
182 |
183 | Button.prototype.setState = function (state) {
184 | var d = 'disabled'
185 | , $el = this.$element
186 | , data = $el.data()
187 | , val = $el.is('input') ? 'val' : 'html'
188 |
189 | state = state + 'Text'
190 | data.resetText || $el.data('resetText', $el[val]())
191 |
192 | $el[val](data[state] || this.options[state])
193 |
194 | // push to event loop to allow forms to submit
195 | setTimeout(function () {
196 | state == 'loadingText' ?
197 | $el.addClass(d).attr(d, d) :
198 | $el.removeClass(d).removeAttr(d)
199 | }, 0)
200 | }
201 |
202 | Button.prototype.toggle = function () {
203 | var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
204 |
205 | $parent && $parent
206 | .find('.active')
207 | .removeClass('active')
208 |
209 | this.$element.toggleClass('active')
210 | }
211 |
212 |
213 | /* BUTTON PLUGIN DEFINITION
214 | * ======================== */
215 |
216 | $.fn.button = function (option) {
217 | return this.each(function () {
218 | var $this = $(this)
219 | , data = $this.data('button')
220 | , options = typeof option == 'object' && option
221 | if (!data) $this.data('button', (data = new Button(this, options)))
222 | if (option == 'toggle') data.toggle()
223 | else if (option) data.setState(option)
224 | })
225 | }
226 |
227 | $.fn.button.defaults = {
228 | loadingText: 'loading...'
229 | }
230 |
231 | $.fn.button.Constructor = Button
232 |
233 |
234 | /* BUTTON DATA-API
235 | * =============== */
236 |
237 | $(function () {
238 | $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
239 | var $btn = $(e.target)
240 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
241 | $btn.button('toggle')
242 | })
243 | })
244 |
245 | }(window.jQuery);/* ==========================================================
246 | * bootstrap-carousel.js v2.0.4
247 | * http://twitter.github.com/bootstrap/javascript.html#carousel
248 | * ==========================================================
249 | * Copyright 2012 Twitter, Inc.
250 | *
251 | * Licensed under the Apache License, Version 2.0 (the "License");
252 | * you may not use this file except in compliance with the License.
253 | * You may obtain a copy of the License at
254 | *
255 | * http://www.apache.org/licenses/LICENSE-2.0
256 | *
257 | * Unless required by applicable law or agreed to in writing, software
258 | * distributed under the License is distributed on an "AS IS" BASIS,
259 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
260 | * See the License for the specific language governing permissions and
261 | * limitations under the License.
262 | * ========================================================== */
263 |
264 |
265 | !function ($) {
266 |
267 | "use strict"; // jshint ;_;
268 |
269 |
270 | /* CAROUSEL CLASS DEFINITION
271 | * ========================= */
272 |
273 | var Carousel = function (element, options) {
274 | this.$element = $(element)
275 | this.options = options
276 | this.options.slide && this.slide(this.options.slide)
277 | this.options.pause == 'hover' && this.$element
278 | .on('mouseenter', $.proxy(this.pause, this))
279 | .on('mouseleave', $.proxy(this.cycle, this))
280 | }
281 |
282 | Carousel.prototype = {
283 |
284 | cycle: function (e) {
285 | if (!e) this.paused = false
286 | this.options.interval
287 | && !this.paused
288 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
289 | return this
290 | }
291 |
292 | , to: function (pos) {
293 | var $active = this.$element.find('.active')
294 | , children = $active.parent().children()
295 | , activePos = children.index($active)
296 | , that = this
297 |
298 | if (pos > (children.length - 1) || pos < 0) return
299 |
300 | if (this.sliding) {
301 | return this.$element.one('slid', function () {
302 | that.to(pos)
303 | })
304 | }
305 |
306 | if (activePos == pos) {
307 | return this.pause().cycle()
308 | }
309 |
310 | return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
311 | }
312 |
313 | , pause: function (e) {
314 | if (!e) this.paused = true
315 | clearInterval(this.interval)
316 | this.interval = null
317 | return this
318 | }
319 |
320 | , next: function () {
321 | if (this.sliding) return
322 | return this.slide('next')
323 | }
324 |
325 | , prev: function () {
326 | if (this.sliding) return
327 | return this.slide('prev')
328 | }
329 |
330 | , slide: function (type, next) {
331 | var $active = this.$element.find('.active')
332 | , $next = next || $active[type]()
333 | , isCycling = this.interval
334 | , direction = type == 'next' ? 'left' : 'right'
335 | , fallback = type == 'next' ? 'first' : 'last'
336 | , that = this
337 | , e = $.Event('slide')
338 |
339 | this.sliding = true
340 |
341 | isCycling && this.pause()
342 |
343 | $next = $next.length ? $next : this.$element.find('.item')[fallback]()
344 |
345 | if ($next.hasClass('active')) return
346 |
347 | if ($.support.transition && this.$element.hasClass('slide')) {
348 | this.$element.trigger(e)
349 | if (e.isDefaultPrevented()) return
350 | $next.addClass(type)
351 | $next[0].offsetWidth // force reflow
352 | $active.addClass(direction)
353 | $next.addClass(direction)
354 | this.$element.one($.support.transition.end, function () {
355 | $next.removeClass([type, direction].join(' ')).addClass('active')
356 | $active.removeClass(['active', direction].join(' '))
357 | that.sliding = false
358 | setTimeout(function () { that.$element.trigger('slid') }, 0)
359 | })
360 | } else {
361 | this.$element.trigger(e)
362 | if (e.isDefaultPrevented()) return
363 | $active.removeClass('active')
364 | $next.addClass('active')
365 | this.sliding = false
366 | this.$element.trigger('slid')
367 | }
368 |
369 | isCycling && this.cycle()
370 |
371 | return this
372 | }
373 |
374 | }
375 |
376 |
377 | /* CAROUSEL PLUGIN DEFINITION
378 | * ========================== */
379 |
380 | $.fn.carousel = function (option) {
381 | return this.each(function () {
382 | var $this = $(this)
383 | , data = $this.data('carousel')
384 | , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
385 | if (!data) $this.data('carousel', (data = new Carousel(this, options)))
386 | if (typeof option == 'number') data.to(option)
387 | else if (typeof option == 'string' || (option = options.slide)) data[option]()
388 | else if (options.interval) data.cycle()
389 | })
390 | }
391 |
392 | $.fn.carousel.defaults = {
393 | interval: 5000
394 | , pause: 'hover'
395 | }
396 |
397 | $.fn.carousel.Constructor = Carousel
398 |
399 |
400 | /* CAROUSEL DATA-API
401 | * ================= */
402 |
403 | $(function () {
404 | $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
405 | var $this = $(this), href
406 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
407 | , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
408 | $target.carousel(options)
409 | e.preventDefault()
410 | })
411 | })
412 |
413 | }(window.jQuery);/* =============================================================
414 | * bootstrap-collapse.js v2.0.4
415 | * http://twitter.github.com/bootstrap/javascript.html#collapse
416 | * =============================================================
417 | * Copyright 2012 Twitter, Inc.
418 | *
419 | * Licensed under the Apache License, Version 2.0 (the "License");
420 | * you may not use this file except in compliance with the License.
421 | * You may obtain a copy of the License at
422 | *
423 | * http://www.apache.org/licenses/LICENSE-2.0
424 | *
425 | * Unless required by applicable law or agreed to in writing, software
426 | * distributed under the License is distributed on an "AS IS" BASIS,
427 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
428 | * See the License for the specific language governing permissions and
429 | * limitations under the License.
430 | * ============================================================ */
431 |
432 |
433 | !function ($) {
434 |
435 | "use strict"; // jshint ;_;
436 |
437 |
438 | /* COLLAPSE PUBLIC CLASS DEFINITION
439 | * ================================ */
440 |
441 | var Collapse = function (element, options) {
442 | this.$element = $(element)
443 | this.options = $.extend({}, $.fn.collapse.defaults, options)
444 |
445 | if (this.options.parent) {
446 | this.$parent = $(this.options.parent)
447 | }
448 |
449 | this.options.toggle && this.toggle()
450 | }
451 |
452 | Collapse.prototype = {
453 |
454 | constructor: Collapse
455 |
456 | , dimension: function () {
457 | var hasWidth = this.$element.hasClass('width')
458 | return hasWidth ? 'width' : 'height'
459 | }
460 |
461 | , show: function () {
462 | var dimension
463 | , scroll
464 | , actives
465 | , hasData
466 |
467 | if (this.transitioning) return
468 |
469 | dimension = this.dimension()
470 | scroll = $.camelCase(['scroll', dimension].join('-'))
471 | actives = this.$parent && this.$parent.find('> .accordion-group > .in')
472 |
473 | if (actives && actives.length) {
474 | hasData = actives.data('collapse')
475 | if (hasData && hasData.transitioning) return
476 | actives.collapse('hide')
477 | hasData || actives.data('collapse', null)
478 | }
479 |
480 | this.$element[dimension](0)
481 | this.transition('addClass', $.Event('show'), 'shown')
482 | this.$element[dimension](this.$element[0][scroll])
483 | }
484 |
485 | , hide: function () {
486 | var dimension
487 | if (this.transitioning) return
488 | dimension = this.dimension()
489 | this.reset(this.$element[dimension]())
490 | this.transition('removeClass', $.Event('hide'), 'hidden')
491 | this.$element[dimension](0)
492 | }
493 |
494 | , reset: function (size) {
495 | var dimension = this.dimension()
496 |
497 | this.$element
498 | .removeClass('collapse')
499 | [dimension](size || 'auto')
500 | [0].offsetWidth
501 |
502 | this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
503 |
504 | return this
505 | }
506 |
507 | , transition: function (method, startEvent, completeEvent) {
508 | var that = this
509 | , complete = function () {
510 | if (startEvent.type == 'show') that.reset()
511 | that.transitioning = 0
512 | that.$element.trigger(completeEvent)
513 | }
514 |
515 | this.$element.trigger(startEvent)
516 |
517 | if (startEvent.isDefaultPrevented()) return
518 |
519 | this.transitioning = 1
520 |
521 | this.$element[method]('in')
522 |
523 | $.support.transition && this.$element.hasClass('collapse') ?
524 | this.$element.one($.support.transition.end, complete) :
525 | complete()
526 | }
527 |
528 | , toggle: function () {
529 | this[this.$element.hasClass('in') ? 'hide' : 'show']()
530 | }
531 |
532 | }
533 |
534 |
535 | /* COLLAPSIBLE PLUGIN DEFINITION
536 | * ============================== */
537 |
538 | $.fn.collapse = function (option) {
539 | return this.each(function () {
540 | var $this = $(this)
541 | , data = $this.data('collapse')
542 | , options = typeof option == 'object' && option
543 | if (!data) $this.data('collapse', (data = new Collapse(this, options)))
544 | if (typeof option == 'string') data[option]()
545 | })
546 | }
547 |
548 | $.fn.collapse.defaults = {
549 | toggle: true
550 | }
551 |
552 | $.fn.collapse.Constructor = Collapse
553 |
554 |
555 | /* COLLAPSIBLE DATA-API
556 | * ==================== */
557 |
558 | $(function () {
559 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
560 | var $this = $(this), href
561 | , target = $this.attr('data-target')
562 | || e.preventDefault()
563 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
564 | , option = $(target).data('collapse') ? 'toggle' : $this.data()
565 | $(target).collapse(option)
566 | })
567 | })
568 |
569 | }(window.jQuery);/* ============================================================
570 | * bootstrap-dropdown.js v2.0.4
571 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns
572 | * ============================================================
573 | * Copyright 2012 Twitter, Inc.
574 | *
575 | * Licensed under the Apache License, Version 2.0 (the "License");
576 | * you may not use this file except in compliance with the License.
577 | * You may obtain a copy of the License at
578 | *
579 | * http://www.apache.org/licenses/LICENSE-2.0
580 | *
581 | * Unless required by applicable law or agreed to in writing, software
582 | * distributed under the License is distributed on an "AS IS" BASIS,
583 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
584 | * See the License for the specific language governing permissions and
585 | * limitations under the License.
586 | * ============================================================ */
587 |
588 |
589 | !function ($) {
590 |
591 | "use strict"; // jshint ;_;
592 |
593 |
594 | /* DROPDOWN CLASS DEFINITION
595 | * ========================= */
596 |
597 | var toggle = '[data-toggle="dropdown"]'
598 | , Dropdown = function (element) {
599 | var $el = $(element).on('click.dropdown.data-api', this.toggle)
600 | $('html').on('click.dropdown.data-api', function () {
601 | $el.parent().removeClass('open')
602 | })
603 | }
604 |
605 | Dropdown.prototype = {
606 |
607 | constructor: Dropdown
608 |
609 | , toggle: function (e) {
610 | var $this = $(this)
611 | , $parent
612 | , selector
613 | , isActive
614 |
615 | if ($this.is('.disabled, :disabled')) return
616 |
617 | selector = $this.attr('data-target')
618 |
619 | if (!selector) {
620 | selector = $this.attr('href')
621 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
622 | }
623 |
624 | $parent = $(selector)
625 | $parent.length || ($parent = $this.parent())
626 |
627 | isActive = $parent.hasClass('open')
628 |
629 | clearMenus()
630 |
631 | if (!isActive) $parent.toggleClass('open')
632 |
633 | return false
634 | }
635 |
636 | }
637 |
638 | function clearMenus() {
639 | $(toggle).parent().removeClass('open')
640 | }
641 |
642 |
643 | /* DROPDOWN PLUGIN DEFINITION
644 | * ========================== */
645 |
646 | $.fn.dropdown = function (option) {
647 | return this.each(function () {
648 | var $this = $(this)
649 | , data = $this.data('dropdown')
650 | if (!data) $this.data('dropdown', (data = new Dropdown(this)))
651 | if (typeof option == 'string') data[option].call($this)
652 | })
653 | }
654 |
655 | $.fn.dropdown.Constructor = Dropdown
656 |
657 |
658 | /* APPLY TO STANDARD DROPDOWN ELEMENTS
659 | * =================================== */
660 |
661 | $(function () {
662 | $('html').on('click.dropdown.data-api', clearMenus)
663 | $('body')
664 | .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
665 | .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
666 | })
667 |
668 | }(window.jQuery);/* =========================================================
669 | * bootstrap-modal.js v2.0.4
670 | * http://twitter.github.com/bootstrap/javascript.html#modals
671 | * =========================================================
672 | * Copyright 2012 Twitter, Inc.
673 | *
674 | * Licensed under the Apache License, Version 2.0 (the "License");
675 | * you may not use this file except in compliance with the License.
676 | * You may obtain a copy of the License at
677 | *
678 | * http://www.apache.org/licenses/LICENSE-2.0
679 | *
680 | * Unless required by applicable law or agreed to in writing, software
681 | * distributed under the License is distributed on an "AS IS" BASIS,
682 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
683 | * See the License for the specific language governing permissions and
684 | * limitations under the License.
685 | * ========================================================= */
686 |
687 |
688 | !function ($) {
689 |
690 | "use strict"; // jshint ;_;
691 |
692 |
693 | /* MODAL CLASS DEFINITION
694 | * ====================== */
695 |
696 | var Modal = function (content, options) {
697 | this.options = options
698 | this.$element = $(content)
699 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
700 | }
701 |
702 | Modal.prototype = {
703 |
704 | constructor: Modal
705 |
706 | , toggle: function () {
707 | return this[!this.isShown ? 'show' : 'hide']()
708 | }
709 |
710 | , show: function () {
711 | var that = this
712 | , e = $.Event('show')
713 |
714 | this.$element.trigger(e)
715 |
716 | if (this.isShown || e.isDefaultPrevented()) return
717 |
718 | $('body').addClass('modal-open')
719 |
720 | this.isShown = true
721 |
722 | escape.call(this)
723 | backdrop.call(this, function () {
724 | var transition = $.support.transition && that.$element.hasClass('fade')
725 |
726 | if (!that.$element.parent().length) {
727 | that.$element.appendTo(document.body) //don't move modals dom position
728 | }
729 |
730 | that.$element
731 | .show()
732 |
733 | if (transition) {
734 | that.$element[0].offsetWidth // force reflow
735 | }
736 |
737 | that.$element.addClass('in')
738 |
739 | transition ?
740 | that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
741 | that.$element.trigger('shown')
742 |
743 | })
744 | }
745 |
746 | , hide: function (e) {
747 | e && e.preventDefault()
748 |
749 | var that = this
750 |
751 | e = $.Event('hide')
752 |
753 | this.$element.trigger(e)
754 |
755 | if (!this.isShown || e.isDefaultPrevented()) return
756 |
757 | this.isShown = false
758 |
759 | $('body').removeClass('modal-open')
760 |
761 | escape.call(this)
762 |
763 | this.$element.removeClass('in')
764 |
765 | $.support.transition && this.$element.hasClass('fade') ?
766 | hideWithTransition.call(this) :
767 | hideModal.call(this)
768 | }
769 |
770 | }
771 |
772 |
773 | /* MODAL PRIVATE METHODS
774 | * ===================== */
775 |
776 | function hideWithTransition() {
777 | var that = this
778 | , timeout = setTimeout(function () {
779 | that.$element.off($.support.transition.end)
780 | hideModal.call(that)
781 | }, 500)
782 |
783 | this.$element.one($.support.transition.end, function () {
784 | clearTimeout(timeout)
785 | hideModal.call(that)
786 | })
787 | }
788 |
789 | function hideModal(that) {
790 | this.$element
791 | .hide()
792 | .trigger('hidden')
793 |
794 | backdrop.call(this)
795 | }
796 |
797 | function backdrop(callback) {
798 | var that = this
799 | , animate = this.$element.hasClass('fade') ? 'fade' : ''
800 |
801 | if (this.isShown && this.options.backdrop) {
802 | var doAnimate = $.support.transition && animate
803 |
804 | this.$backdrop = $('
')
805 | .appendTo(document.body)
806 |
807 | if (this.options.backdrop != 'static') {
808 | this.$backdrop.click($.proxy(this.hide, this))
809 | }
810 |
811 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
812 |
813 | this.$backdrop.addClass('in')
814 |
815 | doAnimate ?
816 | this.$backdrop.one($.support.transition.end, callback) :
817 | callback()
818 |
819 | } else if (!this.isShown && this.$backdrop) {
820 | this.$backdrop.removeClass('in')
821 |
822 | $.support.transition && this.$element.hasClass('fade')?
823 | this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
824 | removeBackdrop.call(this)
825 |
826 | } else if (callback) {
827 | callback()
828 | }
829 | }
830 |
831 | function removeBackdrop() {
832 | this.$backdrop.remove()
833 | this.$backdrop = null
834 | }
835 |
836 | function escape() {
837 | var that = this
838 | if (this.isShown && this.options.keyboard) {
839 | $(document).on('keyup.dismiss.modal', function ( e ) {
840 | e.which == 27 && that.hide()
841 | })
842 | } else if (!this.isShown) {
843 | $(document).off('keyup.dismiss.modal')
844 | }
845 | }
846 |
847 |
848 | /* MODAL PLUGIN DEFINITION
849 | * ======================= */
850 |
851 | $.fn.modal = function (option) {
852 | return this.each(function () {
853 | var $this = $(this)
854 | , data = $this.data('modal')
855 | , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
856 | if (!data) $this.data('modal', (data = new Modal(this, options)))
857 | if (typeof option == 'string') data[option]()
858 | else if (options.show) data.show()
859 | })
860 | }
861 |
862 | $.fn.modal.defaults = {
863 | backdrop: true
864 | , keyboard: true
865 | , show: true
866 | }
867 |
868 | $.fn.modal.Constructor = Modal
869 |
870 |
871 | /* MODAL DATA-API
872 | * ============== */
873 |
874 | $(function () {
875 | $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
876 | var $this = $(this), href
877 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
878 | , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
879 |
880 | e.preventDefault()
881 | $target.modal(option)
882 | })
883 | })
884 |
885 | }(window.jQuery);/* ===========================================================
886 | * bootstrap-tooltip.js v2.0.4
887 | * http://twitter.github.com/bootstrap/javascript.html#tooltips
888 | * Inspired by the original jQuery.tipsy by Jason Frame
889 | * ===========================================================
890 | * Copyright 2012 Twitter, Inc.
891 | *
892 | * Licensed under the Apache License, Version 2.0 (the "License");
893 | * you may not use this file except in compliance with the License.
894 | * You may obtain a copy of the License at
895 | *
896 | * http://www.apache.org/licenses/LICENSE-2.0
897 | *
898 | * Unless required by applicable law or agreed to in writing, software
899 | * distributed under the License is distributed on an "AS IS" BASIS,
900 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
901 | * See the License for the specific language governing permissions and
902 | * limitations under the License.
903 | * ========================================================== */
904 |
905 |
906 | !function ($) {
907 |
908 | "use strict"; // jshint ;_;
909 |
910 |
911 | /* TOOLTIP PUBLIC CLASS DEFINITION
912 | * =============================== */
913 |
914 | var Tooltip = function (element, options) {
915 | this.init('tooltip', element, options)
916 | }
917 |
918 | Tooltip.prototype = {
919 |
920 | constructor: Tooltip
921 |
922 | , init: function (type, element, options) {
923 | var eventIn
924 | , eventOut
925 |
926 | this.type = type
927 | this.$element = $(element)
928 | this.options = this.getOptions(options)
929 | this.enabled = true
930 |
931 | if (this.options.trigger != 'manual') {
932 | eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
933 | eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
934 | this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
935 | this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
936 | }
937 |
938 | this.options.selector ?
939 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
940 | this.fixTitle()
941 | }
942 |
943 | , getOptions: function (options) {
944 | options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
945 |
946 | if (options.delay && typeof options.delay == 'number') {
947 | options.delay = {
948 | show: options.delay
949 | , hide: options.delay
950 | }
951 | }
952 |
953 | return options
954 | }
955 |
956 | , enter: function (e) {
957 | var self = $(e.currentTarget)[this.type](this._options).data(this.type)
958 |
959 | if (!self.options.delay || !self.options.delay.show) return self.show()
960 |
961 | clearTimeout(this.timeout)
962 | self.hoverState = 'in'
963 | this.timeout = setTimeout(function() {
964 | if (self.hoverState == 'in') self.show()
965 | }, self.options.delay.show)
966 | }
967 |
968 | , leave: function (e) {
969 | var self = $(e.currentTarget)[this.type](this._options).data(this.type)
970 |
971 | if (this.timeout) clearTimeout(this.timeout)
972 | if (!self.options.delay || !self.options.delay.hide) return self.hide()
973 |
974 | self.hoverState = 'out'
975 | this.timeout = setTimeout(function() {
976 | if (self.hoverState == 'out') self.hide()
977 | }, self.options.delay.hide)
978 | }
979 |
980 | , show: function () {
981 | var $tip
982 | , inside
983 | , pos
984 | , actualWidth
985 | , actualHeight
986 | , placement
987 | , tp
988 |
989 | if (this.hasContent() && this.enabled) {
990 | $tip = this.tip()
991 | this.setContent()
992 |
993 | if (this.options.animation) {
994 | $tip.addClass('fade')
995 | }
996 |
997 | placement = typeof this.options.placement == 'function' ?
998 | this.options.placement.call(this, $tip[0], this.$element[0]) :
999 | this.options.placement
1000 |
1001 | inside = /in/.test(placement)
1002 |
1003 | $tip
1004 | .remove()
1005 | .css({ top: 0, left: 0, display: 'block' })
1006 | .appendTo(inside ? this.$element : document.body)
1007 |
1008 | pos = this.getPosition(inside)
1009 |
1010 | actualWidth = $tip[0].offsetWidth
1011 | actualHeight = $tip[0].offsetHeight
1012 |
1013 | switch (inside ? placement.split(' ')[1] : placement) {
1014 | case 'bottom':
1015 | tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
1016 | break
1017 | case 'top':
1018 | tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
1019 | break
1020 | case 'left':
1021 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
1022 | break
1023 | case 'right':
1024 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
1025 | break
1026 | }
1027 |
1028 | $tip
1029 | .css(tp)
1030 | .addClass(placement)
1031 | .addClass('in')
1032 | }
1033 | }
1034 |
1035 | , isHTML: function(text) {
1036 | // html string detection logic adapted from jQuery
1037 | return typeof text != 'string'
1038 | || ( text.charAt(0) === "<"
1039 | && text.charAt( text.length - 1 ) === ">"
1040 | && text.length >= 3
1041 | ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
1042 | }
1043 |
1044 | , setContent: function () {
1045 | var $tip = this.tip()
1046 | , title = this.getTitle()
1047 |
1048 | $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
1049 | $tip.removeClass('fade in top bottom left right')
1050 | }
1051 |
1052 | , hide: function () {
1053 | var that = this
1054 | , $tip = this.tip()
1055 |
1056 | $tip.removeClass('in')
1057 |
1058 | function removeWithAnimation() {
1059 | var timeout = setTimeout(function () {
1060 | $tip.off($.support.transition.end).remove()
1061 | }, 500)
1062 |
1063 | $tip.one($.support.transition.end, function () {
1064 | clearTimeout(timeout)
1065 | $tip.remove()
1066 | })
1067 | }
1068 |
1069 | $.support.transition && this.$tip.hasClass('fade') ?
1070 | removeWithAnimation() :
1071 | $tip.remove()
1072 | }
1073 |
1074 | , fixTitle: function () {
1075 | var $e = this.$element
1076 | if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
1077 | $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
1078 | }
1079 | }
1080 |
1081 | , hasContent: function () {
1082 | return this.getTitle()
1083 | }
1084 |
1085 | , getPosition: function (inside) {
1086 | return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
1087 | width: this.$element[0].offsetWidth
1088 | , height: this.$element[0].offsetHeight
1089 | })
1090 | }
1091 |
1092 | , getTitle: function () {
1093 | var title
1094 | , $e = this.$element
1095 | , o = this.options
1096 |
1097 | title = $e.attr('data-original-title')
1098 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1099 |
1100 | return title
1101 | }
1102 |
1103 | , tip: function () {
1104 | return this.$tip = this.$tip || $(this.options.template)
1105 | }
1106 |
1107 | , validate: function () {
1108 | if (!this.$element[0].parentNode) {
1109 | this.hide()
1110 | this.$element = null
1111 | this.options = null
1112 | }
1113 | }
1114 |
1115 | , enable: function () {
1116 | this.enabled = true
1117 | }
1118 |
1119 | , disable: function () {
1120 | this.enabled = false
1121 | }
1122 |
1123 | , toggleEnabled: function () {
1124 | this.enabled = !this.enabled
1125 | }
1126 |
1127 | , toggle: function () {
1128 | this[this.tip().hasClass('in') ? 'hide' : 'show']()
1129 | }
1130 |
1131 | }
1132 |
1133 |
1134 | /* TOOLTIP PLUGIN DEFINITION
1135 | * ========================= */
1136 |
1137 | $.fn.tooltip = function ( option ) {
1138 | return this.each(function () {
1139 | var $this = $(this)
1140 | , data = $this.data('tooltip')
1141 | , options = typeof option == 'object' && option
1142 | if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
1143 | if (typeof option == 'string') data[option]()
1144 | })
1145 | }
1146 |
1147 | $.fn.tooltip.Constructor = Tooltip
1148 |
1149 | $.fn.tooltip.defaults = {
1150 | animation: true
1151 | , placement: 'top'
1152 | , selector: false
1153 | , template: ''
1154 | , trigger: 'hover'
1155 | , title: ''
1156 | , delay: 0
1157 | }
1158 |
1159 | }(window.jQuery);
1160 | /* ===========================================================
1161 | * bootstrap-popover.js v2.0.4
1162 | * http://twitter.github.com/bootstrap/javascript.html#popovers
1163 | * ===========================================================
1164 | * Copyright 2012 Twitter, Inc.
1165 | *
1166 | * Licensed under the Apache License, Version 2.0 (the "License");
1167 | * you may not use this file except in compliance with the License.
1168 | * You may obtain a copy of the License at
1169 | *
1170 | * http://www.apache.org/licenses/LICENSE-2.0
1171 | *
1172 | * Unless required by applicable law or agreed to in writing, software
1173 | * distributed under the License is distributed on an "AS IS" BASIS,
1174 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1175 | * See the License for the specific language governing permissions and
1176 | * limitations under the License.
1177 | * =========================================================== */
1178 |
1179 |
1180 | !function ($) {
1181 |
1182 | "use strict"; // jshint ;_;
1183 |
1184 |
1185 | /* POPOVER PUBLIC CLASS DEFINITION
1186 | * =============================== */
1187 |
1188 | var Popover = function ( element, options ) {
1189 | this.init('popover', element, options)
1190 | }
1191 |
1192 |
1193 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
1194 | ========================================== */
1195 |
1196 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
1197 |
1198 | constructor: Popover
1199 |
1200 | , setContent: function () {
1201 | var $tip = this.tip()
1202 | , title = this.getTitle()
1203 | , content = this.getContent()
1204 |
1205 | $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
1206 | $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
1207 |
1208 | $tip.removeClass('fade top bottom left right in')
1209 | }
1210 |
1211 | , hasContent: function () {
1212 | return this.getTitle() || this.getContent()
1213 | }
1214 |
1215 | , getContent: function () {
1216 | var content
1217 | , $e = this.$element
1218 | , o = this.options
1219 |
1220 | content = $e.attr('data-content')
1221 | || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1222 |
1223 | return content
1224 | }
1225 |
1226 | , tip: function () {
1227 | if (!this.$tip) {
1228 | this.$tip = $(this.options.template)
1229 | }
1230 | return this.$tip
1231 | }
1232 |
1233 | })
1234 |
1235 |
1236 | /* POPOVER PLUGIN DEFINITION
1237 | * ======================= */
1238 |
1239 | $.fn.popover = function (option) {
1240 | return this.each(function () {
1241 | var $this = $(this)
1242 | , data = $this.data('popover')
1243 | , options = typeof option == 'object' && option
1244 | if (!data) $this.data('popover', (data = new Popover(this, options)))
1245 | if (typeof option == 'string') data[option]()
1246 | })
1247 | }
1248 |
1249 | $.fn.popover.Constructor = Popover
1250 |
1251 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1252 | placement: 'right'
1253 | , content: ''
1254 | , template: ''
1255 | })
1256 |
1257 | }(window.jQuery);/* =============================================================
1258 | * bootstrap-scrollspy.js v2.0.4
1259 | * http://twitter.github.com/bootstrap/javascript.html#scrollspy
1260 | * =============================================================
1261 | * Copyright 2012 Twitter, Inc.
1262 | *
1263 | * Licensed under the Apache License, Version 2.0 (the "License");
1264 | * you may not use this file except in compliance with the License.
1265 | * You may obtain a copy of the License at
1266 | *
1267 | * http://www.apache.org/licenses/LICENSE-2.0
1268 | *
1269 | * Unless required by applicable law or agreed to in writing, software
1270 | * distributed under the License is distributed on an "AS IS" BASIS,
1271 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1272 | * See the License for the specific language governing permissions and
1273 | * limitations under the License.
1274 | * ============================================================== */
1275 |
1276 |
1277 | !function ($) {
1278 |
1279 | "use strict"; // jshint ;_;
1280 |
1281 |
1282 | /* SCROLLSPY CLASS DEFINITION
1283 | * ========================== */
1284 |
1285 | function ScrollSpy( element, options) {
1286 | var process = $.proxy(this.process, this)
1287 | , $element = $(element).is('body') ? $(window) : $(element)
1288 | , href
1289 | this.options = $.extend({}, $.fn.scrollspy.defaults, options)
1290 | this.$scrollElement = $element.on('scroll.scroll.data-api', process)
1291 | this.selector = (this.options.target
1292 | || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1293 | || '') + ' .nav li > a'
1294 | this.$body = $('body')
1295 | this.refresh()
1296 | this.process()
1297 | }
1298 |
1299 | ScrollSpy.prototype = {
1300 |
1301 | constructor: ScrollSpy
1302 |
1303 | , refresh: function () {
1304 | var self = this
1305 | , $targets
1306 |
1307 | this.offsets = $([])
1308 | this.targets = $([])
1309 |
1310 | $targets = this.$body
1311 | .find(this.selector)
1312 | .map(function () {
1313 | var $el = $(this)
1314 | , href = $el.data('target') || $el.attr('href')
1315 | , $href = /^#\w/.test(href) && $(href)
1316 | return ( $href
1317 | && href.length
1318 | && [[ $href.position().top, href ]] ) || null
1319 | })
1320 | .sort(function (a, b) { return a[0] - b[0] })
1321 | .each(function () {
1322 | self.offsets.push(this[0])
1323 | self.targets.push(this[1])
1324 | })
1325 | }
1326 |
1327 | , process: function () {
1328 | var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1329 | , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
1330 | , maxScroll = scrollHeight - this.$scrollElement.height()
1331 | , offsets = this.offsets
1332 | , targets = this.targets
1333 | , activeTarget = this.activeTarget
1334 | , i
1335 |
1336 | if (scrollTop >= maxScroll) {
1337 | return activeTarget != (i = targets.last()[0])
1338 | && this.activate ( i )
1339 | }
1340 |
1341 | for (i = offsets.length; i--;) {
1342 | activeTarget != targets[i]
1343 | && scrollTop >= offsets[i]
1344 | && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1345 | && this.activate( targets[i] )
1346 | }
1347 | }
1348 |
1349 | , activate: function (target) {
1350 | var active
1351 | , selector
1352 |
1353 | this.activeTarget = target
1354 |
1355 | $(this.selector)
1356 | .parent('.active')
1357 | .removeClass('active')
1358 |
1359 | selector = this.selector
1360 | + '[data-target="' + target + '"],'
1361 | + this.selector + '[href="' + target + '"]'
1362 |
1363 | active = $(selector)
1364 | .parent('li')
1365 | .addClass('active')
1366 |
1367 | if (active.parent('.dropdown-menu')) {
1368 | active = active.closest('li.dropdown').addClass('active')
1369 | }
1370 |
1371 | active.trigger('activate')
1372 | }
1373 |
1374 | }
1375 |
1376 |
1377 | /* SCROLLSPY PLUGIN DEFINITION
1378 | * =========================== */
1379 |
1380 | $.fn.scrollspy = function ( option ) {
1381 | return this.each(function () {
1382 | var $this = $(this)
1383 | , data = $this.data('scrollspy')
1384 | , options = typeof option == 'object' && option
1385 | if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
1386 | if (typeof option == 'string') data[option]()
1387 | })
1388 | }
1389 |
1390 | $.fn.scrollspy.Constructor = ScrollSpy
1391 |
1392 | $.fn.scrollspy.defaults = {
1393 | offset: 10
1394 | }
1395 |
1396 |
1397 | /* SCROLLSPY DATA-API
1398 | * ================== */
1399 |
1400 | $(function () {
1401 | $('[data-spy="scroll"]').each(function () {
1402 | var $spy = $(this)
1403 | $spy.scrollspy($spy.data())
1404 | })
1405 | })
1406 |
1407 | }(window.jQuery);/* ========================================================
1408 | * bootstrap-tab.js v2.0.4
1409 | * http://twitter.github.com/bootstrap/javascript.html#tabs
1410 | * ========================================================
1411 | * Copyright 2012 Twitter, Inc.
1412 | *
1413 | * Licensed under the Apache License, Version 2.0 (the "License");
1414 | * you may not use this file except in compliance with the License.
1415 | * You may obtain a copy of the License at
1416 | *
1417 | * http://www.apache.org/licenses/LICENSE-2.0
1418 | *
1419 | * Unless required by applicable law or agreed to in writing, software
1420 | * distributed under the License is distributed on an "AS IS" BASIS,
1421 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1422 | * See the License for the specific language governing permissions and
1423 | * limitations under the License.
1424 | * ======================================================== */
1425 |
1426 |
1427 | !function ($) {
1428 |
1429 | "use strict"; // jshint ;_;
1430 |
1431 |
1432 | /* TAB CLASS DEFINITION
1433 | * ==================== */
1434 |
1435 | var Tab = function ( element ) {
1436 | this.element = $(element)
1437 | }
1438 |
1439 | Tab.prototype = {
1440 |
1441 | constructor: Tab
1442 |
1443 | , show: function () {
1444 | var $this = this.element
1445 | , $ul = $this.closest('ul:not(.dropdown-menu)')
1446 | , selector = $this.attr('data-target')
1447 | , previous
1448 | , $target
1449 | , e
1450 |
1451 | if (!selector) {
1452 | selector = $this.attr('href')
1453 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1454 | }
1455 |
1456 | if ( $this.parent('li').hasClass('active') ) return
1457 |
1458 | previous = $ul.find('.active a').last()[0]
1459 |
1460 | e = $.Event('show', {
1461 | relatedTarget: previous
1462 | })
1463 |
1464 | $this.trigger(e)
1465 |
1466 | if (e.isDefaultPrevented()) return
1467 |
1468 | $target = $(selector)
1469 |
1470 | this.activate($this.parent('li'), $ul)
1471 | this.activate($target, $target.parent(), function () {
1472 | $this.trigger({
1473 | type: 'shown'
1474 | , relatedTarget: previous
1475 | })
1476 | })
1477 | }
1478 |
1479 | , activate: function ( element, container, callback) {
1480 | var $active = container.find('> .active')
1481 | , transition = callback
1482 | && $.support.transition
1483 | && $active.hasClass('fade')
1484 |
1485 | function next() {
1486 | $active
1487 | .removeClass('active')
1488 | .find('> .dropdown-menu > .active')
1489 | .removeClass('active')
1490 |
1491 | element.addClass('active')
1492 |
1493 | if (transition) {
1494 | element[0].offsetWidth // reflow for transition
1495 | element.addClass('in')
1496 | } else {
1497 | element.removeClass('fade')
1498 | }
1499 |
1500 | if ( element.parent('.dropdown-menu') ) {
1501 | element.closest('li.dropdown').addClass('active')
1502 | }
1503 |
1504 | callback && callback()
1505 | }
1506 |
1507 | transition ?
1508 | $active.one($.support.transition.end, next) :
1509 | next()
1510 |
1511 | $active.removeClass('in')
1512 | }
1513 | }
1514 |
1515 |
1516 | /* TAB PLUGIN DEFINITION
1517 | * ===================== */
1518 |
1519 | $.fn.tab = function ( option ) {
1520 | return this.each(function () {
1521 | var $this = $(this)
1522 | , data = $this.data('tab')
1523 | if (!data) $this.data('tab', (data = new Tab(this)))
1524 | if (typeof option == 'string') data[option]()
1525 | })
1526 | }
1527 |
1528 | $.fn.tab.Constructor = Tab
1529 |
1530 |
1531 | /* TAB DATA-API
1532 | * ============ */
1533 |
1534 | $(function () {
1535 | $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1536 | e.preventDefault()
1537 | $(this).tab('show')
1538 | })
1539 | })
1540 |
1541 | }(window.jQuery);/* =============================================================
1542 | * bootstrap-typeahead.js v2.0.4
1543 | * http://twitter.github.com/bootstrap/javascript.html#typeahead
1544 | * =============================================================
1545 | * Copyright 2012 Twitter, Inc.
1546 | *
1547 | * Licensed under the Apache License, Version 2.0 (the "License");
1548 | * you may not use this file except in compliance with the License.
1549 | * You may obtain a copy of the License at
1550 | *
1551 | * http://www.apache.org/licenses/LICENSE-2.0
1552 | *
1553 | * Unless required by applicable law or agreed to in writing, software
1554 | * distributed under the License is distributed on an "AS IS" BASIS,
1555 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1556 | * See the License for the specific language governing permissions and
1557 | * limitations under the License.
1558 | * ============================================================ */
1559 |
1560 |
1561 | !function($){
1562 |
1563 | "use strict"; // jshint ;_;
1564 |
1565 |
1566 | /* TYPEAHEAD PUBLIC CLASS DEFINITION
1567 | * ================================= */
1568 |
1569 | var Typeahead = function (element, options) {
1570 | this.$element = $(element)
1571 | this.options = $.extend({}, $.fn.typeahead.defaults, options)
1572 | this.matcher = this.options.matcher || this.matcher
1573 | this.sorter = this.options.sorter || this.sorter
1574 | this.highlighter = this.options.highlighter || this.highlighter
1575 | this.updater = this.options.updater || this.updater
1576 | this.$menu = $(this.options.menu).appendTo('body')
1577 | this.source = this.options.source
1578 | this.shown = false
1579 | this.listen()
1580 | }
1581 |
1582 | Typeahead.prototype = {
1583 |
1584 | constructor: Typeahead
1585 |
1586 | , select: function () {
1587 | var val = this.$menu.find('.active').attr('data-value')
1588 | this.$element
1589 | .val(this.updater(val))
1590 | .change()
1591 | return this.hide()
1592 | }
1593 |
1594 | , updater: function (item) {
1595 | return item
1596 | }
1597 |
1598 | , show: function () {
1599 | var pos = $.extend({}, this.$element.offset(), {
1600 | height: this.$element[0].offsetHeight
1601 | })
1602 |
1603 | this.$menu.css({
1604 | top: pos.top + pos.height
1605 | , left: pos.left
1606 | })
1607 |
1608 | this.$menu.show()
1609 | this.shown = true
1610 | return this
1611 | }
1612 |
1613 | , hide: function () {
1614 | this.$menu.hide()
1615 | this.shown = false
1616 | return this
1617 | }
1618 |
1619 | , lookup: function (event) {
1620 | var that = this
1621 | , items
1622 | , q
1623 |
1624 | this.query = this.$element.val()
1625 |
1626 | if (!this.query) {
1627 | return this.shown ? this.hide() : this
1628 | }
1629 |
1630 | items = $.grep(this.source, function (item) {
1631 | return that.matcher(item)
1632 | })
1633 |
1634 | items = this.sorter(items)
1635 |
1636 | if (!items.length) {
1637 | return this.shown ? this.hide() : this
1638 | }
1639 |
1640 | return this.render(items.slice(0, this.options.items)).show()
1641 | }
1642 |
1643 | , matcher: function (item) {
1644 | return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1645 | }
1646 |
1647 | , sorter: function (items) {
1648 | var beginswith = []
1649 | , caseSensitive = []
1650 | , caseInsensitive = []
1651 | , item
1652 |
1653 | while (item = items.shift()) {
1654 | if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1655 | else if (~item.indexOf(this.query)) caseSensitive.push(item)
1656 | else caseInsensitive.push(item)
1657 | }
1658 |
1659 | return beginswith.concat(caseSensitive, caseInsensitive)
1660 | }
1661 |
1662 | , highlighter: function (item) {
1663 | var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1664 | return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1665 | return '' + match + ' '
1666 | })
1667 | }
1668 |
1669 | , render: function (items) {
1670 | var that = this
1671 |
1672 | items = $(items).map(function (i, item) {
1673 | i = $(that.options.item).attr('data-value', item)
1674 | i.find('a').html(that.highlighter(item))
1675 | return i[0]
1676 | })
1677 |
1678 | items.first().addClass('active')
1679 | this.$menu.html(items)
1680 | return this
1681 | }
1682 |
1683 | , next: function (event) {
1684 | var active = this.$menu.find('.active').removeClass('active')
1685 | , next = active.next()
1686 |
1687 | if (!next.length) {
1688 | next = $(this.$menu.find('li')[0])
1689 | }
1690 |
1691 | next.addClass('active')
1692 | }
1693 |
1694 | , prev: function (event) {
1695 | var active = this.$menu.find('.active').removeClass('active')
1696 | , prev = active.prev()
1697 |
1698 | if (!prev.length) {
1699 | prev = this.$menu.find('li').last()
1700 | }
1701 |
1702 | prev.addClass('active')
1703 | }
1704 |
1705 | , listen: function () {
1706 | this.$element
1707 | .on('blur', $.proxy(this.blur, this))
1708 | .on('keypress', $.proxy(this.keypress, this))
1709 | .on('keyup', $.proxy(this.keyup, this))
1710 |
1711 | if ($.browser.webkit || $.browser.msie) {
1712 | this.$element.on('keydown', $.proxy(this.keypress, this))
1713 | }
1714 |
1715 | this.$menu
1716 | .on('click', $.proxy(this.click, this))
1717 | .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
1718 | }
1719 |
1720 | , keyup: function (e) {
1721 | switch(e.keyCode) {
1722 | case 40: // down arrow
1723 | case 38: // up arrow
1724 | break
1725 |
1726 | case 9: // tab
1727 | case 13: // enter
1728 | if (!this.shown) return
1729 | this.select()
1730 | break
1731 |
1732 | case 27: // escape
1733 | if (!this.shown) return
1734 | this.hide()
1735 | break
1736 |
1737 | default:
1738 | this.lookup()
1739 | }
1740 |
1741 | e.stopPropagation()
1742 | e.preventDefault()
1743 | }
1744 |
1745 | , keypress: function (e) {
1746 | if (!this.shown) return
1747 |
1748 | switch(e.keyCode) {
1749 | case 9: // tab
1750 | case 13: // enter
1751 | case 27: // escape
1752 | e.preventDefault()
1753 | break
1754 |
1755 | case 38: // up arrow
1756 | if (e.type != 'keydown') break
1757 | e.preventDefault()
1758 | this.prev()
1759 | break
1760 |
1761 | case 40: // down arrow
1762 | if (e.type != 'keydown') break
1763 | e.preventDefault()
1764 | this.next()
1765 | break
1766 | }
1767 |
1768 | e.stopPropagation()
1769 | }
1770 |
1771 | , blur: function (e) {
1772 | var that = this
1773 | setTimeout(function () { that.hide() }, 150)
1774 | }
1775 |
1776 | , click: function (e) {
1777 | e.stopPropagation()
1778 | e.preventDefault()
1779 | this.select()
1780 | }
1781 |
1782 | , mouseenter: function (e) {
1783 | this.$menu.find('.active').removeClass('active')
1784 | $(e.currentTarget).addClass('active')
1785 | }
1786 |
1787 | }
1788 |
1789 |
1790 | /* TYPEAHEAD PLUGIN DEFINITION
1791 | * =========================== */
1792 |
1793 | $.fn.typeahead = function (option) {
1794 | return this.each(function () {
1795 | var $this = $(this)
1796 | , data = $this.data('typeahead')
1797 | , options = typeof option == 'object' && option
1798 | if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
1799 | if (typeof option == 'string') data[option]()
1800 | })
1801 | }
1802 |
1803 | $.fn.typeahead.defaults = {
1804 | source: []
1805 | , items: 8
1806 | , menu: ''
1807 | , item: ' '
1808 | }
1809 |
1810 | $.fn.typeahead.Constructor = Typeahead
1811 |
1812 |
1813 | /* TYPEAHEAD DATA-API
1814 | * ================== */
1815 |
1816 | $(function () {
1817 | $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
1818 | var $this = $(this)
1819 | if ($this.data('typeahead')) return
1820 | e.preventDefault()
1821 | $this.typeahead($this.data())
1822 | })
1823 | })
1824 |
1825 | }(window.jQuery);
--------------------------------------------------------------------------------
/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap.js by @fat & @mdo
3 | * Copyright 2012 Twitter, Inc.
4 | * http://www.apache.org/licenses/LICENSE-2.0.txt
5 | */
6 | !function(a){a(function(){"use strict",a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=c,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(a){return a||(this.paused=!0),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j=a.Event("slide");this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c);e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():f.interval&&e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('
').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}"use strict";var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var e=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show)return c.show();clearTimeout(this.timeout),c.hoverState="in",this.timeout=setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},isHTML:function(a){return typeof a!="string"||a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(a)},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.isHTML(b)?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover",title:"",delay:0}}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.isHTML(b)?"html":"text"](b),a.find(".popover-content > *")[this.isHTML(c)?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:''})}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}"use strict",b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var b=a(this),c=b.data("target")||b.attr("href"),d=/^#\w/.test(c)&&a(c);return d&&c.length&&[[d.position().top,c]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu")&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}},a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a(function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active a").last()[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}},a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a(function(){a("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){return c.matcher(a)}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return""+b+" "})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},keypress:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.type!="keydown")break;a.preventDefault(),this.prev();break;case 40:if(a.type!="keydown")break;a.preventDefault(),this.next()}a.stopPropagation()},blur:function(a){var b=this;setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'',item:' '},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery);
--------------------------------------------------------------------------------
/logout.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/template/footer.php:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
17 |