├── README ├── api ├── modsec-status-config.pl └── modsec-status.pl ├── collector ├── modsec-tinydns-parser-config.pl └── modsec-tinydns-parser.pl ├── database-structure.sql └── static-html ├── ModSecurityLogo.png ├── images ├── animated-overlay.gif ├── ui-bg_flat_0_aaaaaa_40x100.png ├── ui-bg_flat_75_ffffff_40x100.png ├── ui-bg_glass_55_fbf9ee_1x400.png ├── ui-bg_glass_65_ffffff_1x400.png ├── ui-bg_glass_75_dadada_1x400.png ├── ui-bg_glass_75_e6e6e6_1x400.png ├── ui-bg_glass_95_fef1ec_1x400.png ├── ui-bg_highlight-soft_75_cccccc_1x100.png ├── ui-icons_222222_256x240.png ├── ui-icons_2e83ff_256x240.png ├── ui-icons_454545_256x240.png ├── ui-icons_888888_256x240.png └── ui-icons_cd0a0a_256x240.png ├── jquery-1.10.2.js ├── jquery-ui.css ├── jquery-ui.js ├── jquery.balloon.js ├── modsec-status-loading.gif ├── modsec-status-spider.png ├── modsec-status.css ├── modsec-status.html └── modsec-status.js /README: -------------------------------------------------------------------------------- 1 | 2 | ModSecurity status 3 | 4 | 5 | ModSecurity status is a mechanism to collect and display usage statistics of 6 | ModSecurity. It is divided into four main components: 7 | 8 | - WebSite: A rich html page that is responsable to show the utilization 9 | status in a user friendly way. 10 | 11 | - API: An api which is utilized by the WebSite component to retrieve 12 | data from our database. 13 | 14 | - Collector: Set of scripts responsable to parser tinydns log files and 15 | populate a database that can be comsumed by the API. 16 | 17 | - ModSecurity: Responsible to provide information about every instance of 18 | itself, using DNS queries. 19 | 20 | ModSecurity is not part of this repository, it is available under its own 21 | repository at: https://github.com/SpiderLabs/ModSecurity. The other three 22 | compoents lies on the same repository as that file. 23 | 24 | The WebSite and API componets are deployed under the official ModSecurity 25 | status page, public available at: 26 | 27 | http://status.modsecurity.org 28 | 29 | For more information about the stats mechanism, check ModSecurity wiki. 30 | FIXME: feed the wiki and place the url. 31 | 32 | -------------------------------------------------------------------------------- /api/modsec-status-config.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | 4 | our $mysql_dbi, $mysql_username, $mysql_password; 5 | 6 | $mysql_dbi = "dbi goes here"; 7 | $mysql_username = "username goes here"; 8 | $mysql_password = "password goes here"; 9 | 10 | 1; 11 | -------------------------------------------------------------------------------- /api/modsec-status.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use DBI; 4 | 5 | require "modsec-status-config.pl"; 6 | 7 | our $mysql_dbi, $mysql_username, $mysql_password; 8 | 9 | $dbh = DBI->connect($mysql_dbi, $mysql_username, $mysql_password) or die "Connection Error: $DBI::errstr\n"; 10 | 11 | my $uri = $ENV{'REQUEST_URI'}; 12 | my ($unique) = $uri =~m/(unique)/; 13 | my ($from, $to) = $uri =~ m/.*\/([\d+]+)\/([\d+]+)$/; 14 | 15 | my $sql; 16 | 17 | if ($unique) 18 | { 19 | $sql = "select ts,modsec,apache,apr,apr_loaded,pcre,pcre_loaded," . 20 | "lua,lua_loaded,libxml,libxml_loaded,host,latitude,longitude, ". 21 | "country,city,id,UNIX_TIMESTAMP(ts) from status where " . 22 | "ts >= FROM_UNIXTIME($from) and ts < FROM_UNIXTIME($to) " . 23 | "group by id order by ts ASC LIMIT 0, 20000"; 24 | } 25 | else 26 | { 27 | $sql = "select ts,modsec,apache,apr,apr_loaded,pcre,pcre_loaded," . 28 | "lua,lua_loaded,libxml,libxml_loaded,host,latitude,longitude, ". 29 | "country,city,id,UNIX_TIMESTAMP(ts) from status where " . 30 | "ts >= FROM_UNIXTIME($from) and ts < FROM_UNIXTIME($to) " . 31 | "order by ts ASC LIMIT 0, 20000;"; 32 | } 33 | 34 | $sth = $dbh->prepare($sql); 35 | $sth->execute or die "SQL Error: $DBI::errstr\n"; 36 | 37 | print "Content-type: application/json\n\n"; 38 | print "{\n"; 39 | print ' "time": {' . "\n"; 40 | print ' "from": "' . $from . '",' . "\n"; 41 | print ' "to": "' . $to . '"' . "\n"; 42 | print ' },' . "\n"; 43 | print ' "amount": ' . $sth->rows . ",\n"; 44 | print ' "results": [' . "\n"; 45 | $count = 0; 46 | 47 | while (@row = $sth->fetchrow_array) { 48 | print ' {' . "\n"; 49 | print ' "ts": "' . $row[0] . '"' . ",\n" if ($full); 50 | print ' "ts_epoch": "' . $row[17] . '"' . ",\n"; 51 | print ' "version": "' . $row[1] . '"' . ",\n"; 52 | print ' "installation_id": "' . $row[16] . '"' . ",\n" if ($full); 53 | print ' "apache": "' . $row[2] . '"' . ",\n" if ($full); 54 | print ' "apr": {' . "\n" if ($full); 55 | print ' "compiled": "' . $row[3] . '"' . ",\n" if ($full); 56 | print ' "running": "' . $row[4] . '"' . "\n" if ($full); 57 | print ' },' . "\n" if ($full); 58 | print ' "pcre": {' . "\n" if ($full); 59 | print ' "compiled": "' . $row[5] . '"' . ",\n" if ($full); 60 | print ' "running": "' . $row[6] . '"' . "\n" if ($full); 61 | print ' },' . "\n" if ($full); 62 | print ' "lua": {' . "\n" if ($full); 63 | print ' "compiled": "' . $row[7] . '"' . ",\n" if ($full); 64 | print ' "running": "' . $row[8] . '"' . "\n" if ($full); 65 | print ' },' . "\n" if ($full); 66 | print ' "libxml": {' . "\n" if ($full); 67 | print ' "compiled": "' . $row[9] . '"' . ",\n" if ($full); 68 | print ' "running": "' . $row[10] . '"' . "\n" if ($full); 69 | print ' },' . "\n" if ($full); 70 | print ' "dns_server": {' . "\n"; 71 | print ' "ip": "' . $row[11] . '"' . ",\n" if ($full); 72 | print ' "latitude": "' . $row[12] . '"' . ",\n"; 73 | print ' "longitude": "' . $row[13] . '"' . ",\n"; 74 | print ' "country": "' . $row[14] . '"' . ",\n" if (full); 75 | print ' "city": "' . $row[15] . '"' . "\n"; 76 | print ' }' . "\n"; 77 | $count++; 78 | if ($count == $sth->rows) { 79 | print ' }' . "\n"; 80 | } else { 81 | print ' },' . "\n"; 82 | } 83 | } 84 | 85 | print ' ]' . "\n"; 86 | print "}\n"; 87 | 88 | -------------------------------------------------------------------------------- /collector/modsec-tinydns-parser-config.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -p 2 | 3 | our $tail, $geo_lite_db, $mysql_dbi, $mysql_username, $mysql_password, $log_uri; 4 | 5 | $tail = "status.modsecurity.org"; 6 | $geo_lite_db = "/usr/local/apache/conf/GeoLiteCity.dat"; 7 | 8 | $mysql_dbi = "dbi:mysql:modsecurity_db_goes_here"; 9 | $mysql_username = "db_username_goes_here"; 10 | $mysql_password = "db_password_goes_here"; 11 | 12 | $log_uri = "/tmp/tinydns-parser-collector.txt"; 13 | 14 | 1; 15 | 16 | -------------------------------------------------------------------------------- /collector/modsec-tinydns-parser.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -p 2 | 3 | # tinydns log formatting utility 4 | # based on Faried Nawaz's logfile formatter for dnscache 5 | # based on Kenji Rikitake 29-JUL-2000 6 | # by zimmerle 26-Dez-2013 7 | 8 | use MIME::Base32 qw( RFC ); 9 | use Geo::IP; 10 | use DBI; 11 | 12 | require "modsec-tinydns-parser-config.pl"; 13 | 14 | our $tail, $geo_lite_db, $mysql_dbi, $mysql_username, $mysql_password, $log_uri; 15 | our @connection = ($mysql_dbi, $mysql_username, $mysql_password); 16 | 17 | my $gi = Geo::IP->open($geo_lite_db, GEOIP_STANDARD); 18 | my $dbh = DBI->connect_cached(@connection) or die "Connection Error: $DBI::errstr\n"; 19 | 20 | if ($log_uri) { 21 | open(LOG, ">>$log_uri" ) || die "Problems opening log file"; 22 | print LOG time . " Start!\n"; 23 | } 24 | 25 | s/\b([a-f0-9]{8})\b/join(".", unpack("C*", pack("H8", $1)))/eg; 26 | s/^(@[a-f0-9]+) \b([\d.]+):(\w+):(\w+) ([\+\-\I\/]) \b([a-f0-9]+) \b([-.=\w]+)\n/printQueryLine($1, $2,$3,$4,$5,$6,$7)/e; 27 | s/\b([\d.]+):(\w+):(\w+) ([\+\-\I\/]) \b([a-f0-9]+) \b([-.=\w]+)\n/printQueryLine('date', $1,$2,$3,$4,$5,$6)/e; 28 | 29 | sub escape { 30 | my ($str) = @_; 31 | $str =~ s/[^0-9a-fA-F.-]+//g; 32 | return $str; 33 | } 34 | 35 | sub printQueryLine { 36 | my ($date, $host, $port, $query_id, $flag, $query_type, $query) = @_; 37 | 38 | return if (!($query =~ m/$tail$/)); 39 | 40 | my $ret = $query; 41 | 42 | $ret =~ s/\d+\.$tail$//g; 43 | $ret =~ s/\.//g; 44 | $ret = MIME::Base32::decode(uc $ret); 45 | 46 | return if (!($ret =~ m/^[A-Za-z0-9-_,.)(\/ ]+$/)); 47 | my $l = time . ",$host,$ret"; 48 | my ($modsec, $apache, $apr, $pcre, $lua, $libxml, $install_id) = split(/,/, $ret); 49 | 50 | ($apr, $apr_loaded) = split(/\//, $apr); 51 | ($pcre, $pcre_loaded) = split(/\//, $pcre); 52 | ($lua, $lua_loaded) = split(/\//, $lua); 53 | ($libxml, $libxml_loaded) = split(/\//, $libxml); 54 | 55 | $modsec = escape($modsec); 56 | $apache = escape($apache); 57 | $apr = escape($apr); 58 | $apr_loaded = escape($apr_loaded); 59 | $pcre = escape($pcre); 60 | $pcre_loaded = escape($pcre_loaded); 61 | $lua = escape($lua); 62 | $lua_loaded = escape($lua_loaded); 63 | $libxml = escape($libxml); 64 | $libxml_loaded = escape($libxml_loaded); 65 | $install_id = escape($install_id); 66 | 67 | my $record, $latitude, $logitude, $country, $city; 68 | $record = $gi->record_by_addr($host); 69 | if ($record) 70 | { 71 | $latitude = $record->latitude; 72 | $longitude = $record->longitude; 73 | $country = $record->country_name; 74 | $city = $record->city; 75 | 76 | $country =~ s/\'/\\'/g; 77 | $city =~ s/\'/\\'/g; 78 | } 79 | 80 | my $sql = "insert into status (host, modsec, apache, apr, apr_loaded, pcre, ". 81 | "pcre_loaded, lua, lua_loaded, libxml, libxml_loaded, payload, " . 82 | "latitude, longitude, country, city, id) values ". 83 | "('$host', '$modsec', '$apache', '$apr', '$apr_loaded', " . 84 | "'$pcre', '$pcre_loaded', '$lua', '$lua_loaded', '$libxml', " . 85 | "'$libxml_loaded', '', '$latitude', '$longitude', " . 86 | "'$country', '$city', '$install_id')"; 87 | 88 | $dbh = DBI->connect_cached(@connection) or die "Connection Error: $DBI::errstr\n"; 89 | $sth = $dbh->prepare($sql); 90 | $sth->execute or die "Failed to insert: $DBI::errstr\n"; 91 | 92 | if ($log_uri) { 93 | print LOG "Adding: $sql\n"; 94 | } 95 | return "Adding: $sql\n"; 96 | } 97 | 98 | if ($log_uri) { 99 | close(LOG); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /database-structure.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Table structure for table `status` 3 | -- 4 | 5 | DROP TABLE IF EXISTS `status`; 6 | CREATE TABLE `status` ( 7 | `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 8 | `payload` varchar(400) DEFAULT NULL, 9 | `host` varchar(15) DEFAULT NULL, 10 | `modsec` varchar(15) DEFAULT NULL, 11 | `apache` varchar(15) DEFAULT NULL, 12 | `apr` varchar(15) DEFAULT NULL, 13 | `apr_loaded` varchar(15) DEFAULT NULL, 14 | `pcre` varchar(15) DEFAULT NULL, 15 | `pcre_loaded` varchar(15) DEFAULT NULL, 16 | `lua` varchar(15) DEFAULT NULL, 17 | `lua_loaded` varchar(15) DEFAULT NULL, 18 | `libxml` varchar(15) DEFAULT NULL, 19 | `libxml_loaded` varchar(15) DEFAULT NULL, 20 | `well_formated` int(1) DEFAULT '1', 21 | `latitude` varchar(14) DEFAULT NULL, 22 | `longitude` varchar(14) DEFAULT NULL, 23 | `country` varchar(20) DEFAULT NULL, 24 | `city` varchar(20) DEFAULT NULL, 25 | `id` varchar(40) DEFAULT NULL 26 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 27 | 28 | -------------------------------------------------------------------------------- /static-html/ModSecurityLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/ModSecurityLogo.png -------------------------------------------------------------------------------- /static-html/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/animated-overlay.gif -------------------------------------------------------------------------------- /static-html/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /static-html/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /static-html/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /static-html/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /static-html/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /static-html/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /static-html/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /static-html/jquery-ui.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.3 - 2013-05-03 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px 5 | * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ 6 | 7 | /* Layout helpers 8 | ----------------------------------*/ 9 | .ui-helper-hidden { 10 | display: none; 11 | } 12 | .ui-helper-hidden-accessible { 13 | border: 0; 14 | clip: rect(0 0 0 0); 15 | height: 1px; 16 | margin: -1px; 17 | overflow: hidden; 18 | padding: 0; 19 | position: absolute; 20 | width: 1px; 21 | } 22 | .ui-helper-reset { 23 | margin: 0; 24 | padding: 0; 25 | border: 0; 26 | outline: 0; 27 | line-height: 1.3; 28 | text-decoration: none; 29 | font-size: 100%; 30 | list-style: none; 31 | } 32 | .ui-helper-clearfix:before, 33 | .ui-helper-clearfix:after { 34 | content: ""; 35 | display: table; 36 | border-collapse: collapse; 37 | } 38 | .ui-helper-clearfix:after { 39 | clear: both; 40 | } 41 | .ui-helper-clearfix { 42 | min-height: 0; /* support: IE7 */ 43 | } 44 | .ui-helper-zfix { 45 | width: 100%; 46 | height: 100%; 47 | top: 0; 48 | left: 0; 49 | position: absolute; 50 | opacity: 0; 51 | filter:Alpha(Opacity=0); 52 | } 53 | 54 | .ui-front { 55 | z-index: 100; 56 | } 57 | 58 | 59 | /* Interaction Cues 60 | ----------------------------------*/ 61 | .ui-state-disabled { 62 | cursor: default !important; 63 | } 64 | 65 | 66 | /* Icons 67 | ----------------------------------*/ 68 | 69 | /* states and images */ 70 | .ui-icon { 71 | display: block; 72 | text-indent: -99999px; 73 | overflow: hidden; 74 | background-repeat: no-repeat; 75 | } 76 | 77 | 78 | /* Misc visuals 79 | ----------------------------------*/ 80 | 81 | /* Overlays */ 82 | .ui-widget-overlay { 83 | position: fixed; 84 | top: 0; 85 | left: 0; 86 | width: 100%; 87 | height: 100%; 88 | } 89 | .ui-accordion .ui-accordion-header { 90 | display: block; 91 | cursor: pointer; 92 | position: relative; 93 | margin-top: 2px; 94 | padding: .5em .5em .5em .7em; 95 | min-height: 0; /* support: IE7 */ 96 | } 97 | .ui-accordion .ui-accordion-icons { 98 | padding-left: 2.2em; 99 | } 100 | .ui-accordion .ui-accordion-noicons { 101 | padding-left: .7em; 102 | } 103 | .ui-accordion .ui-accordion-icons .ui-accordion-icons { 104 | padding-left: 2.2em; 105 | } 106 | .ui-accordion .ui-accordion-header .ui-accordion-header-icon { 107 | position: absolute; 108 | left: .5em; 109 | top: 50%; 110 | margin-top: -8px; 111 | } 112 | .ui-accordion .ui-accordion-content { 113 | padding: 1em 2.2em; 114 | border-top: 0; 115 | overflow: auto; 116 | } 117 | .ui-autocomplete { 118 | position: absolute; 119 | top: 0; 120 | left: 0; 121 | cursor: default; 122 | } 123 | .ui-button { 124 | display: inline-block; 125 | position: relative; 126 | padding: 0; 127 | line-height: normal; 128 | margin-right: .1em; 129 | cursor: pointer; 130 | vertical-align: middle; 131 | text-align: center; 132 | overflow: visible; /* removes extra width in IE */ 133 | } 134 | .ui-button, 135 | .ui-button:link, 136 | .ui-button:visited, 137 | .ui-button:hover, 138 | .ui-button:active { 139 | text-decoration: none; 140 | } 141 | /* to make room for the icon, a width needs to be set here */ 142 | .ui-button-icon-only { 143 | width: 2.2em; 144 | } 145 | /* button elements seem to need a little more width */ 146 | button.ui-button-icon-only { 147 | width: 2.4em; 148 | } 149 | .ui-button-icons-only { 150 | width: 3.4em; 151 | } 152 | button.ui-button-icons-only { 153 | width: 3.7em; 154 | } 155 | 156 | /* button text element */ 157 | .ui-button .ui-button-text { 158 | display: block; 159 | line-height: normal; 160 | } 161 | .ui-button-text-only .ui-button-text { 162 | padding: .4em 1em; 163 | } 164 | .ui-button-icon-only .ui-button-text, 165 | .ui-button-icons-only .ui-button-text { 166 | padding: .4em; 167 | text-indent: -9999999px; 168 | } 169 | .ui-button-text-icon-primary .ui-button-text, 170 | .ui-button-text-icons .ui-button-text { 171 | padding: .4em 1em .4em 2.1em; 172 | } 173 | .ui-button-text-icon-secondary .ui-button-text, 174 | .ui-button-text-icons .ui-button-text { 175 | padding: .4em 2.1em .4em 1em; 176 | } 177 | .ui-button-text-icons .ui-button-text { 178 | padding-left: 2.1em; 179 | padding-right: 2.1em; 180 | } 181 | /* no icon support for input elements, provide padding by default */ 182 | input.ui-button { 183 | padding: .4em 1em; 184 | } 185 | 186 | /* button icon element(s) */ 187 | .ui-button-icon-only .ui-icon, 188 | .ui-button-text-icon-primary .ui-icon, 189 | .ui-button-text-icon-secondary .ui-icon, 190 | .ui-button-text-icons .ui-icon, 191 | .ui-button-icons-only .ui-icon { 192 | position: absolute; 193 | top: 50%; 194 | margin-top: -8px; 195 | } 196 | .ui-button-icon-only .ui-icon { 197 | left: 50%; 198 | margin-left: -8px; 199 | } 200 | .ui-button-text-icon-primary .ui-button-icon-primary, 201 | .ui-button-text-icons .ui-button-icon-primary, 202 | .ui-button-icons-only .ui-button-icon-primary { 203 | left: .5em; 204 | } 205 | .ui-button-text-icon-secondary .ui-button-icon-secondary, 206 | .ui-button-text-icons .ui-button-icon-secondary, 207 | .ui-button-icons-only .ui-button-icon-secondary { 208 | right: .5em; 209 | } 210 | 211 | /* button sets */ 212 | .ui-buttonset { 213 | margin-right: 7px; 214 | } 215 | .ui-buttonset .ui-button { 216 | margin-left: 0; 217 | margin-right: -.3em; 218 | } 219 | 220 | /* workarounds */ 221 | /* reset extra padding in Firefox, see h5bp.com/l */ 222 | input.ui-button::-moz-focus-inner, 223 | button.ui-button::-moz-focus-inner { 224 | border: 0; 225 | padding: 0; 226 | } 227 | .ui-datepicker { 228 | width: 17em; 229 | padding: .2em .2em 0; 230 | display: none; 231 | } 232 | .ui-datepicker .ui-datepicker-header { 233 | position: relative; 234 | padding: .2em 0; 235 | } 236 | .ui-datepicker .ui-datepicker-prev, 237 | .ui-datepicker .ui-datepicker-next { 238 | position: absolute; 239 | top: 2px; 240 | width: 1.8em; 241 | height: 1.8em; 242 | } 243 | .ui-datepicker .ui-datepicker-prev-hover, 244 | .ui-datepicker .ui-datepicker-next-hover { 245 | top: 1px; 246 | } 247 | .ui-datepicker .ui-datepicker-prev { 248 | left: 2px; 249 | } 250 | .ui-datepicker .ui-datepicker-next { 251 | right: 2px; 252 | } 253 | .ui-datepicker .ui-datepicker-prev-hover { 254 | left: 1px; 255 | } 256 | .ui-datepicker .ui-datepicker-next-hover { 257 | right: 1px; 258 | } 259 | .ui-datepicker .ui-datepicker-prev span, 260 | .ui-datepicker .ui-datepicker-next span { 261 | display: block; 262 | position: absolute; 263 | left: 50%; 264 | margin-left: -8px; 265 | top: 50%; 266 | margin-top: -8px; 267 | } 268 | .ui-datepicker .ui-datepicker-title { 269 | margin: 0 2.3em; 270 | line-height: 1.8em; 271 | text-align: center; 272 | } 273 | .ui-datepicker .ui-datepicker-title select { 274 | font-size: 1em; 275 | margin: 1px 0; 276 | } 277 | .ui-datepicker select.ui-datepicker-month-year { 278 | width: 100%; 279 | } 280 | .ui-datepicker select.ui-datepicker-month, 281 | .ui-datepicker select.ui-datepicker-year { 282 | width: 49%; 283 | } 284 | .ui-datepicker table { 285 | width: 100%; 286 | font-size: .9em; 287 | border-collapse: collapse; 288 | margin: 0 0 .4em; 289 | } 290 | .ui-datepicker th { 291 | padding: .7em .3em; 292 | text-align: center; 293 | font-weight: bold; 294 | border: 0; 295 | } 296 | .ui-datepicker td { 297 | border: 0; 298 | padding: 1px; 299 | } 300 | .ui-datepicker td span, 301 | .ui-datepicker td a { 302 | display: block; 303 | padding: .2em; 304 | text-align: right; 305 | text-decoration: none; 306 | } 307 | .ui-datepicker .ui-datepicker-buttonpane { 308 | background-image: none; 309 | margin: .7em 0 0 0; 310 | padding: 0 .2em; 311 | border-left: 0; 312 | border-right: 0; 313 | border-bottom: 0; 314 | } 315 | .ui-datepicker .ui-datepicker-buttonpane button { 316 | float: right; 317 | margin: .5em .2em .4em; 318 | cursor: pointer; 319 | padding: .2em .6em .3em .6em; 320 | width: auto; 321 | overflow: visible; 322 | } 323 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { 324 | float: left; 325 | } 326 | 327 | /* with multiple calendars */ 328 | .ui-datepicker.ui-datepicker-multi { 329 | width: auto; 330 | } 331 | .ui-datepicker-multi .ui-datepicker-group { 332 | float: left; 333 | } 334 | .ui-datepicker-multi .ui-datepicker-group table { 335 | width: 95%; 336 | margin: 0 auto .4em; 337 | } 338 | .ui-datepicker-multi-2 .ui-datepicker-group { 339 | width: 50%; 340 | } 341 | .ui-datepicker-multi-3 .ui-datepicker-group { 342 | width: 33.3%; 343 | } 344 | .ui-datepicker-multi-4 .ui-datepicker-group { 345 | width: 25%; 346 | } 347 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, 348 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { 349 | border-left-width: 0; 350 | } 351 | .ui-datepicker-multi .ui-datepicker-buttonpane { 352 | clear: left; 353 | } 354 | .ui-datepicker-row-break { 355 | clear: both; 356 | width: 100%; 357 | font-size: 0; 358 | } 359 | 360 | /* RTL support */ 361 | .ui-datepicker-rtl { 362 | direction: rtl; 363 | } 364 | .ui-datepicker-rtl .ui-datepicker-prev { 365 | right: 2px; 366 | left: auto; 367 | } 368 | .ui-datepicker-rtl .ui-datepicker-next { 369 | left: 2px; 370 | right: auto; 371 | } 372 | .ui-datepicker-rtl .ui-datepicker-prev:hover { 373 | right: 1px; 374 | left: auto; 375 | } 376 | .ui-datepicker-rtl .ui-datepicker-next:hover { 377 | left: 1px; 378 | right: auto; 379 | } 380 | .ui-datepicker-rtl .ui-datepicker-buttonpane { 381 | clear: right; 382 | } 383 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { 384 | float: left; 385 | } 386 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, 387 | .ui-datepicker-rtl .ui-datepicker-group { 388 | float: right; 389 | } 390 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, 391 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { 392 | border-right-width: 0; 393 | border-left-width: 1px; 394 | } 395 | .ui-dialog { 396 | position: absolute; 397 | top: 0; 398 | left: 0; 399 | padding: .2em; 400 | outline: 0; 401 | } 402 | .ui-dialog .ui-dialog-titlebar { 403 | padding: .4em 1em; 404 | position: relative; 405 | } 406 | .ui-dialog .ui-dialog-title { 407 | float: left; 408 | margin: .1em 0; 409 | white-space: nowrap; 410 | width: 90%; 411 | overflow: hidden; 412 | text-overflow: ellipsis; 413 | } 414 | .ui-dialog .ui-dialog-titlebar-close { 415 | position: absolute; 416 | right: .3em; 417 | top: 50%; 418 | width: 21px; 419 | margin: -10px 0 0 0; 420 | padding: 1px; 421 | height: 20px; 422 | } 423 | .ui-dialog .ui-dialog-content { 424 | position: relative; 425 | border: 0; 426 | padding: .5em 1em; 427 | background: none; 428 | overflow: auto; 429 | } 430 | .ui-dialog .ui-dialog-buttonpane { 431 | text-align: left; 432 | border-width: 1px 0 0 0; 433 | background-image: none; 434 | margin-top: .5em; 435 | padding: .3em 1em .5em .4em; 436 | } 437 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { 438 | float: right; 439 | } 440 | .ui-dialog .ui-dialog-buttonpane button { 441 | margin: .5em .4em .5em 0; 442 | cursor: pointer; 443 | } 444 | .ui-dialog .ui-resizable-se { 445 | width: 12px; 446 | height: 12px; 447 | right: -5px; 448 | bottom: -5px; 449 | background-position: 16px 16px; 450 | } 451 | .ui-draggable .ui-dialog-titlebar { 452 | cursor: move; 453 | } 454 | .ui-menu { 455 | list-style: none; 456 | padding: 2px; 457 | margin: 0; 458 | display: block; 459 | outline: none; 460 | } 461 | .ui-menu .ui-menu { 462 | margin-top: -3px; 463 | position: absolute; 464 | } 465 | .ui-menu .ui-menu-item { 466 | margin: 0; 467 | padding: 0; 468 | width: 100%; 469 | /* support: IE10, see #8844 */ 470 | list-style-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); 471 | } 472 | .ui-menu .ui-menu-divider { 473 | margin: 5px -2px 5px -2px; 474 | height: 0; 475 | font-size: 0; 476 | line-height: 0; 477 | border-width: 1px 0 0 0; 478 | } 479 | .ui-menu .ui-menu-item a { 480 | text-decoration: none; 481 | display: block; 482 | padding: 2px .4em; 483 | line-height: 1.5; 484 | min-height: 0; /* support: IE7 */ 485 | font-weight: normal; 486 | } 487 | .ui-menu .ui-menu-item a.ui-state-focus, 488 | .ui-menu .ui-menu-item a.ui-state-active { 489 | font-weight: normal; 490 | margin: -1px; 491 | } 492 | 493 | .ui-menu .ui-state-disabled { 494 | font-weight: normal; 495 | margin: .4em 0 .2em; 496 | line-height: 1.5; 497 | } 498 | .ui-menu .ui-state-disabled a { 499 | cursor: default; 500 | } 501 | 502 | /* icon support */ 503 | .ui-menu-icons { 504 | position: relative; 505 | } 506 | .ui-menu-icons .ui-menu-item a { 507 | position: relative; 508 | padding-left: 2em; 509 | } 510 | 511 | /* left-aligned */ 512 | .ui-menu .ui-icon { 513 | position: absolute; 514 | top: .2em; 515 | left: .2em; 516 | } 517 | 518 | /* right-aligned */ 519 | .ui-menu .ui-menu-icon { 520 | position: static; 521 | float: right; 522 | } 523 | .ui-progressbar { 524 | height: 2em; 525 | text-align: left; 526 | overflow: hidden; 527 | } 528 | .ui-progressbar .ui-progressbar-value { 529 | margin: -1px; 530 | height: 100%; 531 | } 532 | .ui-progressbar .ui-progressbar-overlay { 533 | background: url("images/animated-overlay.gif"); 534 | height: 100%; 535 | filter: alpha(opacity=25); 536 | opacity: 0.25; 537 | } 538 | .ui-progressbar-indeterminate .ui-progressbar-value { 539 | background-image: none; 540 | } 541 | .ui-resizable { 542 | position: relative; 543 | } 544 | .ui-resizable-handle { 545 | position: absolute; 546 | font-size: 0.1px; 547 | display: block; 548 | } 549 | .ui-resizable-disabled .ui-resizable-handle, 550 | .ui-resizable-autohide .ui-resizable-handle { 551 | display: none; 552 | } 553 | .ui-resizable-n { 554 | cursor: n-resize; 555 | height: 7px; 556 | width: 100%; 557 | top: -5px; 558 | left: 0; 559 | } 560 | .ui-resizable-s { 561 | cursor: s-resize; 562 | height: 7px; 563 | width: 100%; 564 | bottom: -5px; 565 | left: 0; 566 | } 567 | .ui-resizable-e { 568 | cursor: e-resize; 569 | width: 7px; 570 | right: -5px; 571 | top: 0; 572 | height: 100%; 573 | } 574 | .ui-resizable-w { 575 | cursor: w-resize; 576 | width: 7px; 577 | left: -5px; 578 | top: 0; 579 | height: 100%; 580 | } 581 | .ui-resizable-se { 582 | cursor: se-resize; 583 | width: 12px; 584 | height: 12px; 585 | right: 1px; 586 | bottom: 1px; 587 | } 588 | .ui-resizable-sw { 589 | cursor: sw-resize; 590 | width: 9px; 591 | height: 9px; 592 | left: -5px; 593 | bottom: -5px; 594 | } 595 | .ui-resizable-nw { 596 | cursor: nw-resize; 597 | width: 9px; 598 | height: 9px; 599 | left: -5px; 600 | top: -5px; 601 | } 602 | .ui-resizable-ne { 603 | cursor: ne-resize; 604 | width: 9px; 605 | height: 9px; 606 | right: -5px; 607 | top: -5px; 608 | } 609 | .ui-selectable-helper { 610 | position: absolute; 611 | z-index: 100; 612 | border: 1px dotted black; 613 | } 614 | .ui-slider { 615 | position: relative; 616 | text-align: left; 617 | } 618 | .ui-slider .ui-slider-handle { 619 | position: absolute; 620 | z-index: 2; 621 | width: 1.2em; 622 | height: 1.2em; 623 | cursor: default; 624 | } 625 | .ui-slider .ui-slider-range { 626 | position: absolute; 627 | z-index: 1; 628 | font-size: .7em; 629 | display: block; 630 | border: 0; 631 | background-position: 0 0; 632 | } 633 | 634 | /* For IE8 - See #6727 */ 635 | .ui-slider.ui-state-disabled .ui-slider-handle, 636 | .ui-slider.ui-state-disabled .ui-slider-range { 637 | filter: inherit; 638 | } 639 | 640 | .ui-slider-horizontal { 641 | height: .8em; 642 | } 643 | .ui-slider-horizontal .ui-slider-handle { 644 | top: -.3em; 645 | margin-left: -.6em; 646 | } 647 | .ui-slider-horizontal .ui-slider-range { 648 | top: 0; 649 | height: 100%; 650 | } 651 | .ui-slider-horizontal .ui-slider-range-min { 652 | left: 0; 653 | } 654 | .ui-slider-horizontal .ui-slider-range-max { 655 | right: 0; 656 | } 657 | 658 | .ui-slider-vertical { 659 | width: .8em; 660 | height: 100px; 661 | } 662 | .ui-slider-vertical .ui-slider-handle { 663 | left: -.3em; 664 | margin-left: 0; 665 | margin-bottom: -.6em; 666 | } 667 | .ui-slider-vertical .ui-slider-range { 668 | left: 0; 669 | width: 100%; 670 | } 671 | .ui-slider-vertical .ui-slider-range-min { 672 | bottom: 0; 673 | } 674 | .ui-slider-vertical .ui-slider-range-max { 675 | top: 0; 676 | } 677 | .ui-spinner { 678 | position: relative; 679 | display: inline-block; 680 | overflow: hidden; 681 | padding: 0; 682 | vertical-align: middle; 683 | } 684 | .ui-spinner-input { 685 | border: none; 686 | background: none; 687 | color: inherit; 688 | padding: 0; 689 | margin: .2em 0; 690 | vertical-align: middle; 691 | margin-left: .4em; 692 | margin-right: 22px; 693 | } 694 | .ui-spinner-button { 695 | width: 16px; 696 | height: 50%; 697 | font-size: .5em; 698 | padding: 0; 699 | margin: 0; 700 | text-align: center; 701 | position: absolute; 702 | cursor: default; 703 | display: block; 704 | overflow: hidden; 705 | right: 0; 706 | } 707 | /* more specificity required here to overide default borders */ 708 | .ui-spinner a.ui-spinner-button { 709 | border-top: none; 710 | border-bottom: none; 711 | border-right: none; 712 | } 713 | /* vertical centre icon */ 714 | .ui-spinner .ui-icon { 715 | position: absolute; 716 | margin-top: -8px; 717 | top: 50%; 718 | left: 0; 719 | } 720 | .ui-spinner-up { 721 | top: 0; 722 | } 723 | .ui-spinner-down { 724 | bottom: 0; 725 | } 726 | 727 | /* TR overrides */ 728 | .ui-spinner .ui-icon-triangle-1-s { 729 | /* need to fix icons sprite */ 730 | background-position: -65px -16px; 731 | } 732 | .ui-tabs { 733 | position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ 734 | padding: .2em; 735 | } 736 | .ui-tabs .ui-tabs-nav { 737 | margin: 0; 738 | padding: .2em .2em 0; 739 | } 740 | .ui-tabs .ui-tabs-nav li { 741 | list-style: none; 742 | float: left; 743 | position: relative; 744 | top: 0; 745 | margin: 1px .2em 0 0; 746 | border-bottom-width: 0; 747 | padding: 0; 748 | white-space: nowrap; 749 | } 750 | .ui-tabs .ui-tabs-nav li a { 751 | float: left; 752 | padding: .5em 1em; 753 | text-decoration: none; 754 | } 755 | .ui-tabs .ui-tabs-nav li.ui-tabs-active { 756 | margin-bottom: -1px; 757 | padding-bottom: 1px; 758 | } 759 | .ui-tabs .ui-tabs-nav li.ui-tabs-active a, 760 | .ui-tabs .ui-tabs-nav li.ui-state-disabled a, 761 | .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { 762 | cursor: text; 763 | } 764 | .ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ 765 | .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { 766 | cursor: pointer; 767 | } 768 | .ui-tabs .ui-tabs-panel { 769 | display: block; 770 | border-width: 0; 771 | padding: 1em 1.4em; 772 | background: none; 773 | } 774 | .ui-tooltip { 775 | padding: 8px; 776 | position: absolute; 777 | z-index: 9999; 778 | max-width: 300px; 779 | -webkit-box-shadow: 0 0 5px #aaa; 780 | box-shadow: 0 0 5px #aaa; 781 | } 782 | body .ui-tooltip { 783 | border-width: 2px; 784 | } 785 | 786 | /* Component containers 787 | ----------------------------------*/ 788 | .ui-widget { 789 | font-family: Verdana,Arial,sans-serif; 790 | font-size: 1.1em; 791 | } 792 | .ui-widget .ui-widget { 793 | font-size: 1em; 794 | } 795 | .ui-widget input, 796 | .ui-widget select, 797 | .ui-widget textarea, 798 | .ui-widget button { 799 | font-family: Verdana,Arial,sans-serif; 800 | font-size: 1em; 801 | } 802 | .ui-widget-content { 803 | border: 1px solid #aaaaaa; 804 | background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; 805 | color: #222222; 806 | } 807 | .ui-widget-content a { 808 | color: #222222; 809 | } 810 | .ui-widget-header { 811 | border: 1px solid #aaaaaa; 812 | background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; 813 | color: #222222; 814 | font-weight: bold; 815 | } 816 | .ui-widget-header a { 817 | color: #222222; 818 | } 819 | 820 | /* Interaction states 821 | ----------------------------------*/ 822 | .ui-state-default, 823 | .ui-widget-content .ui-state-default, 824 | .ui-widget-header .ui-state-default { 825 | border: 1px solid #d3d3d3; 826 | background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; 827 | font-weight: normal; 828 | color: #555555; 829 | } 830 | .ui-state-default a, 831 | .ui-state-default a:link, 832 | .ui-state-default a:visited { 833 | color: #555555; 834 | text-decoration: none; 835 | } 836 | .ui-state-hover, 837 | .ui-widget-content .ui-state-hover, 838 | .ui-widget-header .ui-state-hover, 839 | .ui-state-focus, 840 | .ui-widget-content .ui-state-focus, 841 | .ui-widget-header .ui-state-focus { 842 | border: 1px solid #999999; 843 | background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; 844 | font-weight: normal; 845 | color: #212121; 846 | } 847 | .ui-state-hover a, 848 | .ui-state-hover a:hover, 849 | .ui-state-hover a:link, 850 | .ui-state-hover a:visited { 851 | color: #212121; 852 | text-decoration: none; 853 | } 854 | .ui-state-active, 855 | .ui-widget-content .ui-state-active, 856 | .ui-widget-header .ui-state-active { 857 | border: 1px solid #aaaaaa; 858 | background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; 859 | font-weight: normal; 860 | color: #212121; 861 | } 862 | .ui-state-active a, 863 | .ui-state-active a:link, 864 | .ui-state-active a:visited { 865 | color: #212121; 866 | text-decoration: none; 867 | } 868 | 869 | /* Interaction Cues 870 | ----------------------------------*/ 871 | .ui-state-highlight, 872 | .ui-widget-content .ui-state-highlight, 873 | .ui-widget-header .ui-state-highlight { 874 | border: 1px solid #fcefa1; 875 | background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; 876 | color: #363636; 877 | } 878 | .ui-state-highlight a, 879 | .ui-widget-content .ui-state-highlight a, 880 | .ui-widget-header .ui-state-highlight a { 881 | color: #363636; 882 | } 883 | .ui-state-error, 884 | .ui-widget-content .ui-state-error, 885 | .ui-widget-header .ui-state-error { 886 | border: 1px solid #cd0a0a; 887 | background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; 888 | color: #cd0a0a; 889 | } 890 | .ui-state-error a, 891 | .ui-widget-content .ui-state-error a, 892 | .ui-widget-header .ui-state-error a { 893 | color: #cd0a0a; 894 | } 895 | .ui-state-error-text, 896 | .ui-widget-content .ui-state-error-text, 897 | .ui-widget-header .ui-state-error-text { 898 | color: #cd0a0a; 899 | } 900 | .ui-priority-primary, 901 | .ui-widget-content .ui-priority-primary, 902 | .ui-widget-header .ui-priority-primary { 903 | font-weight: bold; 904 | } 905 | .ui-priority-secondary, 906 | .ui-widget-content .ui-priority-secondary, 907 | .ui-widget-header .ui-priority-secondary { 908 | opacity: .7; 909 | filter:Alpha(Opacity=70); 910 | font-weight: normal; 911 | } 912 | .ui-state-disabled, 913 | .ui-widget-content .ui-state-disabled, 914 | .ui-widget-header .ui-state-disabled { 915 | opacity: .35; 916 | filter:Alpha(Opacity=35); 917 | background-image: none; 918 | } 919 | .ui-state-disabled .ui-icon { 920 | filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ 921 | } 922 | 923 | /* Icons 924 | ----------------------------------*/ 925 | 926 | /* states and images */ 927 | .ui-icon { 928 | width: 16px; 929 | height: 16px; 930 | } 931 | .ui-icon, 932 | .ui-widget-content .ui-icon { 933 | background-image: url(images/ui-icons_222222_256x240.png); 934 | } 935 | .ui-widget-header .ui-icon { 936 | background-image: url(images/ui-icons_222222_256x240.png); 937 | } 938 | .ui-state-default .ui-icon { 939 | background-image: url(images/ui-icons_888888_256x240.png); 940 | } 941 | .ui-state-hover .ui-icon, 942 | .ui-state-focus .ui-icon { 943 | background-image: url(images/ui-icons_454545_256x240.png); 944 | } 945 | .ui-state-active .ui-icon { 946 | background-image: url(images/ui-icons_454545_256x240.png); 947 | } 948 | .ui-state-highlight .ui-icon { 949 | background-image: url(images/ui-icons_2e83ff_256x240.png); 950 | } 951 | .ui-state-error .ui-icon, 952 | .ui-state-error-text .ui-icon { 953 | background-image: url(images/ui-icons_cd0a0a_256x240.png); 954 | } 955 | 956 | /* positioning */ 957 | .ui-icon-blank { background-position: 16px 16px; } 958 | .ui-icon-carat-1-n { background-position: 0 0; } 959 | .ui-icon-carat-1-ne { background-position: -16px 0; } 960 | .ui-icon-carat-1-e { background-position: -32px 0; } 961 | .ui-icon-carat-1-se { background-position: -48px 0; } 962 | .ui-icon-carat-1-s { background-position: -64px 0; } 963 | .ui-icon-carat-1-sw { background-position: -80px 0; } 964 | .ui-icon-carat-1-w { background-position: -96px 0; } 965 | .ui-icon-carat-1-nw { background-position: -112px 0; } 966 | .ui-icon-carat-2-n-s { background-position: -128px 0; } 967 | .ui-icon-carat-2-e-w { background-position: -144px 0; } 968 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 969 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 970 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 971 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 972 | .ui-icon-triangle-1-s { background-position: -64px -16px; } 973 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 974 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 975 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 976 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 977 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 978 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 979 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 980 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 981 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 982 | .ui-icon-arrow-1-s { background-position: -64px -32px; } 983 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 984 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 985 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 986 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 987 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 988 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 989 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 990 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 991 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 992 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 993 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 994 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } 995 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 996 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 997 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 998 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 999 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 1000 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 1001 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 1002 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 1003 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 1004 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 1005 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 1006 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 1007 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 1008 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 1009 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 1010 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 1011 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 1012 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 1013 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 1014 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 1015 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 1016 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 1017 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 1018 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 1019 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 1020 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 1021 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 1022 | .ui-icon-arrow-4 { background-position: 0 -80px; } 1023 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 1024 | .ui-icon-extlink { background-position: -32px -80px; } 1025 | .ui-icon-newwin { background-position: -48px -80px; } 1026 | .ui-icon-refresh { background-position: -64px -80px; } 1027 | .ui-icon-shuffle { background-position: -80px -80px; } 1028 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 1029 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 1030 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 1031 | .ui-icon-folder-open { background-position: -16px -96px; } 1032 | .ui-icon-document { background-position: -32px -96px; } 1033 | .ui-icon-document-b { background-position: -48px -96px; } 1034 | .ui-icon-note { background-position: -64px -96px; } 1035 | .ui-icon-mail-closed { background-position: -80px -96px; } 1036 | .ui-icon-mail-open { background-position: -96px -96px; } 1037 | .ui-icon-suitcase { background-position: -112px -96px; } 1038 | .ui-icon-comment { background-position: -128px -96px; } 1039 | .ui-icon-person { background-position: -144px -96px; } 1040 | .ui-icon-print { background-position: -160px -96px; } 1041 | .ui-icon-trash { background-position: -176px -96px; } 1042 | .ui-icon-locked { background-position: -192px -96px; } 1043 | .ui-icon-unlocked { background-position: -208px -96px; } 1044 | .ui-icon-bookmark { background-position: -224px -96px; } 1045 | .ui-icon-tag { background-position: -240px -96px; } 1046 | .ui-icon-home { background-position: 0 -112px; } 1047 | .ui-icon-flag { background-position: -16px -112px; } 1048 | .ui-icon-calendar { background-position: -32px -112px; } 1049 | .ui-icon-cart { background-position: -48px -112px; } 1050 | .ui-icon-pencil { background-position: -64px -112px; } 1051 | .ui-icon-clock { background-position: -80px -112px; } 1052 | .ui-icon-disk { background-position: -96px -112px; } 1053 | .ui-icon-calculator { background-position: -112px -112px; } 1054 | .ui-icon-zoomin { background-position: -128px -112px; } 1055 | .ui-icon-zoomout { background-position: -144px -112px; } 1056 | .ui-icon-search { background-position: -160px -112px; } 1057 | .ui-icon-wrench { background-position: -176px -112px; } 1058 | .ui-icon-gear { background-position: -192px -112px; } 1059 | .ui-icon-heart { background-position: -208px -112px; } 1060 | .ui-icon-star { background-position: -224px -112px; } 1061 | .ui-icon-link { background-position: -240px -112px; } 1062 | .ui-icon-cancel { background-position: 0 -128px; } 1063 | .ui-icon-plus { background-position: -16px -128px; } 1064 | .ui-icon-plusthick { background-position: -32px -128px; } 1065 | .ui-icon-minus { background-position: -48px -128px; } 1066 | .ui-icon-minusthick { background-position: -64px -128px; } 1067 | .ui-icon-close { background-position: -80px -128px; } 1068 | .ui-icon-closethick { background-position: -96px -128px; } 1069 | .ui-icon-key { background-position: -112px -128px; } 1070 | .ui-icon-lightbulb { background-position: -128px -128px; } 1071 | .ui-icon-scissors { background-position: -144px -128px; } 1072 | .ui-icon-clipboard { background-position: -160px -128px; } 1073 | .ui-icon-copy { background-position: -176px -128px; } 1074 | .ui-icon-contact { background-position: -192px -128px; } 1075 | .ui-icon-image { background-position: -208px -128px; } 1076 | .ui-icon-video { background-position: -224px -128px; } 1077 | .ui-icon-script { background-position: -240px -128px; } 1078 | .ui-icon-alert { background-position: 0 -144px; } 1079 | .ui-icon-info { background-position: -16px -144px; } 1080 | .ui-icon-notice { background-position: -32px -144px; } 1081 | .ui-icon-help { background-position: -48px -144px; } 1082 | .ui-icon-check { background-position: -64px -144px; } 1083 | .ui-icon-bullet { background-position: -80px -144px; } 1084 | .ui-icon-radio-on { background-position: -96px -144px; } 1085 | .ui-icon-radio-off { background-position: -112px -144px; } 1086 | .ui-icon-pin-w { background-position: -128px -144px; } 1087 | .ui-icon-pin-s { background-position: -144px -144px; } 1088 | .ui-icon-play { background-position: 0 -160px; } 1089 | .ui-icon-pause { background-position: -16px -160px; } 1090 | .ui-icon-seek-next { background-position: -32px -160px; } 1091 | .ui-icon-seek-prev { background-position: -48px -160px; } 1092 | .ui-icon-seek-end { background-position: -64px -160px; } 1093 | .ui-icon-seek-start { background-position: -80px -160px; } 1094 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 1095 | .ui-icon-seek-first { background-position: -80px -160px; } 1096 | .ui-icon-stop { background-position: -96px -160px; } 1097 | .ui-icon-eject { background-position: -112px -160px; } 1098 | .ui-icon-volume-off { background-position: -128px -160px; } 1099 | .ui-icon-volume-on { background-position: -144px -160px; } 1100 | .ui-icon-power { background-position: 0 -176px; } 1101 | .ui-icon-signal-diag { background-position: -16px -176px; } 1102 | .ui-icon-signal { background-position: -32px -176px; } 1103 | .ui-icon-battery-0 { background-position: -48px -176px; } 1104 | .ui-icon-battery-1 { background-position: -64px -176px; } 1105 | .ui-icon-battery-2 { background-position: -80px -176px; } 1106 | .ui-icon-battery-3 { background-position: -96px -176px; } 1107 | .ui-icon-circle-plus { background-position: 0 -192px; } 1108 | .ui-icon-circle-minus { background-position: -16px -192px; } 1109 | .ui-icon-circle-close { background-position: -32px -192px; } 1110 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 1111 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 1112 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 1113 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 1114 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 1115 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 1116 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 1117 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 1118 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 1119 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 1120 | .ui-icon-circle-check { background-position: -208px -192px; } 1121 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 1122 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 1123 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 1124 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 1125 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 1126 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 1127 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 1128 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 1129 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 1130 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 1131 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 1132 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 1133 | 1134 | 1135 | /* Misc visuals 1136 | ----------------------------------*/ 1137 | 1138 | /* Corner radius */ 1139 | .ui-corner-all, 1140 | .ui-corner-top, 1141 | .ui-corner-left, 1142 | .ui-corner-tl { 1143 | border-top-left-radius: 4px; 1144 | } 1145 | .ui-corner-all, 1146 | .ui-corner-top, 1147 | .ui-corner-right, 1148 | .ui-corner-tr { 1149 | border-top-right-radius: 4px; 1150 | } 1151 | .ui-corner-all, 1152 | .ui-corner-bottom, 1153 | .ui-corner-left, 1154 | .ui-corner-bl { 1155 | border-bottom-left-radius: 4px; 1156 | } 1157 | .ui-corner-all, 1158 | .ui-corner-bottom, 1159 | .ui-corner-right, 1160 | .ui-corner-br { 1161 | border-bottom-right-radius: 4px; 1162 | } 1163 | 1164 | /* Overlays */ 1165 | .ui-widget-overlay { 1166 | background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; 1167 | opacity: .3; 1168 | filter: Alpha(Opacity=30); 1169 | } 1170 | .ui-widget-shadow { 1171 | margin: -8px 0 0 -8px; 1172 | padding: 8px; 1173 | background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; 1174 | opacity: .3; 1175 | filter: Alpha(Opacity=30); 1176 | border-radius: 8px; 1177 | } 1178 | -------------------------------------------------------------------------------- /static-html/jquery.balloon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hover balloon on elements without css and images. 3 | * 4 | * Copyright (c) 2011 Hayato Takenaka 5 | * Dual licensed under the MIT and GPL licenses: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * http://www.gnu.org/licenses/gpl.html 8 | * @author: Hayato Takenaka (http://urin.take-uma.net) 9 | * @version: 0.3.0 - 2012/02/25 10 | **/ 11 | ;(function($) { 12 | //----------------------------------------------------------------------------- 13 | // Private 14 | //----------------------------------------------------------------------------- 15 | // Helper for meta programming 16 | var Meta = {}; 17 | Meta.pos = $.extend(["top", "bottom", "left", "right"], {camel: ["Top", "Bottom", "Left", "Right"]}); 18 | Meta.size = $.extend(["height", "width"], {camel: ["Height", "Width"]}); 19 | Meta.getRelativeNames = function(position) { 20 | var idx = { 21 | pos: { 22 | o: position, // origin 23 | f: (position % 2 == 0) ? position + 1 : position - 1, // faced 24 | p1: (position % 2 == 0) ? position : position - 1, 25 | p2: (position % 2 == 0) ? position + 1 : position, 26 | c1: (position < 2) ? 2 : 0, 27 | c2: (position < 2) ? 3 : 1 28 | }, 29 | size: { 30 | p: (position < 2) ? 0 : 1, // parallel 31 | c: (position < 2) ? 1 : 0 // cross 32 | } 33 | }; 34 | var names = {}; 35 | for(var m1 in idx) { 36 | if(!names[m1]) names[m1] = {}; 37 | for(var m2 in idx[m1]) { 38 | names[m1][m2] = Meta[m1][idx[m1][m2]]; 39 | if(!names.camel) names.camel = {}; 40 | if(!names.camel[m1]) names.camel[m1] = {}; 41 | names.camel[m1][m2] = Meta[m1].camel[idx[m1][m2]]; 42 | } 43 | } 44 | names.isTopLeft = (names.pos.o == names.pos.p1); 45 | return names; 46 | }; 47 | 48 | // Helper class to handle position and size as numerical pixels. 49 | function NumericalBoxElement() { this.initialize.apply(this, arguments); } 50 | (function() { 51 | // Method factories 52 | var Methods = { 53 | setBorder: function(pos, isVertical) { 54 | return function(value) { 55 | this.$.css("border-" + pos.toLowerCase() + "-width", value + "px"); 56 | this["border" + pos] = value; 57 | return (this.isActive) ? digitalize(this, isVertical) : this; 58 | } 59 | }, 60 | setPosition: function(pos, isVertical) { 61 | return function(value) { 62 | this.$.css(pos.toLowerCase(), value + "px"); 63 | this[pos.toLowerCase()] = value; 64 | return (this.isActive) ? digitalize(this, isVertical) : this; 65 | } 66 | } 67 | }; 68 | 69 | NumericalBoxElement.prototype = { 70 | initialize: function($element) { 71 | this.$ = $element; 72 | $.extend(true, this, this.$.offset(), {center: {}, inner: {center: {}}}); 73 | for(var i = 0; i < Meta.pos.length; i++) { 74 | this["border" + Meta.pos.camel[i]] = parseInt(this.$.css("border-" + Meta.pos[i] + "-width")) || 0; 75 | } 76 | this.active(); 77 | }, 78 | active: function() { this.isActive = true; digitalize(this); return this; }, 79 | inactive: function() { this.isActive = false; return this; } 80 | }; 81 | for(var i = 0; i < Meta.pos.length; i++) { 82 | NumericalBoxElement.prototype["setBorder" + Meta.pos.camel[i]] = Methods.setBorder(Meta.pos.camel[i], (i < 2)); 83 | if(i % 2 == 0) 84 | NumericalBoxElement.prototype["set" + Meta.pos.camel[i]] = Methods.setPosition(Meta.pos.camel[i], (i < 2)); 85 | } 86 | 87 | function digitalize(box, isVertical) { 88 | if(isVertical == undefined) { digitalize(box, true); return digitalize(box, false); } 89 | var m = Meta.getRelativeNames((isVertical) ? 0 : 2); 90 | box[m.size.p] = box.$["outer" + m.camel.size.p](); 91 | box[m.pos.f] = box[m.pos.o] + box[m.size.p]; 92 | box.center[m.pos.o] = box[m.pos.o] + box[m.size.p] / 2; 93 | box.inner[m.pos.o] = box[m.pos.o] + box["border" + m.camel.pos.o]; 94 | box.inner[m.size.p] = box.$["inner" + m.camel.size.p](); 95 | box.inner[m.pos.f] = box.inner[m.pos.o] + box.inner[m.size.p]; 96 | box.inner.center[m.pos.o] = box.inner[m.pos.f] + box.inner[m.size.p] / 2; 97 | return box; 98 | } 99 | })(); 100 | 101 | // Adjust position of balloon body 102 | function makeupBalloon($target, $balloon, options) { 103 | $balloon.stop(true, true); 104 | var outerTip, innerTip, 105 | initTipStyle = {position: "absolute", height: "0", width: "0", border: "solid 0 transparent"}, 106 | target = new NumericalBoxElement($target), 107 | balloon = new NumericalBoxElement($balloon); 108 | balloon.setTop(-options.offsetY 109 | + ((options.position && options.position.indexOf("top") >= 0) ? target.top - balloon.height 110 | : ((options.position && options.position.indexOf("bottom") >= 0) ? target.bottom 111 | : target.center.top - balloon.height / 2))); 112 | balloon.setLeft(options.offsetX 113 | + ((options.position && options.position.indexOf("left") >= 0) ? target.left - balloon.width 114 | : ((options.position && options.position.indexOf("right") >= 0) ? target.right 115 | : target.center.left - balloon.width / 2))); 116 | if(options.tipSize > 0) { 117 | // Add hidden balloon tips into balloon body. 118 | if($balloon.data("outerTip")) { $balloon.data("outerTip").remove(); $balloon.removeData("outerTip"); } 119 | if($balloon.data("innerTip")) { $balloon.data("innerTip").remove(); $balloon.removeData("innerTip"); } 120 | outerTip = new NumericalBoxElement($("
").css(initTipStyle).appendTo($balloon)); 121 | innerTip = new NumericalBoxElement($("
").css(initTipStyle).appendTo($balloon)); 122 | // Make tip triangle, adjust position of tips. 123 | var m; 124 | for(var i = 0; i < Meta.pos.length; i++) { 125 | m = Meta.getRelativeNames(i); 126 | if(balloon.center[m.pos.c1] >= target[m.pos.c1] && 127 | balloon.center[m.pos.c1] <= target[m.pos.c2]) { 128 | if(i % 2 == 0) { 129 | if(balloon[m.pos.o] >= target[m.pos.o] && balloon[m.pos.f] >= target[m.pos.f]) break; 130 | } else { 131 | if(balloon[m.pos.o] <= target[m.pos.o] && balloon[m.pos.f] <= target[m.pos.f]) break; 132 | } 133 | } 134 | m = null; 135 | } 136 | if(m) { 137 | balloon["set" + m.camel.pos.p1] 138 | (balloon[m.pos.p1] + ((m.isTopLeft) ? 1 : -1) * (options.tipSize - balloon["border" + m.camel.pos.o])); 139 | makeTip(balloon, outerTip, m, options.tipSize, $balloon.css("border-" + m.pos.o + "-color")); 140 | makeTip(balloon, innerTip, m, options.tipSize - 2 * balloon["border" + m.camel.pos.o], $balloon.css("background-color")); 141 | $balloon.data("outerTip", outerTip.$).data("innerTip", innerTip.$); 142 | } else { 143 | $.each([outerTip.$, innerTip.$], function() { this.remove(); }); 144 | } 145 | } 146 | // Make up balloon tip. 147 | function makeTip(balloon, tip, m, tipSize, color) { 148 | var len = Math.round(tipSize / 1.7320508); 149 | tip.inactive() 150 | ["setBorder" + m.camel.pos.f](tipSize) 151 | ["setBorder" + m.camel.pos.c1](len) 152 | ["setBorder" + m.camel.pos.c2](len) 153 | ["set" + m.camel.pos.p1]((m.isTopLeft) ? -tipSize : balloon.inner[m.size.p]) 154 | ["set" + m.camel.pos.c1](balloon.inner[m.size.c] / 2 - len) 155 | .active() 156 | .$.css("border-" + m.pos.f + "-color", color); 157 | } 158 | } 159 | 160 | // True if the event comes from the target or balloon. 161 | function isValidTargetEvent($target, e) { 162 | var b = $target.data("balloon") && $target.data("balloon").get(0); 163 | return !(b && (b == e.relatedTarget || $.contains(b, e.relatedTarget))); 164 | } 165 | 166 | //----------------------------------------------------------------------------- 167 | // Public 168 | //----------------------------------------------------------------------------- 169 | $.fn.balloon = function(options) { 170 | options = $.extend(true, {}, $.balloon.defaults, options); 171 | return this.one("mouseenter", function(e) { 172 | var $target = $(this), t = this; 173 | var $balloon = $target.unbind("mouseenter", arguments.callee) 174 | .showBalloon(options).mouseenter(function(e) { 175 | isValidTargetEvent($target, e) && $target.showBalloon(); 176 | }).data("balloon"); 177 | if($balloon) { 178 | $balloon.mouseleave(function(e) { 179 | if(t == e.relatedTarget || $.contains(t, e.relatedTarget)) return; 180 | $target.hideBalloon(); 181 | }).mouseenter(function(e) { $target.showBalloon(); }); 182 | } 183 | }).mouseleave(function(e) { 184 | var $target = $(this); 185 | isValidTargetEvent($target, e) && $target.hideBalloon(); 186 | }); 187 | }; 188 | 189 | $.fn.showBalloon = function(options) { 190 | var $target, $balloon, offTimer; 191 | if(!$.balloon.defaults.css) $.balloon.defaults.css = {}; 192 | if(options || !this.data("options")) 193 | this.data("options", $.extend(true, {}, $.balloon.defaults, options)); 194 | options = this.data("options"); 195 | return this.each(function() { 196 | $target = $(this); 197 | (offTimer = $target.data("offTimer")) && clearTimeout(offTimer); 198 | var contents = $.isFunction(options.contents) 199 | ? options.contents() 200 | : (options.contents || $target.attr("title")); 201 | var isNew = !($balloon = $target.data("balloon")); 202 | if(isNew) $balloon = $("
").append(contents); 203 | if(!options.url && (!$balloon || $balloon.html() == "")) return; 204 | if(!isNew && contents && contents != $balloon.html()) $balloon.empty().append(contents); 205 | $target.removeAttr("title"); 206 | if(options.url) { 207 | $balloon.load($.isFunction(options.url) ? options.url(this) : options.url, function(res, sts, xhr) { 208 | if(options.ajaxComplete) options.ajaxComplete(res, sts, xhr); 209 | makeupBalloon($target, $balloon, options); 210 | }); 211 | } 212 | if(isNew) { 213 | $balloon 214 | .addClass(options.classname) 215 | .css(options.css) 216 | .css({visibility: "hidden", position: "absolute"}) 217 | .appendTo("body"); 218 | $target.data("balloon", $balloon); 219 | makeupBalloon($target, $balloon, options); 220 | $balloon.hide().css("visibility", "visible"); 221 | } else { 222 | makeupBalloon($target, $balloon, options); 223 | } 224 | $target.data("onTimer", setTimeout(function() { 225 | if(options.showAnimation) { 226 | options.showAnimation.apply($balloon.stop(true, true), [options.showDuration]); 227 | } else { 228 | $balloon.show(options.showDuration, function() { 229 | if(this.style.removeAttribute) { this.style.removeAttribute("filter"); } 230 | }); 231 | } 232 | }, options.delay)); 233 | }); 234 | }; 235 | 236 | $.fn.hideBalloon = function() { 237 | var options = this.data("options"), onTimer, offTimer; 238 | return this.each(function() { 239 | var $target = $(this); 240 | (onTimer = $target.data("onTimer")) && clearTimeout(onTimer); 241 | (offTimer = $target.data("offTimer")) && clearTimeout(offTimer); 242 | $target.data("offTimer", setTimeout(function() { 243 | var $balloon = $target.data("balloon"); 244 | if(options.hideAnimation) { 245 | $balloon && options.hideAnimation.apply($balloon.stop(true, true), [options.hideDuration]); 246 | } else { 247 | $balloon && $balloon.stop(true, true).hide(options.hideDuration); 248 | } 249 | }, 250 | options.minLifetime)); 251 | }); 252 | }; 253 | 254 | $.balloon = { 255 | defaults: { 256 | contents: null, url: null, ajaxComplete: null, classname: null, 257 | position: "top", offsetX: 0, offsetY: 0, tipSize: 12, 258 | delay: 0, minLifetime: 200, 259 | showDuration: 100, showAnimation: null, 260 | hideDuration: 80, hideAnimation: function(d) { this.fadeOut(d); }, 261 | css: { 262 | minWidth : "20px", 263 | padding : "5px", 264 | color : "#000000", 265 | backgroundColor: "#ffffff", 266 | opacity : 1, //$.support.opacity) ? "0.85" : null, 267 | zIndex : "6", 268 | } 269 | } 270 | }; 271 | })(jQuery); 272 | -------------------------------------------------------------------------------- /static-html/modsec-status-loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/modsec-status-loading.gif -------------------------------------------------------------------------------- /static-html/modsec-status-spider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpiderLabs/ModSecurity-status/fbaa6ce8652553429729dc6e1b4201199a4da04a/static-html/modsec-status-spider.png -------------------------------------------------------------------------------- /static-html/modsec-status.css: -------------------------------------------------------------------------------- 1 | /* 2 | * ModSecurity, http://www.modsecurity.org/ 3 | * Copyright (c) 2004-2014 Trustwave Holdings, Inc. (http://www.trustwave.com/) 4 | * 5 | * You may not use this file except in compliance with 6 | * the License.  You may obtain a copy of the License at 7 | * 8 | *     http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * If any of the files related to licensing are missing or if you have any 11 | * other questions related to licensing please contact Trustwave Holdings, Inc. 12 | * directly using the email address security@modsecurity.org. 13 | * 14 | */ 15 | 16 | html,body,#map-canvas { 17 | height:100%; 18 | overflow:hidden; 19 | background-image:url(modsec-status-spider.png); 20 | background-repeat:repeat; 21 | font-family:Verdana, Arial; 22 | font-size:10pt; 23 | margin:0; 24 | padding:0; 25 | } 26 | 27 | #panel { 28 | position:absolute; 29 | top:5px; 30 | left:50%; 31 | margin-left:-180px; 32 | z-index:5; 33 | background-color:#fff; 34 | border:1px solid #999; 35 | padding:5px; 36 | } 37 | 38 | #modSecLogo { 39 | width:250px; 40 | margin:10px 14px 7px; 41 | } 42 | 43 | #headerBoxes { 44 | position:absolute; 45 | z-index:5; 46 | top:10px; 47 | left:100px; 48 | height:100%; 49 | overflow:hidden; 50 | pointer-events:none; 51 | } 52 | 53 | #headerBg { 54 | outline:none; 55 | overflow:hidden; 56 | background:#fff; 57 | border-radius:2px; 58 | box-shadow:0 2px 6px rgba(0,0,0,0.3),0 -3px 8px rgba(0,0,0,0.2); 59 | box-sizing:border-box; 60 | -moz-box-sizing:border-box; 61 | -webkit-box-sizing:border-box; 62 | -webkit-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 63 | -moz-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 64 | -ms-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 65 | -o-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 66 | transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 67 | margin:10px; 68 | } 69 | 70 | #extraInfo { 71 | outline:none; 72 | overflow:hidden; 73 | background:#fff; 74 | border-radius:2px; 75 | box-shadow:0 2px 6px rgba(0,0,0,0.3),0 -3px 8px rgba(0,0,0,0.2); 76 | box-sizing:border-box; 77 | -moz-box-sizing:border-box; 78 | -webkit-box-sizing:border-box; 79 | -webkit-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 80 | -moz-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 81 | -ms-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 82 | -o-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 83 | transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 84 | margin:14px 10px 10px; 85 | padding:14px; 86 | } 87 | 88 | #options { 89 | position:absolute; 90 | background-color:#FFF; 91 | bottom:20px; 92 | outline:none; 93 | overflow:hidden; 94 | border-radius:2px; 95 | box-shadow:0 2px 6px rgba(0,0,0,0.3),0 -3px 8px rgba(0,0,0,0.2); 96 | box-sizing:border-box; 97 | -moz-box-sizing:border-box; 98 | -webkit-box-sizing:border-box; 99 | -webkit-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 100 | -moz-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 101 | -ms-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 102 | -o-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 103 | transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 104 | font-size:8pt; 105 | pointer-events:auto; 106 | margin:10px; 107 | padding:14px; 108 | } 109 | 110 | #header { 111 | top:0; 112 | left:0; 113 | right:0; 114 | bottom:0; 115 | } 116 | 117 | #amountOfData { 118 | margin-bottom:5px; 119 | margin-left:0; 120 | font-size:10pt; 121 | } 122 | 123 | #amountOfDataII { 124 | margin-left:0; 125 | } 126 | 127 | #loadingGif { 128 | margin-top:0; 129 | width:15px; 130 | } 131 | 132 | #legend { 133 | position:absolute; 134 | bottom:20px; 135 | right:-20px; 136 | z-index:5; 137 | border:0 solid #999; 138 | opacity:1; 139 | font-size:6pt; 140 | padding:5px; 141 | } 142 | 143 | #min { 144 | padding-top:1px; 145 | width:10px; 146 | float:right; 147 | opacity:0; 148 | margin:0; 149 | } 150 | 151 | #colorBar { 152 | width:100px; 153 | height:10px; 154 | float:right; 155 | border-radius:2px; 156 | vertical-align:middle; 157 | border:1px solid #999; 158 | margin:0; 159 | } 160 | 161 | #max { 162 | padding-top:1px; 163 | width:15px; 164 | float:right; 165 | opacity:0; 166 | margin:0 0 0 8px; 167 | } 168 | 169 | #range { 170 | font-size:6pt; 171 | margin:0; 172 | padding:0; 173 | } 174 | 175 | #slider-range { 176 | margin:4px; 177 | padding:0; 178 | } 179 | 180 | #first-register { 181 | float:left; 182 | } 183 | 184 | #last-register { 185 | float:right; 186 | } 187 | 188 | #consoleLoading { 189 | font-size:7pt; 190 | height:10px; 191 | } 192 | 193 | #ignore { 194 | margin-top:10px; 195 | } 196 | 197 | #lhebs { 198 | font-size:6pt; 199 | font-color:#000; 200 | text-align:center; 201 | border-radius:2px; 202 | box-shadow:0 2px 6px rgba(0,0,0,0.3),0 -3px 8px rgba(0,0,0,0.2); 203 | box-sizing:border-box; 204 | -moz-box-sizing:border-box; 205 | -webkit-box-sizing:border-box; 206 | -webkit-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 207 | -moz-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 208 | -ms-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 209 | -o-transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 210 | transition:background-color 200ms cubic-bezier(0.52,0,0.48,1); 211 | } 212 | -------------------------------------------------------------------------------- /static-html/modsec-status.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ModSecurity status map 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 22 |
23 |
24 |
 
