mirror of https://github.com/prometheus/prometheus
Julien
3 months ago
committed by
GitHub
68 changed files with 3 additions and 38767 deletions
@ -1,82 +0,0 @@
|
||||
{{/* vim: set ft=html: */}} |
||||
|
||||
{{/* Navbar, should be passed . */}} |
||||
{{ define "navbar" }} |
||||
<nav class="navbar fixed-top navbar-expand-sm navbar-dark bg-dark"> |
||||
<div class="container-fluid"> |
||||
<!-- Brand and toggle get grouped for better mobile display --> |
||||
<div class="navbar-header"> |
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false" aria-controls="navbar-nav" aria-label="toggle navigation"> |
||||
<span class="navbar-toggler-icon"></span> |
||||
|
||||
|
||||
|
||||
|
||||
</button> |
||||
<a class="navbar-brand" href="{{ pathPrefix }}/">Prometheus</a> |
||||
</div> |
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> |
||||
<ul class="nav navbar-nav"> |
||||
<li class="nav-item"><a class="nav-link" href="{{ pathPrefix }}/alerts">Alerts</a></li> |
||||
<li class="nav-item"><a class="nav-link" href="https://www.pagerduty.com/">PagerDuty</a></li> |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
</nav> |
||||
{{ end }} |
||||
|
||||
{{/* LHS menu, should be passed . */}} |
||||
{{ define "menu" }} |
||||
<div class="prom_lhs_menu row"> |
||||
<nav class="col-md-2 md-block bg-dark sidebar prom_lhs_menu_nav"> |
||||
<div class="sidebar-sticky"> |
||||
<ul class="nav flex-column"> |
||||
|
||||
{{ template "_menuItem" (args . "index.html.example" "Overview") }} |
||||
|
||||
{{ if query "up{job='node'}" }} |
||||
{{ template "_menuItem" (args . "node.html" "Node") }} |
||||
{{ if match "^node" .Path }} |
||||
{{ if .Params.instance }} |
||||
<ul> |
||||
<li {{ if eq .Path "node-overview.html" }}class="prom_lhs_menu_selected nav-item"{{ end }}> |
||||
<a class="nav-link" href="node-overview.html?instance={{ .Params.instance }}">{{ reReplaceAll "(.*?://)([^:/]+?)(:\\d+)?/.*" "$2" .Params.instance }}</a> |
||||
</li> |
||||
<ul> |
||||
<li {{ if eq .Path "node-cpu.html" }}class="prom_lhs_menu_selected nav-item"{{ end }}> |
||||
<a class="nav-link" href="node-cpu.html?instance={{ .Params.instance }}">CPU</a> |
||||
</li> |
||||
<li {{ if eq .Path "node-disk.html" }}class="prom_lhs_menu_selected nav-item"{{ end }}> |
||||
<a class="nav-link" href="node-disk.html?instance={{ .Params.instance }}">Disk</a> |
||||
</li> |
||||
</ul> |
||||
</ul> |
||||
{{ end }} |
||||
{{ end }} |
||||
{{ end }} |
||||
|
||||
{{ if query "up{job='prometheus'}" }} |
||||
{{ template "_menuItem" (args . "prometheus.html" "Prometheus") }} |
||||
{{ if match "^prometheus" .Path }} |
||||
{{ if .Params.instance }} |
||||
<ul> |
||||
<li {{ if eq .Path "prometheus-overview.html" }}class="prom_lhs_menu_selected nav-item"{{ end }}> |
||||
<a class="nav-link" href="prometheus-overview.html?instance={{ .Params.instance }}">{{.Params.instance }}</a> |
||||
</li> |
||||
</ul> |
||||
{{ end }} |
||||
{{ end }} |
||||
{{ end }} |
||||
|
||||
</ul> |
||||
</div> |
||||
</nav> |
||||
</div> |
||||
{{ end }} |
||||
|
||||
{{/* Helper, pass (args . path name) */}} |
||||
{{ define "_menuItem" }} |
||||
<li {{ if eq .arg0.Path .arg1 }} class="prom_lhs_menu_selected nav-item" {{ end }}><a class="nav-link" href="{{ .arg1 }}">{{ .arg2 }}</a></li> |
||||
{{ end }} |
||||
|
@ -1,138 +0,0 @@
|
||||
{{/* vim: set ft=html: */}} |
||||
{{/* Load Prometheus console library JS/CSS. Should go in <head> */}} |
||||
{{ define "prom_console_head" }} |
||||
<link type="text/css" rel="stylesheet" href="{{ pathPrefix }}/classic/static/vendor/rickshaw/rickshaw.min.css"> |
||||
<link type="text/css" rel="stylesheet" href="{{ pathPrefix }}/classic/static/vendor/bootstrap-4.5.2/css/bootstrap.min.css"> |
||||
<link type="text/css" rel="stylesheet" href="{{ pathPrefix }}/classic/static/css/prom_console.css"> |
||||
<link type="text/css" rel="stylesheet" href="{{ pathPrefix }}/classic/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.min.css"> |
||||
<script src="{{ pathPrefix }}/classic/static/vendor/rickshaw/vendor/d3.v3.js"></script> |
||||
<script src="{{ pathPrefix }}/classic/static/vendor/rickshaw/vendor/d3.layout.min.js"></script> |
||||
<script src="{{ pathPrefix }}/classic/static/vendor/rickshaw/rickshaw.min.js"></script> |
||||
<script src="{{ pathPrefix }}/classic/static/vendor/js/jquery-3.5.1.min.js"></script> |
||||
<script src="{{ pathPrefix }}/classic/static/vendor/js/popper.min.js"></script> |
||||
<script src="{{ pathPrefix }}/classic/static/vendor/bootstrap-4.5.2/js/bootstrap.min.js"></script> |
||||
|
||||
<script> |
||||
var PATH_PREFIX = "{{ pathPrefix }}"; |
||||
</script> |
||||
<script src="{{ pathPrefix }}/classic/static/js/prom_console.js"></script> |
||||
{{ end }} |
||||
|
||||
{{/* Top of all pages. */}} |
||||
{{ define "head" -}} |
||||
<!doctype html> |
||||
<html lang="en"> |
||||
<head> |
||||
{{ template "prom_console_head" }} |
||||
</head> |
||||
<body> |
||||
{{ template "navbar" . }} |
||||
|
||||
{{ template "menu" . }} |
||||
{{ end }} |
||||
|
||||
{{ define "__prom_query_drilldown_noop" }}{{ . }}{{ end }} |
||||
{{ define "humanize" }}{{ humanize . }}{{ end }} |
||||
{{ define "humanizeNoSmallPrefix" }}{{ if and (lt . 1.0) (gt . -1.0) }}{{ printf "%.3g" . }}{{ else }}{{ humanize . }}{{ end }}{{ end }} |
||||
{{ define "humanize1024" }}{{ humanize1024 . }}{{ end }} |
||||
{{ define "humanizeDuration" }}{{ humanizeDuration . }}{{ end }} |
||||
{{ define "humanizePercentage" }}{{ humanizePercentage . }}{{ end }} |
||||
{{ define "humanizeTimestamp" }}{{ humanizeTimestamp . }}{{ end }} |
||||
{{ define "printf.1f" }}{{ printf "%.1f" . }}{{ end }} |
||||
{{ define "printf.3g" }}{{ printf "%.3g" . }}{{ end }} |
||||
|
||||
{{/* prom_query_drilldown (args expr suffix? renderTemplate?) |
||||
Displays the result of the expression, with a link to /graph for it. |
||||
|
||||
renderTemplate is the name of the template to use to render the value. |
||||
*/}} |
||||
{{ define "prom_query_drilldown" }} |
||||
{{ $expr := .arg0 }}{{ $suffix := (or .arg1 "") }}{{ $renderTemplate := (or .arg2 "__prom_query_drilldown_noop") }} |
||||
<a class="prom_query_drilldown" href="{{ pathPrefix }}{{ graphLink $expr }}">{{ with query $expr }}{{tmpl $renderTemplate ( . | first | value )}}{{ $suffix }}{{ else }}-{{ end }}</a> |
||||
{{ end }} |
||||
|
||||
{{ define "prom_path" }}/consoles/{{ .Path }}?{{ range $param, $value := .Params }}{{ $param }}={{ $value }}&{{ end }}{{ end }}" |
||||
|
||||
{{ define "prom_right_table_head" }} |
||||
<div class="prom_console_rhs"> |
||||
<table class="table table-bordered table-hover table-sm"> |
||||
{{ end }} |
||||
{{ define "prom_right_table_tail" }} |
||||
</table> |
||||
</div> |
||||
{{ end }} |
||||
|
||||
{{/* RHS table head, pass job name. Should be used after prom_right_table_head. */}} |
||||
{{ define "prom_right_table_job_head" }} |
||||
<tr> |
||||
<th>{{ . }}</th> |
||||
<th>{{ template "prom_query_drilldown" (args (printf "sum(up{job='%s'})" .)) }} / {{ template "prom_query_drilldown" (args (printf "count(up{job='%s'})" .)) }}</th> |
||||
</tr> |
||||
<tr> |
||||
<td>CPU</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "avg by(job)(irate(process_cpu_seconds_total{job='%s'}[5m]))" .) "s/s" "humanizeNoSmallPrefix") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Memory</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "avg by(job)(process_resident_memory_bytes{job='%s'})" .) "B" "humanize1024") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
|
||||
|
||||
{{ define "prom_content_head" }} |
||||
<div class="prom_console_content"> |
||||
<div class="container-fluid"> |
||||
{{ template "prom_graph_timecontrol" . }} |
||||
{{ end }} |
||||
{{ define "prom_content_tail" }} |
||||
</div> |
||||
</div> |
||||
{{ end }} |
||||
|
||||
{{ define "prom_graph_timecontrol" }} |
||||
<div class="prom_graph_timecontrol"> |
||||
<div class="prom_graph_timecontrol_inner"> |
||||
<div class="prom_graph_timecontrol_group "> |
||||
<button class="btn btn-light pull-left" type="button" id="prom_graph_duration_shrink" title="Shrink the time range."> |
||||
<i class="glyphicon glyphicon-minus"></i> |
||||
</button><!-- Comments between elements to remove spaces |
||||
--><input class="input pull-left align-middle" size="3" title="Time range of graph" type="text" id="prom_graph_duration"><!-- |
||||
--><button class="btn btn-light pull-left" type="button" id="prom_graph_duration_grow" title="Grow the time range."> |
||||
<i class="glyphicon glyphicon-plus"></i> |
||||
</button> |
||||
</div> |
||||
<div class="prom_graph_timecontrol_group "> |
||||
<button class="btn btn-light pull-left" type="button" id="prom_graph_time_back" title="Rewind the end time."> |
||||
<i class="glyphicon glyphicon-backward"></i> |
||||
</button><!-- |
||||
--><input class="input pull-left align-middle" title="End time of graph" placeholder="Until" type="text" id="prom_graph_time_end" size="16" value=""><!-- |
||||
--><button class="btn btn-light pull-left" type="button" id="prom_graph_time_forward" title="Advance the end time."> |
||||
<i class="glyphicon glyphicon-forward"></i> |
||||
</button> |
||||
</div> |
||||
<div class="prom_graph_timecontrol_group "> |
||||
<div class="btn-group dropup prom_graph_timecontrol_refresh pull-left"> |
||||
<button type="button" class="btn btn-light pull-left" id="prom_graph_refresh_button" title="Refresh."> |
||||
<i class="glyphicon glyphicon-repeat"></i> |
||||
<span class="icon-repeat"></span> |
||||
(<span id="prom_graph_refresh_button_value">Off</span>) |
||||
</button> |
||||
<button type="button" class="btn btn-light pull-left dropdown-toggle" data-toggle="dropdown" title="Set autorefresh."aria-haspopup="true" aria-expanded="false"> |
||||
<span class="caret"></span> |
||||
</button> |
||||
<ul class="dropdown-menu" id="prom_graph_refresh_intervals" role="menu"> |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<script> |
||||
new PromConsole.TimeControl(); |
||||
</script> |
||||
</div> |
||||
{{ end }} |
||||
|
||||
{{/* Bottom of all pages. */}} |
||||
{{ define "tail" }} |
||||
</body> |
||||
</html> |
||||
{{ end }} |
@ -1,28 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<h1>Overview</h1> |
||||
<p>These are example consoles for Prometheus.</p> |
||||
|
||||
<p>These consoles expect exporters to have the following job labels:</p> |
||||
<table class="table table-sm table-striped table-bordered" style="width: 0%"> |
||||
<tr> |
||||
<th>Exporter</th> |
||||
<th>Job label</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Node Exporter</td> |
||||
<td><code>node</code></td> |
||||
</tr> |
||||
<tr> |
||||
<td>Prometheus</td> |
||||
<td><code>prometheus</code></td> |
||||
</tr> |
||||
</table> |
||||
|
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,60 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
<tr> |
||||
<th colspan="2">CPU(s): {{ template "prom_query_drilldown" (args (printf "scalar(count(count by (cpu)(node_cpu_seconds_total{job='node',instance='%s'})))" .Params.instance)) }}</th> |
||||
</tr> |
||||
{{ range printf "sum by (mode)(irate(node_cpu_seconds_total{job='node',instance='%s'}[5m])) * 100 / scalar(count(count by (cpu)(node_cpu_seconds_total{job='node',instance='%s'})))" .Params.instance .Params.instance | query | sortByLabel "mode" }} |
||||
<tr> |
||||
<td>{{ .Labels.mode | title }} CPU</td> |
||||
<td>{{ .Value | printf "%.1f" }}%</td> |
||||
</tr> |
||||
{{ end }} |
||||
<tr><th colspan="2">Misc</th></tr> |
||||
<tr> |
||||
<td>Processes Running</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "node_procs_running{job='node',instance='%s'}" .Params.instance) "" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Processes Blocked</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "node_procs_blocked{job='node',instance='%s'}" .Params.instance) "" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Forks</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_forks_total{job='node',instance='%s'}[5m])" .Params.instance) "/s" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Context Switches</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_context_switches_total{job='node',instance='%s'}[5m])" .Params.instance) "/s" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Interrupts</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_intr_total{job='node',instance='%s'}[5m])" .Params.instance) "/s" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>1m Loadavg</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "node_load1{job='node',instance='%s'}" .Params.instance)) }}</td> |
||||
</tr> |
||||
<tr> |
||||
</tr> |
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<h1>Node CPU - {{ reReplaceAll "(.*?://)([^:/]+?)(:\\d+)?/.*" "$2" .Params.instance }}</h1> |
||||
|
||||
<h3>CPU Usage</h3> |
||||
<div id="cpuGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#cpuGraph"), |
||||
expr: "sum by (mode)(irate(node_cpu_seconds_total{job='node',instance='{{ .Params.instance }}',mode!='idle',mode!='iowait',mode!='steal'}[5m]))", |
||||
renderer: 'area', |
||||
max: {{ with printf "count(count by (cpu)(node_cpu_seconds_total{job='node',instance='%s'}))" .Params.instance | query }}{{ . | first | value }}{{ else}}undefined{{end}}, |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yTitle: 'Cores' |
||||
}) |
||||
</script> |
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,78 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
<tr> |
||||
<th colspan="2">Disks</th> |
||||
</tr> |
||||
{{ range printf "node_disk_io_time_seconds_total{job='node',instance='%s'}" .Params.instance | query | sortByLabel "device" }} |
||||
<th colspan="2">{{ .Labels.device }}</th> |
||||
<tr> |
||||
<td>Utilization</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_disk_io_time_seconds_total{job='node',instance='%s',device='%s'}[5m]) * 100" .Labels.instance .Labels.device) "%" "printf.1f") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Throughput</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_disk_read_bytes_total{job='node',instance='%s',device='%s'}[5m]) + irate(node_disk_written_bytes_total{job='node',instance='%s',device='%s'}[5m])" .Labels.instance .Labels.device .Labels.instance .Labels.device) "B/s" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Avg Read Time</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_disk_read_time_seconds_total{job='node',instance='%s',device='%s'}[5m]) / irate(node_disk_reads_completed_total{job='node',instance='%s',device='%s'}[5m])" .Labels.instance .Labels.device .Labels.instance .Labels.device) "s" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Avg Write Time</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_disk_write_time_seconds_total{job='node',instance='%s',device='%s'}[5m]) / irate(node_disk_writes_completed_total{job='node',instance='%s',device='%s'}[5m])" .Labels.instance .Labels.device .Labels.instance .Labels.device) "s" "humanize") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
<tr> |
||||
<th colspan="2">Filesystem Fullness</th> |
||||
</tr> |
||||
{{ define "roughlyNearZero" }} |
||||
{{ if gt .1 . }}~0{{ else }}{{ printf "%.1f" . }}{{ end }} |
||||
{{ end }} |
||||
{{ range printf "node_filesystem_size_bytes{job='node',instance='%s'}" .Params.instance | query | sortByLabel "mountpoint" }} |
||||
<tr> |
||||
<td>{{ .Labels.mountpoint }}</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "100 - node_filesystem_avail_bytes{job='node',instance='%s',mountpoint='%s'} / node_filesystem_size_bytes{job='node'} * 100" .Labels.instance .Labels.mountpoint) "%" "roughlyNearZero") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
<tr> |
||||
</tr> |
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<h1>Node Disk - {{ reReplaceAll "(.*?://)([^:/]+?)(:\\d+)?/.*" "$2" .Params.instance }}</h1> |
||||
|
||||
<h3>Disk I/O Utilization</h3> |
||||
<div id="diskioGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#diskioGraph"), |
||||
expr: [ |
||||
"irate(node_disk_io_time_seconds_total{job='node',instance='{{ .Params.instance }}',device!~'^(md\\\\d+$|dm-)'}[5m]) * 100", |
||||
], |
||||
min: 0, |
||||
name: '[[ device ]]', |
||||
yUnits: "%", |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yTitle: 'Disk I/O Utilization' |
||||
}) |
||||
</script> |
||||
<h3>Filesystem Usage</h3> |
||||
<div id="fsGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#fsGraph"), |
||||
expr: "100 - node_filesystem_avail_bytes{job='node',instance='{{ .Params.instance }}'} / node_filesystem_size_bytes{job='node'} * 100", |
||||
min: 0, |
||||
max: 100, |
||||
name: '[[ mountpoint ]]', |
||||
yUnits: "%", |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yTitle: 'Filesystem Fullness' |
||||
}) |
||||
</script> |
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,121 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
<tr><th colspan="2">Overview</th></tr> |
||||
<tr> |
||||
<td>User CPU</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "sum(irate(node_cpu_seconds_total{job='node',instance='%s',mode='user'}[5m])) * 100 / count(count by (cpu)(node_cpu_seconds_total{job='node',instance='%s'}))" .Params.instance .Params.instance) "%" "printf.1f") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>System CPU</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "sum(irate(node_cpu_seconds_total{job='node',instance='%s',mode='system'}[5m])) * 100 / count(count by (cpu)(node_cpu_seconds_total{job='node',instance='%s'}))" .Params.instance .Params.instance) "%" "printf.1f") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Memory Total</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "node_memory_MemTotal_bytes{job='node',instance='%s'}" .Params.instance) "B" "humanize1024") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Memory Free</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "node_memory_MemFree_bytes{job='node',instance='%s'}" .Params.instance) "B" "humanize1024") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<th colspan="2">Network</th> |
||||
</tr> |
||||
{{ range printf "node_network_receive_bytes_total{job='node',instance='%s',device!='lo'}" .Params.instance | query | sortByLabel "device" }} |
||||
<tr> |
||||
<td>{{ .Labels.device }} Received</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_network_receive_bytes_total{job='node',instance='%s',device='%s'}[5m])" .Labels.instance .Labels.device) "B/s" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>{{ .Labels.device }} Transmitted</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_network_transmit_bytes_total{job='node',instance='%s',device='%s'}[5m])" .Labels.instance .Labels.device) "B/s" "humanize") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
<tr> |
||||
<th colspan="2">Disks</th> |
||||
</tr> |
||||
{{ range printf "node_disk_io_time_seconds_total{job='node',instance='%s',device!~'^(md\\\\d+$|dm-)'}" .Params.instance | query | sortByLabel "device" }} |
||||
<tr> |
||||
<td>{{ .Labels.device }} Utilization</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_disk_io_time_seconds_total{job='node',instance='%s',device='%s'}[5m]) * 100" .Labels.instance .Labels.device) "%" "printf.1f") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
{{ range printf "node_disk_io_time_seconds_total{job='node',instance='%s'}" .Params.instance | query | sortByLabel "device" }} |
||||
<tr> |
||||
<td>{{ .Labels.device }} Throughput</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(node_disk_read_bytes_total{job='node',instance='%s',device='%s'}[5m]) + irate(node_disk_written_bytes_total{job='node',instance='%s',device='%s'}[5m])" .Labels.instance .Labels.device .Labels.instance .Labels.device) "B/s" "humanize") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
<tr> |
||||
<th colspan="2">Filesystem Fullness</th> |
||||
</tr> |
||||
{{ define "roughlyNearZero" }} |
||||
{{ if gt .1 . }}~0{{ else }}{{ printf "%.1f" . }}{{ end }} |
||||
{{ end }} |
||||
{{ range printf "node_filesystem_size_bytes{job='node',instance='%s'}" .Params.instance | query | sortByLabel "mountpoint" }} |
||||
<tr> |
||||
<td>{{ .Labels.mountpoint }}</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "100 - node_filesystem_avail_bytes{job='node',instance='%s',mountpoint='%s'} / node_filesystem_size_bytes{job='node'} * 100" .Labels.instance .Labels.mountpoint) "%" "roughlyNearZero") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
|
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<h1>Node Overview - {{ reReplaceAll "(.*?://)([^:/]+?)(:\\d+)?/.*" "$2" .Params.instance }}</h1> |
||||
|
||||
<h3>CPU Usage</h3> |
||||
<div id="cpuGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#cpuGraph"), |
||||
expr: "sum by (mode)(irate(node_cpu_seconds_total{job='node',instance='{{ .Params.instance }}',mode!='idle',mode!='iowait',mode!='steal'}[5m]))", |
||||
renderer: 'area', |
||||
max: {{ with printf "count(count by (cpu)(node_cpu_seconds_total{job='node',instance='%s'}))" .Params.instance | query }}{{ . | first | value }}{{ else}}undefined{{end}}, |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yTitle: 'Cores' |
||||
}) |
||||
</script> |
||||
|
||||
<h3>Disk I/O Utilization</h3> |
||||
<div id="diskioGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#diskioGraph"), |
||||
expr: [ |
||||
"irate(node_disk_io_time_seconds_total{job='node',instance='{{ .Params.instance }}',device!~'^(md\\\\d+$|dm-)'}[5m]) * 100", |
||||
], |
||||
min: 0, |
||||
name: '[[ device ]]', |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yUnits: "%", |
||||
yTitle: 'Disk I/O Utilization' |
||||
}) |
||||
</script> |
||||
|
||||
<h3>Memory</h3> |
||||
<div id="memoryGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#memoryGraph"), |
||||
renderer: 'area', |
||||
expr: [ |
||||
"node_memory_Cached_bytes{job='node',instance='{{ .Params.instance }}'}", |
||||
"node_memory_Buffers_bytes{job='node',instance='{{ .Params.instance }}'}", |
||||
"node_memory_MemTotal_bytes{job='node',instance='{{ .Params.instance }}'} - node_memory_MemFree_bytes{job='node',instance='{{.Params.instance}}'} - node_memory_Buffers_bytes{job='node',instance='{{.Params.instance}}'} - node_memory_Cached_bytes{job='node',instance='{{.Params.instance}}'}", |
||||
"node_memory_MemFree{job='node',instance='{{ .Params.instance }}'}", |
||||
], |
||||
name: ["Cached", "Buffers", "Used", "Free"], |
||||
min: 0, |
||||
yUnits: "B", |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanize1024, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanize1024, |
||||
yTitle: 'Memory' |
||||
}) |
||||
</script> |
||||
|
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,35 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
<tr> |
||||
<th>Node</th> |
||||
<th>{{ template "prom_query_drilldown" (args "sum(up{job='node'})") }} / {{ template "prom_query_drilldown" (args "count(up{job='node'})") }}</th> |
||||
</tr> |
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<h1>Node</h1> |
||||
|
||||
<table class="table table-condensed table-striped table-bordered" style="width: 0%"> |
||||
<tr> |
||||
<th>Node</th> |
||||
<th>Up</th> |
||||
<th>CPU<br/>Used</th> |
||||
<th>Memory<br/> Available</th> |
||||
</tr> |
||||
{{ range query "up{job='node'}" | sortByLabel "instance" }} |
||||
<tr> |
||||
<td><a href="node-overview.html?instance={{ .Labels.instance }}">{{ reReplaceAll "(.*?://)([^:/]+?)(:\\d+)?/.*" "$2" .Labels.instance }}</a></td> |
||||
<td{{ if eq (. | value) 1.0 }}>Yes{{ else }} class="alert-danger">No{{ end }}</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "100 * (1 - avg by(instance) (sum without(mode) (irate(node_cpu_seconds_total{job='node',mode=~'idle|iowait|steal',instance='%s'}[5m]))))" .Labels.instance) "%" "printf.1f") }}</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "node_memory_MemFree_bytes{job='node',instance='%s'} + node_memory_Cached_bytes{job='node',instance='%s'} + node_memory_Buffers_bytes{job='node',instance='%s'}" .Labels.instance .Labels.instance .Labels.instance) "B" "humanize1024") }}</td> |
||||
</tr> |
||||
{{ else }} |
||||
<tr><td colspan=4>No nodes found.</td></tr> |
||||
{{ end }} |
||||
</table> |
||||
|
||||
|
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,96 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
<tr> |
||||
<th colspan="2">Overview</th> |
||||
</tr> |
||||
<tr> |
||||
<td>CPU</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(process_cpu_seconds_total{job='prometheus',instance='%s'}[5m])" .Params.instance) "s/s" "humanizeNoSmallPrefix") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Memory</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "process_resident_memory_bytes{job='prometheus',instance='%s'}" .Params.instance) "B" "humanize1024") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Version</td> |
||||
<td>{{ with query (printf "prometheus_build_info{job='prometheus',instance='%s'}" .Params.instance) }}{{. | first | label "version"}}{{end}}</td> |
||||
</tr> |
||||
|
||||
<tr> |
||||
<th colspan="2">Storage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Ingested Samples</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(prometheus_tsdb_head_samples_appended_total{job='prometheus',instance='%s'}[5m])" .Params.instance) "/s" "humanizeNoSmallPrefix") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Head Series</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "prometheus_tsdb_head_series{job='prometheus',instance='%s'}" .Params.instance) "" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Blocks Loaded</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "prometheus_tsdb_blocks_loaded{job='prometheus',instance='%s'}" .Params.instance) "" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<th colspan="2">Rules</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Evaluation Duration</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(prometheus_evaluator_duration_seconds_sum{job='prometheus',instance='%s'}[5m]) / irate(prometheus_evaluator_duration_seconds_count{job='prometheus',instance='%s'}[5m])" .Params.instance .Params.instance) "" "humanizeDuration") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Notification Latency</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(prometheus_notifications_latency_seconds_sum{job='prometheus',instance='%s'}[5m]) / irate(prometheus_notifications_latency_seconds_count{job='prometheus',instance='%s'}[5m])" .Params.instance .Params.instance) "" "humanizeDuration") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Notification Queue</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "prometheus_notifications_queue_length{job='prometheus',instance='%s'}" .Params.instance) "" "humanize") }}</td> |
||||
</tr> |
||||
<tr> |
||||
<th colspan="2">HTTP Server</th> |
||||
</tr> |
||||
{{ range printf "prometheus_http_request_duration_seconds_count{job='prometheus',instance='%s'}" .Params.instance | query | sortByLabel "handler" }} |
||||
<tr> |
||||
<td>{{ .Labels.handler }}</td> |
||||
<td>{{ template "prom_query_drilldown" (args (printf "irate(prometheus_http_request_duration_seconds_count{job='prometheus',instance='%s',handler='%s'}[5m])" .Labels.instance .Labels.handler) "/s" "humanizeNoSmallPrefix") }}</td> |
||||
</tr> |
||||
{{ end }} |
||||
|
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<div class="prom_content_div"> |
||||
<h1>Prometheus Overview - {{ .Params.instance }}</h1> |
||||
|
||||
<h3>Ingested Samples</h3> |
||||
<div id="samplesGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#samplesGraph"), |
||||
expr: "irate(prometheus_tsdb_head_samples_appended_total{job='prometheus',instance='{{ .Params.instance }}'}[5m])", |
||||
name: 'Ingested Samples', |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yTitle: "Samples", |
||||
yUnits: "/s", |
||||
}) |
||||
</script> |
||||
|
||||
<h3>HTTP Server</h3> |
||||
<div id="serverGraph"></div> |
||||
<script> |
||||
new PromConsole.Graph({ |
||||
node: document.querySelector("#serverGraph"), |
||||
expr: "irate(prometheus_http_request_duration_seconds_count{job='prometheus',instance='{{ .Params.instance }}'}[5m])", |
||||
name: '[[handler]]', |
||||
yAxisFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeNoSmallPrefix, |
||||
yTitle: "Requests", |
||||
yUnits: "/s", |
||||
}) |
||||
</script> |
||||
</div> |
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,34 +0,0 @@
|
||||
{{ template "head" . }} |
||||
|
||||
{{ template "prom_right_table_head" }} |
||||
<tr> |
||||
<th>Prometheus</th> |
||||
<th>{{ template "prom_query_drilldown" (args "sum(up{job='prometheus'})") }} / {{ template "prom_query_drilldown" (args "count(up{job='prometheus'})") }}</th> |
||||
</tr> |
||||
{{ template "prom_right_table_tail" }} |
||||
|
||||
{{ template "prom_content_head" . }} |
||||
<h1>Prometheus</h1> |
||||
|
||||
<table class="table table-sm table-striped table-bordered" style="width: 0%"> |
||||
<tr> |
||||
<th>Prometheus</th> |
||||
<th>Up</th> |
||||
<th>Ingested Samples</th> |
||||
<th>Memory</th> |
||||
</tr> |
||||
{{ range query "up{job='prometheus'}" | sortByLabel "instance" }} |
||||
<tr> |
||||
<td><a href="prometheus-overview.html?instance={{ .Labels.instance }}">{{ .Labels.instance }}</a></td> |
||||
<td {{ if eq (. | value) 1.0 }}>Yes{{ else }} class="alert-danger">No{{ end }}</td> |
||||
<td class="text-right">{{ template "prom_query_drilldown" (args (printf "irate(prometheus_tsdb_head_samples_appended_total{job='prometheus',instance='%s'}[5m])" .Labels.instance) "/s" "humanizeNoSmallPrefix") }}</td> |
||||
<td class="text-right">{{ template "prom_query_drilldown" (args (printf "process_resident_memory_bytes{job='prometheus',instance='%s'}" .Labels.instance) "B" "humanize1024")}}</td> |
||||
</tr> |
||||
{{ else }} |
||||
<tr><td colspan=4>No devices found.</td></tr> |
||||
{{ end }} |
||||
</table> |
||||
|
||||
{{ template "prom_content_tail" . }} |
||||
|
||||
{{ template "tail" }} |
@ -1,190 +0,0 @@
|
||||
.navbar { |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
div.prom_lhs_menu { |
||||
float: left; |
||||
margin-right: 2ex; |
||||
background: #222; |
||||
min-height: 100%; |
||||
overflow: auto; |
||||
width: auto; |
||||
margin-left: -40px; |
||||
margin-top: 55px; |
||||
height: 100%; |
||||
} |
||||
.prom_lhs_menu_nav { |
||||
padding-right: 0; |
||||
} |
||||
.prom_lhs_menu ul { |
||||
list-style: none; |
||||
padding-left: .5ex; |
||||
margin-left: .5ex; |
||||
} |
||||
.prom_lhs_menu li { |
||||
padding-right: 1ex; |
||||
padding-left: 1ex; |
||||
font-size: 0.9rem; |
||||
} |
||||
.prom_lhs_menu a, |
||||
.prom_lhs_menu li { |
||||
color: #999999; |
||||
display: block; |
||||
} |
||||
.prom_lhs_menu a { |
||||
text-decoration: none; |
||||
padding-top: 0; |
||||
padding-bottom: 0; |
||||
} |
||||
.prom_lhs_menu_selected a { |
||||
pointer-events: none; |
||||
cursor: default; |
||||
} |
||||
li.prom_lhs_menu_selected { |
||||
background: #555555; |
||||
background-clip: padding-box; |
||||
} |
||||
.prom_lhs_menu li:hover { |
||||
background: #666666; |
||||
} |
||||
|
||||
.prom_console_rhs { |
||||
float: right; |
||||
margin-left: 1ex; |
||||
height: 100%; |
||||
padding-top: 55px; |
||||
} |
||||
.prom_console_rhs table { |
||||
margin-top: 1ex; |
||||
margin-bottom: 32px; /* Space for time control. */ |
||||
} |
||||
.prom_console_rhs th { |
||||
text-align: center; |
||||
} |
||||
.prom_console_rhs td:nth-child(2) { |
||||
text-align: right; |
||||
} |
||||
|
||||
.prom_console_content { |
||||
overflow: visible; |
||||
margin-bottom: 32px; /* Space for time control. */ |
||||
padding-top: 70px; /* Space for navbar */ |
||||
} |
||||
|
||||
a.prom_query_drilldown { |
||||
text-decoration: none; |
||||
color: black; |
||||
} |
||||
a.prom_query_drilldown:hover, a.prom_query_drilldown:active { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
#samplesGraph { |
||||
width: 100%; |
||||
} |
||||
|
||||
.prom_content_div { |
||||
width: 80%; |
||||
} |
||||
|
||||
.prom_graph_table { |
||||
} |
||||
.rickshaw_legend { |
||||
padding: 2px; |
||||
margin-top: 1px; |
||||
} |
||||
.rickshaw_legend li { |
||||
min-width: 0; |
||||
} |
||||
.rickshaw_legend ul li { |
||||
list-style-type: none; |
||||
display: inline-block; |
||||
} |
||||
.rickshaw_graph { |
||||
width: 100%; |
||||
padding: 0; |
||||
} |
||||
.prom_graph_hover_flipped.x_label { |
||||
right: 0; |
||||
} |
||||
.prom_graph_hover_flipped.item { |
||||
right: 10px; |
||||
} |
||||
.rickshaw_graph .detail .prom_graph_hover_flipped.item:before { |
||||
content: "\25b8"; |
||||
left: auto; |
||||
right: 1px; |
||||
font-size: 0.8em; |
||||
} |
||||
.prom_graph_ytitle { |
||||
-webkit-transform: rotate(-90deg); |
||||
-moz-transform: rotate(-90deg); |
||||
font-size: 11px; |
||||
font-family: Arial; |
||||
max-width: 13px; |
||||
white-space: nowrap; |
||||
} |
||||
.prom_graph_xtitle { |
||||
text-align: center; |
||||
font-size: 11px; |
||||
font-family: Arial; |
||||
} |
||||
.prom_graph_loading { |
||||
position: absolute; |
||||
top: 0px; |
||||
left: 0px; |
||||
} |
||||
.prom_graph_error { |
||||
font-family: Arial; |
||||
text-align: center; |
||||
} |
||||
a.prom_graph_link { |
||||
text-decoration: none; |
||||
color: black; |
||||
} |
||||
|
||||
|
||||
.prom_graph_timecontrol { |
||||
background: #222; |
||||
position: fixed; |
||||
padding: 2px; |
||||
bottom: 0; |
||||
left: 0; |
||||
z-index: 2; |
||||
width: 100%; |
||||
} |
||||
|
||||
.prom_graph_timecontrol_inner { |
||||
text-align: center; |
||||
height: 31px; |
||||
} |
||||
|
||||
.prom_graph_timecontrol_group { |
||||
display: inline-block; |
||||
margin: 1px 5px; |
||||
} |
||||
.prom_graph_timecontrol_group .btn { |
||||
font-size: 0.8em; |
||||
border-radius: 0; |
||||
height: 29px; |
||||
border-color: #ccc; |
||||
} |
||||
|
||||
.prom_graph_timecontrol_group .input { |
||||
height: 29px; |
||||
padding: 6px 12px; |
||||
font-size: 14px; |
||||
line-height: 1.42857143; |
||||
color: #555; |
||||
background-color: #fff; |
||||
background-image: none; |
||||
border: 1px solid #ccc; |
||||
text-align: center; |
||||
} |
||||
|
||||
.prom_graph_timecontrol_group .dropdown-menu { |
||||
min-width: 90px; |
||||
} |
||||
.prom_graph_timecontrol_group .dropdown-menu li { |
||||
text-align: center; |
||||
} |
@ -1,687 +0,0 @@
|
||||
/* |
||||
* Functions to make it easier to write prometheus consoles, such |
||||
* as graphs. |
||||
* |
||||
*/ |
||||
PromConsole = {}; |
||||
|
||||
PromConsole.NumberFormatter = {}; |
||||
PromConsole.NumberFormatter.prefixesBig = ["k", "M", "G", "T", "P", "E", "Z", "Y"]; |
||||
PromConsole.NumberFormatter.prefixesBig1024 = ["ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"]; |
||||
PromConsole.NumberFormatter.prefixesSmall = ["m", "u", "n", "p", "f", "a", "z", "y"]; |
||||
|
||||
PromConsole._stripTrailingZero = function(x) { |
||||
if (x.indexOf("e") == -1) { |
||||
// It's not safe to strip if it's scientific notation.
|
||||
return x.replace(/\.?0*$/, ''); |
||||
} |
||||
return x; |
||||
}; |
||||
|
||||
// Humanize a number.
|
||||
PromConsole.NumberFormatter.humanize = function(x) { |
||||
if (x === null) { |
||||
return "null"; |
||||
} |
||||
var ret = PromConsole.NumberFormatter._humanize( |
||||
x, PromConsole.NumberFormatter.prefixesBig, |
||||
PromConsole.NumberFormatter.prefixesSmall, 1000); |
||||
x = ret[0]; |
||||
var prefix = ret[1]; |
||||
if (Math.abs(x) < 1) { |
||||
return x.toExponential(3) + prefix; |
||||
} |
||||
return PromConsole._stripTrailingZero(x.toFixed(3)) + prefix; |
||||
}; |
||||
|
||||
// Humanize a number, don't use milli/micro/etc. prefixes.
|
||||
PromConsole.NumberFormatter.humanizeNoSmallPrefix = function(x) { |
||||
if (x === null) { |
||||
return "null"; |
||||
} |
||||
if (Math.abs(x) < 1) { |
||||
return PromConsole._stripTrailingZero(x.toPrecision(3)); |
||||
} |
||||
var ret = PromConsole.NumberFormatter._humanize( |
||||
x, PromConsole.NumberFormatter.prefixesBig, |
||||
[], 1000); |
||||
x = ret[0]; |
||||
var prefix = ret[1]; |
||||
return PromConsole._stripTrailingZero(x.toFixed(3)) + prefix; |
||||
}; |
||||
|
||||
// Humanize a number with 1024 as the base, rather than 1000.
|
||||
PromConsole.NumberFormatter.humanize1024 = function(x) { |
||||
if (x === null) { |
||||
return "null"; |
||||
} |
||||
var ret = PromConsole.NumberFormatter._humanize( |
||||
x, PromConsole.NumberFormatter.prefixesBig1024, |
||||
[], 1024); |
||||
x = ret[0]; |
||||
var prefix = ret[1]; |
||||
if (Math.abs(x) < 1) { |
||||
return x.toExponential(3) + prefix; |
||||
} |
||||
return PromConsole._stripTrailingZero(x.toFixed(3)) + prefix; |
||||
}; |
||||
|
||||
// Humanize a number, returning an exact representation.
|
||||
PromConsole.NumberFormatter.humanizeExact = function(x) { |
||||
if (x === null) { |
||||
return "null"; |
||||
} |
||||
var ret = PromConsole.NumberFormatter._humanize( |
||||
x, PromConsole.NumberFormatter.prefixesBig, |
||||
PromConsole.NumberFormatter.prefixesSmall, 1000); |
||||
return ret[0] + ret[1]; |
||||
}; |
||||
|
||||
PromConsole.NumberFormatter._humanize = function(x, prefixesBig, prefixesSmall, factor) { |
||||
var prefix = ""; |
||||
if (x === 0) { |
||||
/* Do nothing. */ |
||||
} else if (Math.abs(x) >= 1) { |
||||
for (var i=0; i < prefixesBig.length && Math.abs(x) >= factor; ++i) { |
||||
x /= factor; |
||||
prefix = prefixesBig[i]; |
||||
} |
||||
} else { |
||||
for (var i=0; i < prefixesSmall.length && Math.abs(x) < 1; ++i) { |
||||
x *= factor; |
||||
prefix = prefixesSmall[i]; |
||||
} |
||||
} |
||||
return [x, prefix]; |
||||
}; |
||||
|
||||
|
||||
PromConsole.TimeControl = function() { |
||||
document.getElementById("prom_graph_duration_shrink").onclick = this.decreaseDuration.bind(this); |
||||
document.getElementById("prom_graph_duration_grow").onclick = this.increaseDuration.bind(this); |
||||
document.getElementById("prom_graph_time_back").onclick = this.decreaseEnd.bind(this); |
||||
document.getElementById("prom_graph_time_forward").onclick = this.increaseEnd.bind(this); |
||||
document.getElementById("prom_graph_refresh_button").onclick = this.refresh.bind(this); |
||||
this.durationElement = document.getElementById("prom_graph_duration"); |
||||
this.endElement = document.getElementById("prom_graph_time_end"); |
||||
this.durationElement.oninput = this.dispatch.bind(this); |
||||
this.endElement.oninput = this.dispatch.bind(this); |
||||
this.endElement.oninput = this.dispatch.bind(this); |
||||
this.refreshValueElement = document.getElementById("prom_graph_refresh_button_value"); |
||||
|
||||
var refreshList = document.getElementById("prom_graph_refresh_intervals"); |
||||
var refreshIntervals = ["Off", "1m", "5m", "15m", "1h"]; |
||||
for (var i=0; i < refreshIntervals.length; ++i) { |
||||
var li = document.createElement("li"); |
||||
li.onclick = this.setRefresh.bind(this, refreshIntervals[i]); |
||||
li.textContent = refreshIntervals[i]; |
||||
refreshList.appendChild(li); |
||||
} |
||||
|
||||
this.durationElement.value = PromConsole.TimeControl.prototype.getHumanDuration( |
||||
PromConsole.TimeControl._initialValues.duration); |
||||
if (!PromConsole.TimeControl._initialValues.endTimeNow) { |
||||
this.endElement.value = PromConsole.TimeControl.prototype.getHumanDate( |
||||
new Date(PromConsole.TimeControl._initialValues.endTime * 1000)); |
||||
} |
||||
}; |
||||
|
||||
PromConsole.TimeControl.timeFactors = { |
||||
"y": 60 * 60 * 24 * 365, |
||||
"w": 60 * 60 * 24 * 7, |
||||
"d": 60 * 60 * 24, |
||||
"h": 60 * 60, |
||||
"m": 60, |
||||
"s": 1 |
||||
}; |
||||
|
||||
PromConsole.TimeControl.stepValues = [ |
||||
"10s", "1m", "5m", "15m", "30m", "1h", "2h", "6h", "12h", "1d", "2d", |
||||
"1w", "2w", "4w", "8w", "1y", "2y" |
||||
]; |
||||
|
||||
PromConsole.TimeControl.prototype._setHash = function() { |
||||
var duration = this.parseDuration(this.durationElement.value); |
||||
var endTime = this.getEndDate() / 1000; |
||||
window.location.hash = "#pctc" + encodeURIComponent(JSON.stringify( |
||||
{duration: duration, endTime: endTime})); |
||||
}; |
||||
|
||||
PromConsole.TimeControl._initialValues = function() { |
||||
var hash = window.location.hash; |
||||
var values; |
||||
if (hash.indexOf('#pctc') === 0) { |
||||
values = JSON.parse(decodeURIComponent(hash.substring(5))); |
||||
} else { |
||||
values = {duration: 3600, endTime: 0}; |
||||
} |
||||
if (values.endTime == 0) { |
||||
values.endTime = new Date().getTime() / 1000; |
||||
values.endTimeNow = true; |
||||
} |
||||
return values; |
||||
}(); |
||||
|
||||
PromConsole.TimeControl.prototype.parseDuration = function(durationText) { |
||||
var durationRE = new RegExp("^([0-9]+)([ywdhms]?)$"); |
||||
var matches = durationText.match(durationRE); |
||||
if (!matches) { return 3600; } |
||||
var value = parseInt(matches[1]); |
||||
var unit = matches[2] || 's'; |
||||
return value * PromConsole.TimeControl.timeFactors[unit]; |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.getHumanDuration = function(duration) { |
||||
var units = []; |
||||
for (var key in PromConsole.TimeControl.timeFactors) { |
||||
units.push([PromConsole.TimeControl.timeFactors[key], key]); |
||||
} |
||||
units.sort(function(a, b) { return b[0] - a[0]; }); |
||||
for (var i = 0; i < units.length; ++i) { |
||||
if (duration % units[i][0] === 0) { |
||||
return (duration / units[i][0]) + units[i][1]; |
||||
} |
||||
} |
||||
return duration; |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.increaseDuration = function() { |
||||
var durationSeconds = this.parseDuration(this.durationElement.value); |
||||
for (var i = 0; i < PromConsole.TimeControl.stepValues.length; i++) { |
||||
if (durationSeconds < this.parseDuration(PromConsole.TimeControl.stepValues[i])) { |
||||
this.setDuration(PromConsole.TimeControl.stepValues[i]); |
||||
this.dispatch(); |
||||
return; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.decreaseDuration = function() { |
||||
var durationSeconds = this.parseDuration(this.durationElement.value); |
||||
for (var i = PromConsole.TimeControl.stepValues.length - 1; i >= 0; i--) { |
||||
if (durationSeconds > this.parseDuration(PromConsole.TimeControl.stepValues[i])) { |
||||
this.setDuration(PromConsole.TimeControl.stepValues[i]); |
||||
this.dispatch(); |
||||
return; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.setDuration = function(duration) { |
||||
this.durationElement.value = duration; |
||||
this._setHash(); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.getEndDate = function() { |
||||
if (this.endElement.value === '') { |
||||
return null; |
||||
} |
||||
var dateParts = this.endElement.value.split(/[- :]/) |
||||
return Date.UTC(dateParts[0], dateParts[1] - 1, dateParts[2], dateParts[3], dateParts[4]); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.getOrSetEndDate = function() { |
||||
var date = this.getEndDate(); |
||||
if (date) { |
||||
return date; |
||||
} |
||||
date = new Date(); |
||||
this.setEndDate(date); |
||||
return date.getTime(); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.getHumanDate = function(date) { |
||||
var hours = date.getUTCHours() < 10 ? '0' + date.getUTCHours() : date.getUTCHours(); |
||||
var minutes = date.getUTCMinutes() < 10 ? '0' + date.getUTCMinutes() : date.getUTCMinutes(); |
||||
return date.getUTCFullYear() + "-" + (date.getUTCMonth()+1) + "-" + date.getUTCDate() + " " + |
||||
hours + ":" + minutes; |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.setEndDate = function(date) { |
||||
this.setRefresh("Off"); |
||||
this.endElement.value = this.getHumanDate(date); |
||||
this._setHash(); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.increaseEnd = function() { |
||||
// Increase duration 25% range & convert ms to s.
|
||||
this.setEndDate(new Date(this.getOrSetEndDate() + this.parseDuration(this.durationElement.value) * 1000/4 )); |
||||
this.dispatch(); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.decreaseEnd = function() { |
||||
this.setEndDate(new Date(this.getOrSetEndDate() - this.parseDuration(this.durationElement.value) * 1000/4 )); |
||||
this.dispatch(); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.refresh = function() { |
||||
this.endElement.value = ''; |
||||
this._setHash(); |
||||
this.dispatch(); |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype.dispatch = function() { |
||||
var durationSeconds = this.parseDuration(this.durationElement.value); |
||||
var end = this.getEndDate(); |
||||
if (end === null) { |
||||
end = new Date().getTime(); |
||||
} |
||||
for (var i = 0; i< PromConsole._graph_registry.length; i++) { |
||||
var graph = PromConsole._graph_registry[i]; |
||||
graph.params.duration = durationSeconds; |
||||
graph.params.endTime = end / 1000; |
||||
graph.dispatch(); |
||||
} |
||||
}; |
||||
|
||||
PromConsole.TimeControl.prototype._refreshInterval = null; |
||||
|
||||
PromConsole.TimeControl.prototype.setRefresh = function(duration) { |
||||
if (this._refreshInterval !== null) { |
||||
window.clearInterval(this._refreshInterval); |
||||
this._refreshInterval = null; |
||||
} |
||||
if (duration != "Off") { |
||||
if (this.endElement.value !== '') { |
||||
this.refresh(); |
||||
} |
||||
var durationSeconds = this.parseDuration(duration); |
||||
this._refreshInterval = window.setInterval(this.dispatch.bind(this), durationSeconds * 1000); |
||||
} |
||||
this.refreshValueElement.textContent = duration; |
||||
}; |
||||
|
||||
// List of all graphs, used by time controls.
|
||||
PromConsole._graph_registry = []; |
||||
|
||||
PromConsole.graphDefaults = { |
||||
expr: null, // Expression to graph. Can be a list of strings.
|
||||
node: null, // DOM node to place graph under.
|
||||
// How long the graph is over, in seconds.
|
||||
duration: PromConsole.TimeControl._initialValues.duration, |
||||
// The unixtime the graph ends at.
|
||||
endTime: PromConsole.TimeControl._initialValues.endTime, |
||||
width: null, // Height of the graph div, excluding titles and legends.
|
||||
// Defaults to auto-detection.
|
||||
height: 200, // Height of the graph div, excluding titles and legends.
|
||||
min: "auto", // Minimum Y-axis value, defaults to lowest data value.
|
||||
max: undefined, // Maximum Y-axis value, defaults to highest data value.
|
||||
renderer: 'line', // Type of graphs, options are 'line' and 'area'.
|
||||
name: null, // What to call plots, defaults to trying to do
|
||||
// something reasonable.
|
||||
// If a string, it'll use that. [[ label ]] will be substituted.
|
||||
// If a function it'll be called with a map of keys to values,
|
||||
// and should return the name to use.
|
||||
// Can be a list of strings/functions, each element
|
||||
// will be applied to the plots from the corresponding
|
||||
// element of the expr list.
|
||||
xTitle: "Time", // The title of the x axis.
|
||||
yUnits: "", // The units of the y axis.
|
||||
yTitle: "", // The title of the y axis.
|
||||
// Number formatter for y axis.
|
||||
yAxisFormatter: PromConsole.NumberFormatter.humanize, |
||||
// Number of ticks (horizontal lines) for the y axis
|
||||
yAxisTicks: null, |
||||
// Number formatter for y values hover detail.
|
||||
yHoverFormatter: PromConsole.NumberFormatter.humanizeExact, |
||||
// Color scheme to be used by the plots. Can be either a list of hex color
|
||||
// codes or one of the color scheme names supported by Rickshaw.
|
||||
colorScheme: null, |
||||
}; |
||||
|
||||
PromConsole.Graph = function(params) { |
||||
for (var k in PromConsole.graphDefaults) { |
||||
if (!(k in params)) { |
||||
params[k] = PromConsole.graphDefaults[k]; |
||||
} |
||||
} |
||||
if (typeof params.expr == "string") { |
||||
params.expr = [params.expr]; |
||||
} |
||||
if (typeof params.name == "string" || typeof params.name == "function") { |
||||
var name = []; |
||||
for (var i = 0; i < params.expr.length; i++) { |
||||
name.push(params.name); |
||||
} |
||||
params.name = name; |
||||
} |
||||
|
||||
this.params = params; |
||||
this.rendered_data = null; |
||||
// Keep a reference so that further updates (e.g. annotations) can be made
|
||||
// by the user in their templates.
|
||||
this.rickshawGraph = null; |
||||
PromConsole._graph_registry.push(this); |
||||
|
||||
/* |
||||
* Table layout: |
||||
* | yTitle | Graph | |
||||
* | | xTitle | |
||||
* | /graph | Legend | |
||||
*/ |
||||
var table = document.createElement("table"); |
||||
table.className = "prom_graph_table"; |
||||
params.node.appendChild(table); |
||||
var tr = document.createElement("tr"); |
||||
table.appendChild(tr); |
||||
var yTitleTd = document.createElement("td"); |
||||
tr.appendChild(yTitleTd); |
||||
var yTitleDiv = document.createElement("td"); |
||||
yTitleTd.appendChild(yTitleDiv); |
||||
yTitleDiv.className = "prom_graph_ytitle"; |
||||
yTitleDiv.textContent = params.yTitle + (params.yUnits ? " (" + params.yUnits.trim() + ")" : ""); |
||||
|
||||
this.graphTd = document.createElement("td"); |
||||
tr.appendChild(this.graphTd); |
||||
this.graphTd.className = "rickshaw_graph"; |
||||
this.graphTd.width = params.width; |
||||
this.graphTd.height = params.height; |
||||
|
||||
tr = document.createElement("tr"); |
||||
table.appendChild(tr); |
||||
tr.appendChild(document.createElement("td")); |
||||
var xTitleTd = document.createElement("td"); |
||||
tr.appendChild(xTitleTd); |
||||
xTitleTd.className = "prom_graph_xtitle"; |
||||
xTitleTd.textContent = params.xTitle; |
||||
|
||||
tr = document.createElement("tr"); |
||||
table.appendChild(tr); |
||||
var graphLinkTd = document.createElement("td"); |
||||
tr.appendChild(graphLinkTd); |
||||
var graphLinkA = document.createElement("a"); |
||||
graphLinkTd.appendChild(graphLinkA); |
||||
graphLinkA.className = "prom_graph_link"; |
||||
graphLinkA.textContent = "+"; |
||||
graphLinkA.href = PromConsole._graphsToSlashGraphURL(params.expr); |
||||
var legendTd = document.createElement("td"); |
||||
tr.appendChild(legendTd); |
||||
this.legendDiv = document.createElement("div"); |
||||
legendTd.width = params.width; |
||||
legendTd.appendChild(this.legendDiv); |
||||
|
||||
window.addEventListener('resize', function() { |
||||
if(this.rendered_data !== null) { |
||||
this._render(this.rendered_data); |
||||
} |
||||
}.bind(this)); |
||||
|
||||
this.dispatch(); |
||||
}; |
||||
|
||||
PromConsole.Graph.prototype._parseValue = function(value) { |
||||
var val = parseFloat(value); |
||||
if (isNaN(val)) { |
||||
// "+Inf", "-Inf", "+Inf" will be parsed into NaN by parseFloat(). The
|
||||
// can't be graphed, so show them as gaps (null).
|
||||
return null; |
||||
} |
||||
return val; |
||||
}; |
||||
|
||||
PromConsole.Graph.prototype._escapeHTML = function(string) { |
||||
var entityMap = { |
||||
"&": "&", |
||||
"<": "<", |
||||
">": ">", |
||||
'"': '"', |
||||
"'": ''', |
||||
"/": '/' |
||||
}; |
||||
|
||||
return string.replace(/[&<>"'\/]/g, function (s) { |
||||
return entityMap[s]; |
||||
}); |
||||
}; |
||||
|
||||
PromConsole.Graph.prototype._render = function(data) { |
||||
var self = this; |
||||
var palette = new Rickshaw.Color.Palette({scheme: this.params.colorScheme}); |
||||
var series = []; |
||||
|
||||
// This will be used on resize.
|
||||
this.rendered_data = data; |
||||
|
||||
|
||||
var nameFuncs = []; |
||||
if (this.params.name === null) { |
||||
var chooser = PromConsole._chooseNameFunction(data); |
||||
for (var i = 0; i < this.params.expr.length; i++) { |
||||
nameFuncs.push(chooser); |
||||
} |
||||
} else { |
||||
for (var i = 0; i < this.params.name.length; i++) { |
||||
if (typeof this.params.name[i] == "string") { |
||||
nameFuncs.push(function(i, metric) { |
||||
return PromConsole._interpolateName(this.params.name[i], metric); |
||||
}.bind(this, i)); |
||||
} else { |
||||
nameFuncs.push(this.params.name[i]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Get the data into the right format.
|
||||
var seriesLen = 0; |
||||
|
||||
for (var e = 0; e < data.length; e++) { |
||||
for (var i = 0; i < data[e].data.result.length; i++) { |
||||
series[seriesLen] = { |
||||
data: data[e].data.result[i].values.map(function(s) { return {x: s[0], y: self._parseValue(s[1])}; }), |
||||
color: palette.color(), |
||||
name: self._escapeHTML(nameFuncs[e](data[e].data.result[i].metric)), |
||||
}; |
||||
// Insert nulls for all missing steps.
|
||||
var newSeries = []; |
||||
var pos = 0; |
||||
var start = self.params.endTime - self.params.duration; |
||||
var step = Math.floor(self.params.duration / this.graphTd.offsetWidth * 1000) / 1000; |
||||
for (var t = start; t <= self.params.endTime; t += step) { |
||||
// Allow for floating point inaccuracy.
|
||||
if (series[seriesLen].data.length > pos && series[seriesLen].data[pos].x < t + step / 100) { |
||||
newSeries.push(series[seriesLen].data[pos]); |
||||
pos++; |
||||
} else { |
||||
newSeries.push({x: t, y: null}); |
||||
} |
||||
} |
||||
series[seriesLen].data = newSeries; |
||||
seriesLen++; |
||||
} |
||||
} |
||||
this._clearGraph(); |
||||
if (!series.length) { |
||||
var errorText = document.createElement("div"); |
||||
errorText.className = 'prom_graph_error'; |
||||
errorText.textContent = 'No timeseries returned'; |
||||
this.graphTd.appendChild(errorText); |
||||
return; |
||||
} |
||||
// Render.
|
||||
var graph = new Rickshaw.Graph({ |
||||
interpolation: "linear", |
||||
width: this.graphTd.offsetWidth, |
||||
height: this.params.height, |
||||
element: this.graphTd, |
||||
renderer: this.params.renderer, |
||||
max: this.params.max, |
||||
min: this.params.min, |
||||
series: series |
||||
}); |
||||
var hoverDetail = new Rickshaw.Graph.HoverDetail({ |
||||
graph: graph, |
||||
onRender: function() { |
||||
var xLabel = this.element.getElementsByClassName("x_label")[0]; |
||||
var item = this.element.getElementsByClassName("item")[0]; |
||||
if (xLabel.offsetWidth + xLabel.offsetLeft + this.element.offsetLeft > graph.element.offsetWidth || |
||||
item.offsetWidth + item.offsetLeft + this.element.offsetLeft > graph.element.offsetWidth) { |
||||
xLabel.classList.add("prom_graph_hover_flipped"); |
||||
item.classList.add("prom_graph_hover_flipped"); |
||||
} else { |
||||
xLabel.classList.remove("prom_graph_hover_flipped"); |
||||
item.classList.remove("prom_graph_hover_flipped"); |
||||
} |
||||
}, |
||||
yFormatter: function(y) { |
||||
if (y === null) { |
||||
return ""; |
||||
} |
||||
return this.params.yHoverFormatter(y) + this.params.yUnits; |
||||
}.bind(this) |
||||
}); |
||||
var yAxis = new Rickshaw.Graph.Axis.Y({ |
||||
graph: graph, |
||||
tickFormat: this.params.yAxisFormatter, |
||||
ticks: this.params.yAxisTicks |
||||
}); |
||||
var xAxis = new Rickshaw.Graph.Axis.Time({ |
||||
graph: graph, |
||||
}); |
||||
var legend = new Rickshaw.Graph.Legend({ |
||||
graph: graph, |
||||
element: this.legendDiv |
||||
}); |
||||
xAxis.render(); |
||||
yAxis.render(); |
||||
graph.render(); |
||||
|
||||
this.rickshawGraph = graph; |
||||
}; |
||||
|
||||
PromConsole.Graph.prototype._clearGraph = function() { |
||||
while (this.graphTd.lastChild) { |
||||
this.graphTd.removeChild(this.graphTd.lastChild); |
||||
} |
||||
while (this.legendDiv.lastChild) { |
||||
this.legendDiv.removeChild(this.legendDiv.lastChild); |
||||
} |
||||
this.rickshawGraph = null; |
||||
}; |
||||
|
||||
PromConsole.Graph.prototype._xhrs = []; |
||||
|
||||
PromConsole.Graph.prototype.buildQueryUrl = function(expr) { |
||||
var p = this.params; |
||||
return PATH_PREFIX + "/api/v1/query_range?query=" + |
||||
encodeURIComponent(expr) + |
||||
"&step=" + Math.floor(p.duration / this.graphTd.offsetWidth * 1000) / 1000 + |
||||
"&start=" + (p.endTime - p.duration) + "&end=" + p.endTime; |
||||
}; |
||||
|
||||
PromConsole.Graph.prototype.dispatch = function() { |
||||
for (var j = 0; j < this._xhrs.length; j++) { |
||||
this._xhrs[j].abort(); |
||||
} |
||||
var all_data = new Array(this.params.expr.length); |
||||
this._xhrs = new Array(this.params.expr.length); |
||||
var pending_requests = this.params.expr.length; |
||||
for (var i = 0; i < this.params.expr.length; ++i) { |
||||
var endTime = this.params.endTime; |
||||
var url = this.buildQueryUrl(this.params.expr[i]); |
||||
var xhr = new XMLHttpRequest(); |
||||
xhr.open('get', url, true); |
||||
xhr.responseType = 'json'; |
||||
xhr.onerror = function(xhr, i) { |
||||
this._clearGraph(); |
||||
var errorText = document.createElement("div"); |
||||
errorText.className = 'prom_graph_error'; |
||||
errorText.textContent = 'Error loading data'; |
||||
this.graphTd.appendChild(errorText); |
||||
console.log('Error loading data for ' + this.params.expr[i]); |
||||
pending_requests = 0; |
||||
// onabort gets any aborts.
|
||||
for (var j = 0; j < pending_requests; j++) { |
||||
this._xhrs[j].abort(); |
||||
} |
||||
}.bind(this, xhr, i); |
||||
xhr.onload = function(xhr, i) { |
||||
if (pending_requests === 0) { |
||||
// Got an error before this success.
|
||||
return; |
||||
} |
||||
var data = xhr.response; |
||||
if (typeof data !== "object") { |
||||
data = JSON.parse(xhr.responseText); |
||||
} |
||||
pending_requests -= 1; |
||||
all_data[i] = data; |
||||
if (pending_requests === 0) { |
||||
this._xhrs = []; |
||||
this._render(all_data); |
||||
} |
||||
}.bind(this, xhr, i); |
||||
xhr.send(); |
||||
this._xhrs[i] = xhr; |
||||
} |
||||
|
||||
var loadingImg = document.createElement("img"); |
||||
loadingImg.src = PATH_PREFIX + '/classic/static/img/ajax-loader.gif'; |
||||
loadingImg.alt = 'Loading...'; |
||||
loadingImg.className = 'prom_graph_loading'; |
||||
this.graphTd.appendChild(loadingImg); |
||||
}; |
||||
|
||||
// Substitute the value of 'label' for [[ label ]].
|
||||
PromConsole._interpolateName = function(name, metric) { |
||||
var re = /(.*?)\[\[\s*(\w+)+\s*\]\](.*?)/g; |
||||
var result = ''; |
||||
while (match = re.exec(name)) { |
||||
result = result + match[1] + metric[match[2]] + match[3]; |
||||
} |
||||
if (!result) { |
||||
return name; |
||||
} |
||||
return result; |
||||
}; |
||||
|
||||
// Given the data returned by the API, return an appropriate function
|
||||
// to return plot names.
|
||||
PromConsole._chooseNameFunction = function(data) { |
||||
// By default, use the full metric name.
|
||||
var nameFunc = function (metric) { |
||||
var name = metric.__name__ + "{"; |
||||
for (var label in metric) { |
||||
if (label.substring(0,2) == "__") { |
||||
continue; |
||||
} |
||||
name += label + "='" + metric[label] + "',"; |
||||
} |
||||
return name + "}"; |
||||
}; |
||||
|
||||
// If only one label varies, use that value.
|
||||
var labelValues = {}; |
||||
for (var e = 0; e < data.length; e++) { |
||||
for (var i = 0; i < data[e].data.result.length; i++) { |
||||
for (var label in data[e].data.result[i].metric) { |
||||
if (!(label in labelValues)) { |
||||
labelValues[label] = {}; |
||||
} |
||||
labelValues[label][data[e].data.result[i].metric[label]] = 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
var multiValueLabels = []; |
||||
for (var label in labelValues) { |
||||
if (Object.keys(labelValues[label]).length > 1) { |
||||
multiValueLabels.push(label); |
||||
} |
||||
} |
||||
if (multiValueLabels.length == 1) { |
||||
nameFunc = function(metric) { |
||||
return metric[multiValueLabels[0]]; |
||||
}; |
||||
} |
||||
return nameFunc; |
||||
}; |
||||
|
||||
// Given a list of expressions, produce the /graph url for them.
|
||||
PromConsole._graphsToSlashGraphURL = function(exprs) { |
||||
var data = []; |
||||
for (var i = 0; i < exprs.length; ++i) { |
||||
data.push({'expr': exprs[i], 'tab': 0}); |
||||
} |
||||
return PATH_PREFIX + '/graph#' + encodeURIComponent(JSON.stringify(data)); |
||||
|
||||
}; |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,325 +0,0 @@
|
||||
/*! |
||||
* Bootstrap Reboot v4.5.2 (https://getbootstrap.com/) |
||||
* Copyright 2011-2020 The Bootstrap Authors |
||||
* Copyright 2011-2020 Twitter, Inc. |
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) |
||||
*/ |
||||
*, |
||||
*::before, |
||||
*::after { |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
html { |
||||
font-family: sans-serif; |
||||
line-height: 1.15; |
||||
-webkit-text-size-adjust: 100%; |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
} |
||||
|
||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { |
||||
display: block; |
||||
} |
||||
|
||||
body { |
||||
margin: 0; |
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; |
||||
font-size: 1rem; |
||||
font-weight: 400; |
||||
line-height: 1.5; |
||||
color: #212529; |
||||
text-align: left; |
||||
background-color: #fff; |
||||
} |
||||
|
||||
[tabindex="-1"]:focus:not(:focus-visible) { |
||||
outline: 0 !important; |
||||
} |
||||
|
||||
hr { |
||||
box-sizing: content-box; |
||||
height: 0; |
||||
overflow: visible; |
||||
} |
||||
|
||||
h1, h2, h3, h4, h5, h6 { |
||||
margin-top: 0; |
||||
margin-bottom: 0.5rem; |
||||
} |
||||
|
||||
p { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
abbr[title], |
||||
abbr[data-original-title] { |
||||
text-decoration: underline; |
||||
-webkit-text-decoration: underline dotted; |
||||
text-decoration: underline dotted; |
||||
cursor: help; |
||||
border-bottom: 0; |
||||
-webkit-text-decoration-skip-ink: none; |
||||
text-decoration-skip-ink: none; |
||||
} |
||||
|
||||
address { |
||||
margin-bottom: 1rem; |
||||
font-style: normal; |
||||
line-height: inherit; |
||||
} |
||||
|
||||
ol, |
||||
ul, |
||||
dl { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
ol ol, |
||||
ul ul, |
||||
ol ul, |
||||
ul ol { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
dt { |
||||
font-weight: 700; |
||||
} |
||||
|
||||
dd { |
||||
margin-bottom: .5rem; |
||||
margin-left: 0; |
||||
} |
||||
|
||||
blockquote { |
||||
margin: 0 0 1rem; |
||||
} |
||||
|
||||
b, |
||||
strong { |
||||
font-weight: bolder; |
||||
} |
||||
|
||||
small { |
||||
font-size: 80%; |
||||
} |
||||
|
||||
sub, |
||||
sup { |
||||
position: relative; |
||||
font-size: 75%; |
||||
line-height: 0; |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
sub { |
||||
bottom: -.25em; |
||||
} |
||||
|
||||
sup { |
||||
top: -.5em; |
||||
} |
||||
|
||||
a { |
||||
color: #007bff; |
||||
text-decoration: none; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
a:hover { |
||||
color: #0056b3; |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
a:not([href]):not([class]) { |
||||
color: inherit; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
a:not([href]):not([class]):hover { |
||||
color: inherit; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
pre, |
||||
code, |
||||
kbd, |
||||
samp { |
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; |
||||
font-size: 1em; |
||||
} |
||||
|
||||
pre { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
overflow: auto; |
||||
-ms-overflow-style: scrollbar; |
||||
} |
||||
|
||||
figure { |
||||
margin: 0 0 1rem; |
||||
} |
||||
|
||||
img { |
||||
vertical-align: middle; |
||||
border-style: none; |
||||
} |
||||
|
||||
svg { |
||||
overflow: hidden; |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
table { |
||||
border-collapse: collapse; |
||||
} |
||||
|
||||
caption { |
||||
padding-top: 0.75rem; |
||||
padding-bottom: 0.75rem; |
||||
color: #6c757d; |
||||
text-align: left; |
||||
caption-side: bottom; |
||||
} |
||||
|
||||
th { |
||||
text-align: inherit; |
||||
} |
||||
|
||||
label { |
||||
display: inline-block; |
||||
margin-bottom: 0.5rem; |
||||
} |
||||
|
||||
button { |
||||
border-radius: 0; |
||||
} |
||||
|
||||
button:focus { |
||||
outline: 1px dotted; |
||||
outline: 5px auto -webkit-focus-ring-color; |
||||
} |
||||
|
||||
input, |
||||
button, |
||||
select, |
||||
optgroup, |
||||
textarea { |
||||
margin: 0; |
||||
font-family: inherit; |
||||
font-size: inherit; |
||||
line-height: inherit; |
||||
} |
||||
|
||||
button, |
||||
input { |
||||
overflow: visible; |
||||
} |
||||
|
||||
button, |
||||
select { |
||||
text-transform: none; |
||||
} |
||||
|
||||
[role="button"] { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
select { |
||||
word-wrap: normal; |
||||
} |
||||
|
||||
button, |
||||
[type="button"], |
||||
[type="reset"], |
||||
[type="submit"] { |
||||
-webkit-appearance: button; |
||||
} |
||||
|
||||
button:not(:disabled), |
||||
[type="button"]:not(:disabled), |
||||
[type="reset"]:not(:disabled), |
||||
[type="submit"]:not(:disabled) { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
button::-moz-focus-inner, |
||||
[type="button"]::-moz-focus-inner, |
||||
[type="reset"]::-moz-focus-inner, |
||||
[type="submit"]::-moz-focus-inner { |
||||
padding: 0; |
||||
border-style: none; |
||||
} |
||||
|
||||
input[type="radio"], |
||||
input[type="checkbox"] { |
||||
box-sizing: border-box; |
||||
padding: 0; |
||||
} |
||||
|
||||
textarea { |
||||
overflow: auto; |
||||
resize: vertical; |
||||
} |
||||
|
||||
fieldset { |
||||
min-width: 0; |
||||
padding: 0; |
||||
margin: 0; |
||||
border: 0; |
||||
} |
||||
|
||||
legend { |
||||
display: block; |
||||
width: 100%; |
||||
max-width: 100%; |
||||
padding: 0; |
||||
margin-bottom: .5rem; |
||||
font-size: 1.5rem; |
||||
line-height: inherit; |
||||
color: inherit; |
||||
white-space: normal; |
||||
} |
||||
|
||||
progress { |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
[type="number"]::-webkit-inner-spin-button, |
||||
[type="number"]::-webkit-outer-spin-button { |
||||
height: auto; |
||||
} |
||||
|
||||
[type="search"] { |
||||
outline-offset: -2px; |
||||
-webkit-appearance: none; |
||||
} |
||||
|
||||
[type="search"]::-webkit-search-decoration { |
||||
-webkit-appearance: none; |
||||
} |
||||
|
||||
::-webkit-file-upload-button { |
||||
font: inherit; |
||||
-webkit-appearance: button; |
||||
} |
||||
|
||||
output { |
||||
display: inline-block; |
||||
} |
||||
|
||||
summary { |
||||
display: list-item; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
template { |
||||
display: none; |
||||
} |
||||
|
||||
[hidden] { |
||||
display: none !important; |
||||
} |
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */ |
File diff suppressed because one or more lines are too long
@ -1,8 +0,0 @@
|
||||
/*! |
||||
* Bootstrap Reboot v4.5.2 (https://getbootstrap.com/) |
||||
* Copyright 2011-2020 The Bootstrap Authors |
||||
* Copyright 2011-2020 Twitter, Inc. |
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) |
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} |
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */ |
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,809 +0,0 @@
|
||||
/*! |
||||
* Bootstrap v3.3.7 (http://getbootstrap.com) |
||||
* Copyright 2011-2018 Twitter, Inc. |
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) |
||||
*/ |
||||
|
||||
@font-face { |
||||
font-family: 'Glyphicons Halflings'; |
||||
src: url('../fonts/glyphicons/glyphicons-halflings-regular.eot'); |
||||
src: url('../fonts/glyphicons/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); |
||||
} |
||||
.glyphicon { |
||||
position: relative; |
||||
top: 1px; |
||||
display: inline-block; |
||||
font-family: 'Glyphicons Halflings'; |
||||
font-style: normal; |
||||
font-weight: normal; |
||||
line-height: 1; |
||||
-webkit-font-smoothing: antialiased; |
||||
-moz-osx-font-smoothing: grayscale; |
||||
} |
||||
.glyphicon-asterisk:before { |
||||
content: "\002a"; |
||||
} |
||||
.glyphicon-plus:before { |
||||
content: "\002b"; |
||||
} |
||||
.glyphicon-euro:before, |
||||
.glyphicon-eur:before { |
||||
content: "\20ac"; |
||||
} |
||||
.glyphicon-minus:before { |
||||
content: "\2212"; |
||||
} |
||||
.glyphicon-cloud:before { |
||||
content: "\2601"; |
||||
} |
||||
.glyphicon-envelope:before { |
||||
content: "\2709"; |
||||
} |
||||
.glyphicon-pencil:before { |
||||
content: "\270f"; |
||||
} |
||||
.glyphicon-glass:before { |
||||
content: "\e001"; |
||||
} |
||||
.glyphicon-music:before { |
||||
content: "\e002"; |
||||
} |
||||
.glyphicon-search:before { |
||||
content: "\e003"; |
||||
} |
||||
.glyphicon-heart:before { |
||||
content: "\e005"; |
||||
} |
||||
.glyphicon-star:before { |
||||
content: "\e006"; |
||||
} |
||||
.glyphicon-star-empty:before { |
||||
content: "\e007"; |
||||
} |
||||
.glyphicon-user:before { |
||||
content: "\e008"; |
||||
} |
||||
.glyphicon-film:before { |
||||
content: "\e009"; |
||||
} |
||||
.glyphicon-th-large:before { |
||||
content: "\e010"; |
||||
} |
||||
.glyphicon-th:before { |
||||
content: "\e011"; |
||||
} |
||||
.glyphicon-th-list:before { |
||||
content: "\e012"; |
||||
} |
||||
.glyphicon-ok:before { |
||||
content: "\e013"; |
||||
} |
||||
.glyphicon-remove:before { |
||||
content: "\e014"; |
||||
} |
||||
.glyphicon-zoom-in:before { |
||||
content: "\e015"; |
||||
} |
||||
.glyphicon-zoom-out:before { |
||||
content: "\e016"; |
||||
} |
||||
.glyphicon-off:before { |
||||
content: "\e017"; |
||||
} |
||||
.glyphicon-signal:before { |
||||
content: "\e018"; |
||||
} |
||||
.glyphicon-cog:before { |
||||
content: "\e019"; |
||||
} |
||||
.glyphicon-trash:before { |
||||
content: "\e020"; |
||||
} |
||||
.glyphicon-home:before { |
||||
content: "\e021"; |
||||
} |
||||
.glyphicon-file:before { |
||||
content: "\e022"; |
||||
} |
||||
.glyphicon-time:before { |
||||
content: "\e023"; |
||||
} |
||||
.glyphicon-road:before { |
||||
content: "\e024"; |
||||
} |
||||
.glyphicon-download-alt:before { |
||||
content: "\e025"; |
||||
} |
||||
.glyphicon-download:before { |
||||
content: "\e026"; |
||||
} |
||||
.glyphicon-upload:before { |
||||
content: "\e027"; |
||||
} |
||||
.glyphicon-inbox:before { |
||||
content: "\e028"; |
||||
} |
||||
.glyphicon-play-circle:before { |
||||
content: "\e029"; |
||||
} |
||||
.glyphicon-repeat:before { |
||||
content: "\e030"; |
||||
} |
||||
.glyphicon-refresh:before { |
||||
content: "\e031"; |
||||
} |
||||
.glyphicon-list-alt:before { |
||||
content: "\e032"; |
||||
} |
||||
.glyphicon-lock:before { |
||||
content: "\e033"; |
||||
} |
||||
.glyphicon-flag:before { |
||||
content: "\e034"; |
||||
} |
||||
.glyphicon-headphones:before { |
||||
content: "\e035"; |
||||
} |
||||
.glyphicon-volume-off:before { |
||||
content: "\e036"; |
||||
} |
||||
.glyphicon-volume-down:before { |
||||
content: "\e037"; |
||||
} |
||||
.glyphicon-volume-up:before { |
||||
content: "\e038"; |
||||
} |
||||
.glyphicon-qrcode:before { |
||||
content: "\e039"; |
||||
} |
||||
.glyphicon-barcode:before { |
||||
content: "\e040"; |
||||
} |
||||
.glyphicon-tag:before { |
||||
content: "\e041"; |
||||
} |
||||
.glyphicon-tags:before { |
||||
content: "\e042"; |
||||
} |
||||
.glyphicon-book:before { |
||||
content: "\e043"; |
||||
} |
||||
.glyphicon-bookmark:before { |
||||
content: "\e044"; |
||||
} |
||||
.glyphicon-print:before { |
||||
content: "\e045"; |
||||
} |
||||
.glyphicon-camera:before { |
||||
content: "\e046"; |
||||
} |
||||
.glyphicon-font:before { |
||||
content: "\e047"; |
||||
} |
||||
.glyphicon-bold:before { |
||||
content: "\e048"; |
||||
} |
||||
.glyphicon-italic:before { |
||||
content: "\e049"; |
||||
} |
||||
.glyphicon-text-height:before { |
||||
content: "\e050"; |
||||
} |
||||
.glyphicon-text-width:before { |
||||
content: "\e051"; |
||||
} |
||||
.glyphicon-align-left:before { |
||||
content: "\e052"; |
||||
} |
||||
.glyphicon-align-center:before { |
||||
content: "\e053"; |
||||
} |
||||
.glyphicon-align-right:before { |
||||
content: "\e054"; |
||||
} |
||||
.glyphicon-align-justify:before { |
||||
content: "\e055"; |
||||
} |
||||
.glyphicon-list:before { |
||||
content: "\e056"; |
||||
} |
||||
.glyphicon-indent-left:before { |
||||
content: "\e057"; |
||||
} |
||||
.glyphicon-indent-right:before { |
||||
content: "\e058"; |
||||
} |
||||
.glyphicon-facetime-video:before { |
||||
content: "\e059"; |
||||
} |
||||
.glyphicon-picture:before { |
||||
content: "\e060"; |
||||
} |
||||
.glyphicon-map-marker:before { |
||||
content: "\e062"; |
||||
} |
||||
.glyphicon-adjust:before { |
||||
content: "\e063"; |
||||
} |
||||
.glyphicon-tint:before { |
||||
content: "\e064"; |
||||
} |
||||
.glyphicon-edit:before { |
||||
content: "\e065"; |
||||
} |
||||
.glyphicon-share:before { |
||||
content: "\e066"; |
||||
} |
||||
.glyphicon-check:before { |
||||
content: "\e067"; |
||||
} |
||||
.glyphicon-move:before { |
||||
content: "\e068"; |
||||
} |
||||
.glyphicon-step-backward:before { |
||||
content: "\e069"; |
||||
} |
||||
.glyphicon-fast-backward:before { |
||||
content: "\e070"; |
||||
} |
||||
.glyphicon-backward:before { |
||||
content: "\e071"; |
||||
} |
||||
.glyphicon-play:before { |
||||
content: "\e072"; |
||||
} |
||||
.glyphicon-pause:before { |
||||
content: "\e073"; |
||||
} |
||||
.glyphicon-stop:before { |
||||
content: "\e074"; |
||||
} |
||||
.glyphicon-forward:before { |
||||
content: "\e075"; |
||||
} |
||||
.glyphicon-fast-forward:before { |
||||
content: "\e076"; |
||||
} |
||||
.glyphicon-step-forward:before { |
||||
content: "\e077"; |
||||
} |
||||
.glyphicon-eject:before { |
||||
content: "\e078"; |
||||
} |
||||
.glyphicon-chevron-left:before { |
||||
content: "\e079"; |
||||
} |
||||
.glyphicon-chevron-right:before { |
||||
content: "\e080"; |
||||
} |
||||
.glyphicon-plus-sign:before { |
||||
content: "\e081"; |
||||
} |
||||
.glyphicon-minus-sign:before { |
||||
content: "\e082"; |
||||
} |
||||
.glyphicon-remove-sign:before { |
||||
content: "\e083"; |
||||
} |
||||
.glyphicon-ok-sign:before { |
||||
content: "\e084"; |
||||
} |
||||
.glyphicon-question-sign:before { |
||||
content: "\e085"; |
||||
} |
||||
.glyphicon-info-sign:before { |
||||
content: "\e086"; |
||||
} |
||||
.glyphicon-screenshot:before { |
||||
content: "\e087"; |
||||
} |
||||
.glyphicon-remove-circle:before { |
||||
content: "\e088"; |
||||
} |
||||
.glyphicon-ok-circle:before { |
||||
content: "\e089"; |
||||
} |
||||
.glyphicon-ban-circle:before { |
||||
content: "\e090"; |
||||
} |
||||
.glyphicon-arrow-left:before { |
||||
content: "\e091"; |
||||
} |
||||
.glyphicon-arrow-right:before { |
||||
content: "\e092"; |
||||
} |
||||
.glyphicon-arrow-up:before { |
||||
content: "\e093"; |
||||
} |
||||
.glyphicon-arrow-down:before { |
||||
content: "\e094"; |
||||
} |
||||
.glyphicon-share-alt:before { |
||||
content: "\e095"; |
||||
} |
||||
.glyphicon-resize-full:before { |
||||
content: "\e096"; |
||||
} |
||||
.glyphicon-resize-small:before { |
||||
content: "\e097"; |
||||
} |
||||
.glyphicon-exclamation-sign:before { |
||||
content: "\e101"; |
||||
} |
||||
.glyphicon-gift:before { |
||||
content: "\e102"; |
||||
} |
||||
.glyphicon-leaf:before { |
||||
content: "\e103"; |
||||
} |
||||
.glyphicon-fire:before { |
||||
content: "\e104"; |
||||
} |
||||
.glyphicon-eye-open:before { |
||||
content: "\e105"; |
||||
} |
||||
.glyphicon-eye-close:before { |
||||
content: "\e106"; |
||||
} |
||||
.glyphicon-warning-sign:before { |
||||
content: "\e107"; |
||||
} |
||||
.glyphicon-plane:before { |
||||
content: "\e108"; |
||||
} |
||||
.glyphicon-calendar:before { |
||||
content: "\e109"; |
||||
} |
||||
.glyphicon-random:before { |
||||
content: "\e110"; |
||||
} |
||||
.glyphicon-comment:before { |
||||
content: "\e111"; |
||||
} |
||||
.glyphicon-magnet:before { |
||||
content: "\e112"; |
||||
} |
||||
.glyphicon-chevron-up:before { |
||||
content: "\e113"; |
||||
} |
||||
.glyphicon-chevron-down:before { |
||||
content: "\e114"; |
||||
} |
||||
.glyphicon-retweet:before { |
||||
content: "\e115"; |
||||
} |
||||
.glyphicon-shopping-cart:before { |
||||
content: "\e116"; |
||||
} |
||||
.glyphicon-folder-close:before { |
||||
content: "\e117"; |
||||
} |
||||
.glyphicon-folder-open:before { |
||||
content: "\e118"; |
||||
} |
||||
.glyphicon-resize-vertical:before { |
||||
content: "\e119"; |
||||
} |
||||
.glyphicon-resize-horizontal:before { |
||||
content: "\e120"; |
||||
} |
||||
.glyphicon-hdd:before { |
||||
content: "\e121"; |
||||
} |
||||
.glyphicon-bullhorn:before { |
||||
content: "\e122"; |
||||
} |
||||
.glyphicon-bell:before { |
||||
content: "\e123"; |
||||
} |
||||
.glyphicon-certificate:before { |
||||
content: "\e124"; |
||||
} |
||||
.glyphicon-thumbs-up:before { |
||||
content: "\e125"; |
||||
} |
||||
.glyphicon-thumbs-down:before { |
||||
content: "\e126"; |
||||
} |
||||
.glyphicon-hand-right:before { |
||||
content: "\e127"; |
||||
} |
||||
.glyphicon-hand-left:before { |
||||
content: "\e128"; |
||||
} |
||||
.glyphicon-hand-up:before { |
||||
content: "\e129"; |
||||
} |
||||
.glyphicon-hand-down:before { |
||||
content: "\e130"; |
||||
} |
||||
.glyphicon-circle-arrow-right:before { |
||||
content: "\e131"; |
||||
} |
||||
.glyphicon-circle-arrow-left:before { |
||||
content: "\e132"; |
||||
} |
||||
.glyphicon-circle-arrow-up:before { |
||||
content: "\e133"; |
||||
} |
||||
.glyphicon-circle-arrow-down:before { |
||||
content: "\e134"; |
||||
} |
||||
.glyphicon-globe:before { |
||||
content: "\e135"; |
||||
} |
||||
.glyphicon-wrench:before { |
||||
content: "\e136"; |
||||
} |
||||
.glyphicon-tasks:before { |
||||
content: "\e137"; |
||||
} |
||||
.glyphicon-filter:before { |
||||
content: "\e138"; |
||||
} |
||||
.glyphicon-briefcase:before { |
||||
content: "\e139"; |
||||
} |
||||
.glyphicon-fullscreen:before { |
||||
content: "\e140"; |
||||
} |
||||
.glyphicon-dashboard:before { |
||||
content: "\e141"; |
||||
} |
||||
.glyphicon-paperclip:before { |
||||
content: "\e142"; |
||||
} |
||||
.glyphicon-heart-empty:before { |
||||
content: "\e143"; |
||||
} |
||||
.glyphicon-link:before { |
||||
content: "\e144"; |
||||
} |
||||
.glyphicon-phone:before { |
||||
content: "\e145"; |
||||
} |
||||
.glyphicon-pushpin:before { |
||||
content: "\e146"; |
||||
} |
||||
.glyphicon-usd:before { |
||||
content: "\e148"; |
||||
} |
||||
.glyphicon-gbp:before { |
||||
content: "\e149"; |
||||
} |
||||
.glyphicon-sort:before { |
||||
content: "\e150"; |
||||
} |
||||
.glyphicon-sort-by-alphabet:before { |
||||
content: "\e151"; |
||||
} |
||||
.glyphicon-sort-by-alphabet-alt:before { |
||||
content: "\e152"; |
||||
} |
||||
.glyphicon-sort-by-order:before { |
||||
content: "\e153"; |
||||
} |
||||
.glyphicon-sort-by-order-alt:before { |
||||
content: "\e154"; |
||||
} |
||||
.glyphicon-sort-by-attributes:before { |
||||
content: "\e155"; |
||||
} |
||||
.glyphicon-sort-by-attributes-alt:before { |
||||
content: "\e156"; |
||||
} |
||||
.glyphicon-unchecked:before { |
||||
content: "\e157"; |
||||
} |
||||
.glyphicon-expand:before { |
||||
content: "\e158"; |
||||
} |
||||
.glyphicon-collapse-down:before { |
||||
content: "\e159"; |
||||
} |
||||
.glyphicon-collapse-up:before { |
||||
content: "\e160"; |
||||
} |
||||
.glyphicon-log-in:before { |
||||
content: "\e161"; |
||||
} |
||||
.glyphicon-flash:before { |
||||
content: "\e162"; |
||||
} |
||||
.glyphicon-log-out:before { |
||||
content: "\e163"; |
||||
} |
||||
.glyphicon-new-window:before { |
||||
content: "\e164"; |
||||
} |
||||
.glyphicon-record:before { |
||||
content: "\e165"; |
||||
} |
||||
.glyphicon-save:before { |
||||
content: "\e166"; |
||||
} |
||||
.glyphicon-open:before { |
||||
content: "\e167"; |
||||
} |
||||
.glyphicon-saved:before { |
||||
content: "\e168"; |
||||
} |
||||
.glyphicon-import:before { |
||||
content: "\e169"; |
||||
} |
||||
.glyphicon-export:before { |
||||
content: "\e170"; |
||||
} |
||||
.glyphicon-send:before { |
||||
content: "\e171"; |
||||
} |
||||
.glyphicon-floppy-disk:before { |
||||
content: "\e172"; |
||||
} |
||||
.glyphicon-floppy-saved:before { |
||||
content: "\e173"; |
||||
} |
||||
.glyphicon-floppy-remove:before { |
||||
content: "\e174"; |
||||
} |
||||
.glyphicon-floppy-save:before { |
||||
content: "\e175"; |
||||
} |
||||
.glyphicon-floppy-open:before { |
||||
content: "\e176"; |
||||
} |
||||
.glyphicon-credit-card:before { |
||||
content: "\e177"; |
||||
} |
||||
.glyphicon-transfer:before { |
||||
content: "\e178"; |
||||
} |
||||
.glyphicon-cutlery:before { |
||||
content: "\e179"; |
||||
} |
||||
.glyphicon-header:before { |
||||
content: "\e180"; |
||||
} |
||||
.glyphicon-compressed:before { |
||||
content: "\e181"; |
||||
} |
||||
.glyphicon-earphone:before { |
||||
content: "\e182"; |
||||
} |
||||
.glyphicon-phone-alt:before { |
||||
content: "\e183"; |
||||
} |
||||
.glyphicon-tower:before { |
||||
content: "\e184"; |
||||
} |
||||
.glyphicon-stats:before { |
||||
content: "\e185"; |
||||
} |
||||
.glyphicon-sd-video:before { |
||||
content: "\e186"; |
||||
} |
||||
.glyphicon-hd-video:before { |
||||
content: "\e187"; |
||||
} |
||||
.glyphicon-subtitles:before { |
||||
content: "\e188"; |
||||
} |
||||
.glyphicon-sound-stereo:before { |
||||
content: "\e189"; |
||||
} |
||||
.glyphicon-sound-dolby:before { |
||||
content: "\e190"; |
||||
} |
||||
.glyphicon-sound-5-1:before { |
||||
content: "\e191"; |
||||
} |
||||
.glyphicon-sound-6-1:before { |
||||
content: "\e192"; |
||||
} |
||||
.glyphicon-sound-7-1:before { |
||||
content: "\e193"; |
||||
} |
||||
.glyphicon-copyright-mark:before { |
||||
content: "\e194"; |
||||
} |
||||
.glyphicon-registration-mark:before { |
||||
content: "\e195"; |
||||
} |
||||
.glyphicon-cloud-download:before { |
||||
content: "\e197"; |
||||
} |
||||
.glyphicon-cloud-upload:before { |
||||
content: "\e198"; |
||||
} |
||||
.glyphicon-tree-conifer:before { |
||||
content: "\e199"; |
||||
} |
||||
.glyphicon-tree-deciduous:before { |
||||
content: "\e200"; |
||||
} |
||||
.glyphicon-cd:before { |
||||
content: "\e201"; |
||||
} |
||||
.glyphicon-save-file:before { |
||||
content: "\e202"; |
||||
} |
||||
.glyphicon-open-file:before { |
||||
content: "\e203"; |
||||
} |
||||
.glyphicon-level-up:before { |
||||
content: "\e204"; |
||||
} |
||||
.glyphicon-copy:before { |
||||
content: "\e205"; |
||||
} |
||||
.glyphicon-paste:before { |
||||
content: "\e206"; |
||||
} |
||||
.glyphicon-alert:before { |
||||
content: "\e209"; |
||||
} |
||||
.glyphicon-equalizer:before { |
||||
content: "\e210"; |
||||
} |
||||
.glyphicon-king:before { |
||||
content: "\e211"; |
||||
} |
||||
.glyphicon-queen:before { |
||||
content: "\e212"; |
||||
} |
||||
.glyphicon-pawn:before { |
||||
content: "\e213"; |
||||
} |
||||
.glyphicon-bishop:before { |
||||
content: "\e214"; |
||||
} |
||||
.glyphicon-knight:before { |
||||
content: "\e215"; |
||||
} |
||||
.glyphicon-baby-formula:before { |
||||
content: "\e216"; |
||||
} |
||||
.glyphicon-tent:before { |
||||
content: "\26fa"; |
||||
} |
||||
.glyphicon-blackboard:before { |
||||
content: "\e218"; |
||||
} |
||||
.glyphicon-bed:before { |
||||
content: "\e219"; |
||||
} |
||||
.glyphicon-apple:before { |
||||
content: "\f8ff"; |
||||
} |
||||
.glyphicon-erase:before { |
||||
content: "\e221"; |
||||
} |
||||
.glyphicon-hourglass:before { |
||||
content: "\231b"; |
||||
} |
||||
.glyphicon-lamp:before { |
||||
content: "\e223"; |
||||
} |
||||
.glyphicon-duplicate:before { |
||||
content: "\e224"; |
||||
} |
||||
.glyphicon-piggy-bank:before { |
||||
content: "\e225"; |
||||
} |
||||
.glyphicon-scissors:before { |
||||
content: "\e226"; |
||||
} |
||||
.glyphicon-bitcoin:before { |
||||
content: "\e227"; |
||||
} |
||||
.glyphicon-btc:before { |
||||
content: "\e227"; |
||||
} |
||||
.glyphicon-xbt:before { |
||||
content: "\e227"; |
||||
} |
||||
.glyphicon-yen:before { |
||||
content: "\00a5"; |
||||
} |
||||
.glyphicon-jpy:before { |
||||
content: "\00a5"; |
||||
} |
||||
.glyphicon-ruble:before { |
||||
content: "\20bd"; |
||||
} |
||||
.glyphicon-rub:before { |
||||
content: "\20bd"; |
||||
} |
||||
.glyphicon-scale:before { |
||||
content: "\e230"; |
||||
} |
||||
.glyphicon-ice-lolly:before { |
||||
content: "\e231"; |
||||
} |
||||
.glyphicon-ice-lolly-tasted:before { |
||||
content: "\e232"; |
||||
} |
||||
.glyphicon-education:before { |
||||
content: "\e233"; |
||||
} |
||||
.glyphicon-option-horizontal:before { |
||||
content: "\e234"; |
||||
} |
||||
.glyphicon-option-vertical:before { |
||||
content: "\e235"; |
||||
} |
||||
.glyphicon-menu-hamburger:before { |
||||
content: "\e236"; |
||||
} |
||||
.glyphicon-modal-window:before { |
||||
content: "\e237"; |
||||
} |
||||
.glyphicon-oil:before { |
||||
content: "\e238"; |
||||
} |
||||
.glyphicon-grain:before { |
||||
content: "\e239"; |
||||
} |
||||
.glyphicon-sunglasses:before { |
||||
content: "\e240"; |
||||
} |
||||
.glyphicon-text-size:before { |
||||
content: "\e241"; |
||||
} |
||||
.glyphicon-text-color:before { |
||||
content: "\e242"; |
||||
} |
||||
.glyphicon-text-background:before { |
||||
content: "\e243"; |
||||
} |
||||
.glyphicon-object-align-top:before { |
||||
content: "\e244"; |
||||
} |
||||
.glyphicon-object-align-bottom:before { |
||||
content: "\e245"; |
||||
} |
||||
.glyphicon-object-align-horizontal:before { |
||||
content: "\e246"; |
||||
} |
||||
.glyphicon-object-align-left:before { |
||||
content: "\e247"; |
||||
} |
||||
.glyphicon-object-align-vertical:before { |
||||
content: "\e248"; |
||||
} |
||||
.glyphicon-object-align-right:before { |
||||
content: "\e249"; |
||||
} |
||||
.glyphicon-triangle-right:before { |
||||
content: "\e250"; |
||||
} |
||||
.glyphicon-triangle-left:before { |
||||
content: "\e251"; |
||||
} |
||||
.glyphicon-triangle-bottom:before { |
||||
content: "\e252"; |
||||
} |
||||
.glyphicon-triangle-top:before { |
||||
content: "\e253"; |
||||
} |
||||
.glyphicon-console:before { |
||||
content: "\e254"; |
||||
} |
||||
.glyphicon-superscript:before { |
||||
content: "\e255"; |
||||
} |
||||
.glyphicon-subscript:before { |
||||
content: "\e256"; |
||||
} |
||||
.glyphicon-menu-left:before { |
||||
content: "\e257"; |
||||
} |
||||
.glyphicon-menu-right:before { |
||||
content: "\e258"; |
||||
} |
||||
.glyphicon-menu-down:before { |
||||
content: "\e259"; |
||||
} |
||||
.glyphicon-menu-up:before { |
||||
content: "\e260"; |
||||
} |
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 496 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 105 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 369 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 106 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,113 +0,0 @@
|
||||
/* |
||||
* jQuery Hotkeys Plugin |
||||
* Copyright 2010, John Resig |
||||
* Dual licensed under the MIT or GPL Version 2 licenses. |
||||
* |
||||
* Based upon the plugin by Tzury Bar Yochay: |
||||
* http://github.com/tzuryby/hotkeys
|
||||
* |
||||
* Original idea by: |
||||
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
||||
*/ |
||||
|
||||
(function(jQuery){ |
||||
|
||||
jQuery.hotkeys = { |
||||
version: "0.8+", |
||||
|
||||
specialKeys: { |
||||
8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", |
||||
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", |
||||
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", |
||||
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", |
||||
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", |
||||
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", |
||||
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 188: ",", 190: ".", |
||||
191: "/", 224: "meta" |
||||
}, |
||||
|
||||
shiftNums: { |
||||
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", |
||||
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", |
||||
".": ">", "/": "?", "\\": "|" |
||||
} |
||||
}; |
||||
|
||||
function keyHandler( handleObj ) { |
||||
|
||||
var origHandler = handleObj.handler, |
||||
//use namespace as keys so it works with event delegation as well
|
||||
//will also allow removing listeners of a specific key combination
|
||||
//and support data objects
|
||||
keys = (handleObj.namespace || "").toLowerCase().split(" "); |
||||
keys = jQuery.map(keys, function(key) { return key.split("."); }); |
||||
|
||||
//no need to modify handler if no keys specified
|
||||
//Added keys[0].substring(0, 12) to work with jQuery ui 1.9.0
|
||||
//Added accordion, tabs and menu, then jquery ui can use keys.
|
||||
|
||||
if (keys.length === 1 && (keys[0] === "" || |
||||
keys[0].substring(0, 12) === "autocomplete" || |
||||
keys[0].substring(0, 9) === "accordion" || |
||||
keys[0].substring(0, 4) === "tabs" || |
||||
keys[0].substring(0, 4) === "menu")) { |
||||
return; |
||||
} |
||||
|
||||
handleObj.handler = function( event ) { |
||||
// Don't fire in text-accepting inputs that we didn't directly bind to
|
||||
// important to note that $.fn.prop is only available on jquery 1.6+
|
||||
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || |
||||
event.target.type === "text" || $(event.target).prop('contenteditable') == 'true' )) { |
||||
return; |
||||
} |
||||
|
||||
// Keypress represents characters, not special keys
|
||||
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ], |
||||
character = String.fromCharCode( event.which ).toLowerCase(), |
||||
key, modif = "", possible = {}; |
||||
|
||||
// check combinations (alt|ctrl|shift+anything)
|
||||
if ( event.altKey && special !== "alt" ) { |
||||
modif += "alt_"; |
||||
} |
||||
|
||||
if ( event.ctrlKey && special !== "ctrl" ) { |
||||
modif += "ctrl_"; |
||||
} |
||||
|
||||
// TODO: Need to make sure this works consistently across platforms
|
||||
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { |
||||
modif += "meta_"; |
||||
} |
||||
|
||||
if ( event.shiftKey && special !== "shift" ) { |
||||
modif += "shift_"; |
||||
} |
||||
|
||||
if ( special ) { |
||||
possible[ modif + special ] = true; |
||||
|
||||
} else { |
||||
possible[ modif + character ] = true; |
||||
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; |
||||
|
||||
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
|
||||
if ( modif === "shift_" ) { |
||||
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; |
||||
} |
||||
} |
||||
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) { |
||||
if ( possible[ keys[i] ] ) { |
||||
return origHandler.apply( this, arguments ); |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
jQuery.each([ "keydown", "keyup", "keypress" ], function() { |
||||
jQuery.event.special[ this ] = { add: keyHandler }; |
||||
}); |
||||
|
||||
})( jQuery ); |
@ -1,354 +0,0 @@
|
||||
/*! |
||||
* jQuery.selection - jQuery Plugin |
||||
* |
||||
* Copyright (c) 2010-2014 IWASAKI Koji (@madapaja). |
||||
* http://blog.madapaja.net/
|
||||
* Under The MIT License |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining |
||||
* a copy of this software and associated documentation files (the |
||||
* "Software"), to deal in the Software without restriction, including |
||||
* without limitation the rights to use, copy, modify, merge, publish, |
||||
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
* permit persons to whom the Software is furnished to do so, subject to |
||||
* the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be |
||||
* included in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
(function($, win, doc) { |
||||
/** |
||||
* get caret status of the selection of the element |
||||
* |
||||
* @param {Element} element target DOM element |
||||
* @return {Object} return |
||||
* @return {String} return.text selected text |
||||
* @return {Number} return.start start position of the selection |
||||
* @return {Number} return.end end position of the selection |
||||
*/ |
||||
var _getCaretInfo = function(element){ |
||||
var res = { |
||||
text: '', |
||||
start: 0, |
||||
end: 0 |
||||
}; |
||||
|
||||
if (!element.value) { |
||||
/* no value or empty string */ |
||||
return res; |
||||
} |
||||
|
||||
try { |
||||
if (win.getSelection) { |
||||
/* except IE */ |
||||
res.start = element.selectionStart; |
||||
res.end = element.selectionEnd; |
||||
res.text = element.value.slice(res.start, res.end); |
||||
} else if (doc.selection) { |
||||
/* for IE */ |
||||
element.focus(); |
||||
|
||||
var range = doc.selection.createRange(), |
||||
range2 = doc.body.createTextRange(); |
||||
|
||||
res.text = range.text; |
||||
|
||||
try { |
||||
range2.moveToElementText(element); |
||||
range2.setEndPoint('StartToStart', range); |
||||
} catch (e) { |
||||
range2 = element.createTextRange(); |
||||
range2.setEndPoint('StartToStart', range); |
||||
} |
||||
|
||||
res.start = element.value.length - range2.text.length; |
||||
res.end = res.start + range.text.length; |
||||
} |
||||
} catch (e) { |
||||
/* give up */ |
||||
} |
||||
|
||||
return res; |
||||
}; |
||||
|
||||
/** |
||||
* caret operation for the element |
||||
* @type {Object} |
||||
*/ |
||||
var _CaretOperation = { |
||||
/** |
||||
* get caret position |
||||
* |
||||
* @param {Element} element target element |
||||
* @return {Object} return |
||||
* @return {Number} return.start start position for the selection |
||||
* @return {Number} return.end end position for the selection |
||||
*/ |
||||
getPos: function(element) { |
||||
var tmp = _getCaretInfo(element); |
||||
return {start: tmp.start, end: tmp.end}; |
||||
}, |
||||
|
||||
/** |
||||
* set caret position |
||||
* |
||||
* @param {Element} element target element |
||||
* @param {Object} toRange caret position |
||||
* @param {Number} toRange.start start position for the selection |
||||
* @param {Number} toRange.end end position for the selection |
||||
* @param {String} caret caret mode: any of the following: "keep" | "start" | "end" |
||||
*/ |
||||
setPos: function(element, toRange, caret) { |
||||
caret = this._caretMode(caret); |
||||
|
||||
if (caret === 'start') { |
||||
toRange.end = toRange.start; |
||||
} else if (caret === 'end') { |
||||
toRange.start = toRange.end; |
||||
} |
||||
|
||||
element.focus(); |
||||
try { |
||||
if (element.createTextRange) { |
||||
var range = element.createTextRange(); |
||||
|
||||
if (win.navigator.userAgent.toLowerCase().indexOf("msie") >= 0) { |
||||
toRange.start = element.value.substr(0, toRange.start).replace(/\r/g, '').length; |
||||
toRange.end = element.value.substr(0, toRange.end).replace(/\r/g, '').length; |
||||
} |
||||
|
||||
range.collapse(true); |
||||
range.moveStart('character', toRange.start); |
||||
range.moveEnd('character', toRange.end - toRange.start); |
||||
|
||||
range.select(); |
||||
} else if (element.setSelectionRange) { |
||||
element.setSelectionRange(toRange.start, toRange.end); |
||||
} |
||||
} catch (e) { |
||||
/* give up */ |
||||
} |
||||
}, |
||||
|
||||
/** |
||||
* get selected text |
||||
* |
||||
* @param {Element} element target element |
||||
* @return {String} return selected text |
||||
*/ |
||||
getText: function(element) { |
||||
return _getCaretInfo(element).text; |
||||
}, |
||||
|
||||
/** |
||||
* get caret mode |
||||
* |
||||
* @param {String} caret caret mode |
||||
* @return {String} return any of the following: "keep" | "start" | "end" |
||||
*/ |
||||
_caretMode: function(caret) { |
||||
caret = caret || "keep"; |
||||
if (caret === false) { |
||||
caret = 'end'; |
||||
} |
||||
|
||||
switch (caret) { |
||||
case 'keep': |
||||
case 'start': |
||||
case 'end': |
||||
break; |
||||
|
||||
default: |
||||
caret = 'keep'; |
||||
} |
||||
|
||||
return caret; |
||||
}, |
||||
|
||||
/** |
||||
* replace selected text |
||||
* |
||||
* @param {Element} element target element |
||||
* @param {String} text replacement text |
||||
* @param {String} caret caret mode: any of the following: "keep" | "start" | "end" |
||||
*/ |
||||
replace: function(element, text, caret) { |
||||
var tmp = _getCaretInfo(element), |
||||
orig = element.value, |
||||
pos = $(element).scrollTop(), |
||||
range = {start: tmp.start, end: tmp.start + text.length}; |
||||
|
||||
element.value = orig.substr(0, tmp.start) + text + orig.substr(tmp.end); |
||||
|
||||
$(element).scrollTop(pos); |
||||
this.setPos(element, range, caret); |
||||
}, |
||||
|
||||
/** |
||||
* insert before the selected text |
||||
* |
||||
* @param {Element} element target element |
||||
* @param {String} text insertion text |
||||
* @param {String} caret caret mode: any of the following: "keep" | "start" | "end" |
||||
*/ |
||||
insertBefore: function(element, text, caret) { |
||||
var tmp = _getCaretInfo(element), |
||||
orig = element.value, |
||||
pos = $(element).scrollTop(), |
||||
range = {start: tmp.start + text.length, end: tmp.end + text.length}; |
||||
|
||||
element.value = orig.substr(0, tmp.start) + text + orig.substr(tmp.start); |
||||
|
||||
$(element).scrollTop(pos); |
||||
this.setPos(element, range, caret); |
||||
}, |
||||
|
||||
/** |
||||
* insert after the selected text |
||||
* |
||||
* @param {Element} element target element |
||||
* @param {String} text insertion text |
||||
* @param {String} caret caret mode: any of the following: "keep" | "start" | "end" |
||||
*/ |
||||
insertAfter: function(element, text, caret) { |
||||
var tmp = _getCaretInfo(element), |
||||
orig = element.value, |
||||
pos = $(element).scrollTop(), |
||||
range = {start: tmp.start, end: tmp.end}; |
||||
|
||||
element.value = orig.substr(0, tmp.end) + text + orig.substr(tmp.end); |
||||
|
||||
$(element).scrollTop(pos); |
||||
this.setPos(element, range, caret); |
||||
} |
||||
}; |
||||
|
||||
/* add jQuery.selection */ |
||||
$.extend({ |
||||
/** |
||||
* get selected text on the window |
||||
* |
||||
* @param {String} mode selection mode: any of the following: "text" | "html" |
||||
* @return {String} return |
||||
*/ |
||||
selection: function(mode) { |
||||
var getText = ((mode || 'text').toLowerCase() === 'text'); |
||||
|
||||
try { |
||||
if (win.getSelection) { |
||||
if (getText) { |
||||
// get text
|
||||
return win.getSelection().toString(); |
||||
} else { |
||||
// get html
|
||||
var sel = win.getSelection(), range; |
||||
|
||||
if (sel.getRangeAt) { |
||||
range = sel.getRangeAt(0); |
||||
} else { |
||||
range = doc.createRange(); |
||||
range.setStart(sel.anchorNode, sel.anchorOffset); |
||||
range.setEnd(sel.focusNode, sel.focusOffset); |
||||
} |
||||
|
||||
return $('<div></div>').append(range.cloneContents()).html(); |
||||
} |
||||
} else if (doc.selection) { |
||||
if (getText) { |
||||
// get text
|
||||
return doc.selection.createRange().text; |
||||
} else { |
||||
// get html
|
||||
return doc.selection.createRange().htmlText; |
||||
} |
||||
} |
||||
} catch (e) { |
||||
/* give up */ |
||||
} |
||||
|
||||
return ''; |
||||
} |
||||
}); |
||||
|
||||
/* add selection */ |
||||
$.fn.extend({ |
||||
selection: function(mode, opts) { |
||||
opts = opts || {}; |
||||
|
||||
switch (mode) { |
||||
/** |
||||
* selection('getPos') |
||||
* get caret position |
||||
* |
||||
* @return {Object} return |
||||
* @return {Number} return.start start position for the selection |
||||
* @return {Number} return.end end position for the selection |
||||
*/ |
||||
case 'getPos': |
||||
return _CaretOperation.getPos(this[0]); |
||||
|
||||
/** |
||||
* selection('setPos', opts) |
||||
* set caret position |
||||
* |
||||
* @param {Number} opts.start start position for the selection |
||||
* @param {Number} opts.end end position for the selection |
||||
*/ |
||||
case 'setPos': |
||||
return this.each(function() { |
||||
_CaretOperation.setPos(this, opts); |
||||
}); |
||||
|
||||
/** |
||||
* selection('replace', opts) |
||||
* replace the selected text |
||||
* |
||||
* @param {String} opts.text replacement text |
||||
* @param {String} opts.caret caret mode: any of the following: "keep" | "start" | "end" |
||||
*/ |
||||
case 'replace': |
||||
return this.each(function() { |
||||
_CaretOperation.replace(this, opts.text, opts.caret); |
||||
}); |
||||
|
||||
/** |
||||
* selection('insert', opts) |
||||
* insert before/after the selected text |
||||
* |
||||
* @param {String} opts.text insertion text |
||||
* @param {String} opts.caret caret mode: any of the following: "keep" | "start" | "end" |
||||
* @param {String} opts.mode insertion mode: any of the following: "before" | "after" |
||||
*/ |
||||
case 'insert': |
||||
return this.each(function() { |
||||
if (opts.mode === 'before') { |
||||
_CaretOperation.insertBefore(this, opts.text, opts.caret); |
||||
} else { |
||||
_CaretOperation.insertAfter(this, opts.text, opts.caret); |
||||
} |
||||
}); |
||||
|
||||
/** |
||||
* selection('get') |
||||
* get selected text |
||||
* |
||||
* @return {String} return |
||||
*/ |
||||
case 'get': |
||||
/* falls through */ |
||||
default: |
||||
return _CaretOperation.getText(this[0]); |
||||
} |
||||
|
||||
return this; |
||||
} |
||||
}); |
||||
})(jQuery, window, window.document); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue