Dodanie właściwej konfiguracji dockera
This commit is contained in:
1 parent
6a225cb60c
commit
d3fb703ed6
4364 files changed
+828806
-10
No files matched your search
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Bootstrap v5.3.8 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,(t,e)=>`#${CSS.escape(e)}`)),t),s=t=>null==t?`${t}`:Object.prototype.toString.call(t).match(/\s([a-z]+)/i)[1].toLowerCase(),o=t=>{t.dispatchEvent(new Event(i))},r=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),a=t=>r(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,l=t=>{if(!r(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",()=>{for(const t of p)t()}),p.push(e)):e()},_=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,b=(t,e,n=!0)=>{if(!n)return void _(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),_(t))};e.addEventListener(i,a),setTimeout(()=>{r||o(e)},s)},v=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,A=/::\d+$/,E={};let T=1;const C={mouseenter:"mouseover",mouseleave:"mouseout"},O=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function x(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function k(t){const e=x(t);return t.uidEvent=e,E[e]=E[e]||{},E[e]}function L(t,e,i=null){return Object.values(t).find(t=>t.callable===e&&t.delegationSelector===i)}function S(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=N(t);return O.has(o)||(o=t),[n,s,o]}function D(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=S(e,i,n);if(e in C){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=k(t),c=l[a]||(l[a]={}),h=L(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=x(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return j(s,{delegateTarget:r}),n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return j(n,{delegateTarget:t}),i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function $(t,e,i,n,s){const o=L(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function I(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&$(t,e,i,r.callable,r.delegationSelector)}function N(t){return t=t.replace(w,""),C[t]||t}const P={on(t,e,i,n){D(t,e,i,n,!1)},one(t,e,i,n){D(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=k(t),c=l[rLine truncated
|
||||
//# sourceMappingURL=bootstrap.bundle.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","Object","prototype","toString","call","toLowerCase","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ARROW_LEFT_KEY$1","ARROW_RIGHT_KEY$1","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex",Line truncated
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2017 by Marijn Haverbeke <[email protected]> and others
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,37 @@
|
||||
.CodeMirror-hints {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
|
||||
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
border-radius: 3px;
|
||||
border: 1px solid silver;
|
||||
|
||||
background: white;
|
||||
font-size: 90%;
|
||||
font-family: monospace;
|
||||
|
||||
max-height: 20em;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.CodeMirror-hint {
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
white-space: pre;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
li.CodeMirror-hint-active {
|
||||
background: #08f;
|
||||
color: white;
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
// declare global: DOMRect
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var HINT_ELEMENT_CLASS = "CodeMirror-hint";
|
||||
var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
|
||||
|
||||
// This is the old interface, kept around for now to stay
|
||||
// backwards-compatible.
|
||||
CodeMirror.showHint = function(cm, getHints, options) {
|
||||
if (!getHints) return cm.showHint(options);
|
||||
if (options && options.async) getHints.async = true;
|
||||
var newOpts = {hint: getHints};
|
||||
if (options) for (var prop in options) newOpts[prop] = options[prop];
|
||||
return cm.showHint(newOpts);
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("showHint", function(options) {
|
||||
options = parseOptions(this, this.getCursor("start"), options);
|
||||
var selections = this.listSelections()
|
||||
if (selections.length > 1) return;
|
||||
// By default, don't allow completion when something is selected.
|
||||
// A hint function can have a `supportsSelection` property to
|
||||
// indicate that it can handle selections.
|
||||
if (this.somethingSelected()) {
|
||||
if (!options.hint.supportsSelection) return;
|
||||
// Don't try with cross-line selections
|
||||
for (var i = 0; i < selections.length; i++)
|
||||
if (selections[i].head.line != selections[i].anchor.line) return;
|
||||
}
|
||||
|
||||
if (this.state.completionActive) this.state.completionActive.close();
|
||||
var completion = this.state.completionActive = new Completion(this, options);
|
||||
if (!completion.options.hint) return;
|
||||
|
||||
CodeMirror.signal(this, "startCompletion", this);
|
||||
completion.update(true);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("closeHint", function() {
|
||||
if (this.state.completionActive) this.state.completionActive.close()
|
||||
})
|
||||
|
||||
function Completion(cm, options) {
|
||||
this.cm = cm;
|
||||
this.options = options;
|
||||
this.widget = null;
|
||||
this.debounce = 0;
|
||||
this.tick = 0;
|
||||
this.startPos = this.cm.getCursor("start");
|
||||
this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
|
||||
|
||||
if (this.options.updateOnCursorActivity) {
|
||||
var self = this;
|
||||
cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
|
||||
}
|
||||
}
|
||||
|
||||
var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
|
||||
return setTimeout(fn, 1000/60);
|
||||
};
|
||||
var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
|
||||
|
||||
Completion.prototype = {
|
||||
close: function() {
|
||||
if (!this.active()) return;
|
||||
this.cm.state.completionActive = null;
|
||||
this.tick = null;
|
||||
if (this.options.updateOnCursorActivity) {
|
||||
this.cm.off("cursorActivity", this.activityFunc);
|
||||
}
|
||||
|
||||
if (this.widget && this.data) CodeMirror.signal(this.data, "close");
|
||||
if (this.widget) this.widget.close();
|
||||
CodeMirror.signal(this.cm, "endCompletion", this.cm);
|
||||
},
|
||||
|
||||
active: function() {
|
||||
return this.cm.state.completionActive == this;
|
||||
},
|
||||
|
||||
pick: function(data, i) {
|
||||
var completion = data.list[i], self = this;
|
||||
this.cm.operation(function() {
|
||||
if (completion.hint)
|
||||
completion.hint(self.cm, data, completion);
|
||||
else
|
||||
self.cm.replaceRange(getText(completion), completion.from || data.from,
|
||||
completion.to || data.to, "complete");
|
||||
CodeMirror.signal(data, "pick", completion);
|
||||
self.cm.scrollIntoView();
|
||||
});
|
||||
if (this.options.closeOnPick) {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
|
||||
cursorActivity: function() {
|
||||
if (this.debounce) {
|
||||
cancelAnimationFrame(this.debounce);
|
||||
this.debounce = 0;
|
||||
}
|
||||
|
||||
var identStart = this.startPos;
|
||||
if(this.data) {
|
||||
identStart = this.data.from;
|
||||
}
|
||||
|
||||
var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
|
||||
if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
|
||||
pos.ch < identStart.ch || this.cm.somethingSelected() ||
|
||||
(!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
|
||||
this.close();
|
||||
} else {
|
||||
var self = this;
|
||||
this.debounce = requestAnimationFrame(function() {self.update();});
|
||||
if (this.widget) this.widget.disable();
|
||||
}
|
||||
},
|
||||
|
||||
update: function(first) {
|
||||
if (this.tick == null) return
|
||||
var self = this, myTick = ++this.tick
|
||||
fetchHints(this.options.hint, this.cm, this.options, function(data) {
|
||||
if (self.tick == myTick) self.finishUpdate(data, first)
|
||||
})
|
||||
},
|
||||
|
||||
finishUpdate: function(data, first) {
|
||||
if (this.data) CodeMirror.signal(this.data, "update");
|
||||
|
||||
var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
|
||||
if (this.widget) this.widget.close();
|
||||
|
||||
this.data = data;
|
||||
|
||||
if (data && data.list.length) {
|
||||
if (picked && data.list.length == 1) {
|
||||
this.pick(data, 0);
|
||||
} else {
|
||||
this.widget = new Widget(this, data);
|
||||
CodeMirror.signal(data, "shown");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function parseOptions(cm, pos, options) {
|
||||
var editor = cm.options.hintOptions;
|
||||
var out = {};
|
||||
for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
|
||||
if (editor) for (var prop in editor)
|
||||
if (editor[prop] !== undefined) out[prop] = editor[prop];
|
||||
if (options) for (var prop in options)
|
||||
if (options[prop] !== undefined) out[prop] = options[prop];
|
||||
if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
|
||||
return out;
|
||||
}
|
||||
|
||||
function getText(completion) {
|
||||
if (typeof completion == "string") return completion;
|
||||
else return completion.text;
|
||||
}
|
||||
|
||||
function buildKeyMap(completion, handle) {
|
||||
var baseMap = {
|
||||
Up: function() {handle.moveFocus(-1);},
|
||||
Down: function() {handle.moveFocus(1);},
|
||||
PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
|
||||
PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
|
||||
Home: function() {handle.setFocus(0);},
|
||||
End: function() {handle.setFocus(handle.length - 1);},
|
||||
Enter: handle.pick,
|
||||
Tab: handle.pick,
|
||||
Esc: handle.close
|
||||
};
|
||||
|
||||
var mac = /Mac/.test(navigator.platform);
|
||||
|
||||
if (mac) {
|
||||
baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);};
|
||||
baseMap["Ctrl-N"] = function() {handle.moveFocus(1);};
|
||||
}
|
||||
|
||||
var custom = completion.options.customKeys;
|
||||
var ourMap = custom ? {} : baseMap;
|
||||
function addBinding(key, val) {
|
||||
var bound;
|
||||
if (typeof val != "string")
|
||||
bound = function(cm) { return val(cm, handle); };
|
||||
// This mechanism is deprecated
|
||||
else if (baseMap.hasOwnProperty(val))
|
||||
bound = baseMap[val];
|
||||
else
|
||||
bound = val;
|
||||
ourMap[key] = bound;
|
||||
}
|
||||
if (custom)
|
||||
for (var key in custom) if (custom.hasOwnProperty(key))
|
||||
addBinding(key, custom[key]);
|
||||
var extra = completion.options.extraKeys;
|
||||
if (extra)
|
||||
for (var key in extra) if (extra.hasOwnProperty(key))
|
||||
addBinding(key, extra[key]);
|
||||
return ourMap;
|
||||
}
|
||||
|
||||
function getHintElement(hintsElement, el) {
|
||||
while (el && el != hintsElement) {
|
||||
if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
|
||||
el = el.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
function Widget(completion, data) {
|
||||
this.id = "cm-complete-" + Math.floor(Math.random(1e6))
|
||||
this.completion = completion;
|
||||
this.data = data;
|
||||
this.picked = false;
|
||||
var widget = this, cm = completion.cm;
|
||||
var ownerDocument = cm.getInputField().ownerDocument;
|
||||
var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
|
||||
|
||||
var hints = this.hints = ownerDocument.createElement("ul");
|
||||
hints.setAttribute("role", "listbox")
|
||||
hints.setAttribute("aria-expanded", "true")
|
||||
hints.id = this.id
|
||||
var theme = completion.cm.options.theme;
|
||||
hints.className = "CodeMirror-hints " + theme;
|
||||
this.selectedHint = data.selectedHint || 0;
|
||||
|
||||
var completions = data.list;
|
||||
for (var i = 0; i < completions.length; ++i) {
|
||||
var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
|
||||
var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
|
||||
if (cur.className != null) className = cur.className + " " + className;
|
||||
elt.className = className;
|
||||
if (i == this.selectedHint) elt.setAttribute("aria-selected", "true")
|
||||
elt.id = this.id + "-" + i
|
||||
elt.setAttribute("role", "option")
|
||||
if (cur.render) cur.render(elt, data, cur);
|
||||
else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur)));
|
||||
elt.hintId = i;
|
||||
}
|
||||
|
||||
var container = completion.options.container || ownerDocument.body;
|
||||
var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
|
||||
var left = pos.left, top = pos.bottom, below = true;
|
||||
var offsetLeft = 0, offsetTop = 0;
|
||||
if (container !== ownerDocument.body) {
|
||||
// We offset the cursor position because left and top are relative to the offsetParent's top left corner.
|
||||
var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1;
|
||||
var offsetParent = isContainerPositioned ? container : container.offsetParent;
|
||||
var offsetParentPosition = offsetParent.getBoundingClientRect();
|
||||
var bodyPosition = ownerDocument.body.getBoundingClientRect();
|
||||
offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft);
|
||||
offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop);
|
||||
}
|
||||
hints.style.left = (left - offsetLeft) + "px";
|
||||
hints.style.top = (top - offsetTop) + "px";
|
||||
|
||||
// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
|
||||
var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
|
||||
var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
|
||||
container.appendChild(hints);
|
||||
cm.getInputField().setAttribute("aria-autocomplete", "list")
|
||||
cm.getInputField().setAttribute("aria-owns", this.id)
|
||||
cm.getInputField().setAttribute("aria-activedescendant", this.id + "-" + this.selectedHint)
|
||||
|
||||
var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect();
|
||||
var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false;
|
||||
|
||||
// Compute in the timeout to avoid reflow on init
|
||||
var startScroll;
|
||||
setTimeout(function() { startScroll = cm.getScrollInfo(); });
|
||||
|
||||
var overlapY = box.bottom - winH;
|
||||
if (overlapY > 0) { // Does not fit below
|
||||
var height = box.bottom - box.top, spaceAbove = box.top - (pos.bottom - pos.top) - 2
|
||||
if (winH - box.top < spaceAbove) { // More room at the top
|
||||
if (height > spaceAbove) hints.style.height = (height = spaceAbove) + "px";
|
||||
hints.style.top = ((top = pos.top - height) + offsetTop) + "px";
|
||||
below = false;
|
||||
} else {
|
||||
hints.style.height = (winH - box.top - 2) + "px";
|
||||
}
|
||||
}
|
||||
var overlapX = box.right - winW;
|
||||
if (scrolls) overlapX += cm.display.nativeBarWidth;
|
||||
if (overlapX > 0) {
|
||||
if (box.right - box.left > winW) {
|
||||
hints.style.width = (winW - 5) + "px";
|
||||
overlapX -= (box.right - box.left) - winW;
|
||||
}
|
||||
hints.style.left = (left = Math.max(pos.left - overlapX - offsetLeft, 0)) + "px";
|
||||
}
|
||||
if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
|
||||
node.style.paddingRight = cm.display.nativeBarWidth + "px"
|
||||
|
||||
cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
|
||||
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
|
||||
setFocus: function(n) { widget.changeActive(n); },
|
||||
menuSize: function() { return widget.screenAmount(); },
|
||||
length: completions.length,
|
||||
close: function() { completion.close(); },
|
||||
pick: function() { widget.pick(); },
|
||||
data: data
|
||||
}));
|
||||
|
||||
if (completion.options.closeOnUnfocus) {
|
||||
var closingOnBlur;
|
||||
cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
|
||||
cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
|
||||
}
|
||||
|
||||
cm.on("scroll", this.onScroll = function() {
|
||||
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
|
||||
if (!startScroll) startScroll = cm.getScrollInfo();
|
||||
var newTop = top + startScroll.top - curScroll.top;
|
||||
var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop);
|
||||
if (!below) point += hints.offsetHeight;
|
||||
if (point <= editor.top || point >= editor.bottom) return completion.close();
|
||||
hints.style.top = newTop + "px";
|
||||
hints.style.left = (left + startScroll.left - curScroll.left) + "px";
|
||||
});
|
||||
|
||||
CodeMirror.on(hints, "dblclick", function(e) {
|
||||
var t = getHintElement(hints, e.target || e.srcElement);
|
||||
if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
|
||||
});
|
||||
|
||||
CodeMirror.on(hints, "click", function(e) {
|
||||
var t = getHintElement(hints, e.target || e.srcElement);
|
||||
if (t && t.hintId != null) {
|
||||
widget.changeActive(t.hintId);
|
||||
if (completion.options.completeOnSingleClick) widget.pick();
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.on(hints, "mousedown", function() {
|
||||
setTimeout(function(){cm.focus();}, 20);
|
||||
});
|
||||
|
||||
// The first hint doesn't need to be scrolled to on init
|
||||
var selectedHintRange = this.getSelectedHintRange();
|
||||
if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) {
|
||||
this.scrollToActive();
|
||||
}
|
||||
|
||||
CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Widget.prototype = {
|
||||
close: function() {
|
||||
if (this.completion.widget != this) return;
|
||||
this.completion.widget = null;
|
||||
if (this.hints.parentNode) this.hints.parentNode.removeChild(this.hints);
|
||||
this.completion.cm.removeKeyMap(this.keyMap);
|
||||
var input = this.completion.cm.getInputField()
|
||||
input.removeAttribute("aria-activedescendant")
|
||||
input.removeAttribute("aria-owns")
|
||||
|
||||
var cm = this.completion.cm;
|
||||
if (this.completion.options.closeOnUnfocus) {
|
||||
cm.off("blur", this.onBlur);
|
||||
cm.off("focus", this.onFocus);
|
||||
}
|
||||
cm.off("scroll", this.onScroll);
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
this.completion.cm.removeKeyMap(this.keyMap);
|
||||
var widget = this;
|
||||
this.keyMap = {Enter: function() { widget.picked = true; }};
|
||||
this.completion.cm.addKeyMap(this.keyMap);
|
||||
},
|
||||
|
||||
pick: function() {
|
||||
this.completion.pick(this.data, this.selectedHint);
|
||||
},
|
||||
|
||||
changeActive: function(i, avoidWrap) {
|
||||
if (i >= this.data.list.length)
|
||||
i = avoidWrap ? this.data.list.length - 1 : 0;
|
||||
else if (i < 0)
|
||||
i = avoidWrap ? 0 : this.data.list.length - 1;
|
||||
if (this.selectedHint == i) return;
|
||||
var node = this.hints.childNodes[this.selectedHint];
|
||||
if (node) {
|
||||
node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
|
||||
node.removeAttribute("aria-selected")
|
||||
}
|
||||
node = this.hints.childNodes[this.selectedHint = i];
|
||||
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
|
||||
node.setAttribute("aria-selected", "true")
|
||||
this.completion.cm.getInputField().setAttribute("aria-activedescendant", node.id)
|
||||
this.scrollToActive()
|
||||
CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
|
||||
},
|
||||
|
||||
scrollToActive: function() {
|
||||
var selectedHintRange = this.getSelectedHintRange();
|
||||
var node1 = this.hints.childNodes[selectedHintRange.from];
|
||||
var node2 = this.hints.childNodes[selectedHintRange.to];
|
||||
var firstNode = this.hints.firstChild;
|
||||
if (node1.offsetTop < this.hints.scrollTop)
|
||||
this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop;
|
||||
else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
|
||||
this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop;
|
||||
},
|
||||
|
||||
screenAmount: function() {
|
||||
return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
|
||||
},
|
||||
|
||||
getSelectedHintRange: function() {
|
||||
var margin = this.completion.options.scrollMargin || 0;
|
||||
return {
|
||||
from: Math.max(0, this.selectedHint - margin),
|
||||
to: Math.min(this.data.list.length - 1, this.selectedHint + margin),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function applicableHelpers(cm, helpers) {
|
||||
if (!cm.somethingSelected()) return helpers
|
||||
var result = []
|
||||
for (var i = 0; i < helpers.length; i++)
|
||||
if (helpers[i].supportsSelection) result.push(helpers[i])
|
||||
return result
|
||||
}
|
||||
|
||||
function fetchHints(hint, cm, options, callback) {
|
||||
if (hint.async) {
|
||||
hint(cm, callback, options)
|
||||
} else {
|
||||
var result = hint(cm, options)
|
||||
if (result && result.then) result.then(callback)
|
||||
else callback(result)
|
||||
}
|
||||
}
|
||||
|
||||
function resolveAutoHints(cm, pos) {
|
||||
var helpers = cm.getHelpers(pos, "hint"), words
|
||||
if (helpers.length) {
|
||||
var resolved = function(cm, callback, options) {
|
||||
var app = applicableHelpers(cm, helpers);
|
||||
function run(i) {
|
||||
if (i == app.length) return callback(null)
|
||||
fetchHints(app[i], cm, options, function(result) {
|
||||
if (result && result.list.length > 0) callback(result)
|
||||
else run(i + 1)
|
||||
})
|
||||
}
|
||||
run(0)
|
||||
}
|
||||
resolved.async = true
|
||||
resolved.supportsSelection = true
|
||||
return resolved
|
||||
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
|
||||
return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
|
||||
} else if (CodeMirror.hint.anyword) {
|
||||
return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
|
||||
} else {
|
||||
return function() {}
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("hint", "auto", {
|
||||
resolve: resolveAutoHints
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
|
||||
var cur = cm.getCursor(), token = cm.getTokenAt(cur)
|
||||
var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
|
||||
if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
|
||||
term = token.string.substr(0, cur.ch - token.start)
|
||||
} else {
|
||||
term = ""
|
||||
from = cur
|
||||
}
|
||||
var found = [];
|
||||
for (var i = 0; i < options.words.length; i++) {
|
||||
var word = options.words[i];
|
||||
if (word.slice(0, term.length) == term)
|
||||
found.push(word);
|
||||
}
|
||||
|
||||
if (found.length) return {list: found, from: from, to: to};
|
||||
});
|
||||
|
||||
CodeMirror.commands.autocomplete = CodeMirror.showHint;
|
||||
|
||||
var defaultOptions = {
|
||||
hint: CodeMirror.hint.auto,
|
||||
completeSingle: true,
|
||||
alignWithWord: true,
|
||||
closeCharacters: /[\s()\[\]{};:>,]/,
|
||||
closeOnPick: true,
|
||||
closeOnUnfocus: true,
|
||||
updateOnCursorActivity: true,
|
||||
completeOnSingleClick: true,
|
||||
container: null,
|
||||
customKeys: null,
|
||||
extraKeys: null,
|
||||
paddingForScrollbar: true,
|
||||
moveOnOverlap: true,
|
||||
};
|
||||
|
||||
CodeMirror.defineOption("hintOptions", null);
|
||||
});
|
||||
@@ -0,0 +1,304 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var tables;
|
||||
var defaultTable;
|
||||
var keywords;
|
||||
var identifierQuote;
|
||||
var CONS = {
|
||||
QUERY_DIV: ";",
|
||||
ALIAS_KEYWORD: "AS"
|
||||
};
|
||||
var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
|
||||
|
||||
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
|
||||
|
||||
function getModeConf(editor) {
|
||||
return editor.getModeAt(editor.getCursor()).config || CodeMirror.resolveMode("text/x-sql")
|
||||
}
|
||||
|
||||
function getKeywords(editor) {
|
||||
return getModeConf(editor).keywords || []
|
||||
}
|
||||
|
||||
function getIdentifierQuote(editor) {
|
||||
return getModeConf(editor).identifierQuote || "`";
|
||||
}
|
||||
|
||||
function getText(item) {
|
||||
return typeof item == "string" ? item : item.text;
|
||||
}
|
||||
|
||||
function wrapTable(name, value) {
|
||||
if (isArray(value)) value = {columns: value}
|
||||
if (!value.text) value.text = name
|
||||
return value
|
||||
}
|
||||
|
||||
function parseTables(input) {
|
||||
var result = {}
|
||||
if (isArray(input)) {
|
||||
for (var i = input.length - 1; i >= 0; i--) {
|
||||
var item = input[i]
|
||||
result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
|
||||
}
|
||||
} else if (input) {
|
||||
for (var name in input)
|
||||
result[name.toUpperCase()] = wrapTable(name, input[name])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function getTable(name) {
|
||||
return tables[name.toUpperCase()]
|
||||
}
|
||||
|
||||
function shallowClone(object) {
|
||||
var result = {};
|
||||
for (var key in object) if (object.hasOwnProperty(key))
|
||||
result[key] = object[key];
|
||||
return result;
|
||||
}
|
||||
|
||||
function match(string, word) {
|
||||
var len = string.length;
|
||||
var sub = getText(word).substr(0, len);
|
||||
return string.toUpperCase() === sub.toUpperCase();
|
||||
}
|
||||
|
||||
function addMatches(result, search, wordlist, formatter) {
|
||||
if (isArray(wordlist)) {
|
||||
for (var i = 0; i < wordlist.length; i++)
|
||||
if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
|
||||
} else {
|
||||
for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
|
||||
var val = wordlist[word]
|
||||
if (!val || val === true)
|
||||
val = word
|
||||
else
|
||||
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
|
||||
if (match(search, val)) result.push(formatter(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanName(name) {
|
||||
// Get rid name from identifierQuote and preceding dot(.)
|
||||
if (name.charAt(0) == ".") {
|
||||
name = name.substr(1);
|
||||
}
|
||||
// replace duplicated identifierQuotes with single identifierQuotes
|
||||
// and remove single identifierQuotes
|
||||
var nameParts = name.split(identifierQuote+identifierQuote);
|
||||
for (var i = 0; i < nameParts.length; i++)
|
||||
nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), "");
|
||||
return nameParts.join(identifierQuote);
|
||||
}
|
||||
|
||||
function insertIdentifierQuotes(name) {
|
||||
var nameParts = getText(name).split(".");
|
||||
for (var i = 0; i < nameParts.length; i++)
|
||||
nameParts[i] = identifierQuote +
|
||||
// duplicate identifierQuotes
|
||||
nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) +
|
||||
identifierQuote;
|
||||
var escaped = nameParts.join(".");
|
||||
if (typeof name == "string") return escaped;
|
||||
name = shallowClone(name);
|
||||
name.text = escaped;
|
||||
return name;
|
||||
}
|
||||
|
||||
function nameCompletion(cur, token, result, editor) {
|
||||
// Try to complete table, column names and return start position of completion
|
||||
var useIdentifierQuotes = false;
|
||||
var nameParts = [];
|
||||
var start = token.start;
|
||||
var cont = true;
|
||||
while (cont) {
|
||||
cont = (token.string.charAt(0) == ".");
|
||||
useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote);
|
||||
|
||||
start = token.start;
|
||||
nameParts.unshift(cleanName(token.string));
|
||||
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start));
|
||||
if (token.string == ".") {
|
||||
cont = true;
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start));
|
||||
}
|
||||
}
|
||||
|
||||
// Try to complete table names
|
||||
var string = nameParts.join(".");
|
||||
addMatches(result, string, tables, function(w) {
|
||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||
});
|
||||
|
||||
// Try to complete columns from defaultTable
|
||||
addMatches(result, string, defaultTable, function(w) {
|
||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||
});
|
||||
|
||||
// Try to complete columns
|
||||
string = nameParts.pop();
|
||||
var table = nameParts.join(".");
|
||||
|
||||
var alias = false;
|
||||
var aliasTable = table;
|
||||
// Check if table is available. If not, find table by Alias
|
||||
if (!getTable(table)) {
|
||||
var oldTable = table;
|
||||
table = findTableByAlias(table, editor);
|
||||
if (table !== oldTable) alias = true;
|
||||
}
|
||||
|
||||
var columns = getTable(table);
|
||||
if (columns && columns.columns)
|
||||
columns = columns.columns;
|
||||
|
||||
if (columns) {
|
||||
addMatches(result, string, columns, function(w) {
|
||||
var tableInsert = table;
|
||||
if (alias == true) tableInsert = aliasTable;
|
||||
if (typeof w == "string") {
|
||||
w = tableInsert + "." + w;
|
||||
} else {
|
||||
w = shallowClone(w);
|
||||
w.text = tableInsert + "." + w.text;
|
||||
}
|
||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||
});
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
function eachWord(lineText, f) {
|
||||
var words = lineText.split(/\s+/)
|
||||
for (var i = 0; i < words.length; i++)
|
||||
if (words[i]) f(words[i].replace(/[`,;]/g, ''))
|
||||
}
|
||||
|
||||
function findTableByAlias(alias, editor) {
|
||||
var doc = editor.doc;
|
||||
var fullQuery = doc.getValue();
|
||||
var aliasUpperCase = alias.toUpperCase();
|
||||
var previousWord = "";
|
||||
var table = "";
|
||||
var separator = [];
|
||||
var validRange = {
|
||||
start: Pos(0, 0),
|
||||
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
|
||||
};
|
||||
|
||||
//add separator
|
||||
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
|
||||
while(indexOfSeparator != -1) {
|
||||
separator.push(doc.posFromIndex(indexOfSeparator));
|
||||
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
|
||||
}
|
||||
separator.unshift(Pos(0, 0));
|
||||
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
|
||||
|
||||
//find valid range
|
||||
var prevItem = null;
|
||||
var current = editor.getCursor()
|
||||
for (var i = 0; i < separator.length; i++) {
|
||||
if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
|
||||
validRange = {start: prevItem, end: separator[i]};
|
||||
break;
|
||||
}
|
||||
prevItem = separator[i];
|
||||
}
|
||||
|
||||
if (validRange.start) {
|
||||
var query = doc.getRange(validRange.start, validRange.end, false);
|
||||
|
||||
for (var i = 0; i < query.length; i++) {
|
||||
var lineText = query[i];
|
||||
eachWord(lineText, function(word) {
|
||||
var wordUpperCase = word.toUpperCase();
|
||||
if (wordUpperCase === aliasUpperCase && getTable(previousWord))
|
||||
table = previousWord;
|
||||
if (wordUpperCase !== CONS.ALIAS_KEYWORD)
|
||||
previousWord = word;
|
||||
});
|
||||
if (table) break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
|
||||
tables = parseTables(options && options.tables)
|
||||
var defaultTableName = options && options.defaultTable;
|
||||
var disableKeywords = options && options.disableKeywords;
|
||||
defaultTable = defaultTableName && getTable(defaultTableName);
|
||||
keywords = getKeywords(editor);
|
||||
identifierQuote = getIdentifierQuote(editor);
|
||||
|
||||
if (defaultTableName && !defaultTable)
|
||||
defaultTable = findTableByAlias(defaultTableName, editor);
|
||||
|
||||
defaultTable = defaultTable || [];
|
||||
|
||||
if (defaultTable.columns)
|
||||
defaultTable = defaultTable.columns;
|
||||
|
||||
var cur = editor.getCursor();
|
||||
var result = [];
|
||||
var token = editor.getTokenAt(cur), start, end, search;
|
||||
if (token.end > cur.ch) {
|
||||
token.end = cur.ch;
|
||||
token.string = token.string.slice(0, cur.ch - token.start);
|
||||
}
|
||||
|
||||
if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) {
|
||||
search = token.string;
|
||||
start = token.start;
|
||||
end = token.end;
|
||||
} else {
|
||||
start = end = cur.ch;
|
||||
search = "";
|
||||
}
|
||||
if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
|
||||
start = nameCompletion(cur, token, result, editor);
|
||||
} else {
|
||||
var objectOrClass = function(w, className) {
|
||||
if (typeof w === "object") {
|
||||
w.className = className;
|
||||
} else {
|
||||
w = { text: w, className: className };
|
||||
}
|
||||
return w;
|
||||
};
|
||||
addMatches(result, search, defaultTable, function(w) {
|
||||
return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table");
|
||||
});
|
||||
addMatches(
|
||||
result,
|
||||
search,
|
||||
tables, function(w) {
|
||||
return objectOrClass(w, "CodeMirror-hint-table");
|
||||
}
|
||||
);
|
||||
if (!disableKeywords)
|
||||
addMatches(result, search, keywords, function(w) {
|
||||
return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword");
|
||||
});
|
||||
}
|
||||
|
||||
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
/* The lint marker gutter */
|
||||
.CodeMirror-lint-markers {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-tooltip {
|
||||
background-color: #ffd;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
overflow: hidden;
|
||||
padding: 2px 5px;
|
||||
position: fixed;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
z-index: 100;
|
||||
max-width: 600px;
|
||||
opacity: 0;
|
||||
transition: opacity .4s;
|
||||
-moz-transition: opacity .4s;
|
||||
-webkit-transition: opacity .4s;
|
||||
-o-transition: opacity .4s;
|
||||
-ms-transition: opacity .4s;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark {
|
||||
background-position: left bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-message {
|
||||
padding-left: 18px;
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-multiple {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right bottom;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-line-error {
|
||||
background-color: rgba(183, 76, 81, 0.08);
|
||||
}
|
||||
|
||||
.CodeMirror-lint-line-warning {
|
||||
background-color: rgba(255, 211, 0, 0.1);
|
||||
}
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
var GUTTER_ID = "CodeMirror-lint-markers";
|
||||
var LINT_LINE_ID = "CodeMirror-lint-line-";
|
||||
|
||||
function showTooltip(cm, e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme;
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
if (cm.state.lint.options.selfContain)
|
||||
cm.getWrapperElement().appendChild(tt);
|
||||
else
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
|
||||
tt.style.left = (e.clientX + 5) + "px";
|
||||
}
|
||||
CodeMirror.on(document, "mousemove", position);
|
||||
position(e);
|
||||
if (tt.style.opacity != null) tt.style.opacity = 1;
|
||||
return tt;
|
||||
}
|
||||
function rm(elt) {
|
||||
if (elt.parentNode) elt.parentNode.removeChild(elt);
|
||||
}
|
||||
function hideTooltip(tt) {
|
||||
if (!tt.parentNode) return;
|
||||
if (tt.style.opacity == null) rm(tt);
|
||||
tt.style.opacity = 0;
|
||||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(cm, e, content, node) {
|
||||
var tooltip = showTooltip(cm, e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
}
|
||||
var poll = setInterval(function() {
|
||||
if (tooltip) for (var n = node;; n = n.parentNode) {
|
||||
if (n && n.nodeType == 11) n = n.host;
|
||||
if (n == document.body) return;
|
||||
if (!n) { hide(); break; }
|
||||
}
|
||||
if (!tooltip) return clearInterval(poll);
|
||||
}, 400);
|
||||
CodeMirror.on(node, "mouseout", hide);
|
||||
}
|
||||
|
||||
function LintState(cm, conf, hasGutter) {
|
||||
this.marked = [];
|
||||
if (conf instanceof Function) conf = {getAnnotations: conf};
|
||||
if (!conf || conf === true) conf = {};
|
||||
this.options = {};
|
||||
this.linterOptions = conf.options || {};
|
||||
for (var prop in defaults) this.options[prop] = defaults[prop];
|
||||
for (var prop in conf) {
|
||||
if (defaults.hasOwnProperty(prop)) {
|
||||
if (conf[prop] != null) this.options[prop] = conf[prop];
|
||||
} else if (!conf.options) {
|
||||
this.linterOptions[prop] = conf[prop];
|
||||
}
|
||||
}
|
||||
this.timeout = null;
|
||||
this.hasGutter = hasGutter;
|
||||
this.onMouseOver = function(e) { onMouseOver(cm, e); };
|
||||
this.waitingFor = 0
|
||||
}
|
||||
|
||||
var defaults = {
|
||||
highlightLines: false,
|
||||
tooltips: true,
|
||||
delay: 500,
|
||||
lintOnChange: true,
|
||||
getAnnotations: null,
|
||||
async: false,
|
||||
selfContain: null,
|
||||
formatAnnotation: null,
|
||||
onUpdateLinting: null
|
||||
}
|
||||
|
||||
function clearMarks(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
|
||||
if (state.options.highlightLines) clearErrorLines(cm);
|
||||
for (var i = 0; i < state.marked.length; ++i)
|
||||
state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function clearErrorLines(cm) {
|
||||
cm.eachLine(function(line) {
|
||||
var has = line.wrapClass && /\bCodeMirror-lint-line-\w+\b/.exec(line.wrapClass);
|
||||
if (has) cm.removeLineClass(line, "wrap", has[0]);
|
||||
})
|
||||
}
|
||||
|
||||
function makeMarker(cm, labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
inner = marker.appendChild(document.createElement("div"));
|
||||
inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple";
|
||||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(cm, e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getMaxSeverity(a, b) {
|
||||
if (a == "error") return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
function groupByLine(annotations) {
|
||||
var lines = [];
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var ann = annotations[i], line = ann.from.line;
|
||||
(lines[line] || (lines[line] = [])).push(ann);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function annotationTooltip(ann) {
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity;
|
||||
if (typeof ann.messageHTML != 'undefined') {
|
||||
tip.innerHTML = ann.messageHTML;
|
||||
} else {
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
}
|
||||
return tip;
|
||||
}
|
||||
|
||||
function lintAsync(cm, getAnnotations) {
|
||||
var state = cm.state.lint
|
||||
var id = ++state.waitingFor
|
||||
function abort() {
|
||||
id = -1
|
||||
cm.off("change", abort)
|
||||
}
|
||||
cm.on("change", abort)
|
||||
getAnnotations(cm.getValue(), function(annotations, arg2) {
|
||||
cm.off("change", abort)
|
||||
if (state.waitingFor != id) return
|
||||
if (arg2 && annotations instanceof CodeMirror) annotations = arg2
|
||||
cm.operation(function() {updateLinting(cm, annotations)})
|
||||
}, state.linterOptions, cm);
|
||||
}
|
||||
|
||||
function startLinting(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
var options = state.options;
|
||||
/*
|
||||
* Passing rules in `options` property prevents JSHint (and other linters) from complaining
|
||||
* about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc.
|
||||
*/
|
||||
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
|
||||
if (!getAnnotations) return;
|
||||
if (options.async || getAnnotations.async) {
|
||||
lintAsync(cm, getAnnotations)
|
||||
} else {
|
||||
var annotations = getAnnotations(cm.getValue(), state.linterOptions, cm);
|
||||
if (!annotations) return;
|
||||
if (annotations.then) annotations.then(function(issues) {
|
||||
cm.operation(function() {updateLinting(cm, issues)})
|
||||
});
|
||||
else cm.operation(function() {updateLinting(cm, annotations)})
|
||||
}
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
var options = state.options;
|
||||
clearMarks(cm);
|
||||
|
||||
var annotations = groupByLine(annotationsNotSorted);
|
||||
|
||||
for (var line = 0; line < annotations.length; ++line) {
|
||||
var anns = annotations[line];
|
||||
if (!anns) continue;
|
||||
|
||||
// filter out duplicate messages
|
||||
var message = [];
|
||||
anns = anns.filter(function(item) { return message.indexOf(item.message) > -1 ? false : message.push(item.message) });
|
||||
|
||||
var maxSeverity = null;
|
||||
var tipLabel = state.hasGutter && document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < anns.length; ++i) {
|
||||
var ann = anns[i];
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
maxSeverity = getMaxSeverity(maxSeverity, severity);
|
||||
|
||||
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
|
||||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
|
||||
|
||||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
|
||||
className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity,
|
||||
__annotation: ann
|
||||
}));
|
||||
}
|
||||
// use original annotations[line] to show multiple messages
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, annotations[line].length > 1,
|
||||
options.tooltips));
|
||||
|
||||
if (options.highlightLines)
|
||||
cm.addLineClass(line, "wrap", LINT_LINE_ID + maxSeverity);
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay);
|
||||
}
|
||||
|
||||
function popupTooltips(cm, annotations, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
var tooltip = document.createDocumentFragment();
|
||||
for (var i = 0; i < annotations.length; i++) {
|
||||
var ann = annotations[i];
|
||||
tooltip.appendChild(annotationTooltip(ann));
|
||||
}
|
||||
showTooltipFor(cm, e, tooltip, target);
|
||||
}
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
|
||||
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
|
||||
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
|
||||
|
||||
var annotations = [];
|
||||
for (var i = 0; i < spans.length; ++i) {
|
||||
var ann = spans[i].__annotation;
|
||||
if (ann) annotations.push(ann);
|
||||
}
|
||||
if (annotations.length) popupTooltips(cm, annotations, e);
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lint", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearMarks(cm);
|
||||
if (cm.state.lint.options.lintOnChange !== false)
|
||||
cm.off("change", onChange);
|
||||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
|
||||
clearTimeout(cm.state.lint.timeout);
|
||||
delete cm.state.lint;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var gutters = cm.getOption("gutters"), hasLintGutter = false;
|
||||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
|
||||
var state = cm.state.lint = new LintState(cm, val, hasLintGutter);
|
||||
if (state.options.lintOnChange)
|
||||
cm.on("change", onChange);
|
||||
if (state.options.tooltips != false && state.options.tooltips != "gutter")
|
||||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
|
||||
|
||||
startLinting(cm);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("performLint", function() {
|
||||
startLinting(this);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.runMode = function(string, modespec, callback, options) {
|
||||
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
|
||||
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
|
||||
|
||||
// Create a tokenizing callback function if passed-in callback is a DOM element.
|
||||
if (callback.appendChild) {
|
||||
var ie = /MSIE \d/.test(navigator.userAgent);
|
||||
var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
|
||||
var node = callback, col = 0;
|
||||
node.textContent = "";
|
||||
callback = function(text, style) {
|
||||
if (text == "\n") {
|
||||
// Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
|
||||
// Emitting a carriage return makes everything ok.
|
||||
node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
|
||||
col = 0;
|
||||
return;
|
||||
}
|
||||
var content = "";
|
||||
// replace tabs
|
||||
for (var pos = 0;;) {
|
||||
var idx = text.indexOf("\t", pos);
|
||||
if (idx == -1) {
|
||||
content += text.slice(pos);
|
||||
col += text.length - pos;
|
||||
break;
|
||||
} else {
|
||||
col += idx - pos;
|
||||
content += text.slice(pos, idx);
|
||||
var size = tabSize - col % tabSize;
|
||||
col += size;
|
||||
for (var i = 0; i < size; ++i) content += " ";
|
||||
pos = idx + 1;
|
||||
}
|
||||
}
|
||||
// Create a node with token style and append it to the callback DOM element.
|
||||
if (style) {
|
||||
var sp = node.appendChild(document.createElement("span"));
|
||||
sp.className = "cm-" + style.replace(/ +/g, " cm-");
|
||||
sp.appendChild(document.createTextNode(content));
|
||||
} else {
|
||||
node.appendChild(document.createTextNode(content));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
|
||||
for (var i = 0, e = lines.length; i < e; ++i) {
|
||||
if (i) callback("\n");
|
||||
var stream = new CodeMirror.StringStream(lines[i], null, {
|
||||
lookAhead: function(n) { return lines[i + n] },
|
||||
baseToken: function() {}
|
||||
});
|
||||
if (!stream.string && mode.blankLine) mode.blankLine(state);
|
||||
while (!stream.eol()) {
|
||||
var style = mode.token(stream, state);
|
||||
callback(stream.current(), style, i, stream.start, state, mode);
|
||||
stream.start = stream.pos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
color: black;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line,
|
||||
.CodeMirror pre.CodeMirror-line-like {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0 !important;
|
||||
background: #7e7;
|
||||
}
|
||||
.cm-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-line::selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span::selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
|
||||
.cm-fat-cursor .CodeMirror-line::-moz-selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span::-moz-selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
|
||||
.cm-fat-cursor { caret-color: transparent; }
|
||||
@-moz-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror-overwrite .CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-rulers {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: -50px; bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
top: 0; bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
.CodeMirror-composing { border-bottom: 2px solid; }
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 50px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -50px; margin-right: -50px;
|
||||
padding-bottom: 50px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 50px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actual scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
outline: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
min-height: 100%;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.CodeMirror-gutter-background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
|
||||
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line,
|
||||
.CodeMirror pre.CodeMirror-line-like {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-font-variant-ligatures: contextual;
|
||||
font-variant-ligatures: contextual;
|
||||
}
|
||||
.CodeMirror-wrap pre.CodeMirror-line,
|
||||
.CodeMirror-wrap pre.CodeMirror-line-like {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 0.1px; /* Force widget margins to stay inside of the container */
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-rtl pre { direction: rtl; }
|
||||
|
||||
.CodeMirror-code {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Force content-box sizing for the elements where we expect it */
|
||||
.CodeMirror-scroll,
|
||||
.CodeMirror-sizer,
|
||||
.CodeMirror-gutter,
|
||||
.CodeMirror-gutters,
|
||||
.CodeMirror-linenumber {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
div.CodeMirror-dragcursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
||||
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background-color: #ffa;
|
||||
background-color: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* See issue #2901 */
|
||||
.cm-tab-wrap-hack:after { content: ''; }
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
||||
+9872
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,960 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
var jsonldMode = parserConfig.jsonld;
|
||||
var jsonMode = parserConfig.json || jsonldMode;
|
||||
var trackScope = parserConfig.trackScope !== false
|
||||
var isTS = parserConfig.typescript;
|
||||
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
return {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
|
||||
"debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
|
||||
"await": C
|
||||
};
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (expressionAllowed(stream, state, 1)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eat("=");
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#" && stream.peek() == "!") {
|
||||
stream.skipToEnd();
|
||||
return ret("meta", "meta");
|
||||
} else if (ch == "#" && stream.eatWhile(wordRE)) {
|
||||
return ret("variable", "property")
|
||||
} else if (ch == "<" && stream.match("!--") ||
|
||||
(ch == "-" && stream.match("->") && !/\S/.test(stream.string.slice(0, stream.start)))) {
|
||||
stream.skipToEnd()
|
||||
return ret("comment", "comment")
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
if (ch != ">" || !state.lexical || state.lexical.type != ">") {
|
||||
if (stream.eat("=")) {
|
||||
if (ch == "!" || ch == "=") stream.eat("=")
|
||||
} else if (/[<>*+\-|&?]/.test(ch)) {
|
||||
stream.eat(ch)
|
||||
if (ch == ">") stream.eat(ch)
|
||||
}
|
||||
}
|
||||
if (ch == "?" && stream.eat(".")) return ret(".")
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current()
|
||||
if (state.lastType != ".") {
|
||||
if (keywords.propertyIsEnumerable(word)) {
|
||||
var kw = keywords[word]
|
||||
return ret(kw.type, kw.style, word)
|
||||
}
|
||||
if (word == "async" && stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/, false))
|
||||
return ret("async", "keyword", word)
|
||||
}
|
||||
return ret("variable", "variable", word)
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next;
|
||||
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
|
||||
state.tokenize = tokenBase;
|
||||
return ret("jsonld-keyword", "meta");
|
||||
}
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
if (isTS) { // Try to skip TypeScript return type declarations after the arguments
|
||||
var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
|
||||
if (m) arrow = m.index
|
||||
}
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (wordRE.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (/["'\/`]/.test(ch)) {
|
||||
for (;; --pos) {
|
||||
if (pos == 0) return
|
||||
var next = stream.string.charAt(pos - 1)
|
||||
if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break }
|
||||
}
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true,
|
||||
"regexp": true, "this": true, "import": true, "jsonld-keyword": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
if (!trackScope) return false
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function inList(name, list) {
|
||||
for (var v = list; v; v = v.next) if (v.name == name) return true
|
||||
return false;
|
||||
}
|
||||
function register(varname) {
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (!trackScope) return
|
||||
if (state.context) {
|
||||
if (state.lexical.info == "var" && state.context && state.context.block) {
|
||||
// FIXME function decls are also not block scoped
|
||||
var newContext = registerVarScoped(varname, state.context)
|
||||
if (newContext != null) {
|
||||
state.context = newContext
|
||||
return
|
||||
}
|
||||
} else if (!inList(varname, state.localVars)) {
|
||||
state.localVars = new Var(varname, state.localVars)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Fall through means this is global
|
||||
if (parserConfig.globalVars && !inList(varname, state.globalVars))
|
||||
state.globalVars = new Var(varname, state.globalVars)
|
||||
}
|
||||
function registerVarScoped(varname, context) {
|
||||
if (!context) {
|
||||
return null
|
||||
} else if (context.block) {
|
||||
var inner = registerVarScoped(varname, context.prev)
|
||||
if (!inner) return null
|
||||
if (inner == context.prev) return context
|
||||
return new Context(inner, context.vars, true)
|
||||
} else if (inList(varname, context.vars)) {
|
||||
return context
|
||||
} else {
|
||||
return new Context(context.prev, new Var(varname, context.vars), false)
|
||||
}
|
||||
}
|
||||
|
||||
function isModifier(name) {
|
||||
return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block }
|
||||
function Var(name, next) { this.name = name; this.next = next }
|
||||
|
||||
var defaultVars = new Var("this", new Var("arguments", null))
|
||||
function pushcontext() {
|
||||
cx.state.context = new Context(cx.state.context, cx.state.localVars, false)
|
||||
cx.state.localVars = defaultVars
|
||||
}
|
||||
function pushblockcontext() {
|
||||
cx.state.context = new Context(cx.state.context, cx.state.localVars, true)
|
||||
cx.state.localVars = null
|
||||
}
|
||||
pushcontext.lex = pushblockcontext.lex = true
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars
|
||||
cx.state.context = cx.state.context.prev
|
||||
}
|
||||
popcontext.lex = true
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
if (state.lexical.type == "stat") indent = state.lexical.indented;
|
||||
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
|
||||
indent = outer.indented;
|
||||
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
|
||||
if (type == "debugger") return cont(expect(";"));
|
||||
if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
cx.state.cc.pop()();
|
||||
return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), pushblockcontext, forspec, statement, popcontext, poplex);
|
||||
if (type == "class" || (isTS && value == "interface")) {
|
||||
cx.marked = "keyword"
|
||||
return cont(pushlex("form", type == "class" ? type : value), className, poplex)
|
||||
}
|
||||
if (type == "variable") {
|
||||
if (isTS && value == "declare") {
|
||||
cx.marked = "keyword"
|
||||
return cont(statement)
|
||||
} else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
|
||||
cx.marked = "keyword"
|
||||
if (value == "enum") return cont(enumdef);
|
||||
else if (value == "type") return cont(typename, expect("operator"), typeexpr, expect(";"));
|
||||
else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
|
||||
} else if (isTS && value == "namespace") {
|
||||
cx.marked = "keyword"
|
||||
return cont(pushlex("form"), expression, statement, poplex)
|
||||
} else if (isTS && value == "abstract") {
|
||||
cx.marked = "keyword"
|
||||
return cont(statement)
|
||||
} else {
|
||||
return cont(pushlex("stat"), maybelabel);
|
||||
}
|
||||
}
|
||||
if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext,
|
||||
block, poplex, poplex, popcontext);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext);
|
||||
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
|
||||
if (type == "async") return cont(statement)
|
||||
if (value == "@") return cont(expression, statement)
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function maybeCatchBinding(type) {
|
||||
if (type == "(") return cont(funarg, expect(")"))
|
||||
}
|
||||
function expression(type, value) {
|
||||
return expressionInner(type, value, false);
|
||||
}
|
||||
function expressionNoComma(type, value) {
|
||||
return expressionInner(type, value, true);
|
||||
}
|
||||
function parenExpr(type) {
|
||||
if (type != "(") return pass()
|
||||
return cont(pushlex(")"), maybeexpression, expect(")"), poplex)
|
||||
}
|
||||
function expressionInner(type, value, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
|
||||
if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(maybeexpression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
|
||||
if (isTS && value == "<" && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false))
|
||||
return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { return pass(quasi, me); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
|
||||
if (type == "regexp") {
|
||||
cx.state.lastType = cx.marked = "operator"
|
||||
cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
|
||||
return cont(expr)
|
||||
}
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasi);
|
||||
return cont(maybeexpression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasi);
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
function target(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
|
||||
}
|
||||
function targetNoComma(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "async") {
|
||||
cx.marked = "property";
|
||||
return cont(objprop);
|
||||
} else if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
|
||||
if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
|
||||
cx.state.fatArrowAt = cx.stream.pos + m[0].length
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (isTS && isModifier(value)) {
|
||||
cx.marked = "keyword"
|
||||
return cont(objprop)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, maybetype, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expressionNoComma, afterprop);
|
||||
} else if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(objprop);
|
||||
} else if (type == ":") {
|
||||
return pass(afterprop)
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end, sep) {
|
||||
function proceed(type, value) {
|
||||
if (sep ? sep.indexOf(type) > -1 : type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(function(type, value) {
|
||||
if (type == end || value == end) return pass()
|
||||
return pass(what)
|
||||
}, proceed);
|
||||
}
|
||||
if (type == end || value == end) return cont();
|
||||
if (sep && sep.indexOf(";") > -1) return pass(what)
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type, value) {
|
||||
if (type == end || value == end) return cont();
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type, value) {
|
||||
if (isTS) {
|
||||
if (type == ":") return cont(typeexpr);
|
||||
if (value == "?") return cont(maybetype);
|
||||
}
|
||||
}
|
||||
function maybetypeOrIn(type, value) {
|
||||
if (isTS && (type == ":" || value == "in")) return cont(typeexpr)
|
||||
}
|
||||
function mayberettype(type) {
|
||||
if (isTS && type == ":") {
|
||||
if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
|
||||
else return cont(typeexpr)
|
||||
}
|
||||
}
|
||||
function isKW(_, value) {
|
||||
if (value == "is") {
|
||||
cx.marked = "keyword"
|
||||
return cont()
|
||||
}
|
||||
}
|
||||
function typeexpr(type, value) {
|
||||
if (value == "keyof" || value == "typeof" || value == "infer" || value == "readonly") {
|
||||
cx.marked = "keyword"
|
||||
return cont(value == "typeof" ? expressionNoComma : typeexpr)
|
||||
}
|
||||
if (type == "variable" || value == "void") {
|
||||
cx.marked = "type"
|
||||
return cont(afterType)
|
||||
}
|
||||
if (value == "|" || value == "&") return cont(typeexpr)
|
||||
if (type == "string" || type == "number" || type == "atom") return cont(afterType);
|
||||
if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
|
||||
if (type == "{") return cont(pushlex("}"), typeprops, poplex, afterType)
|
||||
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType)
|
||||
if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
|
||||
if (type == "quasi") { return pass(quasiType, afterType); }
|
||||
}
|
||||
function maybeReturnType(type) {
|
||||
if (type == "=>") return cont(typeexpr)
|
||||
}
|
||||
function typeprops(type) {
|
||||
if (type.match(/[\}\)\]]/)) return cont()
|
||||
if (type == "," || type == ";") return cont(typeprops)
|
||||
return pass(typeprop, typeprops)
|
||||
}
|
||||
function typeprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property"
|
||||
return cont(typeprop)
|
||||
} else if (value == "?" || type == "number" || type == "string") {
|
||||
return cont(typeprop)
|
||||
} else if (type == ":") {
|
||||
return cont(typeexpr)
|
||||
} else if (type == "[") {
|
||||
return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop)
|
||||
} else if (type == "(") {
|
||||
return pass(functiondecl, typeprop)
|
||||
} else if (!type.match(/[;\}\)\],]/)) {
|
||||
return cont()
|
||||
}
|
||||
}
|
||||
function quasiType(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasiType);
|
||||
return cont(typeexpr, continueQuasiType);
|
||||
}
|
||||
function continueQuasiType(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasiType);
|
||||
}
|
||||
}
|
||||
function typearg(type, value) {
|
||||
if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
|
||||
if (type == ":") return cont(typeexpr)
|
||||
if (type == "spread") return cont(typearg)
|
||||
return pass(typeexpr)
|
||||
}
|
||||
function afterType(type, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
|
||||
if (value == "|" || type == "." || value == "&") return cont(typeexpr)
|
||||
if (type == "[") return cont(typeexpr, expect("]"), afterType)
|
||||
if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
|
||||
if (value == "?") return cont(typeexpr, expect(":"), typeexpr)
|
||||
}
|
||||
function maybeTypeArgs(_, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
|
||||
}
|
||||
function typeparam() {
|
||||
return pass(typeexpr, maybeTypeDefault)
|
||||
}
|
||||
function maybeTypeDefault(_, value) {
|
||||
if (value == "=") return cont(typeexpr)
|
||||
}
|
||||
function vardef(_, value) {
|
||||
if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(eltpattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "}") return pass();
|
||||
if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern);
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function eltpattern() {
|
||||
return pass(pattern, maybeAssign)
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type, value) {
|
||||
if (value == "await") return cont(forspec);
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef, forspec2);
|
||||
if (type == "variable") return cont(forspec2);
|
||||
return pass(forspec2)
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ")") return cont()
|
||||
if (type == ";") return cont(forspec2)
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression, forspec2) }
|
||||
return pass(expression, forspec2)
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
|
||||
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
|
||||
}
|
||||
function functiondecl(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);}
|
||||
if (type == "variable") {register(value); return cont(functiondecl);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext);
|
||||
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl)
|
||||
}
|
||||
function typename(type, value) {
|
||||
if (type == "keyword" || type == "variable") {
|
||||
cx.marked = "type"
|
||||
return cont(typename)
|
||||
} else if (value == "<") {
|
||||
return cont(pushlex(">"), commasep(typeparam, ">"), poplex)
|
||||
}
|
||||
}
|
||||
function funarg(type, value) {
|
||||
if (value == "@") cont(expression, funarg)
|
||||
if (type == "spread") return cont(funarg);
|
||||
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
|
||||
if (isTS && type == "this") return cont(maybetype, maybeAssign)
|
||||
return pass(pattern, maybetype, maybeAssign);
|
||||
}
|
||||
function classExpression(type, value) {
|
||||
// Class expressions may have an optional name.
|
||||
if (type == "variable") return className(type, value);
|
||||
return classNameAfter(type, value);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
|
||||
if (value == "extends" || value == "implements" || (isTS && type == ",")) {
|
||||
if (value == "implements") cx.marked = "keyword";
|
||||
return cont(isTS ? typeexpr : expression, classNameAfter);
|
||||
}
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "async" ||
|
||||
(type == "variable" &&
|
||||
(value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
|
||||
cx.stream.match(/^\s+#?[\w$\xa1-\uffff]/, false))) {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
return cont(classfield, classBody);
|
||||
}
|
||||
if (type == "number" || type == "string") return cont(classfield, classBody);
|
||||
if (type == "[")
|
||||
return cont(expression, maybetype, expect("]"), classfield, classBody)
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (isTS && type == "(") return pass(functiondecl, classBody)
|
||||
if (type == ";" || type == ",") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
if (value == "@") return cont(expression, classBody)
|
||||
}
|
||||
function classfield(type, value) {
|
||||
if (value == "!") return cont(classfield)
|
||||
if (value == "?") return cont(classfield)
|
||||
if (type == ":") return cont(typeexpr, maybeAssign)
|
||||
if (value == "=") return cont(expressionNoComma)
|
||||
var context = cx.state.lexical.prev, isInterface = context && context.info == "interface"
|
||||
return pass(isInterface ? functiondecl : functiondef)
|
||||
}
|
||||
function afterExport(type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
|
||||
return pass(statement);
|
||||
}
|
||||
function exportField(type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
|
||||
if (type == "variable") return pass(expressionNoComma, exportField);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
if (type == "(") return pass(expression);
|
||||
if (type == ".") return pass(maybeoperatorComma);
|
||||
return pass(importSpec, maybeMoreImports, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
if (value == "*") cx.marked = "keyword";
|
||||
return cont(maybeAs);
|
||||
}
|
||||
function maybeMoreImports(type) {
|
||||
if (type == ",") return cont(importSpec, maybeMoreImports)
|
||||
}
|
||||
function maybeAs(_type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function enumdef() {
|
||||
return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
|
||||
}
|
||||
function enummember() {
|
||||
return pass(pattern, maybeAssign);
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
isOperatorChar.test(textAfter.charAt(0)) ||
|
||||
/[,.]/.test(textAfter.charAt(0));
|
||||
}
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return state.tokenize == tokenBase &&
|
||||
/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && new Context(null, null, false),
|
||||
indented: basecolumn || 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == tokenComment || state.tokenize == tokenQuasi) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse && c != popcontext) break;
|
||||
}
|
||||
while ((lexical.type == "stat" || lexical.type == "form") &&
|
||||
(firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
|
||||
(top == maybeoperatorComma || top == maybeoperatorNoComma) &&
|
||||
!/^[,\.=+\-*:?[\(]/.test(textAfter))))
|
||||
lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
blockCommentContinue: jsonMode ? null : " * ",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode,
|
||||
|
||||
expressionAllowed: expressionAllowed,
|
||||
|
||||
skipExpression: function(state) {
|
||||
parseJS(state, "atom", "atom", "true", new CodeMirror.StringStream("", 2, null))
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/x-javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", { name: "javascript", json: true });
|
||||
CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true });
|
||||
CodeMirror.defineMIME("application/manifest+json", { name: "javascript", json: true })
|
||||
CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true });
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
||||
|
||||
});
|
||||
+528
@@ -0,0 +1,528 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("sql", function(config, parserConfig) {
|
||||
var client = parserConfig.client || {},
|
||||
atoms = parserConfig.atoms || {"false": true, "true": true, "null": true},
|
||||
builtin = parserConfig.builtin || set(defaultBuiltin),
|
||||
keywords = parserConfig.keywords || set(sqlKeywords),
|
||||
operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^\/]/,
|
||||
support = parserConfig.support || {},
|
||||
hooks = parserConfig.hooks || {},
|
||||
dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true},
|
||||
backslashStringEscapes = parserConfig.backslashStringEscapes !== false,
|
||||
brackets = parserConfig.brackets || /^[\{}\(\)\[\]]/,
|
||||
punctuation = parserConfig.punctuation || /^[;.,:]/
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
|
||||
// call hooks from the mime type
|
||||
if (hooks[ch]) {
|
||||
var result = hooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
|
||||
if (support.hexNumber &&
|
||||
((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
|
||||
|| (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]*'/))) {
|
||||
// hex
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/hexadecimal-literals.html
|
||||
return "number";
|
||||
} else if (support.binaryNumber &&
|
||||
(((ch == "b" || ch == "B") && stream.match(/^'[01]*'/))
|
||||
|| (ch == "0" && stream.match(/^b[01]+/)))) {
|
||||
// bitstring
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/bit-value-literals.html
|
||||
return "number";
|
||||
} else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
|
||||
// numbers
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/number-literals.html
|
||||
stream.match(/^[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?/);
|
||||
support.decimallessFloat && stream.match(/^\.(?!\.)/);
|
||||
return "number";
|
||||
} else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
|
||||
// placeholders
|
||||
return "variable-3";
|
||||
} else if (ch == "'" || (ch == '"' && support.doubleQuote)) {
|
||||
// strings
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/string-literals.html
|
||||
state.tokenize = tokenLiteral(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if ((((support.nCharCast && (ch == "n" || ch == "N"))
|
||||
|| (support.charsetCast && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
|
||||
&& (stream.peek() == "'" || stream.peek() == '"'))) {
|
||||
// charset casting: _utf8'str', N'str', n'str'
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/string-literals.html
|
||||
return "keyword";
|
||||
} else if (support.escapeConstant && (ch == "e" || ch == "E")
|
||||
&& (stream.peek() == "'" || (stream.peek() == '"' && support.doubleQuote))) {
|
||||
// escape constant: E'str', e'str'
|
||||
// ref: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE
|
||||
state.tokenize = function(stream, state) {
|
||||
return (state.tokenize = tokenLiteral(stream.next(), true))(stream, state);
|
||||
}
|
||||
return "keyword";
|
||||
} else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
|
||||
// 1-line comment
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
} else if ((support.commentHash && ch == "#")
|
||||
|| (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) {
|
||||
// 1-line comments
|
||||
// ref: https://kb.askmonty.org/en/comment-syntax/
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
} else if (ch == "/" && stream.eat("*")) {
|
||||
// multi-line comments
|
||||
// ref: https://kb.askmonty.org/en/comment-syntax/
|
||||
state.tokenize = tokenComment(1);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ".") {
|
||||
// .1 for 0.1
|
||||
if (support.zerolessFloat && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i))
|
||||
return "number";
|
||||
if (stream.match(/^\.+/))
|
||||
return null
|
||||
// .table_name (ODBC)
|
||||
// // ref: https://dev.mysql.com/doc/refman/8.0/en/identifier-qualifiers.html
|
||||
if (support.ODBCdotTable && stream.match(/^[\w\d_$#]+/))
|
||||
return "variable-2";
|
||||
} else if (operatorChars.test(ch)) {
|
||||
// operators
|
||||
stream.eatWhile(operatorChars);
|
||||
return "operator";
|
||||
} else if (brackets.test(ch)) {
|
||||
// brackets
|
||||
return "bracket";
|
||||
} else if (punctuation.test(ch)) {
|
||||
// punctuation
|
||||
stream.eatWhile(punctuation);
|
||||
return "punctuation";
|
||||
} else if (ch == '{' &&
|
||||
(stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
|
||||
// dates (weird ODBC syntax)
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-literals.html
|
||||
return "number";
|
||||
} else {
|
||||
stream.eatWhile(/^[_\w\d]/);
|
||||
var word = stream.current().toLowerCase();
|
||||
// dates (standard SQL syntax)
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-literals.html
|
||||
if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/)))
|
||||
return "number";
|
||||
if (atoms.hasOwnProperty(word)) return "atom";
|
||||
if (builtin.hasOwnProperty(word)) return "type";
|
||||
if (keywords.hasOwnProperty(word)) return "keyword";
|
||||
if (client.hasOwnProperty(word)) return "builtin";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 'string', with char specified in quote escaped by '\'
|
||||
function tokenLiteral(quote, backslashEscapes) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = (backslashStringEscapes || backslashEscapes) && !escaped && ch == "\\";
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
function tokenComment(depth) {
|
||||
return function(stream, state) {
|
||||
var m = stream.match(/^.*?(\/\*|\*\/)/)
|
||||
if (!m) stream.skipToEnd()
|
||||
else if (m[1] == "/*") state.tokenize = tokenComment(depth + 1)
|
||||
else if (depth > 1) state.tokenize = tokenComment(depth - 1)
|
||||
else state.tokenize = tokenBase
|
||||
return "comment"
|
||||
}
|
||||
}
|
||||
|
||||
function pushContext(stream, state, type) {
|
||||
state.context = {
|
||||
prev: state.context,
|
||||
indent: stream.indentation(),
|
||||
col: stream.column(),
|
||||
type: type
|
||||
};
|
||||
}
|
||||
|
||||
function popContext(state) {
|
||||
state.indent = state.context.indent;
|
||||
state.context = state.context.prev;
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {tokenize: tokenBase, context: null};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (state.context && state.context.align == null)
|
||||
state.context.align = false;
|
||||
}
|
||||
if (state.tokenize == tokenBase && stream.eatSpace()) return null;
|
||||
|
||||
var style = state.tokenize(stream, state);
|
||||
if (style == "comment") return style;
|
||||
|
||||
if (state.context && state.context.align == null)
|
||||
state.context.align = true;
|
||||
|
||||
var tok = stream.current();
|
||||
if (tok == "(")
|
||||
pushContext(stream, state, ")");
|
||||
else if (tok == "[")
|
||||
pushContext(stream, state, "]");
|
||||
else if (state.context && state.context.type == tok)
|
||||
popContext(state);
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var cx = state.context;
|
||||
if (!cx) return CodeMirror.Pass;
|
||||
var closing = textAfter.charAt(0) == cx.type;
|
||||
if (cx.align) return cx.col + (closing ? 0 : 1);
|
||||
else return cx.indent + (closing ? 0 : config.indentUnit);
|
||||
},
|
||||
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : "--",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
config: parserConfig
|
||||
};
|
||||
});
|
||||
|
||||
// `identifier`
|
||||
function hookIdentifier(stream) {
|
||||
// MySQL/MariaDB identifiers
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/identifier-qualifiers.html
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "`" && !stream.eat("`")) return "variable-2";
|
||||
}
|
||||
stream.backUp(stream.current().length - 1);
|
||||
return stream.eatWhile(/\w/) ? "variable-2" : null;
|
||||
}
|
||||
|
||||
// "identifier"
|
||||
function hookIdentifierDoublequote(stream) {
|
||||
// Standard SQL /SQLite identifiers
|
||||
// ref: http://web.archive.org/web/20160813185132/http://savage.net.au/SQL/sql-99.bnf.html#delimited%20identifier
|
||||
// ref: http://sqlite.org/lang_keywords.html
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "\"" && !stream.eat("\"")) return "variable-2";
|
||||
}
|
||||
stream.backUp(stream.current().length - 1);
|
||||
return stream.eatWhile(/\w/) ? "variable-2" : null;
|
||||
}
|
||||
|
||||
// variable token
|
||||
function hookVar(stream) {
|
||||
// variables
|
||||
// @@prefix.varName @varName
|
||||
// varName can be quoted with ` or ' or "
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/user-variables.html
|
||||
if (stream.eat("@")) {
|
||||
stream.match('session.');
|
||||
stream.match('local.');
|
||||
stream.match('global.');
|
||||
}
|
||||
|
||||
if (stream.eat("'")) {
|
||||
stream.match(/^.*'/);
|
||||
return "variable-2";
|
||||
} else if (stream.eat('"')) {
|
||||
stream.match(/^.*"/);
|
||||
return "variable-2";
|
||||
} else if (stream.eat("`")) {
|
||||
stream.match(/^.*`/);
|
||||
return "variable-2";
|
||||
} else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) {
|
||||
return "variable-2";
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// short client keyword token
|
||||
function hookClient(stream) {
|
||||
// \N means NULL
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/null-values.html
|
||||
if (stream.eat("N")) {
|
||||
return "atom";
|
||||
}
|
||||
// \g, etc
|
||||
// ref: https://dev.mysql.com/doc/refman/8.0/en/mysql-commands.html
|
||||
return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null;
|
||||
}
|
||||
|
||||
// these keywords are used by all SQL dialects (however, a mode can still overwrite it)
|
||||
var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit ";
|
||||
|
||||
// turn a space-separated list into an array
|
||||
function set(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
var defaultBuiltin = "bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"
|
||||
|
||||
// A generic SQL Mode. It's not a standard, it just tries to support what is generally supported
|
||||
CodeMirror.defineMIME("text/x-sql", {
|
||||
name: "sql",
|
||||
keywords: set(sqlKeywords + "begin"),
|
||||
builtin: set(defaultBuiltin),
|
||||
atoms: set("false true null unknown"),
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-mssql", {
|
||||
name: "sql",
|
||||
client: set("$partition binary_checksum checksum connectionproperty context_info current_request_id error_line error_message error_number error_procedure error_severity error_state formatmessage get_filestream_transaction_context getansinull host_id host_name isnull isnumeric min_active_rowversion newid newsequentialid rowcount_big xact_state object_id"),
|
||||
keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare exec go if use index holdlock nolock nowait paglock readcommitted readcommittedlock readpast readuncommitted repeatableread rowlock serializable snapshot tablock tablockx updlock with"),
|
||||
builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "),
|
||||
atoms: set("is not null like and or in left right between inner outer join all any some cross unpivot pivot exists"),
|
||||
operatorChars: /^[*+\-%<>!=^\&|\/]/,
|
||||
brackets: /^[\{}\(\)]/,
|
||||
punctuation: /^[;.,:/]/,
|
||||
backslashStringEscapes: false,
|
||||
dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"),
|
||||
hooks: {
|
||||
"@": hookVar
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-mysql", {
|
||||
name: "sql",
|
||||
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
|
||||
keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group group_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
|
||||
builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=&|^]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),
|
||||
hooks: {
|
||||
"@": hookVar,
|
||||
"`": hookIdentifier,
|
||||
"\\": hookClient
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-mariadb", {
|
||||
name: "sql",
|
||||
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
|
||||
keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group group_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
|
||||
builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=&|^]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),
|
||||
hooks: {
|
||||
"@": hookVar,
|
||||
"`": hookIdentifier,
|
||||
"\\": hookClient
|
||||
}
|
||||
});
|
||||
|
||||
// provided by the phpLiteAdmin project - phpliteadmin.org
|
||||
CodeMirror.defineMIME("text/x-sqlite", {
|
||||
name: "sql",
|
||||
// commands of the official SQLite client, ref: https://www.sqlite.org/cli.html#dotcmd
|
||||
client: set("auth backup bail binary changes check clone databases dbinfo dump echo eqp exit explain fullschema headers help import imposter indexes iotrace limit lint load log mode nullvalue once open output print prompt quit read restore save scanstats schema separator session shell show stats system tables testcase timeout timer trace vfsinfo vfslist vfsname width"),
|
||||
// ref: http://sqlite.org/lang_keywords.html
|
||||
keywords: set(sqlKeywords + "abort action add after all analyze attach autoincrement before begin cascade case cast check collate column commit conflict constraint cross current_date current_time current_timestamp database default deferrable deferred detach each else end escape except exclusive exists explain fail for foreign full glob if ignore immediate index indexed initially inner instead intersect isnull key left limit match natural no notnull null of offset outer plan pragma primary query raise recursive references regexp reindex release rename replace restrict right rollback row savepoint temp temporary then to transaction trigger unique using vacuum view virtual when with without"),
|
||||
// SQLite is weakly typed, ref: http://sqlite.org/datatype3.html. This is just a list of some common types.
|
||||
builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text clob bigint int int2 int8 integer float double char varchar date datetime year unsigned signed numeric real"),
|
||||
// ref: http://sqlite.org/syntax/literal-value.html
|
||||
atoms: set("null current_date current_time current_timestamp"),
|
||||
// ref: http://sqlite.org/lang_expr.html#binaryops
|
||||
operatorChars: /^[*+\-%<>!=&|/~]/,
|
||||
// SQLite is weakly typed, ref: http://sqlite.org/datatype3.html. This is just a list of some common types.
|
||||
dateSQL: set("date time timestamp datetime"),
|
||||
support: set("decimallessFloat zerolessFloat"),
|
||||
identifierQuote: "\"", //ref: http://sqlite.org/lang_keywords.html
|
||||
hooks: {
|
||||
// bind-parameters ref:http://sqlite.org/lang_expr.html#varparam
|
||||
"@": hookVar,
|
||||
":": hookVar,
|
||||
"?": hookVar,
|
||||
"$": hookVar,
|
||||
// The preferred way to escape Identifiers is using double quotes, ref: http://sqlite.org/lang_keywords.html
|
||||
"\"": hookIdentifierDoublequote,
|
||||
// there is also support for backticks, ref: http://sqlite.org/lang_keywords.html
|
||||
"`": hookIdentifier
|
||||
}
|
||||
});
|
||||
|
||||
// the query language used by Apache Cassandra is called CQL, but this mime type
|
||||
// is called Cassandra to avoid confusion with Contextual Query Language
|
||||
CodeMirror.defineMIME("text/x-cassandra", {
|
||||
name: "sql",
|
||||
client: { },
|
||||
keywords: set("add all allow alter and any apply as asc authorize batch begin by clustering columnfamily compact consistency count create custom delete desc distinct drop each_quorum exists filtering from grant if in index insert into key keyspace keyspaces level limit local_one local_quorum modify nan norecursive nosuperuser not of on one order password permission permissions primary quorum rename revoke schema select set storage superuser table three to token truncate ttl two type unlogged update use user users using values where with writetime"),
|
||||
builtin: set("ascii bigint blob boolean counter decimal double float frozen inet int list map static text timestamp timeuuid tuple uuid varchar varint"),
|
||||
atoms: set("false true infinity NaN"),
|
||||
operatorChars: /^[<>=]/,
|
||||
dateSQL: { },
|
||||
support: set("commentSlashSlash decimallessFloat"),
|
||||
hooks: { }
|
||||
});
|
||||
|
||||
// this is based on Peter Raganitsch's 'plsql' mode
|
||||
CodeMirror.defineMIME("text/x-plsql", {
|
||||
name: "sql",
|
||||
client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"),
|
||||
keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"),
|
||||
builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least length lengthb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"),
|
||||
operatorChars: /^[*\/+\-%<>!=~]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber")
|
||||
});
|
||||
|
||||
// Created to support specific hive keywords
|
||||
CodeMirror.defineMIME("text/x-hive", {
|
||||
name: "sql",
|
||||
keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with admin authorization char compact compactions conf cube current current_date current_timestamp day decimal defined dependency directories elem_type exchange file following for grouping hour ignore inner interval jar less logical macro minute month more none noscan over owner partialscan preceding pretty principals protection reload rewrite role roles rollup rows second server sets skewed transactions truncate unbounded unset uri user values window year"),
|
||||
builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype key_type utctimestamp value_type varchar"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=]/,
|
||||
dateSQL: set("date timestamp"),
|
||||
support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-pgsql", {
|
||||
name: "sql",
|
||||
client: set("source"),
|
||||
// For PostgreSQL - https://www.postgresql.org/docs/11/sql-keywords-appendix.html
|
||||
// For pl/pgsql lang - https://github.com/postgres/postgres/blob/REL_11_2/src/pl/plpgsql/src/pl_scanner.c
|
||||
keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate alias all allocate also alter always analyse analyze and any are array array_agg array_max_cardinality as asc asensitive assert assertion assignment asymmetric at atomic attach attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli between bigint binary bit bit_length blob blocked bom boolean both breadth by c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain char char_length character character_length character_set_catalog character_set_name character_set_schema characteristics characters check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column column_name columns command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constant constraint constraint_catalog constraint_name constraint_schema constraints constructor contains content continue control conversion convert copy corr corresponding cost count covar_pop covar_samp create cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datatype date datetime_interval_code datetime_interval_precision day db deallocate debug dec decimal declare default defaults deferrable deferred defined definer degree delete delimiter delimiters dense_rank depends depth deref derived desc describe descriptor detach detail deterministic diagnostics dictionary disable discard disconnect dispatch distinct dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain double drop dump dynamic dynamic_function dynamic_function_code each element else elseif elsif empty enable encoding encrypted end end_frame end_partition endexec enforced enum equals errcode error escape event every except exception exclude excluding exclusive exec execute exists exit exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreach foreign fortran forward found frame_row free freeze from fs full function functions fusion g general generated get global go goto grant granted greatest group grouping groups handler having header hex hierarchy hint hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import in include including increment indent index indexes indicator info inherit inherits initially inline inner inout input insensitive insert instance instantiable instead int integer integrity intersect intersection interval into invoker is isnull isolation join k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like like_regex limit link listen ln load local localtime localtimestamp location locator lock locked log logged loop lower m map mapping match matched materialized max max_cardinality maxvalue member merge message message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized not nothing notice notify notnull nowait nth_value ntile null nullable nullif nulls number numeric object occurrences_regex octet_length octets of off offset oids old on only open operator option options or order ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parallel parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password path percent percent_rank percentile_cont percentile_disc perform period permission pg_context pg_datatype_name pg_exception_context pg_exception_detail pg_exception_hint placing plans pli policy portion position position_regex power precedes preceding precision prepare prepared preserve primary print_strict_params prior privileges procedural procedure procedures program public publication query quote raise range rank read reads real reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict result result_oid return returned_cardinality returned_length returned_octet_length returned_sqlstaLine truncated
|
||||
// https://www.postgresql.org/docs/11/datatype.html
|
||||
builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*\/+\-%<>!=&|^\/#@?~]/,
|
||||
backslashStringEscapes: false,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast escapeConstant")
|
||||
});
|
||||
|
||||
// Google's SQL-like query language, GQL
|
||||
CodeMirror.defineMIME("text/x-gql", {
|
||||
name: "sql",
|
||||
keywords: set("ancestor and asc by contains desc descendant distinct from group has in is limit offset on order select superset where"),
|
||||
atoms: set("false true"),
|
||||
builtin: set("blob datetime first key __key__ string integer double boolean null"),
|
||||
operatorChars: /^[*+\-%<>!=]/
|
||||
});
|
||||
|
||||
// Greenplum
|
||||
CodeMirror.defineMIME("text/x-gpsql", {
|
||||
name: "sql",
|
||||
client: set("source"),
|
||||
//https://github.com/greenplum-db/gpdb/blob/master/src/include/parser/kwlist.h
|
||||
keywords: set("abort absolute access action active add admin after aggregate all also alter always analyse analyze and any array as asc assertion assignment asymmetric at authorization backward before begin between bigint binary bit boolean both by cache called cascade cascaded case cast chain char character characteristics check checkpoint class close cluster coalesce codegen collate column comment commit committed concurrency concurrently configuration connection constraint constraints contains content continue conversion copy cost cpu_rate_limit create createdb createexttable createrole createuser cross csv cube current current_catalog current_date current_role current_schema current_time current_timestamp current_user cursor cycle data database day deallocate dec decimal declare decode default defaults deferrable deferred definer delete delimiter delimiters deny desc dictionary disable discard distinct distributed do document domain double drop dxl each else enable encoding encrypted end enum errors escape every except exchange exclude excluding exclusive execute exists explain extension external extract false family fetch fields filespace fill filter first float following for force foreign format forward freeze from full function global grant granted greatest group group_id grouping handler hash having header hold host hour identity if ignore ilike immediate immutable implicit in including inclusive increment index indexes inherit inherits initially inline inner inout input insensitive insert instead int integer intersect interval into invoker is isnull isolation join key language large last leading least left level like limit list listen load local localtime localtimestamp location lock log login mapping master match maxvalue median merge minute minvalue missing mode modifies modify month move name names national natural nchar new newline next no nocreatedb nocreateexttable nocreaterole nocreateuser noinherit nologin none noovercommit nosuperuser not nothing notify notnull nowait null nullif nulls numeric object of off offset oids old on only operator option options or order ordered others out outer over overcommit overlaps overlay owned owner parser partial partition partitions passing password percent percentile_cont percentile_disc placing plans position preceding precision prepare prepared preserve primary prior privileges procedural procedure protocol queue quote randomly range read readable reads real reassign recheck recursive ref references reindex reject relative release rename repeatable replace replica reset resource restart restrict returning returns revoke right role rollback rollup rootpartition row rows rule savepoint scatter schema scroll search second security segment select sequence serializable session session_user set setof sets share show similar simple smallint some split sql stable standalone start statement statistics stdin stdout storage strict strip subpartition subpartitions substring superuser symmetric sysid system table tablespace temp template temporary text then threshold ties time timestamp to trailing transaction treat trigger trim true truncate trusted type unbounded uncommitted unencrypted union unique unknown unlisten until update user using vacuum valid validation validator value values varchar variadic varying verbose version view volatile web when where whitespace window with within without work writable write xml xmlattributes xmlconcat xmlelement xmlexists xmlforest xmlparse xmlpi xmlroot xmlserialize year yes zone"),
|
||||
builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=&|^\/#@?~]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast")
|
||||
});
|
||||
|
||||
// Spark SQL
|
||||
CodeMirror.defineMIME("text/x-sparksql", {
|
||||
name: "sql",
|
||||
keywords: set("add after all alter analyze and anti archive array as asc at between bucket buckets by cache cascade case cast change clear cluster clustered codegen collection column columns comment commit compact compactions compute concatenate cost create cross cube current current_date current_timestamp database databases data dbproperties defined delete delimited deny desc describe dfs directories distinct distribute drop else end escaped except exchange exists explain export extended external false fields fileformat first following for format formatted from full function functions global grant group grouping having if ignore import in index indexes inner inpath inputformat insert intersect interval into is items join keys last lateral lazy left like limit lines list load local location lock locks logical macro map minus msck natural no not null nulls of on optimize option options or order out outer outputformat over overwrite partition partitioned partitions percent preceding principals purge range recordreader recordwriter recover reduce refresh regexp rename repair replace reset restrict revoke right rlike role roles rollback rollup row rows schema schemas select semi separated serde serdeproperties set sets show skewed sort sorted start statistics stored stratify struct table tables tablesample tblproperties temp temporary terminated then to touch transaction transactions transform true truncate unarchive unbounded uncache union unlock unset use using values view when where window with"),
|
||||
builtin: set("abs acos acosh add_months aggregate and any approx_count_distinct approx_percentile array array_contains array_distinct array_except array_intersect array_join array_max array_min array_position array_remove array_repeat array_sort array_union arrays_overlap arrays_zip ascii asin asinh assert_true atan atan2 atanh avg base64 between bigint bin binary bit_and bit_count bit_get bit_length bit_or bit_xor bool_and bool_or boolean bround btrim cardinality case cast cbrt ceil ceiling char char_length character_length chr coalesce collect_list collect_set concat concat_ws conv corr cos cosh cot count count_if count_min_sketch covar_pop covar_samp crc32 cume_dist current_catalog current_database current_date current_timestamp current_timezone current_user date date_add date_format date_from_unix_date date_part date_sub date_trunc datediff day dayofmonth dayofweek dayofyear decimal decode degrees delimited dense_rank div double e element_at elt encode every exists exp explode explode_outer expm1 extract factorial filter find_in_set first first_value flatten float floor forall format_number format_string from_csv from_json from_unixtime from_utc_timestamp get_json_object getbit greatest grouping grouping_id hash hex hour hypot if ifnull in initcap inline inline_outer input_file_block_length input_file_block_start input_file_name inputformat instr int isnan isnotnull isnull java_method json_array_length json_object_keys json_tuple kurtosis lag last last_day last_value lcase lead least left length levenshtein like ln locate log log10 log1p log2 lower lpad ltrim make_date make_dt_interval make_interval make_timestamp make_ym_interval map map_concat map_entries map_filter map_from_arrays map_from_entries map_keys map_values map_zip_with max max_by md5 mean min min_by minute mod monotonically_increasing_id month months_between named_struct nanvl negative next_day not now nth_value ntile nullif nvl nvl2 octet_length or outputformat overlay parse_url percent_rank percentile percentile_approx pi pmod posexplode posexplode_outer position positive pow power printf quarter radians raise_error rand randn random rank rcfile reflect regexp regexp_extract regexp_extract_all regexp_like regexp_replace repeat replace reverse right rint rlike round row_number rpad rtrim schema_of_csv schema_of_json second sentences sequence sequencefile serde session_window sha sha1 sha2 shiftleft shiftright shiftrightunsigned shuffle sign signum sin sinh size skewness slice smallint some sort_array soundex space spark_partition_id split sqrt stack std stddev stddev_pop stddev_samp str_to_map string struct substr substring substring_index sum tan tanh textfile timestamp timestamp_micros timestamp_millis timestamp_seconds tinyint to_csv to_date to_json to_timestamp to_unix_timestamp to_utc_timestamp transform transform_keys transform_values translate trim trunc try_add try_divide typeof ucase unbase64 unhex uniontype unix_date unix_micros unix_millis unix_seconds unix_timestamp upper uuid var_pop var_samp variance version weekday weekofyear when width_bucket window xpath xpath_boolean xpath_double xpath_float xpath_int xpath_long xpath_number xpath_short xpath_string xxhash64 year zip_with"),
|
||||
atoms: set("false true null"),
|
||||
operatorChars: /^[*\/+\-%<>!=~&|^]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable doubleQuote zerolessFloat")
|
||||
});
|
||||
|
||||
// Esper
|
||||
CodeMirror.defineMIME("text/x-esper", {
|
||||
name: "sql",
|
||||
client: set("source"),
|
||||
// http://www.espertech.com/esper/release-5.5.0/esper-reference/html/appendix_keywords.html
|
||||
keywords: set("alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit after all and as at asc avedev avg between by case cast coalesce count create current_timestamp day days delete define desc distinct else end escape events every exists false first from full group having hour hours in inner insert instanceof into irstream is istream join last lastweekday left limit like max match_recognize matches median measures metadatasql min minute minutes msec millisecond milliseconds not null offset on or order outer output partition pattern prev prior regexp retain-union retain-intersection right rstream sec second seconds select set some snapshot sql stddev sum then true unidirectional until update variable weekday when where window"),
|
||||
builtin: {},
|
||||
atoms: set("false true null"),
|
||||
operatorChars: /^[*+\-%<>!=&|^\/#@?~]/,
|
||||
dateSQL: set("time"),
|
||||
support: set("decimallessFloat zerolessFloat binaryNumber hexNumber")
|
||||
});
|
||||
|
||||
// Trino (formerly known as Presto)
|
||||
CodeMirror.defineMIME("text/x-trino", {
|
||||
name: "sql",
|
||||
// https://github.com/trinodb/trino/blob/bc7a4eeedde28684c7ae6f74cefcaf7c6e782174/core/trino-parser/src/main/antlr4/io/trino/sql/parser/SqlBase.g4#L859-L1129
|
||||
// https://github.com/trinodb/trino/blob/bc7a4eeedde28684c7ae6f74cefcaf7c6e782174/docs/src/main/sphinx/functions/list.rst
|
||||
keywords: set("abs absent acos add admin after all all_match alter analyze and any any_match approx_distinct approx_most_frequent approx_percentile approx_set arbitrary array_agg array_distinct array_except array_intersect array_join array_max array_min array_position array_remove array_sort array_union arrays_overlap as asc asin at at_timezone atan atan2 authorization avg bar bernoulli beta_cdf between bing_tile bing_tile_at bing_tile_coordinates bing_tile_polygon bing_tile_quadkey bing_tile_zoom_level bing_tiles_around bit_count bitwise_and bitwise_and_agg bitwise_left_shift bitwise_not bitwise_or bitwise_or_agg bitwise_right_shift bitwise_right_shift_arithmetic bitwise_xor bool_and bool_or both by call cardinality cascade case cast catalogs cbrt ceil ceiling char2hexint checksum chr classify coalesce codepoint column columns combinations comment commit committed concat concat_ws conditional constraint contains contains_sequence convex_hull_agg copartition corr cos cosh cosine_similarity count count_if covar_pop covar_samp crc32 create cross cube cume_dist current current_catalog current_date current_groups current_path current_role current_schema current_time current_timestamp current_timezone current_user data date_add date_diff date_format date_parse date_trunc day day_of_month day_of_week day_of_year deallocate default define definer degrees delete dense_rank deny desc describe descriptor distinct distributed dow doy drop e element_at else empty empty_approx_set encoding end error escape evaluate_classifier_predictions every except excluding execute exists exp explain extract false features fetch filter final first first_value flatten floor following for format format_datetime format_number from from_base from_base32 from_base64 from_base64url from_big_endian_32 from_big_endian_64 from_encoded_polyline from_geojson_geometry from_hex from_ieee754_32 from_ieee754_64 from_iso8601_date from_iso8601_timestamp from_iso8601_timestamp_nanos from_unixtime from_unixtime_nanos from_utf8 full functions geometric_mean geometry_from_hadoop_shape geometry_invalid_reason geometry_nearest_points geometry_to_bing_tiles geometry_union geometry_union_agg grant granted grants graphviz great_circle_distance greatest group grouping groups hamming_distance hash_counts having histogram hmac_md5 hmac_sha1 hmac_sha256 hmac_sha512 hour human_readable_seconds if ignore in including index infinity initial inner input insert intersect intersection_cardinality into inverse_beta_cdf inverse_normal_cdf invoker io is is_finite is_infinite is_json_scalar is_nan isolation jaccard_index join json_array json_array_contains json_array_get json_array_length json_exists json_extract json_extract_scalar json_format json_object json_parse json_query json_size json_value keep key keys kurtosis lag last last_day_of_month last_value lateral lead leading learn_classifier learn_libsvm_classifier learn_libsvm_regressor learn_regressor least left length level levenshtein_distance like limit line_interpolate_point line_interpolate_points line_locate_point listagg ln local localtime localtimestamp log log10 log2 logical lower lpad ltrim luhn_check make_set_digest map_agg map_concat map_entries map_filter map_from_entries map_keys map_union map_values map_zip_with match match_recognize matched matches materialized max max_by md5 measures merge merge_set_digest millisecond min min_by minute mod month multimap_agg multimap_from_entries murmur3 nan natural next nfc nfd nfkc nfkd ngrams no none none_match normal_cdf normalize not now nth_value ntile null nullif nulls numeric_histogram object objectid_timestamp of offset omit on one only option or order ordinality outer output over overflow parse_data_size parse_datetime parse_duration partition partitions passing past path pattern per percent_rank permute pi position pow power preceding prepare privileges properties prune qdigest_agg quarter quotes radians rand random range rank read recursive reduce reduce_agg refresh regexp_count regexp_extract regexp_extract_all regexp_like regexp_position regexp_replace regexp_split regr_intercept regr_slope regress rename render repeat repeatable replace reset respect restrict returning reverse revoke rgb right role roles rollback rollup round row_number rows rpad rtrim running scalar schema schemas second security seek select sequence serializable session set sets sha1 sha256 sha512 show shuffle sign simplify_geometry sin skewness skip slice some soundex spatial_partitioning spatial_partitions split split_part split_to_map split_to_multimap spooky_hash_v2_32 spooky_hash_v2_64 sqrt st_area st_asbinary st_astext st_boundary st_buffer st_centroid st_contains st_convexhull st_coorddim st_crosses st_difference st_dimension st_disjoint st_distance st_endpoint st_envelope st_envelopeaspts st_equals st_exteriorring st_geometries st_geometryfromtext st_geometryn st_geometrytype st_geomfrombinary st_interiorringn st_interiorrings st_intersection st_intersects st_isclosed stLine truncated
|
||||
// https://github.com/trinodb/trino/blob/bc7a4eeedde28684c7ae6f74cefcaf7c6e782174/core/trino-main/src/main/java/io/trino/metadata/TypeRegistry.java#L131-L168
|
||||
// https://github.com/trinodb/trino/blob/bc7a4eeedde28684c7ae6f74cefcaf7c6e782174/plugin/trino-ml/src/main/java/io/trino/plugin/ml/MLPlugin.java#L35
|
||||
// https://github.com/trinodb/trino/blob/bc7a4eeedde28684c7ae6f74cefcaf7c6e782174/plugin/trino-mongodb/src/main/java/io/trino/plugin/mongodb/MongoPlugin.java#L32
|
||||
// https://github.com/trinodb/trino/blob/bc7a4eeedde28684c7ae6f74cefcaf7c6e782174/plugin/trino-geospatial/src/main/java/io/trino/plugin/geospatial/GeoPlugin.java#L37
|
||||
builtin: set("array bigint bingtile boolean char codepoints color date decimal double function geometry hyperloglog int integer interval ipaddress joniregexp json json2016 jsonpath kdbtree likepattern map model objectid p4hyperloglog precision qdigest re2jregexp real regressor row setdigest smallint sphericalgeography tdigest time timestamp tinyint uuid varbinary varchar zone"),
|
||||
atoms: set("false true null unknown"),
|
||||
// https://trino.io/docs/current/functions/list.html#id1
|
||||
operatorChars: /^[[\]|<>=!\-+*/%]/,
|
||||
dateSQL: set("date time timestamp zone"),
|
||||
// hexNumber is necessary for VARBINARY literals, e.g. X'65683F'
|
||||
// but it also enables 0xFF hex numbers, which Trino doesn't support.
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat hexNumber")
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
How Properties of Mime Types are used by SQL Mode
|
||||
=================================================
|
||||
|
||||
keywords:
|
||||
A list of keywords you want to be highlighted.
|
||||
builtin:
|
||||
A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword").
|
||||
operatorChars:
|
||||
All characters that must be handled as operators.
|
||||
client:
|
||||
Commands parsed and executed by the client (not the server).
|
||||
support:
|
||||
A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.
|
||||
* ODBCdotTable: .tableName
|
||||
* zerolessFloat: .1
|
||||
* decimallessFloat: 1.
|
||||
* hexNumber: X'01AF' X'01af' x'01AF' x'01af' 0x01AF 0x01af
|
||||
* binaryNumber: b'01' B'01' 0b01
|
||||
* doubleQuote: "string"
|
||||
* escapeConstant: E''
|
||||
* nCharCast: N'string'
|
||||
* charsetCast: _utf8'string'
|
||||
* commentHash: use # char for comments
|
||||
* commentSlashSlash: use // for comments
|
||||
* commentSpaceRequired: require a space after -- for comments
|
||||
atoms:
|
||||
Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:
|
||||
UNKNOWN, INFINITY, UNDERFLOW, NaN...
|
||||
dateSQL:
|
||||
Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.
|
||||
*/
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var htmlConfig = {
|
||||
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
|
||||
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
|
||||
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
|
||||
'track': true, 'wbr': true, 'menuitem': true},
|
||||
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
|
||||
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
|
||||
'th': true, 'tr': true},
|
||||
contextGrabbers: {
|
||||
'dd': {'dd': true, 'dt': true},
|
||||
'dt': {'dd': true, 'dt': true},
|
||||
'li': {'li': true},
|
||||
'option': {'option': true, 'optgroup': true},
|
||||
'optgroup': {'optgroup': true},
|
||||
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
|
||||
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
|
||||
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
|
||||
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
|
||||
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
|
||||
'rp': {'rp': true, 'rt': true},
|
||||
'rt': {'rp': true, 'rt': true},
|
||||
'tbody': {'tbody': true, 'tfoot': true},
|
||||
'td': {'td': true, 'th': true},
|
||||
'tfoot': {'tbody': true},
|
||||
'th': {'td': true, 'th': true},
|
||||
'thead': {'tbody': true, 'tfoot': true},
|
||||
'tr': {'tr': true}
|
||||
},
|
||||
doNotIndent: {"pre": true},
|
||||
allowUnquoted: true,
|
||||
allowMissing: true,
|
||||
caseFold: true
|
||||
}
|
||||
|
||||
var xmlConfig = {
|
||||
autoSelfClosers: {},
|
||||
implicitlyClosed: {},
|
||||
contextGrabbers: {},
|
||||
doNotIndent: {},
|
||||
allowUnquoted: false,
|
||||
allowMissing: false,
|
||||
allowMissingTagName: false,
|
||||
caseFold: false
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("xml", function(editorConf, config_) {
|
||||
var indentUnit = editorConf.indentUnit
|
||||
var config = {}
|
||||
var defaults = config_.htmlMode ? htmlConfig : xmlConfig
|
||||
for (var prop in defaults) config[prop] = defaults[prop]
|
||||
for (var prop in config_) config[prop] = config_[prop]
|
||||
|
||||
// Return variables for tokenizers
|
||||
var type, setStyle;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
state.tokenize = parser;
|
||||
return parser(stream, state);
|
||||
}
|
||||
|
||||
var ch = stream.next();
|
||||
if (ch == "<") {
|
||||
if (stream.eat("!")) {
|
||||
if (stream.eat("[")) {
|
||||
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
|
||||
else return null;
|
||||
} else if (stream.match("--")) {
|
||||
return chain(inBlock("comment", "-->"));
|
||||
} else if (stream.match("DOCTYPE", true, true)) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
return chain(doctype(1));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (stream.eat("?")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
state.tokenize = inBlock("meta", "?>");
|
||||
return "meta";
|
||||
} else {
|
||||
type = stream.eat("/") ? "closeTag" : "openTag";
|
||||
state.tokenize = inTag;
|
||||
return "tag bracket";
|
||||
}
|
||||
} else if (ch == "&") {
|
||||
var ok;
|
||||
if (stream.eat("#")) {
|
||||
if (stream.eat("x")) {
|
||||
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
|
||||
}
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
|
||||
}
|
||||
return ok ? "atom" : "error";
|
||||
} else {
|
||||
stream.eatWhile(/[^&<]/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
inText.isInText = true;
|
||||
|
||||
function inTag(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
|
||||
state.tokenize = inText;
|
||||
type = ch == ">" ? "endTag" : "selfcloseTag";
|
||||
return "tag bracket";
|
||||
} else if (ch == "=") {
|
||||
type = "equals";
|
||||
return null;
|
||||
} else if (ch == "<") {
|
||||
state.tokenize = inText;
|
||||
state.state = baseState;
|
||||
state.tagName = state.tagStart = null;
|
||||
var next = state.tokenize(stream, state);
|
||||
return next ? next + " tag error" : "tag error";
|
||||
} else if (/[\'\"]/.test(ch)) {
|
||||
state.tokenize = inAttribute(ch);
|
||||
state.stringStartCol = stream.column();
|
||||
return state.tokenize(stream, state);
|
||||
} else {
|
||||
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
|
||||
return "word";
|
||||
}
|
||||
}
|
||||
|
||||
function inAttribute(quote) {
|
||||
var closure = function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.next() == quote) {
|
||||
state.tokenize = inTag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
closure.isInAttribute = true;
|
||||
return closure;
|
||||
}
|
||||
|
||||
function inBlock(style, terminator) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.match(terminator)) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
return style;
|
||||
}
|
||||
}
|
||||
|
||||
function doctype(depth) {
|
||||
return function(stream, state) {
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "<") {
|
||||
state.tokenize = doctype(depth + 1);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ">") {
|
||||
if (depth == 1) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
} else {
|
||||
state.tokenize = doctype(depth - 1);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "meta";
|
||||
};
|
||||
}
|
||||
|
||||
function lower(tagName) {
|
||||
return tagName && tagName.toLowerCase();
|
||||
}
|
||||
|
||||
function Context(state, tagName, startOfLine) {
|
||||
this.prev = state.context;
|
||||
this.tagName = tagName || "";
|
||||
this.indent = state.indented;
|
||||
this.startOfLine = startOfLine;
|
||||
if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
|
||||
this.noIndent = true;
|
||||
}
|
||||
function popContext(state) {
|
||||
if (state.context) state.context = state.context.prev;
|
||||
}
|
||||
function maybePopContext(state, nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!state.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = state.context.tagName;
|
||||
if (!config.contextGrabbers.hasOwnProperty(lower(parentTagName)) ||
|
||||
!config.contextGrabbers[lower(parentTagName)].hasOwnProperty(lower(nextTagName))) {
|
||||
return;
|
||||
}
|
||||
popContext(state);
|
||||
}
|
||||
}
|
||||
|
||||
function baseState(type, stream, state) {
|
||||
if (type == "openTag") {
|
||||
state.tagStart = stream.column();
|
||||
return tagNameState;
|
||||
} else if (type == "closeTag") {
|
||||
return closeTagNameState;
|
||||
} else {
|
||||
return baseState;
|
||||
}
|
||||
}
|
||||
function tagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
state.tagName = stream.current();
|
||||
setStyle = "tag";
|
||||
return attrState;
|
||||
} else if (config.allowMissingTagName && type == "endTag") {
|
||||
setStyle = "tag bracket";
|
||||
return attrState(type, stream, state);
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return tagNameState;
|
||||
}
|
||||
}
|
||||
function closeTagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
var tagName = stream.current();
|
||||
if (state.context && state.context.tagName != tagName &&
|
||||
config.implicitlyClosed.hasOwnProperty(lower(state.context.tagName)))
|
||||
popContext(state);
|
||||
if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
|
||||
setStyle = "tag";
|
||||
return closeState;
|
||||
} else {
|
||||
setStyle = "tag error";
|
||||
return closeStateErr;
|
||||
}
|
||||
} else if (config.allowMissingTagName && type == "endTag") {
|
||||
setStyle = "tag bracket";
|
||||
return closeState(type, stream, state);
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return closeStateErr;
|
||||
}
|
||||
}
|
||||
|
||||
function closeState(type, _stream, state) {
|
||||
if (type != "endTag") {
|
||||
setStyle = "error";
|
||||
return closeState;
|
||||
}
|
||||
popContext(state);
|
||||
return baseState;
|
||||
}
|
||||
function closeStateErr(type, stream, state) {
|
||||
setStyle = "error";
|
||||
return closeState(type, stream, state);
|
||||
}
|
||||
|
||||
function attrState(type, _stream, state) {
|
||||
if (type == "word") {
|
||||
setStyle = "attribute";
|
||||
return attrEqState;
|
||||
} else if (type == "endTag" || type == "selfcloseTag") {
|
||||
var tagName = state.tagName, tagStart = state.tagStart;
|
||||
state.tagName = state.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
config.autoSelfClosers.hasOwnProperty(lower(tagName))) {
|
||||
maybePopContext(state, tagName);
|
||||
} else {
|
||||
maybePopContext(state, tagName);
|
||||
state.context = new Context(state, tagName, tagStart == state.indented);
|
||||
}
|
||||
return baseState;
|
||||
}
|
||||
setStyle = "error";
|
||||
return attrState;
|
||||
}
|
||||
function attrEqState(type, stream, state) {
|
||||
if (type == "equals") return attrValueState;
|
||||
if (!config.allowMissing) setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrValueState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
|
||||
setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrContinuedState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function(baseIndent) {
|
||||
var state = {tokenize: inText,
|
||||
state: baseState,
|
||||
indented: baseIndent || 0,
|
||||
tagName: null, tagStart: null,
|
||||
context: null}
|
||||
if (baseIndent != null) state.baseIndent = baseIndent
|
||||
return state
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tagName && stream.sol())
|
||||
state.indented = stream.indentation();
|
||||
|
||||
if (stream.eatSpace()) return null;
|
||||
type = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if ((style || type) && style != "comment") {
|
||||
setStyle = null;
|
||||
state.state = state.state(type || style, stream, state);
|
||||
if (setStyle)
|
||||
style = setStyle == "error" ? style + " error" : setStyle;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
var context = state.context;
|
||||
// Indent multi-line strings (e.g. css).
|
||||
if (state.tokenize.isInAttribute) {
|
||||
if (state.tagStart == state.indented)
|
||||
return state.stringStartCol + 1;
|
||||
else
|
||||
return state.indented + indentUnit;
|
||||
}
|
||||
if (context && context.noIndent) return CodeMirror.Pass;
|
||||
if (state.tokenize != inTag && state.tokenize != inText)
|
||||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
|
||||
// Indent the starts of attribute names.
|
||||
if (state.tagName) {
|
||||
if (config.multilineTagIndentPastTag !== false)
|
||||
return state.tagStart + state.tagName.length + 2;
|
||||
else
|
||||
return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
|
||||
}
|
||||
if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
|
||||
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
|
||||
if (tagAfter && tagAfter[1]) { // Closing tag spotted
|
||||
while (context) {
|
||||
if (context.tagName == tagAfter[2]) {
|
||||
context = context.prev;
|
||||
break;
|
||||
} else if (config.implicitlyClosed.hasOwnProperty(lower(context.tagName))) {
|
||||
context = context.prev;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagAfter) { // Opening tag spotted
|
||||
while (context) {
|
||||
var grabbers = config.contextGrabbers[lower(context.tagName)];
|
||||
if (grabbers && grabbers.hasOwnProperty(lower(tagAfter[2])))
|
||||
context = context.prev;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (context && context.prev && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return state.baseIndent || 0;
|
||||
},
|
||||
|
||||
electricInput: /<\/[\s\w:]+>$/,
|
||||
blockCommentStart: "<!--",
|
||||
blockCommentEnd: "-->",
|
||||
|
||||
configuration: config.htmlMode ? "html" : "xml",
|
||||
helperType: config.htmlMode ? "html" : "xml",
|
||||
|
||||
skipAttribute: function(state) {
|
||||
if (state.state == attrValueState)
|
||||
state.state = attrState
|
||||
},
|
||||
|
||||
xmlCurrentTag: function(state) {
|
||||
return state.tagName ? {name: state.tagName, close: state.type == "closeTag"} : null
|
||||
},
|
||||
|
||||
xmlCurrentContext: function(state) {
|
||||
var context = []
|
||||
for (var cx = state.context; cx; cx = cx.prev)
|
||||
context.push(cx.tagName)
|
||||
return context.reverse()
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/xml", "xml");
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
||||
|
||||
});
|
||||
+11519
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,801 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
// Class: $.jqplot.BarRenderer
|
||||
// A plugin renderer for jqPlot to draw a bar plot.
|
||||
// Draws series as a line.
|
||||
|
||||
$.jqplot.BarRenderer = function(){
|
||||
$.jqplot.LineRenderer.call(this);
|
||||
};
|
||||
|
||||
$.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
|
||||
$.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
|
||||
|
||||
// called with scope of series.
|
||||
$.jqplot.BarRenderer.prototype.init = function(options, plot) {
|
||||
// Group: Properties
|
||||
//
|
||||
// prop: barPadding
|
||||
// Number of pixels between adjacent bars at the same axis value.
|
||||
this.barPadding = 8;
|
||||
// prop: barMargin
|
||||
// Number of pixels between groups of bars at adjacent axis values.
|
||||
this.barMargin = 10;
|
||||
// prop: barDirection
|
||||
// 'vertical' = up and down bars, 'horizontal' = side to side bars
|
||||
this.barDirection = 'vertical';
|
||||
// prop: barWidth
|
||||
// Width of the bar in pixels (auto by devaul). null = calculated automatically.
|
||||
this.barWidth = null;
|
||||
// prop: shadowOffset
|
||||
// offset of the shadow from the slice and offset of
|
||||
// each succesive stroke of the shadow from the last.
|
||||
this.shadowOffset = 2;
|
||||
// prop: shadowDepth
|
||||
// number of strokes to apply to the shadow,
|
||||
// each stroke offset shadowOffset from the last.
|
||||
this.shadowDepth = 5;
|
||||
// prop: shadowAlpha
|
||||
// transparency of the shadow (0 = transparent, 1 = opaque)
|
||||
this.shadowAlpha = 0.08;
|
||||
// prop: waterfall
|
||||
// true to enable waterfall plot.
|
||||
this.waterfall = false;
|
||||
// prop: groups
|
||||
// group bars into this many groups
|
||||
this.groups = 1;
|
||||
// prop: varyBarColor
|
||||
// true to color each bar of a series separately rather than
|
||||
// have every bar of a given series the same color.
|
||||
// If used for non-stacked multiple series bar plots, user should
|
||||
// specify a separate 'seriesColors' array for each series.
|
||||
// Otherwise, each series will set their bars to the same color array.
|
||||
// This option has no Effect for stacked bar charts and is disabled.
|
||||
this.varyBarColor = false;
|
||||
// prop: highlightMouseOver
|
||||
// True to highlight slice when moused over.
|
||||
// This must be false to enable highlightMouseDown to highlight when clicking on a slice.
|
||||
this.highlightMouseOver = true;
|
||||
// prop: highlightMouseDown
|
||||
// True to highlight when a mouse button is pressed over a slice.
|
||||
// This will be disabled if highlightMouseOver is true.
|
||||
this.highlightMouseDown = false;
|
||||
// prop: highlightColors
|
||||
// an array of colors to use when highlighting a bar.
|
||||
this.highlightColors = [];
|
||||
// prop: transposedData
|
||||
// NOT IMPLEMENTED YET. True if this is a horizontal bar plot and
|
||||
// x and y values are "transposed". Tranposed, or "swapped", data is
|
||||
// required prior to rev. 894 builds of jqPlot with horizontal bars.
|
||||
// Allows backward compatability of bar renderer horizontal bars with
|
||||
// old style data sets.
|
||||
this.transposedData = true;
|
||||
this.renderer.animation = {
|
||||
show: false,
|
||||
direction: 'down',
|
||||
speed: 3000,
|
||||
_supported: true
|
||||
};
|
||||
this._type = 'bar';
|
||||
|
||||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
|
||||
if (options.highlightMouseDown && options.highlightMouseOver == null) {
|
||||
options.highlightMouseOver = false;
|
||||
}
|
||||
|
||||
//////
|
||||
// This is probably wrong here.
|
||||
// After going back and forth on whether renderer should be the thing
|
||||
// or extend the thing, it seems that it it best if it is a property
|
||||
// on the thing. This should be something that is commonized
|
||||
// among series renderers in the future.
|
||||
//////
|
||||
$.extend(true, this, options);
|
||||
|
||||
// really should probably do this
|
||||
$.extend(true, this.renderer, options);
|
||||
// fill is still needed to properly draw the legend.
|
||||
// bars have to be filled.
|
||||
this.fill = true;
|
||||
|
||||
// if horizontal bar and animating, reset the default direction
|
||||
if (this.barDirection === 'horizontal' && this.rendererOptions.animation && this.rendererOptions.animation.direction == null) {
|
||||
this.renderer.animation.direction = 'left';
|
||||
}
|
||||
|
||||
if (this.waterfall) {
|
||||
this.fillToZero = false;
|
||||
this.disableStack = true;
|
||||
}
|
||||
|
||||
if (this.barDirection == 'vertical' ) {
|
||||
this._primaryAxis = '_xaxis';
|
||||
this._stackAxis = 'y';
|
||||
this.fillAxis = 'y';
|
||||
}
|
||||
else {
|
||||
this._primaryAxis = '_yaxis';
|
||||
this._stackAxis = 'x';
|
||||
this.fillAxis = 'x';
|
||||
}
|
||||
// index of the currenty highlighted point, if any
|
||||
this._highlightedPoint = null;
|
||||
// total number of values for all bar series, total number of bar series, and position of this series
|
||||
this._plotSeriesInfo = null;
|
||||
// Array of actual data colors used for each data point.
|
||||
this._dataColors = [];
|
||||
this._barPoints = [];
|
||||
|
||||
// set the shape renderer options
|
||||
var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
|
||||
this.renderer.shapeRenderer.init(opts);
|
||||
// set the shadow renderer options
|
||||
var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
|
||||
this.renderer.shadowRenderer.init(sopts);
|
||||
|
||||
plot.postInitHooks.addOnce(postInit);
|
||||
plot.postDrawHooks.addOnce(postPlotDraw);
|
||||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
|
||||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
|
||||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
|
||||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
|
||||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
|
||||
};
|
||||
|
||||
// called with scope of series
|
||||
function barPreInit(target, data, seriesDefaults, options) {
|
||||
if (this.rendererOptions.barDirection == 'horizontal') {
|
||||
this._stackAxis = 'x';
|
||||
this._primaryAxis = '_yaxis';
|
||||
}
|
||||
if (this.rendererOptions.waterfall == true) {
|
||||
this._data = $.extend(true, [], this.data);
|
||||
var sum = 0;
|
||||
var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection === 'vertical' || this.transposedData === false) ? 1 : 0;
|
||||
for(var i=0; i<this.data.length; i++) {
|
||||
sum += this.data[i][pos];
|
||||
if (i>0) {
|
||||
this.data[i][pos] += this.data[i-1][pos];
|
||||
}
|
||||
}
|
||||
this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1];
|
||||
this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1];
|
||||
}
|
||||
if (this.rendererOptions.groups > 1) {
|
||||
this.breakOnNull = true;
|
||||
var l = this.data.length;
|
||||
var skip = parseInt(l/this.rendererOptions.groups, 10);
|
||||
var count = 0;
|
||||
for (var i=skip; i<l; i+=skip) {
|
||||
this.data.splice(i+count, 0, [null, null]);
|
||||
this._plotData.splice(i+count, 0, [null, null]);
|
||||
this._stackData.splice(i+count, 0, [null, null]);
|
||||
count++;
|
||||
}
|
||||
for (i=0; i<this.data.length; i++) {
|
||||
if (this._primaryAxis == '_xaxis') {
|
||||
this.data[i][0] = i+1;
|
||||
this._plotData[i][0] = i+1;
|
||||
this._stackData[i][0] = i+1;
|
||||
}
|
||||
else {
|
||||
this.data[i][1] = i+1;
|
||||
this._plotData[i][1] = i+1;
|
||||
this._stackData[i][1] = i+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$.jqplot.preSeriesInitHooks.push(barPreInit);
|
||||
|
||||
// needs to be called with scope of series, not renderer.
|
||||
$.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
|
||||
var nvals = 0;
|
||||
var nseries = 0;
|
||||
var paxis = this[this._primaryAxis];
|
||||
var s, series, pos;
|
||||
// loop through all series on this axis
|
||||
for (var i=0; i < paxis._series.length; i++) {
|
||||
series = paxis._series[i];
|
||||
if (series === this) {
|
||||
pos = i;
|
||||
}
|
||||
// is the series rendered as a bar?
|
||||
if (series.renderer.constructor == $.jqplot.BarRenderer) {
|
||||
// gridData may not be computed yet, use data length insted
|
||||
nvals += series.data.length;
|
||||
nseries += 1;
|
||||
}
|
||||
}
|
||||
// return total number of values for all bar series, total number of bar series, and position of this series
|
||||
return [nvals, nseries, pos];
|
||||
};
|
||||
|
||||
$.jqplot.BarRenderer.prototype.setBarWidth = function() {
|
||||
// need to know how many data values we have on the approprate axis and figure it out.
|
||||
var i;
|
||||
var nvals = 0;
|
||||
var nseries = 0;
|
||||
var paxis = this[this._primaryAxis];
|
||||
var s, series, pos;
|
||||
var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
|
||||
nvals = temp[0];
|
||||
nseries = temp[1];
|
||||
var nticks = paxis.numberTicks;
|
||||
var nbins = (nticks-1)/2;
|
||||
// so, now we have total number of axis values.
|
||||
if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
|
||||
if (this._stack) {
|
||||
this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
|
||||
}
|
||||
else {
|
||||
this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
|
||||
// this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this._stack) {
|
||||
this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
|
||||
}
|
||||
else {
|
||||
this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
|
||||
// this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
|
||||
}
|
||||
}
|
||||
return [nvals, nseries];
|
||||
};
|
||||
|
||||
function computeHighlightColors (colors) {
|
||||
var ret = [];
|
||||
for (var i=0; i<colors.length; i++){
|
||||
var rgba = $.jqplot.getColorComponents(colors[i]);
|
||||
var newrgb = [rgba[0], rgba[1], rgba[2]];
|
||||
var sum = newrgb[0] + newrgb[1] + newrgb[2];
|
||||
for (var j=0; j<3; j++) {
|
||||
// when darkening, lowest color component can be is 60.
|
||||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
|
||||
newrgb[j] = parseInt(newrgb[j], 10);
|
||||
}
|
||||
ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getStart(sidx, didx, comp, plot, axis) {
|
||||
// check if sign change
|
||||
var seriesIndex = sidx,
|
||||
prevSeriesIndex = sidx - 1,
|
||||
start,
|
||||
prevVal,
|
||||
aidx = (axis === 'x') ? 0 : 1;
|
||||
|
||||
// is this not the first series?
|
||||
if (seriesIndex > 0) {
|
||||
prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx];
|
||||
|
||||
// is there a sign change
|
||||
if ((comp * prevVal) < 0) {
|
||||
start = getStart(prevSeriesIndex, didx, comp, plot, axis);
|
||||
}
|
||||
|
||||
// no sign change.
|
||||
else {
|
||||
start = plot.series[prevSeriesIndex].gridData[didx][aidx];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if first series, return value at 0
|
||||
else {
|
||||
|
||||
start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0);
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
$.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) {
|
||||
var i;
|
||||
// Ughhh, have to make a copy of options b/c it may be modified later.
|
||||
var opts = $.extend({}, options);
|
||||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
|
||||
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
|
||||
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
|
||||
var xaxis = this.xaxis;
|
||||
var yaxis = this.yaxis;
|
||||
var xp = this._xaxis.series_u2p;
|
||||
var yp = this._yaxis.series_u2p;
|
||||
var pointx, pointy;
|
||||
// clear out data colors.
|
||||
this._dataColors = [];
|
||||
this._barPoints = [];
|
||||
|
||||
if (this.barWidth == null || this.rendererOptions.barWidth == null) {//check pull request https://bitbucket.org/cleonello/jqplot/pull-request/61/fix-for-issue-513/diff
|
||||
this.renderer.setBarWidth.call(this);
|
||||
}
|
||||
|
||||
var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
|
||||
var nvals = temp[0];
|
||||
var nseries = temp[1];
|
||||
var pos = temp[2];
|
||||
var points = [];
|
||||
|
||||
if (this._stack) {
|
||||
this._barNudge = 0;
|
||||
}
|
||||
else {
|
||||
this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
|
||||
}
|
||||
if (showLine) {
|
||||
var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
|
||||
var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
|
||||
var negativeColor = negativeColors.get(this.index);
|
||||
if (! this.useNegativeColors) {
|
||||
negativeColor = opts.fillStyle;
|
||||
}
|
||||
var positiveColor = opts.fillStyle;
|
||||
var base;
|
||||
var xstart;
|
||||
var ystart;
|
||||
|
||||
if (this.barDirection == 'vertical') {
|
||||
for (var i=0; i<gridData.length; i++) {
|
||||
if (!this._stack && this.data[i][1] == null) {
|
||||
continue;
|
||||
}
|
||||
points = [];
|
||||
base = gridData[i][0] + this._barNudge;
|
||||
|
||||
// stacked
|
||||
if (this._stack && this._prevGridData.length) {
|
||||
ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
|
||||
}
|
||||
|
||||
// not stacked
|
||||
else {
|
||||
if (this.fillToZero) {
|
||||
ystart = this._yaxis.series_u2p(0);
|
||||
}
|
||||
else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
|
||||
ystart = this.gridData[i-1][1];
|
||||
}
|
||||
else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
|
||||
if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
|
||||
ystart = this._yaxis.series_u2p(0);
|
||||
}
|
||||
else if (this._yaxis.min > 0) {
|
||||
ystart = ctx.canvas.height;
|
||||
}
|
||||
else {
|
||||
ystart = 0;
|
||||
}
|
||||
}
|
||||
else if (this.waterfall && i == this.gridData.length - 1) {
|
||||
if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
|
||||
ystart = this._yaxis.series_u2p(0);
|
||||
}
|
||||
else if (this._yaxis.min > 0) {
|
||||
ystart = ctx.canvas.height;
|
||||
}
|
||||
else {
|
||||
ystart = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ystart = ctx.canvas.height;
|
||||
}
|
||||
}
|
||||
if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
|
||||
if (this.varyBarColor && !this._stack) {
|
||||
if (this.useNegativeColors) {
|
||||
opts.fillStyle = negativeColors.next();
|
||||
}
|
||||
else {
|
||||
opts.fillStyle = positiveColors.next();
|
||||
}
|
||||
}
|
||||
else {
|
||||
opts.fillStyle = negativeColor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.varyBarColor && !this._stack) {
|
||||
opts.fillStyle = positiveColors.next();
|
||||
}
|
||||
else {
|
||||
opts.fillStyle = positiveColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.fillToZero || this._plotData[i][1] >= 0) {
|
||||
points.push([base-this.barWidth/2, ystart]);
|
||||
points.push([base-this.barWidth/2, gridData[i][1]]);
|
||||
points.push([base+this.barWidth/2, gridData[i][1]]);
|
||||
points.push([base+this.barWidth/2, ystart]);
|
||||
}
|
||||
// for negative bars make sure points are always ordered clockwise
|
||||
else {
|
||||
points.push([base-this.barWidth/2, gridData[i][1]]);
|
||||
points.push([base-this.barWidth/2, ystart]);
|
||||
points.push([base+this.barWidth/2, ystart]);
|
||||
points.push([base+this.barWidth/2, gridData[i][1]]);
|
||||
}
|
||||
this._barPoints.push(points);
|
||||
// now draw the shadows if not stacked.
|
||||
// for stacked plots, they are predrawn by drawShadow
|
||||
if (shadow && !this._stack) {
|
||||
var sopts = $.extend(true, {}, opts);
|
||||
// need to get rid of fillStyle on shadow.
|
||||
delete sopts.fillStyle;
|
||||
this.renderer.shadowRenderer.draw(ctx, points, sopts);
|
||||
}
|
||||
var clr = opts.fillStyle || this.color;
|
||||
this._dataColors.push(clr);
|
||||
this.renderer.shapeRenderer.draw(ctx, points, opts);
|
||||
}
|
||||
}
|
||||
|
||||
else if (this.barDirection == 'horizontal'){
|
||||
for (var i=0; i<gridData.length; i++) {
|
||||
if (!this._stack && this.data[i][0] == null) {
|
||||
continue;
|
||||
}
|
||||
points = [];
|
||||
base = gridData[i][1] - this._barNudge;
|
||||
xstart;
|
||||
|
||||
if (this._stack && this._prevGridData.length) {
|
||||
xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
|
||||
}
|
||||
// not stacked
|
||||
else {
|
||||
if (this.fillToZero) {
|
||||
xstart = this._xaxis.series_u2p(0);
|
||||
}
|
||||
else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
|
||||
xstart = this.gridData[i-1][0];
|
||||
}
|
||||
else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
|
||||
if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
|
||||
xstart = this._xaxis.series_u2p(0);
|
||||
}
|
||||
else if (this._xaxis.min > 0) {
|
||||
xstart = 0;
|
||||
}
|
||||
else {
|
||||
xstart = 0;
|
||||
}
|
||||
}
|
||||
else if (this.waterfall && i == this.gridData.length - 1) {
|
||||
if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
|
||||
xstart = this._xaxis.series_u2p(0);
|
||||
}
|
||||
else if (this._xaxis.min > 0) {
|
||||
xstart = 0;
|
||||
}
|
||||
else {
|
||||
xstart = ctx.canvas.width;
|
||||
}
|
||||
}
|
||||
else {
|
||||
xstart = 0;
|
||||
}
|
||||
}
|
||||
if ((this.fillToZero && this._plotData[i][0] < 0) || (this.waterfall && this._data[i][0] < 0)) {
|
||||
if (this.varyBarColor && !this._stack) {
|
||||
if (this.useNegativeColors) {
|
||||
opts.fillStyle = negativeColors.next();
|
||||
}
|
||||
else {
|
||||
opts.fillStyle = positiveColors.next();
|
||||
}
|
||||
}
|
||||
else {
|
||||
opts.fillStyle = negativeColor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.varyBarColor && !this._stack) {
|
||||
opts.fillStyle = positiveColors.next();
|
||||
}
|
||||
else {
|
||||
opts.fillStyle = positiveColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!this.fillToZero || this._plotData[i][0] >= 0) {
|
||||
points.push([xstart, base + this.barWidth / 2]);
|
||||
points.push([xstart, base - this.barWidth / 2]);
|
||||
points.push([gridData[i][0], base - this.barWidth / 2]);
|
||||
points.push([gridData[i][0], base + this.barWidth / 2]);
|
||||
}
|
||||
else {
|
||||
points.push([gridData[i][0], base + this.barWidth / 2]);
|
||||
points.push([gridData[i][0], base - this.barWidth / 2]);
|
||||
points.push([xstart, base - this.barWidth / 2]);
|
||||
points.push([xstart, base + this.barWidth / 2]);
|
||||
}
|
||||
|
||||
this._barPoints.push(points);
|
||||
// now draw the shadows if not stacked.
|
||||
// for stacked plots, they are predrawn by drawShadow
|
||||
if (shadow && !this._stack) {
|
||||
var sopts = $.extend(true, {}, opts);
|
||||
delete sopts.fillStyle;
|
||||
this.renderer.shadowRenderer.draw(ctx, points, sopts);
|
||||
}
|
||||
var clr = opts.fillStyle || this.color;
|
||||
this._dataColors.push(clr);
|
||||
this.renderer.shapeRenderer.draw(ctx, points, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.highlightColors.length == 0) {
|
||||
this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors);
|
||||
}
|
||||
|
||||
else if (typeof(this.highlightColors) == 'string') {
|
||||
var temp = this.highlightColors;
|
||||
this.highlightColors = [];
|
||||
for (var i=0; i<this._dataColors.length; i++) {
|
||||
this.highlightColors.push(temp);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// for stacked plots, shadows will be pre drawn by drawShadow.
|
||||
$.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options, plot) {
|
||||
var i;
|
||||
var opts = (options != undefined) ? options : {};
|
||||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
|
||||
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
|
||||
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
|
||||
var xaxis = this.xaxis;
|
||||
var yaxis = this.yaxis;
|
||||
var xp = this._xaxis.series_u2p;
|
||||
var yp = this._yaxis.series_u2p;
|
||||
var pointx, points, pointy, nvals, nseries, pos;
|
||||
|
||||
if (this._stack && this.shadow) {
|
||||
if (this.barWidth == null || this.rendererOptions.barWidth == null) {//check pull request https://bitbucket.org/cleonello/jqplot/pull-request/61/fix-for-issue-513/diff) {
|
||||
this.renderer.setBarWidth.call(this);
|
||||
}
|
||||
|
||||
var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
|
||||
nvals = temp[0];
|
||||
nseries = temp[1];
|
||||
pos = temp[2];
|
||||
|
||||
if (this._stack) {
|
||||
this._barNudge = 0;
|
||||
}
|
||||
else {
|
||||
this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
|
||||
}
|
||||
if (showLine) {
|
||||
|
||||
if (this.barDirection == 'vertical') {
|
||||
for (var i=0; i<gridData.length; i++) {
|
||||
if (this.data[i][1] == null) {
|
||||
continue;
|
||||
}
|
||||
points = [];
|
||||
var base = gridData[i][0] + this._barNudge;
|
||||
var ystart;
|
||||
|
||||
if (this._stack && this._prevGridData.length) {
|
||||
ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
|
||||
}
|
||||
else {
|
||||
if (this.fillToZero) {
|
||||
ystart = this._yaxis.series_u2p(0);
|
||||
}
|
||||
else {
|
||||
ystart = ctx.canvas.height;
|
||||
}
|
||||
}
|
||||
|
||||
points.push([base-this.barWidth/2, ystart]);
|
||||
points.push([base-this.barWidth/2, gridData[i][1]]);
|
||||
points.push([base+this.barWidth/2, gridData[i][1]]);
|
||||
points.push([base+this.barWidth/2, ystart]);
|
||||
this.renderer.shadowRenderer.draw(ctx, points, opts);
|
||||
}
|
||||
}
|
||||
|
||||
else if (this.barDirection == 'horizontal'){
|
||||
for (var i=0; i<gridData.length; i++) {
|
||||
if (this.data[i][0] == null) {
|
||||
continue;
|
||||
}
|
||||
points = [];
|
||||
var base = gridData[i][1] - this._barNudge;
|
||||
var xstart;
|
||||
|
||||
if (this._stack && this._prevGridData.length) {
|
||||
xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
|
||||
}
|
||||
else {
|
||||
if (this.fillToZero) {
|
||||
xstart = this._xaxis.series_u2p(0);
|
||||
}
|
||||
else {
|
||||
xstart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
points.push([xstart, base+this.barWidth/2]);
|
||||
points.push([gridData[i][0], base+this.barWidth/2]);
|
||||
points.push([gridData[i][0], base-this.barWidth/2]);
|
||||
points.push([xstart, base-this.barWidth/2]);
|
||||
this.renderer.shadowRenderer.draw(ctx, points, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function postInit(target, data, options) {
|
||||
for (var i=0; i<this.series.length; i++) {
|
||||
if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) {
|
||||
// don't allow mouseover and mousedown at same time.
|
||||
if (this.series[i].highlightMouseOver) {
|
||||
this.series[i].highlightMouseDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called within context of plot
|
||||
// create a canvas which we can draw on.
|
||||
// insert it before the eventCanvas, so eventCanvas will still capture events.
|
||||
function postPlotDraw() {
|
||||
// Memory Leaks patch
|
||||
if (this.plugins.barRenderer && this.plugins.barRenderer.highlightCanvas) {
|
||||
|
||||
this.plugins.barRenderer.highlightCanvas.resetCanvas();
|
||||
this.plugins.barRenderer.highlightCanvas = null;
|
||||
}
|
||||
|
||||
this.plugins.barRenderer = {highlightedSeriesIndex:null};
|
||||
this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
|
||||
|
||||
this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions, this));
|
||||
this.plugins.barRenderer.highlightCanvas.setContext();
|
||||
this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
|
||||
}
|
||||
|
||||
function highlight (plot, sidx, pidx, points) {
|
||||
var s = plot.series[sidx];
|
||||
var canvas = plot.plugins.barRenderer.highlightCanvas;
|
||||
canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
|
||||
s._highlightedPoint = pidx;
|
||||
plot.plugins.barRenderer.highlightedSeriesIndex = sidx;
|
||||
var opts = {fillStyle: s.highlightColors[pidx]};
|
||||
s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
|
||||
canvas = null;
|
||||
}
|
||||
|
||||
function unhighlight (plot) {
|
||||
var canvas = plot.plugins.barRenderer.highlightCanvas;
|
||||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
|
||||
for (var i=0; i<plot.series.length; i++) {
|
||||
plot.series[i]._highlightedPoint = null;
|
||||
}
|
||||
plot.plugins.barRenderer.highlightedSeriesIndex = null;
|
||||
plot.target.trigger('jqplotDataUnhighlight');
|
||||
canvas = null;
|
||||
}
|
||||
|
||||
|
||||
function handleMove(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
var evt1 = jQuery.Event('jqplotDataMouseOver');
|
||||
evt1.pageX = ev.pageX;
|
||||
evt1.pageY = ev.pageY;
|
||||
plot.target.trigger(evt1, ins);
|
||||
if (plot.series[ins[0]].show && plot.series[ins[0]].highlightMouseOver &&
|
||||
!(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
|
||||
var evt = jQuery.Event('jqplotDataHighlight');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
|
||||
}
|
||||
}
|
||||
else if (neighbor == null) {
|
||||
unhighlight (plot);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
|
||||
var evt = jQuery.Event('jqplotDataHighlight');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
|
||||
}
|
||||
}
|
||||
else if (neighbor == null) {
|
||||
unhighlight (plot);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
|
||||
var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
|
||||
if (idx != null && plot.series[idx].highlightMouseDown) {
|
||||
unhighlight(plot);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
var evt = jQuery.Event('jqplotDataClick');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
}
|
||||
}
|
||||
|
||||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
|
||||
if (idx != null && plot.series[idx].highlightMouseDown) {
|
||||
unhighlight(plot);
|
||||
}
|
||||
var evt = jQuery.Event('jqplotDataRightClick');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* Class: $.jqplot.CanvasAxisLabelRenderer
|
||||
* Renderer to draw axis labels with a canvas element to support advanced
|
||||
* featrues such as rotated text. This renderer uses a separate rendering engine
|
||||
* to draw the text on the canvas. Two modes of rendering the text are available.
|
||||
* If the browser has native font support for canvas fonts (currently Mozila 3.5
|
||||
* and Safari 4), you can enable text rendering with the canvas fillText method.
|
||||
* You do so by setting the "enableFontSupport" option to true.
|
||||
*
|
||||
* Browsers lacking native font support will have the text drawn on the canvas
|
||||
* using the Hershey font metrics. Even if the "enableFontSupport" option is true
|
||||
* non-supporting browsers will still render with the Hershey font.
|
||||
*
|
||||
*/
|
||||
$.jqplot.CanvasAxisLabelRenderer = function(options) {
|
||||
// Group: Properties
|
||||
|
||||
// prop: angle
|
||||
// angle of text, measured clockwise from x axis.
|
||||
this.angle = 0;
|
||||
// name of the axis associated with this tick
|
||||
this.axis;
|
||||
// prop: show
|
||||
// whether or not to show the tick (mark and label).
|
||||
this.show = true;
|
||||
// prop: showLabel
|
||||
// whether or not to show the label.
|
||||
this.showLabel = true;
|
||||
// prop: label
|
||||
// label for the axis.
|
||||
this.label = '';
|
||||
// prop: fontFamily
|
||||
// CSS spec for the font-family css attribute.
|
||||
// Applies only to browsers supporting native font rendering in the
|
||||
// canvas tag. Currently Mozilla 3.5 and Safari 4.
|
||||
this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
|
||||
// prop: fontSize
|
||||
// CSS spec for font size.
|
||||
this.fontSize = '11pt';
|
||||
// prop: fontWeight
|
||||
// CSS spec for fontWeight: normal, bold, bolder, lighter or a number 100 - 900
|
||||
this.fontWeight = 'normal';
|
||||
// prop: fontStretch
|
||||
// Multiplier to condense or expand font width.
|
||||
// Applies only to browsers which don't support canvas native font rendering.
|
||||
this.fontStretch = 1.0;
|
||||
// prop: textColor
|
||||
// css spec for the color attribute.
|
||||
this.textColor = '#666666';
|
||||
// prop: enableFontSupport
|
||||
// true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+.
|
||||
// If true, label will be drawn with canvas tag native support for fonts.
|
||||
// If false, label will be drawn with Hershey font metrics.
|
||||
this.enableFontSupport = true;
|
||||
// prop: pt2px
|
||||
// Point to pixel scaling factor, used for computing height of bounding box
|
||||
// around a label. The labels text renderer has a default setting of 1.4, which
|
||||
// should be suitable for most fonts. Leave as null to use default. If tops of
|
||||
// letters appear clipped, increase this. If bounding box seems too big, decrease.
|
||||
// This is an issue only with the native font renderering capabilities of Mozilla
|
||||
// 3.5 and Safari 4 since they do not provide a method to determine the font height.
|
||||
this.pt2px = null;
|
||||
|
||||
this._elem;
|
||||
this._ctx;
|
||||
this._plotWidth;
|
||||
this._plotHeight;
|
||||
this._plotDimensions = {height:null, width:null};
|
||||
|
||||
$.extend(true, this, options);
|
||||
|
||||
if (options.angle == null && this.axis != 'xaxis' && this.axis != 'x2axis') {
|
||||
this.angle = -90;
|
||||
}
|
||||
|
||||
var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
|
||||
if (this.pt2px) {
|
||||
ropts.pt2px = this.pt2px;
|
||||
}
|
||||
|
||||
if (this.enableFontSupport) {
|
||||
if ($.jqplot.support_canvas_text()) {
|
||||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
|
||||
}
|
||||
|
||||
else {
|
||||
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
|
||||
}
|
||||
};
|
||||
|
||||
$.jqplot.CanvasAxisLabelRenderer.prototype.init = function(options) {
|
||||
$.extend(true, this, options);
|
||||
this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
|
||||
};
|
||||
|
||||
// return width along the x axis
|
||||
// will check first to see if an element exists.
|
||||
// if not, will return the computed text box width.
|
||||
$.jqplot.CanvasAxisLabelRenderer.prototype.getWidth = function(ctx) {
|
||||
if (this._elem) {
|
||||
return this._elem.outerWidth(true);
|
||||
}
|
||||
else {
|
||||
var tr = this._textRenderer;
|
||||
var l = tr.getWidth(ctx);
|
||||
var h = tr.getHeight(ctx);
|
||||
var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
// return height along the y axis.
|
||||
$.jqplot.CanvasAxisLabelRenderer.prototype.getHeight = function(ctx) {
|
||||
if (this._elem) {
|
||||
return this._elem.outerHeight(true);
|
||||
}
|
||||
else {
|
||||
var tr = this._textRenderer;
|
||||
var l = tr.getWidth(ctx);
|
||||
var h = tr.getHeight(ctx);
|
||||
var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
$.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad = function() {
|
||||
var a = this.angle * Math.PI/180;
|
||||
return a;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx, plot) {
|
||||
// Memory Leaks patch
|
||||
if (this._elem) {
|
||||
if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
|
||||
window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
|
||||
}
|
||||
|
||||
this._elem.emptyForce();
|
||||
this._elem = null;
|
||||
}
|
||||
|
||||
// create a canvas here, but can't draw on it untill it is appended
|
||||
// to dom for IE compatability.
|
||||
var elem = plot.canvasManager.getCanvas();
|
||||
|
||||
this._textRenderer.setText(this.label, ctx);
|
||||
var w = this.getWidth(ctx);
|
||||
var h = this.getHeight(ctx);
|
||||
elem.width = w;
|
||||
elem.height = h;
|
||||
elem.style.width = w;
|
||||
elem.style.height = h;
|
||||
|
||||
elem = plot.canvasManager.initCanvas(elem);
|
||||
|
||||
this._elem = $(elem);
|
||||
this._elem.css({ position: 'absolute'});
|
||||
this._elem.addClass('jqplot-'+this.axis+'-label');
|
||||
|
||||
elem = null;
|
||||
return this._elem;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasAxisLabelRenderer.prototype.pack = function() {
|
||||
this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label);
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,449 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
* included jsDate library by Chris Leonello:
|
||||
*
|
||||
* Copyright (c) 2010-2015 Chris Leonello
|
||||
*
|
||||
* jsDate is currently available for use in all personal or commercial projects
|
||||
* under both the MIT and GPL version 2.0 licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* jsDate borrows many concepts and ideas from the Date Instance
|
||||
* Methods by Ken Snyder along with some parts of Ken's actual code.
|
||||
*
|
||||
* Ken's original Date Instance Methods and copyright notice:
|
||||
*
|
||||
* Ken Snyder (ken d snyder at gmail dot com)
|
||||
* 2008-09-10
|
||||
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
|
||||
* Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
||||
*
|
||||
* jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
|
||||
* Larry has generously given permission to adapt his code for inclusion
|
||||
* into jqPlot.
|
||||
*
|
||||
* Larry's original code can be found here:
|
||||
*
|
||||
* https://github.com/lsiden/export-jqplot-to-png
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
// This code is a modified version of the canvastext.js code, copyright below:
|
||||
//
|
||||
// This code is released to the public domain by Jim Studt, 2007.
|
||||
// He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
|
||||
//
|
||||
$.jqplot.CanvasTextRenderer = function(options){
|
||||
this.fontStyle = 'normal'; // normal, italic, oblique [not implemented]
|
||||
this.fontVariant = 'normal'; // normal, small caps [not implemented]
|
||||
this.fontWeight = 'normal'; // normal, bold, bolder, lighter, 100 - 900
|
||||
this.fontSize = '10px';
|
||||
this.fontFamily = 'sans-serif';
|
||||
this.fontStretch = 1.0;
|
||||
this.fillStyle = '#666666';
|
||||
this.angle = 0;
|
||||
this.textAlign = 'start';
|
||||
this.textBaseline = 'alphabetic';
|
||||
this.text;
|
||||
this.width;
|
||||
this.height;
|
||||
this.pt2px = 1.28;
|
||||
|
||||
$.extend(true, this, options);
|
||||
this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
|
||||
this.setHeight();
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.init = function(options) {
|
||||
$.extend(true, this, options);
|
||||
this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
|
||||
this.setHeight();
|
||||
};
|
||||
|
||||
// convert css spec into point size
|
||||
// returns float
|
||||
$.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) {
|
||||
sz = String(sz);
|
||||
var n = parseFloat(sz);
|
||||
if (sz.indexOf('px') > -1) {
|
||||
return n/this.pt2px;
|
||||
}
|
||||
else if (sz.indexOf('pt') > -1) {
|
||||
return n;
|
||||
}
|
||||
else if (sz.indexOf('em') > -1) {
|
||||
return n*12;
|
||||
}
|
||||
else if (sz.indexOf('%') > -1) {
|
||||
return n*12/100;
|
||||
}
|
||||
// default to pixels;
|
||||
else {
|
||||
return n/this.pt2px;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.fontWeight2Float = function(w) {
|
||||
// w = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
|
||||
// return values adjusted for Hershey font.
|
||||
if (Number(w)) {
|
||||
return w/400;
|
||||
}
|
||||
else {
|
||||
switch (w) {
|
||||
case 'normal':
|
||||
return 1;
|
||||
break;
|
||||
case 'bold':
|
||||
return 1.75;
|
||||
break;
|
||||
case 'bolder':
|
||||
return 2.25;
|
||||
break;
|
||||
case 'lighter':
|
||||
return 0.75;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.getText = function() {
|
||||
return this.text;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.setText = function(t, ctx) {
|
||||
this.text = t;
|
||||
this.setWidth(ctx);
|
||||
return this;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.getWidth = function(ctx) {
|
||||
return this.width;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.setWidth = function(ctx, w) {
|
||||
if (!w) {
|
||||
this.width = this.measure(ctx, this.text);
|
||||
}
|
||||
else {
|
||||
this.width = w;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// return height in pixels.
|
||||
$.jqplot.CanvasTextRenderer.prototype.getHeight = function(ctx) {
|
||||
return this.height;
|
||||
};
|
||||
|
||||
// w - height in pt
|
||||
// set heigh in px
|
||||
$.jqplot.CanvasTextRenderer.prototype.setHeight = function(w) {
|
||||
if (!w) {
|
||||
//height = this.fontSize /0.75;
|
||||
this.height = this.normalizedFontSize * this.pt2px;
|
||||
}
|
||||
else {
|
||||
this.height = w;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.letter = function (ch)
|
||||
{
|
||||
return this.letters[ch];
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.ascent = function()
|
||||
{
|
||||
return this.normalizedFontSize;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.descent = function()
|
||||
{
|
||||
return 7.0*this.normalizedFontSize/25.0;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.measure = function(ctx, str)
|
||||
{
|
||||
var total = 0;
|
||||
var len = str.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
var c = this.letter(str.charAt(i));
|
||||
if (c) {
|
||||
total += c.width * this.normalizedFontSize / 25.0 * this.fontStretch;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.draw = function(ctx,str)
|
||||
{
|
||||
var x = 0;
|
||||
// leave room at bottom for descenders.
|
||||
var y = this.height*0.72;
|
||||
var total = 0;
|
||||
var len = str.length;
|
||||
var mag = this.normalizedFontSize / 25.0;
|
||||
|
||||
ctx.save();
|
||||
var tx, ty;
|
||||
|
||||
// 1st quadrant
|
||||
if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
|
||||
tx = 0;
|
||||
ty = -Math.sin(this.angle) * this.width;
|
||||
}
|
||||
// 4th quadrant
|
||||
else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
|
||||
tx = Math.sin(this.angle) * this.height;
|
||||
ty = 0;
|
||||
}
|
||||
// 2nd quadrant
|
||||
else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
|
||||
tx = -Math.cos(this.angle) * this.width;
|
||||
ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
|
||||
}
|
||||
// 3rd quadrant
|
||||
else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
|
||||
tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
|
||||
ty = -Math.cos(this.angle) * this.height;
|
||||
}
|
||||
|
||||
ctx.strokeStyle = this.fillStyle;
|
||||
ctx.fillStyle = this.fillStyle;
|
||||
ctx.translate(tx, ty);
|
||||
ctx.rotate(this.angle);
|
||||
ctx.lineCap = "round";
|
||||
// multiplier was 2.0
|
||||
var fact = (this.normalizedFontSize > 30) ? 2.0 : 2 + (30 - this.normalizedFontSize)/20;
|
||||
ctx.lineWidth = fact * mag * this.fontWeight2Float(this.fontWeight);
|
||||
|
||||
for ( var i = 0; i < len; i++) {
|
||||
var c = this.letter( str.charAt(i));
|
||||
if ( !c) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
var penUp = 1;
|
||||
var needStroke = 0;
|
||||
for ( var j = 0; j < c.points.length; j++) {
|
||||
var a = c.points[j];
|
||||
if ( a[0] == -1 && a[1] == -1) {
|
||||
penUp = 1;
|
||||
continue;
|
||||
}
|
||||
if ( penUp) {
|
||||
ctx.moveTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
|
||||
penUp = false;
|
||||
} else {
|
||||
ctx.lineTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
x += c.width*mag*this.fontStretch;
|
||||
}
|
||||
ctx.restore();
|
||||
return total;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasTextRenderer.prototype.letters = {
|
||||
' ': { width: 16, points: [] },
|
||||
'!': { width: 10, points: [[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
|
||||
'"': { width: 16, points: [[4,21],[4,14],[-1,-1],[12,21],[12,14]] },
|
||||
'#': { width: 21, points: [[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]] },
|
||||
'$': { width: 20, points: [[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
|
||||
'%': { width: 24, points: [[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
|
||||
'&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
|
||||
'\'': { width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
|
||||
'(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
|
||||
')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
|
||||
'*': { width: 16, points: [[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]] },
|
||||
'+': { width: 26, points: [[13,18],[13,0],[-1,-1],[4,9],[22,9]] },
|
||||
',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
|
||||
'-': { width: 18, points: [[6,9],[12,9]] },
|
||||
'.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
|
||||
'/': { width: 22, points: [[20,25],[2,-7]] },
|
||||
'0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
|
||||
'1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
|
||||
'2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
|
||||
'3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
|
||||
'4': { width: 20, points: [[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]] },
|
||||
'5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
|
||||
'6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
|
||||
'7': { width: 20, points: [[17,21],[7,0],[-1,-1],[3,21],[17,21]] },
|
||||
'8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
|
||||
'9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
|
||||
':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
|
||||
';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
|
||||
'<': { width: 24, points: [[20,18],[4,9],[20,0]] },
|
||||
'=': { width: 26, points: [[4,12],[22,12],[-1,-1],[4,6],[22,6]] },
|
||||
'>': { width: 24, points: [[4,18],[20,9],[4,0]] },
|
||||
'?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]] },
|
||||
'@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]] },
|
||||
'A': { width: 18, points: [[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]] },
|
||||
'B': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
|
||||
'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
|
||||
'D': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
|
||||
'E': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]] },
|
||||
'F': { width: 18, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]] },
|
||||
'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]] },
|
||||
'H': { width: 22, points: [[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]] },
|
||||
'I': { width: 8, points: [[4,21],[4,0]] },
|
||||
'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
|
||||
'K': { width: 21, points: [[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]] },
|
||||
'L': { width: 17, points: [[4,21],[4,0],[-1,-1],[4,0],[16,0]] },
|
||||
'M': { width: 24, points: [[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]] },
|
||||
'N': { width: 22, points: [[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]] },
|
||||
'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
|
||||
'P': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
|
||||
'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]] },
|
||||
'R': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]] },
|
||||
'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
|
||||
'T': { width: 16, points: [[8,21],[8,0],[-1,-1],[1,21],[15,21]] },
|
||||
'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
|
||||
'V': { width: 18, points: [[1,21],[9,0],[-1,-1],[17,21],[9,0]] },
|
||||
'W': { width: 24, points: [[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]] },
|
||||
'X': { width: 20, points: [[3,21],[17,0],[-1,-1],[17,21],[3,0]] },
|
||||
'Y': { width: 18, points: [[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]] },
|
||||
'Z': { width: 20, points: [[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]] },
|
||||
'[': { width: 14, points: [[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]] },
|
||||
'\\': { width: 14, points: [[0,21],[14,-3]] },
|
||||
']': { width: 14, points: [[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]] },
|
||||
'^': { width: 16, points: [[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]] },
|
||||
'_': { width: 16, points: [[0,-2],[16,-2]] },
|
||||
'`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
|
||||
'a': { width: 19, points: [[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
|
||||
'b': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
|
||||
'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
|
||||
'd': { width: 19, points: [[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
|
||||
'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
|
||||
'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]] },
|
||||
'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
|
||||
'h': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
|
||||
'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]] },
|
||||
'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
|
||||
'k': { width: 17, points: [[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]] },
|
||||
'l': { width: 8, points: [[4,21],[4,0]] },
|
||||
'm': { width: 30, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
|
||||
'n': { width: 19, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
|
||||
'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
|
||||
'p': { width: 19, points: [[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
|
||||
'q': { width: 19, points: [[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
|
||||
'r': { width: 13, points: [[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]] },
|
||||
's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
|
||||
't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]] },
|
||||
'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]] },
|
||||
'v': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0]] },
|
||||
'w': { width: 22, points: [[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]] },
|
||||
'x': { width: 17, points: [[3,14],[14,0],[-1,-1],[14,14],[3,0]] },
|
||||
'y': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
|
||||
'z': { width: 17, points: [[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]] },
|
||||
'{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
|
||||
'|': { width: 8, points: [[4,25],[4,-7]] },
|
||||
'}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
|
||||
'~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] }
|
||||
};
|
||||
|
||||
$.jqplot.CanvasFontRenderer = function(options) {
|
||||
options = options || {};
|
||||
if (!options.pt2px) {
|
||||
options.pt2px = 1.5;
|
||||
}
|
||||
$.jqplot.CanvasTextRenderer.call(this, options);
|
||||
};
|
||||
|
||||
$.jqplot.CanvasFontRenderer.prototype = new $.jqplot.CanvasTextRenderer({});
|
||||
$.jqplot.CanvasFontRenderer.prototype.constructor = $.jqplot.CanvasFontRenderer;
|
||||
|
||||
$.jqplot.CanvasFontRenderer.prototype.measure = function(ctx, str)
|
||||
{
|
||||
// var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
|
||||
var fstyle = this.fontSize+' '+this.fontFamily;
|
||||
ctx.save();
|
||||
ctx.font = fstyle;
|
||||
var w = ctx.measureText(str).width;
|
||||
ctx.restore();
|
||||
return w;
|
||||
};
|
||||
|
||||
$.jqplot.CanvasFontRenderer.prototype.draw = function(ctx, str)
|
||||
{
|
||||
var x = 0;
|
||||
// leave room at bottom for descenders.
|
||||
var y = this.height*0.72;
|
||||
//var y = 12;
|
||||
|
||||
ctx.save();
|
||||
var tx, ty;
|
||||
|
||||
// 1st quadrant
|
||||
if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
|
||||
tx = 0;
|
||||
ty = -Math.sin(this.angle) * this.width;
|
||||
}
|
||||
// 4th quadrant
|
||||
else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
|
||||
tx = Math.sin(this.angle) * this.height;
|
||||
ty = 0;
|
||||
}
|
||||
// 2nd quadrant
|
||||
else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
|
||||
tx = -Math.cos(this.angle) * this.width;
|
||||
ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
|
||||
}
|
||||
// 3rd quadrant
|
||||
else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
|
||||
tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
|
||||
ty = -Math.cos(this.angle) * this.height;
|
||||
}
|
||||
ctx.strokeStyle = this.fillStyle;
|
||||
ctx.fillStyle = this.fillStyle;
|
||||
// var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
|
||||
var fstyle = this.fontSize+' '+this.fontFamily;
|
||||
ctx.font = fstyle;
|
||||
ctx.translate(tx, ty);
|
||||
ctx.rotate(this.angle);
|
||||
ctx.fillText(str, x, y);
|
||||
// ctx.strokeText(str, x, y);
|
||||
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,679 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* class: $.jqplot.CategoryAxisRenderer
|
||||
* A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series.
|
||||
*
|
||||
* To use this renderer, include the plugin in your source
|
||||
* > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script>
|
||||
*
|
||||
* and supply the appropriate options to your plot
|
||||
*
|
||||
* > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}}
|
||||
**/
|
||||
$.jqplot.CategoryAxisRenderer = function(options) {
|
||||
$.jqplot.LinearAxisRenderer.call(this);
|
||||
// prop: sortMergedLabels
|
||||
// True to sort tick labels when labels are created by merging
|
||||
// x axis values from multiple series. That is, say you have
|
||||
// two series like:
|
||||
// > line1 = [[2006, 4], [2008, 9], [2009, 16]];
|
||||
// > line2 = [[2006, 3], [2007, 7], [2008, 6]];
|
||||
// If no label array is specified, tick labels will be collected
|
||||
// from the x values of the series. With sortMergedLabels
|
||||
// set to true, tick labels will be:
|
||||
// > [2006, 2007, 2008, 2009]
|
||||
// With sortMergedLabels set to false, tick labels will be:
|
||||
// > [2006, 2008, 2009, 2007]
|
||||
//
|
||||
// Note, this property is specified on the renderOptions for the
|
||||
// axes when creating a plot:
|
||||
// > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}}
|
||||
this.sortMergedLabels = false;
|
||||
};
|
||||
|
||||
$.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
|
||||
$.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer;
|
||||
|
||||
$.jqplot.CategoryAxisRenderer.prototype.init = function(options){
|
||||
this.groups = 1;
|
||||
this.groupLabels = [];
|
||||
this._groupLabels = [];
|
||||
this._grouped = false;
|
||||
this._barsPerGroup = null;
|
||||
this.reverse = false;
|
||||
// prop: tickRenderer
|
||||
// A class of a rendering engine for creating the ticks labels displayed on the plot,
|
||||
// See <$.jqplot.AxisTickRenderer>.
|
||||
// this.tickRenderer = $.jqplot.AxisTickRenderer;
|
||||
// this.labelRenderer = $.jqplot.AxisLabelRenderer;
|
||||
$.extend(true, this, {tickOptions:{formatString:'%d'}}, options);
|
||||
var db = this._dataBounds;
|
||||
// Go through all the series attached to this axis and find
|
||||
// the min/max bounds for this axis.
|
||||
for (var i=0; i<this._series.length; i++) {
|
||||
var s = this._series[i];
|
||||
if (s.groups) {
|
||||
this.groups = s.groups;
|
||||
}
|
||||
var d = s.data;
|
||||
|
||||
for (var j=0; j<d.length; j++) {
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
if (d[j][0] < db.min || db.min == null) {
|
||||
db.min = d[j][0];
|
||||
}
|
||||
if (d[j][0] > db.max || db.max == null) {
|
||||
db.max = d[j][0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (d[j][1] < db.min || db.min == null) {
|
||||
db.min = d[j][1];
|
||||
}
|
||||
if (d[j][1] > db.max || db.max == null) {
|
||||
db.max = d[j][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.groupLabels.length) {
|
||||
this.groups = this.groupLabels.length;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$.jqplot.CategoryAxisRenderer.prototype.createTicks = function() {
|
||||
// we're are operating on an axis here
|
||||
var ticks = this._ticks;
|
||||
var userTicks = this.ticks;
|
||||
var name = this.name;
|
||||
// databounds were set on axis initialization.
|
||||
var db = this._dataBounds;
|
||||
var dim, interval;
|
||||
var min, max;
|
||||
var pos1, pos2;
|
||||
var tt, i;
|
||||
|
||||
// if we already have ticks, use them.
|
||||
if (userTicks.length) {
|
||||
// adjust with blanks if we have groups
|
||||
if (this.groups > 1 && !this._grouped) {
|
||||
var l = userTicks.length;
|
||||
var skip = parseInt(l/this.groups, 10);
|
||||
var count = 0;
|
||||
for (var i=skip; i<l; i+=skip) {
|
||||
userTicks.splice(i+count, 0, ' ');
|
||||
count++;
|
||||
}
|
||||
this._grouped = true;
|
||||
}
|
||||
this.min = 0.5;
|
||||
this.max = userTicks.length + 0.5;
|
||||
var range = this.max - this.min;
|
||||
this.numberTicks = 2*userTicks.length + 1;
|
||||
for (i=0; i<userTicks.length; i++){
|
||||
tt = this.min + 2 * i * range / (this.numberTicks-1);
|
||||
// need a marker before and after the tick
|
||||
var t = new this.tickRenderer(this.tickOptions);
|
||||
t.showLabel = false;
|
||||
// t.showMark = true;
|
||||
t.setTick(tt, this.name);
|
||||
this._ticks.push(t);
|
||||
var t = new this.tickRenderer(this.tickOptions);
|
||||
t.label = userTicks[i];
|
||||
// t.showLabel = true;
|
||||
t.showMark = false;
|
||||
t.showGridline = false;
|
||||
t.setTick(tt+0.5, this.name);
|
||||
this._ticks.push(t);
|
||||
}
|
||||
// now add the last tick at the end
|
||||
var t = new this.tickRenderer(this.tickOptions);
|
||||
t.showLabel = false;
|
||||
// t.showMark = true;
|
||||
t.setTick(tt+1, this.name);
|
||||
this._ticks.push(t);
|
||||
}
|
||||
|
||||
// we don't have any ticks yet, let's make some!
|
||||
else {
|
||||
if (name == 'xaxis' || name == 'x2axis') {
|
||||
dim = this._plotDimensions.width;
|
||||
}
|
||||
else {
|
||||
dim = this._plotDimensions.height;
|
||||
}
|
||||
|
||||
// if min, max and number of ticks specified, user can't specify interval.
|
||||
if (this.min != null && this.max != null && this.numberTicks != null) {
|
||||
this.tickInterval = null;
|
||||
}
|
||||
|
||||
// if max, min, and interval specified and interval won't fit, ignore interval.
|
||||
if (this.min != null && this.max != null && this.tickInterval != null) {
|
||||
if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
|
||||
this.tickInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
// find out how many categories are in the lines and collect labels
|
||||
var labels = [];
|
||||
var numcats = 0;
|
||||
var min = 0.5;
|
||||
var max, val;
|
||||
var isMerged = false;
|
||||
for (var i=0; i<this._series.length; i++) {
|
||||
var s = this._series[i];
|
||||
for (var j=0; j<s.data.length; j++) {
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
val = s.data[j][0];
|
||||
}
|
||||
else {
|
||||
val = s.data[j][1];
|
||||
}
|
||||
if ($.inArray(val, labels) == -1) {
|
||||
isMerged = true;
|
||||
numcats += 1;
|
||||
labels.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isMerged && this.sortMergedLabels) {
|
||||
if (typeof labels[0] == "string") {
|
||||
labels.sort();
|
||||
} else {
|
||||
labels.sort(function(a,b) { return a - b; });
|
||||
}
|
||||
}
|
||||
|
||||
// keep a reference to these tick labels to use for redrawing plot (see bug #57)
|
||||
this.ticks = labels;
|
||||
|
||||
// now bin the data values to the right lables.
|
||||
for (var i=0; i<this._series.length; i++) {
|
||||
var s = this._series[i];
|
||||
for (var j=0; j<s.data.length; j++) {
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
val = s.data[j][0];
|
||||
}
|
||||
else {
|
||||
val = s.data[j][1];
|
||||
}
|
||||
// for category axis, force the values into category bins.
|
||||
// we should have the value in the label array now.
|
||||
var idx = $.inArray(val, labels)+1;
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
s.data[j][0] = idx;
|
||||
}
|
||||
else {
|
||||
s.data[j][1] = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjust with blanks if we have groups
|
||||
if (this.groups > 1 && !this._grouped) {
|
||||
var l = labels.length;
|
||||
var skip = parseInt(l/this.groups, 10);
|
||||
var count = 0;
|
||||
for (var i=skip; i<l; i+=skip+1) {
|
||||
labels[i] = ' ';
|
||||
}
|
||||
this._grouped = true;
|
||||
}
|
||||
|
||||
max = numcats + 0.5;
|
||||
if (this.numberTicks == null) {
|
||||
this.numberTicks = 2*numcats + 1;
|
||||
}
|
||||
|
||||
var range = max - min;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
var track = 0;
|
||||
|
||||
// todo: adjust this so more ticks displayed.
|
||||
var maxVisibleTicks = parseInt(3+dim/10, 10);
|
||||
var skip = parseInt(numcats/maxVisibleTicks, 10);
|
||||
|
||||
if (this.tickInterval == null) {
|
||||
|
||||
this.tickInterval = range / (this.numberTicks-1);
|
||||
|
||||
}
|
||||
// if tickInterval is specified, we will ignore any computed maximum.
|
||||
for (var i=0; i<this.numberTicks; i++){
|
||||
tt = this.min + i * this.tickInterval;
|
||||
var t = new this.tickRenderer(this.tickOptions);
|
||||
// if even tick, it isn't a category, it's a divider
|
||||
if (i/2 == parseInt(i/2, 10)) {
|
||||
t.showLabel = false;
|
||||
t.showMark = true;
|
||||
}
|
||||
else {
|
||||
if (skip>0 && track<skip) {
|
||||
t.showLabel = false;
|
||||
track += 1;
|
||||
}
|
||||
else {
|
||||
t.showLabel = true;
|
||||
track = 0;
|
||||
}
|
||||
t.label = t.formatter(t.formatString, labels[(i-1)/2]);
|
||||
t.showMark = false;
|
||||
t.showGridline = false;
|
||||
}
|
||||
t.setTick(tt, this.name);
|
||||
this._ticks.push(t);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// called with scope of axis
|
||||
$.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) {
|
||||
if (this.show) {
|
||||
// populate the axis label and value properties.
|
||||
// createTicks is a method on the renderer, but
|
||||
// call it within the scope of the axis.
|
||||
this.renderer.createTicks.call(this);
|
||||
// fill a div with axes labels in the right direction.
|
||||
// Need to pregenerate each axis to get its bounds and
|
||||
// position it and the labels correctly on the plot.
|
||||
var dim=0;
|
||||
var temp;
|
||||
// Added for theming.
|
||||
if (this._elem) {
|
||||
// this._elem.empty();
|
||||
// Memory Leaks patch
|
||||
this._elem.emptyForce();
|
||||
}
|
||||
|
||||
this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');
|
||||
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
this._elem.width(this._plotDimensions.width);
|
||||
}
|
||||
else {
|
||||
this._elem.height(this._plotDimensions.height);
|
||||
}
|
||||
|
||||
// create a _label object.
|
||||
this.labelOptions.axis = this.name;
|
||||
this._label = new this.labelRenderer(this.labelOptions);
|
||||
if (this._label.show) {
|
||||
var elem = this._label.draw(ctx, plot);
|
||||
elem.appendTo(this._elem);
|
||||
}
|
||||
|
||||
var t = this._ticks;
|
||||
for (var i=0; i<t.length; i++) {
|
||||
var tick = t[i];
|
||||
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
|
||||
var elem = tick.draw(ctx, plot);
|
||||
elem.appendTo(this._elem);
|
||||
}
|
||||
}
|
||||
|
||||
this._groupLabels = [];
|
||||
// now make group labels
|
||||
for (var i=0; i<this.groupLabels.length; i++)
|
||||
{
|
||||
var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>');
|
||||
elem.html(this.groupLabels[i]);
|
||||
this._groupLabels.push(elem);
|
||||
elem.appendTo(this._elem);
|
||||
}
|
||||
}
|
||||
return this._elem;
|
||||
};
|
||||
|
||||
// called with scope of axis
|
||||
$.jqplot.CategoryAxisRenderer.prototype.set = function() {
|
||||
var dim = 0;
|
||||
var temp;
|
||||
var w = 0;
|
||||
var h = 0;
|
||||
var lshow = (this._label == null) ? false : this._label.show;
|
||||
if (this.show) {
|
||||
var t = this._ticks;
|
||||
for (var i=0; i<t.length; i++) {
|
||||
var tick = t[i];
|
||||
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
temp = tick._elem.outerHeight(true);
|
||||
}
|
||||
else {
|
||||
temp = tick._elem.outerWidth(true);
|
||||
}
|
||||
if (temp > dim) {
|
||||
dim = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dim2 = 0;
|
||||
for (var i=0; i<this._groupLabels.length; i++) {
|
||||
var l = this._groupLabels[i];
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
temp = l.outerHeight(true);
|
||||
}
|
||||
else {
|
||||
temp = l.outerWidth(true);
|
||||
}
|
||||
if (temp > dim2) {
|
||||
dim2 = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (lshow) {
|
||||
w = this._label._elem.outerWidth(true);
|
||||
h = this._label._elem.outerHeight(true);
|
||||
}
|
||||
if (this.name == 'xaxis') {
|
||||
dim += dim2 + h;
|
||||
this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
|
||||
}
|
||||
else if (this.name == 'x2axis') {
|
||||
dim += dim2 + h;
|
||||
this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
|
||||
}
|
||||
else if (this.name == 'yaxis') {
|
||||
dim += dim2 + w;
|
||||
this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
|
||||
if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
|
||||
this._label._elem.css('width', w+'px');
|
||||
}
|
||||
}
|
||||
else {
|
||||
dim += dim2 + w;
|
||||
this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
|
||||
if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
|
||||
this._label._elem.css('width', w+'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// called with scope of axis
|
||||
$.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) {
|
||||
var ticks = this._ticks;
|
||||
var max = this.max;
|
||||
var min = this.min;
|
||||
var offmax = offsets.max;
|
||||
var offmin = offsets.min;
|
||||
var lshow = (this._label == null) ? false : this._label.show;
|
||||
var i;
|
||||
|
||||
for (var p in pos) {
|
||||
this._elem.css(p, pos[p]);
|
||||
}
|
||||
|
||||
this._offsets = offsets;
|
||||
// pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
|
||||
var pixellength = offmax - offmin;
|
||||
var unitlength = max - min;
|
||||
|
||||
if (!this.reverse) {
|
||||
// point to unit and unit to point conversions references to Plot DOM element top left corner.
|
||||
|
||||
this.u2p = function(u){
|
||||
return (u - min) * pixellength / unitlength + offmin;
|
||||
};
|
||||
|
||||
this.p2u = function(p){
|
||||
return (p - offmin) * unitlength / pixellength + min;
|
||||
};
|
||||
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis'){
|
||||
this.series_u2p = function(u){
|
||||
return (u - min) * pixellength / unitlength;
|
||||
};
|
||||
this.series_p2u = function(p){
|
||||
return p * unitlength / pixellength + min;
|
||||
};
|
||||
}
|
||||
|
||||
else {
|
||||
this.series_u2p = function(u){
|
||||
return (u - max) * pixellength / unitlength;
|
||||
};
|
||||
this.series_p2u = function(p){
|
||||
return p * unitlength / pixellength + max;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// point to unit and unit to point conversions references to Plot DOM element top left corner.
|
||||
|
||||
this.u2p = function(u){
|
||||
return offmin + (max - u) * pixellength / unitlength;
|
||||
};
|
||||
|
||||
this.p2u = function(p){
|
||||
return min + (p - offmin) * unitlength / pixellength;
|
||||
};
|
||||
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis'){
|
||||
this.series_u2p = function(u){
|
||||
return (max - u) * pixellength / unitlength;
|
||||
};
|
||||
this.series_p2u = function(p){
|
||||
return p * unitlength / pixellength + max;
|
||||
};
|
||||
}
|
||||
|
||||
else {
|
||||
this.series_u2p = function(u){
|
||||
return (min - u) * pixellength / unitlength;
|
||||
};
|
||||
this.series_p2u = function(p){
|
||||
return p * unitlength / pixellength + min;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (this.show) {
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
for (i=0; i<ticks.length; i++) {
|
||||
var t = ticks[i];
|
||||
if (t.show && t.showLabel) {
|
||||
var shim;
|
||||
|
||||
if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
|
||||
// will need to adjust auto positioning based on which axis this is.
|
||||
var temp = (this.name == 'xaxis') ? 1 : -1;
|
||||
switch (t.labelPosition) {
|
||||
case 'auto':
|
||||
// position at end
|
||||
if (temp * t.angle < 0) {
|
||||
shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
|
||||
}
|
||||
// position at start
|
||||
else {
|
||||
shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
|
||||
}
|
||||
break;
|
||||
case 'end':
|
||||
shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
|
||||
break;
|
||||
case 'start':
|
||||
shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
|
||||
break;
|
||||
case 'middle':
|
||||
shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
|
||||
break;
|
||||
default:
|
||||
shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
shim = -t.getWidth()/2;
|
||||
}
|
||||
var val = this.u2p(t.value) + shim + 'px';
|
||||
t._elem.css('left', val);
|
||||
t.pack();
|
||||
}
|
||||
}
|
||||
|
||||
var labeledge=['bottom', 0];
|
||||
if (lshow) {
|
||||
var w = this._label._elem.outerWidth(true);
|
||||
this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
|
||||
if (this.name == 'xaxis') {
|
||||
this._label._elem.css('bottom', '0px');
|
||||
labeledge = ['bottom', this._label._elem.outerHeight(true)];
|
||||
}
|
||||
else {
|
||||
this._label._elem.css('top', '0px');
|
||||
labeledge = ['top', this._label._elem.outerHeight(true)];
|
||||
}
|
||||
this._label.pack();
|
||||
}
|
||||
|
||||
// draw the group labels
|
||||
var step = parseInt(this._ticks.length/this.groups, 10) + 1;
|
||||
for (i=0; i<this._groupLabels.length; i++) {
|
||||
var mid = 0;
|
||||
var count = 0;
|
||||
for (var j=i*step; j<(i+1)*step; j++) {
|
||||
if (j >= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one.
|
||||
if (this._ticks[j]._elem && this._ticks[j].label != " ") {
|
||||
var t = this._ticks[j]._elem;
|
||||
var p = t.position();
|
||||
mid += p.left + t.outerWidth(true)/2;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
mid = mid/count;
|
||||
this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)});
|
||||
this._groupLabels[i].css(labeledge[0], labeledge[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i=0; i<ticks.length; i++) {
|
||||
var t = ticks[i];
|
||||
if (t.show && t.showLabel) {
|
||||
var shim;
|
||||
if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
|
||||
// will need to adjust auto positioning based on which axis this is.
|
||||
var temp = (this.name == 'yaxis') ? 1 : -1;
|
||||
switch (t.labelPosition) {
|
||||
case 'auto':
|
||||
// position at end
|
||||
case 'end':
|
||||
if (temp * t.angle < 0) {
|
||||
shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
|
||||
}
|
||||
else {
|
||||
shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
|
||||
}
|
||||
break;
|
||||
case 'start':
|
||||
if (t.angle > 0) {
|
||||
shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
|
||||
}
|
||||
else {
|
||||
shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
|
||||
}
|
||||
break;
|
||||
case 'middle':
|
||||
// if (t.angle > 0) {
|
||||
// shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
|
||||
// }
|
||||
// else {
|
||||
// shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
|
||||
// }
|
||||
shim = -t.getHeight()/2;
|
||||
break;
|
||||
default:
|
||||
shim = -t.getHeight()/2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
shim = -t.getHeight()/2;
|
||||
}
|
||||
|
||||
var val = this.u2p(t.value) + shim + 'px';
|
||||
t._elem.css('top', val);
|
||||
t.pack();
|
||||
}
|
||||
}
|
||||
|
||||
var labeledge=['left', 0];
|
||||
if (lshow) {
|
||||
var h = this._label._elem.outerHeight(true);
|
||||
this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
|
||||
if (this.name == 'yaxis') {
|
||||
this._label._elem.css('left', '0px');
|
||||
labeledge = ['left', this._label._elem.outerWidth(true)];
|
||||
}
|
||||
else {
|
||||
this._label._elem.css('right', '0px');
|
||||
labeledge = ['right', this._label._elem.outerWidth(true)];
|
||||
}
|
||||
this._label.pack();
|
||||
}
|
||||
|
||||
// draw the group labels, position top here, do left after label position.
|
||||
var step = parseInt(this._ticks.length/this.groups, 10) + 1; // step is one more than before as we don't want to have overlaps in loops
|
||||
for (i=0; i<this._groupLabels.length; i++) {
|
||||
var mid = 0;
|
||||
var count = 0;
|
||||
for (var j=i*step; j<(i+1)*step; j++) { // j must never reach (i+1)*step as we don't want to have overlap between loops
|
||||
if (j >= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one.
|
||||
if (this._ticks[j]._elem && this._ticks[j].label != " ") {
|
||||
var t = this._ticks[j]._elem;
|
||||
var p = t.position();
|
||||
mid += p.top + t.outerHeight()/2;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
mid = mid/count;
|
||||
this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2});
|
||||
this._groupLabels[i].css(labeledge[0], labeledge[1]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
})(jQuery);
|
||||
+1146
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,741 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* Class: $.jqplot.DateAxisRenderer
|
||||
* A plugin for a jqPlot to render an axis as a series of date values.
|
||||
* This renderer has no options beyond those supplied by the <Axis> class.
|
||||
* It supplies its own tick formatter, so the tickOptions.formatter option
|
||||
* should not be overridden.
|
||||
*
|
||||
* Thanks to Ken Synder for his enhanced Date instance methods which are
|
||||
* included with this code <http://kendsnyder.com/sandbox/date/>.
|
||||
*
|
||||
* To use this renderer, include the plugin in your source
|
||||
* > <script type="text/javascript" language="javascript" src="plugins/jqplot.dateAxisRenderer.js"></script>
|
||||
*
|
||||
* and supply the appropriate options to your plot
|
||||
*
|
||||
* > {axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer}}}
|
||||
*
|
||||
* Dates can be passed into the axis in almost any recognizable value and
|
||||
* will be parsed. They will be rendered on the axis in the format
|
||||
* specified by tickOptions.formatString. e.g. tickOptions.formatString = '%Y-%m-%d'.
|
||||
*
|
||||
* Accecptable format codes
|
||||
* are:
|
||||
*
|
||||
* > Code Result Description
|
||||
* > == Years ==
|
||||
* > %Y 2008 Four-digit year
|
||||
* > %y 08 Two-digit year
|
||||
* > == Months ==
|
||||
* > %m 09 Two-digit month
|
||||
* > %#m 9 One or two-digit month
|
||||
* > %B September Full month name
|
||||
* > %b Sep Abbreviated month name
|
||||
* > == Days ==
|
||||
* > %d 05 Two-digit day of month
|
||||
* > %#d 5 One or two-digit day of month
|
||||
* > %e 5 One or two-digit day of month
|
||||
* > %A Sunday Full name of the day of the week
|
||||
* > %a Sun Abbreviated name of the day of the week
|
||||
* > %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday)
|
||||
* > %o th The ordinal suffix string following the day of the month
|
||||
* > == Hours ==
|
||||
* > %H 23 Hours in 24-hour format (two digits)
|
||||
* > %#H 3 Hours in 24-hour integer format (one or two digits)
|
||||
* > %I 11 Hours in 12-hour format (two digits)
|
||||
* > %#I 3 Hours in 12-hour integer format (one or two digits)
|
||||
* > %p PM AM or PM
|
||||
* > == Minutes ==
|
||||
* > %M 09 Minutes (two digits)
|
||||
* > %#M 9 Minutes (one or two digits)
|
||||
* > == Seconds ==
|
||||
* > %S 02 Seconds (two digits)
|
||||
* > %#S 2 Seconds (one or two digits)
|
||||
* > %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00)
|
||||
* > == Milliseconds ==
|
||||
* > %N 008 Milliseconds (three digits)
|
||||
* > %#N 8 Milliseconds (one to three digits)
|
||||
* > == Timezone ==
|
||||
* > %O 360 difference in minutes between local time and GMT
|
||||
* > %Z Mountain Standard Time Name of timezone as reported by browser
|
||||
* > %G -06:00 Hours and minutes between GMT
|
||||
* > == Shortcuts ==
|
||||
* > %F 2008-03-26 %Y-%m-%d
|
||||
* > %T 05:06:30 %H:%M:%S
|
||||
* > %X 05:06:30 %H:%M:%S
|
||||
* > %x 03/26/08 %m/%d/%y
|
||||
* > %D 03/26/08 %m/%d/%y
|
||||
* > %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y
|
||||
* > %v 3-Sep-2008 %e-%b-%Y
|
||||
* > %R 15:31 %H:%M
|
||||
* > %r 3:31:00 PM %I:%M:%S %p
|
||||
* > == Characters ==
|
||||
* > %n \n Newline
|
||||
* > %t \t Tab
|
||||
* > %% % Percent Symbol
|
||||
*/
|
||||
$.jqplot.DateAxisRenderer = function() {
|
||||
$.jqplot.LinearAxisRenderer.call(this);
|
||||
this.date = new $.jsDate();
|
||||
};
|
||||
|
||||
var second = 1000;
|
||||
var minute = 60 * second;
|
||||
var hour = 60 * minute;
|
||||
var day = 24 * hour;
|
||||
var week = 7 * day;
|
||||
|
||||
// these are less definitive
|
||||
var month = 30.4368499 * day;
|
||||
var year = 365.242199 * day;
|
||||
|
||||
var daysInMonths = [31,28,31,30,31,30,31,30,31,30,31,30];
|
||||
// array of consistent nice intervals. Longer intervals
|
||||
// will depend on days in month, days in year, etc.
|
||||
var niceFormatStrings = ['%M:%S.%#N', '%M:%S.%#N', '%M:%S.%#N', '%M:%S', '%M:%S', '%M:%S', '%M:%S', '%H:%M:%S', '%H:%M:%S', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%a %H:%M', '%a %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%v', '%v', '%v', '%v', '%v', '%v', '%v'];
|
||||
var niceIntervals = [0.1*second, 0.2*second, 0.5*second, second, 2*second, 5*second, 10*second, 15*second, 30*second, minute, 2*minute, 5*minute, 10*minute, 15*minute, 30*minute, hour, 2*hour, 4*hour, 6*hour, 8*hour, 12*hour, day, 2*day, 3*day, 4*day, 5*day, week, 2*week];
|
||||
|
||||
var niceMonthlyIntervals = [];
|
||||
|
||||
function bestDateInterval(min, max, titarget) {
|
||||
// iterate through niceIntervals to find one closest to titarget
|
||||
var badness = Number.MAX_VALUE;
|
||||
var temp, bestTi, bestfmt;
|
||||
for (var i=0, l=niceIntervals.length; i < l; i++) {
|
||||
temp = Math.abs(titarget - niceIntervals[i]);
|
||||
if (temp < badness) {
|
||||
badness = temp;
|
||||
bestTi = niceIntervals[i];
|
||||
bestfmt = niceFormatStrings[i];
|
||||
}
|
||||
}
|
||||
|
||||
return [bestTi, bestfmt];
|
||||
}
|
||||
|
||||
$.jqplot.DateAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
|
||||
$.jqplot.DateAxisRenderer.prototype.constructor = $.jqplot.DateAxisRenderer;
|
||||
|
||||
$.jqplot.DateTickFormatter = function(format, val) {
|
||||
if (!format) {
|
||||
format = '%Y/%m/%d';
|
||||
}
|
||||
return $.jsDate.strftime(val, format);
|
||||
};
|
||||
|
||||
$.jqplot.DateAxisRenderer.prototype.init = function(options){
|
||||
// prop: tickRenderer
|
||||
// A class of a rendering engine for creating the ticks labels displayed on the plot,
|
||||
// See <$.jqplot.AxisTickRenderer>.
|
||||
// this.tickRenderer = $.jqplot.AxisTickRenderer;
|
||||
// this.labelRenderer = $.jqplot.AxisLabelRenderer;
|
||||
this.tickOptions.formatter = $.jqplot.DateTickFormatter;
|
||||
// prop: tickInset
|
||||
// Controls the amount to inset the first and last ticks from
|
||||
// the edges of the grid, in multiples of the tick interval.
|
||||
// 0 is no inset, 0.5 is one half a tick interval, 1 is a full
|
||||
// tick interval, etc.
|
||||
this.tickInset = 0;
|
||||
// prop: drawBaseline
|
||||
// True to draw the axis baseline.
|
||||
this.drawBaseline = true;
|
||||
// prop: baselineWidth
|
||||
// width of the baseline in pixels.
|
||||
this.baselineWidth = null;
|
||||
// prop: baselineColor
|
||||
// CSS color spec for the baseline.
|
||||
this.baselineColor = null;
|
||||
this.daTickInterval = null;
|
||||
this._daTickInterval = null;
|
||||
|
||||
$.extend(true, this, options);
|
||||
|
||||
var db = this._dataBounds,
|
||||
stats,
|
||||
sum,
|
||||
s,
|
||||
d,
|
||||
pd,
|
||||
sd,
|
||||
intv;
|
||||
|
||||
// Go through all the series attached to this axis and find
|
||||
// the min/max bounds for this axis.
|
||||
for (var i=0; i<this._series.length; i++) {
|
||||
stats = {intervals:[], frequencies:{}, sortedIntervals:[], min:null, max:null, mean:null};
|
||||
sum = 0;
|
||||
s = this._series[i];
|
||||
d = s.data;
|
||||
pd = s._plotData;
|
||||
sd = s._stackData;
|
||||
intv = 0;
|
||||
|
||||
for (var j=0; j<d.length; j++) {
|
||||
if (this.name == 'xaxis' || this.name == 'x2axis') {
|
||||
d[j][0] = new $.jsDate(d[j][0]).getTime();
|
||||
pd[j][0] = new $.jsDate(pd[j][0]).getTime();
|
||||
sd[j][0] = new $.jsDate(sd[j][0]).getTime();
|
||||
if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
|
||||
db.min = d[j][0];
|
||||
}
|
||||
if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
|
||||
db.max = d[j][0];
|
||||
}
|
||||
if (j>0) {
|
||||
intv = Math.abs(d[j][0] - d[j-1][0]);
|
||||
stats.intervals.push(intv);
|
||||
if (stats.frequencies.hasOwnProperty(intv)) {
|
||||
stats.frequencies[intv] += 1;
|
||||
}
|
||||
else {
|
||||
stats.frequencies[intv] = 1;
|
||||
}
|
||||
}
|
||||
sum += intv;
|
||||
|
||||
}
|
||||
else {
|
||||
d[j][1] = new $.jsDate(d[j][1]).getTime();
|
||||
pd[j][1] = new $.jsDate(pd[j][1]).getTime();
|
||||
sd[j][1] = new $.jsDate(sd[j][1]).getTime();
|
||||
if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) {
|
||||
db.min = d[j][1];
|
||||
}
|
||||
if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) {
|
||||
db.max = d[j][1];
|
||||
}
|
||||
if (j>0) {
|
||||
intv = Math.abs(d[j][1] - d[j-1][1]);
|
||||
stats.intervals.push(intv);
|
||||
if (stats.frequencies.hasOwnProperty(intv)) {
|
||||
stats.frequencies[intv] += 1;
|
||||
}
|
||||
else {
|
||||
stats.frequencies[intv] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
sum += intv;
|
||||
}
|
||||
|
||||
if (s.renderer.bands) {
|
||||
if (s.renderer.bands.hiData.length) {
|
||||
var bd = s.renderer.bands.hiData;
|
||||
for (var j=0, l=bd.length; j < l; j++) {
|
||||
if (this.name === 'xaxis' || this.name === 'x2axis') {
|
||||
bd[j][0] = new $.jsDate(bd[j][0]).getTime();
|
||||
if ((bd[j][0] != null && bd[j][0] > db.max) || db.max == null) {
|
||||
db.max = bd[j][0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
bd[j][1] = new $.jsDate(bd[j][1]).getTime();
|
||||
if ((bd[j][1] != null && bd[j][1] > db.max) || db.max == null) {
|
||||
db.max = bd[j][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.renderer.bands.lowData.length) {
|
||||
var bd = s.renderer.bands.lowData;
|
||||
for (var j=0, l=bd.length; j < l; j++) {
|
||||
if (this.name === 'xaxis' || this.name === 'x2axis') {
|
||||
bd[j][0] = new $.jsDate(bd[j][0]).getTime();
|
||||
if ((bd[j][0] != null && bd[j][0] < db.min) || db.min == null) {
|
||||
db.min = bd[j][0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
bd[j][1] = new $.jsDate(bd[j][1]).getTime();
|
||||
if ((bd[j][1] != null && bd[j][1] < db.min) || db.min == null) {
|
||||
db.min = bd[j][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tempf = 0,
|
||||
tempn=0;
|
||||
for (var n in stats.frequencies) {
|
||||
stats.sortedIntervals.push({interval:n, frequency:stats.frequencies[n]});
|
||||
}
|
||||
stats.sortedIntervals.sort(function(a, b){
|
||||
return b.frequency - a.frequency;
|
||||
});
|
||||
|
||||
stats.min = $.jqplot.arrayMin(stats.intervals);
|
||||
stats.max = $.jqplot.arrayMax(stats.intervals);
|
||||
stats.mean = sum/d.length;
|
||||
this._intervalStats.push(stats);
|
||||
stats = sum = s = d = pd = sd = null;
|
||||
}
|
||||
db = null;
|
||||
|
||||
};
|
||||
|
||||
// called with scope of an axis
|
||||
$.jqplot.DateAxisRenderer.prototype.reset = function() {
|
||||
this.min = this._options.min;
|
||||
this.max = this._options.max;
|
||||
this.tickInterval = this._options.tickInterval;
|
||||
this.numberTicks = this._options.numberTicks;
|
||||
this._autoFormatString = '';
|
||||
if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) {
|
||||
this.tickOptions.formatString = '';
|
||||
}
|
||||
this.daTickInterval = this._daTickInterval;
|
||||
// this._ticks = this.__ticks;
|
||||
};
|
||||
|
||||
$.jqplot.DateAxisRenderer.prototype.createTicks = function(plot) {
|
||||
// we're are operating on an axis here
|
||||
var ticks = this._ticks;
|
||||
var userTicks = this.ticks;
|
||||
var name = this.name;
|
||||
// databounds were set on axis initialization.
|
||||
var db = this._dataBounds;
|
||||
var iv = this._intervalStats;
|
||||
var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
|
||||
var interval;
|
||||
var min, max;
|
||||
var pos1, pos2;
|
||||
var tt, i;
|
||||
var threshold = 30;
|
||||
var insetMult = 1;
|
||||
var daTickInterval = null;
|
||||
|
||||
// if user specified a tick interval, convert to usable.
|
||||
if (this.tickInterval != null)
|
||||
{
|
||||
// if interval is a number or can be converted to one, use it.
|
||||
// Assume it is in SECONDS!!!
|
||||
if (Number(this.tickInterval)) {
|
||||
daTickInterval = [Number(this.tickInterval), 'seconds'];
|
||||
}
|
||||
// else, parse out something we can build from.
|
||||
else if (typeof this.tickInterval == "string") {
|
||||
var parts = this.tickInterval.split(' ');
|
||||
if (parts.length == 1) {
|
||||
daTickInterval = [1, parts[0]];
|
||||
}
|
||||
else if (parts.length == 2) {
|
||||
daTickInterval = [parts[0], parts[1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tickInterval = this.tickInterval;
|
||||
|
||||
// if we already have ticks, use them.
|
||||
// ticks must be in order of increasing value.
|
||||
|
||||
min = new $.jsDate((this.min != null) ? this.min : db.min).getTime();
|
||||
max = new $.jsDate((this.max != null) ? this.max : db.max).getTime();
|
||||
|
||||
// see if we're zooming. if we are, don't use the min and max we're given,
|
||||
// but compute some nice ones. They will be reset later.
|
||||
|
||||
var cursor = plot.plugins.cursor;
|
||||
|
||||
if (cursor && cursor._zoom && cursor._zoom.zooming) {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
}
|
||||
|
||||
var range = max - min;
|
||||
|
||||
if (this.tickOptions == null || !this.tickOptions.formatString) {
|
||||
this._overrideFormatString = true;
|
||||
}
|
||||
|
||||
if (userTicks.length) {
|
||||
// ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
|
||||
for (i=0; i<userTicks.length; i++){
|
||||
var ut = userTicks[i];
|
||||
var t = new this.tickRenderer(this.tickOptions);
|
||||
if (ut.constructor == Array) {
|
||||
t.value = new $.jsDate(ut[0]).getTime();
|
||||
t.label = ut[1];
|
||||
if (!this.showTicks) {
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
}
|
||||
else if (!this.showTickMarks) {
|
||||
t.showMark = false;
|
||||
}
|
||||
t.setTick(t.value, this.name);
|
||||
this._ticks.push(t);
|
||||
}
|
||||
|
||||
else {
|
||||
t.value = new $.jsDate(ut).getTime();
|
||||
if (!this.showTicks) {
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
}
|
||||
else if (!this.showTickMarks) {
|
||||
t.showMark = false;
|
||||
}
|
||||
t.setTick(t.value, this.name);
|
||||
this._ticks.push(t);
|
||||
}
|
||||
}
|
||||
this.numberTicks = userTicks.length;
|
||||
this.min = this._ticks[0].value;
|
||||
this.max = this._ticks[this.numberTicks-1].value;
|
||||
this.daTickInterval = [(this.max - this.min) / (this.numberTicks - 1)/1000, 'seconds'];
|
||||
}
|
||||
|
||||
////////
|
||||
// We don't have any ticks yet, let's make some!
|
||||
////////
|
||||
|
||||
// special case when there is only one point, make three tick marks to center the point
|
||||
else if (this.min == null && this.max == null && db.min == db.max)
|
||||
{
|
||||
var onePointOpts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
|
||||
var delta = 300000;
|
||||
this.min = db.min - delta;
|
||||
this.max = db.max + delta;
|
||||
this.numberTicks = 3;
|
||||
|
||||
for(var i=this.min;i<=this.max;i+= delta)
|
||||
{
|
||||
onePointOpts.value = i;
|
||||
|
||||
var t = new this.tickRenderer(onePointOpts);
|
||||
|
||||
if (this._overrideFormatString && this._autoFormatString != '') {
|
||||
t.formatString = this._autoFormatString;
|
||||
}
|
||||
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
|
||||
this._ticks.push(t);
|
||||
}
|
||||
|
||||
if(this.showTicks) {
|
||||
this._ticks[1].showLabel = true;
|
||||
}
|
||||
if(this.showTickMarks) {
|
||||
this._ticks[1].showTickMarks = true;
|
||||
}
|
||||
}
|
||||
// if user specified min and max are null, we set those to make best ticks.
|
||||
else if (this.min == null && this.max == null) {
|
||||
|
||||
var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
|
||||
|
||||
// want to find a nice interval
|
||||
var nttarget,
|
||||
titarget;
|
||||
|
||||
// if no tickInterval or numberTicks options specified, make a good guess.
|
||||
if (!this.tickInterval && !this.numberTicks) {
|
||||
var tdim = Math.max(dim, threshold+1);
|
||||
// how many ticks to put on the axis?
|
||||
// date labels tend to be long. If ticks not rotated,
|
||||
// don't use too many and have a high spacing factor.
|
||||
// If we are rotating ticks, use a lower factor.
|
||||
var spacingFactor = 115;
|
||||
if (this.tickRenderer === $.jqplot.CanvasAxisTickRenderer && this.tickOptions.angle) {
|
||||
spacingFactor = 115 - 40 * Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI));
|
||||
}
|
||||
|
||||
nttarget = Math.ceil((tdim-threshold)/spacingFactor + 1);
|
||||
titarget = (max - min) / (nttarget - 1);
|
||||
}
|
||||
|
||||
// If tickInterval is specified, we'll try to honor it.
|
||||
// Not guaranteed to get this interval, but we'll get as close as
|
||||
// we can.
|
||||
// tickInterval will be used before numberTicks, that is if
|
||||
// both are specified, numberTicks will be ignored.
|
||||
else if (this.tickInterval) {
|
||||
titarget = new $.jsDate(0).add(daTickInterval[0], daTickInterval[1]).getTime();
|
||||
}
|
||||
|
||||
// if numberTicks specified, try to honor it.
|
||||
// Not guaranteed, but will try to get close.
|
||||
else if (this.numberTicks) {
|
||||
nttarget = this.numberTicks;
|
||||
titarget = (max - min) / (nttarget - 1);
|
||||
}
|
||||
|
||||
// If we can use an interval of 2 weeks or less, pick best one
|
||||
if (titarget <= 19*day) {
|
||||
var ret = bestDateInterval(min, max, titarget);
|
||||
var tempti = ret[0];
|
||||
this._autoFormatString = ret[1];
|
||||
|
||||
min = new $.jsDate(min);
|
||||
min = Math.floor((min.getTime() - min.getUtcOffset())/tempti) * tempti + min.getUtcOffset();
|
||||
|
||||
nttarget = Math.ceil((max - min) / tempti) + 1;
|
||||
this.min = min;
|
||||
this.max = min + (nttarget - 1) * tempti;
|
||||
|
||||
// if max is less than max, add an interval
|
||||
if (this.max < max) {
|
||||
this.max += tempti;
|
||||
nttarget += 1;
|
||||
}
|
||||
this.tickInterval = tempti;
|
||||
this.numberTicks = nttarget;
|
||||
|
||||
for (var i=0; i<nttarget; i++) {
|
||||
opts.value = this.min + i * tempti;
|
||||
t = new this.tickRenderer(opts);
|
||||
|
||||
if (this._overrideFormatString && this._autoFormatString != '') {
|
||||
t.formatString = this._autoFormatString;
|
||||
}
|
||||
if (!this.showTicks) {
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
}
|
||||
else if (!this.showTickMarks) {
|
||||
t.showMark = false;
|
||||
}
|
||||
this._ticks.push(t);
|
||||
}
|
||||
|
||||
insetMult = this.tickInterval;
|
||||
}
|
||||
|
||||
// should we use a monthly interval?
|
||||
else if (titarget <= 9 * month) {
|
||||
|
||||
this._autoFormatString = '%v';
|
||||
|
||||
// how many months in an interval?
|
||||
var intv = Math.round(titarget/month);
|
||||
if (intv < 1) {
|
||||
intv = 1;
|
||||
}
|
||||
else if (intv > 6) {
|
||||
intv = 6;
|
||||
}
|
||||
|
||||
// figure out the starting month and ending month.
|
||||
var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0);
|
||||
|
||||
// See if max ends exactly on a month
|
||||
var tempmend = new $.jsDate(max);
|
||||
var mend = new $.jsDate(max).setDate(1).setHours(0,0,0,0);
|
||||
|
||||
if (tempmend.getTime() !== mend.getTime()) {
|
||||
mend = mend.add(1, 'month');
|
||||
}
|
||||
|
||||
var nmonths = mend.diff(mstart, 'month');
|
||||
|
||||
nttarget = Math.ceil(nmonths/intv) + 1;
|
||||
|
||||
this.min = mstart.getTime();
|
||||
this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime();
|
||||
this.numberTicks = nttarget;
|
||||
|
||||
for (var i=0; i<nttarget; i++) {
|
||||
if (i === 0) {
|
||||
opts.value = mstart.getTime();
|
||||
}
|
||||
else {
|
||||
opts.value = mstart.add(intv, 'month').getTime();
|
||||
}
|
||||
t = new this.tickRenderer(opts);
|
||||
|
||||
if (this._overrideFormatString && this._autoFormatString != '') {
|
||||
t.formatString = this._autoFormatString;
|
||||
}
|
||||
if (!this.showTicks) {
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
}
|
||||
else if (!this.showTickMarks) {
|
||||
t.showMark = false;
|
||||
}
|
||||
this._ticks.push(t);
|
||||
}
|
||||
|
||||
insetMult = intv * month;
|
||||
}
|
||||
|
||||
// use yearly intervals
|
||||
else {
|
||||
|
||||
this._autoFormatString = '%v';
|
||||
|
||||
// how many years in an interval?
|
||||
var intv = Math.round(titarget/year);
|
||||
if (intv < 1) {
|
||||
intv = 1;
|
||||
}
|
||||
|
||||
// figure out the starting and ending years.
|
||||
var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0);
|
||||
var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0);
|
||||
|
||||
var nyears = mend.diff(mstart, 'year');
|
||||
|
||||
nttarget = Math.ceil(nyears/intv) + 1;
|
||||
|
||||
this.min = mstart.getTime();
|
||||
this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime();
|
||||
this.numberTicks = nttarget;
|
||||
|
||||
for (var i=0; i<nttarget; i++) {
|
||||
if (i === 0) {
|
||||
opts.value = mstart.getTime();
|
||||
}
|
||||
else {
|
||||
opts.value = mstart.add(intv, 'year').getTime();
|
||||
}
|
||||
t = new this.tickRenderer(opts);
|
||||
|
||||
if (this._overrideFormatString && this._autoFormatString != '') {
|
||||
t.formatString = this._autoFormatString;
|
||||
}
|
||||
if (!this.showTicks) {
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
}
|
||||
else if (!this.showTickMarks) {
|
||||
t.showMark = false;
|
||||
}
|
||||
this._ticks.push(t);
|
||||
}
|
||||
|
||||
insetMult = intv * year;
|
||||
}
|
||||
}
|
||||
|
||||
////////
|
||||
// Some option(s) specified, work around that.
|
||||
////////
|
||||
|
||||
else {
|
||||
if (name == 'xaxis' || name == 'x2axis') {
|
||||
dim = this._plotDimensions.width;
|
||||
}
|
||||
else {
|
||||
dim = this._plotDimensions.height;
|
||||
}
|
||||
|
||||
// if min, max and number of ticks specified, user can't specify interval.
|
||||
if (this.min != null && this.max != null && this.numberTicks != null) {
|
||||
this.tickInterval = null;
|
||||
}
|
||||
|
||||
if (this.tickInterval != null && daTickInterval != null) {
|
||||
this.daTickInterval = daTickInterval;
|
||||
}
|
||||
|
||||
// if min and max are same, space them out a bit
|
||||
if (min == max) {
|
||||
var adj = 24*60*60*500; // 1/2 day
|
||||
min -= adj;
|
||||
max += adj;
|
||||
}
|
||||
|
||||
range = max - min;
|
||||
|
||||
var optNumTicks = 2 + parseInt(Math.max(0, dim-100)/100, 10);
|
||||
|
||||
|
||||
var rmin, rmax;
|
||||
|
||||
rmin = (this.min != null) ? new $.jsDate(this.min).getTime() : min - range/2*(this.padMin - 1);
|
||||
rmax = (this.max != null) ? new $.jsDate(this.max).getTime() : max + range/2*(this.padMax - 1);
|
||||
this.min = rmin;
|
||||
this.max = rmax;
|
||||
range = this.max - this.min;
|
||||
|
||||
if (this.numberTicks == null){
|
||||
// if tickInterval is specified by user, we will ignore computed maximum.
|
||||
// max will be equal or greater to fit even # of ticks.
|
||||
if (this.daTickInterval != null) {
|
||||
var nc = new $.jsDate(this.max).diff(this.min, this.daTickInterval[1], true);
|
||||
this.numberTicks = Math.ceil(nc/this.daTickInterval[0]) +1;
|
||||
// this.max = new $.jsDate(this.min).add(this.numberTicks-1, this.daTickInterval[1]).getTime();
|
||||
this.max = new $.jsDate(this.min).add((this.numberTicks-1) * this.daTickInterval[0], this.daTickInterval[1]).getTime();
|
||||
}
|
||||
else if (dim > 200) {
|
||||
this.numberTicks = parseInt(3+(dim-200)/100, 10);
|
||||
}
|
||||
else {
|
||||
this.numberTicks = 2;
|
||||
}
|
||||
}
|
||||
|
||||
insetMult = range / (this.numberTicks-1)/1000;
|
||||
|
||||
if (this.daTickInterval == null) {
|
||||
this.daTickInterval = [insetMult, 'seconds'];
|
||||
}
|
||||
|
||||
|
||||
for (var i=0; i<this.numberTicks; i++){
|
||||
var min = new $.jsDate(this.min);
|
||||
tt = min.add(i*this.daTickInterval[0], this.daTickInterval[1]).getTime();
|
||||
var t = new this.tickRenderer(this.tickOptions);
|
||||
// var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
|
||||
if (!this.showTicks) {
|
||||
t.showLabel = false;
|
||||
t.showMark = false;
|
||||
}
|
||||
else if (!this.showTickMarks) {
|
||||
t.showMark = false;
|
||||
}
|
||||
t.setTick(tt, this.name);
|
||||
this._ticks.push(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.tickInset) {
|
||||
this.min = this.min - this.tickInset * insetMult;
|
||||
this.max = this.max + this.tickInset * insetMult;
|
||||
}
|
||||
|
||||
if (this._daTickInterval == null) {
|
||||
this._daTickInterval = this.daTickInterval;
|
||||
}
|
||||
|
||||
ticks = null;
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
// class $.jqplot.EnhancedPieLegendRenderer
|
||||
// Legend renderer which can specify the number of rows and/or columns in the legend
|
||||
// Similar to EnhancedLegendRenderer, but for pie charts
|
||||
$.jqplot.EnhancedPieLegendRenderer = function(){
|
||||
$.jqplot.TableLegendRenderer.call(this);
|
||||
};
|
||||
|
||||
$.jqplot.EnhancedPieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
|
||||
$.jqplot.EnhancedPieLegendRenderer.prototype.constructor = $.jqplot.EnhancedPieLegendRenderer;
|
||||
|
||||
// called with scope of legend.
|
||||
$.jqplot.EnhancedPieLegendRenderer.prototype.init = function(options) {
|
||||
// prop: numberRows
|
||||
// Maximum number of rows in the legend. 0 or null for unlimited.
|
||||
this.numberRows = null;
|
||||
// prop: numberColumns
|
||||
// Maximum number of columns in the legend. 0 or null for unlimited.
|
||||
this.numberColumns = null;
|
||||
// prop: seriesToggle
|
||||
// false to not enable series on/off toggling on the legend.
|
||||
// true or a fadein/fadeout speed (number of milliseconds or 'fast', 'normal', 'slow')
|
||||
// to enable show/hide of series on click of legend item.
|
||||
this.seriesToggle = 'normal';
|
||||
// prop: seriesToggleReplot
|
||||
// True to replot the chart after toggling series on/off.
|
||||
// This will set the series show property to false.
|
||||
// This allows for rescaling or other maniplation of chart.
|
||||
// Set to an options object (e.g. {resetAxes: true}) for replot options.
|
||||
this.seriesToggleReplot = false;
|
||||
// prop: disableIEFading
|
||||
// true to toggle series with a show/hide method only and not allow fading in/out.
|
||||
// This is to overcome poor performance of fade in some versions of IE.
|
||||
this.disableIEFading = true;
|
||||
// prop: toolTips
|
||||
// optional array of toolTip text corresponding to each pie slice
|
||||
this.toolTips = [];
|
||||
$.extend(true, this, options);
|
||||
|
||||
if (this.seriesToggle) {
|
||||
$.jqplot.postDrawHooks.push(postDraw);
|
||||
}
|
||||
};
|
||||
|
||||
// called with scope of legend
|
||||
$.jqplot.EnhancedPieLegendRenderer.prototype.draw = function(offsets, plot) {
|
||||
var legend = this;
|
||||
if (this.show) {
|
||||
var series = this._series;
|
||||
var s;
|
||||
var ss = 'position:absolute;';
|
||||
ss += (this.background) ? 'background:'+this.background+';' : '';
|
||||
ss += (this.border) ? 'border:'+this.border+';' : '';
|
||||
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
|
||||
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
|
||||
ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
|
||||
ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
|
||||
ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
|
||||
ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
|
||||
ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
|
||||
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
|
||||
if (this.seriesToggle) {
|
||||
this._elem.css('z-index', '3');
|
||||
}
|
||||
|
||||
var pad = false,
|
||||
reverse = false,
|
||||
nr, nc;
|
||||
var s = series[0];
|
||||
var slen = s.data.length;
|
||||
var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
|
||||
|
||||
if (this.numberRows) {
|
||||
nr = this.numberRows;
|
||||
if (!this.numberColumns){
|
||||
nc = Math.ceil(slen/nr);
|
||||
}
|
||||
else{
|
||||
nc = this.numberColumns;
|
||||
}
|
||||
}
|
||||
else if (this.numberColumns) {
|
||||
nc = this.numberColumns;
|
||||
nr = Math.ceil(slen/this.numberColumns);
|
||||
}
|
||||
else {
|
||||
nr = slen;
|
||||
nc = 1;
|
||||
}
|
||||
|
||||
var i, j, tr, td1, td2, lt, rs, div, div0, div1;
|
||||
var idx = 0;
|
||||
// check to see if we need to reverse
|
||||
for (i=series.length-1; i>=0; i--) {
|
||||
if (nc == 1 && series[i]._stack || series[i].renderer.constructor == $.jqplot.BezierCurveRenderer){
|
||||
reverse = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<nr; i++) {
|
||||
tr = $(document.createElement('tr'));
|
||||
tr.addClass('jqplot-table-legend');
|
||||
if (reverse){
|
||||
tr.prependTo(this._elem);
|
||||
}
|
||||
else{
|
||||
tr.appendTo(this._elem);
|
||||
}
|
||||
for (j=0; j<nc; j++) {
|
||||
if (idx < slen){
|
||||
lt = this.labels[idx] || s.data[idx][0].toString();
|
||||
tt = this.toolTips[idx];
|
||||
if (lt) {
|
||||
var color = colorGenerator.next();
|
||||
if (!reverse){
|
||||
if (i>0){
|
||||
pad = true;
|
||||
}
|
||||
else{
|
||||
pad = false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (i == nr -1){
|
||||
pad = false;
|
||||
}
|
||||
else{
|
||||
pad = true;
|
||||
}
|
||||
}
|
||||
rs = (pad) ? this.rowSpacing : '0';
|
||||
|
||||
td1 = $(document.createElement('td'));
|
||||
td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
|
||||
td1.css({textAlign: 'center', paddingTop: rs});
|
||||
|
||||
div0 = $(document.createElement('div'));
|
||||
div0.addClass('jqplot-table-legend-swatch-outline');
|
||||
if (tt !== undefined) {
|
||||
div0.attr("title", tt);
|
||||
}
|
||||
|
||||
div1 = $(document.createElement('div'));
|
||||
div1.addClass('jqplot-table-legend-swatch');
|
||||
div1.css({backgroundColor: color, borderColor: color});
|
||||
|
||||
td1.append(div0.append(div1));
|
||||
|
||||
td2 = $(document.createElement('td'));
|
||||
td2.addClass('jqplot-table-legend jqplot-table-legend-label');
|
||||
td2.css('paddingTop', rs);
|
||||
if (tt !== undefined) {
|
||||
td2.attr("title", tt);
|
||||
}
|
||||
|
||||
if (this.escapeHtml){
|
||||
td2.text(lt);
|
||||
}
|
||||
else {
|
||||
td2.html(lt);
|
||||
}
|
||||
if (reverse) {
|
||||
if (this.showLabels) {td2.prependTo(tr);}
|
||||
if (this.showSwatches) {td1.prependTo(tr);}
|
||||
}
|
||||
else {
|
||||
if (this.showSwatches) {td1.appendTo(tr);}
|
||||
if (this.showLabels) {td2.appendTo(tr);}
|
||||
}
|
||||
|
||||
if (this.seriesToggle) {
|
||||
|
||||
var speed;
|
||||
if (typeof(this.seriesToggle) === 'string' || typeof(this.seriesToggle) === 'number') {
|
||||
if (!$.jqplot.use_excanvas || !this.disableIEFading) {
|
||||
speed = this.seriesToggle;
|
||||
}
|
||||
}
|
||||
if (this.showSwatches) {
|
||||
td1.bind('click', {series:s, index:idx, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle);
|
||||
td1.addClass('jqplot-seriesToggle');
|
||||
}
|
||||
if (this.showLabels) {
|
||||
td2.bind('click', {series:s, index:idx, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle);
|
||||
td2.addClass('jqplot-seriesToggle');
|
||||
}
|
||||
|
||||
// for slices that are already hidden, add the hidden class
|
||||
if (s.showSlice[idx] === false && s.showLabel) {
|
||||
td1.addClass('jqplot-series-hidden');
|
||||
td2.addClass('jqplot-series-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
pad = true;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
td1 = td2 = div0 = div1 = null;
|
||||
}
|
||||
}
|
||||
return this._elem;
|
||||
};
|
||||
|
||||
var handleToggle = function (ev) {
|
||||
var d = ev.data,
|
||||
replot = d.replot,
|
||||
plot = d.plot,
|
||||
idx = d.index;
|
||||
|
||||
d.series.showSlice[idx] = (d.series.showSlice[idx] === false) ? true : false;
|
||||
|
||||
var opts = {};
|
||||
|
||||
if ($.isPlainObject(replot)) {
|
||||
$.extend(true, opts, replot);
|
||||
}
|
||||
|
||||
plot.replot(opts);
|
||||
};
|
||||
|
||||
// called with scope of plot.
|
||||
var postDraw = function () {
|
||||
if (this.legend.renderer.constructor == $.jqplot.EnhancedPieLegendRenderer && this.legend.seriesToggle) {
|
||||
var e = this.legend._elem.detach();
|
||||
this.eventCanvas._elem.after(e);
|
||||
}
|
||||
};
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,484 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
$.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
|
||||
|
||||
/**
|
||||
* Class: $.jqplot.Highlighter
|
||||
* Plugin which will highlight data points when they are moused over.
|
||||
*
|
||||
* To use this plugin, include the js
|
||||
* file in your source:
|
||||
*
|
||||
* > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>
|
||||
*
|
||||
* A tooltip providing information about the data point is enabled by default.
|
||||
* To disable the tooltip, set "showTooltip" to false.
|
||||
*
|
||||
* You can control what data is displayed in the tooltip with various
|
||||
* options. The "tooltipAxes" option controls whether the x, y or both
|
||||
* data values are displayed.
|
||||
*
|
||||
* Some chart types (e.g. hi-low-close) have more than one y value per
|
||||
* data point. To display the additional values in the tooltip, set the
|
||||
* "yvalues" option to the desired number of y values present (3 for a hlc chart).
|
||||
*
|
||||
* By default, data values will be formatted with the same formatting
|
||||
* specifiers as used to format the axis ticks. A custom format code
|
||||
* can be supplied with the tooltipFormatString option. This will apply
|
||||
* to all values in the tooltip.
|
||||
*
|
||||
* For more complete control, the "formatString" option can be set. This
|
||||
* Allows conplete control over tooltip formatting. Values are passed to
|
||||
* the format string in an order determined by the "tooltipAxes" and "yvalues"
|
||||
* options. So, if you have a hi-low-close chart and you just want to display
|
||||
* the hi-low-close values in the tooltip, you could set a formatString like:
|
||||
*
|
||||
* > highlighter: {
|
||||
* > tooltipAxes: 'y',
|
||||
* > yvalues: 3,
|
||||
* > formatString:'<table class="jqplot-highlighter">
|
||||
* > <tr><td>hi:</td><td>%s</td></tr>
|
||||
* > <tr><td>low:</td><td>%s</td></tr>
|
||||
* > <tr><td>close:</td><td>%s</td></tr></table>'
|
||||
* > }
|
||||
*
|
||||
*/
|
||||
$.jqplot.Highlighter = function(options) {
|
||||
// Group: Properties
|
||||
//
|
||||
//prop: show
|
||||
// true to show the highlight.
|
||||
this.show = $.jqplot.config.enablePlugins;
|
||||
// prop: markerRenderer
|
||||
// Renderer used to draw the marker of the highlighted point.
|
||||
// Renderer will assimilate attributes from the data point being highlighted,
|
||||
// so no attributes need set on the renderer directly.
|
||||
// Default is to turn off shadow drawing on the highlighted point.
|
||||
this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
|
||||
// prop: showMarker
|
||||
// true to show the marker
|
||||
this.showMarker = true;
|
||||
// prop: lineWidthAdjust
|
||||
// Pixels to add to the lineWidth of the highlight.
|
||||
this.lineWidthAdjust = 2.5;
|
||||
// prop: sizeAdjust
|
||||
// Pixels to add to the overall size of the highlight.
|
||||
this.sizeAdjust = 5;
|
||||
// prop: showTooltip
|
||||
// Show a tooltip with data point values.
|
||||
this.showTooltip = true;
|
||||
// prop: tooltipLocation
|
||||
// Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
|
||||
this.tooltipLocation = 'nw';
|
||||
// prop: fadeTooltip
|
||||
// true = fade in/out tooltip, flase = show/hide tooltip
|
||||
this.fadeTooltip = true;
|
||||
// prop: tooltipFadeSpeed
|
||||
// 'slow', 'def', 'fast', or number of milliseconds.
|
||||
this.tooltipFadeSpeed = "fast";
|
||||
// prop: tooltipOffset
|
||||
// Pixel offset of tooltip from the highlight.
|
||||
this.tooltipOffset = 2;
|
||||
// prop: tooltipAxes
|
||||
// Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'
|
||||
// 'both' and 'xy' are equivalent, 'yx' reverses order of labels.
|
||||
this.tooltipAxes = 'both';
|
||||
// prop; tooltipSeparator
|
||||
// String to use to separate x and y axes in tooltip.
|
||||
this.tooltipSeparator = ', ';
|
||||
// prop; tooltipContentEditor
|
||||
// Function used to edit/augment/replace the formatted tooltip contents.
|
||||
// Called as str = tooltipContentEditor(str, seriesIndex, pointIndex)
|
||||
// where str is the generated tooltip html and seriesIndex and pointIndex identify
|
||||
// the data point being highlighted. Should return the html for the tooltip contents.
|
||||
this.tooltipContentEditor = null;
|
||||
// prop: useAxesFormatters
|
||||
// Use the x and y axes formatters to format the text in the tooltip.
|
||||
this.useAxesFormatters = true;
|
||||
// prop: tooltipFormatString
|
||||
// sprintf format string for the tooltip.
|
||||
// Uses Ash Searle's javascript sprintf implementation
|
||||
// found here: http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
// See http://perldoc.perl.org/functions/sprintf.html for reference.
|
||||
// Additional "p" and "P" format specifiers added by Chris Leonello.
|
||||
this.tooltipFormatString = '%.5P';
|
||||
// prop: formatString
|
||||
// alternative to tooltipFormatString
|
||||
// will format the whole tooltip text, populating with x, y values as
|
||||
// indicated by tooltipAxes option. So, you could have a tooltip like:
|
||||
// 'Date: %s, number of cats: %d' to format the whole tooltip at one go.
|
||||
// If useAxesFormatters is true, values will be formatted according to
|
||||
// Axes formatters and you can populate your tooltip string with
|
||||
// %s placeholders.
|
||||
this.formatString = null;
|
||||
// prop: yvalues
|
||||
// Number of y values to expect in the data point array.
|
||||
// Typically this is 1. Certain plots, like OHLC, will
|
||||
// have more y values in each data point array.
|
||||
this.yvalues = 1;
|
||||
// prop: bringSeriesToFront
|
||||
// This option requires jQuery 1.4+
|
||||
// True to bring the series of the highlighted point to the front
|
||||
// of other series.
|
||||
this.bringSeriesToFront = false;
|
||||
this._tooltipElem;
|
||||
this.isHighlighting = false;
|
||||
this.currentNeighbor = null;
|
||||
|
||||
$.extend(true, this, options);
|
||||
};
|
||||
|
||||
var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
|
||||
var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
|
||||
var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
|
||||
|
||||
// axis.renderer.tickrenderer.formatter
|
||||
|
||||
// called with scope of plot
|
||||
$.jqplot.Highlighter.init = function (target, data, opts){
|
||||
var options = opts || {};
|
||||
// add a highlighter attribute to the plot
|
||||
this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);
|
||||
};
|
||||
|
||||
// called within scope of series
|
||||
$.jqplot.Highlighter.parseOptions = function (defaults, options) {
|
||||
// Add a showHighlight option to the series
|
||||
// and set it to true by default.
|
||||
this.showHighlight = true;
|
||||
};
|
||||
|
||||
// called within context of plot
|
||||
// create a canvas which we can draw on.
|
||||
// insert it before the eventCanvas, so eventCanvas will still capture events.
|
||||
$.jqplot.Highlighter.postPlotDraw = function() {
|
||||
// Memory Leaks patch
|
||||
if (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) {
|
||||
this.plugins.highlighter.highlightCanvas.resetCanvas();
|
||||
this.plugins.highlighter.highlightCanvas = null;
|
||||
}
|
||||
|
||||
if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) {
|
||||
this.plugins.highlighter._tooltipElem.emptyForce();
|
||||
this.plugins.highlighter._tooltipElem = null;
|
||||
}
|
||||
|
||||
this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas();
|
||||
|
||||
this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this));
|
||||
this.plugins.highlighter.highlightCanvas.setContext();
|
||||
|
||||
var elem = document.createElement('div');
|
||||
this.plugins.highlighter._tooltipElem = $(elem);
|
||||
elem = null;
|
||||
this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip');
|
||||
this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'});
|
||||
|
||||
this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem);
|
||||
};
|
||||
|
||||
$.jqplot.preInitHooks.push($.jqplot.Highlighter.init);
|
||||
$.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);
|
||||
$.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);
|
||||
|
||||
function draw(plot, neighbor) {
|
||||
var hl = plot.plugins.highlighter;
|
||||
var s = plot.series[neighbor.seriesIndex];
|
||||
var smr = s.markerRenderer;
|
||||
var mr = hl.markerRenderer;
|
||||
mr.style = smr.style;
|
||||
mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;
|
||||
mr.size = smr.size + hl.sizeAdjust;
|
||||
var rgba = $.jqplot.getColorComponents(smr.color);
|
||||
var newrgb = [rgba[0], rgba[1], rgba[2]];
|
||||
var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
|
||||
mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
|
||||
mr.init();
|
||||
var x_pos = s.gridData[neighbor.pointIndex][0];
|
||||
var y_pos = s.gridData[neighbor.pointIndex][1];
|
||||
// Adjusting with s._barNudge
|
||||
if (s.renderer.constructor == $.jqplot.BarRenderer) {
|
||||
if (s.barDirection == "vertical") {
|
||||
x_pos += s._barNudge;
|
||||
}
|
||||
else {
|
||||
y_pos -= s._barNudge;
|
||||
}
|
||||
}
|
||||
mr.draw(x_pos, y_pos, hl.highlightCanvas._ctx);
|
||||
}
|
||||
|
||||
function showTooltip(plot, series, neighbor) {
|
||||
// neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}
|
||||
// gridData should be x,y pixel coords on the grid.
|
||||
// add the plot._gridPadding to that to get x,y in the target.
|
||||
var hl = plot.plugins.highlighter;
|
||||
var elem = hl._tooltipElem;
|
||||
var serieshl = series.highlighter || {};
|
||||
|
||||
var opts = $.extend(true, {}, hl, serieshl);
|
||||
|
||||
if (opts.useAxesFormatters) {
|
||||
var xf = series._xaxis._ticks[0].formatter;
|
||||
var yf = series._yaxis._ticks[0].formatter;
|
||||
var xfstr = series._xaxis._ticks[0].formatString;
|
||||
var yfstr = series._yaxis._ticks[0].formatString;
|
||||
var str;
|
||||
var xstr = xf(xfstr, neighbor.data[0]);
|
||||
var ystrs = [];
|
||||
for (var i=1; i<opts.yvalues+1; i++) {
|
||||
ystrs.push(yf(yfstr, neighbor.data[i]));
|
||||
}
|
||||
if (typeof opts.formatString === 'string') {
|
||||
switch (opts.tooltipAxes) {
|
||||
case 'both':
|
||||
case 'xy':
|
||||
ystrs.unshift(xstr);
|
||||
ystrs.unshift(opts.formatString);
|
||||
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
|
||||
break;
|
||||
case 'yx':
|
||||
ystrs.push(xstr);
|
||||
ystrs.unshift(opts.formatString);
|
||||
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
|
||||
break;
|
||||
case 'x':
|
||||
str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]);
|
||||
break;
|
||||
case 'y':
|
||||
ystrs.unshift(opts.formatString);
|
||||
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
|
||||
break;
|
||||
default: // same as xy
|
||||
ystrs.unshift(xstr);
|
||||
ystrs.unshift(opts.formatString);
|
||||
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (opts.tooltipAxes) {
|
||||
case 'both':
|
||||
case 'xy':
|
||||
str = xstr;
|
||||
for (var i=0; i<ystrs.length; i++) {
|
||||
str += opts.tooltipSeparator + ystrs[i];
|
||||
}
|
||||
break;
|
||||
case 'yx':
|
||||
str = '';
|
||||
for (var i=0; i<ystrs.length; i++) {
|
||||
str += ystrs[i] + opts.tooltipSeparator;
|
||||
}
|
||||
str += xstr;
|
||||
break;
|
||||
case 'x':
|
||||
str = xstr;
|
||||
break;
|
||||
case 'y':
|
||||
str = ystrs.join(opts.tooltipSeparator);
|
||||
break;
|
||||
default: // same as 'xy'
|
||||
str = xstr;
|
||||
for (var i=0; i<ystrs.length; i++) {
|
||||
str += opts.tooltipSeparator + ystrs[i];
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var str;
|
||||
if (typeof opts.formatString === 'string') {
|
||||
str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data));
|
||||
}
|
||||
|
||||
else {
|
||||
if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') {
|
||||
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
|
||||
}
|
||||
else if (opts.tooltipAxes == 'yx') {
|
||||
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
|
||||
}
|
||||
else if (opts.tooltipAxes == 'x') {
|
||||
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
|
||||
}
|
||||
else if (opts.tooltipAxes == 'y') {
|
||||
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($.isFunction(opts.tooltipContentEditor)) {
|
||||
// args str, seriesIndex, pointIndex are essential so the hook can look up
|
||||
// extra data for the point.
|
||||
str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);
|
||||
}
|
||||
elem.html(str);
|
||||
var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};
|
||||
var ms = 0;
|
||||
var fact = 0.707;
|
||||
if (series.markerRenderer.show == true) {
|
||||
ms = (series.markerRenderer.size + opts.sizeAdjust)/2;
|
||||
}
|
||||
|
||||
var loc = locations;
|
||||
if (series.fillToZero && series.fill && neighbor.data[1] < 0) {
|
||||
loc = oppositeLocations;
|
||||
}
|
||||
|
||||
switch (loc[locationIndicies[opts.tooltipLocation]]) {
|
||||
case 'nw':
|
||||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
|
||||
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
|
||||
break;
|
||||
case 'n':
|
||||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
|
||||
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms;
|
||||
break;
|
||||
case 'ne':
|
||||
var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
|
||||
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
|
||||
break;
|
||||
case 'e':
|
||||
var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms;
|
||||
var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
|
||||
break;
|
||||
case 'se':
|
||||
var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
|
||||
var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
|
||||
break;
|
||||
case 's':
|
||||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
|
||||
var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms;
|
||||
break;
|
||||
case 'sw':
|
||||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
|
||||
var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
|
||||
break;
|
||||
case 'w':
|
||||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms;
|
||||
var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
|
||||
break;
|
||||
default: // same as 'nw'
|
||||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
|
||||
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
|
||||
break;
|
||||
}
|
||||
if (series.renderer.constructor == $.jqplot.BarRenderer) {
|
||||
if (series.barDirection == 'vertical') {
|
||||
x += series._barNudge;
|
||||
}
|
||||
else {
|
||||
y -= series._barNudge;
|
||||
}
|
||||
}
|
||||
elem.css('left', x);
|
||||
elem.css('top', y);
|
||||
if (opts.fadeTooltip) {
|
||||
// Fix for stacked up animations. Thnanks Trevor!
|
||||
elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
|
||||
}
|
||||
else {
|
||||
elem.show();
|
||||
}
|
||||
elem = null;
|
||||
|
||||
}
|
||||
|
||||
function handleMove(ev, gridpos, datapos, neighbor, plot) {
|
||||
var hl = plot.plugins.highlighter;
|
||||
var c = plot.plugins.cursor;
|
||||
if (hl.show) {
|
||||
if (neighbor == null && hl.isHighlighting) {
|
||||
var evt = jQuery.Event('jqplotHighlighterUnhighlight');
|
||||
plot.target.trigger(evt);
|
||||
|
||||
var ctx = hl.highlightCanvas._ctx;
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
if (hl.fadeTooltip) {
|
||||
hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);
|
||||
}
|
||||
else {
|
||||
hl._tooltipElem.hide();
|
||||
}
|
||||
if (hl.bringSeriesToFront) {
|
||||
plot.restorePreviousSeriesOrder();
|
||||
}
|
||||
hl.isHighlighting = false;
|
||||
hl.currentNeighbor = null;
|
||||
ctx = null;
|
||||
}
|
||||
else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {
|
||||
var evt = jQuery.Event('jqplotHighlighterHighlight');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data, plot];
|
||||
plot.target.trigger(evt, ins);
|
||||
|
||||
hl.isHighlighting = true;
|
||||
hl.currentNeighbor = neighbor;
|
||||
if (hl.showMarker) {
|
||||
draw(plot, neighbor);
|
||||
}
|
||||
if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) {
|
||||
showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
|
||||
}
|
||||
if (hl.bringSeriesToFront) {
|
||||
plot.moveSeriesToFront(neighbor.seriesIndex);
|
||||
}
|
||||
}
|
||||
// check to see if we're highlighting the wrong point.
|
||||
else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) {
|
||||
// highlighting the wrong point.
|
||||
|
||||
// if new series allows highlighting, highlight new point.
|
||||
if (plot.series[neighbor.seriesIndex].showHighlight) {
|
||||
var ctx = hl.highlightCanvas._ctx;
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
hl.isHighlighting = true;
|
||||
hl.currentNeighbor = neighbor;
|
||||
if (hl.showMarker) {
|
||||
draw(plot, neighbor);
|
||||
}
|
||||
if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) {
|
||||
showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
|
||||
}
|
||||
if (hl.bringSeriesToFront) {
|
||||
plot.moveSeriesToFront(neighbor.seriesIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,946 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* Class: $.jqplot.PieRenderer
|
||||
* Plugin renderer to draw a pie chart.
|
||||
* x values, if present, will be used as slice labels.
|
||||
* y values give slice size.
|
||||
*
|
||||
* To use this renderer, you need to include the
|
||||
* pie renderer plugin, for example:
|
||||
*
|
||||
* > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
|
||||
*
|
||||
* Properties described here are passed into the $.jqplot function
|
||||
* as options on the series renderer. For example:
|
||||
*
|
||||
* > plot2 = $.jqplot('chart2', [s1, s2], {
|
||||
* > seriesDefaults: {
|
||||
* > renderer:$.jqplot.PieRenderer,
|
||||
* > rendererOptions:{
|
||||
* > sliceMargin: 2,
|
||||
* > startAngle: -90
|
||||
* > }
|
||||
* > }
|
||||
* > });
|
||||
*
|
||||
* A pie plot will trigger events on the plot target
|
||||
* according to user interaction. All events return the event object,
|
||||
* the series index, the point (slice) index, and the point data for
|
||||
* the appropriate slice.
|
||||
*
|
||||
* 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
|
||||
* 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
|
||||
* if highlighting is enabled.
|
||||
* 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
|
||||
* a highlighted slice.
|
||||
* 'jqplotLegendHighlight' - triggered the first time user mouses over a legend,
|
||||
* if highlighting is enabled.
|
||||
* 'jqplotLegendUnhighlight' - triggered when a user moves the mouse out of
|
||||
* a highlighted legend.
|
||||
* 'jqplotDataClick' - triggered when the user clicks on a slice.
|
||||
* 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
|
||||
* the "captureRightClick" option is set to true on the plot.
|
||||
*/
|
||||
$.jqplot.PieRenderer = function(){
|
||||
$.jqplot.LineRenderer.call(this);
|
||||
};
|
||||
|
||||
$.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
|
||||
$.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
|
||||
|
||||
// called with scope of a series
|
||||
$.jqplot.PieRenderer.prototype.init = function(options, plot) {
|
||||
// Group: Properties
|
||||
//
|
||||
// prop: diameter
|
||||
// Outer diameter of the pie, auto computed by default
|
||||
this.diameter = null;
|
||||
// prop: padding
|
||||
// padding between the pie and plot edges, legend, etc.
|
||||
this.padding = 20;
|
||||
// prop: sliceMargin
|
||||
// angular spacing between pie slices in degrees.
|
||||
this.sliceMargin = 0;
|
||||
// prop: fill
|
||||
// true or false, whether to fil the slices.
|
||||
this.fill = true;
|
||||
// prop: shadowOffset
|
||||
// offset of the shadow from the slice and offset of
|
||||
// each succesive stroke of the shadow from the last.
|
||||
this.shadowOffset = 2;
|
||||
// prop: shadowAlpha
|
||||
// transparency of the shadow (0 = transparent, 1 = opaque)
|
||||
this.shadowAlpha = 0.07;
|
||||
// prop: shadowDepth
|
||||
// number of strokes to apply to the shadow,
|
||||
// each stroke offset shadowOffset from the last.
|
||||
this.shadowDepth = 5;
|
||||
// prop: highlightMouseOver
|
||||
// True to highlight slice when moused over.
|
||||
// This must be false to enable highlightMouseDown to highlight when clicking on a slice.
|
||||
this.highlightMouseOver = true;
|
||||
// prop: highlightMouseDown
|
||||
// True to highlight when a mouse button is pressed over a slice.
|
||||
// This will be disabled if highlightMouseOver is true.
|
||||
this.highlightMouseDown = false;
|
||||
// prop: highlightColors
|
||||
// an array of colors to use when highlighting a slice.
|
||||
this.highlightColors = [];
|
||||
// prop: dataLabels
|
||||
// Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
|
||||
// Defaults to percentage of each pie slice.
|
||||
this.dataLabels = 'percent';
|
||||
// prop: showDataLabels
|
||||
// true to show data labels on slices.
|
||||
this.showDataLabels = false;
|
||||
// prop: dataLabelFormatString
|
||||
// Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
|
||||
this.dataLabelFormatString = null;
|
||||
// prop: dataLabelThreshold
|
||||
// Threshhold in percentage (0-100) of pie area, below which no label will be displayed.
|
||||
// This applies to all label types, not just to percentage labels.
|
||||
this.dataLabelThreshold = 3;
|
||||
// prop: dataLabelPositionFactor
|
||||
// A Multiplier (0-1) of the pie radius which controls position of label on slice.
|
||||
// Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
|
||||
this.dataLabelPositionFactor = 0.52;
|
||||
// prop: dataLabelNudge
|
||||
// Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
|
||||
this.dataLabelNudge = 2;
|
||||
// prop: dataLabelCenterOn
|
||||
// True to center the data label at its position.
|
||||
// False to set the inside facing edge of the label at its position.
|
||||
this.dataLabelCenterOn = true;
|
||||
// prop: startAngle
|
||||
// Angle to start drawing pie in degrees.
|
||||
// According to orientation of canvas coordinate system:
|
||||
// 0 = on the positive x axis
|
||||
// -90 = on the positive y axis.
|
||||
// 90 = on the negaive y axis.
|
||||
// 180 or - 180 = on the negative x axis.
|
||||
this.startAngle = 0;
|
||||
this.tickRenderer = $.jqplot.PieTickRenderer;
|
||||
// prop: showSlice
|
||||
// Array for whether the pie chart slice for a data element should be displayed.
|
||||
// Containsg true or false for each data element. If not specified, defaults to true.
|
||||
this.showSlice = [];
|
||||
// Used as check for conditions where pie shouldn't be drawn.
|
||||
this._drawData = true;
|
||||
this._type = 'pie';
|
||||
|
||||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
|
||||
if (options.highlightMouseDown && options.highlightMouseOver == null) {
|
||||
options.highlightMouseOver = false;
|
||||
}
|
||||
|
||||
$.extend(true, this, options);
|
||||
|
||||
if (this.sliceMargin < 0) {
|
||||
this.sliceMargin = 0;
|
||||
}
|
||||
|
||||
this._diameter = null;
|
||||
this._radius = null;
|
||||
// array of [start,end] angles arrays, one for each slice. In radians.
|
||||
this._sliceAngles = [];
|
||||
// index of the currenty highlighted point, if any
|
||||
this._highlightedPoint = null;
|
||||
|
||||
// set highlight colors if none provided
|
||||
if (this.highlightColors.length == 0) {
|
||||
for (var i=0; i<this.seriesColors.length; i++){
|
||||
var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
|
||||
var newrgb = [rgba[0], rgba[1], rgba[2]];
|
||||
var sum = newrgb[0] + newrgb[1] + newrgb[2];
|
||||
for (var j=0; j<3; j++) {
|
||||
// when darkening, lowest color component can be is 60.
|
||||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
|
||||
newrgb[j] = parseInt(newrgb[j], 10);
|
||||
}
|
||||
this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
|
||||
}
|
||||
}
|
||||
|
||||
this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
|
||||
|
||||
plot.postParseOptionsHooks.addOnce(postParseOptions);
|
||||
plot.postInitHooks.addOnce(postInit);
|
||||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
|
||||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
|
||||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
|
||||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
|
||||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
|
||||
plot.postDrawHooks.addOnce(postPlotDraw);
|
||||
};
|
||||
|
||||
$.jqplot.PieRenderer.prototype.setGridData = function(plot) {
|
||||
// set gridData property. This will hold angle in radians of each data point.
|
||||
var stack = [];
|
||||
var td = [];
|
||||
var sa = this.startAngle/180*Math.PI;
|
||||
var tot = 0;
|
||||
// don't know if we have any valid data yet, so set plot to not draw.
|
||||
this._drawData = false;
|
||||
for (var i=0; i<this.data.length; i++){
|
||||
if (this.data[i][1] != 0) {
|
||||
// we have data, O.K. to draw.
|
||||
this._drawData = true;
|
||||
if (this.showSlice[i] === undefined) {
|
||||
this.showSlice[i] = true;
|
||||
}
|
||||
}
|
||||
stack.push(this.data[i][1]);
|
||||
td.push([this.data[i][0]]);
|
||||
if (i>0) {
|
||||
stack[i] += stack[i-1];
|
||||
}
|
||||
tot += this.data[i][1];
|
||||
}
|
||||
var fact = Math.PI*2/stack[stack.length - 1];
|
||||
|
||||
for (var i=0; i<stack.length; i++) {
|
||||
td[i][1] = stack[i] * fact;
|
||||
td[i][2] = this.data[i][1]/tot;
|
||||
}
|
||||
this.gridData = td;
|
||||
};
|
||||
|
||||
$.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
|
||||
var stack = [];
|
||||
var td = [];
|
||||
var tot = 0;
|
||||
var sa = this.startAngle/180*Math.PI;
|
||||
// don't know if we have any valid data yet, so set plot to not draw.
|
||||
this._drawData = false;
|
||||
for (var i=0; i<data.length; i++){
|
||||
if (this.data[i][1] != 0) {
|
||||
// we have data, O.K. to draw.
|
||||
this._drawData = true;
|
||||
}
|
||||
stack.push(data[i][1]);
|
||||
td.push([data[i][0]]);
|
||||
if (i>0) {
|
||||
stack[i] += stack[i-1];
|
||||
}
|
||||
tot += data[i][1];
|
||||
}
|
||||
var fact = Math.PI*2/stack[stack.length - 1];
|
||||
|
||||
for (var i=0; i<stack.length; i++) {
|
||||
td[i][1] = stack[i] * fact;
|
||||
td[i][2] = data[i][1]/tot;
|
||||
}
|
||||
return td;
|
||||
};
|
||||
|
||||
function calcRadiusAdjustment(ang) {
|
||||
return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0);
|
||||
}
|
||||
|
||||
function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) {
|
||||
var rprime = 0;
|
||||
var ang = ang2 - ang1;
|
||||
var absang = Math.abs(ang);
|
||||
var sm = sliceMargin;
|
||||
if (fill == false) {
|
||||
sm += lineWidth;
|
||||
}
|
||||
|
||||
if (sm > 0 && absang > 0.01 && absang < 6.282) {
|
||||
rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang);
|
||||
}
|
||||
|
||||
return rprime;
|
||||
}
|
||||
|
||||
$.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
|
||||
if (this._drawData) {
|
||||
var r = this._radius;
|
||||
var fill = this.fill;
|
||||
var lineWidth = this.lineWidth;
|
||||
var sm = this.sliceMargin;
|
||||
if (this.fill == false) {
|
||||
sm += this.lineWidth;
|
||||
}
|
||||
ctx.save();
|
||||
ctx.translate(this._center[0], this._center[1]);
|
||||
|
||||
var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
|
||||
|
||||
var transx = rprime * Math.cos((ang1 + ang2) / 2.0);
|
||||
var transy = rprime * Math.sin((ang1 + ang2) / 2.0);
|
||||
|
||||
if ((ang2 - ang1) <= Math.PI) {
|
||||
r -= rprime;
|
||||
}
|
||||
else {
|
||||
r += rprime;
|
||||
}
|
||||
|
||||
ctx.translate(transx, transy);
|
||||
|
||||
if (isShadow) {
|
||||
for (var i=0, l=this.shadowDepth; i<l; i++) {
|
||||
ctx.save();
|
||||
ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
|
||||
doDraw(r);
|
||||
}
|
||||
for (var i=0, l=this.shadowDepth; i<l; i++) {
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
doDraw(r);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function doDraw (rad) {
|
||||
// Fix for IE and Chrome that can't seem to draw circles correctly.
|
||||
// ang2 should always be <= 2 pi since that is the way the data is converted.
|
||||
// 2Pi = 6.2831853, Pi = 3.1415927
|
||||
if (ang2 > 6.282 + this.startAngle) {
|
||||
ang2 = 6.282 + this.startAngle;
|
||||
if (ang1 > ang2) {
|
||||
ang1 = 6.281 + this.startAngle;
|
||||
}
|
||||
}
|
||||
// Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
|
||||
// ugly line on unfilled pies.
|
||||
if (ang1 >= ang2) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = color;
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.arc(0, 0, rad, ang1, ang2, false);
|
||||
ctx.lineTo(0,0);
|
||||
ctx.closePath();
|
||||
|
||||
if (fill) {
|
||||
ctx.fill();
|
||||
}
|
||||
else {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// called with scope of series
|
||||
$.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
|
||||
var i;
|
||||
var opts = (options != undefined) ? options : {};
|
||||
// offset and direction of offset due to legend placement
|
||||
var offx = 0;
|
||||
var offy = 0;
|
||||
var trans = 1;
|
||||
var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
|
||||
var sliceColor;
|
||||
|
||||
if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
|
||||
var li = options.legendInfo;
|
||||
switch (li.location) {
|
||||
case 'nw':
|
||||
offx = li.width + li.xoffset;
|
||||
break;
|
||||
case 'w':
|
||||
offx = li.width + li.xoffset;
|
||||
break;
|
||||
case 'sw':
|
||||
offx = li.width + li.xoffset;
|
||||
break;
|
||||
case 'ne':
|
||||
offx = li.width + li.xoffset;
|
||||
trans = -1;
|
||||
break;
|
||||
case 'e':
|
||||
offx = li.width + li.xoffset;
|
||||
trans = -1;
|
||||
break;
|
||||
case 'se':
|
||||
offx = li.width + li.xoffset;
|
||||
trans = -1;
|
||||
break;
|
||||
case 'n':
|
||||
offy = li.height + li.yoffset;
|
||||
break;
|
||||
case 's':
|
||||
offy = li.height + li.yoffset;
|
||||
trans = -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
|
||||
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
|
||||
|
||||
//see http://stackoverflow.com/questions/20221461/hidpi-retina-plot-drawing
|
||||
var cw = parseInt(ctx.canvas.style.width);
|
||||
var ch = parseInt(ctx.canvas.style.height);
|
||||
//
|
||||
|
||||
var w = cw - offx - 2 * this.padding;
|
||||
var h = ch - offy - 2 * this.padding;
|
||||
var mindim = Math.min(w,h);
|
||||
var d = mindim;
|
||||
|
||||
// Fixes issue #272. Thanks hugwijst!
|
||||
// reset slice angles array.
|
||||
this._sliceAngles = [];
|
||||
|
||||
var sm = this.sliceMargin;
|
||||
if (this.fill == false) {
|
||||
sm += this.lineWidth;
|
||||
}
|
||||
|
||||
var rprime;
|
||||
var maxrprime = 0;
|
||||
|
||||
var ang, ang1, ang2, shadowColor;
|
||||
var sa = this.startAngle / 180 * Math.PI;
|
||||
|
||||
// have to pre-draw shadows, so loop throgh here and calculate some values also.
|
||||
for (var i=0, l=gd.length; i<l; i++) {
|
||||
ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
|
||||
ang2 = gd[i][1] + sa;
|
||||
|
||||
this._sliceAngles.push([ang1, ang2]);
|
||||
|
||||
rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
|
||||
|
||||
if (Math.abs(ang2-ang1) > Math.PI) {
|
||||
maxrprime = Math.max(rprime, maxrprime);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.diameter != null && this.diameter > 0) {
|
||||
this._diameter = this.diameter - 2*maxrprime;
|
||||
}
|
||||
else {
|
||||
this._diameter = d - 2*maxrprime;
|
||||
}
|
||||
|
||||
// Need to check for undersized pie. This can happen if
|
||||
// plot area too small and legend is too big.
|
||||
if (this._diameter < 6) {
|
||||
$.jqplot.log('Diameter of pie too small, not rendering.');
|
||||
return;
|
||||
}
|
||||
|
||||
var r = this._radius = this._diameter/2;
|
||||
|
||||
this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)];
|
||||
|
||||
if (this.shadow) {
|
||||
for (var i=0, l=gd.length; i<l; i++) {
|
||||
shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
|
||||
this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i=0; i<gd.length; i++) {
|
||||
|
||||
sliceColor = colorGenerator.next();
|
||||
|
||||
if (this.showSlice[i]) {
|
||||
this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], sliceColor, false);
|
||||
|
||||
if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
|
||||
var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label;
|
||||
|
||||
if (this.dataLabels == 'label') {
|
||||
fstr = this.dataLabelFormatString || '%s';
|
||||
label = $.jqplot.sprintf(fstr, gd[i][0]);
|
||||
}
|
||||
else if (this.dataLabels == 'value') {
|
||||
fstr = this.dataLabelFormatString || '%d';
|
||||
label = $.jqplot.sprintf(fstr, this.data[i][1]);
|
||||
}
|
||||
else if (this.dataLabels == 'percent') {
|
||||
fstr = this.dataLabelFormatString || '%d%%';
|
||||
label = $.jqplot.sprintf(fstr, gd[i][2]*100);
|
||||
}
|
||||
else if (this.dataLabels.constructor == Array) {
|
||||
fstr = this.dataLabelFormatString || '%s';
|
||||
label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
|
||||
}
|
||||
|
||||
var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
|
||||
|
||||
var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
|
||||
var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
|
||||
|
||||
var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
|
||||
if (this.dataLabelCenterOn) {
|
||||
x -= labelelem.width()/2;
|
||||
y -= labelelem.height()/2;
|
||||
}
|
||||
else {
|
||||
x -= labelelem.width() * Math.sin(avgang/2);
|
||||
y -= labelelem.height()/2;
|
||||
}
|
||||
x = Math.round(x);
|
||||
y = Math.round(y);
|
||||
labelelem.css({left: x, top: y});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.jqplot.PieAxisRenderer = function() {
|
||||
$.jqplot.LinearAxisRenderer.call(this);
|
||||
};
|
||||
|
||||
$.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
|
||||
$.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
|
||||
|
||||
|
||||
// There are no traditional axes on a pie chart. We just need to provide
|
||||
// dummy objects with properties so the plot will render.
|
||||
// called with scope of axis object.
|
||||
$.jqplot.PieAxisRenderer.prototype.init = function(options){
|
||||
//
|
||||
this.tickRenderer = $.jqplot.PieTickRenderer;
|
||||
$.extend(true, this, options);
|
||||
// I don't think I'm going to need _dataBounds here.
|
||||
// have to go Axis scaling in a way to fit chart onto plot area
|
||||
// and provide u2p and p2u functionality for mouse cursor, etc.
|
||||
// for convienence set _dataBounds to 0 and 100 and
|
||||
// set min/max to 0 and 100.
|
||||
this._dataBounds = {min:0, max:100};
|
||||
this.min = 0;
|
||||
this.max = 100;
|
||||
this.showTicks = false;
|
||||
this.ticks = [];
|
||||
this.showMark = false;
|
||||
this.show = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
$.jqplot.PieLegendRenderer = function(){
|
||||
$.jqplot.TableLegendRenderer.call(this);
|
||||
};
|
||||
|
||||
$.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
|
||||
$.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
|
||||
|
||||
/**
|
||||
* Class: $.jqplot.PieLegendRenderer
|
||||
* Legend Renderer specific to pie plots. Set by default
|
||||
* when user creates a pie plot.
|
||||
*/
|
||||
$.jqplot.PieLegendRenderer.prototype.init = function(options) {
|
||||
// Group: Properties
|
||||
//
|
||||
// prop: numberRows
|
||||
// Maximum number of rows in the legend. 0 or null for unlimited.
|
||||
this.numberRows = null;
|
||||
// prop: numberColumns
|
||||
// Maximum number of columns in the legend. 0 or null for unlimited.
|
||||
this.numberColumns = null;
|
||||
// prop: width
|
||||
// Fixed with of legend. 0 or null for auto size
|
||||
this.width = null;
|
||||
$.extend(true, this, options);
|
||||
};
|
||||
|
||||
// called with context of legend
|
||||
$.jqplot.PieLegendRenderer.prototype.draw = function() {
|
||||
var legend = this;
|
||||
if (this.show) {
|
||||
var series = this._series;
|
||||
|
||||
|
||||
this._elem = $(document.createElement('table'));
|
||||
this._elem.addClass('jqplot-table-legend');
|
||||
|
||||
var ss = {position:'absolute'};
|
||||
if (this.background) {
|
||||
ss['background'] = this.background;
|
||||
}
|
||||
if (this.border) {
|
||||
ss['border'] = this.border;
|
||||
}
|
||||
if (this.fontSize) {
|
||||
ss['fontSize'] = this.fontSize;
|
||||
}
|
||||
if (this.fontFamily) {
|
||||
ss['fontFamily'] = this.fontFamily;
|
||||
}
|
||||
if (this.textColor) {
|
||||
ss['textColor'] = this.textColor;
|
||||
}
|
||||
if (this.marginTop != null) {
|
||||
ss['marginTop'] = this.marginTop;
|
||||
}
|
||||
if (this.marginBottom != null) {
|
||||
ss['marginBottom'] = this.marginBottom;
|
||||
}
|
||||
if (this.marginLeft != null) {
|
||||
ss['marginLeft'] = this.marginLeft;
|
||||
}
|
||||
if (this.marginRight != null) {
|
||||
ss['marginRight'] = this.marginRight;
|
||||
}
|
||||
|
||||
this._elem.css(ss);
|
||||
|
||||
// Pie charts legends don't go by number of series, but by number of data points
|
||||
// in the series. Refactor things here for that.
|
||||
|
||||
var pad = false,
|
||||
reverse = false,
|
||||
nr,
|
||||
nc;
|
||||
var s = series[0];
|
||||
var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
|
||||
|
||||
if (s.show) {
|
||||
var pd = s.data;
|
||||
if (this.numberRows) {
|
||||
nr = this.numberRows;
|
||||
if (!this.numberColumns){
|
||||
nc = Math.ceil(pd.length/nr);
|
||||
}
|
||||
else{
|
||||
nc = this.numberColumns;
|
||||
}
|
||||
}
|
||||
else if (this.numberColumns) {
|
||||
nc = this.numberColumns;
|
||||
nr = Math.ceil(pd.length/this.numberColumns);
|
||||
}
|
||||
else {
|
||||
nr = pd.length;
|
||||
nc = 1;
|
||||
}
|
||||
|
||||
var i, j;
|
||||
var tr, td1, td2;
|
||||
var lt, tt, rs, color;
|
||||
var idx = 0;
|
||||
var div0, div1;
|
||||
|
||||
for (i=0; i<nr; i++) {
|
||||
tr = $(document.createElement('tr'));
|
||||
tr.addClass('jqplot-table-legend');
|
||||
|
||||
if (reverse){
|
||||
tr.prependTo(this._elem);
|
||||
}
|
||||
|
||||
else{
|
||||
tr.appendTo(this._elem);
|
||||
}
|
||||
|
||||
for (j=0; j<nc; j++) {
|
||||
if (idx < pd.length) {
|
||||
tt = '';
|
||||
if (this.labels[idx]) {
|
||||
lt = this.labels[idx];
|
||||
}
|
||||
else {
|
||||
if (typeof pd[idx][0] === 'object') {
|
||||
lt = pd[idx][0][0].toString();
|
||||
tt = pd[idx][0][1].toString();
|
||||
}
|
||||
else {
|
||||
lt = pd[idx][0].toString();
|
||||
}
|
||||
}
|
||||
//lt = this.labels[idx] || pd[idx][0].toString();
|
||||
color = colorGenerator.next();
|
||||
if (!reverse){
|
||||
if (i>0){
|
||||
pad = true;
|
||||
}
|
||||
else{
|
||||
pad = false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (i == nr -1){
|
||||
pad = false;
|
||||
}
|
||||
else{
|
||||
pad = true;
|
||||
}
|
||||
}
|
||||
rs = (pad) ? this.rowSpacing : '0';
|
||||
|
||||
|
||||
|
||||
td1 = $(document.createElement('td'));
|
||||
td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
|
||||
td1.css({textAlign: 'center', paddingTop: rs});
|
||||
|
||||
div0 = $(document.createElement('div'));
|
||||
div0.addClass('jqplot-table-legend-swatch-outline');
|
||||
if (tt !== '') {
|
||||
div0.attr("title", tt);
|
||||
}
|
||||
div1 = $(document.createElement('div'));
|
||||
div1.addClass('jqplot-table-legend-swatch');
|
||||
div1.css({backgroundColor: color, borderColor: color});
|
||||
td1.append(div0.append(div1));
|
||||
|
||||
td2 = $(document.createElement('td'));
|
||||
td2.addClass('jqplot-table-legend jqplot-table-legend-label');
|
||||
td2.css('paddingTop', rs);
|
||||
|
||||
if (this.escapeHtml){
|
||||
td2.text(lt);
|
||||
}
|
||||
else {
|
||||
td2.html('<a title="' + tt + '">' + lt + "</a>");
|
||||
}
|
||||
if (reverse) {
|
||||
td2.prependTo(tr);
|
||||
td1.prependTo(tr);
|
||||
}
|
||||
else {
|
||||
td1.appendTo(tr);
|
||||
td2.appendTo(tr);
|
||||
}
|
||||
pad = true;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._elem;
|
||||
};
|
||||
|
||||
$.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
plot.target.trigger('jqplotDataMouseOver', ins);
|
||||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
|
||||
plot.target.trigger('jqplotDataHighlight', ins);
|
||||
highlight (plot, ins[0], ins[1]);
|
||||
}
|
||||
}
|
||||
else if (neighbor == null) {
|
||||
unhighlight (plot);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
|
||||
|
||||
// setup default renderers for axes and legend so user doesn't have to
|
||||
// called with scope of plot
|
||||
function preInit(target, data, options) {
|
||||
options = options || {};
|
||||
options.axesDefaults = options.axesDefaults || {};
|
||||
options.legend = options.legend || {};
|
||||
options.seriesDefaults = options.seriesDefaults || {};
|
||||
// only set these if there is a pie series
|
||||
var setopts = false;
|
||||
if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
|
||||
setopts = true;
|
||||
}
|
||||
else if (options.series) {
|
||||
for (var i=0; i < options.series.length; i++) {
|
||||
if (options.series[i].renderer == $.jqplot.PieRenderer) {
|
||||
setopts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setopts) {
|
||||
options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
|
||||
options.legend.renderer = options.legend.renderer || $.jqplot.PieLegendRenderer;
|
||||
options.legend.preDraw = true;
|
||||
options.seriesDefaults.pointLabels = {show: false};
|
||||
}
|
||||
}
|
||||
|
||||
function postInit(target, data, options) {
|
||||
for (var i=0; i<this.series.length; i++) {
|
||||
if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
|
||||
// don't allow mouseover and mousedown at same time.
|
||||
if (this.series[i].highlightMouseOver) {
|
||||
this.series[i].highlightMouseDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called with scope of plot
|
||||
function postParseOptions(options) {
|
||||
for (var i=0; i<this.series.length; i++) {
|
||||
this.series[i].seriesColors = this.seriesColors;
|
||||
this.series[i].colorGenerator = $.jqplot.colorGenerator;
|
||||
}
|
||||
}
|
||||
|
||||
function highlight (plot, sidx, pidx) {
|
||||
if (plot.series[sidx].showSlice[pidx]) {
|
||||
var s = plot.series[sidx];
|
||||
var canvas = plot.plugins.pieRenderer.highlightCanvas;
|
||||
canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
|
||||
s._highlightedPoint = pidx;
|
||||
plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
|
||||
s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
|
||||
}
|
||||
}
|
||||
|
||||
function unhighlight (plot) {
|
||||
var canvas = plot.plugins.pieRenderer.highlightCanvas;
|
||||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
|
||||
for (var i=0; i<plot.series.length; i++) {
|
||||
plot.series[i]._highlightedPoint = null;
|
||||
}
|
||||
plot.plugins.pieRenderer.highlightedSeriesIndex = null;
|
||||
plot.target.trigger('jqplotDataUnhighlight');
|
||||
}
|
||||
|
||||
function handleMove(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
var evt1 = jQuery.Event('jqplotDataMouseOver');
|
||||
evt1.pageX = ev.pageX;
|
||||
evt1.pageY = ev.pageY;
|
||||
plot.target.trigger(evt1, ins);
|
||||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
|
||||
var evt = jQuery.Event('jqplotDataHighlight');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
highlight (plot, ins[0], ins[1]);
|
||||
}
|
||||
}
|
||||
else if (neighbor == null) {
|
||||
unhighlight (plot);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
|
||||
var evt = jQuery.Event('jqplotDataHighlight');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
highlight (plot, ins[0], ins[1]);
|
||||
}
|
||||
}
|
||||
else if (neighbor == null) {
|
||||
unhighlight (plot);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
|
||||
var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
|
||||
if (idx != null && plot.series[idx].highlightMouseDown) {
|
||||
unhighlight(plot);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
var evt = jQuery.Event('jqplotDataClick');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
}
|
||||
}
|
||||
|
||||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
|
||||
if (neighbor) {
|
||||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
|
||||
var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
|
||||
if (idx != null && plot.series[idx].highlightMouseDown) {
|
||||
unhighlight(plot);
|
||||
}
|
||||
var evt = jQuery.Event('jqplotDataRightClick');
|
||||
evt.which = ev.which;
|
||||
evt.pageX = ev.pageX;
|
||||
evt.pageY = ev.pageY;
|
||||
plot.target.trigger(evt, ins);
|
||||
}
|
||||
}
|
||||
|
||||
// called within context of plot
|
||||
// create a canvas which we can draw on.
|
||||
// insert it before the eventCanvas, so eventCanvas will still capture events.
|
||||
function postPlotDraw() {
|
||||
// Memory Leaks patch
|
||||
if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) {
|
||||
this.plugins.pieRenderer.highlightCanvas.resetCanvas();
|
||||
this.plugins.pieRenderer.highlightCanvas = null;
|
||||
}
|
||||
|
||||
this.plugins.pieRenderer = {highlightedSeriesIndex:null};
|
||||
this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
|
||||
|
||||
// do we have any data labels? if so, put highlight canvas before those
|
||||
var labels = $(this.targetId+' .jqplot-data-label');
|
||||
if (labels.length) {
|
||||
$(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
|
||||
}
|
||||
// else put highlight canvas before event canvas.
|
||||
else {
|
||||
this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
|
||||
}
|
||||
|
||||
var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
|
||||
this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
|
||||
}
|
||||
|
||||
$.jqplot.preInitHooks.push(preInit);
|
||||
|
||||
$.jqplot.PieTickRenderer = function() {
|
||||
$.jqplot.AxisTickRenderer.call(this);
|
||||
};
|
||||
|
||||
$.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
|
||||
$.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
|
||||
|
||||
})(jQuery);
|
||||
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.9
|
||||
* Revision: dff2f04
|
||||
*
|
||||
* Copyright (c) 2009-2016 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
/**
|
||||
* Class: $.jqplot.PointLabels
|
||||
* Plugin for putting labels at the data points.
|
||||
*
|
||||
* To use this plugin, include the js
|
||||
* file in your source:
|
||||
*
|
||||
* > <script type="text/javascript" src="plugins/jqplot.pointLabels.js"></script>
|
||||
*
|
||||
* By default, the last value in the data ponit array in the data series is used
|
||||
* for the label. For most series renderers, extra data can be added to the
|
||||
* data point arrays and the last value will be used as the label.
|
||||
*
|
||||
* For instance,
|
||||
* this series:
|
||||
*
|
||||
* > [[1,4], [3,5], [7,2]]
|
||||
*
|
||||
* Would, by default, use the y values in the labels.
|
||||
* Extra data can be added to the series like so:
|
||||
*
|
||||
* > [[1,4,'mid'], [3 5,'hi'], [7,2,'low']]
|
||||
*
|
||||
* And now the point labels would be 'mid', 'low', and 'hi'.
|
||||
*
|
||||
* Options to the point labels and a custom labels array can be passed into the
|
||||
* "pointLabels" option on the series option like so:
|
||||
*
|
||||
* > series:[{pointLabels:{
|
||||
* > labels:['mid', 'hi', 'low'],
|
||||
* > location:'se',
|
||||
* > ypadding: 12
|
||||
* > }
|
||||
* > }]
|
||||
*
|
||||
* A custom labels array in the options takes precendence over any labels
|
||||
* in the series data. If you have a custom labels array in the options,
|
||||
* but still want to use values from the series array as labels, set the
|
||||
* "labelsFromSeries" option to true.
|
||||
*
|
||||
* By default, html entities (<, >, etc.) are escaped in point labels.
|
||||
* If you want to include actual html markup in the labels,
|
||||
* set the "escapeHTML" option to false.
|
||||
*
|
||||
*/
|
||||
$.jqplot.PointLabels = function(options) {
|
||||
// Group: Properties
|
||||
//
|
||||
// prop: show
|
||||
// show the labels or not.
|
||||
this.show = $.jqplot.config.enablePlugins;
|
||||
// prop: location
|
||||
// compass location where to position the label around the point.
|
||||
// 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
|
||||
this.location = 'n';
|
||||
// prop: labelsFromSeries
|
||||
// true to use labels within data point arrays.
|
||||
this.labelsFromSeries = false;
|
||||
// prop: seriesLabelIndex
|
||||
// array index for location of labels within data point arrays.
|
||||
// if null, will use the last element of the data point array.
|
||||
this.seriesLabelIndex = null;
|
||||
// prop: labels
|
||||
// array of arrays of labels, one array for each series.
|
||||
this.labels = [];
|
||||
// actual labels that will get displayed.
|
||||
// needed to preserve user specified labels in labels array.
|
||||
this._labels = [];
|
||||
// prop: stackedValue
|
||||
// true to display value as stacked in a stacked plot.
|
||||
// no effect if labels is specified.
|
||||
this.stackedValue = false;
|
||||
// prop: ypadding
|
||||
// vertical padding in pixels between point and label
|
||||
this.ypadding = 6;
|
||||
// prop: xpadding
|
||||
// horizontal padding in pixels between point and label
|
||||
this.xpadding = 6;
|
||||
// prop: escapeHTML
|
||||
// true to escape html entities in the labels.
|
||||
// If you want to include markup in the labels, set to false.
|
||||
this.escapeHTML = true;
|
||||
// prop: edgeTolerance
|
||||
// Number of pixels that the label must be away from an axis
|
||||
// boundary in order to be drawn. Negative values will allow overlap
|
||||
// with the grid boundaries.
|
||||
this.edgeTolerance = -5;
|
||||
// prop: formatter
|
||||
// A class of a formatter for the tick text. sprintf by default.
|
||||
this.formatter = $.jqplot.DefaultTickFormatter;
|
||||
// prop: formatString
|
||||
// string passed to the formatter.
|
||||
this.formatString = '';
|
||||
// prop: hideZeros
|
||||
// true to not show a label for a value which is 0.
|
||||
this.hideZeros = false;
|
||||
this._elems = [];
|
||||
|
||||
$.extend(true, this, options);
|
||||
};
|
||||
|
||||
var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
|
||||
var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
|
||||
var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
|
||||
|
||||
// called with scope of a series
|
||||
$.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts, plot){
|
||||
var options = $.extend(true, {}, seriesDefaults, opts);
|
||||
options.pointLabels = options.pointLabels || {};
|
||||
if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal' && !options.pointLabels.location) {
|
||||
options.pointLabels.location = 'e';
|
||||
}
|
||||
// add a pointLabels attribute to the series plugins
|
||||
this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels);
|
||||
this.plugins.pointLabels.setLabels.call(this);
|
||||
};
|
||||
|
||||
// called with scope of series
|
||||
$.jqplot.PointLabels.prototype.setLabels = function() {
|
||||
var p = this.plugins.pointLabels;
|
||||
var labelIdx;
|
||||
if (p.seriesLabelIndex != null) {
|
||||
labelIdx = p.seriesLabelIndex;
|
||||
}
|
||||
else if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal') {
|
||||
labelIdx = (this._plotData[0].length < 3) ? 0 : this._plotData[0].length -1;
|
||||
}
|
||||
else {
|
||||
labelIdx = (this._plotData.length === 0) ? 0 : this._plotData[0].length -1;
|
||||
}
|
||||
p._labels = [];
|
||||
if (p.labels.length === 0 || p.labelsFromSeries) {
|
||||
if (p.stackedValue) {
|
||||
if (this._plotData.length && this._plotData[0].length){
|
||||
// var idx = p.seriesLabelIndex || this._plotData[0].length -1;
|
||||
for (var i=0; i<this._plotData.length; i++) {
|
||||
p._labels.push(this._plotData[i][labelIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// var d = this._plotData;
|
||||
var d = this.data;
|
||||
if (this.renderer.constructor === $.jqplot.BarRenderer && this.waterfall) {
|
||||
d = this._data;
|
||||
}
|
||||
if (d.length && d[0].length) {
|
||||
// var idx = p.seriesLabelIndex || d[0].length -1;
|
||||
for (var i=0; i<d.length; i++) {
|
||||
p._labels.push(d[i][labelIdx]);
|
||||
}
|
||||
}
|
||||
d = null;
|
||||
}
|
||||
}
|
||||
else if (p.labels.length){
|
||||
p._labels = p.labels;
|
||||
}
|
||||
};
|
||||
|
||||
$.jqplot.PointLabels.prototype.xOffset = function(elem, location, padding) {
|
||||
location = location || this.location;
|
||||
padding = padding || this.xpadding;
|
||||
var offset;
|
||||
|
||||
switch (location) {
|
||||
case 'nw':
|
||||
offset = -elem.outerWidth(true) - this.xpadding;
|
||||
break;
|
||||
case 'n':
|
||||
offset = -elem.outerWidth(true)/2;
|
||||
break;
|
||||
case 'ne':
|
||||
offset = this.xpadding;
|
||||
break;
|
||||
case 'e':
|
||||
offset = this.xpadding;
|
||||
break;
|
||||
case 'se':
|
||||
offset = this.xpadding;
|
||||
break;
|
||||
case 's':
|
||||
offset = -elem.outerWidth(true)/2;
|
||||
break;
|
||||
case 'sw':
|
||||
offset = -elem.outerWidth(true) - this.xpadding;
|
||||
break;
|
||||
case 'w':
|
||||
offset = -elem.outerWidth(true) - this.xpadding;
|
||||
break;
|
||||
default: // same as 'nw'
|
||||
offset = -elem.outerWidth(true) - this.xpadding;
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
};
|
||||
|
||||
$.jqplot.PointLabels.prototype.yOffset = function(elem, location, padding) {
|
||||
location = location || this.location;
|
||||
padding = padding || this.xpadding;
|
||||
var offset;
|
||||
|
||||
switch (location) {
|
||||
case 'nw':
|
||||
offset = -elem.outerHeight(true) - this.ypadding;
|
||||
break;
|
||||
case 'n':
|
||||
offset = -elem.outerHeight(true) - this.ypadding;
|
||||
break;
|
||||
case 'ne':
|
||||
offset = -elem.outerHeight(true) - this.ypadding;
|
||||
break;
|
||||
case 'e':
|
||||
offset = -elem.outerHeight(true)/2;
|
||||
break;
|
||||
case 'se':
|
||||
offset = this.ypadding;
|
||||
break;
|
||||
case 's':
|
||||
offset = this.ypadding;
|
||||
break;
|
||||
case 'sw':
|
||||
offset = this.ypadding;
|
||||
break;
|
||||
case 'w':
|
||||
offset = -elem.outerHeight(true)/2;
|
||||
break;
|
||||
default: // same as 'nw'
|
||||
offset = -elem.outerHeight(true) - this.ypadding;
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
};
|
||||
|
||||
// called with scope of series
|
||||
$.jqplot.PointLabels.draw = function (sctx, options, plot) {
|
||||
var p = this.plugins.pointLabels;
|
||||
// set labels again in case they have changed.
|
||||
p.setLabels.call(this);
|
||||
// remove any previous labels
|
||||
for (var i=0; i<p._elems.length; i++) {
|
||||
// Memory Leaks patch
|
||||
// p._elems[i].remove();
|
||||
if(p._elems[i]) {
|
||||
p._elems[i].emptyForce();
|
||||
}
|
||||
}
|
||||
p._elems.splice(0, p._elems.length);
|
||||
|
||||
if (p.show) {
|
||||
var ax = '_'+this._stackAxis+'axis';
|
||||
|
||||
if (!p.formatString) {
|
||||
p.formatString = this[ax]._ticks[0].formatString;
|
||||
p.formatter = this[ax]._ticks[0].formatter;
|
||||
}
|
||||
|
||||
var pd = this._plotData;
|
||||
var ppd = this._prevPlotData;
|
||||
var xax = this._xaxis;
|
||||
var yax = this._yaxis;
|
||||
var elem, helem;
|
||||
|
||||
for (var i=0, l=p._labels.length; i < l; i++) {
|
||||
var label = p._labels[i];
|
||||
|
||||
if (label == null || (p.hideZeros && parseFloat(label) == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
label = p.formatter(p.formatString, label);
|
||||
|
||||
helem = document.createElement('div');
|
||||
p._elems[i] = $(helem);
|
||||
|
||||
elem = p._elems[i];
|
||||
|
||||
|
||||
elem.addClass('jqplot-point-label jqplot-series-'+this.index+' jqplot-point-'+i);
|
||||
elem.css('position', 'absolute');
|
||||
elem.insertAfter(sctx.canvas);
|
||||
|
||||
if (p.escapeHTML) {
|
||||
elem.text(label);
|
||||
}
|
||||
else {
|
||||
elem.html(label);
|
||||
}
|
||||
var location = p.location;
|
||||
if ((this.fillToZero && pd[i][1] < 0) || (this.fillToZero && this._type === 'bar' && this.barDirection === 'horizontal' && pd[i][0] < 0) || (this.waterfall && parseInt(label, 10)) < 0) {
|
||||
location = oppositeLocations[locationIndicies[location]];
|
||||
}
|
||||
|
||||
|
||||
var ell = xax.u2p(pd[i][0]) + p.xOffset(elem, location);
|
||||
var elt = yax.u2p(pd[i][1]) + p.yOffset(elem, location);
|
||||
|
||||
// we have stacked chart but are not showing stacked values,
|
||||
// place labels in center.
|
||||
if (this._stack && !p.stackedValue) {
|
||||
if (this.barDirection === "vertical") {
|
||||
elt = (this._barPoints[i][0][1] + this._barPoints[i][1][1]) / 2 + plot._gridPadding.top - 0.5 * elem.outerHeight(true);
|
||||
}
|
||||
else {
|
||||
ell = (this._barPoints[i][2][0] + this._barPoints[i][0][0]) / 2 + plot._gridPadding.left - 0.5 * elem.outerWidth(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.renderer.constructor == $.jqplot.BarRenderer) {
|
||||
if (this.barDirection == "vertical") {
|
||||
ell += this._barNudge;
|
||||
}
|
||||
else {
|
||||
elt -= this._barNudge;
|
||||
}
|
||||
}
|
||||
elem.css('left', ell);
|
||||
elem.css('top', elt);
|
||||
var elr = ell + elem.width();
|
||||
var elb = elt + elem.height();
|
||||
var et = p.edgeTolerance;
|
||||
var scl = $(sctx.canvas).position().left;
|
||||
var sct = $(sctx.canvas).position().top;
|
||||
var scr = sctx.canvas.width + scl;
|
||||
var scb = sctx.canvas.height + sct;
|
||||
// if label is outside of allowed area, remove it
|
||||
if (ell - et < scl || elt - et < sct || elr + et > scr || elb + et > scb) {
|
||||
elem.remove();
|
||||
}
|
||||
|
||||
elem = null;
|
||||
helem = null;
|
||||
}
|
||||
|
||||
// finally, animate them if the series is animated
|
||||
// if (this.renderer.animation && this.renderer.animation._supported && this.renderer.animation.show && plot._drawCount < 2) {
|
||||
// var sel = '.jqplot-point-label.jqplot-series-'+this.index;
|
||||
// $(sel).hide();
|
||||
// $(sel).fadeIn(1000);
|
||||
// }
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
$.jqplot.postSeriesInitHooks.push($.jqplot.PointLabels.init);
|
||||
$.jqplot.postDrawSeriesHooks.push($.jqplot.PointLabels.draw);
|
||||
})(jQuery);
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
|
||||
|
||||
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.
|
||||
+1505
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,3 @@
|
||||
/*! jQuery Migrate v3.5.2 | (c) OpenJS Foundation and other contributors | jquery.com/license */
|
||||
"undefined"==typeof jQuery.migrateMute&&(jQuery.migrateMute=!0),function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e,window)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery"),window):t(jQuery,window)}(function(s,n){"use strict";function e(e){return 0<=function(e,t){for(var r=/^(\d+)\.(\d+)\.(\d+)/,n=r.exec(e)||[],o=r.exec(t)||[],a=1;a<=3;a++){if(+o[a]<+n[a])return 1;if(+n[a]<+o[a])return-1}return 0}(s.fn.jquery,e)}s.migrateVersion="3.5.2";var t=Object.create(null);s.migrateDisablePatches=function(){for(var e=0;e<arguments.length;e++)t[arguments[e]]=!0},s.migrateEnablePatches=function(){for(var e=0;e<arguments.length;e++)delete t[arguments[e]]},s.migrateIsPatchEnabled=function(e){return!t[e]},n.console&&n.console.log&&(s&&e("3.0.0")&&!e("5.0.0")||n.console.log("JQMIGRATE: jQuery 3.x-4.x REQUIRED"),s.migrateWarnings&&n.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),n.console.log("JQMIGRATE: Migrate is installed"+(s.migrateMute?"":" with logging active")+", version "+s.migrateVersion));var o={};function u(e,t){var r=n.console;!s.migrateIsPatchEnabled(e)||s.migrateDeduplicateWarnings&&o[t]||(o[t]=!0,s.migrateWarnings.push(t+" ["+e+"]"),r&&r.warn&&!s.migrateMute&&(r.warn("JQMIGRATE: "+t),s.migrateTrace&&r.trace&&r.trace()))}function r(e,t,r,n,o){Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return u(n,o),r},set:function(e){u(n,o),r=e}})}function a(e,t,r,n,o){var a=e[t];e[t]=function(){return o&&u(n,o),(s.migrateIsPatchEnabled(n)?r:a||s.noop).apply(this,arguments)}}function c(e,t,r,n,o){if(!o)throw new Error("No warning message provided");return a(e,t,r,n,o),0}function i(e,t,r,n){return a(e,t,r,n),0}s.migrateDeduplicateWarnings=!0,s.migrateWarnings=[],void 0===s.migrateTrace&&(s.migrateTrace=!0),s.migrateReset=function(){o={},s.migrateWarnings.length=0},"BackCompat"===n.document.compatMode&&u("quirks","jQuery is not compatible with Quirks Mode");var d,l,p,f={},m=s.fn.init,y=s.find,g=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,h=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g,v=/^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;for(d in i(s.fn,"init",function(e){var t=Array.prototype.slice.call(arguments);return s.migrateIsPatchEnabled("selector-empty-id")&&"string"==typeof e&&"#"===e&&(u("selector-empty-id","jQuery( '#' ) is not a valid selector"),t[0]=[]),m.apply(this,t)},"selector-empty-id"),s.fn.init.prototype=s.fn,i(s,"find",function(t){var r=Array.prototype.slice.call(arguments);if("string"==typeof t&&g.test(t))try{n.document.querySelector(t)}catch(e){t=t.replace(h,function(e,t,r,n){return"["+t+r+'"'+n+'"]'});try{n.document.querySelector(t),u("selector-hash","Attribute selector with '#' must be quoted: "+r[0]),r[0]=t}catch(e){u("selector-hash","Attribute selector with '#' was not fixed: "+r[0])}}return y.apply(this,r)},"selector-hash"),y)Object.prototype.hasOwnProperty.call(y,d)&&(s.find[d]=y[d]);c(s.fn,"size",function(){return this.length},"size","jQuery.fn.size() is deprecated and removed; use the .length property"),c(s,"parseJSON",function(){return JSON.parse.apply(null,arguments)},"parseJSON","jQuery.parseJSON is deprecated; use JSON.parse"),c(s,"holdReady",s.holdReady,"holdReady","jQuery.holdReady is deprecated"),c(s,"unique",s.uniqueSort,"unique","jQuery.unique is deprecated; use jQuery.uniqueSort"),r(s.expr,"filters",s.expr.pseudos,"expr-pre-pseudos","jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),r(s.expr,":",s.expr.pseudos,"expr-pre-pseudos","jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"),e("3.1.1")&&c(s,"trim",function(e){return null==e?"":(e+"").replace(v,"$1")},"trim","jQuery.trim is deprecated; use String.prototype.trim"),e("3.2.0")&&(c(s,"nodeName",function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},"nodeName","jQuery.nodeName is deprecated"),c(s,"isArray",Array.isArray,"isArray","jQuery.isArray is deprecated; use Array.isArray")),e("3.3.0")&&(c(s,"isNumeric",function(e){var t=typeof e;return("number"==t||"string"==t)&&!isNaN(e-parseFloat(e))},"isNumeric","jQuery.isNumeric() is deprecated"),s.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){f["[object "+t+"]"]=t.toLowerCase()}),c(s,"type",function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?f[Object.prototype.toString.call(e)]||"object":typeof e},"type","jQuery.type is deprecated"),c(s,"isFunction",function(e){return"function"==typeof e},"isFunction","jQuery.isFunction() is deprecated"),c(s,"isWindow",function(e){return null!=e&&e===e.window},"isWindow","jQuery.isWindow() is deprecated")),s.ajax&&(l=s.ajax,p=/(=)\?(?=&|$)|\?\?/,i(s,"ajax",function(){var e=l.apply(this,arguments);return e.promise&&(c(e,"success",e.done,"jqXHR-methods","jQXHR.success is deprecated and removed"),c(e,"error",e.fail,"jqXHR-methods","jQXHR.error is deprecated and removed"),c(e,"complete",e.always,"jqXHR-mLine truncated
|
||||
//# sourceMappingURL=jquery-migrate.min.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jquery-migrate.min.js","sources":["../src/migratemute.js","jquery-migrate.js"],"names":["jQuery","migrateMute","factory","define","amd","window","module","exports","require","jQueryVersionSince","version","v1","v2","rVersionParts","v1p","exec","v2p","i","compareVersions","fn","jquery","migrateVersion","disabledPatches","Object","create","migrateDisablePatches","arguments","length","migrateEnablePatches","migrateIsPatchEnabled","patchCode","console","log","migrateWarnings","warnedAbout","migrateWarn","code","msg","migrateDeduplicateWarnings","push","warn","migrateTrace","trace","migrateWarnProp","obj","prop","value","defineProperty","configurable","enumerable","get","set","newValue","migrateWarnFuncInternal","newFunc","origFunc","noop","apply","this","migratePatchAndWarnFunc","Error","migratePatchFunc","undefined","migrateReset","document","compatMode","findProp","oldAjax","rjsonp","class2type","oldInit","init","oldFind","find","rattrHashTest","rattrHashGlob","rtrim","arg1","args","Array","prototype","slice","call","selector","test","querySelector","err1","replace","_","attr","op","err2","hasOwnProperty","JSON","parse","holdReady","uniqueSort","expr","pseudos","text","elem","name","nodeName","toLowerCase","isArray","type","isNaN","parseFloat","each","split","toString","ajax","jQXHR","promise","done","fail","always","ajaxPrefilter","s","jsonp","url","data","contentType","indexOf","oldRemoveAttr","removeAttr","oldToggleClass","toggleClass","rbooleans","rmatchNonSpace","camelCase","string","letter","toUpperCase","self","patchNeeded","match","_i","state","className","getAttribute","setAttribute","origFnCss","internalCssNumber","internalSwapCall","ralphaStart","rautoPx","swap","oldHook","cssHooks","ret","options","callback","old","style","Proxy","cssProps","Reflect","animationIterationCount","aspectRatio","borderImageSlice","columnCount","flexGrow","flexShrink","fontWeight","gridArea","gridColumn","gridColumnEnd","gridColumnStart","gridRow","gridRowEnd","gridRowStart","lineHeight","opacity","order","orphans","scale","widows","zIndex","zoom","fillOpacity","floodOpacity","stopOpacity","strokeMiterlimit","strokeOpacity","cssNumber","css","camelName","origThis","n","v","intervalValue","intervalMsg","oldTweenRun","linearEasing","origData","curData","sameKeys","key","hasData","fx","Tween","run","pct","easing","interval","requestAnimationFrame","hidden","oldLoad","load","oldEventAdd","event","add","originalFix","fix","props","fixHooks","concat","originalEvent","fixHook","join","addProp","pop","_migrated_","filter","types","readyState","splice","on","triggerHandler","trigger","special","ready","setup","off","fnOver","fnOut","makeMarkup","html","doc","implementation","createHTMLDocument","body","innerHTML","rxhtmlTag","changed","origParam","oldDeferred","tuples","origOffset","offset","nodeType","getBoundingClientRect","param","traditional","ajaxTraditional","ajaxSettings","addBack","Deferred","Callbacks","func","deferred","newDeferredPipe","fns","newDefer","tuple","returned","resolve","reject","progress","notify","exceptionHook"],"mappings":";AAEmC,oBAAvBA,OAAOC,cAClBD,OAAOC,aAAc,GCCtB,SAAYC,gBAGY,mBAAXC,QAAyBA,OAAOC,IAG3CD,OAAQ,CAAE,UAAY,SAAUH,GAC/B,OAAOE,EAASF,EAAQK,UAEI,iBAAXC,QAAuBA,OAAOC,QAIhDD,OAAOC,QAAUL,EAASM,QAAS,UAAYH,QAI/CH,EAASF,OAAQK,QAjBnB,CAmBK,SAAUL,EAAQK,gBAuBvB,SAASI,EAAoBC,GAC5B,OAAuD,GAlBxD,SAA0BC,EAAIC,GAM7B,IALA,IACCC,EAAgB,uBAChBC,EAAMD,EAAcE,KAAMJ,IAAQ,GAClCK,EAAMH,EAAcE,KAAMH,IAAQ,GAE7BK,EAAI,EAAGA,GAAK,EAAGA,IAAM,CAC1B,IAAkBD,EAAKC,IAAjBH,EAAKG,GACV,OAAO,EAER,IAAMH,EAAKG,IAAOD,EAAKC,GACtB,OAAQ,EAGV,OAAO,EAIAC,CAAiBlB,EAAOmB,GAAGC,OAAQV,GArB3CV,EAAOqB,eAAiB,QA0BxB,IAAIC,EAAkBC,OAAOC,OAAQ,MAKrCxB,EAAOyB,sBAAwB,WAE9B,IADA,IACMR,EAAI,EAAGA,EAAIS,UAAUC,OAAQV,IAClCK,EAAiBI,UAAWT,KAAQ,GAatCjB,EAAO4B,qBAAuB,WAE7B,IADA,IACMX,EAAI,EAAGA,EAAIS,UAAUC,OAAQV,WAC3BK,EAAiBI,UAAWT,KAIrCjB,EAAO6B,sBAAwB,SAAUC,GACxC,OAAQR,EAAiBQ,IAQpBzB,EAAO0B,SAAY1B,EAAO0B,QAAQC,MAKlChC,GAAWS,EAAoB,WACnCA,EAAoB,UACrBJ,EAAO0B,QAAQC,IAAK,sCAEhBhC,EAAOiC,iBACX5B,EAAO0B,QAAQC,IAAK,mDAIrB3B,EAAO0B,QAAQC,IAAK,mCACjBhC,EAAOC,YAAc,GAAK,wBAC5B,aAAeD,EAAOqB,iBAIvB,IAAIa,EAAc,GAmBlB,SAASC,EAAaC,EAAMC,GAC3B,IAAIN,EAAU1B,EAAO0B,SAChB/B,EAAO6B,sBAAuBO,IAC/BpC,EAAOsC,4BAA+BJ,EAAaG,KACtDH,EAAaG,IAAQ,EACrBrC,EAAOiC,gBAAgBM,KAAMF,EAAM,KAAOD,EAAO,KAC5CL,GAAWA,EAAQS,OAASxC,EAAOC,cACvC8B,EAAQS,KAAM,cAAgBH,GACzBrC,EAAOyC,cAAgBV,EAAQW,OACnCX,EAAQW,UAMZ,SAASC,EAAiBC,EAAKC,EAAMC,EAAOV,EAAMC,GACjDd,OAAOwB,eAAgBH,EAAKC,EAAM,CACjCG,cAAc,EACdC,YAAY,EACZC,IAAK,WAEJ,OADAf,EAAaC,EAAMC,GACZS,GAERK,IAAK,SAAUC,GACdjB,EAAaC,EAAMC,GACnBS,EAAQM,KAKX,SAASC,EAAyBT,EAAKC,EAAMS,EAASlB,EAAMC,GAC3D,IACCkB,EAAWX,EAAKC,GAEjBD,EAAKC,GAAS,WAkBb,OAZKR,GACJF,EAAaC,EAAMC,IAKRrC,EAAO6B,sBAAuBO,GACzCkB,EAGEC,GAAYvD,EAAOwD,MAELC,MAAOC,KAAMhC,YAIhC,SAASiC,EAAyBf,EAAKC,EAAMS,EAASlB,EAAMC,GAC3D,IAAMA,EACL,MAAM,IAAIuB,MAAO,+BAElB,OAAOP,EAAyBT,EAAKC,EAAMS,EAASlB,EAAMC,GAAnDgB,EAGR,SAASQ,EAAkBjB,EAAKC,EAAMS,EAASlB,GAC9C,OAAOiB,EAAyBT,EAAKC,EAAMS,EAASlB,GAA7CiB,EAhFRrDLine truncated
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
/*! jQuery UI - v1.13.3 - 2024-04-26
|
||||
* https://jqueryui.com
|
||||
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
|
||||
* Copyright OpenJS Foundation and other contributors; Licensed MIT */
|
||||
|
||||
!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(V){"use strict";V.ui=V.ui||{};V.ui.version="1.13.3";var n,s,x,k,o,a,r,l,h,i,N=0,E=Array.prototype.hasOwnProperty,c=Array.prototype.slice;V.cleanData=(n=V.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=V._data(i,"events"))&&e.remove&&V(i).triggerHandler("remove");n(t)}),V.widget=function(t,i,e){var s,n,o,a={},r=t.split(".")[0],l=r+"-"+(t=t.split(".")[1]);return e||(e=i,i=V.Widget),Array.isArray(e)&&(e=V.extend.apply(null,[{}].concat(e))),V.expr.pseudos[l.toLowerCase()]=function(t){return!!V.data(t,l)},V[r]=V[r]||{},s=V[r][t],n=V[r][t]=function(t,e){if(!this||!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},V.extend(n,s,{version:e.version,_proto:V.extend({},e),_childConstructors:[]}),(o=new i).options=V.widget.extend({},o.options),V.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}a[e]="function"!=typeof s?s:function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}}),n.prototype=V.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},a,{constructor:n,namespace:r,widgetName:t,widgetFullName:l}),s?(V.each(s._childConstructors,function(t,e){var i=e.prototype;V.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),V.widget.bridge(t,n),n},V.widget.extend=function(t){for(var e,i,s=c.call(arguments,1),n=0,o=s.length;n<o;n++)for(e in s[n])i=s[n][e],E.call(s[n],e)&&void 0!==i&&(V.isPlainObject(i)?t[e]=V.isPlainObject(t[e])?V.widget.extend({},t[e],i):V.widget.extend({},i):t[e]=i);return t},V.widget.bridge=function(o,e){var a=e.prototype.widgetFullName||o;V.fn[o]=function(i){var t="string"==typeof i,s=c.call(arguments,1),n=this;return t?this.length||"instance"!==i?this.each(function(){var t,e=V.data(this,a);return"instance"===i?(n=e,!1):e?"function"!=typeof e[i]||"_"===i.charAt(0)?V.error("no such method '"+i+"' for "+o+" widget instance"):(t=e[i].apply(e,s))!==e&&void 0!==t?(n=t&&t.jquery?n.pushStack(t.get()):t,!1):void 0:V.error("cannot call methods on "+o+" prior to initialization; attempted to call method '"+i+"'")}):n=void 0:(s.length&&(i=V.widget.extend.apply(null,[i].concat(s))),this.each(function(){var t=V.data(this,a);t?(t.option(i||{}),t._init&&t._init()):V.data(this,a,new e(i,this))})),n}},V.Widget=function(){},V.Widget._childConstructors=[],V.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=V(e||this.defaultElement||this)[0],this.element=V(e),this.uuid=N++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=V(),this.hoverable=V(),this.focusable=V(),this.classesElementLookup={},e!==this&&(V.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=V(e.style?e.ownerDocument:e.document||e),this.window=V(this.document[0].defaultView||this.document[0].parentWindow)),this.options=V.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:V.noop,_create:V.noop,_init:V.noop,destroy:function(){var i=this;this._destroy(),V.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:V.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return V.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=V.widget.extend({},this.options[t]),n=0;n<i.length-1;n++)s[i[n]]=s[i[n]]||{},s=s[i[n]];if(t=i.pop(),1===arguments.length)return void 0===s[t]?null:s[t];s[t]=e}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=e}return this._setOptions(o),this},_setOptions:function(t){for(var e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(t){var e,i,s;for(e in t)s=this.classesElementLookup[e],t[e]!==this.options.classes[e]&&s&&s.length&&(i=V(s.get()),this._removeClass(s,e),i.addClass(this._classes({element:i,keys:e,classes:t,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return thLine truncated
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Debounce and throttle function's decorator plugin 1.0.6
|
||||
*
|
||||
* Copyright (c) 2009 Filatov Dmitry (alpha@zforms.ru)
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
$.extend({
|
||||
|
||||
/**
|
||||
* Debounce's decorator
|
||||
* @param {Function} fn original function
|
||||
* @param {Number} timeout timeout
|
||||
* @param {Boolean} [invokeAsap=false] invoke function as soon as possible
|
||||
* @param {Object} [ctx] context of original function
|
||||
*/
|
||||
debounce: function (fn, timeout, invokeAsap, ctx) {
|
||||
|
||||
if (arguments.length == 3 && typeof invokeAsap != 'boolean') {
|
||||
ctx = invokeAsap;
|
||||
invokeAsap = false;
|
||||
}
|
||||
|
||||
var timer;
|
||||
|
||||
return function () {
|
||||
|
||||
var args = arguments;
|
||||
ctx = ctx || this;
|
||||
|
||||
invokeAsap && !timer && fn.apply(ctx, args);
|
||||
|
||||
clearTimeout(timer);
|
||||
|
||||
timer = setTimeout(function () {
|
||||
invokeAsap || fn.apply(ctx, args);
|
||||
timer = null;
|
||||
}, timeout);
|
||||
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Throttle's decorator
|
||||
* @param {Function} fn original function
|
||||
* @param {Number} timeout timeout
|
||||
* @param {Object} [ctx] context of original function
|
||||
*/
|
||||
throttle: function (fn, timeout, ctx) {
|
||||
|
||||
var timer, args, needInvoke;
|
||||
|
||||
return function () {
|
||||
|
||||
args = arguments;
|
||||
needInvoke = true;
|
||||
ctx = ctx || this;
|
||||
|
||||
timer || (function () {
|
||||
if (needInvoke) {
|
||||
fn.apply(ctx, args);
|
||||
needInvoke = false;
|
||||
timer = setTimeout(arguments.callee, timeout);
|
||||
}
|
||||
else {
|
||||
timer = null;
|
||||
}
|
||||
})();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */
|
||||
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}function fe(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}ce.fn=ce.prototype={jquery:t,constructor:ce,length:0,toArray:function(){return ae.call(this)},get:function(e){return null==e?ae.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=ce.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return ce.each(this,e)},map:function(n){return this.pushStack(ce.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(ae.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(ce.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(ce.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:oe.sort,splice:oe.splice},ce.extend=ce.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||v(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(ce.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||ce.isPlainObject(n)?n:{},i=!1,a[t]=ce.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},ce.extend({expando:"jQuery"+(t+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==i.call(e))&&(!(t=r(e))||"function"==typeof(n=ue.call(t,"constructor")&&t.constructor)&&o.call(n)===a)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){m(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(c(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},text:function(e){var t,n="",r=0,i=e.nodeType;if(!i)while(t=e[r++])n+=ce.text(t);return 1===i||11===i?e.textContent:9===i?e.documentElement.textContent:3===i||4===i?e.nodeValue:n},makeArray:function(e,t){var n=t||[];return null!=e&&(c(Object(e))?ce.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:se.call(t,e,n)},isXMLDoc:function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!l.test(t||n&&n.nodeName||"HTML")},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(c(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:le}),"function"==typeof Symbol&&(ce.fn[Symbol.iterator]=oe[Symbol.iterator]),ce.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var pe=oe.pop,de=oe.sort,he=oe.splice,ge="[\\x20\\t\\r\\n\\f]",ve=new RegExp("^"+ge+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ge+"+$","g");ce.contains=function(e,t){var n=t&&t.parentNode;return e===n||!(!n||1!==n.nodeType||!(e.contains?e.contains(n):e.compareDocumentPosition&&16&e.compareDocumentPosition(n)))};var f=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;function p(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e}ce.escapeSelector=function(e){return(e+"").replace(f,p)};var ye=C,me=s;!function(){var e,b,w,o,a,T,r,C,d,i,k=me,S=ce.expando,E=0,n=0,s=W(),c=W(),u=W(),h=W(),l=function(e,t){return e===t&&(a=!0),0},f="checked|selected|async|autofocus|autoplay|conLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["jquery.js"],"names":["global","factory","module","exports","document","w","Error","window","this","noGlobal","arr","getProto","Object","getPrototypeOf","slice","flat","array","call","concat","apply","push","indexOf","class2type","toString","hasOwn","hasOwnProperty","fnToString","ObjectFunctionString","support","isFunction","obj","nodeType","item","isWindow","preservedScriptAttributes","type","src","nonce","noModule","DOMEval","code","node","doc","i","val","script","createElement","text","getAttribute","setAttribute","head","appendChild","parentNode","removeChild","toType","version","rhtmlSuffix","jQuery","selector","context","fn","init","isArrayLike","length","nodeName","elem","name","toLowerCase","prototype","jquery","constructor","toArray","get","num","pushStack","elems","ret","merge","prevObject","each","callback","map","arguments","first","eq","last","even","grep","_elem","odd","len","j","end","sort","splice","extend","options","copy","copyIsArray","clone","target","deep","isPlainObject","Array","isArray","undefined","expando","Math","random","replace","isReady","error","msg","noop","proto","Ctor","isEmptyObject","globalEval","textContent","documentElement","nodeValue","makeArray","results","inArray","isXMLDoc","namespace","namespaceURI","docElem","ownerDocument","test","second","invert","matches","callbackExpect","arg","value","guid","Symbol","iterator","split","_i","pop","whitespace","rtrimCSS","RegExp","contains","a","b","bup","compareDocumentPosition","rcssescape","fcssescape","ch","asCodePoint","charCodeAt","escapeSelector","sel","preferredDoc","pushNative","Expr","outermostContext","sortInput","hasDuplicate","documentIsHTML","rbuggyQSA","dirruns","done","classCache","createCache","tokenCache","compilerCache","nonnativeSelectorCache","sortOrder","booleans","identifier","attributes","pseudos","rwhitespace","rcomma","rleadingCombinator","rdescend","rpseudo","ridentifier","matchExpr","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","bool","needsContext","rinputs","rheader","rquickExpr","rsibling","runescape","funescape","escape","nonHex","high","String","fromCharCode","unloadHandler","setDocument","inDisabledFieldset","addCombinator","disabled","dir","next","childNodes","e","els","find","seed","m","nid","match","groups","newSelector","newContext","exec","getElementById","id","getElementsByTagName","getElementsByClassName","testContext","scope","tokenize","toSelector","join","querySelectorAll","qsaError","removeAttribute","select","keys","cache","key","cacheLength","shift","markFunction","assert","el","createInputPseudo","createButtonPseudo","createDisabledPseudo","isDisabled","createPositionalPseudo","argument","matchIndexes","subWindow","webkitMatchesSelector","msMatchesSelector","defaultView","top","addEventListener","getById","getElementsByName","disconnectedMatch","cssHas","querySelector","filter","attrId","getAttributeNode","tag","className","input","innerHTML","compare","sortDetached","expr","elements","matchesSelector","attr","attrHandle","uniqueSort","duplicates","sortStable","createPseudo","relative",">"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","expectedNodeName","pattern","operator","check","result","what","_argument","simple","forward","ofType","_context","xml","outerCache","nodeIndex","start","parent","useCache","diff","firstChild","lastChild","pseudo","args","setFilters","idx","matched","not","matcher","compile","unmatched","has","lang","elemLang","hash","location","root","focus","activeElement","err","safeActiveElement","hasFocus","href","tabIndex","enabled","checked","selected","selectedIndex","empty","nextSibling","header","button","_matchIndexes","lt","gt","nth","radio","checkbox","file","password","image","submit","reset","parseOnly","tokens","soFar","preFilters","cached","combinator","base","skip","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","matcherOut","preMap","postMap","preexisting","contexts","multipleContexts","matcherIn","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","filters","unique","getText","isXML","selectors","until","truncate","is","siblings","n","rneedsContext","rsingleTag","winnow","qualifier","self","rootjQuery","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","prev","sibling","cur","targets","l","closest","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","contentDocument","content","reverse","rnothtmlwhite","Identity","v","Thrower","ex","adoptValue","resolve","reject","noValue","method","promise","fail","then","Callbacks","object","_","flag","firing","memory","fired","locked","list","queue","firingIndex","fire","onLine truncated
|
||||
+2916
File diff suppressed because it is too large.
Load diff
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Greg Weber greg at gregweber.info
|
||||
* Dual licensed under the MIT and GPLv2 licenses just as jQuery is:
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* Multi-columns support by natinusala
|
||||
*
|
||||
* documentation at http://gregweber.info/projects/uitablefilter
|
||||
*
|
||||
* allows table rows to be filtered (made invisible)
|
||||
* <code>
|
||||
* t = $('table')
|
||||
* $.uiTableFilter( t, phrase )
|
||||
* </code>
|
||||
* arguments:
|
||||
* jQuery object containing table rows
|
||||
* phrase to search for
|
||||
* optional arguments:
|
||||
* array of columns to limit search too (the column title in the table header)
|
||||
* ifHidden - callback to execute if one or more elements was hidden
|
||||
* tdElem - specific element within <td> to be considered for searching or to limit search to,
|
||||
* default:whole <td>. useful if <td> has more than one elements inside but want to
|
||||
* limit search within only some of elements or only visible elements. eg tdElem can be "td span"
|
||||
*/
|
||||
(function ($) {
|
||||
$.uiTableFilter = function (jq, phrase, column, ifHidden, tdElem) {
|
||||
if (!tdElem) tdElem = "td";
|
||||
var new_hidden = false;
|
||||
if (this.last_phrase === phrase) return false;
|
||||
|
||||
var phrase_length = phrase.length;
|
||||
var words = phrase.toLowerCase().split(" ");
|
||||
|
||||
// these function pointers may change
|
||||
var matches = function (elem) { elem.show() }
|
||||
var noMatch = function (elem) { elem.hide(); new_hidden = true }
|
||||
var getText = function (elem) { return elem.text() }
|
||||
|
||||
if (column) {
|
||||
if (!$.isArray(column)) {
|
||||
column = new Array(column);
|
||||
}
|
||||
|
||||
var index = new Array();
|
||||
|
||||
jq.find("thead > tr:last > th").each(function (i) {
|
||||
for (var j = 0; j < column.length; j++) {
|
||||
if ($.trim($(this).text()) == column[j]) {
|
||||
index[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
getText = function (elem) {
|
||||
var selector = "";
|
||||
for (var i = 0; i < index.length; i++) {
|
||||
if (i != 0) { selector += ","; }
|
||||
selector += tdElem + ":eq(" + index[i] + ")";
|
||||
}
|
||||
return $(elem.find((selector))).text();
|
||||
}
|
||||
}
|
||||
|
||||
// if added one letter to last time,
|
||||
// just check newest word and only need to hide
|
||||
if ((words.size > 1) && (phrase.substr(0, phrase_length - 1) ===
|
||||
this.last_phrase)) {
|
||||
|
||||
if (phrase[-1] === " ") { this.last_phrase = phrase; return false; }
|
||||
|
||||
var words = words[-1]; // just search for the newest word
|
||||
|
||||
// only hide visible rows
|
||||
matches = function (elem) { ; }
|
||||
var elems = jq.find("tbody:first > tr:visible")
|
||||
}
|
||||
else {
|
||||
new_hidden = true;
|
||||
var elems = jq.find("tbody:first > tr")
|
||||
}
|
||||
|
||||
elems.each(function () {
|
||||
var elem = $(this);
|
||||
$.uiTableFilter.has_words(getText(elem), words, false) ?
|
||||
matches(elem) : noMatch(elem);
|
||||
});
|
||||
|
||||
last_phrase = phrase;
|
||||
if (ifHidden && new_hidden) ifHidden();
|
||||
return jq;
|
||||
};
|
||||
|
||||
// caching for speedup
|
||||
$.uiTableFilter.last_phrase = ""
|
||||
|
||||
// not jQuery dependent
|
||||
// "" [""] -> Boolean
|
||||
// "" [""] Boolean -> Boolean
|
||||
$.uiTableFilter.has_words = function (str, words, caseSensitive) {
|
||||
var text = caseSensitive ? str : str.toLowerCase();
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
if (text.indexOf(words[i]) === -1) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,4 @@
|
||||
/*! jQuery Validation Plugin - v1.21.0 - 7/17/2024
|
||||
* https://jqueryvalidation.org/
|
||||
* Copyright (c) 2024 Jörn Zaefferer; Licensed MIT */
|
||||
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.on("click.validate",":submit",function(b){c.submitButton=b.currentTarget,a(this).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(this).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.on("submit.validate",function(b){function d(){var d,e;return c.submitButton&&(c.settings.submitHandler||c.formSubmitted)&&(d=a("<input type='hidden'/>").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),!(c.settings.submitHandler&&!c.settings.debug)||(e=c.settings.submitHandler.call(c,c.currentForm,b),d&&d.remove(),void 0!==e&&e)}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){var d,e,f,g,h,i,j=this[0],k="undefined"!=typeof this.attr("contenteditable")&&"false"!==this.attr("contenteditable");if(null!=j&&(!j.form&&k&&(j.form=this.closest("form")[0],j.name=this.attr("name")),null!=j.form)){if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(a,b){i[b]=f[b],delete f[b]}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g)),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}});var b=function(a){return a.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")};a.extend(a.expr.pseudos||a.expr[":"],{blank:function(c){return!b(""+a(c).val())},filled:function(c){var d=a(c).val();return null!==d&&!!b(""+d)},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",pendingClass:"pending",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,customElements:[],onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||a.inArray(c.keyCode,d)!==-1||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {Line truncated
|
||||
Vendored
+163
@@ -0,0 +1,163 @@
|
||||
/*!
|
||||
* JavaScript Cookie v2.2.1
|
||||
* https://github.com/js-cookie/js-cookie
|
||||
*
|
||||
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
|
||||
* Released under the MIT license
|
||||
*/
|
||||
;(function (factory) {
|
||||
var registeredInModuleLoader;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (!registeredInModuleLoader) {
|
||||
var OldCookies = window.Cookies;
|
||||
var api = window.Cookies = factory();
|
||||
api.noConflict = function () {
|
||||
window.Cookies = OldCookies;
|
||||
return api;
|
||||
};
|
||||
}
|
||||
}(function () {
|
||||
function extend () {
|
||||
var i = 0;
|
||||
var result = {};
|
||||
for (; i < arguments.length; i++) {
|
||||
var attributes = arguments[ i ];
|
||||
for (var key in attributes) {
|
||||
result[key] = attributes[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function decode (s) {
|
||||
return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
|
||||
}
|
||||
|
||||
function init (converter) {
|
||||
function api() {}
|
||||
|
||||
function set (key, value, attributes) {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
attributes = extend({
|
||||
path: '/'
|
||||
}, api.defaults, attributes);
|
||||
|
||||
if (typeof attributes.expires === 'number') {
|
||||
attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
|
||||
}
|
||||
|
||||
// We're using "expires" because "max-age" is not supported by IE
|
||||
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
|
||||
|
||||
try {
|
||||
var result = JSON.stringify(value);
|
||||
if (/^[\{\[]/.test(result)) {
|
||||
value = result;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
value = converter.write ?
|
||||
converter.write(value, key) :
|
||||
encodeURIComponent(String(value))
|
||||
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
||||
|
||||
key = encodeURIComponent(String(key))
|
||||
.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
|
||||
.replace(/[\(\)]/g, escape);
|
||||
|
||||
var stringifiedAttributes = '';
|
||||
for (var attributeName in attributes) {
|
||||
if (!attributes[attributeName]) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '; ' + attributeName;
|
||||
if (attributes[attributeName] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Considers RFC 6265 section 5.2:
|
||||
// ...
|
||||
// 3. If the remaining unparsed-attributes contains a %x3B (";")
|
||||
// character:
|
||||
// Consume the characters of the unparsed-attributes up to,
|
||||
// not including, the first %x3B (";") character.
|
||||
// ...
|
||||
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
|
||||
}
|
||||
|
||||
return (document.cookie = key + '=' + value + stringifiedAttributes);
|
||||
}
|
||||
|
||||
function get (key, json) {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var jar = {};
|
||||
// To prevent the for loop in the first place assign an empty array
|
||||
// in case there are no cookies at all.
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
var i = 0;
|
||||
|
||||
for (; i < cookies.length; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var cookie = parts.slice(1).join('=');
|
||||
|
||||
if (!json && cookie.charAt(0) === '"') {
|
||||
cookie = cookie.slice(1, -1);
|
||||
}
|
||||
|
||||
try {
|
||||
var name = decode(parts[0]);
|
||||
cookie = (converter.read || converter)(cookie, name) ||
|
||||
decode(cookie);
|
||||
|
||||
if (json) {
|
||||
try {
|
||||
cookie = JSON.parse(cookie);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
jar[name] = cookie;
|
||||
|
||||
if (key === name) {
|
||||
break;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return key ? jar[key] : jar;
|
||||
}
|
||||
|
||||
api.set = set;
|
||||
api.get = function (key) {
|
||||
return get(key, false /* read as raw */);
|
||||
};
|
||||
api.getJSON = function (key) {
|
||||
return get(key, true /* read as json */);
|
||||
};
|
||||
api.remove = function (key, attributes) {
|
||||
set(key, '', extend(attributes, {
|
||||
expires: -1
|
||||
}));
|
||||
};
|
||||
|
||||
api.defaults = {};
|
||||
|
||||
api.withConverter = init;
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
return init(function () {});
|
||||
}));
|
||||
+37460
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"OpenLayers.js","mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;;;;;;ACVA,eAAe,KAAoD,oBAAoB,CAAqE,CAAC,iBAAiB,aAAa,sBAAsB,uBAAuB,KAAK,IAAI,EAAE,YAAY,8KAA8K,aAAa,mBAAmB,mCAAmC,IAAI,EAAE,qBAAqB,YAAY,KAAK,KAAK,YAAY,KAAK,+DAA+D,8BAA8B,kBAAkB,WAAW,iBAAiB,gBAAgB,sBAAsB,kBAAkB,2HAA2H,kBAAkB,0BAA0B,YAAY,WAAW,0BAA0B,SAAS,gBAAgB,6BAA6B,sBAAsB,6DAA6D,YAAY,IAAI,KAAK,oBAAoB,mBAAmB,SAAS,gBAAgB,qIAAqI,gBAAgB,qBAAqB,gBAAgB,qBAAqB,cAAc,sCAAsC,cAAc,qCAAqC,gBAAgB,sEAAsE,gBAAgB,sEAAsE,cAAc,OAAO,mEAAmE,sBAAsB,gBAAgB,SAAS,mCAAmC,+BAA+B,8BAA8B,kCAAkC,+BAA+B,gCAAgC,qBAAqB,oBAAoB,2BAA2B,EAAE,EAAE,YAAY,oBAAoB,KAAK,oCAAoC,2DAA2D,UAAU,SAAS,kCAAkC,gBAAgB,oBAAoB,aAAa,EAAE,EAAE,YAAY,oBAAoB,KAAK,8CAA8C,WAAW,2BAA2B,WAAW,UAAU,SAAS,8BAA8B,6BAA6B,8BAA8B,YAAY,WAAW,sBAAsB,YAAY,4CAA4C,yFAAyF,KAAK,8BAA8B,gBAAgB,gBAAgB,+CAA+C,iBAAiB,YAAY,gCAAgC,kDAAkD,8BAA8B,4BAA4B,kCAAkC,kBAAkB,qDAAqD,YAAY,EAAE,yDAAyD,wBAAwB,yEAAyE,qGAAqG,YAAY,gCAAgC,SAAS,uCAAuC,qBAAqB,uCAAuC,qBAAqB,+BAA+B,iBAAiB,kCAAkC,wBAAwB,gCAAgC,aAAa,EAAE,wEAAwE,SAAS,sCAAsC,iCAAiC,oDAAoD,sGAAsG,iDAAiD,4BAA4B,YAAY,KAAK,MAAM,wBAAwB,4BAA4B,YAAY,KAAK,MAAM,wBAAwB,yCAAyC,0BAA0B,8CAA8C,KAAK,kCAAkC,EAAE,iCAAiC,oBAAoB,KAAK,6IAA6I,8CAA8C,mBAAmB,QAAQ,SAAS,qCAAqC,qEAAqE,8BAA8B,4CAA4C,sBAAsB,gCAAgC,kCAAkC,kDAAkD,6BAA6B,kFAAkF,iHAAiH,sCAAsC,0FAA0F,+CAA+C,sCAAsC,OAAO,KAAK,sPAAsP,8CAA8C,cAAc,8CAA8C,4DAA4D,8EAA8E,8CAA8C,mBAAmB,kEAAkE,MAAM,KAAK,oBAAoB,2BAA2B,gBAAgB,KAAK,KAAK,oBAAoB,2BAA2B,SAAS,iDAAiD,YAAY,KAAK,cAAc,mCAAmC,8BAA8B,KAAK,gHAAgH,GAAG;;;;;;;UCA7zM;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA,8CAA8C;;;;;;;;;;;;;;;ACA9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,qCAAqC;AACzC;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA,WAAW,oCAAoC;AAC/C;AACO;AACP;AACA;AACA;AACA,WAAW,oCAAoC;AAC/C;AACO;AACP;AACA;AACA,0CAAe,SAAS,EAAC;AACzB;;ACrEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA,oDAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;AACF;AACA,aAAa,kBAAkB;AAC/B;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,kDAAe,UAAU,EAAC;AAC1B;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,GAAG;AACd,WAAW,UAAU;AACrB,YAAY,QAAQ;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,WAAW,GAAG;AACd,YAAY,QAAQ;AACpB;AACA;AACO;AACP;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,GAAG;AACd,YAAY,SAAS;AACrB;AACO;AACP;AACA;AACA;AACA,IAAI,8DAA8D;AAClE;AACA;AACA,2BAA2B,OAAO;AAClC,OAAO,OAAO;AACd,OAAO,OAAO;AACd,gCAAgC,OAAO;AACvC;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA,WAAW,eAAe;AAC1B,WAAW,QAAQ;AACnB,WAAW,iCAAiC;AAC5C;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,OAAO;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,OAAO;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,OAAO;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,cAAc;AACzB,WAAW,qBAAqB;AAChC;AACA;AACO,SAAS,YAAM;AACtB;AACA;AACA,oBAAoB,YAAY;AAChC;AACA;AACA;AACA;AACA,WAAW,cAAc;AACzB,WAAW,OAAO;AAClB;AACA,YAAY,SAAS;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,cAAc;AACzB,WAAW,sCAAsC;AACjD;AACA,YAAY,YAAY;AACxB;AACO;AACP;AACA;AACA,oBAAoB,YAAY;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,yBAAyB;AACpC,WAAW,yBAAyB;AACpC,YAAY,SAAS;AACrB;AACO;AACP;AACA;AACA;AACA;AACA,oBAAoB,UAAU;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,yBAAyB;AACpC;AACA;AACO;AACP;AACA;AACA;AACA,gBAAgB,YAAY;AAC5B,mBAAmB;AACnB;AACA;AACA;AACA,KAAK;AACL,gBAAgB,gBAAgB;AAChC;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,UAAU;AACrB,YAAY,QAAQ;AACpB;AACO;AACP;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,UAAU;AACrB,WAAW,SAAS;AACpB,YAAY,SAAS;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AC3PA;AACA;AACA;AACmD;AACnD;AACA;AACA,YAAY,SAAS;AACrB;AACO;AACP;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACO,SAAS,eAAK;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,MAAM;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA,WAAW,8BAA8B;AACzC,YAAY,8BAA8B;AAC1C;AACA;AACO;AACP;AACA,eAAe,YAAY;AAC3B;AACA,eAAe,YAAY;AAC3B;AACA;AACA;AACA;AACA,6CAA6C,MAAW;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,8BAA8B;AACzC,YAAY,YAAY;AACxB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,WAAW;AACtB,YAAY,SAAS;AACrB;AACO,IAAI,UAAM;AACjLine truncated
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
.ol-box {
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
border: 1.5px solid rgb(179,197,219);
|
||||
background-color: rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
.ol-mouse-position {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.ol-scale-line {
|
||||
background: rgba(0,60,136,0.3);
|
||||
border-radius: 4px;
|
||||
bottom: 8px;
|
||||
left: 8px;
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
}
|
||||
.ol-scale-line-inner {
|
||||
border: 1px solid #eee;
|
||||
border-top: none;
|
||||
color: #eee;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
margin: 1px;
|
||||
will-change: contents, width;
|
||||
transition: all 0.25s;
|
||||
}
|
||||
.ol-scale-singlebar-even{
|
||||
background-color: #000000;
|
||||
}
|
||||
.ol-scale-singlebar-odd{
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.ol-scale-bar {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 8px;
|
||||
}
|
||||
.ol-scale-step-marker {
|
||||
width: 1px;
|
||||
height: 15px;
|
||||
background-color: #000000;
|
||||
float: right;
|
||||
z-index: 10;
|
||||
}
|
||||
.ol-scale-step-text {
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
font-size: 12px;
|
||||
z-index: 11;
|
||||
color: #000000;
|
||||
text-shadow: -2px 0 #FFFFFF, 0 2px #FFFFFF, 2px 0 #FFFFFF, 0 -2px #FFFFFF;
|
||||
}
|
||||
.ol-scale-text {
|
||||
position: absolute;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
bottom: 25px;
|
||||
color: #000000;
|
||||
text-shadow: -2px 0 #FFFFFF, 0 2px #FFFFFF, 2px 0 #FFFFFF, 0 -2px #FFFFFF;
|
||||
}
|
||||
.ol-scale-singlebar {
|
||||
position: relative;
|
||||
height: 10px;
|
||||
z-index: 9;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.ol-unsupported {
|
||||
display: none;
|
||||
}
|
||||
.ol-viewport, .ol-unselectable {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
.ol-viewport canvas {
|
||||
all: unset;
|
||||
}
|
||||
.ol-selectable {
|
||||
-webkit-touch-callout: default;
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
.ol-grabbing {
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
.ol-grab {
|
||||
cursor: move;
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.ol-control {
|
||||
position: absolute;
|
||||
background-color: rgba(255,255,255,0.4);
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
}
|
||||
.ol-control:hover {
|
||||
background-color: rgba(255,255,255,0.6);
|
||||
}
|
||||
.ol-zoom {
|
||||
top: .5em;
|
||||
left: .5em;
|
||||
}
|
||||
.ol-rotate {
|
||||
top: .5em;
|
||||
right: .5em;
|
||||
transition: opacity .25s linear, visibility 0s linear;
|
||||
}
|
||||
.ol-rotate.ol-hidden {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity .25s linear, visibility 0s linear .25s;
|
||||
}
|
||||
.ol-zoom-extent {
|
||||
top: 4.643em;
|
||||
left: .5em;
|
||||
}
|
||||
.ol-full-screen {
|
||||
right: .5em;
|
||||
top: .5em;
|
||||
}
|
||||
|
||||
.ol-control button {
|
||||
display: block;
|
||||
margin: 1px;
|
||||
padding: 0;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
font-size: inherit;
|
||||
text-align: center;
|
||||
height: 1.375em;
|
||||
width: 1.375em;
|
||||
line-height: .4em;
|
||||
background-color: rgba(0,60,136,0.5);
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.ol-control button::-moz-focus-inner {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
.ol-zoom-extent button {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
.ol-compass {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
font-size: 1.2em;
|
||||
will-change: transform;
|
||||
}
|
||||
.ol-touch .ol-control button {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.ol-touch .ol-zoom-extent {
|
||||
top: 5.5em;
|
||||
}
|
||||
.ol-control button:hover,
|
||||
.ol-control button:focus {
|
||||
text-decoration: none;
|
||||
background-color: rgba(0,60,136,0.7);
|
||||
}
|
||||
.ol-zoom .ol-zoom-in {
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
.ol-zoom .ol-zoom-out {
|
||||
border-radius: 0 0 2px 2px;
|
||||
}
|
||||
|
||||
|
||||
.ol-attribution {
|
||||
text-align: right;
|
||||
bottom: .5em;
|
||||
right: .5em;
|
||||
max-width: calc(100% - 1.3em);
|
||||
display: flex;
|
||||
flex-flow: row-reverse;
|
||||
align-items: center;
|
||||
}
|
||||
.ol-attribution a {
|
||||
color: rgba(0,60,136,0.7);
|
||||
text-decoration: none;
|
||||
}
|
||||
.ol-attribution ul {
|
||||
margin: 0;
|
||||
padding: 1px .5em;
|
||||
color: #000;
|
||||
text-shadow: 0 0 2px #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
.ol-attribution li {
|
||||
display: inline;
|
||||
list-style: none;
|
||||
}
|
||||
.ol-attribution li:not(:last-child):after {
|
||||
content: " ";
|
||||
}
|
||||
.ol-attribution img {
|
||||
max-height: 2em;
|
||||
max-width: inherit;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ol-attribution button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ol-attribution.ol-collapsed ul {
|
||||
display: none;
|
||||
}
|
||||
.ol-attribution:not(.ol-collapsed) {
|
||||
background: rgba(255,255,255,0.8);
|
||||
}
|
||||
.ol-attribution.ol-uncollapsible {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-radius: 4px 0 0;
|
||||
}
|
||||
.ol-attribution.ol-uncollapsible img {
|
||||
margin-top: -.2em;
|
||||
max-height: 1.6em;
|
||||
}
|
||||
.ol-attribution.ol-uncollapsible button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ol-zoomslider {
|
||||
top: 4.5em;
|
||||
left: .5em;
|
||||
height: 200px;
|
||||
}
|
||||
.ol-zoomslider button {
|
||||
position: relative;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.ol-touch .ol-zoomslider {
|
||||
top: 5.5em;
|
||||
}
|
||||
|
||||
.ol-overviewmap {
|
||||
left: 0.5em;
|
||||
bottom: 0.5em;
|
||||
}
|
||||
.ol-overviewmap.ol-uncollapsible {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 0 4px 0 0;
|
||||
}
|
||||
.ol-overviewmap .ol-overviewmap-map,
|
||||
.ol-overviewmap button {
|
||||
display: block;
|
||||
}
|
||||
.ol-overviewmap .ol-overviewmap-map {
|
||||
border: 1px solid #7b98bc;
|
||||
height: 150px;
|
||||
margin: 2px;
|
||||
width: 150px;
|
||||
}
|
||||
.ol-overviewmap:not(.ol-collapsed) button {
|
||||
bottom: 2px;
|
||||
left: 2px;
|
||||
position: absolute;
|
||||
}
|
||||
.ol-overviewmap.ol-collapsed .ol-overviewmap-map,
|
||||
.ol-overviewmap.ol-uncollapsible button {
|
||||
display: none;
|
||||
}
|
||||
.ol-overviewmap:not(.ol-collapsed) {
|
||||
background: rgba(255,255,255,0.8);
|
||||
}
|
||||
.ol-overviewmap-box {
|
||||
border: 2px dotted rgba(0,60,136,0.7);
|
||||
}
|
||||
|
||||
.ol-overviewmap .ol-overviewmap-box:hover {
|
||||
cursor: move;
|
||||
}
|
||||
Vendored
+212
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright (c) 2007-2024 Kevin van Zonneveld (https://kvz.io)
|
||||
* and Contributors (https://locutus.io/authors)
|
||||
*
|
||||
* 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 sprintf () {
|
||||
// discuss at: https://locutus.io/php/sprintf/
|
||||
// original by: Ash Searle (https://hexmen.com/blog/)
|
||||
// improved by: Michael White (https://getsprink.com)
|
||||
// improved by: Jack
|
||||
// improved by: Kevin van Zonneveld (https://kvz.io)
|
||||
// improved by: Kevin van Zonneveld (https://kvz.io)
|
||||
// improved by: Kevin van Zonneveld (https://kvz.io)
|
||||
// improved by: Dj
|
||||
// improved by: Allidylls
|
||||
// input by: Paulo Freitas
|
||||
// input by: Brett Zamir (https://brett-zamir.me)
|
||||
// improved by: Rafał Kukawski (https://kukawski.pl)
|
||||
// example 1: sprintf("%01.2f", 123.1)
|
||||
// returns 1: '123.10'
|
||||
// example 2: sprintf("[%10s]", 'monkey')
|
||||
// returns 2: '[ monkey]'
|
||||
// example 3: sprintf("[%'#10s]", 'monkey')
|
||||
// returns 3: '[####monkey]'
|
||||
// example 4: sprintf("%d", 123456789012345)
|
||||
// returns 4: '123456789012345'
|
||||
// example 5: sprintf('%-03s', 'E')
|
||||
// returns 5: 'E00'
|
||||
// example 6: sprintf('%+010d', 9)
|
||||
// returns 6: '+000000009'
|
||||
// example 7: sprintf('%+0\'@10d', 9)
|
||||
// returns 7: '@@@@@@@@+9'
|
||||
// example 8: sprintf('%.f', 3.14)
|
||||
// returns 8: '3.140000'
|
||||
// example 9: sprintf('%% %2$d', 1, 2)
|
||||
// returns 9: '% 2'
|
||||
|
||||
var regex = /%%|%(?:(\d+)\$)?((?:[-+#0 ]|'[\s\S])*)(\d+)?(?:\.(\d*))?([\s\S])/g
|
||||
var args = arguments
|
||||
var i = 0
|
||||
var format = args[i++]
|
||||
|
||||
var _pad = function (str, len, chr, leftJustify) {
|
||||
if (!chr) {
|
||||
chr = ' '
|
||||
}
|
||||
const padding = str.length >= len ? '' : new Array((1 + len - str.length) >>> 0).join(chr)
|
||||
return leftJustify ? str + padding : padding + str
|
||||
}
|
||||
|
||||
var justify = function (value, prefix, leftJustify, minWidth, padChar) {
|
||||
var diff = minWidth - value.length
|
||||
if (diff > 0) {
|
||||
// when padding with zeros
|
||||
// on the left side
|
||||
// keep sign (+ or -) in front
|
||||
if (!leftJustify && padChar === '0') {
|
||||
value = [value.slice(0, prefix.length), _pad('', diff, '0', true), value.slice(prefix.length)].join('')
|
||||
} else {
|
||||
value = _pad(value, minWidth, padChar, leftJustify)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
var _formatBaseX = function (value, base, leftJustify, minWidth, precision, padChar) {
|
||||
// Note: casts negative numbers to positive ones
|
||||
var number = value >>> 0
|
||||
value = _pad(number.toString(base), precision || 0, '0', false)
|
||||
return justify(value, '', leftJustify, minWidth, padChar)
|
||||
}
|
||||
|
||||
// _formatString()
|
||||
var _formatString = function (value, leftJustify, minWidth, precision, customPadChar) {
|
||||
if (precision !== null && precision !== undefined) {
|
||||
value = value.slice(0, precision)
|
||||
}
|
||||
return justify(value, '', leftJustify, minWidth, customPadChar)
|
||||
}
|
||||
|
||||
// doFormat()
|
||||
var doFormat = function (substring, argIndex, modifiers, minWidth, precision, specifier) {
|
||||
var number, prefix, method, textTransform, value
|
||||
|
||||
if (substring === '%%') {
|
||||
return '%'
|
||||
}
|
||||
|
||||
// parse modifiers
|
||||
var padChar = ' ' // pad with spaces by default
|
||||
var leftJustify = false
|
||||
var positiveNumberPrefix = ''
|
||||
var j, l
|
||||
|
||||
for (j = 0, l = modifiers.length; j < l; j++) {
|
||||
switch (modifiers.charAt(j)) {
|
||||
case ' ':
|
||||
case '0':
|
||||
padChar = modifiers.charAt(j)
|
||||
break
|
||||
case '+':
|
||||
positiveNumberPrefix = '+'
|
||||
break
|
||||
case '-':
|
||||
leftJustify = true
|
||||
break
|
||||
case "'":
|
||||
if (j + 1 < l) {
|
||||
padChar = modifiers.charAt(j + 1)
|
||||
j++
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!minWidth) {
|
||||
minWidth = 0
|
||||
} else {
|
||||
minWidth = +minWidth
|
||||
}
|
||||
|
||||
if (!isFinite(minWidth)) {
|
||||
throw new Error('Width must be finite')
|
||||
}
|
||||
|
||||
if (!precision) {
|
||||
precision = specifier === 'd' ? 0 : 'fFeE'.indexOf(specifier) > -1 ? 6 : undefined
|
||||
} else {
|
||||
precision = +precision
|
||||
}
|
||||
|
||||
if (argIndex && +argIndex === 0) {
|
||||
throw new Error('Argument number must be greater than zero')
|
||||
}
|
||||
|
||||
if (argIndex && +argIndex >= args.length) {
|
||||
throw new Error('Too few arguments')
|
||||
}
|
||||
|
||||
value = argIndex ? args[+argIndex] : args[i++]
|
||||
|
||||
switch (specifier) {
|
||||
case '%':
|
||||
return '%'
|
||||
case 's':
|
||||
return _formatString(value + '', leftJustify, minWidth, precision, padChar)
|
||||
case 'c':
|
||||
return _formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, padChar)
|
||||
case 'b':
|
||||
return _formatBaseX(value, 2, leftJustify, minWidth, precision, padChar)
|
||||
case 'o':
|
||||
return _formatBaseX(value, 8, leftJustify, minWidth, precision, padChar)
|
||||
case 'x':
|
||||
return _formatBaseX(value, 16, leftJustify, minWidth, precision, padChar)
|
||||
case 'X':
|
||||
return _formatBaseX(value, 16, leftJustify, minWidth, precision, padChar).toUpperCase()
|
||||
case 'u':
|
||||
return _formatBaseX(value, 10, leftJustify, minWidth, precision, padChar)
|
||||
case 'i':
|
||||
case 'd':
|
||||
number = +value || 0
|
||||
// Plain Math.round doesn't just truncate
|
||||
number = Math.round(number - (number % 1))
|
||||
prefix = number < 0 ? '-' : positiveNumberPrefix
|
||||
value = prefix + _pad(String(Math.abs(number)), precision, '0', false)
|
||||
|
||||
if (leftJustify && padChar === '0') {
|
||||
// can't right-pad 0s on integers
|
||||
padChar = ' '
|
||||
}
|
||||
return justify(value, prefix, leftJustify, minWidth, padChar)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f': // @todo: Should handle locales (as per setlocale)
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
number = +value
|
||||
prefix = number < 0 ? '-' : positiveNumberPrefix
|
||||
method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(specifier.toLowerCase())]
|
||||
textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(specifier) % 2]
|
||||
value = prefix + Math.abs(number)[method](precision)
|
||||
return justify(value, prefix, leftJustify, minWidth, padChar)[textTransform]()
|
||||
default:
|
||||
// unknown specifier, consume that char and return empty
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return format.replace(regex, doFormat)
|
||||
} catch (err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
Vendored
+1327
File diff suppressed because it is too large.
Load diff
+762
@@ -0,0 +1,762 @@
|
||||
//Copyright 2014-2015 Google Inc. All rights reserved.
|
||||
|
||||
//Use of this source code is governed by a BSD-style
|
||||
//license that can be found in the LICENSE file or at
|
||||
//https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
// NOTE FROM MAINTAINER: This file is copied from google/u2f-ref-code with as
|
||||
// few alterations as possible. Any changes that were necessary are annotated
|
||||
// with "NECESSARY CHANGE". These changes, as well as this note, should be
|
||||
// preserved when updating this file from the source.
|
||||
|
||||
/**
|
||||
* @fileoverview The U2F api.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// NECESSARY CHANGE: wrap the whole file in a closure
|
||||
(function (){
|
||||
// NECESSARY CHANGE: detect UA to avoid clobbering other browser's U2F API.
|
||||
var isChrome = 'chrome' in window && window.navigator.userAgent.indexOf('Edge') < 0;
|
||||
if ('u2f' in window || !isChrome) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Namespace for the U2F api.
|
||||
* @type {Object}
|
||||
*/
|
||||
// NECESSARY CHANGE: define the window.u2f API.
|
||||
var u2f = window.u2f = {};
|
||||
|
||||
/**
|
||||
* FIDO U2F Javascript API Version
|
||||
* @number
|
||||
*/
|
||||
var js_api_version;
|
||||
|
||||
/**
|
||||
* The U2F extension id
|
||||
* @const {string}
|
||||
*/
|
||||
// The Chrome packaged app extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the package Chrome app and does not require installing the U2F Chrome extension.
|
||||
u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
|
||||
// The U2F Chrome extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the U2F Chrome extension to authenticate.
|
||||
// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
|
||||
|
||||
|
||||
/**
|
||||
* Message types for messsages to/from the extension
|
||||
* @const
|
||||
* @enum {string}
|
||||
*/
|
||||
u2f.MessageTypes = {
|
||||
'U2F_REGISTER_REQUEST': 'u2f_register_request',
|
||||
'U2F_REGISTER_RESPONSE': 'u2f_register_response',
|
||||
'U2F_SIGN_REQUEST': 'u2f_sign_request',
|
||||
'U2F_SIGN_RESPONSE': 'u2f_sign_response',
|
||||
'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
|
||||
'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Response status codes
|
||||
* @const
|
||||
* @enum {number}
|
||||
*/
|
||||
u2f.ErrorCodes = {
|
||||
'OK': 0,
|
||||
'OTHER_ERROR': 1,
|
||||
'BAD_REQUEST': 2,
|
||||
'CONFIGURATION_UNSUPPORTED': 3,
|
||||
'DEVICE_INELIGIBLE': 4,
|
||||
'TIMEOUT': 5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration requests
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* appId: ?string,
|
||||
* timeoutSeconds: ?number,
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fRequest;
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration responses
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fResponse;
|
||||
|
||||
|
||||
/**
|
||||
* An error object for responses
|
||||
* @typedef {{
|
||||
* errorCode: u2f.ErrorCodes,
|
||||
* errorMessage: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.Error;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC, USB_INTERNAL}}
|
||||
*/
|
||||
u2f.Transport;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {Array<u2f.Transport>}
|
||||
*/
|
||||
u2f.Transports;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string,
|
||||
* keyHandle: string,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a sign response.
|
||||
* @typedef {{
|
||||
* keyHandle: string,
|
||||
* signatureData: string,
|
||||
* clientData: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration response.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: Transports,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registered key.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: ?Transports,
|
||||
* appId: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisteredKey;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a get API register response.
|
||||
* @typedef {{
|
||||
* js_api_version: number
|
||||
* }}
|
||||
*/
|
||||
u2f.GetJsApiVersionResponse;
|
||||
|
||||
|
||||
//Low level MessagePort API support
|
||||
|
||||
/**
|
||||
* Sets up a MessagePort to the U2F extension using the
|
||||
* available mechanisms.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
*/
|
||||
u2f.getMessagePort = function(callback) {
|
||||
if (typeof chrome != 'undefined' && chrome.runtime) {
|
||||
// The actual message here does not matter, but we need to get a reply
|
||||
// for the callback to run. Thus, send an empty signature request
|
||||
// in order to get a failure response.
|
||||
var msg = {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: []
|
||||
};
|
||||
chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
// We are on a whitelisted origin and can talk directly
|
||||
// with the extension.
|
||||
u2f.getChromeRuntimePort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was available, but we couldn't message
|
||||
// the extension directly, use iframe
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
});
|
||||
} else if (u2f.isAndroidChrome_()) {
|
||||
u2f.getAuthenticatorPort_(callback);
|
||||
} else if (u2f.isIosChrome_()) {
|
||||
u2f.getIosPort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was not available at all, which is normal
|
||||
// when this origin doesn't have access to any extensions.
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on android based on the browser's useragent.
|
||||
* @private
|
||||
*/
|
||||
u2f.isAndroidChrome_ = function() {
|
||||
var userAgent = navigator.userAgent;
|
||||
return userAgent.indexOf('Chrome') != -1 &&
|
||||
userAgent.indexOf('Android') != -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on iOS based on the browser's platform.
|
||||
* @private
|
||||
*/
|
||||
u2f.isIosChrome_ = function() {
|
||||
return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects directly to the extension via chrome.runtime.connect.
|
||||
* @param {function(u2f.WrappedChromeRuntimePort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getChromeRuntimePort_ = function(callback) {
|
||||
var port = chrome.runtime.connect(u2f.EXTENSION_ID,
|
||||
{'includeTlsChannelId': true});
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedChromeRuntimePort_(port));
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the Authenticator app.
|
||||
* @param {function(u2f.WrappedAuthenticatorPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getAuthenticatorPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedAuthenticatorPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the iOS client app.
|
||||
* @param {function(u2f.WrappedIosPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIosPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedIosPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for chrome.runtime.Port that is compatible with MessagePort.
|
||||
* @param {Port} port
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_ = function(port) {
|
||||
this.port_ = port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a sign request compliant with the JS API version supported by the extension.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatSignRequest_ =
|
||||
function(appId, challenge, registeredKeys, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: challenge,
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: signRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
appId: appId,
|
||||
challenge: challenge,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a register request compliant with the JS API version supported by the extension..
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {Array<u2f.RegisterRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatRegisterRequest_ =
|
||||
function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
for (var i = 0; i < registerRequests.length; i++) {
|
||||
registerRequests[i].appId = appId;
|
||||
}
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: registerRequests[0],
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
signRequests: signRequests,
|
||||
registerRequests: registerRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
appId: appId,
|
||||
registerRequests: registerRequests,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Posts a message on the underlying channel.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
|
||||
this.port_.postMessage(message);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface. Works only for the
|
||||
* onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
|
||||
function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message' || name == 'onmessage') {
|
||||
this.port_.onMessage.addListener(function(message) {
|
||||
// Emulate a minimal MessageEvent object
|
||||
handler({'data': message});
|
||||
});
|
||||
} else {
|
||||
console.error('WrappedChromeRuntimePort only supports onMessage');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the Authenticator app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_ = function() {
|
||||
this.requestId_ = -1;
|
||||
this.requestObject_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the Authenticator intent.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
|
||||
var intentUrl =
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||||
';S.request=' + encodeURIComponent(JSON.stringify(message)) +
|
||||
';end';
|
||||
document.location = intentUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() {
|
||||
return "WrappedAuthenticatorPort_";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message') {
|
||||
var self = this;
|
||||
/* Register a callback to that executes when
|
||||
* chrome injects the response. */
|
||||
window.addEventListener(
|
||||
'message', self.onRequestUpdate_.bind(self, handler), false);
|
||||
} else {
|
||||
console.error('WrappedAuthenticatorPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when a response is received from the Authenticator.
|
||||
* @param function({data: Object}) callback
|
||||
* @param {Object} message message Object
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
|
||||
function(callback, message) {
|
||||
var messageObject = JSON.parse(message.data);
|
||||
var intentUrl = messageObject['intentURL'];
|
||||
|
||||
var errorCode = messageObject['errorCode'];
|
||||
var responseObject = null;
|
||||
if (messageObject.hasOwnProperty('data')) {
|
||||
responseObject = /** @type {Object} */ (
|
||||
JSON.parse(messageObject['data']));
|
||||
}
|
||||
|
||||
callback({'data': responseObject});
|
||||
};
|
||||
|
||||
/**
|
||||
* Base URL for intents to Authenticator.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
|
||||
'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
|
||||
|
||||
/**
|
||||
* Wrap the iOS client app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedIosPort_ = function() {};
|
||||
|
||||
/**
|
||||
* Launch the iOS client app request
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.postMessage = function(message) {
|
||||
var str = JSON.stringify(message);
|
||||
var url = "u2f://auth?" + encodeURI(str);
|
||||
location.replace(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.getPortType = function() {
|
||||
return "WrappedIosPort_";
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name !== 'message') {
|
||||
console.error('WrappedIosPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up an embedded trampoline iframe, sourced from the extension.
|
||||
* @param {function(MessagePort)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIframePort_ = function(callback) {
|
||||
// Create the iframe
|
||||
var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = iframeOrigin + '/u2f-comms.html';
|
||||
iframe.setAttribute('style', 'display:none');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var channel = new MessageChannel();
|
||||
var ready = function(message) {
|
||||
if (message.data == 'ready') {
|
||||
channel.port1.removeEventListener('message', ready);
|
||||
callback(channel.port1);
|
||||
} else {
|
||||
console.error('First event on iframe port was not "ready"');
|
||||
}
|
||||
};
|
||||
channel.port1.addEventListener('message', ready);
|
||||
channel.port1.start();
|
||||
|
||||
iframe.addEventListener('load', function() {
|
||||
// Deliver the port to the iframe and initialize
|
||||
iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//High-level JS API
|
||||
|
||||
/**
|
||||
* Default extension response timeout in seconds.
|
||||
* @const
|
||||
*/
|
||||
u2f.EXTENSION_TIMEOUT_SEC = 30;
|
||||
|
||||
/**
|
||||
* A singleton instance for a MessagePort to the extension.
|
||||
* @type {MessagePort|u2f.WrappedChromeRuntimePort_}
|
||||
* @private
|
||||
*/
|
||||
u2f.port_ = null;
|
||||
|
||||
/**
|
||||
* Callbacks waiting for a port
|
||||
* @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.waitingForPort_ = [];
|
||||
|
||||
/**
|
||||
* A counter for requestIds.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
u2f.reqCounter_ = 0;
|
||||
|
||||
/**
|
||||
* A map from requestIds to client callbacks
|
||||
* @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
|
||||
* |function((u2f.Error|u2f.SignResponse)))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.callbackMap_ = {};
|
||||
|
||||
/**
|
||||
* Creates or retrieves the MessagePort singleton to use.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getPortSingleton_ = function(callback) {
|
||||
if (u2f.port_) {
|
||||
callback(u2f.port_);
|
||||
} else {
|
||||
if (u2f.waitingForPort_.length == 0) {
|
||||
u2f.getMessagePort(function(port) {
|
||||
u2f.port_ = port;
|
||||
u2f.port_.addEventListener('message',
|
||||
/** @type {function(Event)} */ (u2f.responseHandler_));
|
||||
|
||||
// Careful, here be async callbacks. Maybe.
|
||||
while (u2f.waitingForPort_.length)
|
||||
u2f.waitingForPort_.shift()(u2f.port_);
|
||||
});
|
||||
}
|
||||
u2f.waitingForPort_.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles response messages from the extension.
|
||||
* @param {MessageEvent.<u2f.Response>} message
|
||||
* @private
|
||||
*/
|
||||
u2f.responseHandler_ = function(message) {
|
||||
var response = message.data;
|
||||
var reqId = response['requestId'];
|
||||
if (!reqId || !u2f.callbackMap_[reqId]) {
|
||||
console.error('Unknown or missing requestId in response.');
|
||||
return;
|
||||
}
|
||||
var cb = u2f.callbackMap_[reqId];
|
||||
delete u2f.callbackMap_[reqId];
|
||||
cb(response['responseData']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the sign request.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual sign request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
|
||||
console.log("Extension JS API Version: ", js_api_version);
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual sign request in the supported API version.
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the register request.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual register request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
|
||||
console.log("Extension JS API Version: ", js_api_version);
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual register request in the supported API version.
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatRegisterRequest_(
|
||||
appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches a message to the extension to find out the supported
|
||||
* JS API version.
|
||||
* If the user is on a mobile phone and is thus using Google Authenticator instead
|
||||
* of the Chrome extension, don't send the request and simply return 0.
|
||||
* @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
// If we are using Android Google Authenticator or iOS client app,
|
||||
// do not fire an intent to ask which JS API version to use.
|
||||
if (port.getPortType) {
|
||||
var apiVersion;
|
||||
switch (port.getPortType()) {
|
||||
case 'WrappedIosPort_':
|
||||
case 'WrappedAuthenticatorPort_':
|
||||
apiVersion = 1.1;
|
||||
break;
|
||||
|
||||
default:
|
||||
apiVersion = 0;
|
||||
break;
|
||||
}
|
||||
callback({ 'js_api_version': apiVersion });
|
||||
return;
|
||||
}
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var req = {
|
||||
type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
|
||||
timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
|
||||
requestId: reqId
|
||||
};
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
})();
|
||||
Vendored
+2216
File diff suppressed because it is too large.
Load diff
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"zxcvbn-ts.js","sources":["../src/helper.ts","../src/data/dateSplits.ts","../src/data/const.ts","../src/matcher/date/matching.ts","../../../../node_modules/fastest-levenshtein/esm/mod.js","../src/levenshtein.ts","../src/data/l33tTable.ts","../src/data/translationKeys.ts","../src/Options.ts","../src/matcher/dictionary/variants/matching/reverse.ts","../src/matcher/dictionary/variants/matching/l33t.ts","../src/matcher/dictionary/matching.ts","../src/matcher/regex/matching.ts","../src/scoring/utils.ts","../src/matcher/bruteforce/scoring.ts","../src/matcher/date/scoring.ts","../src/matcher/dictionary/variants/scoring/uppercase.ts","../src/matcher/dictionary/variants/scoring/l33t.ts","../src/matcher/dictionary/scoring.ts","../src/matcher/regex/scoring.ts","../src/matcher/repeat/scoring.ts","../src/matcher/sequence/scoring.ts","../src/matcher/spatial/scoring.ts","../src/scoring/estimate.ts","../src/scoring/index.ts","../src/matcher/repeat/matching.ts","../src/matcher/sequence/matching.ts","../src/matcher/spatial/matching.ts","../src/Matching.ts","../src/TimeEstimates.ts","../src/matcher/bruteforce/feedback.ts","../src/matcher/date/feedback.ts","../src/matcher/dictionary/feedback.ts","../src/matcher/regex/feedback.ts","../src/matcher/repeat/feedback.ts","../src/matcher/sequence/feedback.ts","../src/matcher/spatial/feedback.ts","../src/Feedback.ts","../src/debounce.ts","../src/index.ts"],"sourcesContent":[null,null,null,null,"const peq = new Uint32Array(0x10000);\nconst myers_32 = (a, b) => {\n const n = a.length;\n const m = b.length;\n const lst = 1 << (n - 1);\n let pv = -1;\n let mv = 0;\n let sc = n;\n let i = n;\n while (i--) {\n peq[a.charCodeAt(i)] |= 1 << i;\n }\n for (i = 0; i < m; i++) {\n let eq = peq[b.charCodeAt(i)];\n const xv = eq | mv;\n eq |= ((eq & pv) + pv) ^ pv;\n mv |= ~(eq | pv);\n pv &= eq;\n if (mv & lst) {\n sc++;\n }\n if (pv & lst) {\n sc--;\n }\n mv = (mv << 1) | 1;\n pv = (pv << 1) | ~(xv | mv);\n mv &= xv;\n }\n i = n;\n while (i--) {\n peq[a.charCodeAt(i)] = 0;\n }\n return sc;\n};\nconst myers_x = (b, a) => {\n const n = a.length;\n const m = b.length;\n const mhc = [];\n const phc = [];\n const hsize = Math.ceil(n / 32);\n const vsize = Math.ceil(m / 32);\n for (let i = 0; i < hsize; i++) {\n phc[i] = -1;\n mhc[i] = 0;\n }\n let j = 0;\n for (; j < vsize - 1; j++) {\n let mv = 0;\n let pv = -1;\n const start = j * 32;\n const vlen = Math.min(32, m) + start;\n for (let k = start; k < vlen; k++) {\n peq[b.charCodeAt(k)] |= 1 << k;\n }\n for (let i = 0; i < n; i++) {\n const eq = peq[a.charCodeAt(i)];\n const pb = (phc[(i / 32) | 0] >>> i) & 1;\n const mb = (mhc[(i / 32) | 0] >>> i) & 1;\n const xv = eq | mv;\n const xh = ((((eq | mb) & pv) + pv) ^ pv) | eq | mb;\n let ph = mv | ~(xh | pv);\n let mh = pv & xh;\n if ((ph >>> 31) ^ pb) {\n phc[(i / 32) | 0] ^= 1 << i;\n }\n if ((mh >>> 31) ^ mb) {\n mhc[(i / 32) | 0] ^= 1 << i;\n }\n ph = (ph << 1) | pb;\n mh = (mh << 1) | mb;\n pv = mh | ~(xv | ph);\n mv = ph & xv;\n }\n for (let k = start; k < vlen; k++) {\n peq[b.charCodeAt(k)] = 0;\n }\n }\n let mv = 0;\n let pv = -1;\n const start = j * 32;\n const vlen = Math.min(32, m - start) + start;\n for (let k = start; k < vlen; k++) {\n peq[b.charCodeAt(k)] |= 1 << k;\n }\n let score = m;\n for (let i = 0; i < n; i++) {\n const eq = peq[a.charCodeAt(i)];\n const pb = (phc[(i / 32) | 0] >>> i) & 1;\n const mb = (mhc[(i / 32) | 0] >>> i) & 1;\n const xv = eq | mv;\n const xh = ((((eq | mb) & pv) + pv) ^ pv) | eq | mb;\n let ph = mv | ~(xh | pv);\n let mh = pv & xh;\n score += (ph >>> (m - 1)) & 1;\n score -= (mh >>> (m - 1)) & 1;\n if ((ph >>> 31) ^ pb) {\n phc[(i / 32) | 0] ^= 1 << i;\n }\n if ((mh >>> 31) ^ mb) {\n mhc[(i / 32) | 0] ^= 1 << i;\n }\n ph = (ph << 1) | pb;\n mh = (mh << 1) | mb;\n pv = mh | ~(xv | ph);\n mv = ph & xv;\n }\n for (let k = start; k < vlen; k++) {\n peq[b.charCodeAt(k)] = 0;\n }\n return score;\n};\nconst distance = (a, b) => {\n if (a.length < b.length) {\n const tmp = b;\n b = a;\n a = tmp;\n }\n if (b.length === 0) {\n return a.length;\n }\n if (a.length <= 32) {\n return myers_32(a, b);\n }\n return myers_x(a, b);\n};\nconst closest = (str, arr) => {\n let min_distance = Infinity;\n let min_index = 0;\nLine truncated
|
||||
Reference in new issue
Block a user