25 |
 
26 |
27 |
28 |
29 |
30 |
20 Jan 2013
31 |
Now
32 |
33 |
34 | 35 | Ignore records without city information 36 | 37 | 38 | Show only unique IDs 39 | 40 |
41 |
42 |
43 |

44 |
45 |

0

46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /static-html/modsec-status.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ModSecurity for Apache 2.x, http://www.modsecurity.org/ 3 | * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) 4 | * 5 | * You may not use this file except in compliance with 6 | * the License.  You may obtain a copy of the License at 7 | * 8 | *     http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * If any of the files related to licensing are missing or if you have any 11 | * other questions related to licensing please contact Trustwave Holdings, Inc. 12 | * directly using the email address security@modsecurity.org. 13 | */ 14 | 15 | 16 | var url_base = "http://status.modsecurity.org/"; 17 | var api_path = "api/"; 18 | var api_uri = url_base + api_path; 19 | 20 | 21 | var gradient = [ 22 | 'rgba(0, 255, 255, 0)', 23 | 'rgba(255, 2, 2, 1)', 24 | 'rgba(255, 91, 1, 1)', 25 | 'rgba(255, 161, 2, 1)', 26 | 'rgba(255, 168, 0, 1)', 27 | 'rgba(255, 241, 0, 1)', 28 | 'rgba(201, 253, 7, 1)', 29 | 'rgba(129, 227, 16, 1)', 30 | 'rgba(31, 188, 39, 1)', 31 | 'rgba(0, 186, 89, 1)', 32 | 'rgba(0, 211, 152, 1)', 33 | 'rgba(0, 234, 245, 1)', 34 | 'rgba(1, 179, 241, 1)', 35 | 'rgba(0, 94, 194, 1)', 36 | 'rgba(2, 22, 135, 1)', 37 | 'rgba(7, 7, 81, 1)' 38 | ] 39 | 40 | var lastFetchedEpoch = 0; 41 | var map, pointarray, heatmap; 42 | var heatmapData = []; 43 | var redrawMapTimeout = 0; 44 | var updateTimeOut = 0; 45 | var preciseOnly = true; 46 | var uniqueIds = true; 47 | var firstItem = getEpoch(); 48 | var firstQueryEver = 1385690874 - 10 * 24 * 60 * 60; 49 | var uiValues = [0, 0]; 50 | var balloonDate = 0; 51 | 52 | 53 | // Detect which browser prefix to use for the specified CSS value 54 | // (e.g., background-image: -moz-linear-gradient(...); 55 | // background-image: -o-linear-gradient(...); etc). 56 | // [from: http://stackoverflow.com/questions/15071062/using-javascript-to-edit-css-gradient] 57 | function getCssValuePrefix(name, value) 58 | { 59 | var prefixes = ['', '-o-', '-ms-', '-moz-', '-webkit-']; 60 | // Create a temporary DOM object for testing 61 | var dom = document.createElement('div'); 62 | for (var i = 0; i < prefixes.length; i++) 63 | { 64 | // Attempt to set the style 65 | dom.style[name] = prefixes[i] + value; 66 | // Detect if the style was successfully set 67 | if (dom.style[name]) 68 | { 69 | return prefixes[i]; 70 | } 71 | dom.style[name] = ''; // Reset the style 72 | } 73 | } 74 | 75 | function processJson(json) 76 | { 77 | $.each(json.results, function (i, item) 78 | { 79 | setTimeout(function () 80 | { 81 | processItem(item); 82 | }, 0) 83 | }); 84 | updateTimeOut = setTimeout(function () 85 | { 86 | fetchJsonData(lastFetchedEpoch, getEpoch()); 87 | }, 10000); 88 | } 89 | 90 | function showLoading() 91 | { 92 | $("#consoleLoading") 93 | .fadeTo("slow", 0, function () 94 | { 95 | $("#consoleLoading") 96 | .empty(); 97 | $("#consoleLoading") 98 | .append( 99 | 'Retrieving data...    ' 100 | ); 101 | $("#consoleLoading") 102 | .fadeTo("slow", 1, function () {}); 103 | }); 104 | } 105 | 106 | function hideLoading() 107 | { 108 | var data = new Date(); 109 | $("#consoleLoading") 110 | .fadeTo("fast", 0, function () 111 | { 112 | $("#consoleLoading") 113 | .empty(); 114 | $("#consoleLoading") 115 | .append('Updated at ' + data.getHours() + ':' + data.getMinutes() + 116 | ':' + data.getSeconds()); 117 | $("#consoleLoading") 118 | .fadeTo("fast", 1, function () {}); 119 | }); 120 | $("#legend") 121 | .fadeTo("slow", 1, function () {}); 122 | } 123 | 124 | function fetchJsonData(from, to) 125 | { 126 | lastFetchedEpoch = to; 127 | showLoading(); 128 | var unique = ""; 129 | 130 | //console.log("fetch: " + from + " to: " + to); 131 | //console.log(api_uri + "/" + from + "/" + to + ""); 132 | if (uniqueIds == true) 133 | { 134 | unique = "/unique/"; 135 | } 136 | else 137 | { 138 | unique = "/"; 139 | } 140 | 141 | var apiData = $.getJSON(api_uri + unique + "/" + from + "/" + to + "", function () 142 | { 143 | console.log("success"); 144 | }) 145 | .done(function (json) 146 | { 147 | processJson(json); 148 | }) 149 | .fail(function (jqxhr, textStatus, error) 150 | { 151 | var err = textStatus + ", " + error; 152 | console.log("Request Failed: " + err); 153 | }) 154 | .always(function () 155 | { 156 | console.log("complete"); 157 | hideLoading(); 158 | }); 159 | } 160 | 161 | function redrawMap() 162 | { 163 | clearTimeout(redrawMapTimeout); 164 | redrawMapTimeout = setTimeout(function () 165 | { 166 | redrawMapNow(); 167 | }, 500); 168 | } 169 | 170 | function redrawMapNow(amount) 171 | { 172 | //console.log("Paiting map."); 173 | var pointArray = new google.maps.MVCArray(); 174 | if (preciseOnly) 175 | { 176 | for (var i = 0; i < heatmapData.length; i++) 177 | if (heatmapData[i][1] != '') 178 | pointArray.push(heatmapData[i][0]); 179 | } 180 | else 181 | { 182 | for (var i = 0; i < heatmapData.length; i++) 183 | pointArray.push(heatmapData[i][0]); 184 | } 185 | if (!heatmap) 186 | { 187 | heatmap = new google.maps.visualization.HeatmapLayer( 188 | { 189 | data: pointArray, 190 | map: map 191 | }); 192 | changeGradient(); 193 | changeRadius(); 194 | } 195 | else 196 | { 197 | heatmap.setData(pointArray); 198 | } 199 | $("#amountOfData") 200 | .fadeTo("slow", 0, function () 201 | { 202 | $("#amountOfData") 203 | .empty(); 204 | $("#amountOfData") 205 | .append("" + pointArray.getLength() + 206 | " initialization records"); 207 | $("#amountOfData") 208 | .fadeTo("slow", 1, function () {}); 209 | }); 210 | 211 | uiValues[0] = lastFetchedEpoch - 1 * 24 * 60 * 60; 212 | uiValues[1] = lastFetchedEpoch; 213 | 214 | $("#slider-range") 215 | .slider( 216 | { 217 | values: [uiValues[0], uiValues[1]] 218 | }) 219 | $("#range-first-date") 220 | .empty(); 221 | f = new Date((lastFetchedEpoch - 1 * 24 * 60 * 60) * 1000); 222 | d = f.getFullYear() + "-" + f.getMonth() + "-" + f.getDay() + "
" + f.getHours() + 223 | ":" + f.getMinutes() + ":" + f.getSeconds(); 224 | $("#range-first-date") 225 | .append("From " + d); 226 | balloonDate = "From " + d; 227 | showB(balloonDate); 228 | $(window) 229 | .resize(function () 230 | { 231 | showB(); 232 | }); 233 | } 234 | 235 | function processItem(item) 236 | { 237 | // console.log('Item: ' + item.dns_server.ip); 238 | // append_to_log_console(item);a 239 | if (item.ts < firstItem) 240 | { 241 | firstItem = item.ts; 242 | } 243 | draw_on_map(item); 244 | redrawMap(); 245 | } 246 | 247 | function append_to_log_console(item) 248 | { 249 | //alert(new Date(item.ts).getTime()/1000); 250 | $('#consoleContent') 251 | .append('

' + item.ts + ' ModSecurity version ' + item.version + 252 | ' started at ' + item.dns_server.country + ' using ' + item.apache) 253 | var elem = document.getElementById('consoleContent'); 254 | elem.scrollTop = elem.scrollHeight; 255 | } 256 | 257 | function draw_on_map(item) 258 | { 259 | heatmapData.push([new google.maps.LatLng(item.dns_server.latitude, item.dns_server 260 | .longitude), item.dns_server.city]); 261 | } 262 | 263 | function showB(content) 264 | { 265 | if (content == null || content == '') 266 | { 267 | content = balloonDate; 268 | } 269 | $('#slider-handle') 270 | .showBalloon( 271 | { 272 | position: "top", 273 | contents: content, 274 | tipSize: 24 275 | }); 276 | } 277 | 278 | function hideB() 279 | { 280 | $('#slider-handle') 281 | .hideBalloon(); 282 | } 283 | 284 | function initialize() 285 | { 286 | // Style from: http://stackoverflow.com/questions/4003578/google-maps-in-grayscale 287 | var stylez = [ 288 | { 289 | featureType: "all", 290 | elementType: "all", 291 | stylers: [ 292 | { 293 | saturation: -70 294 | }] 295 | }]; 296 | var mapOptions = { 297 | zoom: 2, 298 | minZoom: 2, 299 | center: new google.maps.LatLng(0, 0), 300 | mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'tehgrayz'] 301 | //disableDefaultUI: true 302 | }; 303 | map = new google.maps.Map(document.getElementById('map-canvas'), 304 | mapOptions); 305 | var mapType = new google.maps.StyledMapType(stylez, 306 | { 307 | name: "Grayscale" 308 | }); 309 | map.mapTypes.set('tehgrayz', mapType); 310 | map.setMapTypeId('tehgrayz'); 311 | $("#slider-range") 312 | .slider( 313 | { 314 | range: true, 315 | min: getEpoch() - (15 * 24 * 60 * 60), 316 | max: getEpoch(), 317 | values: [getEpoch() - (5 * 24 * 60 * 60), getEpoch()], 318 | step: 1, 319 | disabled: false, 320 | animate: "slow", 321 | start: function (event, ui) 322 | { 323 | hideB(); 324 | }, 325 | stop: function (event, ui) 326 | { 327 | $("#slider-range") 328 | .slider( 329 | { 330 | disabled: true 331 | }); 332 | 333 | showB("Time selection is not implemented yet..."); 334 | 335 | setTimeout(function () 336 | { 337 | hideB(); 338 | 339 | setTimeout(function () { 340 | var a = $("#slider-range") 341 | .slider( 342 | { 343 | values: [uiValues[0], uiValues[1]] 344 | }) 345 | }, 500); 346 | 347 | setTimeout(function () { 348 | showB(null); 349 | $("#slider-range") 350 | .slider( 351 | { 352 | disabled: false 353 | }); 354 | }, 900); 355 | }, 3000) 356 | return false; 357 | } 358 | }); 359 | 360 | /* Legend div */ 361 | var gradientPrefix = getCssValuePrefix('backgroundImage', 362 | 'linear-gradient(left, #fff, #fff)'); 363 | var back = gradientPrefix + 'linear-gradient(' + 'left'; 364 | for (var i = 0; i < gradient.length; i++) 365 | { 366 | back = back + "," + gradient[i] + " " + (100 * (i + 1)) / gradient.length + 367 | "%"; 368 | } 369 | back = back + ")"; 370 | 371 | document.getElementById('colorBar') 372 | .style.backgroundImage = back; 373 | 374 | f = new Date(firstQueryEver * 1000); 375 | d = f.getFullYear() + "-" + f.getMonth() + "-" + f.getDay(); 376 | $('#first-register') 377 | .empty(); 378 | $('#first-register') 379 | .append(d); 380 | fetchJsonData(0, getEpoch()); 381 | $('#max') 382 | .append('??'); 383 | 384 | 385 | $('#ignore').click(function () { 386 | setPreciseOnly(); 387 | }); 388 | $('#uniq').click(function () { 389 | setUniqueIds(); 390 | }); 391 | 392 | } 393 | 394 | function getEpoch() 395 | { 396 | return Math.round(new Date() 397 | .getTime() / 1000); 398 | } 399 | 400 | function setPreciseOnly() 401 | { 402 | showLoading(); 403 | preciseOnly = preciseOnly ? false : true; 404 | redrawMap(); 405 | } 406 | 407 | function setUniqueIds() 408 | { 409 | clearTimeout(updateTimeOut); 410 | showLoading(); 411 | heatmapData = []; 412 | uniqueIds = uniqueIds ? false : true; 413 | fetchJsonData(firstQueryEver, getEpoch()); 414 | } 415 | 416 | function toggleHeatmap() 417 | { 418 | heatmap.setMap(heatmap.getMap() ? null : map); 419 | } 420 | 421 | function changeGradient() 422 | { 423 | heatmap.set('gradient', heatmap.get('gradient') ? null : gradient); 424 | } 425 | 426 | function changeRadius() 427 | { 428 | heatmap.set('radius', heatmap.get('radius') ? null : 10); 429 | } 430 | 431 | function changeOpacity() 432 | { 433 | heatmap.set('opacity', heatmap.get('opacity') ? null : 0.2); 434 | } 435 | 436 | 437 | google.maps.event.addDomListener(window, 'load', initialize); 438 | --------------------------------------------------------------------------------