[enhancement] added heatmaps and item count in dashboard

This commit is contained in:
Rushabh Mehta 2016-04-14 17:29:57 +05:30
parent 8783bd16f6
commit 4bb2fce345
18 changed files with 3844 additions and 97 deletions

View file

@ -446,13 +446,16 @@ def clear_cache(user=None, doctype=None):
frappe.local.role_permissions = {}
def has_permission(doctype, ptype="read", doc=None, user=None, verbose=False, throw=False):
def has_permission(doctype=None, ptype="read", doc=None, user=None, verbose=False, throw=False):
"""Raises `frappe.PermissionError` if not permitted.
:param doctype: DocType for which permission is to be check.
:param ptype: Permission type (`read`, `write`, `create`, `submit`, `cancel`, `amend`). Default: `read`.
:param doc: [optional] Checks User permissions for given doc.
:param user: [optional] Check for given user. Default: current user."""
if not doctype and doc:
doctype = doc.doctype
import frappe.permissions
out = frappe.permissions.has_permission(doctype, ptype, doc=doc, verbose=verbose, user=user)
if throw and not out:

View file

@ -118,28 +118,7 @@ def get_communications(doctype, name, start=0, limit=20):
def _get_communications(doctype, name, start=0, limit=20):
communications = frappe.db.sql("""select name, communication_type,
communication_medium, comment_type,
content, sender, sender_full_name, creation, subject, delivery_status, _liked_by,
timeline_doctype, timeline_name,
reference_doctype, reference_name,
link_doctype, link_name,
"Communication" as doctype
from tabCommunication
where
communication_type in ("Communication", "Comment")
and (
(reference_doctype=%(doctype)s and reference_name=%(name)s)
or (timeline_doctype=%(doctype)s
and timeline_name=%(name)s
and communication_type="Comment"
and comment_type in ("Created", "Updated", "Submitted", "Cancelled", "Deleted"))
)
and (comment_type is null or comment_type != 'Update')
order by creation desc limit %(start)s, %(limit)s""",
{ "doctype": doctype, "name": name, "start": frappe.utils.cint(start), "limit": limit },
as_dict=True)
communications = get_communication_data(doctype, name, start, limit)
for c in communications:
if c.communication_type=="Communication":
c.attachments = json.dumps(frappe.get_all("File",
@ -153,6 +132,43 @@ def _get_communications(doctype, name, start=0, limit=20):
return communications
def get_communication_data(doctype, name, start=0, limit=20, after=None, fields=None,
group_by=None, as_dict=True):
'''Returns list of communicataions for a given document'''
if not fields:
fields = '''name, communication_type,
communication_medium, comment_type,
content, sender, sender_full_name, creation, subject, delivery_status, _liked_by,
timeline_doctype, timeline_name,
reference_doctype, reference_name,
link_doctype, link_name,
"Communication" as doctype'''
conditions = '''communication_type in ("Communication", "Comment")
and (
(reference_doctype=%(doctype)s and reference_name=%(name)s)
or (timeline_doctype=%(doctype)s
and timeline_name=%(name)s
and communication_type="Comment"
and comment_type in ("Created", "Updated", "Submitted", "Cancelled", "Deleted"))
)
and (comment_type is null or comment_type != 'Update')'''
if after:
# find after a particular date
conditions+= ' and creation > {after}'
limit = 1000
communications = frappe.db.sql("""select {fields}
from tabCommunication
where {conditions} {group_by}
order by creation desc limit %(start)s, %(limit)s""".format(
fields = fields, conditions=conditions, group_by=group_by or ""),
{ "doctype": doctype, "name": name, "start": frappe.utils.cint(start), "limit": limit },
as_dict=as_dict)
return communications
def get_assignments(dt, dn):
cl = frappe.db.sql("""select owner, description from `tabToDo`
where reference_type=%(doctype)s and reference_name=%(name)s and status="Open"

View file

@ -6,7 +6,6 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import time_diff_in_seconds, now, now_datetime, DATETIME_FORMAT
from dateutil.relativedelta import relativedelta
from frappe import _
@frappe.whitelist()
def get_notifications():
@ -178,9 +177,6 @@ def get_open_count(doctype, name):
:param transactions: List of transactions (json/dict)
:param filters: optional filters (json/list)'''
doc = frappe.get_doc(doctype, name)
if not doc.has_permission('read'):
frappe.msgprint(_("Not permitted"), raise_exception=True)
links = frappe.get_meta(doctype).get_links_setup()
@ -192,15 +188,20 @@ def get_open_count(doctype, name):
out = []
for doctype in items:
filters = get_filters_for(doctype)
fieldname = links.get('non_standard_fieldnames', {}).get(doctype, links.fieldname)
data = {'name': doctype}
if filters:
# get the fieldname for the current document
# we only need open documents related to the current document
fieldname = links.get('non_standard_fieldnames', {}).get(doctype, links.fieldname)
filters[fieldname] = name
total = len(frappe.get_all(doctype, fields='name',
filters=filters, limit_page_length=6, distinct=True))
data['open_count'] = total
if filters:
open_count = len(frappe.get_all(doctype, fields='name',
filters=filters, limit_page_length=6, distinct=True))
out.append({'name': doctype, 'count': open_count})
total = len(frappe.get_all(doctype, fields='name',
filters={fieldname: name}, limit_page_length=10, distinct=True))
data['count'] = total
out.append(data)
return out

View file

@ -42,7 +42,7 @@
"public/css/bootstrap.css",
"public/css/font-awesome.css",
"public/css/octicons/octicons.css",
"public/css/font/open-sans/open-sans.css",
"public/css/cal-heatmap.css",
"public/css/desk.css",
"public/css/indicator.css",
"public/css/avatar.css",
@ -63,6 +63,8 @@
"public/js/lib/moment/moment-with-locales.min.js",
"public/js/lib/moment/moment-timezone-with-data.min.js",
"public/js/lib/socket.io.min.js",
"public/js/lib/d3.min.js",
"public/js/lib/cal-heatmap.js",
"public/js/frappe/provide.js",
"public/js/frappe/class.js",
@ -150,6 +152,7 @@
"public/js/frappe/form/templates/users_in_sidebar.html",
"public/js/frappe/form/templates/set_sharing.html",
"public/js/frappe/form/templates/form_sidebar.html",
"public/js/frappe/form/templates/form_dashboard.html",
"public/js/frappe/form/templates/form_links.html",
"public/js/frappe/views/formview.js",
"public/js/legacy/form.js",

140
frappe/public/css/cal-heatmap.css Executable file
View file

@ -0,0 +1,140 @@
/* Cal-HeatMap CSS */
.cal-heatmap-container {
display: block;
}
.cal-heatmap-container .graph-label
{
fill: #999;
font-size: 10px
}
.cal-heatmap-container .graph, .cal-heatmap-container .graph-legend rect {
shape-rendering: crispedges
}
.cal-heatmap-container .graph-rect
{
fill: #ededed
}
.cal-heatmap-container .graph-subdomain-group rect:hover
{
stroke: #000;
stroke-width: 1px
}
.cal-heatmap-container .subdomain-text {
font-size: 8px;
fill: #999;
pointer-events: none
}
.cal-heatmap-container .hover_cursor:hover {
cursor: pointer
}
.cal-heatmap-container .qi {
background-color: #999;
fill: #999
}
/*
Remove comment to apply this style to date with value equal to 0
.q0
{
background-color: #fff;
fill: #fff;
stroke: #ededed
}
*/
.cal-heatmap-container .q1
{
background-color: #dae289;
fill: #dae289
}
.cal-heatmap-container .q2
{
background-color: #cedb9c;
fill: #9cc069
}
.cal-heatmap-container .q3
{
background-color: #b5cf6b;
fill: #669d45
}
.cal-heatmap-container .q4
{
background-color: #637939;
fill: #637939
}
.cal-heatmap-container .q5
{
background-color: #3b6427;
fill: #3b6427
}
.cal-heatmap-container rect.highlight
{
stroke:#444;
stroke-width:1
}
.cal-heatmap-container text.highlight
{
fill: #444
}
.cal-heatmap-container rect.now
{
stroke: red
}
.cal-heatmap-container text.now
{
fill: red;
font-weight: 800
}
.cal-heatmap-container .domain-background {
fill: none;
shape-rendering: crispedges
}
.ch-tooltip {
padding: 10px;
background: #222;
color: #bbb;
font-size: 12px;
line-height: 1.4;
width: 140px;
position: absolute;
z-index: 99999;
text-align: center;
border-radius: 2px;
box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
display: none;
box-sizing: border-box;
}
.ch-tooltip::after{
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
content: "";
padding: 0;
display: block;
bottom: -6px;
left: 50%;
margin-left: -6px;
border-width: 6px 6px 0;
border-top-color: #222;
}

View file

@ -28,9 +28,30 @@
border-top: 1px solid #d1d8dd;
}
.form-dashboard {
display: none;
border-bottom: 1px solid #EBEFF2;
}
.form-dashboard-section {
padding: 15px 30px;
margin: 0px;
border-bottom: 1px solid #EBEFF2;
}
.form-dashboard-section:last-child {
border-bottom: none;
}
.form-heatmap {
padding-top: 30px;
}
.form-links .document-link {
margin-bottom: 10px;
height: 22px;
position: relative;
}
.form-links .count {
position: absolute;
left: -20px;
top: 3px;
display: inline-block;
}
.form-section {
margin: 0px;
padding: 15px;

View file

@ -412,7 +412,6 @@ frappe.get_desktop_icons = function(show_hidden, show_global) {
if(m.blocked && !show_global) {
out = false;
}
console.log(module, out);
return out;
}

View file

@ -117,6 +117,12 @@ frappe.ui.form.Control = Class.extend({
this.set_input(value);
}
},
set_focus: function() {
if(this.$input) {
this.$input.get(0).focus();
return true;
}
}
});
frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({
@ -1464,6 +1470,13 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
this.editor.set_input(value);
this.md_editor.val(value);
this.last_value = value;
},
set_focus: function() {
var editor = this.$wrapper.find('.text-editor');
if(editor) {
editor.focus();
return true;
}
}
});

View file

@ -4,27 +4,30 @@
frappe.ui.form.Dashboard = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.wrapper = $('<div class="form-dashboard shaded-section"></div>')
.prependTo(this.frm.layout.wrapper);
this.body = $('<div class="row"></div>').appendTo(this.wrapper)
.css("padding", "15px 30px");
this.wrapper = $(frappe.render_template('form_dashboard',
{frm: this.frm})).prependTo(this.frm.layout.wrapper);
this.headline = this.wrapper.find('.form-headline');
this.heatmap_area = this.wrapper.find('.form-heatmap');
this.stats_area = this.wrapper.find('.form-stats');
this.links_area = this.wrapper.find('.form-links');
this.transactions_area = this.links_area.find('.transactions');
},
reset: function() {
this.wrapper.toggle(false);
this.body.empty();
this.badge_area = $('<div class="hidden" \
style="padding-left: 15px; padding-right: 15px;">\
<p class="text-muted small" style="margin-bottom: 0px;">'
+ __("Documents related to {0}", [this.frm.doc.name]) +'</p></div>').appendTo(this.body);
this.wrapper.addClass('hidden');
this.clear_headline();
// clear links
this.links_area.addClass('hidden');
this.transactions_area.empty();
// clear stats
this.stats_area.empty().addClass('hidden');
},
set_headline: function(html) {
if(!this.headline)
this.headline =
$('<h4 class="form-headline col-md-12 hidden"></h4>').prependTo(this.body);
this.headline.html(html).removeClass('hidden');
this.wrapper.toggle(true);
this.show();
},
clear_headline: function() {
if(this.headline) {
@ -67,7 +70,7 @@ frappe.ui.form.Dashboard = Class.extend({
title="%(title)s"></div>', opts)).appendTo(progress);
});
this.wrapper.toggle(true);
this.show();
},
make_progress_chart: function(title) {
var progress_area = this.body.find(".progress-area");
@ -85,6 +88,8 @@ frappe.ui.form.Dashboard = Class.extend({
return progress_chart;
},
//
show_links: function() {
this.reset();
if(this.frm.doc.__islocal)
@ -96,7 +101,7 @@ frappe.ui.form.Dashboard = Class.extend({
}
this.render_links();
this.set_open_count();
this.show_heatmap();
},
filter_permissions: function() {
// filter out transactions for which the user
@ -123,24 +128,24 @@ frappe.ui.form.Dashboard = Class.extend({
var me = this;
$(frappe.render_template('form_links',
{transactions: this.links.transactions}))
.appendTo(this.badge_area)
.appendTo(this.transactions_area)
// bind links
this.badge_area.find(".badge-link").on('click', function() {
me.open_document_list($(this).attr('data-doctype'));
this.transactions_area.find(".badge-link").on('click', function() {
me.open_document_list($(this).parent().attr('data-doctype'));
});
// bind open notifications
this.badge_area.find('.open-notification').on('click', function() {
me.open_document_list($(this).attr('data-doctype'), true);
this.transactions_area.find('.open-notification').on('click', function() {
me.open_document_list($(this).parent().attr('data-doctype'), true);
});
this.wrapper.toggle(true);
this.badge_area.removeClass('hidden');
this.show();
this.links_area.removeClass('hidden');
},
open_document_list: function(doctype, show_open) {
// show document list with filters
frappe.route_options = this.get_document_filter();
frappe.route_options = this.get_document_filter(doctype);
if(show_open) {
$.extend(frappe.route_options, frappe.ui.notifications.get_filters(doctype));
}
@ -168,25 +173,70 @@ frappe.ui.form.Dashboard = Class.extend({
frappe.call({
type: "GET",
method: "frappe.desk.notifications.get_open_count",
method: frappe.model.get_server_module_name(this.frm.doctype) + ".get_dashboard_data",
args: {
doctype: this.frm.doc.doctype,
name: this.frm.doc.name,
},
callback: function(r) {
$.each(r.message, function(i, d) {
if(d.count) {
me.frm.dashboard.set_badge_count(d.name, (d.count > 5) ? '5+' : d.count)
}
})
me.heatmap.update(r.message.timeline_data);
$.each(r.message.count, function(i, d) {
me.frm.dashboard.set_badge_count(d.name, cint(d.open_count), cint(d.count));
});
me.frm.dashboard_data = r.message;
me.frm.trigger('dashboard_update');
}
});
},
set_badge_count: function(doctype, count) {
$(this.wrapper)
.find('.open-notification[data-doctype="'+doctype+'"]')
.removeClass('hidden')
.html(count);
set_badge_count: function(doctype, open_count, count) {
var $link = $(this.transactions_area)
.find('.document-link[data-doctype="'+doctype+'"]');
if(open_count) {
$link.find('.open-notification')
.removeClass('hidden')
.html((open_count > 5) ? '5+' : open_count);
}
if(count) {
$link.find('.count')
.html((count > 9) ? '9+' : count);
}
},
// heatmap
show_heatmap: function() {
if(!this.heatmap) {
this.heatmap = new CalHeatMap();
this.heatmap.init({
itemSelector: "#heatmap-" + this.frm.doctype,
domain: "month",
subDomain: "day",
start: moment().subtract(1, 'year').add(1, 'month').toDate(),
cellSize: 9,
cellPadding: 2,
domainGutter: 2,
range: 12,
domainLabelFormat: function(date) {
return moment(date).format("MMM").toUpperCase();
},
displayLegend: false,
legend: [5, 10, 15, 20]
// subDomainTextFormat: "%d",
});
// center the heatmap
this.heatmap_area.removeClass('hidden').find('svg').css({'margin': 'auto'});
}
},
// stats
add_stats: function(html) {
this.stats_area.html(html).removeClass('hidden');
this.show();
},
show: function() {
this.wrapper.removeClass('hidden');
}
});

View file

@ -0,0 +1,10 @@
<div class="form-dashboard shaded-section hidden">
<h4 class="form-headline hidden form-dashboard-section">
</h4>
<div class="form-heatmap hidden form-dashboard-section"
id="heatmap-{{ frm.doctype }}"></div>
<div class="form-stats form-dashboard-section hidden"></div>
<div class="form-links form-dashboard-section hidden">
<div class="transactions"></div>
</div>
</div>

View file

@ -1,14 +1,15 @@
<div class="form-documents">
{% for (var i=0; i < transactions.length; i++) { %}
{% if((i % 2)===0) { %}<div class="row">{% } %}
<div class="col-xs-6">
<div class="col-xs-6" style="padding-left: 30px;">
<h5 style="margin-top: 15px;">{{ transactions[i].label }}</h5>
{% for (var j=0; j < transactions[i].items.length; j++) {
var doctype = transactions[i].items[j]; %}
<div style="margin-bottom: 10px; height: 22px;">
<a data-doctype="{{ doctype }}" class="badge-link small">
{{ __(doctype) }}</a>
<span class="open-notification hidden" data-doctype="{{ doctype }}"></span>
<div class="document-link"
data-doctype="{{ doctype }}">
<span class="text-muted small count"></span>
<a class="badge-link small">{{ __(doctype) }}</a>
<span class="open-notification hidden"></span>
</div>
{% } %}
</div>

View file

@ -65,14 +65,11 @@ frappe.ui.Dialog = frappe.ui.FieldGroup.extend({
},
focus_on_first_input: function() {
var first = $(this.body).find(':input:first');
if(first.length && first.attr("data-fieldtype")!="Date") {
try {
first.get(0).focus();
} catch(e) {
console.log("Dialog: unable to focus on first input: " + e);
this.fields_list.every(function(f) {
if(!in_list(['Date', 'Datetime', 'Time'], f.df.fieldtype) && f.set_focus()) {
return false;
}
}
});
},
get_primary_btn: function() {
return this.$wrapper.find(".modal-header .btn-primary");

View file

@ -937,5 +937,7 @@ _f.Frm.prototype.scroll_to_element = function() {
if (selector.length) {
frappe.ui.scroll(selector, true, 30);
}
} else {
window.scroll(0, 0);
}
}

File diff suppressed because it is too large Load diff

5
frappe/public/js/lib/d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,11 +0,0 @@
/**
* Prism: Lightweight, robust, elegant syntax highlighting
* MIT license http://www.opensource.org/licenses/mit-license.php/
* @author Lea Verou http://lea.verou.me
*/(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data),o);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar,l.language);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r,i){return n.stringify(t.tokenize(e,r),i)},tokenize:function(e,n,r){var i=t.Token,s=[e],o=n.rest;if(o){for(var u in o)n[u]=o[u];delete n.rest}e:for(var u in n){if(!n.hasOwnProperty(u)||!n[u])continue;var a=n[u],f=a.inside,l=!!a.lookbehind||0;a=a.pattern||a;for(var c=0;c<s.length;c++){var h=s[c];if(s.length>e.length)break e;if(h instanceof i)continue;a.lastIndex=0;var p=a.exec(h);if(p){l&&(l=p[1].length);var d=p.index-1+l,p=p[0].slice(l),v=p.length,m=d+v,g=h.slice(0,d+1),y=h.slice(m+1),b=[c,1];g&&b.push(g);var w=new i(u,f?t.tokenize(p,f):p);b.push(w);y&&b.push(y);Array.prototype.splice.apply(s,b)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+"</"+s.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();;
Prism.languages.markup={comment:/&lt;!--[\w\W]*?--(&gt;|&gt;)/g,prolog:/&lt;\?.+?\?&gt;/,doctype:/&lt;!DOCTYPE.+?&gt;/,cdata:/&lt;!\[CDATA\[[\w\W]+?]]&gt;/i,tag:{pattern:/&lt;\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?&gt;/gi,inside:{tag:{pattern:/^&lt;\/?[\w:-]+/i,inside:{punctuation:/^&lt;\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|&gt;|"/g}},punctuation:/\/?&gt;/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&amp;#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&amp;/,"&"))});;
Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:/@[\w-]+?(\s+[^;{]+)?(?=\s*{|\s*;)/gi,url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,property:/(\b|\B)[a-z-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[\{\};:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/(&lt;|<)style[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/style(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)style[\w\W]*?(>|&gt;)|(&lt;|<)\/style(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});;
Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:class|interface|extends|implements|trait|instanceof|new)\s+)[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|=?&lt;|=?&gt;|={1,2}|(&amp;){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/script(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)|(&lt;|<)\/script(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});;
Prism.languages.python={comment:{pattern:/(^|[^\\])#.*?(\r?\n|$)/g,lookbehind:!0},string: /("|')(\\?.)*?\1/g,keyword:/\b(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/g,boolean:/\b(True|False)\b/g,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/[-+]{1,2}|=?&lt;|=?&gt;|!|={1,2}|(&){1,2}|(&amp;){1,2}|\|?\||\?|\*|\/|~|\^|%|\b(or|and|not)\b/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)).*?(\r?\n|$))/g,lookbehind:!0},string: /("|')(\\?.)*?\1/g,keyword:/\b(ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMPORARY|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/gi,boolean:/\b(TRUE|FALSE|NULL)\b/gi,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/\b(ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]{1}|!|=?&lt;|=?&gt;|={1}|(&amp;){1,2}|\|?\||\?|\*|\//gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[;[\]()`,.]/g};;

File diff suppressed because one or more lines are too long

View file

@ -37,10 +37,38 @@
}
.form-dashboard {
display: none;
border-bottom: 1px solid @light-border-color;
}
.form-dashboard-section {
padding: 15px 30px;
margin: 0px;
border-bottom: 1px solid @light-border-color;
}
.form-dashboard-section:last-child {
border-bottom: none;
}
.form-heatmap {
padding-top: 30px;
}
.form-links {
.document-link {
margin-bottom: 10px;
height: 22px;
position: relative;
}
.count {
position: absolute;
left: -20px;
top: 3px;
display: inline-block;
}
}
.form-section {
margin: 0px;
padding: 15px;