36930 lines
No EOL
1.4 MiB
36930 lines
No EOL
1.4 MiB
/*! jQuery v3.5.1 | (c) JS 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(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.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:u,sort:t.sort,splice:t.splice},S.extend=S.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||m(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&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+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]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(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},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},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(p(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:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(D).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\s*(?:[^=]|=\s*.checked.)/i,je=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(je,""),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px",t.style.height="1px",n.style.height="9px",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=["Webkit","Moz","ms"],ze=E.createElement("div").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:"absolute",visibility:"hidden",display:"block"},Qe={letterSpacing:"0",fontWeight:"400"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Qe&&(i=Qe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt("show"),slideUp:lt("hide"),slideToggle:lt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement("input"),it=E.createElement("select").appendChild(E.createElement("option")),rt.type="checkbox",y.checkOn=""!==rt.value,y.optSelected=it.selected,(rt=E.createElement("input")).value="t",rt.type="radio",y.radioValue="t"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function mt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr("class","");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=yt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+vt(yt(n))+" ").indexOf(t))return!0;return!1}});var xt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(xt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:vt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||S.error("Invalid XML: "+e),t};var St=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)Dt(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\/\//,Rt={},Mt={},It="*/".concat("*"),Wt=E.createElement("a");function Ft(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":It,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+"//"+Wt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(jt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Et.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,"$1"),o=(Et.test(f)?"&":"?")+"_="+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+It+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&"withCredentials"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Gt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
|
||
var Jupyter = Jupyter || {};
|
||
|
||
var jprop = function(name, module_path){
|
||
Object.defineProperty(Jupyter, name, {
|
||
get: function() {
|
||
console.warn('accessing `'+name+'` is deprecated. Use `requirejs("'+module_path+'")`');
|
||
return requirejs(module_path);
|
||
},
|
||
enumerable: true,
|
||
configurable: false
|
||
});
|
||
}
|
||
|
||
var jglobal = function(name, module_path){
|
||
Object.defineProperty(Jupyter, name, {
|
||
get: function() {
|
||
console.warn('accessing `'+name+'` is deprecated. Use `requirejs("'+module_path+'").'+name+'`');
|
||
return requirejs(module_path)[name];
|
||
},
|
||
enumerable: true,
|
||
configurable: false
|
||
});
|
||
}
|
||
|
||
define('base/js/namespace',[],function(){
|
||
"use strict";
|
||
|
||
// expose modules
|
||
|
||
jprop('utils','base/js/utils')
|
||
|
||
//Jupyter.load_extensions = Jupyter.utils.load_extensions;
|
||
//
|
||
jprop('security','base/js/security');
|
||
jprop('keyboard','base/js/keyboard');
|
||
jprop('dialog','base/js/dialog');
|
||
jprop('mathjaxutils','notebook/js/mathjaxutils');
|
||
|
||
|
||
//// exposed constructors
|
||
jglobal('CommManager','services/kernels/comm')
|
||
jglobal('Comm','services/kernels/comm')
|
||
|
||
jglobal('NotificationWidget','base/js/notificationwidget');
|
||
jglobal('Kernel','services/kernels/kernel');
|
||
jglobal('Session','services/sessions/session');
|
||
jglobal('LoginWidget','auth/js/loginwidget');
|
||
jglobal('Page','base/js/page');
|
||
|
||
// notebook
|
||
jglobal('TextCell','notebook/js/textcell');
|
||
jglobal('OutputArea','notebook/js/outputarea');
|
||
jglobal('KeyboardManager','notebook/js/keyboardmanager');
|
||
jglobal('Completer','notebook/js/completer');
|
||
jglobal('Notebook','notebook/js/notebook');
|
||
jglobal('Tooltip','notebook/js/tooltip');
|
||
jglobal('Toolbar','notebook/js/toolbar');
|
||
jglobal('SaveWidget','notebook/js/savewidget');
|
||
jglobal('Pager','notebook/js/pager');
|
||
jglobal('QuickHelp','notebook/js/quickhelp');
|
||
jglobal('MarkdownCell','notebook/js/textcell');
|
||
jglobal('RawCell','notebook/js/textcell');
|
||
jglobal('Cell','notebook/js/cell');
|
||
jglobal('MainToolBar','notebook/js/maintoolbar');
|
||
jglobal('NotebookNotificationArea','notebook/js/notificationarea');
|
||
jglobal('NotebookTour', 'notebook/js/tour');
|
||
jglobal('MenuBar', 'notebook/js/menubar');
|
||
|
||
// tree
|
||
jglobal('SessionList','tree/js/sessionlist');
|
||
|
||
Jupyter.version = "6.1.5";
|
||
Jupyter._target = '_blank';
|
||
|
||
return Jupyter;
|
||
});
|
||
|
||
// deprecated since 4.0, remove in 5+
|
||
var IPython = Jupyter;
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
// This is CodeMirror (https://codemirror.net), a code editor
|
||
// implemented in JavaScript on top of the browser's DOM.
|
||
//
|
||
// You can find some technical background for some of the code below
|
||
// at http://marijnhaverbeke.nl/blog/#cm-internals .
|
||
|
||
(function (global, factory) {
|
||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||
typeof define === 'function' && define.amd ? define('codemirror/lib/codemirror',factory) :
|
||
(global = global || self, global.CodeMirror = factory());
|
||
}(this, (function () { 'use strict';
|
||
|
||
// Kludges for bugs and behavior differences that can't be feature
|
||
// detected are enabled based on userAgent etc sniffing.
|
||
var userAgent = navigator.userAgent;
|
||
var platform = navigator.platform;
|
||
|
||
var gecko = /gecko\/\d/i.test(userAgent);
|
||
var ie_upto10 = /MSIE \d/.test(userAgent);
|
||
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
|
||
var edge = /Edge\/(\d+)/.exec(userAgent);
|
||
var ie = ie_upto10 || ie_11up || edge;
|
||
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
|
||
var webkit = !edge && /WebKit\//.test(userAgent);
|
||
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
|
||
var chrome = !edge && /Chrome\//.test(userAgent);
|
||
var presto = /Opera\//.test(userAgent);
|
||
var safari = /Apple Computer/.test(navigator.vendor);
|
||
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
|
||
var phantom = /PhantomJS/.test(userAgent);
|
||
|
||
var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
|
||
var android = /Android/.test(userAgent);
|
||
// This is woefully incomplete. Suggestions for alternative methods welcome.
|
||
var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
|
||
var mac = ios || /Mac/.test(platform);
|
||
var chromeOS = /\bCrOS\b/.test(userAgent);
|
||
var windows = /win/i.test(platform);
|
||
|
||
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
|
||
if (presto_version) { presto_version = Number(presto_version[1]); }
|
||
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
|
||
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
|
||
var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
|
||
var captureRightClick = gecko || (ie && ie_version >= 9);
|
||
|
||
function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
|
||
|
||
var rmClass = function(node, cls) {
|
||
var current = node.className;
|
||
var match = classTest(cls).exec(current);
|
||
if (match) {
|
||
var after = current.slice(match.index + match[0].length);
|
||
node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
|
||
}
|
||
};
|
||
|
||
function removeChildren(e) {
|
||
for (var count = e.childNodes.length; count > 0; --count)
|
||
{ e.removeChild(e.firstChild); }
|
||
return e
|
||
}
|
||
|
||
function removeChildrenAndAdd(parent, e) {
|
||
return removeChildren(parent).appendChild(e)
|
||
}
|
||
|
||
function elt(tag, content, className, style) {
|
||
var e = document.createElement(tag);
|
||
if (className) { e.className = className; }
|
||
if (style) { e.style.cssText = style; }
|
||
if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
|
||
else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
|
||
return e
|
||
}
|
||
// wrapper for elt, which removes the elt from the accessibility tree
|
||
function eltP(tag, content, className, style) {
|
||
var e = elt(tag, content, className, style);
|
||
e.setAttribute("role", "presentation");
|
||
return e
|
||
}
|
||
|
||
var range;
|
||
if (document.createRange) { range = function(node, start, end, endNode) {
|
||
var r = document.createRange();
|
||
r.setEnd(endNode || node, end);
|
||
r.setStart(node, start);
|
||
return r
|
||
}; }
|
||
else { range = function(node, start, end) {
|
||
var r = document.body.createTextRange();
|
||
try { r.moveToElementText(node.parentNode); }
|
||
catch(e) { return r }
|
||
r.collapse(true);
|
||
r.moveEnd("character", end);
|
||
r.moveStart("character", start);
|
||
return r
|
||
}; }
|
||
|
||
function contains(parent, child) {
|
||
if (child.nodeType == 3) // Android browser always returns false when child is a textnode
|
||
{ child = child.parentNode; }
|
||
if (parent.contains)
|
||
{ return parent.contains(child) }
|
||
do {
|
||
if (child.nodeType == 11) { child = child.host; }
|
||
if (child == parent) { return true }
|
||
} while (child = child.parentNode)
|
||
}
|
||
|
||
function activeElt() {
|
||
// IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
|
||
// IE < 10 will throw when accessed while the page is loading or in an iframe.
|
||
// IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
|
||
var activeElement;
|
||
try {
|
||
activeElement = document.activeElement;
|
||
} catch(e) {
|
||
activeElement = document.body || null;
|
||
}
|
||
while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
|
||
{ activeElement = activeElement.shadowRoot.activeElement; }
|
||
return activeElement
|
||
}
|
||
|
||
function addClass(node, cls) {
|
||
var current = node.className;
|
||
if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
|
||
}
|
||
function joinClasses(a, b) {
|
||
var as = a.split(" ");
|
||
for (var i = 0; i < as.length; i++)
|
||
{ if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
|
||
return b
|
||
}
|
||
|
||
var selectInput = function(node) { node.select(); };
|
||
if (ios) // Mobile Safari apparently has a bug where select() is broken.
|
||
{ selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
|
||
else if (ie) // Suppress mysterious IE10 errors
|
||
{ selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
|
||
|
||
function bind(f) {
|
||
var args = Array.prototype.slice.call(arguments, 1);
|
||
return function(){return f.apply(null, args)}
|
||
}
|
||
|
||
function copyObj(obj, target, overwrite) {
|
||
if (!target) { target = {}; }
|
||
for (var prop in obj)
|
||
{ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
|
||
{ target[prop] = obj[prop]; } }
|
||
return target
|
||
}
|
||
|
||
// Counts the column offset in a string, taking tabs into account.
|
||
// Used mostly to find indentation.
|
||
function countColumn(string, end, tabSize, startIndex, startValue) {
|
||
if (end == null) {
|
||
end = string.search(/[^\s\u00a0]/);
|
||
if (end == -1) { end = string.length; }
|
||
}
|
||
for (var i = startIndex || 0, n = startValue || 0;;) {
|
||
var nextTab = string.indexOf("\t", i);
|
||
if (nextTab < 0 || nextTab >= end)
|
||
{ return n + (end - i) }
|
||
n += nextTab - i;
|
||
n += tabSize - (n % tabSize);
|
||
i = nextTab + 1;
|
||
}
|
||
}
|
||
|
||
var Delayed = function() {
|
||
this.id = null;
|
||
this.f = null;
|
||
this.time = 0;
|
||
this.handler = bind(this.onTimeout, this);
|
||
};
|
||
Delayed.prototype.onTimeout = function (self) {
|
||
self.id = 0;
|
||
if (self.time <= +new Date) {
|
||
self.f();
|
||
} else {
|
||
setTimeout(self.handler, self.time - +new Date);
|
||
}
|
||
};
|
||
Delayed.prototype.set = function (ms, f) {
|
||
this.f = f;
|
||
var time = +new Date + ms;
|
||
if (!this.id || time < this.time) {
|
||
clearTimeout(this.id);
|
||
this.id = setTimeout(this.handler, ms);
|
||
this.time = time;
|
||
}
|
||
};
|
||
|
||
function indexOf(array, elt) {
|
||
for (var i = 0; i < array.length; ++i)
|
||
{ if (array[i] == elt) { return i } }
|
||
return -1
|
||
}
|
||
|
||
// Number of pixels added to scroller and sizer to hide scrollbar
|
||
var scrollerGap = 50;
|
||
|
||
// Returned or thrown by various protocols to signal 'I'm not
|
||
// handling this'.
|
||
var Pass = {toString: function(){return "CodeMirror.Pass"}};
|
||
|
||
// Reused option objects for setSelection & friends
|
||
var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
|
||
|
||
// The inverse of countColumn -- find the offset that corresponds to
|
||
// a particular column.
|
||
function findColumn(string, goal, tabSize) {
|
||
for (var pos = 0, col = 0;;) {
|
||
var nextTab = string.indexOf("\t", pos);
|
||
if (nextTab == -1) { nextTab = string.length; }
|
||
var skipped = nextTab - pos;
|
||
if (nextTab == string.length || col + skipped >= goal)
|
||
{ return pos + Math.min(skipped, goal - col) }
|
||
col += nextTab - pos;
|
||
col += tabSize - (col % tabSize);
|
||
pos = nextTab + 1;
|
||
if (col >= goal) { return pos }
|
||
}
|
||
}
|
||
|
||
var spaceStrs = [""];
|
||
function spaceStr(n) {
|
||
while (spaceStrs.length <= n)
|
||
{ spaceStrs.push(lst(spaceStrs) + " "); }
|
||
return spaceStrs[n]
|
||
}
|
||
|
||
function lst(arr) { return arr[arr.length-1] }
|
||
|
||
function map(array, f) {
|
||
var out = [];
|
||
for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
|
||
return out
|
||
}
|
||
|
||
function insertSorted(array, value, score) {
|
||
var pos = 0, priority = score(value);
|
||
while (pos < array.length && score(array[pos]) <= priority) { pos++; }
|
||
array.splice(pos, 0, value);
|
||
}
|
||
|
||
function nothing() {}
|
||
|
||
function createObj(base, props) {
|
||
var inst;
|
||
if (Object.create) {
|
||
inst = Object.create(base);
|
||
} else {
|
||
nothing.prototype = base;
|
||
inst = new nothing();
|
||
}
|
||
if (props) { copyObj(props, inst); }
|
||
return inst
|
||
}
|
||
|
||
var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
|
||
function isWordCharBasic(ch) {
|
||
return /\w/.test(ch) || ch > "\x80" &&
|
||
(ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
|
||
}
|
||
function isWordChar(ch, helper) {
|
||
if (!helper) { return isWordCharBasic(ch) }
|
||
if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
|
||
return helper.test(ch)
|
||
}
|
||
|
||
function isEmpty(obj) {
|
||
for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
|
||
return true
|
||
}
|
||
|
||
// Extending unicode characters. A series of a non-extending char +
|
||
// any number of extending chars is treated as a single unit as far
|
||
// as editing and measuring is concerned. This is not fully correct,
|
||
// since some scripts/fonts/browsers also treat other configurations
|
||
// of code points as a group.
|
||
var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
|
||
function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
|
||
|
||
// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
|
||
function skipExtendingChars(str, pos, dir) {
|
||
while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
|
||
return pos
|
||
}
|
||
|
||
// Returns the value from the range [`from`; `to`] that satisfies
|
||
// `pred` and is closest to `from`. Assumes that at least `to`
|
||
// satisfies `pred`. Supports `from` being greater than `to`.
|
||
function findFirst(pred, from, to) {
|
||
// At any point we are certain `to` satisfies `pred`, don't know
|
||
// whether `from` does.
|
||
var dir = from > to ? -1 : 1;
|
||
for (;;) {
|
||
if (from == to) { return from }
|
||
var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
|
||
if (mid == from) { return pred(mid) ? from : to }
|
||
if (pred(mid)) { to = mid; }
|
||
else { from = mid + dir; }
|
||
}
|
||
}
|
||
|
||
// BIDI HELPERS
|
||
|
||
function iterateBidiSections(order, from, to, f) {
|
||
if (!order) { return f(from, to, "ltr", 0) }
|
||
var found = false;
|
||
for (var i = 0; i < order.length; ++i) {
|
||
var part = order[i];
|
||
if (part.from < to && part.to > from || from == to && part.to == from) {
|
||
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
|
||
found = true;
|
||
}
|
||
}
|
||
if (!found) { f(from, to, "ltr"); }
|
||
}
|
||
|
||
var bidiOther = null;
|
||
function getBidiPartAt(order, ch, sticky) {
|
||
var found;
|
||
bidiOther = null;
|
||
for (var i = 0; i < order.length; ++i) {
|
||
var cur = order[i];
|
||
if (cur.from < ch && cur.to > ch) { return i }
|
||
if (cur.to == ch) {
|
||
if (cur.from != cur.to && sticky == "before") { found = i; }
|
||
else { bidiOther = i; }
|
||
}
|
||
if (cur.from == ch) {
|
||
if (cur.from != cur.to && sticky != "before") { found = i; }
|
||
else { bidiOther = i; }
|
||
}
|
||
}
|
||
return found != null ? found : bidiOther
|
||
}
|
||
|
||
// Bidirectional ordering algorithm
|
||
// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
|
||
// that this (partially) implements.
|
||
|
||
// One-char codes used for character types:
|
||
// L (L): Left-to-Right
|
||
// R (R): Right-to-Left
|
||
// r (AL): Right-to-Left Arabic
|
||
// 1 (EN): European Number
|
||
// + (ES): European Number Separator
|
||
// % (ET): European Number Terminator
|
||
// n (AN): Arabic Number
|
||
// , (CS): Common Number Separator
|
||
// m (NSM): Non-Spacing Mark
|
||
// b (BN): Boundary Neutral
|
||
// s (B): Paragraph Separator
|
||
// t (S): Segment Separator
|
||
// w (WS): Whitespace
|
||
// N (ON): Other Neutrals
|
||
|
||
// Returns null if characters are ordered as they appear
|
||
// (left-to-right), or an array of sections ({from, to, level}
|
||
// objects) in the order in which they occur visually.
|
||
var bidiOrdering = (function() {
|
||
// Character types for codepoints 0 to 0xff
|
||
var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
|
||
// Character types for codepoints 0x600 to 0x6f9
|
||
var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
|
||
function charType(code) {
|
||
if (code <= 0xf7) { return lowTypes.charAt(code) }
|
||
else if (0x590 <= code && code <= 0x5f4) { return "R" }
|
||
else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
|
||
else if (0x6ee <= code && code <= 0x8ac) { return "r" }
|
||
else if (0x2000 <= code && code <= 0x200b) { return "w" }
|
||
else if (code == 0x200c) { return "b" }
|
||
else { return "L" }
|
||
}
|
||
|
||
var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
|
||
var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
|
||
|
||
function BidiSpan(level, from, to) {
|
||
this.level = level;
|
||
this.from = from; this.to = to;
|
||
}
|
||
|
||
return function(str, direction) {
|
||
var outerType = direction == "ltr" ? "L" : "R";
|
||
|
||
if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
|
||
var len = str.length, types = [];
|
||
for (var i = 0; i < len; ++i)
|
||
{ types.push(charType(str.charCodeAt(i))); }
|
||
|
||
// W1. Examine each non-spacing mark (NSM) in the level run, and
|
||
// change the type of the NSM to the type of the previous
|
||
// character. If the NSM is at the start of the level run, it will
|
||
// get the type of sor.
|
||
for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
|
||
var type = types[i$1];
|
||
if (type == "m") { types[i$1] = prev; }
|
||
else { prev = type; }
|
||
}
|
||
|
||
// W2. Search backwards from each instance of a European number
|
||
// until the first strong type (R, L, AL, or sor) is found. If an
|
||
// AL is found, change the type of the European number to Arabic
|
||
// number.
|
||
// W3. Change all ALs to R.
|
||
for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
|
||
var type$1 = types[i$2];
|
||
if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
|
||
else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
|
||
}
|
||
|
||
// W4. A single European separator between two European numbers
|
||
// changes to a European number. A single common separator between
|
||
// two numbers of the same type changes to that type.
|
||
for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
|
||
var type$2 = types[i$3];
|
||
if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
|
||
else if (type$2 == "," && prev$1 == types[i$3+1] &&
|
||
(prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
|
||
prev$1 = type$2;
|
||
}
|
||
|
||
// W5. A sequence of European terminators adjacent to European
|
||
// numbers changes to all European numbers.
|
||
// W6. Otherwise, separators and terminators change to Other
|
||
// Neutral.
|
||
for (var i$4 = 0; i$4 < len; ++i$4) {
|
||
var type$3 = types[i$4];
|
||
if (type$3 == ",") { types[i$4] = "N"; }
|
||
else if (type$3 == "%") {
|
||
var end = (void 0);
|
||
for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
|
||
var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
|
||
for (var j = i$4; j < end; ++j) { types[j] = replace; }
|
||
i$4 = end - 1;
|
||
}
|
||
}
|
||
|
||
// W7. Search backwards from each instance of a European number
|
||
// until the first strong type (R, L, or sor) is found. If an L is
|
||
// found, then change the type of the European number to L.
|
||
for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
|
||
var type$4 = types[i$5];
|
||
if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
|
||
else if (isStrong.test(type$4)) { cur$1 = type$4; }
|
||
}
|
||
|
||
// N1. A sequence of neutrals takes the direction of the
|
||
// surrounding strong text if the text on both sides has the same
|
||
// direction. European and Arabic numbers act as if they were R in
|
||
// terms of their influence on neutrals. Start-of-level-run (sor)
|
||
// and end-of-level-run (eor) are used at level run boundaries.
|
||
// N2. Any remaining neutrals take the embedding direction.
|
||
for (var i$6 = 0; i$6 < len; ++i$6) {
|
||
if (isNeutral.test(types[i$6])) {
|
||
var end$1 = (void 0);
|
||
for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
|
||
var before = (i$6 ? types[i$6-1] : outerType) == "L";
|
||
var after = (end$1 < len ? types[end$1] : outerType) == "L";
|
||
var replace$1 = before == after ? (before ? "L" : "R") : outerType;
|
||
for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
|
||
i$6 = end$1 - 1;
|
||
}
|
||
}
|
||
|
||
// Here we depart from the documented algorithm, in order to avoid
|
||
// building up an actual levels array. Since there are only three
|
||
// levels (0, 1, 2) in an implementation that doesn't take
|
||
// explicit embedding into account, we can build up the order on
|
||
// the fly, without following the level-based algorithm.
|
||
var order = [], m;
|
||
for (var i$7 = 0; i$7 < len;) {
|
||
if (countsAsLeft.test(types[i$7])) {
|
||
var start = i$7;
|
||
for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
|
||
order.push(new BidiSpan(0, start, i$7));
|
||
} else {
|
||
var pos = i$7, at = order.length, isRTL = direction == "rtl" ? 1 : 0;
|
||
for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
|
||
for (var j$2 = pos; j$2 < i$7;) {
|
||
if (countsAsNum.test(types[j$2])) {
|
||
if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; }
|
||
var nstart = j$2;
|
||
for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
|
||
order.splice(at, 0, new BidiSpan(2, nstart, j$2));
|
||
at += isRTL;
|
||
pos = j$2;
|
||
} else { ++j$2; }
|
||
}
|
||
if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
|
||
}
|
||
}
|
||
if (direction == "ltr") {
|
||
if (order[0].level == 1 && (m = str.match(/^\s+/))) {
|
||
order[0].from = m[0].length;
|
||
order.unshift(new BidiSpan(0, 0, m[0].length));
|
||
}
|
||
if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
|
||
lst(order).to -= m[0].length;
|
||
order.push(new BidiSpan(0, len - m[0].length, len));
|
||
}
|
||
}
|
||
|
||
return direction == "rtl" ? order.reverse() : order
|
||
}
|
||
})();
|
||
|
||
// Get the bidi ordering for the given line (and cache it). Returns
|
||
// false for lines that are fully left-to-right, and an array of
|
||
// BidiSpan objects otherwise.
|
||
function getOrder(line, direction) {
|
||
var order = line.order;
|
||
if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
|
||
return order
|
||
}
|
||
|
||
// EVENT HANDLING
|
||
|
||
// Lightweight event framework. on/off also work on DOM nodes,
|
||
// registering native DOM handlers.
|
||
|
||
var noHandlers = [];
|
||
|
||
var on = function(emitter, type, f) {
|
||
if (emitter.addEventListener) {
|
||
emitter.addEventListener(type, f, false);
|
||
} else if (emitter.attachEvent) {
|
||
emitter.attachEvent("on" + type, f);
|
||
} else {
|
||
var map = emitter._handlers || (emitter._handlers = {});
|
||
map[type] = (map[type] || noHandlers).concat(f);
|
||
}
|
||
};
|
||
|
||
function getHandlers(emitter, type) {
|
||
return emitter._handlers && emitter._handlers[type] || noHandlers
|
||
}
|
||
|
||
function off(emitter, type, f) {
|
||
if (emitter.removeEventListener) {
|
||
emitter.removeEventListener(type, f, false);
|
||
} else if (emitter.detachEvent) {
|
||
emitter.detachEvent("on" + type, f);
|
||
} else {
|
||
var map = emitter._handlers, arr = map && map[type];
|
||
if (arr) {
|
||
var index = indexOf(arr, f);
|
||
if (index > -1)
|
||
{ map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
|
||
}
|
||
}
|
||
}
|
||
|
||
function signal(emitter, type /*, values...*/) {
|
||
var handlers = getHandlers(emitter, type);
|
||
if (!handlers.length) { return }
|
||
var args = Array.prototype.slice.call(arguments, 2);
|
||
for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
|
||
}
|
||
|
||
// The DOM events that CodeMirror handles can be overridden by
|
||
// registering a (non-DOM) handler on the editor for the event name,
|
||
// and preventDefault-ing the event in that handler.
|
||
function signalDOMEvent(cm, e, override) {
|
||
if (typeof e == "string")
|
||
{ e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
|
||
signal(cm, override || e.type, cm, e);
|
||
return e_defaultPrevented(e) || e.codemirrorIgnore
|
||
}
|
||
|
||
function signalCursorActivity(cm) {
|
||
var arr = cm._handlers && cm._handlers.cursorActivity;
|
||
if (!arr) { return }
|
||
var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
|
||
for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
|
||
{ set.push(arr[i]); } }
|
||
}
|
||
|
||
function hasHandler(emitter, type) {
|
||
return getHandlers(emitter, type).length > 0
|
||
}
|
||
|
||
// Add on and off methods to a constructor's prototype, to make
|
||
// registering events on such objects more convenient.
|
||
function eventMixin(ctor) {
|
||
ctor.prototype.on = function(type, f) {on(this, type, f);};
|
||
ctor.prototype.off = function(type, f) {off(this, type, f);};
|
||
}
|
||
|
||
// Due to the fact that we still support jurassic IE versions, some
|
||
// compatibility wrappers are needed.
|
||
|
||
function e_preventDefault(e) {
|
||
if (e.preventDefault) { e.preventDefault(); }
|
||
else { e.returnValue = false; }
|
||
}
|
||
function e_stopPropagation(e) {
|
||
if (e.stopPropagation) { e.stopPropagation(); }
|
||
else { e.cancelBubble = true; }
|
||
}
|
||
function e_defaultPrevented(e) {
|
||
return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
|
||
}
|
||
function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
|
||
|
||
function e_target(e) {return e.target || e.srcElement}
|
||
function e_button(e) {
|
||
var b = e.which;
|
||
if (b == null) {
|
||
if (e.button & 1) { b = 1; }
|
||
else if (e.button & 2) { b = 3; }
|
||
else if (e.button & 4) { b = 2; }
|
||
}
|
||
if (mac && e.ctrlKey && b == 1) { b = 3; }
|
||
return b
|
||
}
|
||
|
||
// Detect drag-and-drop
|
||
var dragAndDrop = function() {
|
||
// There is *some* kind of drag-and-drop support in IE6-8, but I
|
||
// couldn't get it to work yet.
|
||
if (ie && ie_version < 9) { return false }
|
||
var div = elt('div');
|
||
return "draggable" in div || "dragDrop" in div
|
||
}();
|
||
|
||
var zwspSupported;
|
||
function zeroWidthElement(measure) {
|
||
if (zwspSupported == null) {
|
||
var test = elt("span", "\u200b");
|
||
removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
|
||
if (measure.firstChild.offsetHeight != 0)
|
||
{ zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
|
||
}
|
||
var node = zwspSupported ? elt("span", "\u200b") :
|
||
elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
|
||
node.setAttribute("cm-text", "");
|
||
return node
|
||
}
|
||
|
||
// Feature-detect IE's crummy client rect reporting for bidi text
|
||
var badBidiRects;
|
||
function hasBadBidiRects(measure) {
|
||
if (badBidiRects != null) { return badBidiRects }
|
||
var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
|
||
var r0 = range(txt, 0, 1).getBoundingClientRect();
|
||
var r1 = range(txt, 1, 2).getBoundingClientRect();
|
||
removeChildren(measure);
|
||
if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
|
||
return badBidiRects = (r1.right - r0.right < 3)
|
||
}
|
||
|
||
// See if "".split is the broken IE version, if so, provide an
|
||
// alternative way to split lines.
|
||
var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
|
||
var pos = 0, result = [], l = string.length;
|
||
while (pos <= l) {
|
||
var nl = string.indexOf("\n", pos);
|
||
if (nl == -1) { nl = string.length; }
|
||
var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
|
||
var rt = line.indexOf("\r");
|
||
if (rt != -1) {
|
||
result.push(line.slice(0, rt));
|
||
pos += rt + 1;
|
||
} else {
|
||
result.push(line);
|
||
pos = nl + 1;
|
||
}
|
||
}
|
||
return result
|
||
} : function (string) { return string.split(/\r\n?|\n/); };
|
||
|
||
var hasSelection = window.getSelection ? function (te) {
|
||
try { return te.selectionStart != te.selectionEnd }
|
||
catch(e) { return false }
|
||
} : function (te) {
|
||
var range;
|
||
try {range = te.ownerDocument.selection.createRange();}
|
||
catch(e) {}
|
||
if (!range || range.parentElement() != te) { return false }
|
||
return range.compareEndPoints("StartToEnd", range) != 0
|
||
};
|
||
|
||
var hasCopyEvent = (function () {
|
||
var e = elt("div");
|
||
if ("oncopy" in e) { return true }
|
||
e.setAttribute("oncopy", "return;");
|
||
return typeof e.oncopy == "function"
|
||
})();
|
||
|
||
var badZoomedRects = null;
|
||
function hasBadZoomedRects(measure) {
|
||
if (badZoomedRects != null) { return badZoomedRects }
|
||
var node = removeChildrenAndAdd(measure, elt("span", "x"));
|
||
var normal = node.getBoundingClientRect();
|
||
var fromRange = range(node, 0, 1).getBoundingClientRect();
|
||
return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
|
||
}
|
||
|
||
// Known modes, by name and by MIME
|
||
var modes = {}, mimeModes = {};
|
||
|
||
// Extra arguments are stored as the mode's dependencies, which is
|
||
// used by (legacy) mechanisms like loadmode.js to automatically
|
||
// load a mode. (Preferred mechanism is the require/define calls.)
|
||
function defineMode(name, mode) {
|
||
if (arguments.length > 2)
|
||
{ mode.dependencies = Array.prototype.slice.call(arguments, 2); }
|
||
modes[name] = mode;
|
||
}
|
||
|
||
function defineMIME(mime, spec) {
|
||
mimeModes[mime] = spec;
|
||
}
|
||
|
||
// Given a MIME type, a {name, ...options} config object, or a name
|
||
// string, return a mode config object.
|
||
function resolveMode(spec) {
|
||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
|
||
spec = mimeModes[spec];
|
||
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
|
||
var found = mimeModes[spec.name];
|
||
if (typeof found == "string") { found = {name: found}; }
|
||
spec = createObj(found, spec);
|
||
spec.name = found.name;
|
||
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
|
||
return resolveMode("application/xml")
|
||
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
|
||
return resolveMode("application/json")
|
||
}
|
||
if (typeof spec == "string") { return {name: spec} }
|
||
else { return spec || {name: "null"} }
|
||
}
|
||
|
||
// Given a mode spec (anything that resolveMode accepts), find and
|
||
// initialize an actual mode object.
|
||
function getMode(options, spec) {
|
||
spec = resolveMode(spec);
|
||
var mfactory = modes[spec.name];
|
||
if (!mfactory) { return getMode(options, "text/plain") }
|
||
var modeObj = mfactory(options, spec);
|
||
if (modeExtensions.hasOwnProperty(spec.name)) {
|
||
var exts = modeExtensions[spec.name];
|
||
for (var prop in exts) {
|
||
if (!exts.hasOwnProperty(prop)) { continue }
|
||
if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
|
||
modeObj[prop] = exts[prop];
|
||
}
|
||
}
|
||
modeObj.name = spec.name;
|
||
if (spec.helperType) { modeObj.helperType = spec.helperType; }
|
||
if (spec.modeProps) { for (var prop$1 in spec.modeProps)
|
||
{ modeObj[prop$1] = spec.modeProps[prop$1]; } }
|
||
|
||
return modeObj
|
||
}
|
||
|
||
// This can be used to attach properties to mode objects from
|
||
// outside the actual mode definition.
|
||
var modeExtensions = {};
|
||
function extendMode(mode, properties) {
|
||
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
|
||
copyObj(properties, exts);
|
||
}
|
||
|
||
function copyState(mode, state) {
|
||
if (state === true) { return state }
|
||
if (mode.copyState) { return mode.copyState(state) }
|
||
var nstate = {};
|
||
for (var n in state) {
|
||
var val = state[n];
|
||
if (val instanceof Array) { val = val.concat([]); }
|
||
nstate[n] = val;
|
||
}
|
||
return nstate
|
||
}
|
||
|
||
// Given a mode and a state (for that mode), find the inner mode and
|
||
// state at the position that the state refers to.
|
||
function innerMode(mode, state) {
|
||
var info;
|
||
while (mode.innerMode) {
|
||
info = mode.innerMode(state);
|
||
if (!info || info.mode == mode) { break }
|
||
state = info.state;
|
||
mode = info.mode;
|
||
}
|
||
return info || {mode: mode, state: state}
|
||
}
|
||
|
||
function startState(mode, a1, a2) {
|
||
return mode.startState ? mode.startState(a1, a2) : true
|
||
}
|
||
|
||
// STRING STREAM
|
||
|
||
// Fed to the mode parsers, provides helper functions to make
|
||
// parsers more succinct.
|
||
|
||
var StringStream = function(string, tabSize, lineOracle) {
|
||
this.pos = this.start = 0;
|
||
this.string = string;
|
||
this.tabSize = tabSize || 8;
|
||
this.lastColumnPos = this.lastColumnValue = 0;
|
||
this.lineStart = 0;
|
||
this.lineOracle = lineOracle;
|
||
};
|
||
|
||
StringStream.prototype.eol = function () {return this.pos >= this.string.length};
|
||
StringStream.prototype.sol = function () {return this.pos == this.lineStart};
|
||
StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
|
||
StringStream.prototype.next = function () {
|
||
if (this.pos < this.string.length)
|
||
{ return this.string.charAt(this.pos++) }
|
||
};
|
||
StringStream.prototype.eat = function (match) {
|
||
var ch = this.string.charAt(this.pos);
|
||
var ok;
|
||
if (typeof match == "string") { ok = ch == match; }
|
||
else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
|
||
if (ok) {++this.pos; return ch}
|
||
};
|
||
StringStream.prototype.eatWhile = function (match) {
|
||
var start = this.pos;
|
||
while (this.eat(match)){}
|
||
return this.pos > start
|
||
};
|
||
StringStream.prototype.eatSpace = function () {
|
||
var start = this.pos;
|
||
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }
|
||
return this.pos > start
|
||
};
|
||
StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
|
||
StringStream.prototype.skipTo = function (ch) {
|
||
var found = this.string.indexOf(ch, this.pos);
|
||
if (found > -1) {this.pos = found; return true}
|
||
};
|
||
StringStream.prototype.backUp = function (n) {this.pos -= n;};
|
||
StringStream.prototype.column = function () {
|
||
if (this.lastColumnPos < this.start) {
|
||
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
|
||
this.lastColumnPos = this.start;
|
||
}
|
||
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
|
||
};
|
||
StringStream.prototype.indentation = function () {
|
||
return countColumn(this.string, null, this.tabSize) -
|
||
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
|
||
};
|
||
StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
|
||
if (typeof pattern == "string") {
|
||
var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
|
||
var substr = this.string.substr(this.pos, pattern.length);
|
||
if (cased(substr) == cased(pattern)) {
|
||
if (consume !== false) { this.pos += pattern.length; }
|
||
return true
|
||
}
|
||
} else {
|
||
var match = this.string.slice(this.pos).match(pattern);
|
||
if (match && match.index > 0) { return null }
|
||
if (match && consume !== false) { this.pos += match[0].length; }
|
||
return match
|
||
}
|
||
};
|
||
StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
|
||
StringStream.prototype.hideFirstChars = function (n, inner) {
|
||
this.lineStart += n;
|
||
try { return inner() }
|
||
finally { this.lineStart -= n; }
|
||
};
|
||
StringStream.prototype.lookAhead = function (n) {
|
||
var oracle = this.lineOracle;
|
||
return oracle && oracle.lookAhead(n)
|
||
};
|
||
StringStream.prototype.baseToken = function () {
|
||
var oracle = this.lineOracle;
|
||
return oracle && oracle.baseToken(this.pos)
|
||
};
|
||
|
||
// Find the line object corresponding to the given line number.
|
||
function getLine(doc, n) {
|
||
n -= doc.first;
|
||
if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
|
||
var chunk = doc;
|
||
while (!chunk.lines) {
|
||
for (var i = 0;; ++i) {
|
||
var child = chunk.children[i], sz = child.chunkSize();
|
||
if (n < sz) { chunk = child; break }
|
||
n -= sz;
|
||
}
|
||
}
|
||
return chunk.lines[n]
|
||
}
|
||
|
||
// Get the part of a document between two positions, as an array of
|
||
// strings.
|
||
function getBetween(doc, start, end) {
|
||
var out = [], n = start.line;
|
||
doc.iter(start.line, end.line + 1, function (line) {
|
||
var text = line.text;
|
||
if (n == end.line) { text = text.slice(0, end.ch); }
|
||
if (n == start.line) { text = text.slice(start.ch); }
|
||
out.push(text);
|
||
++n;
|
||
});
|
||
return out
|
||
}
|
||
// Get the lines between from and to, as array of strings.
|
||
function getLines(doc, from, to) {
|
||
var out = [];
|
||
doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
|
||
return out
|
||
}
|
||
|
||
// Update the height of a line, propagating the height change
|
||
// upwards to parent nodes.
|
||
function updateLineHeight(line, height) {
|
||
var diff = height - line.height;
|
||
if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
|
||
}
|
||
|
||
// Given a line object, find its line number by walking up through
|
||
// its parent links.
|
||
function lineNo(line) {
|
||
if (line.parent == null) { return null }
|
||
var cur = line.parent, no = indexOf(cur.lines, line);
|
||
for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
|
||
for (var i = 0;; ++i) {
|
||
if (chunk.children[i] == cur) { break }
|
||
no += chunk.children[i].chunkSize();
|
||
}
|
||
}
|
||
return no + cur.first
|
||
}
|
||
|
||
// Find the line at the given vertical position, using the height
|
||
// information in the document tree.
|
||
function lineAtHeight(chunk, h) {
|
||
var n = chunk.first;
|
||
outer: do {
|
||
for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
|
||
var child = chunk.children[i$1], ch = child.height;
|
||
if (h < ch) { chunk = child; continue outer }
|
||
h -= ch;
|
||
n += child.chunkSize();
|
||
}
|
||
return n
|
||
} while (!chunk.lines)
|
||
var i = 0;
|
||
for (; i < chunk.lines.length; ++i) {
|
||
var line = chunk.lines[i], lh = line.height;
|
||
if (h < lh) { break }
|
||
h -= lh;
|
||
}
|
||
return n + i
|
||
}
|
||
|
||
function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
|
||
|
||
function lineNumberFor(options, i) {
|
||
return String(options.lineNumberFormatter(i + options.firstLineNumber))
|
||
}
|
||
|
||
// A Pos instance represents a position within the text.
|
||
function Pos(line, ch, sticky) {
|
||
if ( sticky === void 0 ) sticky = null;
|
||
|
||
if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
|
||
this.line = line;
|
||
this.ch = ch;
|
||
this.sticky = sticky;
|
||
}
|
||
|
||
// Compare two positions, return 0 if they are the same, a negative
|
||
// number when a is less, and a positive number otherwise.
|
||
function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
|
||
|
||
function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
|
||
|
||
function copyPos(x) {return Pos(x.line, x.ch)}
|
||
function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
|
||
function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
|
||
|
||
// Most of the external API clips given positions to make sure they
|
||
// actually exist within the document.
|
||
function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
|
||
function clipPos(doc, pos) {
|
||
if (pos.line < doc.first) { return Pos(doc.first, 0) }
|
||
var last = doc.first + doc.size - 1;
|
||
if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
|
||
return clipToLen(pos, getLine(doc, pos.line).text.length)
|
||
}
|
||
function clipToLen(pos, linelen) {
|
||
var ch = pos.ch;
|
||
if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
|
||
else if (ch < 0) { return Pos(pos.line, 0) }
|
||
else { return pos }
|
||
}
|
||
function clipPosArray(doc, array) {
|
||
var out = [];
|
||
for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
|
||
return out
|
||
}
|
||
|
||
var SavedContext = function(state, lookAhead) {
|
||
this.state = state;
|
||
this.lookAhead = lookAhead;
|
||
};
|
||
|
||
var Context = function(doc, state, line, lookAhead) {
|
||
this.state = state;
|
||
this.doc = doc;
|
||
this.line = line;
|
||
this.maxLookAhead = lookAhead || 0;
|
||
this.baseTokens = null;
|
||
this.baseTokenPos = 1;
|
||
};
|
||
|
||
Context.prototype.lookAhead = function (n) {
|
||
var line = this.doc.getLine(this.line + n);
|
||
if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
|
||
return line
|
||
};
|
||
|
||
Context.prototype.baseToken = function (n) {
|
||
if (!this.baseTokens) { return null }
|
||
while (this.baseTokens[this.baseTokenPos] <= n)
|
||
{ this.baseTokenPos += 2; }
|
||
var type = this.baseTokens[this.baseTokenPos + 1];
|
||
return {type: type && type.replace(/( |^)overlay .*/, ""),
|
||
size: this.baseTokens[this.baseTokenPos] - n}
|
||
};
|
||
|
||
Context.prototype.nextLine = function () {
|
||
this.line++;
|
||
if (this.maxLookAhead > 0) { this.maxLookAhead--; }
|
||
};
|
||
|
||
Context.fromSaved = function (doc, saved, line) {
|
||
if (saved instanceof SavedContext)
|
||
{ return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
|
||
else
|
||
{ return new Context(doc, copyState(doc.mode, saved), line) }
|
||
};
|
||
|
||
Context.prototype.save = function (copy) {
|
||
var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
|
||
return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
|
||
};
|
||
|
||
|
||
// Compute a style array (an array starting with a mode generation
|
||
// -- for invalidation -- followed by pairs of end positions and
|
||
// style strings), which is used to highlight the tokens on the
|
||
// line.
|
||
function highlightLine(cm, line, context, forceToEnd) {
|
||
// A styles array always starts with a number identifying the
|
||
// mode/overlays that it is based on (for easy invalidation).
|
||
var st = [cm.state.modeGen], lineClasses = {};
|
||
// Compute the base array of styles
|
||
runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
|
||
lineClasses, forceToEnd);
|
||
var state = context.state;
|
||
|
||
// Run overlays, adjust style array.
|
||
var loop = function ( o ) {
|
||
context.baseTokens = st;
|
||
var overlay = cm.state.overlays[o], i = 1, at = 0;
|
||
context.state = true;
|
||
runMode(cm, line.text, overlay.mode, context, function (end, style) {
|
||
var start = i;
|
||
// Ensure there's a token end at the current position, and that i points at it
|
||
while (at < end) {
|
||
var i_end = st[i];
|
||
if (i_end > end)
|
||
{ st.splice(i, 1, end, st[i+1], i_end); }
|
||
i += 2;
|
||
at = Math.min(end, i_end);
|
||
}
|
||
if (!style) { return }
|
||
if (overlay.opaque) {
|
||
st.splice(start, i - start, end, "overlay " + style);
|
||
i = start + 2;
|
||
} else {
|
||
for (; start < i; start += 2) {
|
||
var cur = st[start+1];
|
||
st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
|
||
}
|
||
}
|
||
}, lineClasses);
|
||
context.state = state;
|
||
context.baseTokens = null;
|
||
context.baseTokenPos = 1;
|
||
};
|
||
|
||
for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
|
||
|
||
return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
|
||
}
|
||
|
||
function getLineStyles(cm, line, updateFrontier) {
|
||
if (!line.styles || line.styles[0] != cm.state.modeGen) {
|
||
var context = getContextBefore(cm, lineNo(line));
|
||
var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
|
||
var result = highlightLine(cm, line, context);
|
||
if (resetState) { context.state = resetState; }
|
||
line.stateAfter = context.save(!resetState);
|
||
line.styles = result.styles;
|
||
if (result.classes) { line.styleClasses = result.classes; }
|
||
else if (line.styleClasses) { line.styleClasses = null; }
|
||
if (updateFrontier === cm.doc.highlightFrontier)
|
||
{ cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
|
||
}
|
||
return line.styles
|
||
}
|
||
|
||
function getContextBefore(cm, n, precise) {
|
||
var doc = cm.doc, display = cm.display;
|
||
if (!doc.mode.startState) { return new Context(doc, true, n) }
|
||
var start = findStartLine(cm, n, precise);
|
||
var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
|
||
var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
|
||
|
||
doc.iter(start, n, function (line) {
|
||
processLine(cm, line.text, context);
|
||
var pos = context.line;
|
||
line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
|
||
context.nextLine();
|
||
});
|
||
if (precise) { doc.modeFrontier = context.line; }
|
||
return context
|
||
}
|
||
|
||
// Lightweight form of highlight -- proceed over this line and
|
||
// update state, but don't save a style array. Used for lines that
|
||
// aren't currently visible.
|
||
function processLine(cm, text, context, startAt) {
|
||
var mode = cm.doc.mode;
|
||
var stream = new StringStream(text, cm.options.tabSize, context);
|
||
stream.start = stream.pos = startAt || 0;
|
||
if (text == "") { callBlankLine(mode, context.state); }
|
||
while (!stream.eol()) {
|
||
readToken(mode, stream, context.state);
|
||
stream.start = stream.pos;
|
||
}
|
||
}
|
||
|
||
function callBlankLine(mode, state) {
|
||
if (mode.blankLine) { return mode.blankLine(state) }
|
||
if (!mode.innerMode) { return }
|
||
var inner = innerMode(mode, state);
|
||
if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
|
||
}
|
||
|
||
function readToken(mode, stream, state, inner) {
|
||
for (var i = 0; i < 10; i++) {
|
||
if (inner) { inner[0] = innerMode(mode, state).mode; }
|
||
var style = mode.token(stream, state);
|
||
if (stream.pos > stream.start) { return style }
|
||
}
|
||
throw new Error("Mode " + mode.name + " failed to advance stream.")
|
||
}
|
||
|
||
var Token = function(stream, type, state) {
|
||
this.start = stream.start; this.end = stream.pos;
|
||
this.string = stream.current();
|
||
this.type = type || null;
|
||
this.state = state;
|
||
};
|
||
|
||
// Utility for getTokenAt and getLineTokens
|
||
function takeToken(cm, pos, precise, asArray) {
|
||
var doc = cm.doc, mode = doc.mode, style;
|
||
pos = clipPos(doc, pos);
|
||
var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
|
||
var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
|
||
if (asArray) { tokens = []; }
|
||
while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
|
||
stream.start = stream.pos;
|
||
style = readToken(mode, stream, context.state);
|
||
if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
|
||
}
|
||
return asArray ? tokens : new Token(stream, style, context.state)
|
||
}
|
||
|
||
function extractLineClasses(type, output) {
|
||
if (type) { for (;;) {
|
||
var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
|
||
if (!lineClass) { break }
|
||
type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
|
||
var prop = lineClass[1] ? "bgClass" : "textClass";
|
||
if (output[prop] == null)
|
||
{ output[prop] = lineClass[2]; }
|
||
else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop]))
|
||
{ output[prop] += " " + lineClass[2]; }
|
||
} }
|
||
return type
|
||
}
|
||
|
||
// Run the given mode's parser over a line, calling f for each token.
|
||
function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
|
||
var flattenSpans = mode.flattenSpans;
|
||
if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
|
||
var curStart = 0, curStyle = null;
|
||
var stream = new StringStream(text, cm.options.tabSize, context), style;
|
||
var inner = cm.options.addModeClass && [null];
|
||
if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
|
||
while (!stream.eol()) {
|
||
if (stream.pos > cm.options.maxHighlightLength) {
|
||
flattenSpans = false;
|
||
if (forceToEnd) { processLine(cm, text, context, stream.pos); }
|
||
stream.pos = text.length;
|
||
style = null;
|
||
} else {
|
||
style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
|
||
}
|
||
if (inner) {
|
||
var mName = inner[0].name;
|
||
if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
|
||
}
|
||
if (!flattenSpans || curStyle != style) {
|
||
while (curStart < stream.start) {
|
||
curStart = Math.min(stream.start, curStart + 5000);
|
||
f(curStart, curStyle);
|
||
}
|
||
curStyle = style;
|
||
}
|
||
stream.start = stream.pos;
|
||
}
|
||
while (curStart < stream.pos) {
|
||
// Webkit seems to refuse to render text nodes longer than 57444
|
||
// characters, and returns inaccurate measurements in nodes
|
||
// starting around 5000 chars.
|
||
var pos = Math.min(stream.pos, curStart + 5000);
|
||
f(pos, curStyle);
|
||
curStart = pos;
|
||
}
|
||
}
|
||
|
||
// Finds the line to start with when starting a parse. Tries to
|
||
// find a line with a stateAfter, so that it can start with a
|
||
// valid state. If that fails, it returns the line with the
|
||
// smallest indentation, which tends to need the least context to
|
||
// parse correctly.
|
||
function findStartLine(cm, n, precise) {
|
||
var minindent, minline, doc = cm.doc;
|
||
var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
|
||
for (var search = n; search > lim; --search) {
|
||
if (search <= doc.first) { return doc.first }
|
||
var line = getLine(doc, search - 1), after = line.stateAfter;
|
||
if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
|
||
{ return search }
|
||
var indented = countColumn(line.text, null, cm.options.tabSize);
|
||
if (minline == null || minindent > indented) {
|
||
minline = search - 1;
|
||
minindent = indented;
|
||
}
|
||
}
|
||
return minline
|
||
}
|
||
|
||
function retreatFrontier(doc, n) {
|
||
doc.modeFrontier = Math.min(doc.modeFrontier, n);
|
||
if (doc.highlightFrontier < n - 10) { return }
|
||
var start = doc.first;
|
||
for (var line = n - 1; line > start; line--) {
|
||
var saved = getLine(doc, line).stateAfter;
|
||
// change is on 3
|
||
// state on line 1 looked ahead 2 -- so saw 3
|
||
// test 1 + 2 < 3 should cover this
|
||
if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
|
||
start = line + 1;
|
||
break
|
||
}
|
||
}
|
||
doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
|
||
}
|
||
|
||
// Optimize some code when these features are not used.
|
||
var sawReadOnlySpans = false, sawCollapsedSpans = false;
|
||
|
||
function seeReadOnlySpans() {
|
||
sawReadOnlySpans = true;
|
||
}
|
||
|
||
function seeCollapsedSpans() {
|
||
sawCollapsedSpans = true;
|
||
}
|
||
|
||
// TEXTMARKER SPANS
|
||
|
||
function MarkedSpan(marker, from, to) {
|
||
this.marker = marker;
|
||
this.from = from; this.to = to;
|
||
}
|
||
|
||
// Search an array of spans for a span matching the given marker.
|
||
function getMarkedSpanFor(spans, marker) {
|
||
if (spans) { for (var i = 0; i < spans.length; ++i) {
|
||
var span = spans[i];
|
||
if (span.marker == marker) { return span }
|
||
} }
|
||
}
|
||
// Remove a span from an array, returning undefined if no spans are
|
||
// left (we don't store arrays for lines without spans).
|
||
function removeMarkedSpan(spans, span) {
|
||
var r;
|
||
for (var i = 0; i < spans.length; ++i)
|
||
{ if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
|
||
return r
|
||
}
|
||
// Add a span to a line.
|
||
function addMarkedSpan(line, span) {
|
||
line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
|
||
span.marker.attachLine(line);
|
||
}
|
||
|
||
// Used for the algorithm that adjusts markers for a change in the
|
||
// document. These functions cut an array of spans at a given
|
||
// character position, returning an array of remaining chunks (or
|
||
// undefined if nothing remains).
|
||
function markedSpansBefore(old, startCh, isInsert) {
|
||
var nw;
|
||
if (old) { for (var i = 0; i < old.length; ++i) {
|
||
var span = old[i], marker = span.marker;
|
||
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
|
||
if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
|
||
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
|
||
;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
|
||
}
|
||
} }
|
||
return nw
|
||
}
|
||
function markedSpansAfter(old, endCh, isInsert) {
|
||
var nw;
|
||
if (old) { for (var i = 0; i < old.length; ++i) {
|
||
var span = old[i], marker = span.marker;
|
||
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
|
||
if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
|
||
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
|
||
;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
|
||
span.to == null ? null : span.to - endCh));
|
||
}
|
||
} }
|
||
return nw
|
||
}
|
||
|
||
// Given a change object, compute the new set of marker spans that
|
||
// cover the line in which the change took place. Removes spans
|
||
// entirely within the change, reconnects spans belonging to the
|
||
// same marker that appear on both sides of the change, and cuts off
|
||
// spans partially within the change. Returns an array of span
|
||
// arrays with one element for each line in (after) the change.
|
||
function stretchSpansOverChange(doc, change) {
|
||
if (change.full) { return null }
|
||
var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
|
||
var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
|
||
if (!oldFirst && !oldLast) { return null }
|
||
|
||
var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
|
||
// Get the spans that 'stick out' on both sides
|
||
var first = markedSpansBefore(oldFirst, startCh, isInsert);
|
||
var last = markedSpansAfter(oldLast, endCh, isInsert);
|
||
|
||
// Next, merge those two ends
|
||
var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
|
||
if (first) {
|
||
// Fix up .to properties of first
|
||
for (var i = 0; i < first.length; ++i) {
|
||
var span = first[i];
|
||
if (span.to == null) {
|
||
var found = getMarkedSpanFor(last, span.marker);
|
||
if (!found) { span.to = startCh; }
|
||
else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
|
||
}
|
||
}
|
||
}
|
||
if (last) {
|
||
// Fix up .from in last (or move them into first in case of sameLine)
|
||
for (var i$1 = 0; i$1 < last.length; ++i$1) {
|
||
var span$1 = last[i$1];
|
||
if (span$1.to != null) { span$1.to += offset; }
|
||
if (span$1.from == null) {
|
||
var found$1 = getMarkedSpanFor(first, span$1.marker);
|
||
if (!found$1) {
|
||
span$1.from = offset;
|
||
if (sameLine) { (first || (first = [])).push(span$1); }
|
||
}
|
||
} else {
|
||
span$1.from += offset;
|
||
if (sameLine) { (first || (first = [])).push(span$1); }
|
||
}
|
||
}
|
||
}
|
||
// Make sure we didn't create any zero-length spans
|
||
if (first) { first = clearEmptySpans(first); }
|
||
if (last && last != first) { last = clearEmptySpans(last); }
|
||
|
||
var newMarkers = [first];
|
||
if (!sameLine) {
|
||
// Fill gap with whole-line-spans
|
||
var gap = change.text.length - 2, gapMarkers;
|
||
if (gap > 0 && first)
|
||
{ for (var i$2 = 0; i$2 < first.length; ++i$2)
|
||
{ if (first[i$2].to == null)
|
||
{ (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
|
||
for (var i$3 = 0; i$3 < gap; ++i$3)
|
||
{ newMarkers.push(gapMarkers); }
|
||
newMarkers.push(last);
|
||
}
|
||
return newMarkers
|
||
}
|
||
|
||
// Remove spans that are empty and don't have a clearWhenEmpty
|
||
// option of false.
|
||
function clearEmptySpans(spans) {
|
||
for (var i = 0; i < spans.length; ++i) {
|
||
var span = spans[i];
|
||
if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
|
||
{ spans.splice(i--, 1); }
|
||
}
|
||
if (!spans.length) { return null }
|
||
return spans
|
||
}
|
||
|
||
// Used to 'clip' out readOnly ranges when making a change.
|
||
function removeReadOnlyRanges(doc, from, to) {
|
||
var markers = null;
|
||
doc.iter(from.line, to.line + 1, function (line) {
|
||
if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
|
||
var mark = line.markedSpans[i].marker;
|
||
if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
|
||
{ (markers || (markers = [])).push(mark); }
|
||
} }
|
||
});
|
||
if (!markers) { return null }
|
||
var parts = [{from: from, to: to}];
|
||
for (var i = 0; i < markers.length; ++i) {
|
||
var mk = markers[i], m = mk.find(0);
|
||
for (var j = 0; j < parts.length; ++j) {
|
||
var p = parts[j];
|
||
if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
|
||
var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
|
||
if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
|
||
{ newParts.push({from: p.from, to: m.from}); }
|
||
if (dto > 0 || !mk.inclusiveRight && !dto)
|
||
{ newParts.push({from: m.to, to: p.to}); }
|
||
parts.splice.apply(parts, newParts);
|
||
j += newParts.length - 3;
|
||
}
|
||
}
|
||
return parts
|
||
}
|
||
|
||
// Connect or disconnect spans from a line.
|
||
function detachMarkedSpans(line) {
|
||
var spans = line.markedSpans;
|
||
if (!spans) { return }
|
||
for (var i = 0; i < spans.length; ++i)
|
||
{ spans[i].marker.detachLine(line); }
|
||
line.markedSpans = null;
|
||
}
|
||
function attachMarkedSpans(line, spans) {
|
||
if (!spans) { return }
|
||
for (var i = 0; i < spans.length; ++i)
|
||
{ spans[i].marker.attachLine(line); }
|
||
line.markedSpans = spans;
|
||
}
|
||
|
||
// Helpers used when computing which overlapping collapsed span
|
||
// counts as the larger one.
|
||
function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
|
||
function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
|
||
|
||
// Returns a number indicating which of two overlapping collapsed
|
||
// spans is larger (and thus includes the other). Falls back to
|
||
// comparing ids when the spans cover exactly the same range.
|
||
function compareCollapsedMarkers(a, b) {
|
||
var lenDiff = a.lines.length - b.lines.length;
|
||
if (lenDiff != 0) { return lenDiff }
|
||
var aPos = a.find(), bPos = b.find();
|
||
var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
|
||
if (fromCmp) { return -fromCmp }
|
||
var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
|
||
if (toCmp) { return toCmp }
|
||
return b.id - a.id
|
||
}
|
||
|
||
// Find out whether a line ends or starts in a collapsed span. If
|
||
// so, return the marker for that span.
|
||
function collapsedSpanAtSide(line, start) {
|
||
var sps = sawCollapsedSpans && line.markedSpans, found;
|
||
if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
|
||
sp = sps[i];
|
||
if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
|
||
(!found || compareCollapsedMarkers(found, sp.marker) < 0))
|
||
{ found = sp.marker; }
|
||
} }
|
||
return found
|
||
}
|
||
function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
|
||
function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
|
||
|
||
function collapsedSpanAround(line, ch) {
|
||
var sps = sawCollapsedSpans && line.markedSpans, found;
|
||
if (sps) { for (var i = 0; i < sps.length; ++i) {
|
||
var sp = sps[i];
|
||
if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
|
||
(!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
|
||
} }
|
||
return found
|
||
}
|
||
|
||
// Test whether there exists a collapsed span that partially
|
||
// overlaps (covers the start or end, but not both) of a new span.
|
||
// Such overlap is not allowed.
|
||
function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
|
||
var line = getLine(doc, lineNo);
|
||
var sps = sawCollapsedSpans && line.markedSpans;
|
||
if (sps) { for (var i = 0; i < sps.length; ++i) {
|
||
var sp = sps[i];
|
||
if (!sp.marker.collapsed) { continue }
|
||
var found = sp.marker.find(0);
|
||
var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
|
||
var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
|
||
if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
|
||
if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
|
||
fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
|
||
{ return true }
|
||
} }
|
||
}
|
||
|
||
// A visual line is a line as drawn on the screen. Folding, for
|
||
// example, can cause multiple logical lines to appear on the same
|
||
// visual line. This finds the start of the visual line that the
|
||
// given line is part of (usually that is the line itself).
|
||
function visualLine(line) {
|
||
var merged;
|
||
while (merged = collapsedSpanAtStart(line))
|
||
{ line = merged.find(-1, true).line; }
|
||
return line
|
||
}
|
||
|
||
function visualLineEnd(line) {
|
||
var merged;
|
||
while (merged = collapsedSpanAtEnd(line))
|
||
{ line = merged.find(1, true).line; }
|
||
return line
|
||
}
|
||
|
||
// Returns an array of logical lines that continue the visual line
|
||
// started by the argument, or undefined if there are no such lines.
|
||
function visualLineContinued(line) {
|
||
var merged, lines;
|
||
while (merged = collapsedSpanAtEnd(line)) {
|
||
line = merged.find(1, true).line
|
||
;(lines || (lines = [])).push(line);
|
||
}
|
||
return lines
|
||
}
|
||
|
||
// Get the line number of the start of the visual line that the
|
||
// given line number is part of.
|
||
function visualLineNo(doc, lineN) {
|
||
var line = getLine(doc, lineN), vis = visualLine(line);
|
||
if (line == vis) { return lineN }
|
||
return lineNo(vis)
|
||
}
|
||
|
||
// Get the line number of the start of the next visual line after
|
||
// the given line.
|
||
function visualLineEndNo(doc, lineN) {
|
||
if (lineN > doc.lastLine()) { return lineN }
|
||
var line = getLine(doc, lineN), merged;
|
||
if (!lineIsHidden(doc, line)) { return lineN }
|
||
while (merged = collapsedSpanAtEnd(line))
|
||
{ line = merged.find(1, true).line; }
|
||
return lineNo(line) + 1
|
||
}
|
||
|
||
// Compute whether a line is hidden. Lines count as hidden when they
|
||
// are part of a visual line that starts with another line, or when
|
||
// they are entirely covered by collapsed, non-widget span.
|
||
function lineIsHidden(doc, line) {
|
||
var sps = sawCollapsedSpans && line.markedSpans;
|
||
if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
|
||
sp = sps[i];
|
||
if (!sp.marker.collapsed) { continue }
|
||
if (sp.from == null) { return true }
|
||
if (sp.marker.widgetNode) { continue }
|
||
if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
|
||
{ return true }
|
||
} }
|
||
}
|
||
function lineIsHiddenInner(doc, line, span) {
|
||
if (span.to == null) {
|
||
var end = span.marker.find(1, true);
|
||
return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
|
||
}
|
||
if (span.marker.inclusiveRight && span.to == line.text.length)
|
||
{ return true }
|
||
for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
|
||
sp = line.markedSpans[i];
|
||
if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
|
||
(sp.to == null || sp.to != span.from) &&
|
||
(sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
|
||
lineIsHiddenInner(doc, line, sp)) { return true }
|
||
}
|
||
}
|
||
|
||
// Find the height above the given line.
|
||
function heightAtLine(lineObj) {
|
||
lineObj = visualLine(lineObj);
|
||
|
||
var h = 0, chunk = lineObj.parent;
|
||
for (var i = 0; i < chunk.lines.length; ++i) {
|
||
var line = chunk.lines[i];
|
||
if (line == lineObj) { break }
|
||
else { h += line.height; }
|
||
}
|
||
for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
|
||
for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
|
||
var cur = p.children[i$1];
|
||
if (cur == chunk) { break }
|
||
else { h += cur.height; }
|
||
}
|
||
}
|
||
return h
|
||
}
|
||
|
||
// Compute the character length of a line, taking into account
|
||
// collapsed ranges (see markText) that might hide parts, and join
|
||
// other lines onto it.
|
||
function lineLength(line) {
|
||
if (line.height == 0) { return 0 }
|
||
var len = line.text.length, merged, cur = line;
|
||
while (merged = collapsedSpanAtStart(cur)) {
|
||
var found = merged.find(0, true);
|
||
cur = found.from.line;
|
||
len += found.from.ch - found.to.ch;
|
||
}
|
||
cur = line;
|
||
while (merged = collapsedSpanAtEnd(cur)) {
|
||
var found$1 = merged.find(0, true);
|
||
len -= cur.text.length - found$1.from.ch;
|
||
cur = found$1.to.line;
|
||
len += cur.text.length - found$1.to.ch;
|
||
}
|
||
return len
|
||
}
|
||
|
||
// Find the longest line in the document.
|
||
function findMaxLine(cm) {
|
||
var d = cm.display, doc = cm.doc;
|
||
d.maxLine = getLine(doc, doc.first);
|
||
d.maxLineLength = lineLength(d.maxLine);
|
||
d.maxLineChanged = true;
|
||
doc.iter(function (line) {
|
||
var len = lineLength(line);
|
||
if (len > d.maxLineLength) {
|
||
d.maxLineLength = len;
|
||
d.maxLine = line;
|
||
}
|
||
});
|
||
}
|
||
|
||
// LINE DATA STRUCTURE
|
||
|
||
// Line objects. These hold state related to a line, including
|
||
// highlighting info (the styles array).
|
||
var Line = function(text, markedSpans, estimateHeight) {
|
||
this.text = text;
|
||
attachMarkedSpans(this, markedSpans);
|
||
this.height = estimateHeight ? estimateHeight(this) : 1;
|
||
};
|
||
|
||
Line.prototype.lineNo = function () { return lineNo(this) };
|
||
eventMixin(Line);
|
||
|
||
// Change the content (text, markers) of a line. Automatically
|
||
// invalidates cached information and tries to re-estimate the
|
||
// line's height.
|
||
function updateLine(line, text, markedSpans, estimateHeight) {
|
||
line.text = text;
|
||
if (line.stateAfter) { line.stateAfter = null; }
|
||
if (line.styles) { line.styles = null; }
|
||
if (line.order != null) { line.order = null; }
|
||
detachMarkedSpans(line);
|
||
attachMarkedSpans(line, markedSpans);
|
||
var estHeight = estimateHeight ? estimateHeight(line) : 1;
|
||
if (estHeight != line.height) { updateLineHeight(line, estHeight); }
|
||
}
|
||
|
||
// Detach a line from the document tree and its markers.
|
||
function cleanUpLine(line) {
|
||
line.parent = null;
|
||
detachMarkedSpans(line);
|
||
}
|
||
|
||
// Convert a style as returned by a mode (either null, or a string
|
||
// containing one or more styles) to a CSS style. This is cached,
|
||
// and also looks for line-wide styles.
|
||
var styleToClassCache = {}, styleToClassCacheWithMode = {};
|
||
function interpretTokenStyle(style, options) {
|
||
if (!style || /^\s*$/.test(style)) { return null }
|
||
var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
|
||
return cache[style] ||
|
||
(cache[style] = style.replace(/\S+/g, "cm-$&"))
|
||
}
|
||
|
||
// Render the DOM representation of the text of a line. Also builds
|
||
// up a 'line map', which points at the DOM nodes that represent
|
||
// specific stretches of text, and is used by the measuring code.
|
||
// The returned object contains the DOM node, this map, and
|
||
// information about line-wide styles that were set by the mode.
|
||
function buildLineContent(cm, lineView) {
|
||
// The padding-right forces the element to have a 'border', which
|
||
// is needed on Webkit to be able to get line-level bounding
|
||
// rectangles for it (in measureChar).
|
||
var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
|
||
var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
|
||
col: 0, pos: 0, cm: cm,
|
||
trailingSpace: false,
|
||
splitSpaces: cm.getOption("lineWrapping")};
|
||
lineView.measure = {};
|
||
|
||
// Iterate over the logical lines that make up this visual line.
|
||
for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
|
||
var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
|
||
builder.pos = 0;
|
||
builder.addToken = buildToken;
|
||
// Optionally wire in some hacks into the token-rendering
|
||
// algorithm, to deal with browser quirks.
|
||
if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
|
||
{ builder.addToken = buildTokenBadBidi(builder.addToken, order); }
|
||
builder.map = [];
|
||
var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
|
||
insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
|
||
if (line.styleClasses) {
|
||
if (line.styleClasses.bgClass)
|
||
{ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
|
||
if (line.styleClasses.textClass)
|
||
{ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
|
||
}
|
||
|
||
// Ensure at least a single node is present, for measuring.
|
||
if (builder.map.length == 0)
|
||
{ builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
|
||
|
||
// Store the map and a cache object for the current logical line
|
||
if (i == 0) {
|
||
lineView.measure.map = builder.map;
|
||
lineView.measure.cache = {};
|
||
} else {
|
||
(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
|
||
;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
|
||
}
|
||
}
|
||
|
||
// See issue #2901
|
||
if (webkit) {
|
||
var last = builder.content.lastChild;
|
||
if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
|
||
{ builder.content.className = "cm-tab-wrap-hack"; }
|
||
}
|
||
|
||
signal(cm, "renderLine", cm, lineView.line, builder.pre);
|
||
if (builder.pre.className)
|
||
{ builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
|
||
|
||
return builder
|
||
}
|
||
|
||
function defaultSpecialCharPlaceholder(ch) {
|
||
var token = elt("span", "\u2022", "cm-invalidchar");
|
||
token.title = "\\u" + ch.charCodeAt(0).toString(16);
|
||
token.setAttribute("aria-label", token.title);
|
||
return token
|
||
}
|
||
|
||
// Build up the DOM representation for a single token, and add it to
|
||
// the line map. Takes care to render special characters separately.
|
||
function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
|
||
if (!text) { return }
|
||
var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
|
||
var special = builder.cm.state.specialChars, mustWrap = false;
|
||
var content;
|
||
if (!special.test(text)) {
|
||
builder.col += text.length;
|
||
content = document.createTextNode(displayText);
|
||
builder.map.push(builder.pos, builder.pos + text.length, content);
|
||
if (ie && ie_version < 9) { mustWrap = true; }
|
||
builder.pos += text.length;
|
||
} else {
|
||
content = document.createDocumentFragment();
|
||
var pos = 0;
|
||
while (true) {
|
||
special.lastIndex = pos;
|
||
var m = special.exec(text);
|
||
var skipped = m ? m.index - pos : text.length - pos;
|
||
if (skipped) {
|
||
var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
|
||
if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
|
||
else { content.appendChild(txt); }
|
||
builder.map.push(builder.pos, builder.pos + skipped, txt);
|
||
builder.col += skipped;
|
||
builder.pos += skipped;
|
||
}
|
||
if (!m) { break }
|
||
pos += skipped + 1;
|
||
var txt$1 = (void 0);
|
||
if (m[0] == "\t") {
|
||
var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
|
||
txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
|
||
txt$1.setAttribute("role", "presentation");
|
||
txt$1.setAttribute("cm-text", "\t");
|
||
builder.col += tabWidth;
|
||
} else if (m[0] == "\r" || m[0] == "\n") {
|
||
txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
|
||
txt$1.setAttribute("cm-text", m[0]);
|
||
builder.col += 1;
|
||
} else {
|
||
txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
|
||
txt$1.setAttribute("cm-text", m[0]);
|
||
if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
|
||
else { content.appendChild(txt$1); }
|
||
builder.col += 1;
|
||
}
|
||
builder.map.push(builder.pos, builder.pos + 1, txt$1);
|
||
builder.pos++;
|
||
}
|
||
}
|
||
builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
|
||
if (style || startStyle || endStyle || mustWrap || css) {
|
||
var fullStyle = style || "";
|
||
if (startStyle) { fullStyle += startStyle; }
|
||
if (endStyle) { fullStyle += endStyle; }
|
||
var token = elt("span", [content], fullStyle, css);
|
||
if (attributes) {
|
||
for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
|
||
{ token.setAttribute(attr, attributes[attr]); } }
|
||
}
|
||
return builder.content.appendChild(token)
|
||
}
|
||
builder.content.appendChild(content);
|
||
}
|
||
|
||
// Change some spaces to NBSP to prevent the browser from collapsing
|
||
// trailing spaces at the end of a line when rendering text (issue #1362).
|
||
function splitSpaces(text, trailingBefore) {
|
||
if (text.length > 1 && !/ /.test(text)) { return text }
|
||
var spaceBefore = trailingBefore, result = "";
|
||
for (var i = 0; i < text.length; i++) {
|
||
var ch = text.charAt(i);
|
||
if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
|
||
{ ch = "\u00a0"; }
|
||
result += ch;
|
||
spaceBefore = ch == " ";
|
||
}
|
||
return result
|
||
}
|
||
|
||
// Work around nonsense dimensions being reported for stretches of
|
||
// right-to-left text.
|
||
function buildTokenBadBidi(inner, order) {
|
||
return function (builder, text, style, startStyle, endStyle, css, attributes) {
|
||
style = style ? style + " cm-force-border" : "cm-force-border";
|
||
var start = builder.pos, end = start + text.length;
|
||
for (;;) {
|
||
// Find the part that overlaps with the start of this text
|
||
var part = (void 0);
|
||
for (var i = 0; i < order.length; i++) {
|
||
part = order[i];
|
||
if (part.to > start && part.from <= start) { break }
|
||
}
|
||
if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) }
|
||
inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes);
|
||
startStyle = null;
|
||
text = text.slice(part.to - start);
|
||
start = part.to;
|
||
}
|
||
}
|
||
}
|
||
|
||
function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
|
||
var widget = !ignoreWidget && marker.widgetNode;
|
||
if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
|
||
if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
|
||
if (!widget)
|
||
{ widget = builder.content.appendChild(document.createElement("span")); }
|
||
widget.setAttribute("cm-marker", marker.id);
|
||
}
|
||
if (widget) {
|
||
builder.cm.display.input.setUneditable(widget);
|
||
builder.content.appendChild(widget);
|
||
}
|
||
builder.pos += size;
|
||
builder.trailingSpace = false;
|
||
}
|
||
|
||
// Outputs a number of spans to make up a line, taking highlighting
|
||
// and marked text into account.
|
||
function insertLineContent(line, builder, styles) {
|
||
var spans = line.markedSpans, allText = line.text, at = 0;
|
||
if (!spans) {
|
||
for (var i$1 = 1; i$1 < styles.length; i$1+=2)
|
||
{ builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
|
||
return
|
||
}
|
||
|
||
var len = allText.length, pos = 0, i = 1, text = "", style, css;
|
||
var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes;
|
||
for (;;) {
|
||
if (nextChange == pos) { // Update current marker set
|
||
spanStyle = spanEndStyle = spanStartStyle = css = "";
|
||
attributes = null;
|
||
collapsed = null; nextChange = Infinity;
|
||
var foundBookmarks = [], endStyles = (void 0);
|
||
for (var j = 0; j < spans.length; ++j) {
|
||
var sp = spans[j], m = sp.marker;
|
||
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
|
||
foundBookmarks.push(m);
|
||
} else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
|
||
if (sp.to != null && sp.to != pos && nextChange > sp.to) {
|
||
nextChange = sp.to;
|
||
spanEndStyle = "";
|
||
}
|
||
if (m.className) { spanStyle += " " + m.className; }
|
||
if (m.css) { css = (css ? css + ";" : "") + m.css; }
|
||
if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
|
||
if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
|
||
// support for the old title property
|
||
// https://github.com/codemirror/CodeMirror/pull/5673
|
||
if (m.title) { (attributes || (attributes = {})).title = m.title; }
|
||
if (m.attributes) {
|
||
for (var attr in m.attributes)
|
||
{ (attributes || (attributes = {}))[attr] = m.attributes[attr]; }
|
||
}
|
||
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
|
||
{ collapsed = sp; }
|
||
} else if (sp.from > pos && nextChange > sp.from) {
|
||
nextChange = sp.from;
|
||
}
|
||
}
|
||
if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
|
||
{ if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
|
||
|
||
if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
|
||
{ buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
|
||
if (collapsed && (collapsed.from || 0) == pos) {
|
||
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
|
||
collapsed.marker, collapsed.from == null);
|
||
if (collapsed.to == null) { return }
|
||
if (collapsed.to == pos) { collapsed = false; }
|
||
}
|
||
}
|
||
if (pos >= len) { break }
|
||
|
||
var upto = Math.min(len, nextChange);
|
||
while (true) {
|
||
if (text) {
|
||
var end = pos + text.length;
|
||
if (!collapsed) {
|
||
var tokenText = end > upto ? text.slice(0, upto - pos) : text;
|
||
builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
|
||
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes);
|
||
}
|
||
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
|
||
pos = end;
|
||
spanStartStyle = "";
|
||
}
|
||
text = allText.slice(at, at = styles[i++]);
|
||
style = interpretTokenStyle(styles[i++], builder.cm.options);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// These objects are used to represent the visible (currently drawn)
|
||
// part of the document. A LineView may correspond to multiple
|
||
// logical lines, if those are connected by collapsed ranges.
|
||
function LineView(doc, line, lineN) {
|
||
// The starting line
|
||
this.line = line;
|
||
// Continuing lines, if any
|
||
this.rest = visualLineContinued(line);
|
||
// Number of logical lines in this visual line
|
||
this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
|
||
this.node = this.text = null;
|
||
this.hidden = lineIsHidden(doc, line);
|
||
}
|
||
|
||
// Create a range of LineView objects for the given lines.
|
||
function buildViewArray(cm, from, to) {
|
||
var array = [], nextPos;
|
||
for (var pos = from; pos < to; pos = nextPos) {
|
||
var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
|
||
nextPos = pos + view.size;
|
||
array.push(view);
|
||
}
|
||
return array
|
||
}
|
||
|
||
var operationGroup = null;
|
||
|
||
function pushOperation(op) {
|
||
if (operationGroup) {
|
||
operationGroup.ops.push(op);
|
||
} else {
|
||
op.ownsGroup = operationGroup = {
|
||
ops: [op],
|
||
delayedCallbacks: []
|
||
};
|
||
}
|
||
}
|
||
|
||
function fireCallbacksForOps(group) {
|
||
// Calls delayed callbacks and cursorActivity handlers until no
|
||
// new ones appear
|
||
var callbacks = group.delayedCallbacks, i = 0;
|
||
do {
|
||
for (; i < callbacks.length; i++)
|
||
{ callbacks[i].call(null); }
|
||
for (var j = 0; j < group.ops.length; j++) {
|
||
var op = group.ops[j];
|
||
if (op.cursorActivityHandlers)
|
||
{ while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
|
||
{ op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
|
||
}
|
||
} while (i < callbacks.length)
|
||
}
|
||
|
||
function finishOperation(op, endCb) {
|
||
var group = op.ownsGroup;
|
||
if (!group) { return }
|
||
|
||
try { fireCallbacksForOps(group); }
|
||
finally {
|
||
operationGroup = null;
|
||
endCb(group);
|
||
}
|
||
}
|
||
|
||
var orphanDelayedCallbacks = null;
|
||
|
||
// Often, we want to signal events at a point where we are in the
|
||
// middle of some work, but don't want the handler to start calling
|
||
// other methods on the editor, which might be in an inconsistent
|
||
// state or simply not expect any other events to happen.
|
||
// signalLater looks whether there are any handlers, and schedules
|
||
// them to be executed when the last operation ends, or, if no
|
||
// operation is active, when a timeout fires.
|
||
function signalLater(emitter, type /*, values...*/) {
|
||
var arr = getHandlers(emitter, type);
|
||
if (!arr.length) { return }
|
||
var args = Array.prototype.slice.call(arguments, 2), list;
|
||
if (operationGroup) {
|
||
list = operationGroup.delayedCallbacks;
|
||
} else if (orphanDelayedCallbacks) {
|
||
list = orphanDelayedCallbacks;
|
||
} else {
|
||
list = orphanDelayedCallbacks = [];
|
||
setTimeout(fireOrphanDelayed, 0);
|
||
}
|
||
var loop = function ( i ) {
|
||
list.push(function () { return arr[i].apply(null, args); });
|
||
};
|
||
|
||
for (var i = 0; i < arr.length; ++i)
|
||
loop( i );
|
||
}
|
||
|
||
function fireOrphanDelayed() {
|
||
var delayed = orphanDelayedCallbacks;
|
||
orphanDelayedCallbacks = null;
|
||
for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
|
||
}
|
||
|
||
// When an aspect of a line changes, a string is added to
|
||
// lineView.changes. This updates the relevant part of the line's
|
||
// DOM structure.
|
||
function updateLineForChanges(cm, lineView, lineN, dims) {
|
||
for (var j = 0; j < lineView.changes.length; j++) {
|
||
var type = lineView.changes[j];
|
||
if (type == "text") { updateLineText(cm, lineView); }
|
||
else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
|
||
else if (type == "class") { updateLineClasses(cm, lineView); }
|
||
else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
|
||
}
|
||
lineView.changes = null;
|
||
}
|
||
|
||
// Lines with gutter elements, widgets or a background class need to
|
||
// be wrapped, and have the extra elements added to the wrapper div
|
||
function ensureLineWrapped(lineView) {
|
||
if (lineView.node == lineView.text) {
|
||
lineView.node = elt("div", null, null, "position: relative");
|
||
if (lineView.text.parentNode)
|
||
{ lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
|
||
lineView.node.appendChild(lineView.text);
|
||
if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
|
||
}
|
||
return lineView.node
|
||
}
|
||
|
||
function updateLineBackground(cm, lineView) {
|
||
var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
|
||
if (cls) { cls += " CodeMirror-linebackground"; }
|
||
if (lineView.background) {
|
||
if (cls) { lineView.background.className = cls; }
|
||
else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
|
||
} else if (cls) {
|
||
var wrap = ensureLineWrapped(lineView);
|
||
lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
|
||
cm.display.input.setUneditable(lineView.background);
|
||
}
|
||
}
|
||
|
||
// Wrapper around buildLineContent which will reuse the structure
|
||
// in display.externalMeasured when possible.
|
||
function getLineContent(cm, lineView) {
|
||
var ext = cm.display.externalMeasured;
|
||
if (ext && ext.line == lineView.line) {
|
||
cm.display.externalMeasured = null;
|
||
lineView.measure = ext.measure;
|
||
return ext.built
|
||
}
|
||
return buildLineContent(cm, lineView)
|
||
}
|
||
|
||
// Redraw the line's text. Interacts with the background and text
|
||
// classes because the mode may output tokens that influence these
|
||
// classes.
|
||
function updateLineText(cm, lineView) {
|
||
var cls = lineView.text.className;
|
||
var built = getLineContent(cm, lineView);
|
||
if (lineView.text == lineView.node) { lineView.node = built.pre; }
|
||
lineView.text.parentNode.replaceChild(built.pre, lineView.text);
|
||
lineView.text = built.pre;
|
||
if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
|
||
lineView.bgClass = built.bgClass;
|
||
lineView.textClass = built.textClass;
|
||
updateLineClasses(cm, lineView);
|
||
} else if (cls) {
|
||
lineView.text.className = cls;
|
||
}
|
||
}
|
||
|
||
function updateLineClasses(cm, lineView) {
|
||
updateLineBackground(cm, lineView);
|
||
if (lineView.line.wrapClass)
|
||
{ ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
|
||
else if (lineView.node != lineView.text)
|
||
{ lineView.node.className = ""; }
|
||
var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
|
||
lineView.text.className = textClass || "";
|
||
}
|
||
|
||
function updateLineGutter(cm, lineView, lineN, dims) {
|
||
if (lineView.gutter) {
|
||
lineView.node.removeChild(lineView.gutter);
|
||
lineView.gutter = null;
|
||
}
|
||
if (lineView.gutterBackground) {
|
||
lineView.node.removeChild(lineView.gutterBackground);
|
||
lineView.gutterBackground = null;
|
||
}
|
||
if (lineView.line.gutterClass) {
|
||
var wrap = ensureLineWrapped(lineView);
|
||
lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
|
||
("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
|
||
cm.display.input.setUneditable(lineView.gutterBackground);
|
||
wrap.insertBefore(lineView.gutterBackground, lineView.text);
|
||
}
|
||
var markers = lineView.line.gutterMarkers;
|
||
if (cm.options.lineNumbers || markers) {
|
||
var wrap$1 = ensureLineWrapped(lineView);
|
||
var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
|
||
cm.display.input.setUneditable(gutterWrap);
|
||
wrap$1.insertBefore(gutterWrap, lineView.text);
|
||
if (lineView.line.gutterClass)
|
||
{ gutterWrap.className += " " + lineView.line.gutterClass; }
|
||
if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
|
||
{ lineView.lineNumber = gutterWrap.appendChild(
|
||
elt("div", lineNumberFor(cm.options, lineN),
|
||
"CodeMirror-linenumber CodeMirror-gutter-elt",
|
||
("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
|
||
if (markers) { for (var k = 0; k < cm.display.gutterSpecs.length; ++k) {
|
||
var id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id];
|
||
if (found)
|
||
{ gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
|
||
("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
|
||
} }
|
||
}
|
||
}
|
||
|
||
function updateLineWidgets(cm, lineView, dims) {
|
||
if (lineView.alignable) { lineView.alignable = null; }
|
||
var isWidget = classTest("CodeMirror-linewidget");
|
||
for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
|
||
next = node.nextSibling;
|
||
if (isWidget.test(node.className)) { lineView.node.removeChild(node); }
|
||
}
|
||
insertLineWidgets(cm, lineView, dims);
|
||
}
|
||
|
||
// Build a line's DOM representation from scratch
|
||
function buildLineElement(cm, lineView, lineN, dims) {
|
||
var built = getLineContent(cm, lineView);
|
||
lineView.text = lineView.node = built.pre;
|
||
if (built.bgClass) { lineView.bgClass = built.bgClass; }
|
||
if (built.textClass) { lineView.textClass = built.textClass; }
|
||
|
||
updateLineClasses(cm, lineView);
|
||
updateLineGutter(cm, lineView, lineN, dims);
|
||
insertLineWidgets(cm, lineView, dims);
|
||
return lineView.node
|
||
}
|
||
|
||
// A lineView may contain multiple logical lines (when merged by
|
||
// collapsed spans). The widgets for all of them need to be drawn.
|
||
function insertLineWidgets(cm, lineView, dims) {
|
||
insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
|
||
if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
|
||
{ insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
|
||
}
|
||
|
||
function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
|
||
if (!line.widgets) { return }
|
||
var wrap = ensureLineWrapped(lineView);
|
||
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
|
||
var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className ? " " + widget.className : ""));
|
||
if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
|
||
positionLineWidget(widget, node, lineView, dims);
|
||
cm.display.input.setUneditable(node);
|
||
if (allowAbove && widget.above)
|
||
{ wrap.insertBefore(node, lineView.gutter || lineView.text); }
|
||
else
|
||
{ wrap.appendChild(node); }
|
||
signalLater(widget, "redraw");
|
||
}
|
||
}
|
||
|
||
function positionLineWidget(widget, node, lineView, dims) {
|
||
if (widget.noHScroll) {
|
||
(lineView.alignable || (lineView.alignable = [])).push(node);
|
||
var width = dims.wrapperWidth;
|
||
node.style.left = dims.fixedPos + "px";
|
||
if (!widget.coverGutter) {
|
||
width -= dims.gutterTotalWidth;
|
||
node.style.paddingLeft = dims.gutterTotalWidth + "px";
|
||
}
|
||
node.style.width = width + "px";
|
||
}
|
||
if (widget.coverGutter) {
|
||
node.style.zIndex = 5;
|
||
node.style.position = "relative";
|
||
if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
|
||
}
|
||
}
|
||
|
||
function widgetHeight(widget) {
|
||
if (widget.height != null) { return widget.height }
|
||
var cm = widget.doc.cm;
|
||
if (!cm) { return 0 }
|
||
if (!contains(document.body, widget.node)) {
|
||
var parentStyle = "position: relative;";
|
||
if (widget.coverGutter)
|
||
{ parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
|
||
if (widget.noHScroll)
|
||
{ parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
|
||
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
|
||
}
|
||
return widget.height = widget.node.parentNode.offsetHeight
|
||
}
|
||
|
||
// Return true when the given mouse event happened in a widget
|
||
function eventInWidget(display, e) {
|
||
for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
|
||
if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
|
||
(n.parentNode == display.sizer && n != display.mover))
|
||
{ return true }
|
||
}
|
||
}
|
||
|
||
// POSITION MEASUREMENT
|
||
|
||
function paddingTop(display) {return display.lineSpace.offsetTop}
|
||
function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
|
||
function paddingH(display) {
|
||
if (display.cachedPaddingH) { return display.cachedPaddingH }
|
||
var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like"));
|
||
var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
|
||
var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
|
||
if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
|
||
return data
|
||
}
|
||
|
||
function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
|
||
function displayWidth(cm) {
|
||
return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
|
||
}
|
||
function displayHeight(cm) {
|
||
return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
|
||
}
|
||
|
||
// Ensure the lineView.wrapping.heights array is populated. This is
|
||
// an array of bottom offsets for the lines that make up a drawn
|
||
// line. When lineWrapping is on, there might be more than one
|
||
// height.
|
||
function ensureLineHeights(cm, lineView, rect) {
|
||
var wrapping = cm.options.lineWrapping;
|
||
var curWidth = wrapping && displayWidth(cm);
|
||
if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
|
||
var heights = lineView.measure.heights = [];
|
||
if (wrapping) {
|
||
lineView.measure.width = curWidth;
|
||
var rects = lineView.text.firstChild.getClientRects();
|
||
for (var i = 0; i < rects.length - 1; i++) {
|
||
var cur = rects[i], next = rects[i + 1];
|
||
if (Math.abs(cur.bottom - next.bottom) > 2)
|
||
{ heights.push((cur.bottom + next.top) / 2 - rect.top); }
|
||
}
|
||
}
|
||
heights.push(rect.bottom - rect.top);
|
||
}
|
||
}
|
||
|
||
// Find a line map (mapping character offsets to text nodes) and a
|
||
// measurement cache for the given line number. (A line view might
|
||
// contain multiple lines when collapsed ranges are present.)
|
||
function mapFromLineView(lineView, line, lineN) {
|
||
if (lineView.line == line)
|
||
{ return {map: lineView.measure.map, cache: lineView.measure.cache} }
|
||
for (var i = 0; i < lineView.rest.length; i++)
|
||
{ if (lineView.rest[i] == line)
|
||
{ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
|
||
for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
|
||
{ if (lineNo(lineView.rest[i$1]) > lineN)
|
||
{ return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
|
||
}
|
||
|
||
// Render a line into the hidden node display.externalMeasured. Used
|
||
// when measurement is needed for a line that's not in the viewport.
|
||
function updateExternalMeasurement(cm, line) {
|
||
line = visualLine(line);
|
||
var lineN = lineNo(line);
|
||
var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
|
||
view.lineN = lineN;
|
||
var built = view.built = buildLineContent(cm, view);
|
||
view.text = built.pre;
|
||
removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
|
||
return view
|
||
}
|
||
|
||
// Get a {top, bottom, left, right} box (in line-local coordinates)
|
||
// for a given character.
|
||
function measureChar(cm, line, ch, bias) {
|
||
return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
|
||
}
|
||
|
||
// Find a line view that corresponds to the given line number.
|
||
function findViewForLine(cm, lineN) {
|
||
if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
|
||
{ return cm.display.view[findViewIndex(cm, lineN)] }
|
||
var ext = cm.display.externalMeasured;
|
||
if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
|
||
{ return ext }
|
||
}
|
||
|
||
// Measurement can be split in two steps, the set-up work that
|
||
// applies to the whole line, and the measurement of the actual
|
||
// character. Functions like coordsChar, that need to do a lot of
|
||
// measurements in a row, can thus ensure that the set-up work is
|
||
// only done once.
|
||
function prepareMeasureForLine(cm, line) {
|
||
var lineN = lineNo(line);
|
||
var view = findViewForLine(cm, lineN);
|
||
if (view && !view.text) {
|
||
view = null;
|
||
} else if (view && view.changes) {
|
||
updateLineForChanges(cm, view, lineN, getDimensions(cm));
|
||
cm.curOp.forceUpdate = true;
|
||
}
|
||
if (!view)
|
||
{ view = updateExternalMeasurement(cm, line); }
|
||
|
||
var info = mapFromLineView(view, line, lineN);
|
||
return {
|
||
line: line, view: view, rect: null,
|
||
map: info.map, cache: info.cache, before: info.before,
|
||
hasHeights: false
|
||
}
|
||
}
|
||
|
||
// Given a prepared measurement object, measures the position of an
|
||
// actual character (or fetches it from the cache).
|
||
function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
|
||
if (prepared.before) { ch = -1; }
|
||
var key = ch + (bias || ""), found;
|
||
if (prepared.cache.hasOwnProperty(key)) {
|
||
found = prepared.cache[key];
|
||
} else {
|
||
if (!prepared.rect)
|
||
{ prepared.rect = prepared.view.text.getBoundingClientRect(); }
|
||
if (!prepared.hasHeights) {
|
||
ensureLineHeights(cm, prepared.view, prepared.rect);
|
||
prepared.hasHeights = true;
|
||
}
|
||
found = measureCharInner(cm, prepared, ch, bias);
|
||
if (!found.bogus) { prepared.cache[key] = found; }
|
||
}
|
||
return {left: found.left, right: found.right,
|
||
top: varHeight ? found.rtop : found.top,
|
||
bottom: varHeight ? found.rbottom : found.bottom}
|
||
}
|
||
|
||
var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
|
||
|
||
function nodeAndOffsetInLineMap(map, ch, bias) {
|
||
var node, start, end, collapse, mStart, mEnd;
|
||
// First, search the line map for the text node corresponding to,
|
||
// or closest to, the target character.
|
||
for (var i = 0; i < map.length; i += 3) {
|
||
mStart = map[i];
|
||
mEnd = map[i + 1];
|
||
if (ch < mStart) {
|
||
start = 0; end = 1;
|
||
collapse = "left";
|
||
} else if (ch < mEnd) {
|
||
start = ch - mStart;
|
||
end = start + 1;
|
||
} else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
|
||
end = mEnd - mStart;
|
||
start = end - 1;
|
||
if (ch >= mEnd) { collapse = "right"; }
|
||
}
|
||
if (start != null) {
|
||
node = map[i + 2];
|
||
if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
|
||
{ collapse = bias; }
|
||
if (bias == "left" && start == 0)
|
||
{ while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
|
||
node = map[(i -= 3) + 2];
|
||
collapse = "left";
|
||
} }
|
||
if (bias == "right" && start == mEnd - mStart)
|
||
{ while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
|
||
node = map[(i += 3) + 2];
|
||
collapse = "right";
|
||
} }
|
||
break
|
||
}
|
||
}
|
||
return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
|
||
}
|
||
|
||
function getUsefulRect(rects, bias) {
|
||
var rect = nullRect;
|
||
if (bias == "left") { for (var i = 0; i < rects.length; i++) {
|
||
if ((rect = rects[i]).left != rect.right) { break }
|
||
} } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
|
||
if ((rect = rects[i$1]).left != rect.right) { break }
|
||
} }
|
||
return rect
|
||
}
|
||
|
||
function measureCharInner(cm, prepared, ch, bias) {
|
||
var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
|
||
var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
|
||
|
||
var rect;
|
||
if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
|
||
for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
|
||
while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
|
||
while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
|
||
if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
|
||
{ rect = node.parentNode.getBoundingClientRect(); }
|
||
else
|
||
{ rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
|
||
if (rect.left || rect.right || start == 0) { break }
|
||
end = start;
|
||
start = start - 1;
|
||
collapse = "right";
|
||
}
|
||
if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
|
||
} else { // If it is a widget, simply get the box for the whole widget.
|
||
if (start > 0) { collapse = bias = "right"; }
|
||
var rects;
|
||
if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
|
||
{ rect = rects[bias == "right" ? rects.length - 1 : 0]; }
|
||
else
|
||
{ rect = node.getBoundingClientRect(); }
|
||
}
|
||
if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
|
||
var rSpan = node.parentNode.getClientRects()[0];
|
||
if (rSpan)
|
||
{ rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
|
||
else
|
||
{ rect = nullRect; }
|
||
}
|
||
|
||
var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
|
||
var mid = (rtop + rbot) / 2;
|
||
var heights = prepared.view.measure.heights;
|
||
var i = 0;
|
||
for (; i < heights.length - 1; i++)
|
||
{ if (mid < heights[i]) { break } }
|
||
var top = i ? heights[i - 1] : 0, bot = heights[i];
|
||
var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
|
||
right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
|
||
top: top, bottom: bot};
|
||
if (!rect.left && !rect.right) { result.bogus = true; }
|
||
if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
|
||
|
||
return result
|
||
}
|
||
|
||
// Work around problem with bounding client rects on ranges being
|
||
// returned incorrectly when zoomed on IE10 and below.
|
||
function maybeUpdateRectForZooming(measure, rect) {
|
||
if (!window.screen || screen.logicalXDPI == null ||
|
||
screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
|
||
{ return rect }
|
||
var scaleX = screen.logicalXDPI / screen.deviceXDPI;
|
||
var scaleY = screen.logicalYDPI / screen.deviceYDPI;
|
||
return {left: rect.left * scaleX, right: rect.right * scaleX,
|
||
top: rect.top * scaleY, bottom: rect.bottom * scaleY}
|
||
}
|
||
|
||
function clearLineMeasurementCacheFor(lineView) {
|
||
if (lineView.measure) {
|
||
lineView.measure.cache = {};
|
||
lineView.measure.heights = null;
|
||
if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
|
||
{ lineView.measure.caches[i] = {}; } }
|
||
}
|
||
}
|
||
|
||
function clearLineMeasurementCache(cm) {
|
||
cm.display.externalMeasure = null;
|
||
removeChildren(cm.display.lineMeasure);
|
||
for (var i = 0; i < cm.display.view.length; i++)
|
||
{ clearLineMeasurementCacheFor(cm.display.view[i]); }
|
||
}
|
||
|
||
function clearCaches(cm) {
|
||
clearLineMeasurementCache(cm);
|
||
cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
|
||
if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
|
||
cm.display.lineNumChars = null;
|
||
}
|
||
|
||
function pageScrollX() {
|
||
// Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
|
||
// which causes page_Offset and bounding client rects to use
|
||
// different reference viewports and invalidate our calculations.
|
||
if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
|
||
return window.pageXOffset || (document.documentElement || document.body).scrollLeft
|
||
}
|
||
function pageScrollY() {
|
||
if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
|
||
return window.pageYOffset || (document.documentElement || document.body).scrollTop
|
||
}
|
||
|
||
function widgetTopHeight(lineObj) {
|
||
var height = 0;
|
||
if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
|
||
{ height += widgetHeight(lineObj.widgets[i]); } } }
|
||
return height
|
||
}
|
||
|
||
// Converts a {top, bottom, left, right} box from line-local
|
||
// coordinates into another coordinate system. Context may be one of
|
||
// "line", "div" (display.lineDiv), "local"./null (editor), "window",
|
||
// or "page".
|
||
function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
|
||
if (!includeWidgets) {
|
||
var height = widgetTopHeight(lineObj);
|
||
rect.top += height; rect.bottom += height;
|
||
}
|
||
if (context == "line") { return rect }
|
||
if (!context) { context = "local"; }
|
||
var yOff = heightAtLine(lineObj);
|
||
if (context == "local") { yOff += paddingTop(cm.display); }
|
||
else { yOff -= cm.display.viewOffset; }
|
||
if (context == "page" || context == "window") {
|
||
var lOff = cm.display.lineSpace.getBoundingClientRect();
|
||
yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
|
||
var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
|
||
rect.left += xOff; rect.right += xOff;
|
||
}
|
||
rect.top += yOff; rect.bottom += yOff;
|
||
return rect
|
||
}
|
||
|
||
// Coverts a box from "div" coords to another coordinate system.
|
||
// Context may be "window", "page", "div", or "local"./null.
|
||
function fromCoordSystem(cm, coords, context) {
|
||
if (context == "div") { return coords }
|
||
var left = coords.left, top = coords.top;
|
||
// First move into "page" coordinate system
|
||
if (context == "page") {
|
||
left -= pageScrollX();
|
||
top -= pageScrollY();
|
||
} else if (context == "local" || !context) {
|
||
var localBox = cm.display.sizer.getBoundingClientRect();
|
||
left += localBox.left;
|
||
top += localBox.top;
|
||
}
|
||
|
||
var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
|
||
return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
|
||
}
|
||
|
||
function charCoords(cm, pos, context, lineObj, bias) {
|
||
if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
|
||
return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
|
||
}
|
||
|
||
// Returns a box for a given cursor position, which may have an
|
||
// 'other' property containing the position of the secondary cursor
|
||
// on a bidi boundary.
|
||
// A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
|
||
// and after `char - 1` in writing order of `char - 1`
|
||
// A cursor Pos(line, char, "after") is on the same visual line as `char`
|
||
// and before `char` in writing order of `char`
|
||
// Examples (upper-case letters are RTL, lower-case are LTR):
|
||
// Pos(0, 1, ...)
|
||
// before after
|
||
// ab a|b a|b
|
||
// aB a|B aB|
|
||
// Ab |Ab A|b
|
||
// AB B|A B|A
|
||
// Every position after the last character on a line is considered to stick
|
||
// to the last character on the line.
|
||
function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
|
||
lineObj = lineObj || getLine(cm.doc, pos.line);
|
||
if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
|
||
function get(ch, right) {
|
||
var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
|
||
if (right) { m.left = m.right; } else { m.right = m.left; }
|
||
return intoCoordSystem(cm, lineObj, m, context)
|
||
}
|
||
var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
|
||
if (ch >= lineObj.text.length) {
|
||
ch = lineObj.text.length;
|
||
sticky = "before";
|
||
} else if (ch <= 0) {
|
||
ch = 0;
|
||
sticky = "after";
|
||
}
|
||
if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
|
||
|
||
function getBidi(ch, partPos, invert) {
|
||
var part = order[partPos], right = part.level == 1;
|
||
return get(invert ? ch - 1 : ch, right != invert)
|
||
}
|
||
var partPos = getBidiPartAt(order, ch, sticky);
|
||
var other = bidiOther;
|
||
var val = getBidi(ch, partPos, sticky == "before");
|
||
if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
|
||
return val
|
||
}
|
||
|
||
// Used to cheaply estimate the coordinates for a position. Used for
|
||
// intermediate scroll updates.
|
||
function estimateCoords(cm, pos) {
|
||
var left = 0;
|
||
pos = clipPos(cm.doc, pos);
|
||
if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
|
||
var lineObj = getLine(cm.doc, pos.line);
|
||
var top = heightAtLine(lineObj) + paddingTop(cm.display);
|
||
return {left: left, right: left, top: top, bottom: top + lineObj.height}
|
||
}
|
||
|
||
// Positions returned by coordsChar contain some extra information.
|
||
// xRel is the relative x position of the input coordinates compared
|
||
// to the found position (so xRel > 0 means the coordinates are to
|
||
// the right of the character position, for example). When outside
|
||
// is true, that means the coordinates lie outside the line's
|
||
// vertical range.
|
||
function PosWithInfo(line, ch, sticky, outside, xRel) {
|
||
var pos = Pos(line, ch, sticky);
|
||
pos.xRel = xRel;
|
||
if (outside) { pos.outside = outside; }
|
||
return pos
|
||
}
|
||
|
||
// Compute the character position closest to the given coordinates.
|
||
// Input must be lineSpace-local ("div" coordinate system).
|
||
function coordsChar(cm, x, y) {
|
||
var doc = cm.doc;
|
||
y += cm.display.viewOffset;
|
||
if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) }
|
||
var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
|
||
if (lineN > last)
|
||
{ return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) }
|
||
if (x < 0) { x = 0; }
|
||
|
||
var lineObj = getLine(doc, lineN);
|
||
for (;;) {
|
||
var found = coordsCharInner(cm, lineObj, lineN, x, y);
|
||
var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0));
|
||
if (!collapsed) { return found }
|
||
var rangeEnd = collapsed.find(1);
|
||
if (rangeEnd.line == lineN) { return rangeEnd }
|
||
lineObj = getLine(doc, lineN = rangeEnd.line);
|
||
}
|
||
}
|
||
|
||
function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
|
||
y -= widgetTopHeight(lineObj);
|
||
var end = lineObj.text.length;
|
||
var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
|
||
end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
|
||
return {begin: begin, end: end}
|
||
}
|
||
|
||
function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
|
||
if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
|
||
var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
|
||
return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
|
||
}
|
||
|
||
// Returns true if the given side of a box is after the given
|
||
// coordinates, in top-to-bottom, left-to-right order.
|
||
function boxIsAfter(box, x, y, left) {
|
||
return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
|
||
}
|
||
|
||
function coordsCharInner(cm, lineObj, lineNo, x, y) {
|
||
// Move y into line-local coordinate space
|
||
y -= heightAtLine(lineObj);
|
||
var preparedMeasure = prepareMeasureForLine(cm, lineObj);
|
||
// When directly calling `measureCharPrepared`, we have to adjust
|
||
// for the widgets at this line.
|
||
var widgetHeight = widgetTopHeight(lineObj);
|
||
var begin = 0, end = lineObj.text.length, ltr = true;
|
||
|
||
var order = getOrder(lineObj, cm.doc.direction);
|
||
// If the line isn't plain left-to-right text, first figure out
|
||
// which bidi section the coordinates fall into.
|
||
if (order) {
|
||
var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
|
||
(cm, lineObj, lineNo, preparedMeasure, order, x, y);
|
||
ltr = part.level != 1;
|
||
// The awkward -1 offsets are needed because findFirst (called
|
||
// on these below) will treat its first bound as inclusive,
|
||
// second as exclusive, but we want to actually address the
|
||
// characters in the part's range
|
||
begin = ltr ? part.from : part.to - 1;
|
||
end = ltr ? part.to : part.from - 1;
|
||
}
|
||
|
||
// A binary search to find the first character whose bounding box
|
||
// starts after the coordinates. If we run across any whose box wrap
|
||
// the coordinates, store that.
|
||
var chAround = null, boxAround = null;
|
||
var ch = findFirst(function (ch) {
|
||
var box = measureCharPrepared(cm, preparedMeasure, ch);
|
||
box.top += widgetHeight; box.bottom += widgetHeight;
|
||
if (!boxIsAfter(box, x, y, false)) { return false }
|
||
if (box.top <= y && box.left <= x) {
|
||
chAround = ch;
|
||
boxAround = box;
|
||
}
|
||
return true
|
||
}, begin, end);
|
||
|
||
var baseX, sticky, outside = false;
|
||
// If a box around the coordinates was found, use that
|
||
if (boxAround) {
|
||
// Distinguish coordinates nearer to the left or right side of the box
|
||
var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
|
||
ch = chAround + (atStart ? 0 : 1);
|
||
sticky = atStart ? "after" : "before";
|
||
baseX = atLeft ? boxAround.left : boxAround.right;
|
||
} else {
|
||
// (Adjust for extended bound, if necessary.)
|
||
if (!ltr && (ch == end || ch == begin)) { ch++; }
|
||
// To determine which side to associate with, get the box to the
|
||
// left of the character and compare it's vertical position to the
|
||
// coordinates
|
||
sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
|
||
(measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
|
||
"after" : "before";
|
||
// Now get accurate coordinates for this place, in order to get a
|
||
// base X position
|
||
var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure);
|
||
baseX = coords.left;
|
||
outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0;
|
||
}
|
||
|
||
ch = skipExtendingChars(lineObj.text, ch, 1);
|
||
return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
|
||
}
|
||
|
||
function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
|
||
// Bidi parts are sorted left-to-right, and in a non-line-wrapping
|
||
// situation, we can take this ordering to correspond to the visual
|
||
// ordering. This finds the first part whose end is after the given
|
||
// coordinates.
|
||
var index = findFirst(function (i) {
|
||
var part = order[i], ltr = part.level != 1;
|
||
return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
|
||
"line", lineObj, preparedMeasure), x, y, true)
|
||
}, 0, order.length - 1);
|
||
var part = order[index];
|
||
// If this isn't the first part, the part's start is also after
|
||
// the coordinates, and the coordinates aren't on the same line as
|
||
// that start, move one part back.
|
||
if (index > 0) {
|
||
var ltr = part.level != 1;
|
||
var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
|
||
"line", lineObj, preparedMeasure);
|
||
if (boxIsAfter(start, x, y, true) && start.top > y)
|
||
{ part = order[index - 1]; }
|
||
}
|
||
return part
|
||
}
|
||
|
||
function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
|
||
// In a wrapped line, rtl text on wrapping boundaries can do things
|
||
// that don't correspond to the ordering in our `order` array at
|
||
// all, so a binary search doesn't work, and we want to return a
|
||
// part that only spans one line so that the binary search in
|
||
// coordsCharInner is safe. As such, we first find the extent of the
|
||
// wrapped line, and then do a flat search in which we discard any
|
||
// spans that aren't on the line.
|
||
var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
|
||
var begin = ref.begin;
|
||
var end = ref.end;
|
||
if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
|
||
var part = null, closestDist = null;
|
||
for (var i = 0; i < order.length; i++) {
|
||
var p = order[i];
|
||
if (p.from >= end || p.to <= begin) { continue }
|
||
var ltr = p.level != 1;
|
||
var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
|
||
// Weigh against spans ending before this, so that they are only
|
||
// picked if nothing ends after
|
||
var dist = endX < x ? x - endX + 1e9 : endX - x;
|
||
if (!part || closestDist > dist) {
|
||
part = p;
|
||
closestDist = dist;
|
||
}
|
||
}
|
||
if (!part) { part = order[order.length - 1]; }
|
||
// Clip the part to the wrapped line.
|
||
if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
|
||
if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
|
||
return part
|
||
}
|
||
|
||
var measureText;
|
||
// Compute the default text height.
|
||
function textHeight(display) {
|
||
if (display.cachedTextHeight != null) { return display.cachedTextHeight }
|
||
if (measureText == null) {
|
||
measureText = elt("pre", null, "CodeMirror-line-like");
|
||
// Measure a bunch of lines, for browsers that compute
|
||
// fractional heights.
|
||
for (var i = 0; i < 49; ++i) {
|
||
measureText.appendChild(document.createTextNode("x"));
|
||
measureText.appendChild(elt("br"));
|
||
}
|
||
measureText.appendChild(document.createTextNode("x"));
|
||
}
|
||
removeChildrenAndAdd(display.measure, measureText);
|
||
var height = measureText.offsetHeight / 50;
|
||
if (height > 3) { display.cachedTextHeight = height; }
|
||
removeChildren(display.measure);
|
||
return height || 1
|
||
}
|
||
|
||
// Compute the default character width.
|
||
function charWidth(display) {
|
||
if (display.cachedCharWidth != null) { return display.cachedCharWidth }
|
||
var anchor = elt("span", "xxxxxxxxxx");
|
||
var pre = elt("pre", [anchor], "CodeMirror-line-like");
|
||
removeChildrenAndAdd(display.measure, pre);
|
||
var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
|
||
if (width > 2) { display.cachedCharWidth = width; }
|
||
return width || 10
|
||
}
|
||
|
||
// Do a bulk-read of the DOM positions and sizes needed to draw the
|
||
// view, so that we don't interleave reading and writing to the DOM.
|
||
function getDimensions(cm) {
|
||
var d = cm.display, left = {}, width = {};
|
||
var gutterLeft = d.gutters.clientLeft;
|
||
for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
|
||
var id = cm.display.gutterSpecs[i].className;
|
||
left[id] = n.offsetLeft + n.clientLeft + gutterLeft;
|
||
width[id] = n.clientWidth;
|
||
}
|
||
return {fixedPos: compensateForHScroll(d),
|
||
gutterTotalWidth: d.gutters.offsetWidth,
|
||
gutterLeft: left,
|
||
gutterWidth: width,
|
||
wrapperWidth: d.wrapper.clientWidth}
|
||
}
|
||
|
||
// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
|
||
// but using getBoundingClientRect to get a sub-pixel-accurate
|
||
// result.
|
||
function compensateForHScroll(display) {
|
||
return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
|
||
}
|
||
|
||
// Returns a function that estimates the height of a line, to use as
|
||
// first approximation until the line becomes visible (and is thus
|
||
// properly measurable).
|
||
function estimateHeight(cm) {
|
||
var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
|
||
var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
|
||
return function (line) {
|
||
if (lineIsHidden(cm.doc, line)) { return 0 }
|
||
|
||
var widgetsHeight = 0;
|
||
if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
|
||
if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
|
||
} }
|
||
|
||
if (wrapping)
|
||
{ return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
|
||
else
|
||
{ return widgetsHeight + th }
|
||
}
|
||
}
|
||
|
||
function estimateLineHeights(cm) {
|
||
var doc = cm.doc, est = estimateHeight(cm);
|
||
doc.iter(function (line) {
|
||
var estHeight = est(line);
|
||
if (estHeight != line.height) { updateLineHeight(line, estHeight); }
|
||
});
|
||
}
|
||
|
||
// Given a mouse event, find the corresponding position. If liberal
|
||
// is false, it checks whether a gutter or scrollbar was clicked,
|
||
// and returns null if it was. forRect is used by rectangular
|
||
// selections, and tries to estimate a character position even for
|
||
// coordinates beyond the right of the text.
|
||
function posFromMouse(cm, e, liberal, forRect) {
|
||
var display = cm.display;
|
||
if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
|
||
|
||
var x, y, space = display.lineSpace.getBoundingClientRect();
|
||
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
|
||
try { x = e.clientX - space.left; y = e.clientY - space.top; }
|
||
catch (e$1) { return null }
|
||
var coords = coordsChar(cm, x, y), line;
|
||
if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
|
||
var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
|
||
coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
|
||
}
|
||
return coords
|
||
}
|
||
|
||
// Find the view element corresponding to a given line. Return null
|
||
// when the line isn't visible.
|
||
function findViewIndex(cm, n) {
|
||
if (n >= cm.display.viewTo) { return null }
|
||
n -= cm.display.viewFrom;
|
||
if (n < 0) { return null }
|
||
var view = cm.display.view;
|
||
for (var i = 0; i < view.length; i++) {
|
||
n -= view[i].size;
|
||
if (n < 0) { return i }
|
||
}
|
||
}
|
||
|
||
// Updates the display.view data structure for a given change to the
|
||
// document. From and to are in pre-change coordinates. Lendiff is
|
||
// the amount of lines added or subtracted by the change. This is
|
||
// used for changes that span multiple lines, or change the way
|
||
// lines are divided into visual lines. regLineChange (below)
|
||
// registers single-line changes.
|
||
function regChange(cm, from, to, lendiff) {
|
||
if (from == null) { from = cm.doc.first; }
|
||
if (to == null) { to = cm.doc.first + cm.doc.size; }
|
||
if (!lendiff) { lendiff = 0; }
|
||
|
||
var display = cm.display;
|
||
if (lendiff && to < display.viewTo &&
|
||
(display.updateLineNumbers == null || display.updateLineNumbers > from))
|
||
{ display.updateLineNumbers = from; }
|
||
|
||
cm.curOp.viewChanged = true;
|
||
|
||
if (from >= display.viewTo) { // Change after
|
||
if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
|
||
{ resetView(cm); }
|
||
} else if (to <= display.viewFrom) { // Change before
|
||
if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
|
||
resetView(cm);
|
||
} else {
|
||
display.viewFrom += lendiff;
|
||
display.viewTo += lendiff;
|
||
}
|
||
} else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
|
||
resetView(cm);
|
||
} else if (from <= display.viewFrom) { // Top overlap
|
||
var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
|
||
if (cut) {
|
||
display.view = display.view.slice(cut.index);
|
||
display.viewFrom = cut.lineN;
|
||
display.viewTo += lendiff;
|
||
} else {
|
||
resetView(cm);
|
||
}
|
||
} else if (to >= display.viewTo) { // Bottom overlap
|
||
var cut$1 = viewCuttingPoint(cm, from, from, -1);
|
||
if (cut$1) {
|
||
display.view = display.view.slice(0, cut$1.index);
|
||
display.viewTo = cut$1.lineN;
|
||
} else {
|
||
resetView(cm);
|
||
}
|
||
} else { // Gap in the middle
|
||
var cutTop = viewCuttingPoint(cm, from, from, -1);
|
||
var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
|
||
if (cutTop && cutBot) {
|
||
display.view = display.view.slice(0, cutTop.index)
|
||
.concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
|
||
.concat(display.view.slice(cutBot.index));
|
||
display.viewTo += lendiff;
|
||
} else {
|
||
resetView(cm);
|
||
}
|
||
}
|
||
|
||
var ext = display.externalMeasured;
|
||
if (ext) {
|
||
if (to < ext.lineN)
|
||
{ ext.lineN += lendiff; }
|
||
else if (from < ext.lineN + ext.size)
|
||
{ display.externalMeasured = null; }
|
||
}
|
||
}
|
||
|
||
// Register a change to a single line. Type must be one of "text",
|
||
// "gutter", "class", "widget"
|
||
function regLineChange(cm, line, type) {
|
||
cm.curOp.viewChanged = true;
|
||
var display = cm.display, ext = cm.display.externalMeasured;
|
||
if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
|
||
{ display.externalMeasured = null; }
|
||
|
||
if (line < display.viewFrom || line >= display.viewTo) { return }
|
||
var lineView = display.view[findViewIndex(cm, line)];
|
||
if (lineView.node == null) { return }
|
||
var arr = lineView.changes || (lineView.changes = []);
|
||
if (indexOf(arr, type) == -1) { arr.push(type); }
|
||
}
|
||
|
||
// Clear the view.
|
||
function resetView(cm) {
|
||
cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
|
||
cm.display.view = [];
|
||
cm.display.viewOffset = 0;
|
||
}
|
||
|
||
function viewCuttingPoint(cm, oldN, newN, dir) {
|
||
var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
|
||
if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
|
||
{ return {index: index, lineN: newN} }
|
||
var n = cm.display.viewFrom;
|
||
for (var i = 0; i < index; i++)
|
||
{ n += view[i].size; }
|
||
if (n != oldN) {
|
||
if (dir > 0) {
|
||
if (index == view.length - 1) { return null }
|
||
diff = (n + view[index].size) - oldN;
|
||
index++;
|
||
} else {
|
||
diff = n - oldN;
|
||
}
|
||
oldN += diff; newN += diff;
|
||
}
|
||
while (visualLineNo(cm.doc, newN) != newN) {
|
||
if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
|
||
newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
|
||
index += dir;
|
||
}
|
||
return {index: index, lineN: newN}
|
||
}
|
||
|
||
// Force the view to cover a given range, adding empty view element
|
||
// or clipping off existing ones as needed.
|
||
function adjustView(cm, from, to) {
|
||
var display = cm.display, view = display.view;
|
||
if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
|
||
display.view = buildViewArray(cm, from, to);
|
||
display.viewFrom = from;
|
||
} else {
|
||
if (display.viewFrom > from)
|
||
{ display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
|
||
else if (display.viewFrom < from)
|
||
{ display.view = display.view.slice(findViewIndex(cm, from)); }
|
||
display.viewFrom = from;
|
||
if (display.viewTo < to)
|
||
{ display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
|
||
else if (display.viewTo > to)
|
||
{ display.view = display.view.slice(0, findViewIndex(cm, to)); }
|
||
}
|
||
display.viewTo = to;
|
||
}
|
||
|
||
// Count the number of lines in the view whose DOM representation is
|
||
// out of date (or nonexistent).
|
||
function countDirtyView(cm) {
|
||
var view = cm.display.view, dirty = 0;
|
||
for (var i = 0; i < view.length; i++) {
|
||
var lineView = view[i];
|
||
if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
|
||
}
|
||
return dirty
|
||
}
|
||
|
||
function updateSelection(cm) {
|
||
cm.display.input.showSelection(cm.display.input.prepareSelection());
|
||
}
|
||
|
||
function prepareSelection(cm, primary) {
|
||
if ( primary === void 0 ) primary = true;
|
||
|
||
var doc = cm.doc, result = {};
|
||
var curFragment = result.cursors = document.createDocumentFragment();
|
||
var selFragment = result.selection = document.createDocumentFragment();
|
||
|
||
for (var i = 0; i < doc.sel.ranges.length; i++) {
|
||
if (!primary && i == doc.sel.primIndex) { continue }
|
||
var range = doc.sel.ranges[i];
|
||
if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
|
||
var collapsed = range.empty();
|
||
if (collapsed || cm.options.showCursorWhenSelecting)
|
||
{ drawSelectionCursor(cm, range.head, curFragment); }
|
||
if (!collapsed)
|
||
{ drawSelectionRange(cm, range, selFragment); }
|
||
}
|
||
return result
|
||
}
|
||
|
||
// Draws a cursor for the given range
|
||
function drawSelectionCursor(cm, head, output) {
|
||
var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
|
||
|
||
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
|
||
cursor.style.left = pos.left + "px";
|
||
cursor.style.top = pos.top + "px";
|
||
cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
|
||
|
||
if (pos.other) {
|
||
// Secondary cursor, shown when on a 'jump' in bi-directional text
|
||
var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
|
||
otherCursor.style.display = "";
|
||
otherCursor.style.left = pos.other.left + "px";
|
||
otherCursor.style.top = pos.other.top + "px";
|
||
otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
|
||
}
|
||
}
|
||
|
||
function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
|
||
|
||
// Draws the given range as a highlighted selection
|
||
function drawSelectionRange(cm, range, output) {
|
||
var display = cm.display, doc = cm.doc;
|
||
var fragment = document.createDocumentFragment();
|
||
var padding = paddingH(cm.display), leftSide = padding.left;
|
||
var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
|
||
var docLTR = doc.direction == "ltr";
|
||
|
||
function add(left, top, width, bottom) {
|
||
if (top < 0) { top = 0; }
|
||
top = Math.round(top);
|
||
bottom = Math.round(bottom);
|
||
fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px")));
|
||
}
|
||
|
||
function drawForLine(line, fromArg, toArg) {
|
||
var lineObj = getLine(doc, line);
|
||
var lineLen = lineObj.text.length;
|
||
var start, end;
|
||
function coords(ch, bias) {
|
||
return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
|
||
}
|
||
|
||
function wrapX(pos, dir, side) {
|
||
var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
|
||
var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
|
||
var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
|
||
return coords(ch, prop)[prop]
|
||
}
|
||
|
||
var order = getOrder(lineObj, doc.direction);
|
||
iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
|
||
var ltr = dir == "ltr";
|
||
var fromPos = coords(from, ltr ? "left" : "right");
|
||
var toPos = coords(to - 1, ltr ? "right" : "left");
|
||
|
||
var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
|
||
var first = i == 0, last = !order || i == order.length - 1;
|
||
if (toPos.top - fromPos.top <= 3) { // Single line
|
||
var openLeft = (docLTR ? openStart : openEnd) && first;
|
||
var openRight = (docLTR ? openEnd : openStart) && last;
|
||
var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
|
||
var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
|
||
add(left, fromPos.top, right - left, fromPos.bottom);
|
||
} else { // Multiple lines
|
||
var topLeft, topRight, botLeft, botRight;
|
||
if (ltr) {
|
||
topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
|
||
topRight = docLTR ? rightSide : wrapX(from, dir, "before");
|
||
botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
|
||
botRight = docLTR && openEnd && last ? rightSide : toPos.right;
|
||
} else {
|
||
topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
|
||
topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
|
||
botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
|
||
botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
|
||
}
|
||
add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
|
||
if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
|
||
add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
|
||
}
|
||
|
||
if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
|
||
if (cmpCoords(toPos, start) < 0) { start = toPos; }
|
||
if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
|
||
if (cmpCoords(toPos, end) < 0) { end = toPos; }
|
||
});
|
||
return {start: start, end: end}
|
||
}
|
||
|
||
var sFrom = range.from(), sTo = range.to();
|
||
if (sFrom.line == sTo.line) {
|
||
drawForLine(sFrom.line, sFrom.ch, sTo.ch);
|
||
} else {
|
||
var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
|
||
var singleVLine = visualLine(fromLine) == visualLine(toLine);
|
||
var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
|
||
var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
|
||
if (singleVLine) {
|
||
if (leftEnd.top < rightStart.top - 2) {
|
||
add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
|
||
add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
|
||
} else {
|
||
add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
|
||
}
|
||
}
|
||
if (leftEnd.bottom < rightStart.top)
|
||
{ add(leftSide, leftEnd.bottom, null, rightStart.top); }
|
||
}
|
||
|
||
output.appendChild(fragment);
|
||
}
|
||
|
||
// Cursor-blinking
|
||
function restartBlink(cm) {
|
||
if (!cm.state.focused) { return }
|
||
var display = cm.display;
|
||
clearInterval(display.blinker);
|
||
var on = true;
|
||
display.cursorDiv.style.visibility = "";
|
||
if (cm.options.cursorBlinkRate > 0)
|
||
{ display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
|
||
cm.options.cursorBlinkRate); }
|
||
else if (cm.options.cursorBlinkRate < 0)
|
||
{ display.cursorDiv.style.visibility = "hidden"; }
|
||
}
|
||
|
||
function ensureFocus(cm) {
|
||
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
|
||
}
|
||
|
||
function delayBlurEvent(cm) {
|
||
cm.state.delayingBlurEvent = true;
|
||
setTimeout(function () { if (cm.state.delayingBlurEvent) {
|
||
cm.state.delayingBlurEvent = false;
|
||
onBlur(cm);
|
||
} }, 100);
|
||
}
|
||
|
||
function onFocus(cm, e) {
|
||
if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
|
||
|
||
if (cm.options.readOnly == "nocursor") { return }
|
||
if (!cm.state.focused) {
|
||
signal(cm, "focus", cm, e);
|
||
cm.state.focused = true;
|
||
addClass(cm.display.wrapper, "CodeMirror-focused");
|
||
// This test prevents this from firing when a context
|
||
// menu is closed (since the input reset would kill the
|
||
// select-all detection hack)
|
||
if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
|
||
cm.display.input.reset();
|
||
if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
|
||
}
|
||
cm.display.input.receivedFocus();
|
||
}
|
||
restartBlink(cm);
|
||
}
|
||
function onBlur(cm, e) {
|
||
if (cm.state.delayingBlurEvent) { return }
|
||
|
||
if (cm.state.focused) {
|
||
signal(cm, "blur", cm, e);
|
||
cm.state.focused = false;
|
||
rmClass(cm.display.wrapper, "CodeMirror-focused");
|
||
}
|
||
clearInterval(cm.display.blinker);
|
||
setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
|
||
}
|
||
|
||
// Read the actual heights of the rendered lines, and update their
|
||
// stored heights to match.
|
||
function updateHeightsInViewport(cm) {
|
||
var display = cm.display;
|
||
var prevBottom = display.lineDiv.offsetTop;
|
||
for (var i = 0; i < display.view.length; i++) {
|
||
var cur = display.view[i], wrapping = cm.options.lineWrapping;
|
||
var height = (void 0), width = 0;
|
||
if (cur.hidden) { continue }
|
||
if (ie && ie_version < 8) {
|
||
var bot = cur.node.offsetTop + cur.node.offsetHeight;
|
||
height = bot - prevBottom;
|
||
prevBottom = bot;
|
||
} else {
|
||
var box = cur.node.getBoundingClientRect();
|
||
height = box.bottom - box.top;
|
||
// Check that lines don't extend past the right of the current
|
||
// editor width
|
||
if (!wrapping && cur.text.firstChild)
|
||
{ width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; }
|
||
}
|
||
var diff = cur.line.height - height;
|
||
if (diff > .005 || diff < -.005) {
|
||
updateLineHeight(cur.line, height);
|
||
updateWidgetHeight(cur.line);
|
||
if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
|
||
{ updateWidgetHeight(cur.rest[j]); } }
|
||
}
|
||
if (width > cm.display.sizerWidth) {
|
||
var chWidth = Math.ceil(width / charWidth(cm.display));
|
||
if (chWidth > cm.display.maxLineLength) {
|
||
cm.display.maxLineLength = chWidth;
|
||
cm.display.maxLine = cur.line;
|
||
cm.display.maxLineChanged = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Read and store the height of line widgets associated with the
|
||
// given line.
|
||
function updateWidgetHeight(line) {
|
||
if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
|
||
var w = line.widgets[i], parent = w.node.parentNode;
|
||
if (parent) { w.height = parent.offsetHeight; }
|
||
} }
|
||
}
|
||
|
||
// Compute the lines that are visible in a given viewport (defaults
|
||
// the the current scroll position). viewport may contain top,
|
||
// height, and ensure (see op.scrollToPos) properties.
|
||
function visibleLines(display, doc, viewport) {
|
||
var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
|
||
top = Math.floor(top - paddingTop(display));
|
||
var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
|
||
|
||
var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
|
||
// Ensure is a {from: {line, ch}, to: {line, ch}} object, and
|
||
// forces those lines into the viewport (if possible).
|
||
if (viewport && viewport.ensure) {
|
||
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
|
||
if (ensureFrom < from) {
|
||
from = ensureFrom;
|
||
to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
|
||
} else if (Math.min(ensureTo, doc.lastLine()) >= to) {
|
||
from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
|
||
to = ensureTo;
|
||
}
|
||
}
|
||
return {from: from, to: Math.max(to, from + 1)}
|
||
}
|
||
|
||
// SCROLLING THINGS INTO VIEW
|
||
|
||
// If an editor sits on the top or bottom of the window, partially
|
||
// scrolled out of view, this ensures that the cursor is visible.
|
||
function maybeScrollWindow(cm, rect) {
|
||
if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
|
||
|
||
var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
|
||
if (rect.top + box.top < 0) { doScroll = true; }
|
||
else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
|
||
if (doScroll != null && !phantom) {
|
||
var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
|
||
cm.display.lineSpace.appendChild(scrollNode);
|
||
scrollNode.scrollIntoView(doScroll);
|
||
cm.display.lineSpace.removeChild(scrollNode);
|
||
}
|
||
}
|
||
|
||
// Scroll a given position into view (immediately), verifying that
|
||
// it actually became visible (as line heights are accurately
|
||
// measured, the position of something may 'drift' during drawing).
|
||
function scrollPosIntoView(cm, pos, end, margin) {
|
||
if (margin == null) { margin = 0; }
|
||
var rect;
|
||
if (!cm.options.lineWrapping && pos == end) {
|
||
// Set pos and end to the cursor positions around the character pos sticks to
|
||
// If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
|
||
// If pos == Pos(_, 0, "before"), pos and end are unchanged
|
||
pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
|
||
end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
|
||
}
|
||
for (var limit = 0; limit < 5; limit++) {
|
||
var changed = false;
|
||
var coords = cursorCoords(cm, pos);
|
||
var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
|
||
rect = {left: Math.min(coords.left, endCoords.left),
|
||
top: Math.min(coords.top, endCoords.top) - margin,
|
||
right: Math.max(coords.left, endCoords.left),
|
||
bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
|
||
var scrollPos = calculateScrollPos(cm, rect);
|
||
var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
|
||
if (scrollPos.scrollTop != null) {
|
||
updateScrollTop(cm, scrollPos.scrollTop);
|
||
if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
|
||
}
|
||
if (scrollPos.scrollLeft != null) {
|
||
setScrollLeft(cm, scrollPos.scrollLeft);
|
||
if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
|
||
}
|
||
if (!changed) { break }
|
||
}
|
||
return rect
|
||
}
|
||
|
||
// Scroll a given set of coordinates into view (immediately).
|
||
function scrollIntoView(cm, rect) {
|
||
var scrollPos = calculateScrollPos(cm, rect);
|
||
if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
|
||
if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
|
||
}
|
||
|
||
// Calculate a new scroll position needed to scroll the given
|
||
// rectangle into view. Returns an object with scrollTop and
|
||
// scrollLeft properties. When these are undefined, the
|
||
// vertical/horizontal position does not need to be adjusted.
|
||
function calculateScrollPos(cm, rect) {
|
||
var display = cm.display, snapMargin = textHeight(cm.display);
|
||
if (rect.top < 0) { rect.top = 0; }
|
||
var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
|
||
var screen = displayHeight(cm), result = {};
|
||
if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
|
||
var docBottom = cm.doc.height + paddingVert(display);
|
||
var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
|
||
if (rect.top < screentop) {
|
||
result.scrollTop = atTop ? 0 : rect.top;
|
||
} else if (rect.bottom > screentop + screen) {
|
||
var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
|
||
if (newTop != screentop) { result.scrollTop = newTop; }
|
||
}
|
||
|
||
var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
|
||
var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
|
||
var tooWide = rect.right - rect.left > screenw;
|
||
if (tooWide) { rect.right = rect.left + screenw; }
|
||
if (rect.left < 10)
|
||
{ result.scrollLeft = 0; }
|
||
else if (rect.left < screenleft)
|
||
{ result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
|
||
else if (rect.right > screenw + screenleft - 3)
|
||
{ result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
|
||
return result
|
||
}
|
||
|
||
// Store a relative adjustment to the scroll position in the current
|
||
// operation (to be applied when the operation finishes).
|
||
function addToScrollTop(cm, top) {
|
||
if (top == null) { return }
|
||
resolveScrollToPos(cm);
|
||
cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
|
||
}
|
||
|
||
// Make sure that at the end of the operation the current cursor is
|
||
// shown.
|
||
function ensureCursorVisible(cm) {
|
||
resolveScrollToPos(cm);
|
||
var cur = cm.getCursor();
|
||
cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
|
||
}
|
||
|
||
function scrollToCoords(cm, x, y) {
|
||
if (x != null || y != null) { resolveScrollToPos(cm); }
|
||
if (x != null) { cm.curOp.scrollLeft = x; }
|
||
if (y != null) { cm.curOp.scrollTop = y; }
|
||
}
|
||
|
||
function scrollToRange(cm, range) {
|
||
resolveScrollToPos(cm);
|
||
cm.curOp.scrollToPos = range;
|
||
}
|
||
|
||
// When an operation has its scrollToPos property set, and another
|
||
// scroll action is applied before the end of the operation, this
|
||
// 'simulates' scrolling that position into view in a cheap way, so
|
||
// that the effect of intermediate scroll commands is not ignored.
|
||
function resolveScrollToPos(cm) {
|
||
var range = cm.curOp.scrollToPos;
|
||
if (range) {
|
||
cm.curOp.scrollToPos = null;
|
||
var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
|
||
scrollToCoordsRange(cm, from, to, range.margin);
|
||
}
|
||
}
|
||
|
||
function scrollToCoordsRange(cm, from, to, margin) {
|
||
var sPos = calculateScrollPos(cm, {
|
||
left: Math.min(from.left, to.left),
|
||
top: Math.min(from.top, to.top) - margin,
|
||
right: Math.max(from.right, to.right),
|
||
bottom: Math.max(from.bottom, to.bottom) + margin
|
||
});
|
||
scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
|
||
}
|
||
|
||
// Sync the scrollable area and scrollbars, ensure the viewport
|
||
// covers the visible area.
|
||
function updateScrollTop(cm, val) {
|
||
if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
|
||
if (!gecko) { updateDisplaySimple(cm, {top: val}); }
|
||
setScrollTop(cm, val, true);
|
||
if (gecko) { updateDisplaySimple(cm); }
|
||
startWorker(cm, 100);
|
||
}
|
||
|
||
function setScrollTop(cm, val, forceScroll) {
|
||
val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val));
|
||
if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
|
||
cm.doc.scrollTop = val;
|
||
cm.display.scrollbars.setScrollTop(val);
|
||
if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
|
||
}
|
||
|
||
// Sync scroller and scrollbar, ensure the gutter elements are
|
||
// aligned.
|
||
function setScrollLeft(cm, val, isScroller, forceScroll) {
|
||
val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth));
|
||
if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
|
||
cm.doc.scrollLeft = val;
|
||
alignHorizontally(cm);
|
||
if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
|
||
cm.display.scrollbars.setScrollLeft(val);
|
||
}
|
||
|
||
// SCROLLBARS
|
||
|
||
// Prepare DOM reads needed to update the scrollbars. Done in one
|
||
// shot to minimize update/measure roundtrips.
|
||
function measureForScrollbars(cm) {
|
||
var d = cm.display, gutterW = d.gutters.offsetWidth;
|
||
var docH = Math.round(cm.doc.height + paddingVert(cm.display));
|
||
return {
|
||
clientHeight: d.scroller.clientHeight,
|
||
viewHeight: d.wrapper.clientHeight,
|
||
scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
|
||
viewWidth: d.wrapper.clientWidth,
|
||
barLeft: cm.options.fixedGutter ? gutterW : 0,
|
||
docHeight: docH,
|
||
scrollHeight: docH + scrollGap(cm) + d.barHeight,
|
||
nativeBarWidth: d.nativeBarWidth,
|
||
gutterWidth: gutterW
|
||
}
|
||
}
|
||
|
||
var NativeScrollbars = function(place, scroll, cm) {
|
||
this.cm = cm;
|
||
var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
|
||
var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
|
||
vert.tabIndex = horiz.tabIndex = -1;
|
||
place(vert); place(horiz);
|
||
|
||
on(vert, "scroll", function () {
|
||
if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
|
||
});
|
||
on(horiz, "scroll", function () {
|
||
if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
|
||
});
|
||
|
||
this.checkedZeroWidth = false;
|
||
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
||
if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
|
||
};
|
||
|
||
NativeScrollbars.prototype.update = function (measure) {
|
||
var needsH = measure.scrollWidth > measure.clientWidth + 1;
|
||
var needsV = measure.scrollHeight > measure.clientHeight + 1;
|
||
var sWidth = measure.nativeBarWidth;
|
||
|
||
if (needsV) {
|
||
this.vert.style.display = "block";
|
||
this.vert.style.bottom = needsH ? sWidth + "px" : "0";
|
||
var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
|
||
// A bug in IE8 can cause this value to be negative, so guard it.
|
||
this.vert.firstChild.style.height =
|
||
Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
|
||
} else {
|
||
this.vert.style.display = "";
|
||
this.vert.firstChild.style.height = "0";
|
||
}
|
||
|
||
if (needsH) {
|
||
this.horiz.style.display = "block";
|
||
this.horiz.style.right = needsV ? sWidth + "px" : "0";
|
||
this.horiz.style.left = measure.barLeft + "px";
|
||
var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
|
||
this.horiz.firstChild.style.width =
|
||
Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
|
||
} else {
|
||
this.horiz.style.display = "";
|
||
this.horiz.firstChild.style.width = "0";
|
||
}
|
||
|
||
if (!this.checkedZeroWidth && measure.clientHeight > 0) {
|
||
if (sWidth == 0) { this.zeroWidthHack(); }
|
||
this.checkedZeroWidth = true;
|
||
}
|
||
|
||
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
|
||
};
|
||
|
||
NativeScrollbars.prototype.setScrollLeft = function (pos) {
|
||
if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
|
||
if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
|
||
};
|
||
|
||
NativeScrollbars.prototype.setScrollTop = function (pos) {
|
||
if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
|
||
if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
|
||
};
|
||
|
||
NativeScrollbars.prototype.zeroWidthHack = function () {
|
||
var w = mac && !mac_geMountainLion ? "12px" : "18px";
|
||
this.horiz.style.height = this.vert.style.width = w;
|
||
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
|
||
this.disableHoriz = new Delayed;
|
||
this.disableVert = new Delayed;
|
||
};
|
||
|
||
NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
|
||
bar.style.pointerEvents = "auto";
|
||
function maybeDisable() {
|
||
// To find out whether the scrollbar is still visible, we
|
||
// check whether the element under the pixel in the bottom
|
||
// right corner of the scrollbar box is the scrollbar box
|
||
// itself (when the bar is still visible) or its filler child
|
||
// (when the bar is hidden). If it is still visible, we keep
|
||
// it enabled, if it's hidden, we disable pointer events.
|
||
var box = bar.getBoundingClientRect();
|
||
var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
|
||
: document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
|
||
if (elt != bar) { bar.style.pointerEvents = "none"; }
|
||
else { delay.set(1000, maybeDisable); }
|
||
}
|
||
delay.set(1000, maybeDisable);
|
||
};
|
||
|
||
NativeScrollbars.prototype.clear = function () {
|
||
var parent = this.horiz.parentNode;
|
||
parent.removeChild(this.horiz);
|
||
parent.removeChild(this.vert);
|
||
};
|
||
|
||
var NullScrollbars = function () {};
|
||
|
||
NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
|
||
NullScrollbars.prototype.setScrollLeft = function () {};
|
||
NullScrollbars.prototype.setScrollTop = function () {};
|
||
NullScrollbars.prototype.clear = function () {};
|
||
|
||
function updateScrollbars(cm, measure) {
|
||
if (!measure) { measure = measureForScrollbars(cm); }
|
||
var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
|
||
updateScrollbarsInner(cm, measure);
|
||
for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
|
||
if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
|
||
{ updateHeightsInViewport(cm); }
|
||
updateScrollbarsInner(cm, measureForScrollbars(cm));
|
||
startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
|
||
}
|
||
}
|
||
|
||
// Re-synchronize the fake scrollbars with the actual size of the
|
||
// content.
|
||
function updateScrollbarsInner(cm, measure) {
|
||
var d = cm.display;
|
||
var sizes = d.scrollbars.update(measure);
|
||
|
||
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
|
||
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
|
||
d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
|
||
|
||
if (sizes.right && sizes.bottom) {
|
||
d.scrollbarFiller.style.display = "block";
|
||
d.scrollbarFiller.style.height = sizes.bottom + "px";
|
||
d.scrollbarFiller.style.width = sizes.right + "px";
|
||
} else { d.scrollbarFiller.style.display = ""; }
|
||
if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
|
||
d.gutterFiller.style.display = "block";
|
||
d.gutterFiller.style.height = sizes.bottom + "px";
|
||
d.gutterFiller.style.width = measure.gutterWidth + "px";
|
||
} else { d.gutterFiller.style.display = ""; }
|
||
}
|
||
|
||
var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
|
||
|
||
function initScrollbars(cm) {
|
||
if (cm.display.scrollbars) {
|
||
cm.display.scrollbars.clear();
|
||
if (cm.display.scrollbars.addClass)
|
||
{ rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
|
||
}
|
||
|
||
cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
|
||
cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
|
||
// Prevent clicks in the scrollbars from killing focus
|
||
on(node, "mousedown", function () {
|
||
if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
|
||
});
|
||
node.setAttribute("cm-not-content", "true");
|
||
}, function (pos, axis) {
|
||
if (axis == "horizontal") { setScrollLeft(cm, pos); }
|
||
else { updateScrollTop(cm, pos); }
|
||
}, cm);
|
||
if (cm.display.scrollbars.addClass)
|
||
{ addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
|
||
}
|
||
|
||
// Operations are used to wrap a series of changes to the editor
|
||
// state in such a way that each change won't have to update the
|
||
// cursor and display (which would be awkward, slow, and
|
||
// error-prone). Instead, display updates are batched and then all
|
||
// combined and executed at once.
|
||
|
||
var nextOpId = 0;
|
||
// Start a new operation.
|
||
function startOperation(cm) {
|
||
cm.curOp = {
|
||
cm: cm,
|
||
viewChanged: false, // Flag that indicates that lines might need to be redrawn
|
||
startHeight: cm.doc.height, // Used to detect need to update scrollbar
|
||
forceUpdate: false, // Used to force a redraw
|
||
updateInput: 0, // Whether to reset the input textarea
|
||
typing: false, // Whether this reset should be careful to leave existing text (for compositing)
|
||
changeObjs: null, // Accumulated changes, for firing change events
|
||
cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
|
||
cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
|
||
selectionChanged: false, // Whether the selection needs to be redrawn
|
||
updateMaxLine: false, // Set when the widest line needs to be determined anew
|
||
scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
|
||
scrollToPos: null, // Used to scroll to a specific position
|
||
focus: false,
|
||
id: ++nextOpId // Unique ID
|
||
};
|
||
pushOperation(cm.curOp);
|
||
}
|
||
|
||
// Finish an operation, updating the display and signalling delayed events
|
||
function endOperation(cm) {
|
||
var op = cm.curOp;
|
||
if (op) { finishOperation(op, function (group) {
|
||
for (var i = 0; i < group.ops.length; i++)
|
||
{ group.ops[i].cm.curOp = null; }
|
||
endOperations(group);
|
||
}); }
|
||
}
|
||
|
||
// The DOM updates done when an operation finishes are batched so
|
||
// that the minimum number of relayouts are required.
|
||
function endOperations(group) {
|
||
var ops = group.ops;
|
||
for (var i = 0; i < ops.length; i++) // Read DOM
|
||
{ endOperation_R1(ops[i]); }
|
||
for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
|
||
{ endOperation_W1(ops[i$1]); }
|
||
for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
|
||
{ endOperation_R2(ops[i$2]); }
|
||
for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
|
||
{ endOperation_W2(ops[i$3]); }
|
||
for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
|
||
{ endOperation_finish(ops[i$4]); }
|
||
}
|
||
|
||
function endOperation_R1(op) {
|
||
var cm = op.cm, display = cm.display;
|
||
maybeClipScrollbars(cm);
|
||
if (op.updateMaxLine) { findMaxLine(cm); }
|
||
|
||
op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
|
||
op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
|
||
op.scrollToPos.to.line >= display.viewTo) ||
|
||
display.maxLineChanged && cm.options.lineWrapping;
|
||
op.update = op.mustUpdate &&
|
||
new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
|
||
}
|
||
|
||
function endOperation_W1(op) {
|
||
op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
|
||
}
|
||
|
||
function endOperation_R2(op) {
|
||
var cm = op.cm, display = cm.display;
|
||
if (op.updatedDisplay) { updateHeightsInViewport(cm); }
|
||
|
||
op.barMeasure = measureForScrollbars(cm);
|
||
|
||
// If the max line changed since it was last measured, measure it,
|
||
// and ensure the document's width matches it.
|
||
// updateDisplay_W2 will use these properties to do the actual resizing
|
||
if (display.maxLineChanged && !cm.options.lineWrapping) {
|
||
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
|
||
cm.display.sizerWidth = op.adjustWidthTo;
|
||
op.barMeasure.scrollWidth =
|
||
Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
|
||
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
|
||
}
|
||
|
||
if (op.updatedDisplay || op.selectionChanged)
|
||
{ op.preparedSelection = display.input.prepareSelection(); }
|
||
}
|
||
|
||
function endOperation_W2(op) {
|
||
var cm = op.cm;
|
||
|
||
if (op.adjustWidthTo != null) {
|
||
cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
|
||
if (op.maxScrollLeft < cm.doc.scrollLeft)
|
||
{ setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
|
||
cm.display.maxLineChanged = false;
|
||
}
|
||
|
||
var takeFocus = op.focus && op.focus == activeElt();
|
||
if (op.preparedSelection)
|
||
{ cm.display.input.showSelection(op.preparedSelection, takeFocus); }
|
||
if (op.updatedDisplay || op.startHeight != cm.doc.height)
|
||
{ updateScrollbars(cm, op.barMeasure); }
|
||
if (op.updatedDisplay)
|
||
{ setDocumentHeight(cm, op.barMeasure); }
|
||
|
||
if (op.selectionChanged) { restartBlink(cm); }
|
||
|
||
if (cm.state.focused && op.updateInput)
|
||
{ cm.display.input.reset(op.typing); }
|
||
if (takeFocus) { ensureFocus(op.cm); }
|
||
}
|
||
|
||
function endOperation_finish(op) {
|
||
var cm = op.cm, display = cm.display, doc = cm.doc;
|
||
|
||
if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
|
||
|
||
// Abort mouse wheel delta measurement, when scrolling explicitly
|
||
if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
|
||
{ display.wheelStartX = display.wheelStartY = null; }
|
||
|
||
// Propagate the scroll position to the actual DOM scroller
|
||
if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
|
||
|
||
if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
|
||
// If we need to scroll a specific position into view, do so.
|
||
if (op.scrollToPos) {
|
||
var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
|
||
clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
|
||
maybeScrollWindow(cm, rect);
|
||
}
|
||
|
||
// Fire events for markers that are hidden/unidden by editing or
|
||
// undoing
|
||
var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
|
||
if (hidden) { for (var i = 0; i < hidden.length; ++i)
|
||
{ if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
|
||
if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
|
||
{ if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
|
||
|
||
if (display.wrapper.offsetHeight)
|
||
{ doc.scrollTop = cm.display.scroller.scrollTop; }
|
||
|
||
// Fire change events, and delayed event handlers
|
||
if (op.changeObjs)
|
||
{ signal(cm, "changes", cm, op.changeObjs); }
|
||
if (op.update)
|
||
{ op.update.finish(); }
|
||
}
|
||
|
||
// Run the given function in an operation
|
||
function runInOp(cm, f) {
|
||
if (cm.curOp) { return f() }
|
||
startOperation(cm);
|
||
try { return f() }
|
||
finally { endOperation(cm); }
|
||
}
|
||
// Wraps a function in an operation. Returns the wrapped function.
|
||
function operation(cm, f) {
|
||
return function() {
|
||
if (cm.curOp) { return f.apply(cm, arguments) }
|
||
startOperation(cm);
|
||
try { return f.apply(cm, arguments) }
|
||
finally { endOperation(cm); }
|
||
}
|
||
}
|
||
// Used to add methods to editor and doc instances, wrapping them in
|
||
// operations.
|
||
function methodOp(f) {
|
||
return function() {
|
||
if (this.curOp) { return f.apply(this, arguments) }
|
||
startOperation(this);
|
||
try { return f.apply(this, arguments) }
|
||
finally { endOperation(this); }
|
||
}
|
||
}
|
||
function docMethodOp(f) {
|
||
return function() {
|
||
var cm = this.cm;
|
||
if (!cm || cm.curOp) { return f.apply(this, arguments) }
|
||
startOperation(cm);
|
||
try { return f.apply(this, arguments) }
|
||
finally { endOperation(cm); }
|
||
}
|
||
}
|
||
|
||
// HIGHLIGHT WORKER
|
||
|
||
function startWorker(cm, time) {
|
||
if (cm.doc.highlightFrontier < cm.display.viewTo)
|
||
{ cm.state.highlight.set(time, bind(highlightWorker, cm)); }
|
||
}
|
||
|
||
function highlightWorker(cm) {
|
||
var doc = cm.doc;
|
||
if (doc.highlightFrontier >= cm.display.viewTo) { return }
|
||
var end = +new Date + cm.options.workTime;
|
||
var context = getContextBefore(cm, doc.highlightFrontier);
|
||
var changedLines = [];
|
||
|
||
doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
|
||
if (context.line >= cm.display.viewFrom) { // Visible
|
||
var oldStyles = line.styles;
|
||
var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
|
||
var highlighted = highlightLine(cm, line, context, true);
|
||
if (resetState) { context.state = resetState; }
|
||
line.styles = highlighted.styles;
|
||
var oldCls = line.styleClasses, newCls = highlighted.classes;
|
||
if (newCls) { line.styleClasses = newCls; }
|
||
else if (oldCls) { line.styleClasses = null; }
|
||
var ischange = !oldStyles || oldStyles.length != line.styles.length ||
|
||
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
|
||
for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
|
||
if (ischange) { changedLines.push(context.line); }
|
||
line.stateAfter = context.save();
|
||
context.nextLine();
|
||
} else {
|
||
if (line.text.length <= cm.options.maxHighlightLength)
|
||
{ processLine(cm, line.text, context); }
|
||
line.stateAfter = context.line % 5 == 0 ? context.save() : null;
|
||
context.nextLine();
|
||
}
|
||
if (+new Date > end) {
|
||
startWorker(cm, cm.options.workDelay);
|
||
return true
|
||
}
|
||
});
|
||
doc.highlightFrontier = context.line;
|
||
doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
|
||
if (changedLines.length) { runInOp(cm, function () {
|
||
for (var i = 0; i < changedLines.length; i++)
|
||
{ regLineChange(cm, changedLines[i], "text"); }
|
||
}); }
|
||
}
|
||
|
||
// DISPLAY DRAWING
|
||
|
||
var DisplayUpdate = function(cm, viewport, force) {
|
||
var display = cm.display;
|
||
|
||
this.viewport = viewport;
|
||
// Store some values that we'll need later (but don't want to force a relayout for)
|
||
this.visible = visibleLines(display, cm.doc, viewport);
|
||
this.editorIsHidden = !display.wrapper.offsetWidth;
|
||
this.wrapperHeight = display.wrapper.clientHeight;
|
||
this.wrapperWidth = display.wrapper.clientWidth;
|
||
this.oldDisplayWidth = displayWidth(cm);
|
||
this.force = force;
|
||
this.dims = getDimensions(cm);
|
||
this.events = [];
|
||
};
|
||
|
||
DisplayUpdate.prototype.signal = function (emitter, type) {
|
||
if (hasHandler(emitter, type))
|
||
{ this.events.push(arguments); }
|
||
};
|
||
DisplayUpdate.prototype.finish = function () {
|
||
for (var i = 0; i < this.events.length; i++)
|
||
{ signal.apply(null, this.events[i]); }
|
||
};
|
||
|
||
function maybeClipScrollbars(cm) {
|
||
var display = cm.display;
|
||
if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
|
||
display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
|
||
display.heightForcer.style.height = scrollGap(cm) + "px";
|
||
display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
|
||
display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
|
||
display.scrollbarsClipped = true;
|
||
}
|
||
}
|
||
|
||
function selectionSnapshot(cm) {
|
||
if (cm.hasFocus()) { return null }
|
||
var active = activeElt();
|
||
if (!active || !contains(cm.display.lineDiv, active)) { return null }
|
||
var result = {activeElt: active};
|
||
if (window.getSelection) {
|
||
var sel = window.getSelection();
|
||
if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
|
||
result.anchorNode = sel.anchorNode;
|
||
result.anchorOffset = sel.anchorOffset;
|
||
result.focusNode = sel.focusNode;
|
||
result.focusOffset = sel.focusOffset;
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
function restoreSelection(snapshot) {
|
||
if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
|
||
snapshot.activeElt.focus();
|
||
if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) &&
|
||
snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
|
||
var sel = window.getSelection(), range = document.createRange();
|
||
range.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
|
||
range.collapse(false);
|
||
sel.removeAllRanges();
|
||
sel.addRange(range);
|
||
sel.extend(snapshot.focusNode, snapshot.focusOffset);
|
||
}
|
||
}
|
||
|
||
// Does the actual updating of the line display. Bails out
|
||
// (returning false) when there is nothing to be done and forced is
|
||
// false.
|
||
function updateDisplayIfNeeded(cm, update) {
|
||
var display = cm.display, doc = cm.doc;
|
||
|
||
if (update.editorIsHidden) {
|
||
resetView(cm);
|
||
return false
|
||
}
|
||
|
||
// Bail out if the visible area is already rendered and nothing changed.
|
||
if (!update.force &&
|
||
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
|
||
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
|
||
display.renderedView == display.view && countDirtyView(cm) == 0)
|
||
{ return false }
|
||
|
||
if (maybeUpdateLineNumberWidth(cm)) {
|
||
resetView(cm);
|
||
update.dims = getDimensions(cm);
|
||
}
|
||
|
||
// Compute a suitable new viewport (from & to)
|
||
var end = doc.first + doc.size;
|
||
var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
|
||
var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
|
||
if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
|
||
if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
|
||
if (sawCollapsedSpans) {
|
||
from = visualLineNo(cm.doc, from);
|
||
to = visualLineEndNo(cm.doc, to);
|
||
}
|
||
|
||
var different = from != display.viewFrom || to != display.viewTo ||
|
||
display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
|
||
adjustView(cm, from, to);
|
||
|
||
display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
|
||
// Position the mover div to align with the current scroll position
|
||
cm.display.mover.style.top = display.viewOffset + "px";
|
||
|
||
var toUpdate = countDirtyView(cm);
|
||
if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
|
||
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
|
||
{ return false }
|
||
|
||
// For big changes, we hide the enclosing element during the
|
||
// update, since that speeds up the operations on most browsers.
|
||
var selSnapshot = selectionSnapshot(cm);
|
||
if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
|
||
patchDisplay(cm, display.updateLineNumbers, update.dims);
|
||
if (toUpdate > 4) { display.lineDiv.style.display = ""; }
|
||
display.renderedView = display.view;
|
||
// There might have been a widget with a focused element that got
|
||
// hidden or updated, if so re-focus it.
|
||
restoreSelection(selSnapshot);
|
||
|
||
// Prevent selection and cursors from interfering with the scroll
|
||
// width and height.
|
||
removeChildren(display.cursorDiv);
|
||
removeChildren(display.selectionDiv);
|
||
display.gutters.style.height = display.sizer.style.minHeight = 0;
|
||
|
||
if (different) {
|
||
display.lastWrapHeight = update.wrapperHeight;
|
||
display.lastWrapWidth = update.wrapperWidth;
|
||
startWorker(cm, 400);
|
||
}
|
||
|
||
display.updateLineNumbers = null;
|
||
|
||
return true
|
||
}
|
||
|
||
function postUpdateDisplay(cm, update) {
|
||
var viewport = update.viewport;
|
||
|
||
for (var first = true;; first = false) {
|
||
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
|
||
// Clip forced viewport to actual scrollable area.
|
||
if (viewport && viewport.top != null)
|
||
{ viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
|
||
// Updated line heights might result in the drawn area not
|
||
// actually covering the viewport. Keep looping until it does.
|
||
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
||
if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
|
||
{ break }
|
||
} else if (first) {
|
||
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
||
}
|
||
if (!updateDisplayIfNeeded(cm, update)) { break }
|
||
updateHeightsInViewport(cm);
|
||
var barMeasure = measureForScrollbars(cm);
|
||
updateSelection(cm);
|
||
updateScrollbars(cm, barMeasure);
|
||
setDocumentHeight(cm, barMeasure);
|
||
update.force = false;
|
||
}
|
||
|
||
update.signal(cm, "update", cm);
|
||
if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
|
||
update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
|
||
cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
|
||
}
|
||
}
|
||
|
||
function updateDisplaySimple(cm, viewport) {
|
||
var update = new DisplayUpdate(cm, viewport);
|
||
if (updateDisplayIfNeeded(cm, update)) {
|
||
updateHeightsInViewport(cm);
|
||
postUpdateDisplay(cm, update);
|
||
var barMeasure = measureForScrollbars(cm);
|
||
updateSelection(cm);
|
||
updateScrollbars(cm, barMeasure);
|
||
setDocumentHeight(cm, barMeasure);
|
||
update.finish();
|
||
}
|
||
}
|
||
|
||
// Sync the actual display DOM structure with display.view, removing
|
||
// nodes for lines that are no longer in view, and creating the ones
|
||
// that are not there yet, and updating the ones that are out of
|
||
// date.
|
||
function patchDisplay(cm, updateNumbersFrom, dims) {
|
||
var display = cm.display, lineNumbers = cm.options.lineNumbers;
|
||
var container = display.lineDiv, cur = container.firstChild;
|
||
|
||
function rm(node) {
|
||
var next = node.nextSibling;
|
||
// Works around a throw-scroll bug in OS X Webkit
|
||
if (webkit && mac && cm.display.currentWheelTarget == node)
|
||
{ node.style.display = "none"; }
|
||
else
|
||
{ node.parentNode.removeChild(node); }
|
||
return next
|
||
}
|
||
|
||
var view = display.view, lineN = display.viewFrom;
|
||
// Loop over the elements in the view, syncing cur (the DOM nodes
|
||
// in display.lineDiv) with the view as we go.
|
||
for (var i = 0; i < view.length; i++) {
|
||
var lineView = view[i];
|
||
if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
|
||
var node = buildLineElement(cm, lineView, lineN, dims);
|
||
container.insertBefore(node, cur);
|
||
} else { // Already drawn
|
||
while (cur != lineView.node) { cur = rm(cur); }
|
||
var updateNumber = lineNumbers && updateNumbersFrom != null &&
|
||
updateNumbersFrom <= lineN && lineView.lineNumber;
|
||
if (lineView.changes) {
|
||
if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
|
||
updateLineForChanges(cm, lineView, lineN, dims);
|
||
}
|
||
if (updateNumber) {
|
||
removeChildren(lineView.lineNumber);
|
||
lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
|
||
}
|
||
cur = lineView.node.nextSibling;
|
||
}
|
||
lineN += lineView.size;
|
||
}
|
||
while (cur) { cur = rm(cur); }
|
||
}
|
||
|
||
function updateGutterSpace(display) {
|
||
var width = display.gutters.offsetWidth;
|
||
display.sizer.style.marginLeft = width + "px";
|
||
}
|
||
|
||
function setDocumentHeight(cm, measure) {
|
||
cm.display.sizer.style.minHeight = measure.docHeight + "px";
|
||
cm.display.heightForcer.style.top = measure.docHeight + "px";
|
||
cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
|
||
}
|
||
|
||
// Re-align line numbers and gutter marks to compensate for
|
||
// horizontal scrolling.
|
||
function alignHorizontally(cm) {
|
||
var display = cm.display, view = display.view;
|
||
if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
|
||
var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
|
||
var gutterW = display.gutters.offsetWidth, left = comp + "px";
|
||
for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
|
||
if (cm.options.fixedGutter) {
|
||
if (view[i].gutter)
|
||
{ view[i].gutter.style.left = left; }
|
||
if (view[i].gutterBackground)
|
||
{ view[i].gutterBackground.style.left = left; }
|
||
}
|
||
var align = view[i].alignable;
|
||
if (align) { for (var j = 0; j < align.length; j++)
|
||
{ align[j].style.left = left; } }
|
||
} }
|
||
if (cm.options.fixedGutter)
|
||
{ display.gutters.style.left = (comp + gutterW) + "px"; }
|
||
}
|
||
|
||
// Used to ensure that the line number gutter is still the right
|
||
// size for the current document size. Returns true when an update
|
||
// is needed.
|
||
function maybeUpdateLineNumberWidth(cm) {
|
||
if (!cm.options.lineNumbers) { return false }
|
||
var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
|
||
if (last.length != display.lineNumChars) {
|
||
var test = display.measure.appendChild(elt("div", [elt("div", last)],
|
||
"CodeMirror-linenumber CodeMirror-gutter-elt"));
|
||
var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
|
||
display.lineGutter.style.width = "";
|
||
display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
|
||
display.lineNumWidth = display.lineNumInnerWidth + padding;
|
||
display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
|
||
display.lineGutter.style.width = display.lineNumWidth + "px";
|
||
updateGutterSpace(cm.display);
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
function getGutters(gutters, lineNumbers) {
|
||
var result = [], sawLineNumbers = false;
|
||
for (var i = 0; i < gutters.length; i++) {
|
||
var name = gutters[i], style = null;
|
||
if (typeof name != "string") { style = name.style; name = name.className; }
|
||
if (name == "CodeMirror-linenumbers") {
|
||
if (!lineNumbers) { continue }
|
||
else { sawLineNumbers = true; }
|
||
}
|
||
result.push({className: name, style: style});
|
||
}
|
||
if (lineNumbers && !sawLineNumbers) { result.push({className: "CodeMirror-linenumbers", style: null}); }
|
||
return result
|
||
}
|
||
|
||
// Rebuild the gutter elements, ensure the margin to the left of the
|
||
// code matches their width.
|
||
function renderGutters(display) {
|
||
var gutters = display.gutters, specs = display.gutterSpecs;
|
||
removeChildren(gutters);
|
||
display.lineGutter = null;
|
||
for (var i = 0; i < specs.length; ++i) {
|
||
var ref = specs[i];
|
||
var className = ref.className;
|
||
var style = ref.style;
|
||
var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + className));
|
||
if (style) { gElt.style.cssText = style; }
|
||
if (className == "CodeMirror-linenumbers") {
|
||
display.lineGutter = gElt;
|
||
gElt.style.width = (display.lineNumWidth || 1) + "px";
|
||
}
|
||
}
|
||
gutters.style.display = specs.length ? "" : "none";
|
||
updateGutterSpace(display);
|
||
}
|
||
|
||
function updateGutters(cm) {
|
||
renderGutters(cm.display);
|
||
regChange(cm);
|
||
alignHorizontally(cm);
|
||
}
|
||
|
||
// The display handles the DOM integration, both for input reading
|
||
// and content drawing. It holds references to DOM nodes and
|
||
// display-related state.
|
||
|
||
function Display(place, doc, input, options) {
|
||
var d = this;
|
||
this.input = input;
|
||
|
||
// Covers bottom-right square when both scrollbars are present.
|
||
d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
|
||
d.scrollbarFiller.setAttribute("cm-not-content", "true");
|
||
// Covers bottom of gutter when coverGutterNextToScrollbar is on
|
||
// and h scrollbar is present.
|
||
d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
|
||
d.gutterFiller.setAttribute("cm-not-content", "true");
|
||
// Will contain the actual code, positioned to cover the viewport.
|
||
d.lineDiv = eltP("div", null, "CodeMirror-code");
|
||
// Elements are added to these to represent selection and cursors.
|
||
d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
|
||
d.cursorDiv = elt("div", null, "CodeMirror-cursors");
|
||
// A visibility: hidden element used to find the size of things.
|
||
d.measure = elt("div", null, "CodeMirror-measure");
|
||
// When lines outside of the viewport are measured, they are drawn in this.
|
||
d.lineMeasure = elt("div", null, "CodeMirror-measure");
|
||
// Wraps everything that needs to exist inside the vertically-padded coordinate system
|
||
d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
|
||
null, "position: relative; outline: none");
|
||
var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
|
||
// Moved around its parent to cover visible view.
|
||
d.mover = elt("div", [lines], null, "position: relative");
|
||
// Set to the height of the document, allowing scrolling.
|
||
d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
|
||
d.sizerWidth = null;
|
||
// Behavior of elts with overflow: auto and padding is
|
||
// inconsistent across browsers. This is used to ensure the
|
||
// scrollable area is big enough.
|
||
d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
|
||
// Will contain the gutters, if any.
|
||
d.gutters = elt("div", null, "CodeMirror-gutters");
|
||
d.lineGutter = null;
|
||
// Actual scrollable element.
|
||
d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
|
||
d.scroller.setAttribute("tabIndex", "-1");
|
||
// The element in which the editor lives.
|
||
d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
|
||
|
||
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
|
||
if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
|
||
if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
|
||
|
||
if (place) {
|
||
if (place.appendChild) { place.appendChild(d.wrapper); }
|
||
else { place(d.wrapper); }
|
||
}
|
||
|
||
// Current rendered range (may be bigger than the view window).
|
||
d.viewFrom = d.viewTo = doc.first;
|
||
d.reportedViewFrom = d.reportedViewTo = doc.first;
|
||
// Information about the rendered lines.
|
||
d.view = [];
|
||
d.renderedView = null;
|
||
// Holds info about a single rendered line when it was rendered
|
||
// for measurement, while not in view.
|
||
d.externalMeasured = null;
|
||
// Empty space (in pixels) above the view
|
||
d.viewOffset = 0;
|
||
d.lastWrapHeight = d.lastWrapWidth = 0;
|
||
d.updateLineNumbers = null;
|
||
|
||
d.nativeBarWidth = d.barHeight = d.barWidth = 0;
|
||
d.scrollbarsClipped = false;
|
||
|
||
// Used to only resize the line number gutter when necessary (when
|
||
// the amount of lines crosses a boundary that makes its width change)
|
||
d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
|
||
// Set to true when a non-horizontal-scrolling line widget is
|
||
// added. As an optimization, line widget aligning is skipped when
|
||
// this is false.
|
||
d.alignWidgets = false;
|
||
|
||
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
|
||
|
||
// Tracks the maximum line length so that the horizontal scrollbar
|
||
// can be kept static when scrolling.
|
||
d.maxLine = null;
|
||
d.maxLineLength = 0;
|
||
d.maxLineChanged = false;
|
||
|
||
// Used for measuring wheel scrolling granularity
|
||
d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
|
||
|
||
// True when shift is held down.
|
||
d.shift = false;
|
||
|
||
// Used to track whether anything happened since the context menu
|
||
// was opened.
|
||
d.selForContextMenu = null;
|
||
|
||
d.activeTouch = null;
|
||
|
||
d.gutterSpecs = getGutters(options.gutters, options.lineNumbers);
|
||
renderGutters(d);
|
||
|
||
input.init(d);
|
||
}
|
||
|
||
// Since the delta values reported on mouse wheel events are
|
||
// unstandardized between browsers and even browser versions, and
|
||
// generally horribly unpredictable, this code starts by measuring
|
||
// the scroll effect that the first few mouse wheel events have,
|
||
// and, from that, detects the way it can convert deltas to pixel
|
||
// offsets afterwards.
|
||
//
|
||
// The reason we want to know the amount a wheel event will scroll
|
||
// is that it gives us a chance to update the display before the
|
||
// actual scrolling happens, reducing flickering.
|
||
|
||
var wheelSamples = 0, wheelPixelsPerUnit = null;
|
||
// Fill in a browser-detected starting value on browsers where we
|
||
// know one. These don't have to be accurate -- the result of them
|
||
// being wrong would just be a slight flicker on the first wheel
|
||
// scroll (if it is large enough).
|
||
if (ie) { wheelPixelsPerUnit = -.53; }
|
||
else if (gecko) { wheelPixelsPerUnit = 15; }
|
||
else if (chrome) { wheelPixelsPerUnit = -.7; }
|
||
else if (safari) { wheelPixelsPerUnit = -1/3; }
|
||
|
||
function wheelEventDelta(e) {
|
||
var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
|
||
if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
|
||
if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
|
||
else if (dy == null) { dy = e.wheelDelta; }
|
||
return {x: dx, y: dy}
|
||
}
|
||
function wheelEventPixels(e) {
|
||
var delta = wheelEventDelta(e);
|
||
delta.x *= wheelPixelsPerUnit;
|
||
delta.y *= wheelPixelsPerUnit;
|
||
return delta
|
||
}
|
||
|
||
function onScrollWheel(cm, e) {
|
||
var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
|
||
|
||
var display = cm.display, scroll = display.scroller;
|
||
// Quit if there's nothing to scroll here
|
||
var canScrollX = scroll.scrollWidth > scroll.clientWidth;
|
||
var canScrollY = scroll.scrollHeight > scroll.clientHeight;
|
||
if (!(dx && canScrollX || dy && canScrollY)) { return }
|
||
|
||
// Webkit browsers on OS X abort momentum scrolls when the target
|
||
// of the scroll event is removed from the scrollable element.
|
||
// This hack (see related code in patchDisplay) makes sure the
|
||
// element is kept around.
|
||
if (dy && mac && webkit) {
|
||
outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
|
||
for (var i = 0; i < view.length; i++) {
|
||
if (view[i].node == cur) {
|
||
cm.display.currentWheelTarget = cur;
|
||
break outer
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// On some browsers, horizontal scrolling will cause redraws to
|
||
// happen before the gutter has been realigned, causing it to
|
||
// wriggle around in a most unseemly way. When we have an
|
||
// estimated pixels/delta value, we just handle horizontal
|
||
// scrolling entirely here. It'll be slightly off from native, but
|
||
// better than glitching out.
|
||
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
|
||
if (dy && canScrollY)
|
||
{ updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
|
||
setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
|
||
// Only prevent default scrolling if vertical scrolling is
|
||
// actually possible. Otherwise, it causes vertical scroll
|
||
// jitter on OSX trackpads when deltaX is small and deltaY
|
||
// is large (issue #3579)
|
||
if (!dy || (dy && canScrollY))
|
||
{ e_preventDefault(e); }
|
||
display.wheelStartX = null; // Abort measurement, if in progress
|
||
return
|
||
}
|
||
|
||
// 'Project' the visible viewport to cover the area that is being
|
||
// scrolled into view (if we know enough to estimate it).
|
||
if (dy && wheelPixelsPerUnit != null) {
|
||
var pixels = dy * wheelPixelsPerUnit;
|
||
var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
|
||
if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
|
||
else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
|
||
updateDisplaySimple(cm, {top: top, bottom: bot});
|
||
}
|
||
|
||
if (wheelSamples < 20) {
|
||
if (display.wheelStartX == null) {
|
||
display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
|
||
display.wheelDX = dx; display.wheelDY = dy;
|
||
setTimeout(function () {
|
||
if (display.wheelStartX == null) { return }
|
||
var movedX = scroll.scrollLeft - display.wheelStartX;
|
||
var movedY = scroll.scrollTop - display.wheelStartY;
|
||
var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
|
||
(movedX && display.wheelDX && movedX / display.wheelDX);
|
||
display.wheelStartX = display.wheelStartY = null;
|
||
if (!sample) { return }
|
||
wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
|
||
++wheelSamples;
|
||
}, 200);
|
||
} else {
|
||
display.wheelDX += dx; display.wheelDY += dy;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Selection objects are immutable. A new one is created every time
|
||
// the selection changes. A selection is one or more non-overlapping
|
||
// (and non-touching) ranges, sorted, and an integer that indicates
|
||
// which one is the primary selection (the one that's scrolled into
|
||
// view, that getCursor returns, etc).
|
||
var Selection = function(ranges, primIndex) {
|
||
this.ranges = ranges;
|
||
this.primIndex = primIndex;
|
||
};
|
||
|
||
Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
|
||
|
||
Selection.prototype.equals = function (other) {
|
||
if (other == this) { return true }
|
||
if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
|
||
for (var i = 0; i < this.ranges.length; i++) {
|
||
var here = this.ranges[i], there = other.ranges[i];
|
||
if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
|
||
}
|
||
return true
|
||
};
|
||
|
||
Selection.prototype.deepCopy = function () {
|
||
var out = [];
|
||
for (var i = 0; i < this.ranges.length; i++)
|
||
{ out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); }
|
||
return new Selection(out, this.primIndex)
|
||
};
|
||
|
||
Selection.prototype.somethingSelected = function () {
|
||
for (var i = 0; i < this.ranges.length; i++)
|
||
{ if (!this.ranges[i].empty()) { return true } }
|
||
return false
|
||
};
|
||
|
||
Selection.prototype.contains = function (pos, end) {
|
||
if (!end) { end = pos; }
|
||
for (var i = 0; i < this.ranges.length; i++) {
|
||
var range = this.ranges[i];
|
||
if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
|
||
{ return i }
|
||
}
|
||
return -1
|
||
};
|
||
|
||
var Range = function(anchor, head) {
|
||
this.anchor = anchor; this.head = head;
|
||
};
|
||
|
||
Range.prototype.from = function () { return minPos(this.anchor, this.head) };
|
||
Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
|
||
Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
|
||
|
||
// Take an unsorted, potentially overlapping set of ranges, and
|
||
// build a selection out of it. 'Consumes' ranges array (modifying
|
||
// it).
|
||
function normalizeSelection(cm, ranges, primIndex) {
|
||
var mayTouch = cm && cm.options.selectionsMayTouch;
|
||
var prim = ranges[primIndex];
|
||
ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
|
||
primIndex = indexOf(ranges, prim);
|
||
for (var i = 1; i < ranges.length; i++) {
|
||
var cur = ranges[i], prev = ranges[i - 1];
|
||
var diff = cmp(prev.to(), cur.from());
|
||
if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {
|
||
var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
|
||
var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
|
||
if (i <= primIndex) { --primIndex; }
|
||
ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
|
||
}
|
||
}
|
||
return new Selection(ranges, primIndex)
|
||
}
|
||
|
||
function simpleSelection(anchor, head) {
|
||
return new Selection([new Range(anchor, head || anchor)], 0)
|
||
}
|
||
|
||
// Compute the position of the end of a change (its 'to' property
|
||
// refers to the pre-change end).
|
||
function changeEnd(change) {
|
||
if (!change.text) { return change.to }
|
||
return Pos(change.from.line + change.text.length - 1,
|
||
lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
|
||
}
|
||
|
||
// Adjust a position to refer to the post-change position of the
|
||
// same text, or the end of the change if the change covers it.
|
||
function adjustForChange(pos, change) {
|
||
if (cmp(pos, change.from) < 0) { return pos }
|
||
if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
|
||
|
||
var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
|
||
if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
|
||
return Pos(line, ch)
|
||
}
|
||
|
||
function computeSelAfterChange(doc, change) {
|
||
var out = [];
|
||
for (var i = 0; i < doc.sel.ranges.length; i++) {
|
||
var range = doc.sel.ranges[i];
|
||
out.push(new Range(adjustForChange(range.anchor, change),
|
||
adjustForChange(range.head, change)));
|
||
}
|
||
return normalizeSelection(doc.cm, out, doc.sel.primIndex)
|
||
}
|
||
|
||
function offsetPos(pos, old, nw) {
|
||
if (pos.line == old.line)
|
||
{ return Pos(nw.line, pos.ch - old.ch + nw.ch) }
|
||
else
|
||
{ return Pos(nw.line + (pos.line - old.line), pos.ch) }
|
||
}
|
||
|
||
// Used by replaceSelections to allow moving the selection to the
|
||
// start or around the replaced test. Hint may be "start" or "around".
|
||
function computeReplacedSel(doc, changes, hint) {
|
||
var out = [];
|
||
var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
|
||
for (var i = 0; i < changes.length; i++) {
|
||
var change = changes[i];
|
||
var from = offsetPos(change.from, oldPrev, newPrev);
|
||
var to = offsetPos(changeEnd(change), oldPrev, newPrev);
|
||
oldPrev = change.to;
|
||
newPrev = to;
|
||
if (hint == "around") {
|
||
var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
|
||
out[i] = new Range(inv ? to : from, inv ? from : to);
|
||
} else {
|
||
out[i] = new Range(from, from);
|
||
}
|
||
}
|
||
return new Selection(out, doc.sel.primIndex)
|
||
}
|
||
|
||
// Used to get the editor into a consistent state again when options change.
|
||
|
||
function loadMode(cm) {
|
||
cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
|
||
resetModeState(cm);
|
||
}
|
||
|
||
function resetModeState(cm) {
|
||
cm.doc.iter(function (line) {
|
||
if (line.stateAfter) { line.stateAfter = null; }
|
||
if (line.styles) { line.styles = null; }
|
||
});
|
||
cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
|
||
startWorker(cm, 100);
|
||
cm.state.modeGen++;
|
||
if (cm.curOp) { regChange(cm); }
|
||
}
|
||
|
||
// DOCUMENT DATA STRUCTURE
|
||
|
||
// By default, updates that start and end at the beginning of a line
|
||
// are treated specially, in order to make the association of line
|
||
// widgets and marker elements with the text behave more intuitive.
|
||
function isWholeLineUpdate(doc, change) {
|
||
return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
|
||
(!doc.cm || doc.cm.options.wholeLineUpdateBefore)
|
||
}
|
||
|
||
// Perform a change on the document data structure.
|
||
function updateDoc(doc, change, markedSpans, estimateHeight) {
|
||
function spansFor(n) {return markedSpans ? markedSpans[n] : null}
|
||
function update(line, text, spans) {
|
||
updateLine(line, text, spans, estimateHeight);
|
||
signalLater(line, "change", line, change);
|
||
}
|
||
function linesFor(start, end) {
|
||
var result = [];
|
||
for (var i = start; i < end; ++i)
|
||
{ result.push(new Line(text[i], spansFor(i), estimateHeight)); }
|
||
return result
|
||
}
|
||
|
||
var from = change.from, to = change.to, text = change.text;
|
||
var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
|
||
var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
|
||
|
||
// Adjust the line structure
|
||
if (change.full) {
|
||
doc.insert(0, linesFor(0, text.length));
|
||
doc.remove(text.length, doc.size - text.length);
|
||
} else if (isWholeLineUpdate(doc, change)) {
|
||
// This is a whole-line replace. Treated specially to make
|
||
// sure line objects move the way they are supposed to.
|
||
var added = linesFor(0, text.length - 1);
|
||
update(lastLine, lastLine.text, lastSpans);
|
||
if (nlines) { doc.remove(from.line, nlines); }
|
||
if (added.length) { doc.insert(from.line, added); }
|
||
} else if (firstLine == lastLine) {
|
||
if (text.length == 1) {
|
||
update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
|
||
} else {
|
||
var added$1 = linesFor(1, text.length - 1);
|
||
added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
|
||
update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
|
||
doc.insert(from.line + 1, added$1);
|
||
}
|
||
} else if (text.length == 1) {
|
||
update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
|
||
doc.remove(from.line + 1, nlines);
|
||
} else {
|
||
update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
|
||
update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
|
||
var added$2 = linesFor(1, text.length - 1);
|
||
if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
|
||
doc.insert(from.line + 1, added$2);
|
||
}
|
||
|
||
signalLater(doc, "change", doc, change);
|
||
}
|
||
|
||
// Call f for all linked documents.
|
||
function linkedDocs(doc, f, sharedHistOnly) {
|
||
function propagate(doc, skip, sharedHist) {
|
||
if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
|
||
var rel = doc.linked[i];
|
||
if (rel.doc == skip) { continue }
|
||
var shared = sharedHist && rel.sharedHist;
|
||
if (sharedHistOnly && !shared) { continue }
|
||
f(rel.doc, shared);
|
||
propagate(rel.doc, doc, shared);
|
||
} }
|
||
}
|
||
propagate(doc, null, true);
|
||
}
|
||
|
||
// Attach a document to an editor.
|
||
function attachDoc(cm, doc) {
|
||
if (doc.cm) { throw new Error("This document is already in use.") }
|
||
cm.doc = doc;
|
||
doc.cm = cm;
|
||
estimateLineHeights(cm);
|
||
loadMode(cm);
|
||
setDirectionClass(cm);
|
||
if (!cm.options.lineWrapping) { findMaxLine(cm); }
|
||
cm.options.mode = doc.modeOption;
|
||
regChange(cm);
|
||
}
|
||
|
||
function setDirectionClass(cm) {
|
||
(cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
|
||
}
|
||
|
||
function directionChanged(cm) {
|
||
runInOp(cm, function () {
|
||
setDirectionClass(cm);
|
||
regChange(cm);
|
||
});
|
||
}
|
||
|
||
function History(startGen) {
|
||
// Arrays of change events and selections. Doing something adds an
|
||
// event to done and clears undo. Undoing moves events from done
|
||
// to undone, redoing moves them in the other direction.
|
||
this.done = []; this.undone = [];
|
||
this.undoDepth = Infinity;
|
||
// Used to track when changes can be merged into a single undo
|
||
// event
|
||
this.lastModTime = this.lastSelTime = 0;
|
||
this.lastOp = this.lastSelOp = null;
|
||
this.lastOrigin = this.lastSelOrigin = null;
|
||
// Used by the isClean() method
|
||
this.generation = this.maxGeneration = startGen || 1;
|
||
}
|
||
|
||
// Create a history change event from an updateDoc-style change
|
||
// object.
|
||
function historyChangeFromChange(doc, change) {
|
||
var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
|
||
attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
|
||
linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
|
||
return histChange
|
||
}
|
||
|
||
// Pop all selection events off the end of a history array. Stop at
|
||
// a change event.
|
||
function clearSelectionEvents(array) {
|
||
while (array.length) {
|
||
var last = lst(array);
|
||
if (last.ranges) { array.pop(); }
|
||
else { break }
|
||
}
|
||
}
|
||
|
||
// Find the top change event in the history. Pop off selection
|
||
// events that are in the way.
|
||
function lastChangeEvent(hist, force) {
|
||
if (force) {
|
||
clearSelectionEvents(hist.done);
|
||
return lst(hist.done)
|
||
} else if (hist.done.length && !lst(hist.done).ranges) {
|
||
return lst(hist.done)
|
||
} else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
|
||
hist.done.pop();
|
||
return lst(hist.done)
|
||
}
|
||
}
|
||
|
||
// Register a change in the history. Merges changes that are within
|
||
// a single operation, or are close together with an origin that
|
||
// allows merging (starting with "+") into a single event.
|
||
function addChangeToHistory(doc, change, selAfter, opId) {
|
||
var hist = doc.history;
|
||
hist.undone.length = 0;
|
||
var time = +new Date, cur;
|
||
var last;
|
||
|
||
if ((hist.lastOp == opId ||
|
||
hist.lastOrigin == change.origin && change.origin &&
|
||
((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
|
||
change.origin.charAt(0) == "*")) &&
|
||
(cur = lastChangeEvent(hist, hist.lastOp == opId))) {
|
||
// Merge this change into the last event
|
||
last = lst(cur.changes);
|
||
if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
|
||
// Optimized case for simple insertion -- don't want to add
|
||
// new changesets for every character typed
|
||
last.to = changeEnd(change);
|
||
} else {
|
||
// Add new sub-event
|
||
cur.changes.push(historyChangeFromChange(doc, change));
|
||
}
|
||
} else {
|
||
// Can not be merged, start a new event.
|
||
var before = lst(hist.done);
|
||
if (!before || !before.ranges)
|
||
{ pushSelectionToHistory(doc.sel, hist.done); }
|
||
cur = {changes: [historyChangeFromChange(doc, change)],
|
||
generation: hist.generation};
|
||
hist.done.push(cur);
|
||
while (hist.done.length > hist.undoDepth) {
|
||
hist.done.shift();
|
||
if (!hist.done[0].ranges) { hist.done.shift(); }
|
||
}
|
||
}
|
||
hist.done.push(selAfter);
|
||
hist.generation = ++hist.maxGeneration;
|
||
hist.lastModTime = hist.lastSelTime = time;
|
||
hist.lastOp = hist.lastSelOp = opId;
|
||
hist.lastOrigin = hist.lastSelOrigin = change.origin;
|
||
|
||
if (!last) { signal(doc, "historyAdded"); }
|
||
}
|
||
|
||
function selectionEventCanBeMerged(doc, origin, prev, sel) {
|
||
var ch = origin.charAt(0);
|
||
return ch == "*" ||
|
||
ch == "+" &&
|
||
prev.ranges.length == sel.ranges.length &&
|
||
prev.somethingSelected() == sel.somethingSelected() &&
|
||
new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
|
||
}
|
||
|
||
// Called whenever the selection changes, sets the new selection as
|
||
// the pending selection in the history, and pushes the old pending
|
||
// selection into the 'done' array when it was significantly
|
||
// different (in number of selected ranges, emptiness, or time).
|
||
function addSelectionToHistory(doc, sel, opId, options) {
|
||
var hist = doc.history, origin = options && options.origin;
|
||
|
||
// A new event is started when the previous origin does not match
|
||
// the current, or the origins don't allow matching. Origins
|
||
// starting with * are always merged, those starting with + are
|
||
// merged when similar and close together in time.
|
||
if (opId == hist.lastSelOp ||
|
||
(origin && hist.lastSelOrigin == origin &&
|
||
(hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
|
||
selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
|
||
{ hist.done[hist.done.length - 1] = sel; }
|
||
else
|
||
{ pushSelectionToHistory(sel, hist.done); }
|
||
|
||
hist.lastSelTime = +new Date;
|
||
hist.lastSelOrigin = origin;
|
||
hist.lastSelOp = opId;
|
||
if (options && options.clearRedo !== false)
|
||
{ clearSelectionEvents(hist.undone); }
|
||
}
|
||
|
||
function pushSelectionToHistory(sel, dest) {
|
||
var top = lst(dest);
|
||
if (!(top && top.ranges && top.equals(sel)))
|
||
{ dest.push(sel); }
|
||
}
|
||
|
||
// Used to store marked span information in the history.
|
||
function attachLocalSpans(doc, change, from, to) {
|
||
var existing = change["spans_" + doc.id], n = 0;
|
||
doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
|
||
if (line.markedSpans)
|
||
{ (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
|
||
++n;
|
||
});
|
||
}
|
||
|
||
// When un/re-doing restores text containing marked spans, those
|
||
// that have been explicitly cleared should not be restored.
|
||
function removeClearedSpans(spans) {
|
||
if (!spans) { return null }
|
||
var out;
|
||
for (var i = 0; i < spans.length; ++i) {
|
||
if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
|
||
else if (out) { out.push(spans[i]); }
|
||
}
|
||
return !out ? spans : out.length ? out : null
|
||
}
|
||
|
||
// Retrieve and filter the old marked spans stored in a change event.
|
||
function getOldSpans(doc, change) {
|
||
var found = change["spans_" + doc.id];
|
||
if (!found) { return null }
|
||
var nw = [];
|
||
for (var i = 0; i < change.text.length; ++i)
|
||
{ nw.push(removeClearedSpans(found[i])); }
|
||
return nw
|
||
}
|
||
|
||
// Used for un/re-doing changes from the history. Combines the
|
||
// result of computing the existing spans with the set of spans that
|
||
// existed in the history (so that deleting around a span and then
|
||
// undoing brings back the span).
|
||
function mergeOldSpans(doc, change) {
|
||
var old = getOldSpans(doc, change);
|
||
var stretched = stretchSpansOverChange(doc, change);
|
||
if (!old) { return stretched }
|
||
if (!stretched) { return old }
|
||
|
||
for (var i = 0; i < old.length; ++i) {
|
||
var oldCur = old[i], stretchCur = stretched[i];
|
||
if (oldCur && stretchCur) {
|
||
spans: for (var j = 0; j < stretchCur.length; ++j) {
|
||
var span = stretchCur[j];
|
||
for (var k = 0; k < oldCur.length; ++k)
|
||
{ if (oldCur[k].marker == span.marker) { continue spans } }
|
||
oldCur.push(span);
|
||
}
|
||
} else if (stretchCur) {
|
||
old[i] = stretchCur;
|
||
}
|
||
}
|
||
return old
|
||
}
|
||
|
||
// Used both to provide a JSON-safe object in .getHistory, and, when
|
||
// detaching a document, to split the history in two
|
||
function copyHistoryArray(events, newGroup, instantiateSel) {
|
||
var copy = [];
|
||
for (var i = 0; i < events.length; ++i) {
|
||
var event = events[i];
|
||
if (event.ranges) {
|
||
copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
|
||
continue
|
||
}
|
||
var changes = event.changes, newChanges = [];
|
||
copy.push({changes: newChanges});
|
||
for (var j = 0; j < changes.length; ++j) {
|
||
var change = changes[j], m = (void 0);
|
||
newChanges.push({from: change.from, to: change.to, text: change.text});
|
||
if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
|
||
if (indexOf(newGroup, Number(m[1])) > -1) {
|
||
lst(newChanges)[prop] = change[prop];
|
||
delete change[prop];
|
||
}
|
||
} } }
|
||
}
|
||
}
|
||
return copy
|
||
}
|
||
|
||
// The 'scroll' parameter given to many of these indicated whether
|
||
// the new cursor position should be scrolled into view after
|
||
// modifying the selection.
|
||
|
||
// If shift is held or the extend flag is set, extends a range to
|
||
// include a given position (and optionally a second position).
|
||
// Otherwise, simply returns the range between the given positions.
|
||
// Used for cursor motion and such.
|
||
function extendRange(range, head, other, extend) {
|
||
if (extend) {
|
||
var anchor = range.anchor;
|
||
if (other) {
|
||
var posBefore = cmp(head, anchor) < 0;
|
||
if (posBefore != (cmp(other, anchor) < 0)) {
|
||
anchor = head;
|
||
head = other;
|
||
} else if (posBefore != (cmp(head, other) < 0)) {
|
||
head = other;
|
||
}
|
||
}
|
||
return new Range(anchor, head)
|
||
} else {
|
||
return new Range(other || head, head)
|
||
}
|
||
}
|
||
|
||
// Extend the primary selection range, discard the rest.
|
||
function extendSelection(doc, head, other, options, extend) {
|
||
if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
|
||
setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
|
||
}
|
||
|
||
// Extend all selections (pos is an array of selections with length
|
||
// equal the number of selections)
|
||
function extendSelections(doc, heads, options) {
|
||
var out = [];
|
||
var extend = doc.cm && (doc.cm.display.shift || doc.extend);
|
||
for (var i = 0; i < doc.sel.ranges.length; i++)
|
||
{ out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
|
||
var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex);
|
||
setSelection(doc, newSel, options);
|
||
}
|
||
|
||
// Updates a single range in the selection.
|
||
function replaceOneSelection(doc, i, range, options) {
|
||
var ranges = doc.sel.ranges.slice(0);
|
||
ranges[i] = range;
|
||
setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options);
|
||
}
|
||
|
||
// Reset the selection to a single range.
|
||
function setSimpleSelection(doc, anchor, head, options) {
|
||
setSelection(doc, simpleSelection(anchor, head), options);
|
||
}
|
||
|
||
// Give beforeSelectionChange handlers a change to influence a
|
||
// selection update.
|
||
function filterSelectionChange(doc, sel, options) {
|
||
var obj = {
|
||
ranges: sel.ranges,
|
||
update: function(ranges) {
|
||
this.ranges = [];
|
||
for (var i = 0; i < ranges.length; i++)
|
||
{ this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
|
||
clipPos(doc, ranges[i].head)); }
|
||
},
|
||
origin: options && options.origin
|
||
};
|
||
signal(doc, "beforeSelectionChange", doc, obj);
|
||
if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
|
||
if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) }
|
||
else { return sel }
|
||
}
|
||
|
||
function setSelectionReplaceHistory(doc, sel, options) {
|
||
var done = doc.history.done, last = lst(done);
|
||
if (last && last.ranges) {
|
||
done[done.length - 1] = sel;
|
||
setSelectionNoUndo(doc, sel, options);
|
||
} else {
|
||
setSelection(doc, sel, options);
|
||
}
|
||
}
|
||
|
||
// Set a new selection.
|
||
function setSelection(doc, sel, options) {
|
||
setSelectionNoUndo(doc, sel, options);
|
||
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
|
||
}
|
||
|
||
function setSelectionNoUndo(doc, sel, options) {
|
||
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
|
||
{ sel = filterSelectionChange(doc, sel, options); }
|
||
|
||
var bias = options && options.bias ||
|
||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
|
||
setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
|
||
|
||
if (!(options && options.scroll === false) && doc.cm)
|
||
{ ensureCursorVisible(doc.cm); }
|
||
}
|
||
|
||
function setSelectionInner(doc, sel) {
|
||
if (sel.equals(doc.sel)) { return }
|
||
|
||
doc.sel = sel;
|
||
|
||
if (doc.cm) {
|
||
doc.cm.curOp.updateInput = 1;
|
||
doc.cm.curOp.selectionChanged = true;
|
||
signalCursorActivity(doc.cm);
|
||
}
|
||
signalLater(doc, "cursorActivity", doc);
|
||
}
|
||
|
||
// Verify that the selection does not partially select any atomic
|
||
// marked ranges.
|
||
function reCheckSelection(doc) {
|
||
setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
|
||
}
|
||
|
||
// Return a selection that does not partially select any atomic
|
||
// ranges.
|
||
function skipAtomicInSelection(doc, sel, bias, mayClear) {
|
||
var out;
|
||
for (var i = 0; i < sel.ranges.length; i++) {
|
||
var range = sel.ranges[i];
|
||
var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
|
||
var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
|
||
var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
|
||
if (out || newAnchor != range.anchor || newHead != range.head) {
|
||
if (!out) { out = sel.ranges.slice(0, i); }
|
||
out[i] = new Range(newAnchor, newHead);
|
||
}
|
||
}
|
||
return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel
|
||
}
|
||
|
||
function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
|
||
var line = getLine(doc, pos.line);
|
||
if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
|
||
var sp = line.markedSpans[i], m = sp.marker;
|
||
|
||
// Determine if we should prevent the cursor being placed to the left/right of an atomic marker
|
||
// Historically this was determined using the inclusiveLeft/Right option, but the new way to control it
|
||
// is with selectLeft/Right
|
||
var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft;
|
||
var preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight;
|
||
|
||
if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
|
||
(sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
|
||
if (mayClear) {
|
||
signal(m, "beforeCursorEnter");
|
||
if (m.explicitlyCleared) {
|
||
if (!line.markedSpans) { break }
|
||
else {--i; continue}
|
||
}
|
||
}
|
||
if (!m.atomic) { continue }
|
||
|
||
if (oldPos) {
|
||
var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
|
||
if (dir < 0 ? preventCursorRight : preventCursorLeft)
|
||
{ near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
|
||
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
|
||
{ return skipAtomicInner(doc, near, pos, dir, mayClear) }
|
||
}
|
||
|
||
var far = m.find(dir < 0 ? -1 : 1);
|
||
if (dir < 0 ? preventCursorLeft : preventCursorRight)
|
||
{ far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
|
||
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
|
||
}
|
||
} }
|
||
return pos
|
||
}
|
||
|
||
// Ensure a given position is not inside an atomic range.
|
||
function skipAtomic(doc, pos, oldPos, bias, mayClear) {
|
||
var dir = bias || 1;
|
||
var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
|
||
(!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
|
||
skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
|
||
(!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
|
||
if (!found) {
|
||
doc.cantEdit = true;
|
||
return Pos(doc.first, 0)
|
||
}
|
||
return found
|
||
}
|
||
|
||
function movePos(doc, pos, dir, line) {
|
||
if (dir < 0 && pos.ch == 0) {
|
||
if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
|
||
else { return null }
|
||
} else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
|
||
if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
|
||
else { return null }
|
||
} else {
|
||
return new Pos(pos.line, pos.ch + dir)
|
||
}
|
||
}
|
||
|
||
function selectAll(cm) {
|
||
cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
|
||
}
|
||
|
||
// UPDATING
|
||
|
||
// Allow "beforeChange" event handlers to influence a change
|
||
function filterChange(doc, change, update) {
|
||
var obj = {
|
||
canceled: false,
|
||
from: change.from,
|
||
to: change.to,
|
||
text: change.text,
|
||
origin: change.origin,
|
||
cancel: function () { return obj.canceled = true; }
|
||
};
|
||
if (update) { obj.update = function (from, to, text, origin) {
|
||
if (from) { obj.from = clipPos(doc, from); }
|
||
if (to) { obj.to = clipPos(doc, to); }
|
||
if (text) { obj.text = text; }
|
||
if (origin !== undefined) { obj.origin = origin; }
|
||
}; }
|
||
signal(doc, "beforeChange", doc, obj);
|
||
if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
|
||
|
||
if (obj.canceled) {
|
||
if (doc.cm) { doc.cm.curOp.updateInput = 2; }
|
||
return null
|
||
}
|
||
return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
|
||
}
|
||
|
||
// Apply a change to a document, and add it to the document's
|
||
// history, and propagating it to all linked documents.
|
||
function makeChange(doc, change, ignoreReadOnly) {
|
||
if (doc.cm) {
|
||
if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
|
||
if (doc.cm.state.suppressEdits) { return }
|
||
}
|
||
|
||
if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
|
||
change = filterChange(doc, change, true);
|
||
if (!change) { return }
|
||
}
|
||
|
||
// Possibly split or suppress the update based on the presence
|
||
// of read-only spans in its range.
|
||
var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
|
||
if (split) {
|
||
for (var i = split.length - 1; i >= 0; --i)
|
||
{ makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
|
||
} else {
|
||
makeChangeInner(doc, change);
|
||
}
|
||
}
|
||
|
||
function makeChangeInner(doc, change) {
|
||
if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
|
||
var selAfter = computeSelAfterChange(doc, change);
|
||
addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
|
||
|
||
makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
|
||
var rebased = [];
|
||
|
||
linkedDocs(doc, function (doc, sharedHist) {
|
||
if (!sharedHist && indexOf(rebased, doc.history) == -1) {
|
||
rebaseHist(doc.history, change);
|
||
rebased.push(doc.history);
|
||
}
|
||
makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
|
||
});
|
||
}
|
||
|
||
// Revert a change stored in a document's history.
|
||
function makeChangeFromHistory(doc, type, allowSelectionOnly) {
|
||
var suppress = doc.cm && doc.cm.state.suppressEdits;
|
||
if (suppress && !allowSelectionOnly) { return }
|
||
|
||
var hist = doc.history, event, selAfter = doc.sel;
|
||
var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
|
||
|
||
// Verify that there is a useable event (so that ctrl-z won't
|
||
// needlessly clear selection events)
|
||
var i = 0;
|
||
for (; i < source.length; i++) {
|
||
event = source[i];
|
||
if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
|
||
{ break }
|
||
}
|
||
if (i == source.length) { return }
|
||
hist.lastOrigin = hist.lastSelOrigin = null;
|
||
|
||
for (;;) {
|
||
event = source.pop();
|
||
if (event.ranges) {
|
||
pushSelectionToHistory(event, dest);
|
||
if (allowSelectionOnly && !event.equals(doc.sel)) {
|
||
setSelection(doc, event, {clearRedo: false});
|
||
return
|
||
}
|
||
selAfter = event;
|
||
} else if (suppress) {
|
||
source.push(event);
|
||
return
|
||
} else { break }
|
||
}
|
||
|
||
// Build up a reverse change object to add to the opposite history
|
||
// stack (redo when undoing, and vice versa).
|
||
var antiChanges = [];
|
||
pushSelectionToHistory(selAfter, dest);
|
||
dest.push({changes: antiChanges, generation: hist.generation});
|
||
hist.generation = event.generation || ++hist.maxGeneration;
|
||
|
||
var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
|
||
|
||
var loop = function ( i ) {
|
||
var change = event.changes[i];
|
||
change.origin = type;
|
||
if (filter && !filterChange(doc, change, false)) {
|
||
source.length = 0;
|
||
return {}
|
||
}
|
||
|
||
antiChanges.push(historyChangeFromChange(doc, change));
|
||
|
||
var after = i ? computeSelAfterChange(doc, change) : lst(source);
|
||
makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
|
||
if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
|
||
var rebased = [];
|
||
|
||
// Propagate to the linked documents
|
||
linkedDocs(doc, function (doc, sharedHist) {
|
||
if (!sharedHist && indexOf(rebased, doc.history) == -1) {
|
||
rebaseHist(doc.history, change);
|
||
rebased.push(doc.history);
|
||
}
|
||
makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
|
||
});
|
||
};
|
||
|
||
for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
|
||
var returned = loop( i$1 );
|
||
|
||
if ( returned ) return returned.v;
|
||
}
|
||
}
|
||
|
||
// Sub-views need their line numbers shifted when text is added
|
||
// above or below them in the parent document.
|
||
function shiftDoc(doc, distance) {
|
||
if (distance == 0) { return }
|
||
doc.first += distance;
|
||
doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
|
||
Pos(range.anchor.line + distance, range.anchor.ch),
|
||
Pos(range.head.line + distance, range.head.ch)
|
||
); }), doc.sel.primIndex);
|
||
if (doc.cm) {
|
||
regChange(doc.cm, doc.first, doc.first - distance, distance);
|
||
for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
|
||
{ regLineChange(doc.cm, l, "gutter"); }
|
||
}
|
||
}
|
||
|
||
// More lower-level change function, handling only a single document
|
||
// (not linked ones).
|
||
function makeChangeSingleDoc(doc, change, selAfter, spans) {
|
||
if (doc.cm && !doc.cm.curOp)
|
||
{ return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
|
||
|
||
if (change.to.line < doc.first) {
|
||
shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
|
||
return
|
||
}
|
||
if (change.from.line > doc.lastLine()) { return }
|
||
|
||
// Clip the change to the size of this doc
|
||
if (change.from.line < doc.first) {
|
||
var shift = change.text.length - 1 - (doc.first - change.from.line);
|
||
shiftDoc(doc, shift);
|
||
change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
|
||
text: [lst(change.text)], origin: change.origin};
|
||
}
|
||
var last = doc.lastLine();
|
||
if (change.to.line > last) {
|
||
change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
|
||
text: [change.text[0]], origin: change.origin};
|
||
}
|
||
|
||
change.removed = getBetween(doc, change.from, change.to);
|
||
|
||
if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
|
||
if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
|
||
else { updateDoc(doc, change, spans); }
|
||
setSelectionNoUndo(doc, selAfter, sel_dontScroll);
|
||
|
||
if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0)))
|
||
{ doc.cantEdit = false; }
|
||
}
|
||
|
||
// Handle the interaction of a change to a document with the editor
|
||
// that this document is part of.
|
||
function makeChangeSingleDocInEditor(cm, change, spans) {
|
||
var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
|
||
|
||
var recomputeMaxLength = false, checkWidthStart = from.line;
|
||
if (!cm.options.lineWrapping) {
|
||
checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
|
||
doc.iter(checkWidthStart, to.line + 1, function (line) {
|
||
if (line == display.maxLine) {
|
||
recomputeMaxLength = true;
|
||
return true
|
||
}
|
||
});
|
||
}
|
||
|
||
if (doc.sel.contains(change.from, change.to) > -1)
|
||
{ signalCursorActivity(cm); }
|
||
|
||
updateDoc(doc, change, spans, estimateHeight(cm));
|
||
|
||
if (!cm.options.lineWrapping) {
|
||
doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
|
||
var len = lineLength(line);
|
||
if (len > display.maxLineLength) {
|
||
display.maxLine = line;
|
||
display.maxLineLength = len;
|
||
display.maxLineChanged = true;
|
||
recomputeMaxLength = false;
|
||
}
|
||
});
|
||
if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
|
||
}
|
||
|
||
retreatFrontier(doc, from.line);
|
||
startWorker(cm, 400);
|
||
|
||
var lendiff = change.text.length - (to.line - from.line) - 1;
|
||
// Remember that these lines changed, for updating the display
|
||
if (change.full)
|
||
{ regChange(cm); }
|
||
else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
|
||
{ regLineChange(cm, from.line, "text"); }
|
||
else
|
||
{ regChange(cm, from.line, to.line + 1, lendiff); }
|
||
|
||
var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
|
||
if (changeHandler || changesHandler) {
|
||
var obj = {
|
||
from: from, to: to,
|
||
text: change.text,
|
||
removed: change.removed,
|
||
origin: change.origin
|
||
};
|
||
if (changeHandler) { signalLater(cm, "change", cm, obj); }
|
||
if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
|
||
}
|
||
cm.display.selForContextMenu = null;
|
||
}
|
||
|
||
function replaceRange(doc, code, from, to, origin) {
|
||
var assign;
|
||
|
||
if (!to) { to = from; }
|
||
if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); }
|
||
if (typeof code == "string") { code = doc.splitLines(code); }
|
||
makeChange(doc, {from: from, to: to, text: code, origin: origin});
|
||
}
|
||
|
||
// Rebasing/resetting history to deal with externally-sourced changes
|
||
|
||
function rebaseHistSelSingle(pos, from, to, diff) {
|
||
if (to < pos.line) {
|
||
pos.line += diff;
|
||
} else if (from < pos.line) {
|
||
pos.line = from;
|
||
pos.ch = 0;
|
||
}
|
||
}
|
||
|
||
// Tries to rebase an array of history events given a change in the
|
||
// document. If the change touches the same lines as the event, the
|
||
// event, and everything 'behind' it, is discarded. If the change is
|
||
// before the event, the event's positions are updated. Uses a
|
||
// copy-on-write scheme for the positions, to avoid having to
|
||
// reallocate them all on every rebase, but also avoid problems with
|
||
// shared position objects being unsafely updated.
|
||
function rebaseHistArray(array, from, to, diff) {
|
||
for (var i = 0; i < array.length; ++i) {
|
||
var sub = array[i], ok = true;
|
||
if (sub.ranges) {
|
||
if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
|
||
for (var j = 0; j < sub.ranges.length; j++) {
|
||
rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
|
||
rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
|
||
}
|
||
continue
|
||
}
|
||
for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
|
||
var cur = sub.changes[j$1];
|
||
if (to < cur.from.line) {
|
||
cur.from = Pos(cur.from.line + diff, cur.from.ch);
|
||
cur.to = Pos(cur.to.line + diff, cur.to.ch);
|
||
} else if (from <= cur.to.line) {
|
||
ok = false;
|
||
break
|
||
}
|
||
}
|
||
if (!ok) {
|
||
array.splice(0, i + 1);
|
||
i = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
function rebaseHist(hist, change) {
|
||
var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
|
||
rebaseHistArray(hist.done, from, to, diff);
|
||
rebaseHistArray(hist.undone, from, to, diff);
|
||
}
|
||
|
||
// Utility for applying a change to a line by handle or number,
|
||
// returning the number and optionally registering the line as
|
||
// changed.
|
||
function changeLine(doc, handle, changeType, op) {
|
||
var no = handle, line = handle;
|
||
if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
|
||
else { no = lineNo(handle); }
|
||
if (no == null) { return null }
|
||
if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
|
||
return line
|
||
}
|
||
|
||
// The document is represented as a BTree consisting of leaves, with
|
||
// chunk of lines in them, and branches, with up to ten leaves or
|
||
// other branch nodes below them. The top node is always a branch
|
||
// node, and is the document object itself (meaning it has
|
||
// additional methods and properties).
|
||
//
|
||
// All nodes have parent links. The tree is used both to go from
|
||
// line numbers to line objects, and to go from objects to numbers.
|
||
// It also indexes by height, and is used to convert between height
|
||
// and line object, and to find the total height of the document.
|
||
//
|
||
// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
|
||
|
||
function LeafChunk(lines) {
|
||
this.lines = lines;
|
||
this.parent = null;
|
||
var height = 0;
|
||
for (var i = 0; i < lines.length; ++i) {
|
||
lines[i].parent = this;
|
||
height += lines[i].height;
|
||
}
|
||
this.height = height;
|
||
}
|
||
|
||
LeafChunk.prototype = {
|
||
chunkSize: function() { return this.lines.length },
|
||
|
||
// Remove the n lines at offset 'at'.
|
||
removeInner: function(at, n) {
|
||
for (var i = at, e = at + n; i < e; ++i) {
|
||
var line = this.lines[i];
|
||
this.height -= line.height;
|
||
cleanUpLine(line);
|
||
signalLater(line, "delete");
|
||
}
|
||
this.lines.splice(at, n);
|
||
},
|
||
|
||
// Helper used to collapse a small branch into a single leaf.
|
||
collapse: function(lines) {
|
||
lines.push.apply(lines, this.lines);
|
||
},
|
||
|
||
// Insert the given array of lines at offset 'at', count them as
|
||
// having the given height.
|
||
insertInner: function(at, lines, height) {
|
||
this.height += height;
|
||
this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
|
||
for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; }
|
||
},
|
||
|
||
// Used to iterate over a part of the tree.
|
||
iterN: function(at, n, op) {
|
||
for (var e = at + n; at < e; ++at)
|
||
{ if (op(this.lines[at])) { return true } }
|
||
}
|
||
};
|
||
|
||
function BranchChunk(children) {
|
||
this.children = children;
|
||
var size = 0, height = 0;
|
||
for (var i = 0; i < children.length; ++i) {
|
||
var ch = children[i];
|
||
size += ch.chunkSize(); height += ch.height;
|
||
ch.parent = this;
|
||
}
|
||
this.size = size;
|
||
this.height = height;
|
||
this.parent = null;
|
||
}
|
||
|
||
BranchChunk.prototype = {
|
||
chunkSize: function() { return this.size },
|
||
|
||
removeInner: function(at, n) {
|
||
this.size -= n;
|
||
for (var i = 0; i < this.children.length; ++i) {
|
||
var child = this.children[i], sz = child.chunkSize();
|
||
if (at < sz) {
|
||
var rm = Math.min(n, sz - at), oldHeight = child.height;
|
||
child.removeInner(at, rm);
|
||
this.height -= oldHeight - child.height;
|
||
if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
|
||
if ((n -= rm) == 0) { break }
|
||
at = 0;
|
||
} else { at -= sz; }
|
||
}
|
||
// If the result is smaller than 25 lines, ensure that it is a
|
||
// single leaf node.
|
||
if (this.size - n < 25 &&
|
||
(this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
|
||
var lines = [];
|
||
this.collapse(lines);
|
||
this.children = [new LeafChunk(lines)];
|
||
this.children[0].parent = this;
|
||
}
|
||
},
|
||
|
||
collapse: function(lines) {
|
||
for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); }
|
||
},
|
||
|
||
insertInner: function(at, lines, height) {
|
||
this.size += lines.length;
|
||
this.height += height;
|
||
for (var i = 0; i < this.children.length; ++i) {
|
||
var child = this.children[i], sz = child.chunkSize();
|
||
if (at <= sz) {
|
||
child.insertInner(at, lines, height);
|
||
if (child.lines && child.lines.length > 50) {
|
||
// To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
|
||
// Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
|
||
var remaining = child.lines.length % 25 + 25;
|
||
for (var pos = remaining; pos < child.lines.length;) {
|
||
var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
|
||
child.height -= leaf.height;
|
||
this.children.splice(++i, 0, leaf);
|
||
leaf.parent = this;
|
||
}
|
||
child.lines = child.lines.slice(0, remaining);
|
||
this.maybeSpill();
|
||
}
|
||
break
|
||
}
|
||
at -= sz;
|
||
}
|
||
},
|
||
|
||
// When a node has grown, check whether it should be split.
|
||
maybeSpill: function() {
|
||
if (this.children.length <= 10) { return }
|
||
var me = this;
|
||
do {
|
||
var spilled = me.children.splice(me.children.length - 5, 5);
|
||
var sibling = new BranchChunk(spilled);
|
||
if (!me.parent) { // Become the parent node
|
||
var copy = new BranchChunk(me.children);
|
||
copy.parent = me;
|
||
me.children = [copy, sibling];
|
||
me = copy;
|
||
} else {
|
||
me.size -= sibling.size;
|
||
me.height -= sibling.height;
|
||
var myIndex = indexOf(me.parent.children, me);
|
||
me.parent.children.splice(myIndex + 1, 0, sibling);
|
||
}
|
||
sibling.parent = me.parent;
|
||
} while (me.children.length > 10)
|
||
me.parent.maybeSpill();
|
||
},
|
||
|
||
iterN: function(at, n, op) {
|
||
for (var i = 0; i < this.children.length; ++i) {
|
||
var child = this.children[i], sz = child.chunkSize();
|
||
if (at < sz) {
|
||
var used = Math.min(n, sz - at);
|
||
if (child.iterN(at, used, op)) { return true }
|
||
if ((n -= used) == 0) { break }
|
||
at = 0;
|
||
} else { at -= sz; }
|
||
}
|
||
}
|
||
};
|
||
|
||
// Line widgets are block elements displayed above or below a line.
|
||
|
||
var LineWidget = function(doc, node, options) {
|
||
if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
|
||
{ this[opt] = options[opt]; } } }
|
||
this.doc = doc;
|
||
this.node = node;
|
||
};
|
||
|
||
LineWidget.prototype.clear = function () {
|
||
var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
|
||
if (no == null || !ws) { return }
|
||
for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } }
|
||
if (!ws.length) { line.widgets = null; }
|
||
var height = widgetHeight(this);
|
||
updateLineHeight(line, Math.max(0, line.height - height));
|
||
if (cm) {
|
||
runInOp(cm, function () {
|
||
adjustScrollWhenAboveVisible(cm, line, -height);
|
||
regLineChange(cm, no, "widget");
|
||
});
|
||
signalLater(cm, "lineWidgetCleared", cm, this, no);
|
||
}
|
||
};
|
||
|
||
LineWidget.prototype.changed = function () {
|
||
var this$1 = this;
|
||
|
||
var oldH = this.height, cm = this.doc.cm, line = this.line;
|
||
this.height = null;
|
||
var diff = widgetHeight(this) - oldH;
|
||
if (!diff) { return }
|
||
if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }
|
||
if (cm) {
|
||
runInOp(cm, function () {
|
||
cm.curOp.forceUpdate = true;
|
||
adjustScrollWhenAboveVisible(cm, line, diff);
|
||
signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
|
||
});
|
||
}
|
||
};
|
||
eventMixin(LineWidget);
|
||
|
||
function adjustScrollWhenAboveVisible(cm, line, diff) {
|
||
if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
|
||
{ addToScrollTop(cm, diff); }
|
||
}
|
||
|
||
function addLineWidget(doc, handle, node, options) {
|
||
var widget = new LineWidget(doc, node, options);
|
||
var cm = doc.cm;
|
||
if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
|
||
changeLine(doc, handle, "widget", function (line) {
|
||
var widgets = line.widgets || (line.widgets = []);
|
||
if (widget.insertAt == null) { widgets.push(widget); }
|
||
else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
|
||
widget.line = line;
|
||
if (cm && !lineIsHidden(doc, line)) {
|
||
var aboveVisible = heightAtLine(line) < doc.scrollTop;
|
||
updateLineHeight(line, line.height + widgetHeight(widget));
|
||
if (aboveVisible) { addToScrollTop(cm, widget.height); }
|
||
cm.curOp.forceUpdate = true;
|
||
}
|
||
return true
|
||
});
|
||
if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); }
|
||
return widget
|
||
}
|
||
|
||
// TEXTMARKERS
|
||
|
||
// Created with markText and setBookmark methods. A TextMarker is a
|
||
// handle that can be used to clear or find a marked position in the
|
||
// document. Line objects hold arrays (markedSpans) containing
|
||
// {from, to, marker} object pointing to such marker objects, and
|
||
// indicating that such a marker is present on that line. Multiple
|
||
// lines may point to the same marker when it spans across lines.
|
||
// The spans will have null for their from/to properties when the
|
||
// marker continues beyond the start/end of the line. Markers have
|
||
// links back to the lines they currently touch.
|
||
|
||
// Collapsed markers have unique ids, in order to be able to order
|
||
// them, which is needed for uniquely determining an outer marker
|
||
// when they overlap (they may nest, but not partially overlap).
|
||
var nextMarkerId = 0;
|
||
|
||
var TextMarker = function(doc, type) {
|
||
this.lines = [];
|
||
this.type = type;
|
||
this.doc = doc;
|
||
this.id = ++nextMarkerId;
|
||
};
|
||
|
||
// Clear the marker.
|
||
TextMarker.prototype.clear = function () {
|
||
if (this.explicitlyCleared) { return }
|
||
var cm = this.doc.cm, withOp = cm && !cm.curOp;
|
||
if (withOp) { startOperation(cm); }
|
||
if (hasHandler(this, "clear")) {
|
||
var found = this.find();
|
||
if (found) { signalLater(this, "clear", found.from, found.to); }
|
||
}
|
||
var min = null, max = null;
|
||
for (var i = 0; i < this.lines.length; ++i) {
|
||
var line = this.lines[i];
|
||
var span = getMarkedSpanFor(line.markedSpans, this);
|
||
if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); }
|
||
else if (cm) {
|
||
if (span.to != null) { max = lineNo(line); }
|
||
if (span.from != null) { min = lineNo(line); }
|
||
}
|
||
line.markedSpans = removeMarkedSpan(line.markedSpans, span);
|
||
if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
|
||
{ updateLineHeight(line, textHeight(cm.display)); }
|
||
}
|
||
if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
|
||
var visual = visualLine(this.lines[i$1]), len = lineLength(visual);
|
||
if (len > cm.display.maxLineLength) {
|
||
cm.display.maxLine = visual;
|
||
cm.display.maxLineLength = len;
|
||
cm.display.maxLineChanged = true;
|
||
}
|
||
} }
|
||
|
||
if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
|
||
this.lines.length = 0;
|
||
this.explicitlyCleared = true;
|
||
if (this.atomic && this.doc.cantEdit) {
|
||
this.doc.cantEdit = false;
|
||
if (cm) { reCheckSelection(cm.doc); }
|
||
}
|
||
if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
|
||
if (withOp) { endOperation(cm); }
|
||
if (this.parent) { this.parent.clear(); }
|
||
};
|
||
|
||
// Find the position of the marker in the document. Returns a {from,
|
||
// to} object by default. Side can be passed to get a specific side
|
||
// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
|
||
// Pos objects returned contain a line object, rather than a line
|
||
// number (used to prevent looking up the same line twice).
|
||
TextMarker.prototype.find = function (side, lineObj) {
|
||
if (side == null && this.type == "bookmark") { side = 1; }
|
||
var from, to;
|
||
for (var i = 0; i < this.lines.length; ++i) {
|
||
var line = this.lines[i];
|
||
var span = getMarkedSpanFor(line.markedSpans, this);
|
||
if (span.from != null) {
|
||
from = Pos(lineObj ? line : lineNo(line), span.from);
|
||
if (side == -1) { return from }
|
||
}
|
||
if (span.to != null) {
|
||
to = Pos(lineObj ? line : lineNo(line), span.to);
|
||
if (side == 1) { return to }
|
||
}
|
||
}
|
||
return from && {from: from, to: to}
|
||
};
|
||
|
||
// Signals that the marker's widget changed, and surrounding layout
|
||
// should be recomputed.
|
||
TextMarker.prototype.changed = function () {
|
||
var this$1 = this;
|
||
|
||
var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
|
||
if (!pos || !cm) { return }
|
||
runInOp(cm, function () {
|
||
var line = pos.line, lineN = lineNo(pos.line);
|
||
var view = findViewForLine(cm, lineN);
|
||
if (view) {
|
||
clearLineMeasurementCacheFor(view);
|
||
cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
|
||
}
|
||
cm.curOp.updateMaxLine = true;
|
||
if (!lineIsHidden(widget.doc, line) && widget.height != null) {
|
||
var oldHeight = widget.height;
|
||
widget.height = null;
|
||
var dHeight = widgetHeight(widget) - oldHeight;
|
||
if (dHeight)
|
||
{ updateLineHeight(line, line.height + dHeight); }
|
||
}
|
||
signalLater(cm, "markerChanged", cm, this$1);
|
||
});
|
||
};
|
||
|
||
TextMarker.prototype.attachLine = function (line) {
|
||
if (!this.lines.length && this.doc.cm) {
|
||
var op = this.doc.cm.curOp;
|
||
if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
|
||
{ (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
|
||
}
|
||
this.lines.push(line);
|
||
};
|
||
|
||
TextMarker.prototype.detachLine = function (line) {
|
||
this.lines.splice(indexOf(this.lines, line), 1);
|
||
if (!this.lines.length && this.doc.cm) {
|
||
var op = this.doc.cm.curOp
|
||
;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
|
||
}
|
||
};
|
||
eventMixin(TextMarker);
|
||
|
||
// Create a marker, wire it up to the right lines, and
|
||
function markText(doc, from, to, options, type) {
|
||
// Shared markers (across linked documents) are handled separately
|
||
// (markTextShared will call out to this again, once per
|
||
// document).
|
||
if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
|
||
// Ensure we are in an operation.
|
||
if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
|
||
|
||
var marker = new TextMarker(doc, type), diff = cmp(from, to);
|
||
if (options) { copyObj(options, marker, false); }
|
||
// Don't connect empty markers unless clearWhenEmpty is false
|
||
if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
|
||
{ return marker }
|
||
if (marker.replacedWith) {
|
||
// Showing up as a widget implies collapsed (widget replaces text)
|
||
marker.collapsed = true;
|
||
marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
|
||
if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
|
||
if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
|
||
}
|
||
if (marker.collapsed) {
|
||
if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
|
||
from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
|
||
{ throw new Error("Inserting collapsed marker partially overlapping an existing one") }
|
||
seeCollapsedSpans();
|
||
}
|
||
|
||
if (marker.addToHistory)
|
||
{ addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
|
||
|
||
var curLine = from.line, cm = doc.cm, updateMaxLine;
|
||
doc.iter(curLine, to.line + 1, function (line) {
|
||
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
|
||
{ updateMaxLine = true; }
|
||
if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
|
||
addMarkedSpan(line, new MarkedSpan(marker,
|
||
curLine == from.line ? from.ch : null,
|
||
curLine == to.line ? to.ch : null));
|
||
++curLine;
|
||
});
|
||
// lineIsHidden depends on the presence of the spans, so needs a second pass
|
||
if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
|
||
if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
|
||
}); }
|
||
|
||
if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
|
||
|
||
if (marker.readOnly) {
|
||
seeReadOnlySpans();
|
||
if (doc.history.done.length || doc.history.undone.length)
|
||
{ doc.clearHistory(); }
|
||
}
|
||
if (marker.collapsed) {
|
||
marker.id = ++nextMarkerId;
|
||
marker.atomic = true;
|
||
}
|
||
if (cm) {
|
||
// Sync editor state
|
||
if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
|
||
if (marker.collapsed)
|
||
{ regChange(cm, from.line, to.line + 1); }
|
||
else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
|
||
marker.attributes || marker.title)
|
||
{ for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
|
||
if (marker.atomic) { reCheckSelection(cm.doc); }
|
||
signalLater(cm, "markerAdded", cm, marker);
|
||
}
|
||
return marker
|
||
}
|
||
|
||
// SHARED TEXTMARKERS
|
||
|
||
// A shared marker spans multiple linked documents. It is
|
||
// implemented as a meta-marker-object controlling multiple normal
|
||
// markers.
|
||
var SharedTextMarker = function(markers, primary) {
|
||
this.markers = markers;
|
||
this.primary = primary;
|
||
for (var i = 0; i < markers.length; ++i)
|
||
{ markers[i].parent = this; }
|
||
};
|
||
|
||
SharedTextMarker.prototype.clear = function () {
|
||
if (this.explicitlyCleared) { return }
|
||
this.explicitlyCleared = true;
|
||
for (var i = 0; i < this.markers.length; ++i)
|
||
{ this.markers[i].clear(); }
|
||
signalLater(this, "clear");
|
||
};
|
||
|
||
SharedTextMarker.prototype.find = function (side, lineObj) {
|
||
return this.primary.find(side, lineObj)
|
||
};
|
||
eventMixin(SharedTextMarker);
|
||
|
||
function markTextShared(doc, from, to, options, type) {
|
||
options = copyObj(options);
|
||
options.shared = false;
|
||
var markers = [markText(doc, from, to, options, type)], primary = markers[0];
|
||
var widget = options.widgetNode;
|
||
linkedDocs(doc, function (doc) {
|
||
if (widget) { options.widgetNode = widget.cloneNode(true); }
|
||
markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
|
||
for (var i = 0; i < doc.linked.length; ++i)
|
||
{ if (doc.linked[i].isParent) { return } }
|
||
primary = lst(markers);
|
||
});
|
||
return new SharedTextMarker(markers, primary)
|
||
}
|
||
|
||
function findSharedMarkers(doc) {
|
||
return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
|
||
}
|
||
|
||
function copySharedMarkers(doc, markers) {
|
||
for (var i = 0; i < markers.length; i++) {
|
||
var marker = markers[i], pos = marker.find();
|
||
var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
|
||
if (cmp(mFrom, mTo)) {
|
||
var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
|
||
marker.markers.push(subMark);
|
||
subMark.parent = marker;
|
||
}
|
||
}
|
||
}
|
||
|
||
function detachSharedMarkers(markers) {
|
||
var loop = function ( i ) {
|
||
var marker = markers[i], linked = [marker.primary.doc];
|
||
linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
|
||
for (var j = 0; j < marker.markers.length; j++) {
|
||
var subMarker = marker.markers[j];
|
||
if (indexOf(linked, subMarker.doc) == -1) {
|
||
subMarker.parent = null;
|
||
marker.markers.splice(j--, 1);
|
||
}
|
||
}
|
||
};
|
||
|
||
for (var i = 0; i < markers.length; i++) loop( i );
|
||
}
|
||
|
||
var nextDocId = 0;
|
||
var Doc = function(text, mode, firstLine, lineSep, direction) {
|
||
if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
|
||
if (firstLine == null) { firstLine = 0; }
|
||
|
||
BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
|
||
this.first = firstLine;
|
||
this.scrollTop = this.scrollLeft = 0;
|
||
this.cantEdit = false;
|
||
this.cleanGeneration = 1;
|
||
this.modeFrontier = this.highlightFrontier = firstLine;
|
||
var start = Pos(firstLine, 0);
|
||
this.sel = simpleSelection(start);
|
||
this.history = new History(null);
|
||
this.id = ++nextDocId;
|
||
this.modeOption = mode;
|
||
this.lineSep = lineSep;
|
||
this.direction = (direction == "rtl") ? "rtl" : "ltr";
|
||
this.extend = false;
|
||
|
||
if (typeof text == "string") { text = this.splitLines(text); }
|
||
updateDoc(this, {from: start, to: start, text: text});
|
||
setSelection(this, simpleSelection(start), sel_dontScroll);
|
||
};
|
||
|
||
Doc.prototype = createObj(BranchChunk.prototype, {
|
||
constructor: Doc,
|
||
// Iterate over the document. Supports two forms -- with only one
|
||
// argument, it calls that for each line in the document. With
|
||
// three, it iterates over the range given by the first two (with
|
||
// the second being non-inclusive).
|
||
iter: function(from, to, op) {
|
||
if (op) { this.iterN(from - this.first, to - from, op); }
|
||
else { this.iterN(this.first, this.first + this.size, from); }
|
||
},
|
||
|
||
// Non-public interface for adding and removing lines.
|
||
insert: function(at, lines) {
|
||
var height = 0;
|
||
for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
|
||
this.insertInner(at - this.first, lines, height);
|
||
},
|
||
remove: function(at, n) { this.removeInner(at - this.first, n); },
|
||
|
||
// From here, the methods are part of the public interface. Most
|
||
// are also available from CodeMirror (editor) instances.
|
||
|
||
getValue: function(lineSep) {
|
||
var lines = getLines(this, this.first, this.first + this.size);
|
||
if (lineSep === false) { return lines }
|
||
return lines.join(lineSep || this.lineSeparator())
|
||
},
|
||
setValue: docMethodOp(function(code) {
|
||
var top = Pos(this.first, 0), last = this.first + this.size - 1;
|
||
makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
|
||
text: this.splitLines(code), origin: "setValue", full: true}, true);
|
||
if (this.cm) { scrollToCoords(this.cm, 0, 0); }
|
||
setSelection(this, simpleSelection(top), sel_dontScroll);
|
||
}),
|
||
replaceRange: function(code, from, to, origin) {
|
||
from = clipPos(this, from);
|
||
to = to ? clipPos(this, to) : from;
|
||
replaceRange(this, code, from, to, origin);
|
||
},
|
||
getRange: function(from, to, lineSep) {
|
||
var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
|
||
if (lineSep === false) { return lines }
|
||
return lines.join(lineSep || this.lineSeparator())
|
||
},
|
||
|
||
getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
|
||
|
||
getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
|
||
getLineNumber: function(line) {return lineNo(line)},
|
||
|
||
getLineHandleVisualStart: function(line) {
|
||
if (typeof line == "number") { line = getLine(this, line); }
|
||
return visualLine(line)
|
||
},
|
||
|
||
lineCount: function() {return this.size},
|
||
firstLine: function() {return this.first},
|
||
lastLine: function() {return this.first + this.size - 1},
|
||
|
||
clipPos: function(pos) {return clipPos(this, pos)},
|
||
|
||
getCursor: function(start) {
|
||
var range = this.sel.primary(), pos;
|
||
if (start == null || start == "head") { pos = range.head; }
|
||
else if (start == "anchor") { pos = range.anchor; }
|
||
else if (start == "end" || start == "to" || start === false) { pos = range.to(); }
|
||
else { pos = range.from(); }
|
||
return pos
|
||
},
|
||
listSelections: function() { return this.sel.ranges },
|
||
somethingSelected: function() {return this.sel.somethingSelected()},
|
||
|
||
setCursor: docMethodOp(function(line, ch, options) {
|
||
setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
|
||
}),
|
||
setSelection: docMethodOp(function(anchor, head, options) {
|
||
setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
|
||
}),
|
||
extendSelection: docMethodOp(function(head, other, options) {
|
||
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
|
||
}),
|
||
extendSelections: docMethodOp(function(heads, options) {
|
||
extendSelections(this, clipPosArray(this, heads), options);
|
||
}),
|
||
extendSelectionsBy: docMethodOp(function(f, options) {
|
||
var heads = map(this.sel.ranges, f);
|
||
extendSelections(this, clipPosArray(this, heads), options);
|
||
}),
|
||
setSelections: docMethodOp(function(ranges, primary, options) {
|
||
if (!ranges.length) { return }
|
||
var out = [];
|
||
for (var i = 0; i < ranges.length; i++)
|
||
{ out[i] = new Range(clipPos(this, ranges[i].anchor),
|
||
clipPos(this, ranges[i].head)); }
|
||
if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
|
||
setSelection(this, normalizeSelection(this.cm, out, primary), options);
|
||
}),
|
||
addSelection: docMethodOp(function(anchor, head, options) {
|
||
var ranges = this.sel.ranges.slice(0);
|
||
ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
|
||
setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options);
|
||
}),
|
||
|
||
getSelection: function(lineSep) {
|
||
var ranges = this.sel.ranges, lines;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var sel = getBetween(this, ranges[i].from(), ranges[i].to());
|
||
lines = lines ? lines.concat(sel) : sel;
|
||
}
|
||
if (lineSep === false) { return lines }
|
||
else { return lines.join(lineSep || this.lineSeparator()) }
|
||
},
|
||
getSelections: function(lineSep) {
|
||
var parts = [], ranges = this.sel.ranges;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var sel = getBetween(this, ranges[i].from(), ranges[i].to());
|
||
if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); }
|
||
parts[i] = sel;
|
||
}
|
||
return parts
|
||
},
|
||
replaceSelection: function(code, collapse, origin) {
|
||
var dup = [];
|
||
for (var i = 0; i < this.sel.ranges.length; i++)
|
||
{ dup[i] = code; }
|
||
this.replaceSelections(dup, collapse, origin || "+input");
|
||
},
|
||
replaceSelections: docMethodOp(function(code, collapse, origin) {
|
||
var changes = [], sel = this.sel;
|
||
for (var i = 0; i < sel.ranges.length; i++) {
|
||
var range = sel.ranges[i];
|
||
changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
|
||
}
|
||
var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
|
||
for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
|
||
{ makeChange(this, changes[i$1]); }
|
||
if (newSel) { setSelectionReplaceHistory(this, newSel); }
|
||
else if (this.cm) { ensureCursorVisible(this.cm); }
|
||
}),
|
||
undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
|
||
redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
|
||
undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
|
||
redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
|
||
|
||
setExtending: function(val) {this.extend = val;},
|
||
getExtending: function() {return this.extend},
|
||
|
||
historySize: function() {
|
||
var hist = this.history, done = 0, undone = 0;
|
||
for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
|
||
for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
|
||
return {undo: done, redo: undone}
|
||
},
|
||
clearHistory: function() {
|
||
var this$1 = this;
|
||
|
||
this.history = new History(this.history.maxGeneration);
|
||
linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true);
|
||
},
|
||
|
||
markClean: function() {
|
||
this.cleanGeneration = this.changeGeneration(true);
|
||
},
|
||
changeGeneration: function(forceSplit) {
|
||
if (forceSplit)
|
||
{ this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
|
||
return this.history.generation
|
||
},
|
||
isClean: function (gen) {
|
||
return this.history.generation == (gen || this.cleanGeneration)
|
||
},
|
||
|
||
getHistory: function() {
|
||
return {done: copyHistoryArray(this.history.done),
|
||
undone: copyHistoryArray(this.history.undone)}
|
||
},
|
||
setHistory: function(histData) {
|
||
var hist = this.history = new History(this.history.maxGeneration);
|
||
hist.done = copyHistoryArray(histData.done.slice(0), null, true);
|
||
hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
|
||
},
|
||
|
||
setGutterMarker: docMethodOp(function(line, gutterID, value) {
|
||
return changeLine(this, line, "gutter", function (line) {
|
||
var markers = line.gutterMarkers || (line.gutterMarkers = {});
|
||
markers[gutterID] = value;
|
||
if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
|
||
return true
|
||
})
|
||
}),
|
||
|
||
clearGutter: docMethodOp(function(gutterID) {
|
||
var this$1 = this;
|
||
|
||
this.iter(function (line) {
|
||
if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
|
||
changeLine(this$1, line, "gutter", function () {
|
||
line.gutterMarkers[gutterID] = null;
|
||
if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
|
||
return true
|
||
});
|
||
}
|
||
});
|
||
}),
|
||
|
||
lineInfo: function(line) {
|
||
var n;
|
||
if (typeof line == "number") {
|
||
if (!isLine(this, line)) { return null }
|
||
n = line;
|
||
line = getLine(this, line);
|
||
if (!line) { return null }
|
||
} else {
|
||
n = lineNo(line);
|
||
if (n == null) { return null }
|
||
}
|
||
return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
|
||
textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
|
||
widgets: line.widgets}
|
||
},
|
||
|
||
addLineClass: docMethodOp(function(handle, where, cls) {
|
||
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
|
||
var prop = where == "text" ? "textClass"
|
||
: where == "background" ? "bgClass"
|
||
: where == "gutter" ? "gutterClass" : "wrapClass";
|
||
if (!line[prop]) { line[prop] = cls; }
|
||
else if (classTest(cls).test(line[prop])) { return false }
|
||
else { line[prop] += " " + cls; }
|
||
return true
|
||
})
|
||
}),
|
||
removeLineClass: docMethodOp(function(handle, where, cls) {
|
||
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
|
||
var prop = where == "text" ? "textClass"
|
||
: where == "background" ? "bgClass"
|
||
: where == "gutter" ? "gutterClass" : "wrapClass";
|
||
var cur = line[prop];
|
||
if (!cur) { return false }
|
||
else if (cls == null) { line[prop] = null; }
|
||
else {
|
||
var found = cur.match(classTest(cls));
|
||
if (!found) { return false }
|
||
var end = found.index + found[0].length;
|
||
line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
|
||
}
|
||
return true
|
||
})
|
||
}),
|
||
|
||
addLineWidget: docMethodOp(function(handle, node, options) {
|
||
return addLineWidget(this, handle, node, options)
|
||
}),
|
||
removeLineWidget: function(widget) { widget.clear(); },
|
||
|
||
markText: function(from, to, options) {
|
||
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
|
||
},
|
||
setBookmark: function(pos, options) {
|
||
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
|
||
insertLeft: options && options.insertLeft,
|
||
clearWhenEmpty: false, shared: options && options.shared,
|
||
handleMouseEvents: options && options.handleMouseEvents};
|
||
pos = clipPos(this, pos);
|
||
return markText(this, pos, pos, realOpts, "bookmark")
|
||
},
|
||
findMarksAt: function(pos) {
|
||
pos = clipPos(this, pos);
|
||
var markers = [], spans = getLine(this, pos.line).markedSpans;
|
||
if (spans) { for (var i = 0; i < spans.length; ++i) {
|
||
var span = spans[i];
|
||
if ((span.from == null || span.from <= pos.ch) &&
|
||
(span.to == null || span.to >= pos.ch))
|
||
{ markers.push(span.marker.parent || span.marker); }
|
||
} }
|
||
return markers
|
||
},
|
||
findMarks: function(from, to, filter) {
|
||
from = clipPos(this, from); to = clipPos(this, to);
|
||
var found = [], lineNo = from.line;
|
||
this.iter(from.line, to.line + 1, function (line) {
|
||
var spans = line.markedSpans;
|
||
if (spans) { for (var i = 0; i < spans.length; i++) {
|
||
var span = spans[i];
|
||
if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||
|
||
span.from == null && lineNo != from.line ||
|
||
span.from != null && lineNo == to.line && span.from >= to.ch) &&
|
||
(!filter || filter(span.marker)))
|
||
{ found.push(span.marker.parent || span.marker); }
|
||
} }
|
||
++lineNo;
|
||
});
|
||
return found
|
||
},
|
||
getAllMarks: function() {
|
||
var markers = [];
|
||
this.iter(function (line) {
|
||
var sps = line.markedSpans;
|
||
if (sps) { for (var i = 0; i < sps.length; ++i)
|
||
{ if (sps[i].from != null) { markers.push(sps[i].marker); } } }
|
||
});
|
||
return markers
|
||
},
|
||
|
||
posFromIndex: function(off) {
|
||
var ch, lineNo = this.first, sepSize = this.lineSeparator().length;
|
||
this.iter(function (line) {
|
||
var sz = line.text.length + sepSize;
|
||
if (sz > off) { ch = off; return true }
|
||
off -= sz;
|
||
++lineNo;
|
||
});
|
||
return clipPos(this, Pos(lineNo, ch))
|
||
},
|
||
indexFromPos: function (coords) {
|
||
coords = clipPos(this, coords);
|
||
var index = coords.ch;
|
||
if (coords.line < this.first || coords.ch < 0) { return 0 }
|
||
var sepSize = this.lineSeparator().length;
|
||
this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
|
||
index += line.text.length + sepSize;
|
||
});
|
||
return index
|
||
},
|
||
|
||
copy: function(copyHistory) {
|
||
var doc = new Doc(getLines(this, this.first, this.first + this.size),
|
||
this.modeOption, this.first, this.lineSep, this.direction);
|
||
doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
|
||
doc.sel = this.sel;
|
||
doc.extend = false;
|
||
if (copyHistory) {
|
||
doc.history.undoDepth = this.history.undoDepth;
|
||
doc.setHistory(this.getHistory());
|
||
}
|
||
return doc
|
||
},
|
||
|
||
linkedDoc: function(options) {
|
||
if (!options) { options = {}; }
|
||
var from = this.first, to = this.first + this.size;
|
||
if (options.from != null && options.from > from) { from = options.from; }
|
||
if (options.to != null && options.to < to) { to = options.to; }
|
||
var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
|
||
if (options.sharedHist) { copy.history = this.history
|
||
; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
|
||
copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
|
||
copySharedMarkers(copy, findSharedMarkers(this));
|
||
return copy
|
||
},
|
||
unlinkDoc: function(other) {
|
||
if (other instanceof CodeMirror) { other = other.doc; }
|
||
if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
|
||
var link = this.linked[i];
|
||
if (link.doc != other) { continue }
|
||
this.linked.splice(i, 1);
|
||
other.unlinkDoc(this);
|
||
detachSharedMarkers(findSharedMarkers(this));
|
||
break
|
||
} }
|
||
// If the histories were shared, split them again
|
||
if (other.history == this.history) {
|
||
var splitIds = [other.id];
|
||
linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
|
||
other.history = new History(null);
|
||
other.history.done = copyHistoryArray(this.history.done, splitIds);
|
||
other.history.undone = copyHistoryArray(this.history.undone, splitIds);
|
||
}
|
||
},
|
||
iterLinkedDocs: function(f) {linkedDocs(this, f);},
|
||
|
||
getMode: function() {return this.mode},
|
||
getEditor: function() {return this.cm},
|
||
|
||
splitLines: function(str) {
|
||
if (this.lineSep) { return str.split(this.lineSep) }
|
||
return splitLinesAuto(str)
|
||
},
|
||
lineSeparator: function() { return this.lineSep || "\n" },
|
||
|
||
setDirection: docMethodOp(function (dir) {
|
||
if (dir != "rtl") { dir = "ltr"; }
|
||
if (dir == this.direction) { return }
|
||
this.direction = dir;
|
||
this.iter(function (line) { return line.order = null; });
|
||
if (this.cm) { directionChanged(this.cm); }
|
||
})
|
||
});
|
||
|
||
// Public alias.
|
||
Doc.prototype.eachLine = Doc.prototype.iter;
|
||
|
||
// Kludge to work around strange IE behavior where it'll sometimes
|
||
// re-fire a series of drag-related events right after the drop (#1551)
|
||
var lastDrop = 0;
|
||
|
||
function onDrop(e) {
|
||
var cm = this;
|
||
clearDragCursor(cm);
|
||
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
|
||
{ return }
|
||
e_preventDefault(e);
|
||
if (ie) { lastDrop = +new Date; }
|
||
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
|
||
if (!pos || cm.isReadOnly()) { return }
|
||
// Might be a file drop, in which case we simply extract the text
|
||
// and insert it.
|
||
if (files && files.length && window.FileReader && window.File) {
|
||
var n = files.length, text = Array(n), read = 0;
|
||
var markAsReadAndPasteIfAllFilesAreRead = function () {
|
||
if (++read == n) {
|
||
operation(cm, function () {
|
||
pos = clipPos(cm.doc, pos);
|
||
var change = {from: pos, to: pos,
|
||
text: cm.doc.splitLines(
|
||
text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())),
|
||
origin: "paste"};
|
||
makeChange(cm.doc, change);
|
||
setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change))));
|
||
})();
|
||
}
|
||
};
|
||
var readTextFromFile = function (file, i) {
|
||
if (cm.options.allowDropFileTypes &&
|
||
indexOf(cm.options.allowDropFileTypes, file.type) == -1) {
|
||
markAsReadAndPasteIfAllFilesAreRead();
|
||
return
|
||
}
|
||
var reader = new FileReader;
|
||
reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); };
|
||
reader.onload = function () {
|
||
var content = reader.result;
|
||
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) {
|
||
markAsReadAndPasteIfAllFilesAreRead();
|
||
return
|
||
}
|
||
text[i] = content;
|
||
markAsReadAndPasteIfAllFilesAreRead();
|
||
};
|
||
reader.readAsText(file);
|
||
};
|
||
for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); }
|
||
} else { // Normal drop
|
||
// Don't do a replace if the drop happened inside of the selected text.
|
||
if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
|
||
cm.state.draggingText(e);
|
||
// Ensure the editor is re-focused
|
||
setTimeout(function () { return cm.display.input.focus(); }, 20);
|
||
return
|
||
}
|
||
try {
|
||
var text$1 = e.dataTransfer.getData("Text");
|
||
if (text$1) {
|
||
var selected;
|
||
if (cm.state.draggingText && !cm.state.draggingText.copy)
|
||
{ selected = cm.listSelections(); }
|
||
setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
|
||
if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
|
||
{ replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
|
||
cm.replaceSelection(text$1, "around", "paste");
|
||
cm.display.input.focus();
|
||
}
|
||
}
|
||
catch(e$1){}
|
||
}
|
||
}
|
||
|
||
function onDragStart(cm, e) {
|
||
if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
|
||
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
|
||
|
||
e.dataTransfer.setData("Text", cm.getSelection());
|
||
e.dataTransfer.effectAllowed = "copyMove";
|
||
|
||
// Use dummy image instead of default browsers image.
|
||
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
|
||
if (e.dataTransfer.setDragImage && !safari) {
|
||
var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
|
||
img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
|
||
if (presto) {
|
||
img.width = img.height = 1;
|
||
cm.display.wrapper.appendChild(img);
|
||
// Force a relayout, or Opera won't use our image for some obscure reason
|
||
img._top = img.offsetTop;
|
||
}
|
||
e.dataTransfer.setDragImage(img, 0, 0);
|
||
if (presto) { img.parentNode.removeChild(img); }
|
||
}
|
||
}
|
||
|
||
function onDragOver(cm, e) {
|
||
var pos = posFromMouse(cm, e);
|
||
if (!pos) { return }
|
||
var frag = document.createDocumentFragment();
|
||
drawSelectionCursor(cm, pos, frag);
|
||
if (!cm.display.dragCursor) {
|
||
cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
|
||
cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
|
||
}
|
||
removeChildrenAndAdd(cm.display.dragCursor, frag);
|
||
}
|
||
|
||
function clearDragCursor(cm) {
|
||
if (cm.display.dragCursor) {
|
||
cm.display.lineSpace.removeChild(cm.display.dragCursor);
|
||
cm.display.dragCursor = null;
|
||
}
|
||
}
|
||
|
||
// These must be handled carefully, because naively registering a
|
||
// handler for each editor will cause the editors to never be
|
||
// garbage collected.
|
||
|
||
function forEachCodeMirror(f) {
|
||
if (!document.getElementsByClassName) { return }
|
||
var byClass = document.getElementsByClassName("CodeMirror"), editors = [];
|
||
for (var i = 0; i < byClass.length; i++) {
|
||
var cm = byClass[i].CodeMirror;
|
||
if (cm) { editors.push(cm); }
|
||
}
|
||
if (editors.length) { editors[0].operation(function () {
|
||
for (var i = 0; i < editors.length; i++) { f(editors[i]); }
|
||
}); }
|
||
}
|
||
|
||
var globalsRegistered = false;
|
||
function ensureGlobalHandlers() {
|
||
if (globalsRegistered) { return }
|
||
registerGlobalHandlers();
|
||
globalsRegistered = true;
|
||
}
|
||
function registerGlobalHandlers() {
|
||
// When the window resizes, we need to refresh active editors.
|
||
var resizeTimer;
|
||
on(window, "resize", function () {
|
||
if (resizeTimer == null) { resizeTimer = setTimeout(function () {
|
||
resizeTimer = null;
|
||
forEachCodeMirror(onResize);
|
||
}, 100); }
|
||
});
|
||
// When the window loses focus, we want to show the editor as blurred
|
||
on(window, "blur", function () { return forEachCodeMirror(onBlur); });
|
||
}
|
||
// Called when the window resizes
|
||
function onResize(cm) {
|
||
var d = cm.display;
|
||
// Might be a text scaling operation, clear size caches.
|
||
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
|
||
d.scrollbarsClipped = false;
|
||
cm.setSize();
|
||
}
|
||
|
||
var keyNames = {
|
||
3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
||
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
||
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
||
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
|
||
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock",
|
||
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
|
||
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
|
||
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
|
||
};
|
||
|
||
// Number keys
|
||
for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
|
||
// Alphabetic keys
|
||
for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
|
||
// Function keys
|
||
for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
|
||
|
||
var keyMap = {};
|
||
|
||
keyMap.basic = {
|
||
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
|
||
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
|
||
"Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
|
||
"Tab": "defaultTab", "Shift-Tab": "indentAuto",
|
||
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
|
||
"Esc": "singleSelection"
|
||
};
|
||
// Note that the save and find-related commands aren't defined by
|
||
// default. User code or addons can define them. Unknown commands
|
||
// are simply ignored.
|
||
keyMap.pcDefault = {
|
||
"Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
|
||
"Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
|
||
"Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
|
||
"Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
|
||
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
|
||
"Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
|
||
"Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
|
||
"fallthrough": "basic"
|
||
};
|
||
// Very basic readline/emacs-style bindings, which are standard on Mac.
|
||
keyMap.emacsy = {
|
||
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
|
||
"Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
|
||
"Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
|
||
"Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
|
||
"Ctrl-O": "openLine"
|
||
};
|
||
keyMap.macDefault = {
|
||
"Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
|
||
"Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
|
||
"Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
|
||
"Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
|
||
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
|
||
"Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
|
||
"Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
|
||
"fallthrough": ["basic", "emacsy"]
|
||
};
|
||
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
|
||
|
||
// KEYMAP DISPATCH
|
||
|
||
function normalizeKeyName(name) {
|
||
var parts = name.split(/-(?!$)/);
|
||
name = parts[parts.length - 1];
|
||
var alt, ctrl, shift, cmd;
|
||
for (var i = 0; i < parts.length - 1; i++) {
|
||
var mod = parts[i];
|
||
if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
|
||
else if (/^a(lt)?$/i.test(mod)) { alt = true; }
|
||
else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
|
||
else if (/^s(hift)?$/i.test(mod)) { shift = true; }
|
||
else { throw new Error("Unrecognized modifier name: " + mod) }
|
||
}
|
||
if (alt) { name = "Alt-" + name; }
|
||
if (ctrl) { name = "Ctrl-" + name; }
|
||
if (cmd) { name = "Cmd-" + name; }
|
||
if (shift) { name = "Shift-" + name; }
|
||
return name
|
||
}
|
||
|
||
// This is a kludge to keep keymaps mostly working as raw objects
|
||
// (backwards compatibility) while at the same time support features
|
||
// like normalization and multi-stroke key bindings. It compiles a
|
||
// new normalized keymap, and then updates the old object to reflect
|
||
// this.
|
||
function normalizeKeyMap(keymap) {
|
||
var copy = {};
|
||
for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
|
||
var value = keymap[keyname];
|
||
if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
|
||
if (value == "...") { delete keymap[keyname]; continue }
|
||
|
||
var keys = map(keyname.split(" "), normalizeKeyName);
|
||
for (var i = 0; i < keys.length; i++) {
|
||
var val = (void 0), name = (void 0);
|
||
if (i == keys.length - 1) {
|
||
name = keys.join(" ");
|
||
val = value;
|
||
} else {
|
||
name = keys.slice(0, i + 1).join(" ");
|
||
val = "...";
|
||
}
|
||
var prev = copy[name];
|
||
if (!prev) { copy[name] = val; }
|
||
else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
|
||
}
|
||
delete keymap[keyname];
|
||
} }
|
||
for (var prop in copy) { keymap[prop] = copy[prop]; }
|
||
return keymap
|
||
}
|
||
|
||
function lookupKey(key, map, handle, context) {
|
||
map = getKeyMap(map);
|
||
var found = map.call ? map.call(key, context) : map[key];
|
||
if (found === false) { return "nothing" }
|
||
if (found === "...") { return "multi" }
|
||
if (found != null && handle(found)) { return "handled" }
|
||
|
||
if (map.fallthrough) {
|
||
if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
|
||
{ return lookupKey(key, map.fallthrough, handle, context) }
|
||
for (var i = 0; i < map.fallthrough.length; i++) {
|
||
var result = lookupKey(key, map.fallthrough[i], handle, context);
|
||
if (result) { return result }
|
||
}
|
||
}
|
||
}
|
||
|
||
// Modifier key presses don't count as 'real' key presses for the
|
||
// purpose of keymap fallthrough.
|
||
function isModifierKey(value) {
|
||
var name = typeof value == "string" ? value : keyNames[value.keyCode];
|
||
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
|
||
}
|
||
|
||
function addModifierNames(name, event, noShift) {
|
||
var base = name;
|
||
if (event.altKey && base != "Alt") { name = "Alt-" + name; }
|
||
if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
|
||
if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
|
||
if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
|
||
return name
|
||
}
|
||
|
||
// Look up the name of a key as indicated by an event object.
|
||
function keyName(event, noShift) {
|
||
if (presto && event.keyCode == 34 && event["char"]) { return false }
|
||
var name = keyNames[event.keyCode];
|
||
if (name == null || event.altGraphKey) { return false }
|
||
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
|
||
// so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
|
||
if (event.keyCode == 3 && event.code) { name = event.code; }
|
||
return addModifierNames(name, event, noShift)
|
||
}
|
||
|
||
function getKeyMap(val) {
|
||
return typeof val == "string" ? keyMap[val] : val
|
||
}
|
||
|
||
// Helper for deleting text near the selection(s), used to implement
|
||
// backspace, delete, and similar functionality.
|
||
function deleteNearSelection(cm, compute) {
|
||
var ranges = cm.doc.sel.ranges, kill = [];
|
||
// Build up a set of ranges to kill first, merging overlapping
|
||
// ranges.
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var toKill = compute(ranges[i]);
|
||
while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
|
||
var replaced = kill.pop();
|
||
if (cmp(replaced.from, toKill.from) < 0) {
|
||
toKill.from = replaced.from;
|
||
break
|
||
}
|
||
}
|
||
kill.push(toKill);
|
||
}
|
||
// Next, remove those actual ranges.
|
||
runInOp(cm, function () {
|
||
for (var i = kill.length - 1; i >= 0; i--)
|
||
{ replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
|
||
ensureCursorVisible(cm);
|
||
});
|
||
}
|
||
|
||
function moveCharLogically(line, ch, dir) {
|
||
var target = skipExtendingChars(line.text, ch + dir, dir);
|
||
return target < 0 || target > line.text.length ? null : target
|
||
}
|
||
|
||
function moveLogically(line, start, dir) {
|
||
var ch = moveCharLogically(line, start.ch, dir);
|
||
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
|
||
}
|
||
|
||
function endOfLine(visually, cm, lineObj, lineNo, dir) {
|
||
if (visually) {
|
||
if (cm.doc.direction == "rtl") { dir = -dir; }
|
||
var order = getOrder(lineObj, cm.doc.direction);
|
||
if (order) {
|
||
var part = dir < 0 ? lst(order) : order[0];
|
||
var moveInStorageOrder = (dir < 0) == (part.level == 1);
|
||
var sticky = moveInStorageOrder ? "after" : "before";
|
||
var ch;
|
||
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
|
||
// it could be that the last bidi part is not on the last visual line,
|
||
// since visual lines contain content order-consecutive chunks.
|
||
// Thus, in rtl, we are looking for the first (content-order) character
|
||
// in the rtl chunk that is on the last line (that is, the same line
|
||
// as the last (content-order) character).
|
||
if (part.level > 0 || cm.doc.direction == "rtl") {
|
||
var prep = prepareMeasureForLine(cm, lineObj);
|
||
ch = dir < 0 ? lineObj.text.length - 1 : 0;
|
||
var targetTop = measureCharPrepared(cm, prep, ch).top;
|
||
ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
|
||
if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
|
||
} else { ch = dir < 0 ? part.to : part.from; }
|
||
return new Pos(lineNo, ch, sticky)
|
||
}
|
||
}
|
||
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
|
||
}
|
||
|
||
function moveVisually(cm, line, start, dir) {
|
||
var bidi = getOrder(line, cm.doc.direction);
|
||
if (!bidi) { return moveLogically(line, start, dir) }
|
||
if (start.ch >= line.text.length) {
|
||
start.ch = line.text.length;
|
||
start.sticky = "before";
|
||
} else if (start.ch <= 0) {
|
||
start.ch = 0;
|
||
start.sticky = "after";
|
||
}
|
||
var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
|
||
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
|
||
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
|
||
// nothing interesting happens.
|
||
return moveLogically(line, start, dir)
|
||
}
|
||
|
||
var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
|
||
var prep;
|
||
var getWrappedLineExtent = function (ch) {
|
||
if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
|
||
prep = prep || prepareMeasureForLine(cm, line);
|
||
return wrappedLineExtentChar(cm, line, prep, ch)
|
||
};
|
||
var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
|
||
|
||
if (cm.doc.direction == "rtl" || part.level == 1) {
|
||
var moveInStorageOrder = (part.level == 1) == (dir < 0);
|
||
var ch = mv(start, moveInStorageOrder ? 1 : -1);
|
||
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
|
||
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
|
||
var sticky = moveInStorageOrder ? "before" : "after";
|
||
return new Pos(start.line, ch, sticky)
|
||
}
|
||
}
|
||
|
||
// Case 3: Could not move within this bidi part in this visual line, so leave
|
||
// the current bidi part
|
||
|
||
var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
|
||
var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
|
||
? new Pos(start.line, mv(ch, 1), "before")
|
||
: new Pos(start.line, ch, "after"); };
|
||
|
||
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
|
||
var part = bidi[partPos];
|
||
var moveInStorageOrder = (dir > 0) == (part.level != 1);
|
||
var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
|
||
if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
|
||
ch = moveInStorageOrder ? part.from : mv(part.to, -1);
|
||
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
|
||
}
|
||
};
|
||
|
||
// Case 3a: Look for other bidi parts on the same visual line
|
||
var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
|
||
if (res) { return res }
|
||
|
||
// Case 3b: Look for other bidi parts on the next visual line
|
||
var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
|
||
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
|
||
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
|
||
if (res) { return res }
|
||
}
|
||
|
||
// Case 4: Nowhere to move
|
||
return null
|
||
}
|
||
|
||
// Commands are parameter-less actions that can be performed on an
|
||
// editor, mostly used for keybindings.
|
||
var commands = {
|
||
selectAll: selectAll,
|
||
singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
|
||
killLine: function (cm) { return deleteNearSelection(cm, function (range) {
|
||
if (range.empty()) {
|
||
var len = getLine(cm.doc, range.head.line).text.length;
|
||
if (range.head.ch == len && range.head.line < cm.lastLine())
|
||
{ return {from: range.head, to: Pos(range.head.line + 1, 0)} }
|
||
else
|
||
{ return {from: range.head, to: Pos(range.head.line, len)} }
|
||
} else {
|
||
return {from: range.from(), to: range.to()}
|
||
}
|
||
}); },
|
||
deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
|
||
from: Pos(range.from().line, 0),
|
||
to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
|
||
}); }); },
|
||
delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
|
||
from: Pos(range.from().line, 0), to: range.from()
|
||
}); }); },
|
||
delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
|
||
var top = cm.charCoords(range.head, "div").top + 5;
|
||
var leftPos = cm.coordsChar({left: 0, top: top}, "div");
|
||
return {from: leftPos, to: range.from()}
|
||
}); },
|
||
delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
|
||
var top = cm.charCoords(range.head, "div").top + 5;
|
||
var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
|
||
return {from: range.from(), to: rightPos }
|
||
}); },
|
||
undo: function (cm) { return cm.undo(); },
|
||
redo: function (cm) { return cm.redo(); },
|
||
undoSelection: function (cm) { return cm.undoSelection(); },
|
||
redoSelection: function (cm) { return cm.redoSelection(); },
|
||
goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
|
||
goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
|
||
goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
|
||
{origin: "+move", bias: 1}
|
||
); },
|
||
goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
|
||
{origin: "+move", bias: 1}
|
||
); },
|
||
goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
|
||
{origin: "+move", bias: -1}
|
||
); },
|
||
goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
|
||
var top = cm.cursorCoords(range.head, "div").top + 5;
|
||
return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
|
||
}, sel_move); },
|
||
goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
|
||
var top = cm.cursorCoords(range.head, "div").top + 5;
|
||
return cm.coordsChar({left: 0, top: top}, "div")
|
||
}, sel_move); },
|
||
goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
|
||
var top = cm.cursorCoords(range.head, "div").top + 5;
|
||
var pos = cm.coordsChar({left: 0, top: top}, "div");
|
||
if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
|
||
return pos
|
||
}, sel_move); },
|
||
goLineUp: function (cm) { return cm.moveV(-1, "line"); },
|
||
goLineDown: function (cm) { return cm.moveV(1, "line"); },
|
||
goPageUp: function (cm) { return cm.moveV(-1, "page"); },
|
||
goPageDown: function (cm) { return cm.moveV(1, "page"); },
|
||
goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
|
||
goCharRight: function (cm) { return cm.moveH(1, "char"); },
|
||
goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
|
||
goColumnRight: function (cm) { return cm.moveH(1, "column"); },
|
||
goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
|
||
goGroupRight: function (cm) { return cm.moveH(1, "group"); },
|
||
goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
|
||
goWordRight: function (cm) { return cm.moveH(1, "word"); },
|
||
delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
|
||
delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
|
||
delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
|
||
delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
|
||
delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
|
||
delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
|
||
indentAuto: function (cm) { return cm.indentSelection("smart"); },
|
||
indentMore: function (cm) { return cm.indentSelection("add"); },
|
||
indentLess: function (cm) { return cm.indentSelection("subtract"); },
|
||
insertTab: function (cm) { return cm.replaceSelection("\t"); },
|
||
insertSoftTab: function (cm) {
|
||
var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var pos = ranges[i].from();
|
||
var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
|
||
spaces.push(spaceStr(tabSize - col % tabSize));
|
||
}
|
||
cm.replaceSelections(spaces);
|
||
},
|
||
defaultTab: function (cm) {
|
||
if (cm.somethingSelected()) { cm.indentSelection("add"); }
|
||
else { cm.execCommand("insertTab"); }
|
||
},
|
||
// Swap the two chars left and right of each selection's head.
|
||
// Move cursor behind the two swapped characters afterwards.
|
||
//
|
||
// Doesn't consider line feeds a character.
|
||
// Doesn't scan more than one line above to find a character.
|
||
// Doesn't do anything on an empty line.
|
||
// Doesn't do anything with non-empty selections.
|
||
transposeChars: function (cm) { return runInOp(cm, function () {
|
||
var ranges = cm.listSelections(), newSel = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
if (!ranges[i].empty()) { continue }
|
||
var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
|
||
if (line) {
|
||
if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
|
||
if (cur.ch > 0) {
|
||
cur = new Pos(cur.line, cur.ch + 1);
|
||
cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
|
||
Pos(cur.line, cur.ch - 2), cur, "+transpose");
|
||
} else if (cur.line > cm.doc.first) {
|
||
var prev = getLine(cm.doc, cur.line - 1).text;
|
||
if (prev) {
|
||
cur = new Pos(cur.line, 1);
|
||
cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
|
||
prev.charAt(prev.length - 1),
|
||
Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
|
||
}
|
||
}
|
||
}
|
||
newSel.push(new Range(cur, cur));
|
||
}
|
||
cm.setSelections(newSel);
|
||
}); },
|
||
newlineAndIndent: function (cm) { return runInOp(cm, function () {
|
||
var sels = cm.listSelections();
|
||
for (var i = sels.length - 1; i >= 0; i--)
|
||
{ cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
|
||
sels = cm.listSelections();
|
||
for (var i$1 = 0; i$1 < sels.length; i$1++)
|
||
{ cm.indentLine(sels[i$1].from().line, null, true); }
|
||
ensureCursorVisible(cm);
|
||
}); },
|
||
openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
|
||
toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
|
||
};
|
||
|
||
|
||
function lineStart(cm, lineN) {
|
||
var line = getLine(cm.doc, lineN);
|
||
var visual = visualLine(line);
|
||
if (visual != line) { lineN = lineNo(visual); }
|
||
return endOfLine(true, cm, visual, lineN, 1)
|
||
}
|
||
function lineEnd(cm, lineN) {
|
||
var line = getLine(cm.doc, lineN);
|
||
var visual = visualLineEnd(line);
|
||
if (visual != line) { lineN = lineNo(visual); }
|
||
return endOfLine(true, cm, line, lineN, -1)
|
||
}
|
||
function lineStartSmart(cm, pos) {
|
||
var start = lineStart(cm, pos.line);
|
||
var line = getLine(cm.doc, start.line);
|
||
var order = getOrder(line, cm.doc.direction);
|
||
if (!order || order[0].level == 0) {
|
||
var firstNonWS = Math.max(start.ch, line.text.search(/\S/));
|
||
var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
|
||
return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
|
||
}
|
||
return start
|
||
}
|
||
|
||
// Run a handler that was bound to a key.
|
||
function doHandleBinding(cm, bound, dropShift) {
|
||
if (typeof bound == "string") {
|
||
bound = commands[bound];
|
||
if (!bound) { return false }
|
||
}
|
||
// Ensure previous input has been read, so that the handler sees a
|
||
// consistent view of the document
|
||
cm.display.input.ensurePolled();
|
||
var prevShift = cm.display.shift, done = false;
|
||
try {
|
||
if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
|
||
if (dropShift) { cm.display.shift = false; }
|
||
done = bound(cm) != Pass;
|
||
} finally {
|
||
cm.display.shift = prevShift;
|
||
cm.state.suppressEdits = false;
|
||
}
|
||
return done
|
||
}
|
||
|
||
function lookupKeyForEditor(cm, name, handle) {
|
||
for (var i = 0; i < cm.state.keyMaps.length; i++) {
|
||
var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
|
||
if (result) { return result }
|
||
}
|
||
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
|
||
|| lookupKey(name, cm.options.keyMap, handle, cm)
|
||
}
|
||
|
||
// Note that, despite the name, this function is also used to check
|
||
// for bound mouse clicks.
|
||
|
||
var stopSeq = new Delayed;
|
||
|
||
function dispatchKey(cm, name, e, handle) {
|
||
var seq = cm.state.keySeq;
|
||
if (seq) {
|
||
if (isModifierKey(name)) { return "handled" }
|
||
if (/\'$/.test(name))
|
||
{ cm.state.keySeq = null; }
|
||
else
|
||
{ stopSeq.set(50, function () {
|
||
if (cm.state.keySeq == seq) {
|
||
cm.state.keySeq = null;
|
||
cm.display.input.reset();
|
||
}
|
||
}); }
|
||
if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
|
||
}
|
||
return dispatchKeyInner(cm, name, e, handle)
|
||
}
|
||
|
||
function dispatchKeyInner(cm, name, e, handle) {
|
||
var result = lookupKeyForEditor(cm, name, handle);
|
||
|
||
if (result == "multi")
|
||
{ cm.state.keySeq = name; }
|
||
if (result == "handled")
|
||
{ signalLater(cm, "keyHandled", cm, name, e); }
|
||
|
||
if (result == "handled" || result == "multi") {
|
||
e_preventDefault(e);
|
||
restartBlink(cm);
|
||
}
|
||
|
||
return !!result
|
||
}
|
||
|
||
// Handle a key from the keydown event.
|
||
function handleKeyBinding(cm, e) {
|
||
var name = keyName(e, true);
|
||
if (!name) { return false }
|
||
|
||
if (e.shiftKey && !cm.state.keySeq) {
|
||
// First try to resolve full name (including 'Shift-'). Failing
|
||
// that, see if there is a cursor-motion command (starting with
|
||
// 'go') bound to the keyname without 'Shift-'.
|
||
return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
|
||
|| dispatchKey(cm, name, e, function (b) {
|
||
if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
|
||
{ return doHandleBinding(cm, b) }
|
||
})
|
||
} else {
|
||
return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
|
||
}
|
||
}
|
||
|
||
// Handle a key from the keypress event
|
||
function handleCharBinding(cm, e, ch) {
|
||
return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
|
||
}
|
||
|
||
var lastStoppedKey = null;
|
||
function onKeyDown(e) {
|
||
var cm = this;
|
||
if (e.target && e.target != cm.display.input.getField()) { return }
|
||
cm.curOp.focus = activeElt();
|
||
if (signalDOMEvent(cm, e)) { return }
|
||
// IE does strange things with escape.
|
||
if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
|
||
var code = e.keyCode;
|
||
cm.display.shift = code == 16 || e.shiftKey;
|
||
var handled = handleKeyBinding(cm, e);
|
||
if (presto) {
|
||
lastStoppedKey = handled ? code : null;
|
||
// Opera has no cut event... we try to at least catch the key combo
|
||
if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
|
||
{ cm.replaceSelection("", null, "cut"); }
|
||
}
|
||
if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand)
|
||
{ document.execCommand("cut"); }
|
||
|
||
// Turn mouse into crosshair when Alt is held on Mac.
|
||
if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
|
||
{ showCrossHair(cm); }
|
||
}
|
||
|
||
function showCrossHair(cm) {
|
||
var lineDiv = cm.display.lineDiv;
|
||
addClass(lineDiv, "CodeMirror-crosshair");
|
||
|
||
function up(e) {
|
||
if (e.keyCode == 18 || !e.altKey) {
|
||
rmClass(lineDiv, "CodeMirror-crosshair");
|
||
off(document, "keyup", up);
|
||
off(document, "mouseover", up);
|
||
}
|
||
}
|
||
on(document, "keyup", up);
|
||
on(document, "mouseover", up);
|
||
}
|
||
|
||
function onKeyUp(e) {
|
||
if (e.keyCode == 16) { this.doc.sel.shift = false; }
|
||
signalDOMEvent(this, e);
|
||
}
|
||
|
||
function onKeyPress(e) {
|
||
var cm = this;
|
||
if (e.target && e.target != cm.display.input.getField()) { return }
|
||
if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
|
||
var keyCode = e.keyCode, charCode = e.charCode;
|
||
if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
|
||
if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
|
||
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
|
||
// Some browsers fire keypress events for backspace
|
||
if (ch == "\x08") { return }
|
||
if (handleCharBinding(cm, e, ch)) { return }
|
||
cm.display.input.onKeyPress(e);
|
||
}
|
||
|
||
var DOUBLECLICK_DELAY = 400;
|
||
|
||
var PastClick = function(time, pos, button) {
|
||
this.time = time;
|
||
this.pos = pos;
|
||
this.button = button;
|
||
};
|
||
|
||
PastClick.prototype.compare = function (time, pos, button) {
|
||
return this.time + DOUBLECLICK_DELAY > time &&
|
||
cmp(pos, this.pos) == 0 && button == this.button
|
||
};
|
||
|
||
var lastClick, lastDoubleClick;
|
||
function clickRepeat(pos, button) {
|
||
var now = +new Date;
|
||
if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
|
||
lastClick = lastDoubleClick = null;
|
||
return "triple"
|
||
} else if (lastClick && lastClick.compare(now, pos, button)) {
|
||
lastDoubleClick = new PastClick(now, pos, button);
|
||
lastClick = null;
|
||
return "double"
|
||
} else {
|
||
lastClick = new PastClick(now, pos, button);
|
||
lastDoubleClick = null;
|
||
return "single"
|
||
}
|
||
}
|
||
|
||
// A mouse down can be a single click, double click, triple click,
|
||
// start of selection drag, start of text drag, new cursor
|
||
// (ctrl-click), rectangle drag (alt-drag), or xwin
|
||
// middle-click-paste. Or it might be a click on something we should
|
||
// not interfere with, such as a scrollbar or widget.
|
||
function onMouseDown(e) {
|
||
var cm = this, display = cm.display;
|
||
if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
|
||
display.input.ensurePolled();
|
||
display.shift = e.shiftKey;
|
||
|
||
if (eventInWidget(display, e)) {
|
||
if (!webkit) {
|
||
// Briefly turn off draggability, to allow widgets to do
|
||
// normal dragging things.
|
||
display.scroller.draggable = false;
|
||
setTimeout(function () { return display.scroller.draggable = true; }, 100);
|
||
}
|
||
return
|
||
}
|
||
if (clickInGutter(cm, e)) { return }
|
||
var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
|
||
window.focus();
|
||
|
||
// #3261: make sure, that we're not starting a second selection
|
||
if (button == 1 && cm.state.selectingText)
|
||
{ cm.state.selectingText(e); }
|
||
|
||
if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
|
||
|
||
if (button == 1) {
|
||
if (pos) { leftButtonDown(cm, pos, repeat, e); }
|
||
else if (e_target(e) == display.scroller) { e_preventDefault(e); }
|
||
} else if (button == 2) {
|
||
if (pos) { extendSelection(cm.doc, pos); }
|
||
setTimeout(function () { return display.input.focus(); }, 20);
|
||
} else if (button == 3) {
|
||
if (captureRightClick) { cm.display.input.onContextMenu(e); }
|
||
else { delayBlurEvent(cm); }
|
||
}
|
||
}
|
||
|
||
function handleMappedButton(cm, button, pos, repeat, event) {
|
||
var name = "Click";
|
||
if (repeat == "double") { name = "Double" + name; }
|
||
else if (repeat == "triple") { name = "Triple" + name; }
|
||
name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
|
||
|
||
return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
|
||
if (typeof bound == "string") { bound = commands[bound]; }
|
||
if (!bound) { return false }
|
||
var done = false;
|
||
try {
|
||
if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
|
||
done = bound(cm, pos) != Pass;
|
||
} finally {
|
||
cm.state.suppressEdits = false;
|
||
}
|
||
return done
|
||
})
|
||
}
|
||
|
||
function configureMouse(cm, repeat, event) {
|
||
var option = cm.getOption("configureMouse");
|
||
var value = option ? option(cm, repeat, event) : {};
|
||
if (value.unit == null) {
|
||
var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
|
||
value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
|
||
}
|
||
if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
|
||
if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
|
||
if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
|
||
return value
|
||
}
|
||
|
||
function leftButtonDown(cm, pos, repeat, event) {
|
||
if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
|
||
else { cm.curOp.focus = activeElt(); }
|
||
|
||
var behavior = configureMouse(cm, repeat, event);
|
||
|
||
var sel = cm.doc.sel, contained;
|
||
if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
|
||
repeat == "single" && (contained = sel.contains(pos)) > -1 &&
|
||
(cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
|
||
(cmp(contained.to(), pos) > 0 || pos.xRel < 0))
|
||
{ leftButtonStartDrag(cm, event, pos, behavior); }
|
||
else
|
||
{ leftButtonSelect(cm, event, pos, behavior); }
|
||
}
|
||
|
||
// Start a text drag. When it ends, see if any dragging actually
|
||
// happen, and treat as a click if it didn't.
|
||
function leftButtonStartDrag(cm, event, pos, behavior) {
|
||
var display = cm.display, moved = false;
|
||
var dragEnd = operation(cm, function (e) {
|
||
if (webkit) { display.scroller.draggable = false; }
|
||
cm.state.draggingText = false;
|
||
off(display.wrapper.ownerDocument, "mouseup", dragEnd);
|
||
off(display.wrapper.ownerDocument, "mousemove", mouseMove);
|
||
off(display.scroller, "dragstart", dragStart);
|
||
off(display.scroller, "drop", dragEnd);
|
||
if (!moved) {
|
||
e_preventDefault(e);
|
||
if (!behavior.addNew)
|
||
{ extendSelection(cm.doc, pos, null, null, behavior.extend); }
|
||
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
|
||
if ((webkit && !safari) || ie && ie_version == 9)
|
||
{ setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); }
|
||
else
|
||
{ display.input.focus(); }
|
||
}
|
||
});
|
||
var mouseMove = function(e2) {
|
||
moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
|
||
};
|
||
var dragStart = function () { return moved = true; };
|
||
// Let the drag handler handle this.
|
||
if (webkit) { display.scroller.draggable = true; }
|
||
cm.state.draggingText = dragEnd;
|
||
dragEnd.copy = !behavior.moveOnDrag;
|
||
// IE's approach to draggable
|
||
if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
|
||
on(display.wrapper.ownerDocument, "mouseup", dragEnd);
|
||
on(display.wrapper.ownerDocument, "mousemove", mouseMove);
|
||
on(display.scroller, "dragstart", dragStart);
|
||
on(display.scroller, "drop", dragEnd);
|
||
|
||
delayBlurEvent(cm);
|
||
setTimeout(function () { return display.input.focus(); }, 20);
|
||
}
|
||
|
||
function rangeForUnit(cm, pos, unit) {
|
||
if (unit == "char") { return new Range(pos, pos) }
|
||
if (unit == "word") { return cm.findWordAt(pos) }
|
||
if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
|
||
var result = unit(cm, pos);
|
||
return new Range(result.from, result.to)
|
||
}
|
||
|
||
// Normal selection, as opposed to text dragging.
|
||
function leftButtonSelect(cm, event, start, behavior) {
|
||
var display = cm.display, doc = cm.doc;
|
||
e_preventDefault(event);
|
||
|
||
var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
|
||
if (behavior.addNew && !behavior.extend) {
|
||
ourIndex = doc.sel.contains(start);
|
||
if (ourIndex > -1)
|
||
{ ourRange = ranges[ourIndex]; }
|
||
else
|
||
{ ourRange = new Range(start, start); }
|
||
} else {
|
||
ourRange = doc.sel.primary();
|
||
ourIndex = doc.sel.primIndex;
|
||
}
|
||
|
||
if (behavior.unit == "rectangle") {
|
||
if (!behavior.addNew) { ourRange = new Range(start, start); }
|
||
start = posFromMouse(cm, event, true, true);
|
||
ourIndex = -1;
|
||
} else {
|
||
var range = rangeForUnit(cm, start, behavior.unit);
|
||
if (behavior.extend)
|
||
{ ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); }
|
||
else
|
||
{ ourRange = range; }
|
||
}
|
||
|
||
if (!behavior.addNew) {
|
||
ourIndex = 0;
|
||
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
|
||
startSel = doc.sel;
|
||
} else if (ourIndex == -1) {
|
||
ourIndex = ranges.length;
|
||
setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex),
|
||
{scroll: false, origin: "*mouse"});
|
||
} else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
|
||
setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
|
||
{scroll: false, origin: "*mouse"});
|
||
startSel = doc.sel;
|
||
} else {
|
||
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
|
||
}
|
||
|
||
var lastPos = start;
|
||
function extendTo(pos) {
|
||
if (cmp(lastPos, pos) == 0) { return }
|
||
lastPos = pos;
|
||
|
||
if (behavior.unit == "rectangle") {
|
||
var ranges = [], tabSize = cm.options.tabSize;
|
||
var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
|
||
var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
|
||
var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
|
||
for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
|
||
line <= end; line++) {
|
||
var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
|
||
if (left == right)
|
||
{ ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
|
||
else if (text.length > leftPos)
|
||
{ ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
|
||
}
|
||
if (!ranges.length) { ranges.push(new Range(start, start)); }
|
||
setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
|
||
{origin: "*mouse", scroll: false});
|
||
cm.scrollIntoView(pos);
|
||
} else {
|
||
var oldRange = ourRange;
|
||
var range = rangeForUnit(cm, pos, behavior.unit);
|
||
var anchor = oldRange.anchor, head;
|
||
if (cmp(range.anchor, anchor) > 0) {
|
||
head = range.head;
|
||
anchor = minPos(oldRange.from(), range.anchor);
|
||
} else {
|
||
head = range.anchor;
|
||
anchor = maxPos(oldRange.to(), range.head);
|
||
}
|
||
var ranges$1 = startSel.ranges.slice(0);
|
||
ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
|
||
setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse);
|
||
}
|
||
}
|
||
|
||
var editorSize = display.wrapper.getBoundingClientRect();
|
||
// Used to ensure timeout re-tries don't fire when another extend
|
||
// happened in the meantime (clearTimeout isn't reliable -- at
|
||
// least on Chrome, the timeouts still happen even when cleared,
|
||
// if the clear happens after their scheduled firing time).
|
||
var counter = 0;
|
||
|
||
function extend(e) {
|
||
var curCount = ++counter;
|
||
var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
|
||
if (!cur) { return }
|
||
if (cmp(cur, lastPos) != 0) {
|
||
cm.curOp.focus = activeElt();
|
||
extendTo(cur);
|
||
var visible = visibleLines(display, doc);
|
||
if (cur.line >= visible.to || cur.line < visible.from)
|
||
{ setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
|
||
} else {
|
||
var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
|
||
if (outside) { setTimeout(operation(cm, function () {
|
||
if (counter != curCount) { return }
|
||
display.scroller.scrollTop += outside;
|
||
extend(e);
|
||
}), 50); }
|
||
}
|
||
}
|
||
|
||
function done(e) {
|
||
cm.state.selectingText = false;
|
||
counter = Infinity;
|
||
// If e is null or undefined we interpret this as someone trying
|
||
// to explicitly cancel the selection rather than the user
|
||
// letting go of the mouse button.
|
||
if (e) {
|
||
e_preventDefault(e);
|
||
display.input.focus();
|
||
}
|
||
off(display.wrapper.ownerDocument, "mousemove", move);
|
||
off(display.wrapper.ownerDocument, "mouseup", up);
|
||
doc.history.lastSelOrigin = null;
|
||
}
|
||
|
||
var move = operation(cm, function (e) {
|
||
if (e.buttons === 0 || !e_button(e)) { done(e); }
|
||
else { extend(e); }
|
||
});
|
||
var up = operation(cm, done);
|
||
cm.state.selectingText = up;
|
||
on(display.wrapper.ownerDocument, "mousemove", move);
|
||
on(display.wrapper.ownerDocument, "mouseup", up);
|
||
}
|
||
|
||
// Used when mouse-selecting to adjust the anchor to the proper side
|
||
// of a bidi jump depending on the visual position of the head.
|
||
function bidiSimplify(cm, range) {
|
||
var anchor = range.anchor;
|
||
var head = range.head;
|
||
var anchorLine = getLine(cm.doc, anchor.line);
|
||
if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }
|
||
var order = getOrder(anchorLine);
|
||
if (!order) { return range }
|
||
var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
|
||
if (part.from != anchor.ch && part.to != anchor.ch) { return range }
|
||
var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
|
||
if (boundary == 0 || boundary == order.length) { return range }
|
||
|
||
// Compute the relative visual position of the head compared to the
|
||
// anchor (<0 is to the left, >0 to the right)
|
||
var leftSide;
|
||
if (head.line != anchor.line) {
|
||
leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
|
||
} else {
|
||
var headIndex = getBidiPartAt(order, head.ch, head.sticky);
|
||
var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
|
||
if (headIndex == boundary - 1 || headIndex == boundary)
|
||
{ leftSide = dir < 0; }
|
||
else
|
||
{ leftSide = dir > 0; }
|
||
}
|
||
|
||
var usePart = order[boundary + (leftSide ? -1 : 0)];
|
||
var from = leftSide == (usePart.level == 1);
|
||
var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
|
||
return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
|
||
}
|
||
|
||
|
||
// Determines whether an event happened in the gutter, and fires the
|
||
// handlers for the corresponding event.
|
||
function gutterEvent(cm, e, type, prevent) {
|
||
var mX, mY;
|
||
if (e.touches) {
|
||
mX = e.touches[0].clientX;
|
||
mY = e.touches[0].clientY;
|
||
} else {
|
||
try { mX = e.clientX; mY = e.clientY; }
|
||
catch(e$1) { return false }
|
||
}
|
||
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
|
||
if (prevent) { e_preventDefault(e); }
|
||
|
||
var display = cm.display;
|
||
var lineBox = display.lineDiv.getBoundingClientRect();
|
||
|
||
if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
|
||
mY -= lineBox.top - display.viewOffset;
|
||
|
||
for (var i = 0; i < cm.display.gutterSpecs.length; ++i) {
|
||
var g = display.gutters.childNodes[i];
|
||
if (g && g.getBoundingClientRect().right >= mX) {
|
||
var line = lineAtHeight(cm.doc, mY);
|
||
var gutter = cm.display.gutterSpecs[i];
|
||
signal(cm, type, cm, line, gutter.className, e);
|
||
return e_defaultPrevented(e)
|
||
}
|
||
}
|
||
}
|
||
|
||
function clickInGutter(cm, e) {
|
||
return gutterEvent(cm, e, "gutterClick", true)
|
||
}
|
||
|
||
// CONTEXT MENU HANDLING
|
||
|
||
// To make the context menu work, we need to briefly unhide the
|
||
// textarea (making it as unobtrusive as possible) to let the
|
||
// right-click take effect on it.
|
||
function onContextMenu(cm, e) {
|
||
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
|
||
if (signalDOMEvent(cm, e, "contextmenu")) { return }
|
||
if (!captureRightClick) { cm.display.input.onContextMenu(e); }
|
||
}
|
||
|
||
function contextMenuInGutter(cm, e) {
|
||
if (!hasHandler(cm, "gutterContextMenu")) { return false }
|
||
return gutterEvent(cm, e, "gutterContextMenu", false)
|
||
}
|
||
|
||
function themeChanged(cm) {
|
||
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
|
||
cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
|
||
clearCaches(cm);
|
||
}
|
||
|
||
var Init = {toString: function(){return "CodeMirror.Init"}};
|
||
|
||
var defaults = {};
|
||
var optionHandlers = {};
|
||
|
||
function defineOptions(CodeMirror) {
|
||
var optionHandlers = CodeMirror.optionHandlers;
|
||
|
||
function option(name, deflt, handle, notOnInit) {
|
||
CodeMirror.defaults[name] = deflt;
|
||
if (handle) { optionHandlers[name] =
|
||
notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
|
||
}
|
||
|
||
CodeMirror.defineOption = option;
|
||
|
||
// Passed to option handlers when there is no old value.
|
||
CodeMirror.Init = Init;
|
||
|
||
// These two are, on init, called from the constructor because they
|
||
// have to be initialized before the editor can start at all.
|
||
option("value", "", function (cm, val) { return cm.setValue(val); }, true);
|
||
option("mode", null, function (cm, val) {
|
||
cm.doc.modeOption = val;
|
||
loadMode(cm);
|
||
}, true);
|
||
|
||
option("indentUnit", 2, loadMode, true);
|
||
option("indentWithTabs", false);
|
||
option("smartIndent", true);
|
||
option("tabSize", 4, function (cm) {
|
||
resetModeState(cm);
|
||
clearCaches(cm);
|
||
regChange(cm);
|
||
}, true);
|
||
|
||
option("lineSeparator", null, function (cm, val) {
|
||
cm.doc.lineSep = val;
|
||
if (!val) { return }
|
||
var newBreaks = [], lineNo = cm.doc.first;
|
||
cm.doc.iter(function (line) {
|
||
for (var pos = 0;;) {
|
||
var found = line.text.indexOf(val, pos);
|
||
if (found == -1) { break }
|
||
pos = found + val.length;
|
||
newBreaks.push(Pos(lineNo, found));
|
||
}
|
||
lineNo++;
|
||
});
|
||
for (var i = newBreaks.length - 1; i >= 0; i--)
|
||
{ replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
|
||
});
|
||
option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200c\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) {
|
||
cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
|
||
if (old != Init) { cm.refresh(); }
|
||
});
|
||
option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
|
||
option("electricChars", true);
|
||
option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
|
||
throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
|
||
}, true);
|
||
option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
|
||
option("autocorrect", false, function (cm, val) { return cm.getInputField().autocorrect = val; }, true);
|
||
option("autocapitalize", false, function (cm, val) { return cm.getInputField().autocapitalize = val; }, true);
|
||
option("rtlMoveVisually", !windows);
|
||
option("wholeLineUpdateBefore", true);
|
||
|
||
option("theme", "default", function (cm) {
|
||
themeChanged(cm);
|
||
updateGutters(cm);
|
||
}, true);
|
||
option("keyMap", "default", function (cm, val, old) {
|
||
var next = getKeyMap(val);
|
||
var prev = old != Init && getKeyMap(old);
|
||
if (prev && prev.detach) { prev.detach(cm, next); }
|
||
if (next.attach) { next.attach(cm, prev || null); }
|
||
});
|
||
option("extraKeys", null);
|
||
option("configureMouse", null);
|
||
|
||
option("lineWrapping", false, wrappingChanged, true);
|
||
option("gutters", [], function (cm, val) {
|
||
cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers);
|
||
updateGutters(cm);
|
||
}, true);
|
||
option("fixedGutter", true, function (cm, val) {
|
||
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
|
||
cm.refresh();
|
||
}, true);
|
||
option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
|
||
option("scrollbarStyle", "native", function (cm) {
|
||
initScrollbars(cm);
|
||
updateScrollbars(cm);
|
||
cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
|
||
cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
|
||
}, true);
|
||
option("lineNumbers", false, function (cm, val) {
|
||
cm.display.gutterSpecs = getGutters(cm.options.gutters, val);
|
||
updateGutters(cm);
|
||
}, true);
|
||
option("firstLineNumber", 1, updateGutters, true);
|
||
option("lineNumberFormatter", function (integer) { return integer; }, updateGutters, true);
|
||
option("showCursorWhenSelecting", false, updateSelection, true);
|
||
|
||
option("resetSelectionOnContextMenu", true);
|
||
option("lineWiseCopyCut", true);
|
||
option("pasteLinesPerSelection", true);
|
||
option("selectionsMayTouch", false);
|
||
|
||
option("readOnly", false, function (cm, val) {
|
||
if (val == "nocursor") {
|
||
onBlur(cm);
|
||
cm.display.input.blur();
|
||
}
|
||
cm.display.input.readOnlyChanged(val);
|
||
});
|
||
|
||
option("screenReaderLabel", null, function (cm, val) {
|
||
val = (val === '') ? null : val;
|
||
cm.display.input.screenReaderLabelChanged(val);
|
||
});
|
||
|
||
option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
|
||
option("dragDrop", true, dragDropChanged);
|
||
option("allowDropFileTypes", null);
|
||
|
||
option("cursorBlinkRate", 530);
|
||
option("cursorScrollMargin", 0);
|
||
option("cursorHeight", 1, updateSelection, true);
|
||
option("singleCursorHeightPerLine", true, updateSelection, true);
|
||
option("workTime", 100);
|
||
option("workDelay", 100);
|
||
option("flattenSpans", true, resetModeState, true);
|
||
option("addModeClass", false, resetModeState, true);
|
||
option("pollInterval", 100);
|
||
option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
|
||
option("historyEventDelay", 1250);
|
||
option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
|
||
option("maxHighlightLength", 10000, resetModeState, true);
|
||
option("moveInputWithCursor", true, function (cm, val) {
|
||
if (!val) { cm.display.input.resetPosition(); }
|
||
});
|
||
|
||
option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
|
||
option("autofocus", null);
|
||
option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
|
||
option("phrases", null);
|
||
}
|
||
|
||
function dragDropChanged(cm, value, old) {
|
||
var wasOn = old && old != Init;
|
||
if (!value != !wasOn) {
|
||
var funcs = cm.display.dragFunctions;
|
||
var toggle = value ? on : off;
|
||
toggle(cm.display.scroller, "dragstart", funcs.start);
|
||
toggle(cm.display.scroller, "dragenter", funcs.enter);
|
||
toggle(cm.display.scroller, "dragover", funcs.over);
|
||
toggle(cm.display.scroller, "dragleave", funcs.leave);
|
||
toggle(cm.display.scroller, "drop", funcs.drop);
|
||
}
|
||
}
|
||
|
||
function wrappingChanged(cm) {
|
||
if (cm.options.lineWrapping) {
|
||
addClass(cm.display.wrapper, "CodeMirror-wrap");
|
||
cm.display.sizer.style.minWidth = "";
|
||
cm.display.sizerWidth = null;
|
||
} else {
|
||
rmClass(cm.display.wrapper, "CodeMirror-wrap");
|
||
findMaxLine(cm);
|
||
}
|
||
estimateLineHeights(cm);
|
||
regChange(cm);
|
||
clearCaches(cm);
|
||
setTimeout(function () { return updateScrollbars(cm); }, 100);
|
||
}
|
||
|
||
// A CodeMirror instance represents an editor. This is the object
|
||
// that user code is usually dealing with.
|
||
|
||
function CodeMirror(place, options) {
|
||
var this$1 = this;
|
||
|
||
if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }
|
||
|
||
this.options = options = options ? copyObj(options) : {};
|
||
// Determine effective options based on given values and defaults.
|
||
copyObj(defaults, options, false);
|
||
|
||
var doc = options.value;
|
||
if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
|
||
else if (options.mode) { doc.modeOption = options.mode; }
|
||
this.doc = doc;
|
||
|
||
var input = new CodeMirror.inputStyles[options.inputStyle](this);
|
||
var display = this.display = new Display(place, doc, input, options);
|
||
display.wrapper.CodeMirror = this;
|
||
themeChanged(this);
|
||
if (options.lineWrapping)
|
||
{ this.display.wrapper.className += " CodeMirror-wrap"; }
|
||
initScrollbars(this);
|
||
|
||
this.state = {
|
||
keyMaps: [], // stores maps added by addKeyMap
|
||
overlays: [], // highlighting overlays, as added by addOverlay
|
||
modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
|
||
overwrite: false,
|
||
delayingBlurEvent: false,
|
||
focused: false,
|
||
suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
|
||
pasteIncoming: -1, cutIncoming: -1, // help recognize paste/cut edits in input.poll
|
||
selectingText: false,
|
||
draggingText: false,
|
||
highlight: new Delayed(), // stores highlight worker timeout
|
||
keySeq: null, // Unfinished key sequence
|
||
specialChars: null
|
||
};
|
||
|
||
if (options.autofocus && !mobile) { display.input.focus(); }
|
||
|
||
// Override magic textarea content restore that IE sometimes does
|
||
// on our hidden textarea on reload
|
||
if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
|
||
|
||
registerEventHandlers(this);
|
||
ensureGlobalHandlers();
|
||
|
||
startOperation(this);
|
||
this.curOp.forceUpdate = true;
|
||
attachDoc(this, doc);
|
||
|
||
if ((options.autofocus && !mobile) || this.hasFocus())
|
||
{ setTimeout(bind(onFocus, this), 20); }
|
||
else
|
||
{ onBlur(this); }
|
||
|
||
for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
|
||
{ optionHandlers[opt](this, options[opt], Init); } }
|
||
maybeUpdateLineNumberWidth(this);
|
||
if (options.finishInit) { options.finishInit(this); }
|
||
for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); }
|
||
endOperation(this);
|
||
// Suppress optimizelegibility in Webkit, since it breaks text
|
||
// measuring on line wrapping boundaries.
|
||
if (webkit && options.lineWrapping &&
|
||
getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
|
||
{ display.lineDiv.style.textRendering = "auto"; }
|
||
}
|
||
|
||
// The default configuration options.
|
||
CodeMirror.defaults = defaults;
|
||
// Functions to run when options are changed.
|
||
CodeMirror.optionHandlers = optionHandlers;
|
||
|
||
// Attach the necessary event handlers when initializing the editor
|
||
function registerEventHandlers(cm) {
|
||
var d = cm.display;
|
||
on(d.scroller, "mousedown", operation(cm, onMouseDown));
|
||
// Older IE's will not fire a second mousedown for a double click
|
||
if (ie && ie_version < 11)
|
||
{ on(d.scroller, "dblclick", operation(cm, function (e) {
|
||
if (signalDOMEvent(cm, e)) { return }
|
||
var pos = posFromMouse(cm, e);
|
||
if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
|
||
e_preventDefault(e);
|
||
var word = cm.findWordAt(pos);
|
||
extendSelection(cm.doc, word.anchor, word.head);
|
||
})); }
|
||
else
|
||
{ on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
|
||
// Some browsers fire contextmenu *after* opening the menu, at
|
||
// which point we can't mess with it anymore. Context menu is
|
||
// handled in onMouseDown for these browsers.
|
||
on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); });
|
||
on(d.input.getField(), "contextmenu", function (e) {
|
||
if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); }
|
||
});
|
||
|
||
// Used to suppress mouse event handling when a touch happens
|
||
var touchFinished, prevTouch = {end: 0};
|
||
function finishTouch() {
|
||
if (d.activeTouch) {
|
||
touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
|
||
prevTouch = d.activeTouch;
|
||
prevTouch.end = +new Date;
|
||
}
|
||
}
|
||
function isMouseLikeTouchEvent(e) {
|
||
if (e.touches.length != 1) { return false }
|
||
var touch = e.touches[0];
|
||
return touch.radiusX <= 1 && touch.radiusY <= 1
|
||
}
|
||
function farAway(touch, other) {
|
||
if (other.left == null) { return true }
|
||
var dx = other.left - touch.left, dy = other.top - touch.top;
|
||
return dx * dx + dy * dy > 20 * 20
|
||
}
|
||
on(d.scroller, "touchstart", function (e) {
|
||
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
|
||
d.input.ensurePolled();
|
||
clearTimeout(touchFinished);
|
||
var now = +new Date;
|
||
d.activeTouch = {start: now, moved: false,
|
||
prev: now - prevTouch.end <= 300 ? prevTouch : null};
|
||
if (e.touches.length == 1) {
|
||
d.activeTouch.left = e.touches[0].pageX;
|
||
d.activeTouch.top = e.touches[0].pageY;
|
||
}
|
||
}
|
||
});
|
||
on(d.scroller, "touchmove", function () {
|
||
if (d.activeTouch) { d.activeTouch.moved = true; }
|
||
});
|
||
on(d.scroller, "touchend", function (e) {
|
||
var touch = d.activeTouch;
|
||
if (touch && !eventInWidget(d, e) && touch.left != null &&
|
||
!touch.moved && new Date - touch.start < 300) {
|
||
var pos = cm.coordsChar(d.activeTouch, "page"), range;
|
||
if (!touch.prev || farAway(touch, touch.prev)) // Single tap
|
||
{ range = new Range(pos, pos); }
|
||
else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
|
||
{ range = cm.findWordAt(pos); }
|
||
else // Triple tap
|
||
{ range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
|
||
cm.setSelection(range.anchor, range.head);
|
||
cm.focus();
|
||
e_preventDefault(e);
|
||
}
|
||
finishTouch();
|
||
});
|
||
on(d.scroller, "touchcancel", finishTouch);
|
||
|
||
// Sync scrolling between fake scrollbars and real scrollable
|
||
// area, ensure viewport is updated when scrolling.
|
||
on(d.scroller, "scroll", function () {
|
||
if (d.scroller.clientHeight) {
|
||
updateScrollTop(cm, d.scroller.scrollTop);
|
||
setScrollLeft(cm, d.scroller.scrollLeft, true);
|
||
signal(cm, "scroll", cm);
|
||
}
|
||
});
|
||
|
||
// Listen to wheel events in order to try and update the viewport on time.
|
||
on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
|
||
on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
|
||
|
||
// Prevent wrapper from ever scrolling
|
||
on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
|
||
|
||
d.dragFunctions = {
|
||
enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
|
||
over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
|
||
start: function (e) { return onDragStart(cm, e); },
|
||
drop: operation(cm, onDrop),
|
||
leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
|
||
};
|
||
|
||
var inp = d.input.getField();
|
||
on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
|
||
on(inp, "keydown", operation(cm, onKeyDown));
|
||
on(inp, "keypress", operation(cm, onKeyPress));
|
||
on(inp, "focus", function (e) { return onFocus(cm, e); });
|
||
on(inp, "blur", function (e) { return onBlur(cm, e); });
|
||
}
|
||
|
||
var initHooks = [];
|
||
CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };
|
||
|
||
// Indent the given line. The how parameter can be "smart",
|
||
// "add"/null, "subtract", or "prev". When aggressive is false
|
||
// (typically set to true for forced single-line indents), empty
|
||
// lines are not indented, and places where the mode returns Pass
|
||
// are left alone.
|
||
function indentLine(cm, n, how, aggressive) {
|
||
var doc = cm.doc, state;
|
||
if (how == null) { how = "add"; }
|
||
if (how == "smart") {
|
||
// Fall back to "prev" when the mode doesn't have an indentation
|
||
// method.
|
||
if (!doc.mode.indent) { how = "prev"; }
|
||
else { state = getContextBefore(cm, n).state; }
|
||
}
|
||
|
||
var tabSize = cm.options.tabSize;
|
||
var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
|
||
if (line.stateAfter) { line.stateAfter = null; }
|
||
var curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
||
if (!aggressive && !/\S/.test(line.text)) {
|
||
indentation = 0;
|
||
how = "not";
|
||
} else if (how == "smart") {
|
||
indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
||
if (indentation == Pass || indentation > 150) {
|
||
if (!aggressive) { return }
|
||
how = "prev";
|
||
}
|
||
}
|
||
if (how == "prev") {
|
||
if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
|
||
else { indentation = 0; }
|
||
} else if (how == "add") {
|
||
indentation = curSpace + cm.options.indentUnit;
|
||
} else if (how == "subtract") {
|
||
indentation = curSpace - cm.options.indentUnit;
|
||
} else if (typeof how == "number") {
|
||
indentation = curSpace + how;
|
||
}
|
||
indentation = Math.max(0, indentation);
|
||
|
||
var indentString = "", pos = 0;
|
||
if (cm.options.indentWithTabs)
|
||
{ for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
|
||
if (pos < indentation) { indentString += spaceStr(indentation - pos); }
|
||
|
||
if (indentString != curSpaceString) {
|
||
replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
|
||
line.stateAfter = null;
|
||
return true
|
||
} else {
|
||
// Ensure that, if the cursor was in the whitespace at the start
|
||
// of the line, it is moved to the end of that space.
|
||
for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
|
||
var range = doc.sel.ranges[i$1];
|
||
if (range.head.line == n && range.head.ch < curSpaceString.length) {
|
||
var pos$1 = Pos(n, curSpaceString.length);
|
||
replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// This will be set to a {lineWise: bool, text: [string]} object, so
|
||
// that, when pasting, we know what kind of selections the copied
|
||
// text was made out of.
|
||
var lastCopied = null;
|
||
|
||
function setLastCopied(newLastCopied) {
|
||
lastCopied = newLastCopied;
|
||
}
|
||
|
||
function applyTextInput(cm, inserted, deleted, sel, origin) {
|
||
var doc = cm.doc;
|
||
cm.display.shift = false;
|
||
if (!sel) { sel = doc.sel; }
|
||
|
||
var recent = +new Date - 200;
|
||
var paste = origin == "paste" || cm.state.pasteIncoming > recent;
|
||
var textLines = splitLinesAuto(inserted), multiPaste = null;
|
||
// When pasting N lines into N selections, insert one line per selection
|
||
if (paste && sel.ranges.length > 1) {
|
||
if (lastCopied && lastCopied.text.join("\n") == inserted) {
|
||
if (sel.ranges.length % lastCopied.text.length == 0) {
|
||
multiPaste = [];
|
||
for (var i = 0; i < lastCopied.text.length; i++)
|
||
{ multiPaste.push(doc.splitLines(lastCopied.text[i])); }
|
||
}
|
||
} else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
|
||
multiPaste = map(textLines, function (l) { return [l]; });
|
||
}
|
||
}
|
||
|
||
var updateInput = cm.curOp.updateInput;
|
||
// Normal behavior is to insert the new text into every selection
|
||
for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
|
||
var range = sel.ranges[i$1];
|
||
var from = range.from(), to = range.to();
|
||
if (range.empty()) {
|
||
if (deleted && deleted > 0) // Handle deletion
|
||
{ from = Pos(from.line, from.ch - deleted); }
|
||
else if (cm.state.overwrite && !paste) // Handle overwrite
|
||
{ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
|
||
else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n"))
|
||
{ from = to = Pos(from.line, 0); }
|
||
}
|
||
var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
|
||
origin: origin || (paste ? "paste" : cm.state.cutIncoming > recent ? "cut" : "+input")};
|
||
makeChange(cm.doc, changeEvent);
|
||
signalLater(cm, "inputRead", cm, changeEvent);
|
||
}
|
||
if (inserted && !paste)
|
||
{ triggerElectric(cm, inserted); }
|
||
|
||
ensureCursorVisible(cm);
|
||
if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; }
|
||
cm.curOp.typing = true;
|
||
cm.state.pasteIncoming = cm.state.cutIncoming = -1;
|
||
}
|
||
|
||
function handlePaste(e, cm) {
|
||
var pasted = e.clipboardData && e.clipboardData.getData("Text");
|
||
if (pasted) {
|
||
e.preventDefault();
|
||
if (!cm.isReadOnly() && !cm.options.disableInput)
|
||
{ runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
|
||
return true
|
||
}
|
||
}
|
||
|
||
function triggerElectric(cm, inserted) {
|
||
// When an 'electric' character is inserted, immediately trigger a reindent
|
||
if (!cm.options.electricChars || !cm.options.smartIndent) { return }
|
||
var sel = cm.doc.sel;
|
||
|
||
for (var i = sel.ranges.length - 1; i >= 0; i--) {
|
||
var range = sel.ranges[i];
|
||
if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue }
|
||
var mode = cm.getModeAt(range.head);
|
||
var indented = false;
|
||
if (mode.electricChars) {
|
||
for (var j = 0; j < mode.electricChars.length; j++)
|
||
{ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
|
||
indented = indentLine(cm, range.head.line, "smart");
|
||
break
|
||
} }
|
||
} else if (mode.electricInput) {
|
||
if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
|
||
{ indented = indentLine(cm, range.head.line, "smart"); }
|
||
}
|
||
if (indented) { signalLater(cm, "electricInput", cm, range.head.line); }
|
||
}
|
||
}
|
||
|
||
function copyableRanges(cm) {
|
||
var text = [], ranges = [];
|
||
for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
|
||
var line = cm.doc.sel.ranges[i].head.line;
|
||
var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
|
||
ranges.push(lineRange);
|
||
text.push(cm.getRange(lineRange.anchor, lineRange.head));
|
||
}
|
||
return {text: text, ranges: ranges}
|
||
}
|
||
|
||
function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) {
|
||
field.setAttribute("autocorrect", autocorrect ? "" : "off");
|
||
field.setAttribute("autocapitalize", autocapitalize ? "" : "off");
|
||
field.setAttribute("spellcheck", !!spellcheck);
|
||
}
|
||
|
||
function hiddenTextarea() {
|
||
var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
|
||
var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
|
||
// The textarea is kept positioned near the cursor to prevent the
|
||
// fact that it'll be scrolled into view on input from scrolling
|
||
// our fake cursor out of view. On webkit, when wrap=off, paste is
|
||
// very slow. So make the area wide instead.
|
||
if (webkit) { te.style.width = "1000px"; }
|
||
else { te.setAttribute("wrap", "off"); }
|
||
// If border: 0; -- iOS fails to open keyboard (issue #1287)
|
||
if (ios) { te.style.border = "1px solid black"; }
|
||
disableBrowserMagic(te);
|
||
return div
|
||
}
|
||
|
||
// The publicly visible API. Note that methodOp(f) means
|
||
// 'wrap f in an operation, performed on its `this` parameter'.
|
||
|
||
// This is not the complete set of editor methods. Most of the
|
||
// methods defined on the Doc type are also injected into
|
||
// CodeMirror.prototype, for backwards compatibility and
|
||
// convenience.
|
||
|
||
function addEditorMethods(CodeMirror) {
|
||
var optionHandlers = CodeMirror.optionHandlers;
|
||
|
||
var helpers = CodeMirror.helpers = {};
|
||
|
||
CodeMirror.prototype = {
|
||
constructor: CodeMirror,
|
||
focus: function(){window.focus(); this.display.input.focus();},
|
||
|
||
setOption: function(option, value) {
|
||
var options = this.options, old = options[option];
|
||
if (options[option] == value && option != "mode") { return }
|
||
options[option] = value;
|
||
if (optionHandlers.hasOwnProperty(option))
|
||
{ operation(this, optionHandlers[option])(this, value, old); }
|
||
signal(this, "optionChange", this, option);
|
||
},
|
||
|
||
getOption: function(option) {return this.options[option]},
|
||
getDoc: function() {return this.doc},
|
||
|
||
addKeyMap: function(map, bottom) {
|
||
this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
|
||
},
|
||
removeKeyMap: function(map) {
|
||
var maps = this.state.keyMaps;
|
||
for (var i = 0; i < maps.length; ++i)
|
||
{ if (maps[i] == map || maps[i].name == map) {
|
||
maps.splice(i, 1);
|
||
return true
|
||
} }
|
||
},
|
||
|
||
addOverlay: methodOp(function(spec, options) {
|
||
var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
|
||
if (mode.startState) { throw new Error("Overlays may not be stateful.") }
|
||
insertSorted(this.state.overlays,
|
||
{mode: mode, modeSpec: spec, opaque: options && options.opaque,
|
||
priority: (options && options.priority) || 0},
|
||
function (overlay) { return overlay.priority; });
|
||
this.state.modeGen++;
|
||
regChange(this);
|
||
}),
|
||
removeOverlay: methodOp(function(spec) {
|
||
var overlays = this.state.overlays;
|
||
for (var i = 0; i < overlays.length; ++i) {
|
||
var cur = overlays[i].modeSpec;
|
||
if (cur == spec || typeof spec == "string" && cur.name == spec) {
|
||
overlays.splice(i, 1);
|
||
this.state.modeGen++;
|
||
regChange(this);
|
||
return
|
||
}
|
||
}
|
||
}),
|
||
|
||
indentLine: methodOp(function(n, dir, aggressive) {
|
||
if (typeof dir != "string" && typeof dir != "number") {
|
||
if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
|
||
else { dir = dir ? "add" : "subtract"; }
|
||
}
|
||
if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
|
||
}),
|
||
indentSelection: methodOp(function(how) {
|
||
var ranges = this.doc.sel.ranges, end = -1;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i];
|
||
if (!range.empty()) {
|
||
var from = range.from(), to = range.to();
|
||
var start = Math.max(end, from.line);
|
||
end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
|
||
for (var j = start; j < end; ++j)
|
||
{ indentLine(this, j, how); }
|
||
var newRanges = this.doc.sel.ranges;
|
||
if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
|
||
{ replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
|
||
} else if (range.head.line > end) {
|
||
indentLine(this, range.head.line, how, true);
|
||
end = range.head.line;
|
||
if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); }
|
||
}
|
||
}
|
||
}),
|
||
|
||
// Fetch the parser token for a given character. Useful for hacks
|
||
// that want to inspect the mode state (say, for completion).
|
||
getTokenAt: function(pos, precise) {
|
||
return takeToken(this, pos, precise)
|
||
},
|
||
|
||
getLineTokens: function(line, precise) {
|
||
return takeToken(this, Pos(line), precise, true)
|
||
},
|
||
|
||
getTokenTypeAt: function(pos) {
|
||
pos = clipPos(this.doc, pos);
|
||
var styles = getLineStyles(this, getLine(this.doc, pos.line));
|
||
var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
|
||
var type;
|
||
if (ch == 0) { type = styles[2]; }
|
||
else { for (;;) {
|
||
var mid = (before + after) >> 1;
|
||
if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
|
||
else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
|
||
else { type = styles[mid * 2 + 2]; break }
|
||
} }
|
||
var cut = type ? type.indexOf("overlay ") : -1;
|
||
return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
|
||
},
|
||
|
||
getModeAt: function(pos) {
|
||
var mode = this.doc.mode;
|
||
if (!mode.innerMode) { return mode }
|
||
return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
|
||
},
|
||
|
||
getHelper: function(pos, type) {
|
||
return this.getHelpers(pos, type)[0]
|
||
},
|
||
|
||
getHelpers: function(pos, type) {
|
||
var found = [];
|
||
if (!helpers.hasOwnProperty(type)) { return found }
|
||
var help = helpers[type], mode = this.getModeAt(pos);
|
||
if (typeof mode[type] == "string") {
|
||
if (help[mode[type]]) { found.push(help[mode[type]]); }
|
||
} else if (mode[type]) {
|
||
for (var i = 0; i < mode[type].length; i++) {
|
||
var val = help[mode[type][i]];
|
||
if (val) { found.push(val); }
|
||
}
|
||
} else if (mode.helperType && help[mode.helperType]) {
|
||
found.push(help[mode.helperType]);
|
||
} else if (help[mode.name]) {
|
||
found.push(help[mode.name]);
|
||
}
|
||
for (var i$1 = 0; i$1 < help._global.length; i$1++) {
|
||
var cur = help._global[i$1];
|
||
if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
|
||
{ found.push(cur.val); }
|
||
}
|
||
return found
|
||
},
|
||
|
||
getStateAfter: function(line, precise) {
|
||
var doc = this.doc;
|
||
line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
|
||
return getContextBefore(this, line + 1, precise).state
|
||
},
|
||
|
||
cursorCoords: function(start, mode) {
|
||
var pos, range = this.doc.sel.primary();
|
||
if (start == null) { pos = range.head; }
|
||
else if (typeof start == "object") { pos = clipPos(this.doc, start); }
|
||
else { pos = start ? range.from() : range.to(); }
|
||
return cursorCoords(this, pos, mode || "page")
|
||
},
|
||
|
||
charCoords: function(pos, mode) {
|
||
return charCoords(this, clipPos(this.doc, pos), mode || "page")
|
||
},
|
||
|
||
coordsChar: function(coords, mode) {
|
||
coords = fromCoordSystem(this, coords, mode || "page");
|
||
return coordsChar(this, coords.left, coords.top)
|
||
},
|
||
|
||
lineAtHeight: function(height, mode) {
|
||
height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
|
||
return lineAtHeight(this.doc, height + this.display.viewOffset)
|
||
},
|
||
heightAtLine: function(line, mode, includeWidgets) {
|
||
var end = false, lineObj;
|
||
if (typeof line == "number") {
|
||
var last = this.doc.first + this.doc.size - 1;
|
||
if (line < this.doc.first) { line = this.doc.first; }
|
||
else if (line > last) { line = last; end = true; }
|
||
lineObj = getLine(this.doc, line);
|
||
} else {
|
||
lineObj = line;
|
||
}
|
||
return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
|
||
(end ? this.doc.height - heightAtLine(lineObj) : 0)
|
||
},
|
||
|
||
defaultTextHeight: function() { return textHeight(this.display) },
|
||
defaultCharWidth: function() { return charWidth(this.display) },
|
||
|
||
getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
|
||
|
||
addWidget: function(pos, node, scroll, vert, horiz) {
|
||
var display = this.display;
|
||
pos = cursorCoords(this, clipPos(this.doc, pos));
|
||
var top = pos.bottom, left = pos.left;
|
||
node.style.position = "absolute";
|
||
node.setAttribute("cm-ignore-events", "true");
|
||
this.display.input.setUneditable(node);
|
||
display.sizer.appendChild(node);
|
||
if (vert == "over") {
|
||
top = pos.top;
|
||
} else if (vert == "above" || vert == "near") {
|
||
var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
|
||
hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
|
||
// Default to positioning above (if specified and possible); otherwise default to positioning below
|
||
if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
|
||
{ top = pos.top - node.offsetHeight; }
|
||
else if (pos.bottom + node.offsetHeight <= vspace)
|
||
{ top = pos.bottom; }
|
||
if (left + node.offsetWidth > hspace)
|
||
{ left = hspace - node.offsetWidth; }
|
||
}
|
||
node.style.top = top + "px";
|
||
node.style.left = node.style.right = "";
|
||
if (horiz == "right") {
|
||
left = display.sizer.clientWidth - node.offsetWidth;
|
||
node.style.right = "0px";
|
||
} else {
|
||
if (horiz == "left") { left = 0; }
|
||
else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
|
||
node.style.left = left + "px";
|
||
}
|
||
if (scroll)
|
||
{ scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
|
||
},
|
||
|
||
triggerOnKeyDown: methodOp(onKeyDown),
|
||
triggerOnKeyPress: methodOp(onKeyPress),
|
||
triggerOnKeyUp: onKeyUp,
|
||
triggerOnMouseDown: methodOp(onMouseDown),
|
||
|
||
execCommand: function(cmd) {
|
||
if (commands.hasOwnProperty(cmd))
|
||
{ return commands[cmd].call(null, this) }
|
||
},
|
||
|
||
triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
|
||
|
||
findPosH: function(from, amount, unit, visually) {
|
||
var dir = 1;
|
||
if (amount < 0) { dir = -1; amount = -amount; }
|
||
var cur = clipPos(this.doc, from);
|
||
for (var i = 0; i < amount; ++i) {
|
||
cur = findPosH(this.doc, cur, dir, unit, visually);
|
||
if (cur.hitSide) { break }
|
||
}
|
||
return cur
|
||
},
|
||
|
||
moveH: methodOp(function(dir, unit) {
|
||
var this$1 = this;
|
||
|
||
this.extendSelectionsBy(function (range) {
|
||
if (this$1.display.shift || this$1.doc.extend || range.empty())
|
||
{ return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) }
|
||
else
|
||
{ return dir < 0 ? range.from() : range.to() }
|
||
}, sel_move);
|
||
}),
|
||
|
||
deleteH: methodOp(function(dir, unit) {
|
||
var sel = this.doc.sel, doc = this.doc;
|
||
if (sel.somethingSelected())
|
||
{ doc.replaceSelection("", null, "+delete"); }
|
||
else
|
||
{ deleteNearSelection(this, function (range) {
|
||
var other = findPosH(doc, range.head, dir, unit, false);
|
||
return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}
|
||
}); }
|
||
}),
|
||
|
||
findPosV: function(from, amount, unit, goalColumn) {
|
||
var dir = 1, x = goalColumn;
|
||
if (amount < 0) { dir = -1; amount = -amount; }
|
||
var cur = clipPos(this.doc, from);
|
||
for (var i = 0; i < amount; ++i) {
|
||
var coords = cursorCoords(this, cur, "div");
|
||
if (x == null) { x = coords.left; }
|
||
else { coords.left = x; }
|
||
cur = findPosV(this, coords, dir, unit);
|
||
if (cur.hitSide) { break }
|
||
}
|
||
return cur
|
||
},
|
||
|
||
moveV: methodOp(function(dir, unit) {
|
||
var this$1 = this;
|
||
|
||
var doc = this.doc, goals = [];
|
||
var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
|
||
doc.extendSelectionsBy(function (range) {
|
||
if (collapse)
|
||
{ return dir < 0 ? range.from() : range.to() }
|
||
var headPos = cursorCoords(this$1, range.head, "div");
|
||
if (range.goalColumn != null) { headPos.left = range.goalColumn; }
|
||
goals.push(headPos.left);
|
||
var pos = findPosV(this$1, headPos, dir, unit);
|
||
if (unit == "page" && range == doc.sel.primary())
|
||
{ addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
|
||
return pos
|
||
}, sel_move);
|
||
if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
|
||
{ doc.sel.ranges[i].goalColumn = goals[i]; } }
|
||
}),
|
||
|
||
// Find the word at the given position (as returned by coordsChar).
|
||
findWordAt: function(pos) {
|
||
var doc = this.doc, line = getLine(doc, pos.line).text;
|
||
var start = pos.ch, end = pos.ch;
|
||
if (line) {
|
||
var helper = this.getHelper(pos, "wordChars");
|
||
if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
|
||
var startChar = line.charAt(start);
|
||
var check = isWordChar(startChar, helper)
|
||
? function (ch) { return isWordChar(ch, helper); }
|
||
: /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
|
||
: function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
|
||
while (start > 0 && check(line.charAt(start - 1))) { --start; }
|
||
while (end < line.length && check(line.charAt(end))) { ++end; }
|
||
}
|
||
return new Range(Pos(pos.line, start), Pos(pos.line, end))
|
||
},
|
||
|
||
toggleOverwrite: function(value) {
|
||
if (value != null && value == this.state.overwrite) { return }
|
||
if (this.state.overwrite = !this.state.overwrite)
|
||
{ addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
|
||
else
|
||
{ rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
|
||
|
||
signal(this, "overwriteToggle", this, this.state.overwrite);
|
||
},
|
||
hasFocus: function() { return this.display.input.getField() == activeElt() },
|
||
isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
|
||
|
||
scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
|
||
getScrollInfo: function() {
|
||
var scroller = this.display.scroller;
|
||
return {left: scroller.scrollLeft, top: scroller.scrollTop,
|
||
height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
|
||
width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
|
||
clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
|
||
},
|
||
|
||
scrollIntoView: methodOp(function(range, margin) {
|
||
if (range == null) {
|
||
range = {from: this.doc.sel.primary().head, to: null};
|
||
if (margin == null) { margin = this.options.cursorScrollMargin; }
|
||
} else if (typeof range == "number") {
|
||
range = {from: Pos(range, 0), to: null};
|
||
} else if (range.from == null) {
|
||
range = {from: range, to: null};
|
||
}
|
||
if (!range.to) { range.to = range.from; }
|
||
range.margin = margin || 0;
|
||
|
||
if (range.from.line != null) {
|
||
scrollToRange(this, range);
|
||
} else {
|
||
scrollToCoordsRange(this, range.from, range.to, range.margin);
|
||
}
|
||
}),
|
||
|
||
setSize: methodOp(function(width, height) {
|
||
var this$1 = this;
|
||
|
||
var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
|
||
if (width != null) { this.display.wrapper.style.width = interpret(width); }
|
||
if (height != null) { this.display.wrapper.style.height = interpret(height); }
|
||
if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
|
||
var lineNo = this.display.viewFrom;
|
||
this.doc.iter(lineNo, this.display.viewTo, function (line) {
|
||
if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
|
||
{ if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } }
|
||
++lineNo;
|
||
});
|
||
this.curOp.forceUpdate = true;
|
||
signal(this, "refresh", this);
|
||
}),
|
||
|
||
operation: function(f){return runInOp(this, f)},
|
||
startOperation: function(){return startOperation(this)},
|
||
endOperation: function(){return endOperation(this)},
|
||
|
||
refresh: methodOp(function() {
|
||
var oldHeight = this.display.cachedTextHeight;
|
||
regChange(this);
|
||
this.curOp.forceUpdate = true;
|
||
clearCaches(this);
|
||
scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
|
||
updateGutterSpace(this.display);
|
||
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping)
|
||
{ estimateLineHeights(this); }
|
||
signal(this, "refresh", this);
|
||
}),
|
||
|
||
swapDoc: methodOp(function(doc) {
|
||
var old = this.doc;
|
||
old.cm = null;
|
||
// Cancel the current text selection if any (#5821)
|
||
if (this.state.selectingText) { this.state.selectingText(); }
|
||
attachDoc(this, doc);
|
||
clearCaches(this);
|
||
this.display.input.reset();
|
||
scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
|
||
this.curOp.forceScroll = true;
|
||
signalLater(this, "swapDoc", this, old);
|
||
return old
|
||
}),
|
||
|
||
phrase: function(phraseText) {
|
||
var phrases = this.options.phrases;
|
||
return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText
|
||
},
|
||
|
||
getInputField: function(){return this.display.input.getField()},
|
||
getWrapperElement: function(){return this.display.wrapper},
|
||
getScrollerElement: function(){return this.display.scroller},
|
||
getGutterElement: function(){return this.display.gutters}
|
||
};
|
||
eventMixin(CodeMirror);
|
||
|
||
CodeMirror.registerHelper = function(type, name, value) {
|
||
if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
|
||
helpers[type][name] = value;
|
||
};
|
||
CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
|
||
CodeMirror.registerHelper(type, name, value);
|
||
helpers[type]._global.push({pred: predicate, val: value});
|
||
};
|
||
}
|
||
|
||
// Used for horizontal relative motion. Dir is -1 or 1 (left or
|
||
// right), unit can be "char", "column" (like char, but doesn't
|
||
// cross line boundaries), "word" (across next word), or "group" (to
|
||
// the start of next group of word or non-word-non-whitespace
|
||
// chars). The visually param controls whether, in right-to-left
|
||
// text, direction 1 means to move towards the next index in the
|
||
// string, or towards the character to the right of the current
|
||
// position. The resulting position will have a hitSide=true
|
||
// property if it reached the end of the document.
|
||
function findPosH(doc, pos, dir, unit, visually) {
|
||
var oldPos = pos;
|
||
var origDir = dir;
|
||
var lineObj = getLine(doc, pos.line);
|
||
var lineDir = visually && doc.direction == "rtl" ? -dir : dir;
|
||
function findNextLine() {
|
||
var l = pos.line + lineDir;
|
||
if (l < doc.first || l >= doc.first + doc.size) { return false }
|
||
pos = new Pos(l, pos.ch, pos.sticky);
|
||
return lineObj = getLine(doc, l)
|
||
}
|
||
function moveOnce(boundToLine) {
|
||
var next;
|
||
if (visually) {
|
||
next = moveVisually(doc.cm, lineObj, pos, dir);
|
||
} else {
|
||
next = moveLogically(lineObj, pos, dir);
|
||
}
|
||
if (next == null) {
|
||
if (!boundToLine && findNextLine())
|
||
{ pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); }
|
||
else
|
||
{ return false }
|
||
} else {
|
||
pos = next;
|
||
}
|
||
return true
|
||
}
|
||
|
||
if (unit == "char") {
|
||
moveOnce();
|
||
} else if (unit == "column") {
|
||
moveOnce(true);
|
||
} else if (unit == "word" || unit == "group") {
|
||
var sawType = null, group = unit == "group";
|
||
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
|
||
for (var first = true;; first = false) {
|
||
if (dir < 0 && !moveOnce(!first)) { break }
|
||
var cur = lineObj.text.charAt(pos.ch) || "\n";
|
||
var type = isWordChar(cur, helper) ? "w"
|
||
: group && cur == "\n" ? "n"
|
||
: !group || /\s/.test(cur) ? null
|
||
: "p";
|
||
if (group && !first && !type) { type = "s"; }
|
||
if (sawType && sawType != type) {
|
||
if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
|
||
break
|
||
}
|
||
|
||
if (type) { sawType = type; }
|
||
if (dir > 0 && !moveOnce(!first)) { break }
|
||
}
|
||
}
|
||
var result = skipAtomic(doc, pos, oldPos, origDir, true);
|
||
if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
|
||
return result
|
||
}
|
||
|
||
// For relative vertical movement. Dir may be -1 or 1. Unit can be
|
||
// "page" or "line". The resulting position will have a hitSide=true
|
||
// property if it reached the end of the document.
|
||
function findPosV(cm, pos, dir, unit) {
|
||
var doc = cm.doc, x = pos.left, y;
|
||
if (unit == "page") {
|
||
var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
|
||
var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
|
||
y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
|
||
|
||
} else if (unit == "line") {
|
||
y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
|
||
}
|
||
var target;
|
||
for (;;) {
|
||
target = coordsChar(cm, x, y);
|
||
if (!target.outside) { break }
|
||
if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
|
||
y += dir * 5;
|
||
}
|
||
return target
|
||
}
|
||
|
||
// CONTENTEDITABLE INPUT STYLE
|
||
|
||
var ContentEditableInput = function(cm) {
|
||
this.cm = cm;
|
||
this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
|
||
this.polling = new Delayed();
|
||
this.composing = null;
|
||
this.gracePeriod = false;
|
||
this.readDOMTimeout = null;
|
||
};
|
||
|
||
ContentEditableInput.prototype.init = function (display) {
|
||
var this$1 = this;
|
||
|
||
var input = this, cm = input.cm;
|
||
var div = input.div = display.lineDiv;
|
||
disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize);
|
||
|
||
function belongsToInput(e) {
|
||
for (var t = e.target; t; t = t.parentNode) {
|
||
if (t == div) { return true }
|
||
if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break }
|
||
}
|
||
return false
|
||
}
|
||
|
||
on(div, "paste", function (e) {
|
||
if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
|
||
// IE doesn't fire input events, so we schedule a read for the pasted content in this way
|
||
if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
|
||
});
|
||
|
||
on(div, "compositionstart", function (e) {
|
||
this$1.composing = {data: e.data, done: false};
|
||
});
|
||
on(div, "compositionupdate", function (e) {
|
||
if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
|
||
});
|
||
on(div, "compositionend", function (e) {
|
||
if (this$1.composing) {
|
||
if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
|
||
this$1.composing.done = true;
|
||
}
|
||
});
|
||
|
||
on(div, "touchstart", function () { return input.forceCompositionEnd(); });
|
||
|
||
on(div, "input", function () {
|
||
if (!this$1.composing) { this$1.readFromDOMSoon(); }
|
||
});
|
||
|
||
function onCopyCut(e) {
|
||
if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return }
|
||
if (cm.somethingSelected()) {
|
||
setLastCopied({lineWise: false, text: cm.getSelections()});
|
||
if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
|
||
} else if (!cm.options.lineWiseCopyCut) {
|
||
return
|
||
} else {
|
||
var ranges = copyableRanges(cm);
|
||
setLastCopied({lineWise: true, text: ranges.text});
|
||
if (e.type == "cut") {
|
||
cm.operation(function () {
|
||
cm.setSelections(ranges.ranges, 0, sel_dontScroll);
|
||
cm.replaceSelection("", null, "cut");
|
||
});
|
||
}
|
||
}
|
||
if (e.clipboardData) {
|
||
e.clipboardData.clearData();
|
||
var content = lastCopied.text.join("\n");
|
||
// iOS exposes the clipboard API, but seems to discard content inserted into it
|
||
e.clipboardData.setData("Text", content);
|
||
if (e.clipboardData.getData("Text") == content) {
|
||
e.preventDefault();
|
||
return
|
||
}
|
||
}
|
||
// Old-fashioned briefly-focus-a-textarea hack
|
||
var kludge = hiddenTextarea(), te = kludge.firstChild;
|
||
cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
|
||
te.value = lastCopied.text.join("\n");
|
||
var hadFocus = document.activeElement;
|
||
selectInput(te);
|
||
setTimeout(function () {
|
||
cm.display.lineSpace.removeChild(kludge);
|
||
hadFocus.focus();
|
||
if (hadFocus == div) { input.showPrimarySelection(); }
|
||
}, 50);
|
||
}
|
||
on(div, "copy", onCopyCut);
|
||
on(div, "cut", onCopyCut);
|
||
};
|
||
|
||
ContentEditableInput.prototype.screenReaderLabelChanged = function (label) {
|
||
// Label for screenreaders, accessibility
|
||
if(label) {
|
||
this.div.setAttribute('aria-label', label);
|
||
} else {
|
||
this.div.removeAttribute('aria-label');
|
||
}
|
||
};
|
||
|
||
ContentEditableInput.prototype.prepareSelection = function () {
|
||
var result = prepareSelection(this.cm, false);
|
||
result.focus = document.activeElement == this.div;
|
||
return result
|
||
};
|
||
|
||
ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
|
||
if (!info || !this.cm.display.view.length) { return }
|
||
if (info.focus || takeFocus) { this.showPrimarySelection(); }
|
||
this.showMultipleSelections(info);
|
||
};
|
||
|
||
ContentEditableInput.prototype.getSelection = function () {
|
||
return this.cm.display.wrapper.ownerDocument.getSelection()
|
||
};
|
||
|
||
ContentEditableInput.prototype.showPrimarySelection = function () {
|
||
var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
|
||
var from = prim.from(), to = prim.to();
|
||
|
||
if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
|
||
sel.removeAllRanges();
|
||
return
|
||
}
|
||
|
||
var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
|
||
var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
|
||
if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
|
||
cmp(minPos(curAnchor, curFocus), from) == 0 &&
|
||
cmp(maxPos(curAnchor, curFocus), to) == 0)
|
||
{ return }
|
||
|
||
var view = cm.display.view;
|
||
var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
|
||
{node: view[0].measure.map[2], offset: 0};
|
||
var end = to.line < cm.display.viewTo && posToDOM(cm, to);
|
||
if (!end) {
|
||
var measure = view[view.length - 1].measure;
|
||
var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
|
||
end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
|
||
}
|
||
|
||
if (!start || !end) {
|
||
sel.removeAllRanges();
|
||
return
|
||
}
|
||
|
||
var old = sel.rangeCount && sel.getRangeAt(0), rng;
|
||
try { rng = range(start.node, start.offset, end.offset, end.node); }
|
||
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
|
||
if (rng) {
|
||
if (!gecko && cm.state.focused) {
|
||
sel.collapse(start.node, start.offset);
|
||
if (!rng.collapsed) {
|
||
sel.removeAllRanges();
|
||
sel.addRange(rng);
|
||
}
|
||
} else {
|
||
sel.removeAllRanges();
|
||
sel.addRange(rng);
|
||
}
|
||
if (old && sel.anchorNode == null) { sel.addRange(old); }
|
||
else if (gecko) { this.startGracePeriod(); }
|
||
}
|
||
this.rememberSelection();
|
||
};
|
||
|
||
ContentEditableInput.prototype.startGracePeriod = function () {
|
||
var this$1 = this;
|
||
|
||
clearTimeout(this.gracePeriod);
|
||
this.gracePeriod = setTimeout(function () {
|
||
this$1.gracePeriod = false;
|
||
if (this$1.selectionChanged())
|
||
{ this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
|
||
}, 20);
|
||
};
|
||
|
||
ContentEditableInput.prototype.showMultipleSelections = function (info) {
|
||
removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
|
||
removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
|
||
};
|
||
|
||
ContentEditableInput.prototype.rememberSelection = function () {
|
||
var sel = this.getSelection();
|
||
this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
|
||
this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
|
||
};
|
||
|
||
ContentEditableInput.prototype.selectionInEditor = function () {
|
||
var sel = this.getSelection();
|
||
if (!sel.rangeCount) { return false }
|
||
var node = sel.getRangeAt(0).commonAncestorContainer;
|
||
return contains(this.div, node)
|
||
};
|
||
|
||
ContentEditableInput.prototype.focus = function () {
|
||
if (this.cm.options.readOnly != "nocursor") {
|
||
if (!this.selectionInEditor() || document.activeElement != this.div)
|
||
{ this.showSelection(this.prepareSelection(), true); }
|
||
this.div.focus();
|
||
}
|
||
};
|
||
ContentEditableInput.prototype.blur = function () { this.div.blur(); };
|
||
ContentEditableInput.prototype.getField = function () { return this.div };
|
||
|
||
ContentEditableInput.prototype.supportsTouch = function () { return true };
|
||
|
||
ContentEditableInput.prototype.receivedFocus = function () {
|
||
var input = this;
|
||
if (this.selectionInEditor())
|
||
{ this.pollSelection(); }
|
||
else
|
||
{ runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
|
||
|
||
function poll() {
|
||
if (input.cm.state.focused) {
|
||
input.pollSelection();
|
||
input.polling.set(input.cm.options.pollInterval, poll);
|
||
}
|
||
}
|
||
this.polling.set(this.cm.options.pollInterval, poll);
|
||
};
|
||
|
||
ContentEditableInput.prototype.selectionChanged = function () {
|
||
var sel = this.getSelection();
|
||
return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
|
||
sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
|
||
};
|
||
|
||
ContentEditableInput.prototype.pollSelection = function () {
|
||
if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
|
||
var sel = this.getSelection(), cm = this.cm;
|
||
// On Android Chrome (version 56, at least), backspacing into an
|
||
// uneditable block element will put the cursor in that element,
|
||
// and then, because it's not editable, hide the virtual keyboard.
|
||
// Because Android doesn't allow us to actually detect backspace
|
||
// presses in a sane way, this code checks for when that happens
|
||
// and simulates a backspace press in this case.
|
||
if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {
|
||
this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
|
||
this.blur();
|
||
this.focus();
|
||
return
|
||
}
|
||
if (this.composing) { return }
|
||
this.rememberSelection();
|
||
var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
|
||
var head = domToPos(cm, sel.focusNode, sel.focusOffset);
|
||
if (anchor && head) { runInOp(cm, function () {
|
||
setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
|
||
if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
|
||
}); }
|
||
};
|
||
|
||
ContentEditableInput.prototype.pollContent = function () {
|
||
if (this.readDOMTimeout != null) {
|
||
clearTimeout(this.readDOMTimeout);
|
||
this.readDOMTimeout = null;
|
||
}
|
||
|
||
var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
|
||
var from = sel.from(), to = sel.to();
|
||
if (from.ch == 0 && from.line > cm.firstLine())
|
||
{ from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
|
||
if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
|
||
{ to = Pos(to.line + 1, 0); }
|
||
if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
|
||
|
||
var fromIndex, fromLine, fromNode;
|
||
if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
|
||
fromLine = lineNo(display.view[0].line);
|
||
fromNode = display.view[0].node;
|
||
} else {
|
||
fromLine = lineNo(display.view[fromIndex].line);
|
||
fromNode = display.view[fromIndex - 1].node.nextSibling;
|
||
}
|
||
var toIndex = findViewIndex(cm, to.line);
|
||
var toLine, toNode;
|
||
if (toIndex == display.view.length - 1) {
|
||
toLine = display.viewTo - 1;
|
||
toNode = display.lineDiv.lastChild;
|
||
} else {
|
||
toLine = lineNo(display.view[toIndex + 1].line) - 1;
|
||
toNode = display.view[toIndex + 1].node.previousSibling;
|
||
}
|
||
|
||
if (!fromNode) { return false }
|
||
var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
|
||
var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
|
||
while (newText.length > 1 && oldText.length > 1) {
|
||
if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
|
||
else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
|
||
else { break }
|
||
}
|
||
|
||
var cutFront = 0, cutEnd = 0;
|
||
var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
|
||
while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
|
||
{ ++cutFront; }
|
||
var newBot = lst(newText), oldBot = lst(oldText);
|
||
var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
|
||
oldBot.length - (oldText.length == 1 ? cutFront : 0));
|
||
while (cutEnd < maxCutEnd &&
|
||
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
|
||
{ ++cutEnd; }
|
||
// Try to move start of change to start of selection if ambiguous
|
||
if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
|
||
while (cutFront && cutFront > from.ch &&
|
||
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
|
||
cutFront--;
|
||
cutEnd++;
|
||
}
|
||
}
|
||
|
||
newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
|
||
newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
|
||
|
||
var chFrom = Pos(fromLine, cutFront);
|
||
var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
|
||
if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
|
||
replaceRange(cm.doc, newText, chFrom, chTo, "+input");
|
||
return true
|
||
}
|
||
};
|
||
|
||
ContentEditableInput.prototype.ensurePolled = function () {
|
||
this.forceCompositionEnd();
|
||
};
|
||
ContentEditableInput.prototype.reset = function () {
|
||
this.forceCompositionEnd();
|
||
};
|
||
ContentEditableInput.prototype.forceCompositionEnd = function () {
|
||
if (!this.composing) { return }
|
||
clearTimeout(this.readDOMTimeout);
|
||
this.composing = null;
|
||
this.updateFromDOM();
|
||
this.div.blur();
|
||
this.div.focus();
|
||
};
|
||
ContentEditableInput.prototype.readFromDOMSoon = function () {
|
||
var this$1 = this;
|
||
|
||
if (this.readDOMTimeout != null) { return }
|
||
this.readDOMTimeout = setTimeout(function () {
|
||
this$1.readDOMTimeout = null;
|
||
if (this$1.composing) {
|
||
if (this$1.composing.done) { this$1.composing = null; }
|
||
else { return }
|
||
}
|
||
this$1.updateFromDOM();
|
||
}, 80);
|
||
};
|
||
|
||
ContentEditableInput.prototype.updateFromDOM = function () {
|
||
var this$1 = this;
|
||
|
||
if (this.cm.isReadOnly() || !this.pollContent())
|
||
{ runInOp(this.cm, function () { return regChange(this$1.cm); }); }
|
||
};
|
||
|
||
ContentEditableInput.prototype.setUneditable = function (node) {
|
||
node.contentEditable = "false";
|
||
};
|
||
|
||
ContentEditableInput.prototype.onKeyPress = function (e) {
|
||
if (e.charCode == 0 || this.composing) { return }
|
||
e.preventDefault();
|
||
if (!this.cm.isReadOnly())
|
||
{ operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
|
||
};
|
||
|
||
ContentEditableInput.prototype.readOnlyChanged = function (val) {
|
||
this.div.contentEditable = String(val != "nocursor");
|
||
};
|
||
|
||
ContentEditableInput.prototype.onContextMenu = function () {};
|
||
ContentEditableInput.prototype.resetPosition = function () {};
|
||
|
||
ContentEditableInput.prototype.needsContentAttribute = true;
|
||
|
||
function posToDOM(cm, pos) {
|
||
var view = findViewForLine(cm, pos.line);
|
||
if (!view || view.hidden) { return null }
|
||
var line = getLine(cm.doc, pos.line);
|
||
var info = mapFromLineView(view, line, pos.line);
|
||
|
||
var order = getOrder(line, cm.doc.direction), side = "left";
|
||
if (order) {
|
||
var partPos = getBidiPartAt(order, pos.ch);
|
||
side = partPos % 2 ? "right" : "left";
|
||
}
|
||
var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
|
||
result.offset = result.collapse == "right" ? result.end : result.start;
|
||
return result
|
||
}
|
||
|
||
function isInGutter(node) {
|
||
for (var scan = node; scan; scan = scan.parentNode)
|
||
{ if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
|
||
return false
|
||
}
|
||
|
||
function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
|
||
|
||
function domTextBetween(cm, from, to, fromLine, toLine) {
|
||
var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;
|
||
function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
|
||
function close() {
|
||
if (closing) {
|
||
text += lineSep;
|
||
if (extraLinebreak) { text += lineSep; }
|
||
closing = extraLinebreak = false;
|
||
}
|
||
}
|
||
function addText(str) {
|
||
if (str) {
|
||
close();
|
||
text += str;
|
||
}
|
||
}
|
||
function walk(node) {
|
||
if (node.nodeType == 1) {
|
||
var cmText = node.getAttribute("cm-text");
|
||
if (cmText) {
|
||
addText(cmText);
|
||
return
|
||
}
|
||
var markerID = node.getAttribute("cm-marker"), range;
|
||
if (markerID) {
|
||
var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
|
||
if (found.length && (range = found[0].find(0)))
|
||
{ addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); }
|
||
return
|
||
}
|
||
if (node.getAttribute("contenteditable") == "false") { return }
|
||
var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);
|
||
if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }
|
||
|
||
if (isBlock) { close(); }
|
||
for (var i = 0; i < node.childNodes.length; i++)
|
||
{ walk(node.childNodes[i]); }
|
||
|
||
if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }
|
||
if (isBlock) { closing = true; }
|
||
} else if (node.nodeType == 3) {
|
||
addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "));
|
||
}
|
||
}
|
||
for (;;) {
|
||
walk(from);
|
||
if (from == to) { break }
|
||
from = from.nextSibling;
|
||
extraLinebreak = false;
|
||
}
|
||
return text
|
||
}
|
||
|
||
function domToPos(cm, node, offset) {
|
||
var lineNode;
|
||
if (node == cm.display.lineDiv) {
|
||
lineNode = cm.display.lineDiv.childNodes[offset];
|
||
if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
|
||
node = null; offset = 0;
|
||
} else {
|
||
for (lineNode = node;; lineNode = lineNode.parentNode) {
|
||
if (!lineNode || lineNode == cm.display.lineDiv) { return null }
|
||
if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
|
||
}
|
||
}
|
||
for (var i = 0; i < cm.display.view.length; i++) {
|
||
var lineView = cm.display.view[i];
|
||
if (lineView.node == lineNode)
|
||
{ return locateNodeInLineView(lineView, node, offset) }
|
||
}
|
||
}
|
||
|
||
function locateNodeInLineView(lineView, node, offset) {
|
||
var wrapper = lineView.text.firstChild, bad = false;
|
||
if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
|
||
if (node == wrapper) {
|
||
bad = true;
|
||
node = wrapper.childNodes[offset];
|
||
offset = 0;
|
||
if (!node) {
|
||
var line = lineView.rest ? lst(lineView.rest) : lineView.line;
|
||
return badPos(Pos(lineNo(line), line.text.length), bad)
|
||
}
|
||
}
|
||
|
||
var textNode = node.nodeType == 3 ? node : null, topNode = node;
|
||
if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
|
||
textNode = node.firstChild;
|
||
if (offset) { offset = textNode.nodeValue.length; }
|
||
}
|
||
while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
|
||
var measure = lineView.measure, maps = measure.maps;
|
||
|
||
function find(textNode, topNode, offset) {
|
||
for (var i = -1; i < (maps ? maps.length : 0); i++) {
|
||
var map = i < 0 ? measure.map : maps[i];
|
||
for (var j = 0; j < map.length; j += 3) {
|
||
var curNode = map[j + 2];
|
||
if (curNode == textNode || curNode == topNode) {
|
||
var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
|
||
var ch = map[j] + offset;
|
||
if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; }
|
||
return Pos(line, ch)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
var found = find(textNode, topNode, offset);
|
||
if (found) { return badPos(found, bad) }
|
||
|
||
// FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
|
||
for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
|
||
found = find(after, after.firstChild, 0);
|
||
if (found)
|
||
{ return badPos(Pos(found.line, found.ch - dist), bad) }
|
||
else
|
||
{ dist += after.textContent.length; }
|
||
}
|
||
for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
|
||
found = find(before, before.firstChild, -1);
|
||
if (found)
|
||
{ return badPos(Pos(found.line, found.ch + dist$1), bad) }
|
||
else
|
||
{ dist$1 += before.textContent.length; }
|
||
}
|
||
}
|
||
|
||
// TEXTAREA INPUT STYLE
|
||
|
||
var TextareaInput = function(cm) {
|
||
this.cm = cm;
|
||
// See input.poll and input.reset
|
||
this.prevInput = "";
|
||
|
||
// Flag that indicates whether we expect input to appear real soon
|
||
// now (after some event like 'keypress' or 'input') and are
|
||
// polling intensively.
|
||
this.pollingFast = false;
|
||
// Self-resetting timeout for the poller
|
||
this.polling = new Delayed();
|
||
// Used to work around IE issue with selection being forgotten when focus moves away from textarea
|
||
this.hasSelection = false;
|
||
this.composing = null;
|
||
};
|
||
|
||
TextareaInput.prototype.init = function (display) {
|
||
var this$1 = this;
|
||
|
||
var input = this, cm = this.cm;
|
||
this.createField(display);
|
||
var te = this.textarea;
|
||
|
||
display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);
|
||
|
||
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
|
||
if (ios) { te.style.width = "0px"; }
|
||
|
||
on(te, "input", function () {
|
||
if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
|
||
input.poll();
|
||
});
|
||
|
||
on(te, "paste", function (e) {
|
||
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
|
||
|
||
cm.state.pasteIncoming = +new Date;
|
||
input.fastPoll();
|
||
});
|
||
|
||
function prepareCopyCut(e) {
|
||
if (signalDOMEvent(cm, e)) { return }
|
||
if (cm.somethingSelected()) {
|
||
setLastCopied({lineWise: false, text: cm.getSelections()});
|
||
} else if (!cm.options.lineWiseCopyCut) {
|
||
return
|
||
} else {
|
||
var ranges = copyableRanges(cm);
|
||
setLastCopied({lineWise: true, text: ranges.text});
|
||
if (e.type == "cut") {
|
||
cm.setSelections(ranges.ranges, null, sel_dontScroll);
|
||
} else {
|
||
input.prevInput = "";
|
||
te.value = ranges.text.join("\n");
|
||
selectInput(te);
|
||
}
|
||
}
|
||
if (e.type == "cut") { cm.state.cutIncoming = +new Date; }
|
||
}
|
||
on(te, "cut", prepareCopyCut);
|
||
on(te, "copy", prepareCopyCut);
|
||
|
||
on(display.scroller, "paste", function (e) {
|
||
if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
|
||
if (!te.dispatchEvent) {
|
||
cm.state.pasteIncoming = +new Date;
|
||
input.focus();
|
||
return
|
||
}
|
||
|
||
// Pass the `paste` event to the textarea so it's handled by its event listener.
|
||
var event = new Event("paste");
|
||
event.clipboardData = e.clipboardData;
|
||
te.dispatchEvent(event);
|
||
});
|
||
|
||
// Prevent normal selection in the editor (we handle our own)
|
||
on(display.lineSpace, "selectstart", function (e) {
|
||
if (!eventInWidget(display, e)) { e_preventDefault(e); }
|
||
});
|
||
|
||
on(te, "compositionstart", function () {
|
||
var start = cm.getCursor("from");
|
||
if (input.composing) { input.composing.range.clear(); }
|
||
input.composing = {
|
||
start: start,
|
||
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
|
||
};
|
||
});
|
||
on(te, "compositionend", function () {
|
||
if (input.composing) {
|
||
input.poll();
|
||
input.composing.range.clear();
|
||
input.composing = null;
|
||
}
|
||
});
|
||
};
|
||
|
||
TextareaInput.prototype.createField = function (_display) {
|
||
// Wraps and hides input textarea
|
||
this.wrapper = hiddenTextarea();
|
||
// The semihidden textarea that is focused when the editor is
|
||
// focused, and receives input.
|
||
this.textarea = this.wrapper.firstChild;
|
||
};
|
||
|
||
TextareaInput.prototype.screenReaderLabelChanged = function (label) {
|
||
// Label for screenreaders, accessibility
|
||
if(label) {
|
||
this.textarea.setAttribute('aria-label', label);
|
||
} else {
|
||
this.textarea.removeAttribute('aria-label');
|
||
}
|
||
};
|
||
|
||
TextareaInput.prototype.prepareSelection = function () {
|
||
// Redraw the selection and/or cursor
|
||
var cm = this.cm, display = cm.display, doc = cm.doc;
|
||
var result = prepareSelection(cm);
|
||
|
||
// Move the hidden textarea near the cursor to prevent scrolling artifacts
|
||
if (cm.options.moveInputWithCursor) {
|
||
var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
|
||
var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
|
||
result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
|
||
headPos.top + lineOff.top - wrapOff.top));
|
||
result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
|
||
headPos.left + lineOff.left - wrapOff.left));
|
||
}
|
||
|
||
return result
|
||
};
|
||
|
||
TextareaInput.prototype.showSelection = function (drawn) {
|
||
var cm = this.cm, display = cm.display;
|
||
removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
|
||
removeChildrenAndAdd(display.selectionDiv, drawn.selection);
|
||
if (drawn.teTop != null) {
|
||
this.wrapper.style.top = drawn.teTop + "px";
|
||
this.wrapper.style.left = drawn.teLeft + "px";
|
||
}
|
||
};
|
||
|
||
// Reset the input to correspond to the selection (or to be empty,
|
||
// when not typing and nothing is selected)
|
||
TextareaInput.prototype.reset = function (typing) {
|
||
if (this.contextMenuPending || this.composing) { return }
|
||
var cm = this.cm;
|
||
if (cm.somethingSelected()) {
|
||
this.prevInput = "";
|
||
var content = cm.getSelection();
|
||
this.textarea.value = content;
|
||
if (cm.state.focused) { selectInput(this.textarea); }
|
||
if (ie && ie_version >= 9) { this.hasSelection = content; }
|
||
} else if (!typing) {
|
||
this.prevInput = this.textarea.value = "";
|
||
if (ie && ie_version >= 9) { this.hasSelection = null; }
|
||
}
|
||
};
|
||
|
||
TextareaInput.prototype.getField = function () { return this.textarea };
|
||
|
||
TextareaInput.prototype.supportsTouch = function () { return false };
|
||
|
||
TextareaInput.prototype.focus = function () {
|
||
if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
|
||
try { this.textarea.focus(); }
|
||
catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
|
||
}
|
||
};
|
||
|
||
TextareaInput.prototype.blur = function () { this.textarea.blur(); };
|
||
|
||
TextareaInput.prototype.resetPosition = function () {
|
||
this.wrapper.style.top = this.wrapper.style.left = 0;
|
||
};
|
||
|
||
TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
|
||
|
||
// Poll for input changes, using the normal rate of polling. This
|
||
// runs as long as the editor is focused.
|
||
TextareaInput.prototype.slowPoll = function () {
|
||
var this$1 = this;
|
||
|
||
if (this.pollingFast) { return }
|
||
this.polling.set(this.cm.options.pollInterval, function () {
|
||
this$1.poll();
|
||
if (this$1.cm.state.focused) { this$1.slowPoll(); }
|
||
});
|
||
};
|
||
|
||
// When an event has just come in that is likely to add or change
|
||
// something in the input textarea, we poll faster, to ensure that
|
||
// the change appears on the screen quickly.
|
||
TextareaInput.prototype.fastPoll = function () {
|
||
var missed = false, input = this;
|
||
input.pollingFast = true;
|
||
function p() {
|
||
var changed = input.poll();
|
||
if (!changed && !missed) {missed = true; input.polling.set(60, p);}
|
||
else {input.pollingFast = false; input.slowPoll();}
|
||
}
|
||
input.polling.set(20, p);
|
||
};
|
||
|
||
// Read input from the textarea, and update the document to match.
|
||
// When something is selected, it is present in the textarea, and
|
||
// selected (unless it is huge, in which case a placeholder is
|
||
// used). When nothing is selected, the cursor sits after previously
|
||
// seen text (can be empty), which is stored in prevInput (we must
|
||
// not reset the textarea when typing, because that breaks IME).
|
||
TextareaInput.prototype.poll = function () {
|
||
var this$1 = this;
|
||
|
||
var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
|
||
// Since this is called a *lot*, try to bail out as cheaply as
|
||
// possible when it is clear that nothing happened. hasSelection
|
||
// will be the case when there is a lot of text in the textarea,
|
||
// in which case reading its value would be expensive.
|
||
if (this.contextMenuPending || !cm.state.focused ||
|
||
(hasSelection(input) && !prevInput && !this.composing) ||
|
||
cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
|
||
{ return false }
|
||
|
||
var text = input.value;
|
||
// If nothing changed, bail.
|
||
if (text == prevInput && !cm.somethingSelected()) { return false }
|
||
// Work around nonsensical selection resetting in IE9/10, and
|
||
// inexplicable appearance of private area unicode characters on
|
||
// some key combos in Mac (#2689).
|
||
if (ie && ie_version >= 9 && this.hasSelection === text ||
|
||
mac && /[\uf700-\uf7ff]/.test(text)) {
|
||
cm.display.input.reset();
|
||
return false
|
||
}
|
||
|
||
if (cm.doc.sel == cm.display.selForContextMenu) {
|
||
var first = text.charCodeAt(0);
|
||
if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
|
||
if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
|
||
}
|
||
// Find the part of the input that is actually new
|
||
var same = 0, l = Math.min(prevInput.length, text.length);
|
||
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
|
||
|
||
runInOp(cm, function () {
|
||
applyTextInput(cm, text.slice(same), prevInput.length - same,
|
||
null, this$1.composing ? "*compose" : null);
|
||
|
||
// Don't leave long text in the textarea, since it makes further polling slow
|
||
if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
|
||
else { this$1.prevInput = text; }
|
||
|
||
if (this$1.composing) {
|
||
this$1.composing.range.clear();
|
||
this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
|
||
{className: "CodeMirror-composing"});
|
||
}
|
||
});
|
||
return true
|
||
};
|
||
|
||
TextareaInput.prototype.ensurePolled = function () {
|
||
if (this.pollingFast && this.poll()) { this.pollingFast = false; }
|
||
};
|
||
|
||
TextareaInput.prototype.onKeyPress = function () {
|
||
if (ie && ie_version >= 9) { this.hasSelection = null; }
|
||
this.fastPoll();
|
||
};
|
||
|
||
TextareaInput.prototype.onContextMenu = function (e) {
|
||
var input = this, cm = input.cm, display = cm.display, te = input.textarea;
|
||
if (input.contextMenuPending) { input.contextMenuPending(); }
|
||
var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
|
||
if (!pos || presto) { return } // Opera is difficult.
|
||
|
||
// Reset the current text selection only if the click is done outside of the selection
|
||
// and 'resetSelectionOnContextMenu' option is true.
|
||
var reset = cm.options.resetSelectionOnContextMenu;
|
||
if (reset && cm.doc.sel.contains(pos) == -1)
|
||
{ operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
|
||
|
||
var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
|
||
var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect();
|
||
input.wrapper.style.cssText = "position: static";
|
||
te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
|
||
var oldScrollY;
|
||
if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
|
||
display.input.focus();
|
||
if (webkit) { window.scrollTo(null, oldScrollY); }
|
||
display.input.reset();
|
||
// Adds "Select all" to context menu in FF
|
||
if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
|
||
input.contextMenuPending = rehide;
|
||
display.selForContextMenu = cm.doc.sel;
|
||
clearTimeout(display.detectingSelectAll);
|
||
|
||
// Select-all will be greyed out if there's nothing to select, so
|
||
// this adds a zero-width space so that we can later check whether
|
||
// it got selected.
|
||
function prepareSelectAllHack() {
|
||
if (te.selectionStart != null) {
|
||
var selected = cm.somethingSelected();
|
||
var extval = "\u200b" + (selected ? te.value : "");
|
||
te.value = "\u21da"; // Used to catch context-menu undo
|
||
te.value = extval;
|
||
input.prevInput = selected ? "" : "\u200b";
|
||
te.selectionStart = 1; te.selectionEnd = extval.length;
|
||
// Re-set this, in case some other handler touched the
|
||
// selection in the meantime.
|
||
display.selForContextMenu = cm.doc.sel;
|
||
}
|
||
}
|
||
function rehide() {
|
||
if (input.contextMenuPending != rehide) { return }
|
||
input.contextMenuPending = false;
|
||
input.wrapper.style.cssText = oldWrapperCSS;
|
||
te.style.cssText = oldCSS;
|
||
if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
|
||
|
||
// Try to detect the user choosing select-all
|
||
if (te.selectionStart != null) {
|
||
if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
|
||
var i = 0, poll = function () {
|
||
if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
|
||
te.selectionEnd > 0 && input.prevInput == "\u200b") {
|
||
operation(cm, selectAll)(cm);
|
||
} else if (i++ < 10) {
|
||
display.detectingSelectAll = setTimeout(poll, 500);
|
||
} else {
|
||
display.selForContextMenu = null;
|
||
display.input.reset();
|
||
}
|
||
};
|
||
display.detectingSelectAll = setTimeout(poll, 200);
|
||
}
|
||
}
|
||
|
||
if (ie && ie_version >= 9) { prepareSelectAllHack(); }
|
||
if (captureRightClick) {
|
||
e_stop(e);
|
||
var mouseup = function () {
|
||
off(window, "mouseup", mouseup);
|
||
setTimeout(rehide, 20);
|
||
};
|
||
on(window, "mouseup", mouseup);
|
||
} else {
|
||
setTimeout(rehide, 50);
|
||
}
|
||
};
|
||
|
||
TextareaInput.prototype.readOnlyChanged = function (val) {
|
||
if (!val) { this.reset(); }
|
||
this.textarea.disabled = val == "nocursor";
|
||
};
|
||
|
||
TextareaInput.prototype.setUneditable = function () {};
|
||
|
||
TextareaInput.prototype.needsContentAttribute = false;
|
||
|
||
function fromTextArea(textarea, options) {
|
||
options = options ? copyObj(options) : {};
|
||
options.value = textarea.value;
|
||
if (!options.tabindex && textarea.tabIndex)
|
||
{ options.tabindex = textarea.tabIndex; }
|
||
if (!options.placeholder && textarea.placeholder)
|
||
{ options.placeholder = textarea.placeholder; }
|
||
// Set autofocus to true if this textarea is focused, or if it has
|
||
// autofocus and no other element is focused.
|
||
if (options.autofocus == null) {
|
||
var hasFocus = activeElt();
|
||
options.autofocus = hasFocus == textarea ||
|
||
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
|
||
}
|
||
|
||
function save() {textarea.value = cm.getValue();}
|
||
|
||
var realSubmit;
|
||
if (textarea.form) {
|
||
on(textarea.form, "submit", save);
|
||
// Deplorable hack to make the submit method do the right thing.
|
||
if (!options.leaveSubmitMethodAlone) {
|
||
var form = textarea.form;
|
||
realSubmit = form.submit;
|
||
try {
|
||
var wrappedSubmit = form.submit = function () {
|
||
save();
|
||
form.submit = realSubmit;
|
||
form.submit();
|
||
form.submit = wrappedSubmit;
|
||
};
|
||
} catch(e) {}
|
||
}
|
||
}
|
||
|
||
options.finishInit = function (cm) {
|
||
cm.save = save;
|
||
cm.getTextArea = function () { return textarea; };
|
||
cm.toTextArea = function () {
|
||
cm.toTextArea = isNaN; // Prevent this from being ran twice
|
||
save();
|
||
textarea.parentNode.removeChild(cm.getWrapperElement());
|
||
textarea.style.display = "";
|
||
if (textarea.form) {
|
||
off(textarea.form, "submit", save);
|
||
if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function")
|
||
{ textarea.form.submit = realSubmit; }
|
||
}
|
||
};
|
||
};
|
||
|
||
textarea.style.display = "none";
|
||
var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
|
||
options);
|
||
return cm
|
||
}
|
||
|
||
function addLegacyProps(CodeMirror) {
|
||
CodeMirror.off = off;
|
||
CodeMirror.on = on;
|
||
CodeMirror.wheelEventPixels = wheelEventPixels;
|
||
CodeMirror.Doc = Doc;
|
||
CodeMirror.splitLines = splitLinesAuto;
|
||
CodeMirror.countColumn = countColumn;
|
||
CodeMirror.findColumn = findColumn;
|
||
CodeMirror.isWordChar = isWordCharBasic;
|
||
CodeMirror.Pass = Pass;
|
||
CodeMirror.signal = signal;
|
||
CodeMirror.Line = Line;
|
||
CodeMirror.changeEnd = changeEnd;
|
||
CodeMirror.scrollbarModel = scrollbarModel;
|
||
CodeMirror.Pos = Pos;
|
||
CodeMirror.cmpPos = cmp;
|
||
CodeMirror.modes = modes;
|
||
CodeMirror.mimeModes = mimeModes;
|
||
CodeMirror.resolveMode = resolveMode;
|
||
CodeMirror.getMode = getMode;
|
||
CodeMirror.modeExtensions = modeExtensions;
|
||
CodeMirror.extendMode = extendMode;
|
||
CodeMirror.copyState = copyState;
|
||
CodeMirror.startState = startState;
|
||
CodeMirror.innerMode = innerMode;
|
||
CodeMirror.commands = commands;
|
||
CodeMirror.keyMap = keyMap;
|
||
CodeMirror.keyName = keyName;
|
||
CodeMirror.isModifierKey = isModifierKey;
|
||
CodeMirror.lookupKey = lookupKey;
|
||
CodeMirror.normalizeKeyMap = normalizeKeyMap;
|
||
CodeMirror.StringStream = StringStream;
|
||
CodeMirror.SharedTextMarker = SharedTextMarker;
|
||
CodeMirror.TextMarker = TextMarker;
|
||
CodeMirror.LineWidget = LineWidget;
|
||
CodeMirror.e_preventDefault = e_preventDefault;
|
||
CodeMirror.e_stopPropagation = e_stopPropagation;
|
||
CodeMirror.e_stop = e_stop;
|
||
CodeMirror.addClass = addClass;
|
||
CodeMirror.contains = contains;
|
||
CodeMirror.rmClass = rmClass;
|
||
CodeMirror.keyNames = keyNames;
|
||
}
|
||
|
||
// EDITOR CONSTRUCTOR
|
||
|
||
defineOptions(CodeMirror);
|
||
|
||
addEditorMethods(CodeMirror);
|
||
|
||
// Set up methods on CodeMirror's prototype to redirect to the editor's document.
|
||
var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
|
||
for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
|
||
{ CodeMirror.prototype[prop] = (function(method) {
|
||
return function() {return method.apply(this.doc, arguments)}
|
||
})(Doc.prototype[prop]); } }
|
||
|
||
eventMixin(Doc);
|
||
CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
|
||
|
||
// Extra arguments are stored as the mode's dependencies, which is
|
||
// used by (legacy) mechanisms like loadmode.js to automatically
|
||
// load a mode. (Preferred mechanism is the require/define calls.)
|
||
CodeMirror.defineMode = function(name/*, mode, …*/) {
|
||
if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name; }
|
||
defineMode.apply(this, arguments);
|
||
};
|
||
|
||
CodeMirror.defineMIME = defineMIME;
|
||
|
||
// Minimal default mode.
|
||
CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
|
||
CodeMirror.defineMIME("text/plain", "null");
|
||
|
||
// EXTENSIONS
|
||
|
||
CodeMirror.defineExtension = function (name, func) {
|
||
CodeMirror.prototype[name] = func;
|
||
};
|
||
CodeMirror.defineDocExtension = function (name, func) {
|
||
Doc.prototype[name] = func;
|
||
};
|
||
|
||
CodeMirror.fromTextArea = fromTextArea;
|
||
|
||
addLegacyProps(CodeMirror);
|
||
|
||
CodeMirror.version = "5.56.0";
|
||
|
||
return CodeMirror;
|
||
|
||
})));
|
||
|
||
;(function (global, factory) {
|
||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||
typeof define === 'function' && define.amd ? define('moment',factory) :
|
||
global.moment = factory()
|
||
}(this, (function () { 'use strict';
|
||
|
||
var hookCallback;
|
||
|
||
function hooks () {
|
||
return hookCallback.apply(null, arguments);
|
||
}
|
||
|
||
// This is done to register the method called with moment()
|
||
// without creating circular dependencies.
|
||
function setHookCallback (callback) {
|
||
hookCallback = callback;
|
||
}
|
||
|
||
function isArray(input) {
|
||
return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
|
||
}
|
||
|
||
function isObject(input) {
|
||
// IE8 will treat undefined and null as object if it wasn't for
|
||
// input != null
|
||
return input != null && Object.prototype.toString.call(input) === '[object Object]';
|
||
}
|
||
|
||
function isObjectEmpty(obj) {
|
||
if (Object.getOwnPropertyNames) {
|
||
return (Object.getOwnPropertyNames(obj).length === 0);
|
||
} else {
|
||
var k;
|
||
for (k in obj) {
|
||
if (obj.hasOwnProperty(k)) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
function isUndefined(input) {
|
||
return input === void 0;
|
||
}
|
||
|
||
function isNumber(input) {
|
||
return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
|
||
}
|
||
|
||
function isDate(input) {
|
||
return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
|
||
}
|
||
|
||
function map(arr, fn) {
|
||
var res = [], i;
|
||
for (i = 0; i < arr.length; ++i) {
|
||
res.push(fn(arr[i], i));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
function hasOwnProp(a, b) {
|
||
return Object.prototype.hasOwnProperty.call(a, b);
|
||
}
|
||
|
||
function extend(a, b) {
|
||
for (var i in b) {
|
||
if (hasOwnProp(b, i)) {
|
||
a[i] = b[i];
|
||
}
|
||
}
|
||
|
||
if (hasOwnProp(b, 'toString')) {
|
||
a.toString = b.toString;
|
||
}
|
||
|
||
if (hasOwnProp(b, 'valueOf')) {
|
||
a.valueOf = b.valueOf;
|
||
}
|
||
|
||
return a;
|
||
}
|
||
|
||
function createUTC (input, format, locale, strict) {
|
||
return createLocalOrUTC(input, format, locale, strict, true).utc();
|
||
}
|
||
|
||
function defaultParsingFlags() {
|
||
// We need to deep clone this object.
|
||
return {
|
||
empty : false,
|
||
unusedTokens : [],
|
||
unusedInput : [],
|
||
overflow : -2,
|
||
charsLeftOver : 0,
|
||
nullInput : false,
|
||
invalidMonth : null,
|
||
invalidFormat : false,
|
||
userInvalidated : false,
|
||
iso : false,
|
||
parsedDateParts : [],
|
||
meridiem : null,
|
||
rfc2822 : false,
|
||
weekdayMismatch : false
|
||
};
|
||
}
|
||
|
||
function getParsingFlags(m) {
|
||
if (m._pf == null) {
|
||
m._pf = defaultParsingFlags();
|
||
}
|
||
return m._pf;
|
||
}
|
||
|
||
var some;
|
||
if (Array.prototype.some) {
|
||
some = Array.prototype.some;
|
||
} else {
|
||
some = function (fun) {
|
||
var t = Object(this);
|
||
var len = t.length >>> 0;
|
||
|
||
for (var i = 0; i < len; i++) {
|
||
if (i in t && fun.call(this, t[i], i, t)) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
};
|
||
}
|
||
|
||
function isValid(m) {
|
||
if (m._isValid == null) {
|
||
var flags = getParsingFlags(m);
|
||
var parsedParts = some.call(flags.parsedDateParts, function (i) {
|
||
return i != null;
|
||
});
|
||
var isNowValid = !isNaN(m._d.getTime()) &&
|
||
flags.overflow < 0 &&
|
||
!flags.empty &&
|
||
!flags.invalidMonth &&
|
||
!flags.invalidWeekday &&
|
||
!flags.weekdayMismatch &&
|
||
!flags.nullInput &&
|
||
!flags.invalidFormat &&
|
||
!flags.userInvalidated &&
|
||
(!flags.meridiem || (flags.meridiem && parsedParts));
|
||
|
||
if (m._strict) {
|
||
isNowValid = isNowValid &&
|
||
flags.charsLeftOver === 0 &&
|
||
flags.unusedTokens.length === 0 &&
|
||
flags.bigHour === undefined;
|
||
}
|
||
|
||
if (Object.isFrozen == null || !Object.isFrozen(m)) {
|
||
m._isValid = isNowValid;
|
||
}
|
||
else {
|
||
return isNowValid;
|
||
}
|
||
}
|
||
return m._isValid;
|
||
}
|
||
|
||
function createInvalid (flags) {
|
||
var m = createUTC(NaN);
|
||
if (flags != null) {
|
||
extend(getParsingFlags(m), flags);
|
||
}
|
||
else {
|
||
getParsingFlags(m).userInvalidated = true;
|
||
}
|
||
|
||
return m;
|
||
}
|
||
|
||
// Plugins that add properties should also add the key here (null value),
|
||
// so we can properly clone ourselves.
|
||
var momentProperties = hooks.momentProperties = [];
|
||
|
||
function copyConfig(to, from) {
|
||
var i, prop, val;
|
||
|
||
if (!isUndefined(from._isAMomentObject)) {
|
||
to._isAMomentObject = from._isAMomentObject;
|
||
}
|
||
if (!isUndefined(from._i)) {
|
||
to._i = from._i;
|
||
}
|
||
if (!isUndefined(from._f)) {
|
||
to._f = from._f;
|
||
}
|
||
if (!isUndefined(from._l)) {
|
||
to._l = from._l;
|
||
}
|
||
if (!isUndefined(from._strict)) {
|
||
to._strict = from._strict;
|
||
}
|
||
if (!isUndefined(from._tzm)) {
|
||
to._tzm = from._tzm;
|
||
}
|
||
if (!isUndefined(from._isUTC)) {
|
||
to._isUTC = from._isUTC;
|
||
}
|
||
if (!isUndefined(from._offset)) {
|
||
to._offset = from._offset;
|
||
}
|
||
if (!isUndefined(from._pf)) {
|
||
to._pf = getParsingFlags(from);
|
||
}
|
||
if (!isUndefined(from._locale)) {
|
||
to._locale = from._locale;
|
||
}
|
||
|
||
if (momentProperties.length > 0) {
|
||
for (i = 0; i < momentProperties.length; i++) {
|
||
prop = momentProperties[i];
|
||
val = from[prop];
|
||
if (!isUndefined(val)) {
|
||
to[prop] = val;
|
||
}
|
||
}
|
||
}
|
||
|
||
return to;
|
||
}
|
||
|
||
var updateInProgress = false;
|
||
|
||
// Moment prototype object
|
||
function Moment(config) {
|
||
copyConfig(this, config);
|
||
this._d = new Date(config._d != null ? config._d.getTime() : NaN);
|
||
if (!this.isValid()) {
|
||
this._d = new Date(NaN);
|
||
}
|
||
// Prevent infinite loop in case updateOffset creates new moment
|
||
// objects.
|
||
if (updateInProgress === false) {
|
||
updateInProgress = true;
|
||
hooks.updateOffset(this);
|
||
updateInProgress = false;
|
||
}
|
||
}
|
||
|
||
function isMoment (obj) {
|
||
return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
|
||
}
|
||
|
||
function absFloor (number) {
|
||
if (number < 0) {
|
||
// -0 -> 0
|
||
return Math.ceil(number) || 0;
|
||
} else {
|
||
return Math.floor(number);
|
||
}
|
||
}
|
||
|
||
function toInt(argumentForCoercion) {
|
||
var coercedNumber = +argumentForCoercion,
|
||
value = 0;
|
||
|
||
if (coercedNumber !== 0 && isFinite(coercedNumber)) {
|
||
value = absFloor(coercedNumber);
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
// compare two arrays, return the number of differences
|
||
function compareArrays(array1, array2, dontConvert) {
|
||
var len = Math.min(array1.length, array2.length),
|
||
lengthDiff = Math.abs(array1.length - array2.length),
|
||
diffs = 0,
|
||
i;
|
||
for (i = 0; i < len; i++) {
|
||
if ((dontConvert && array1[i] !== array2[i]) ||
|
||
(!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
|
||
diffs++;
|
||
}
|
||
}
|
||
return diffs + lengthDiff;
|
||
}
|
||
|
||
function warn(msg) {
|
||
if (hooks.suppressDeprecationWarnings === false &&
|
||
(typeof console !== 'undefined') && console.warn) {
|
||
console.warn('Deprecation warning: ' + msg);
|
||
}
|
||
}
|
||
|
||
function deprecate(msg, fn) {
|
||
var firstTime = true;
|
||
|
||
return extend(function () {
|
||
if (hooks.deprecationHandler != null) {
|
||
hooks.deprecationHandler(null, msg);
|
||
}
|
||
if (firstTime) {
|
||
var args = [];
|
||
var arg;
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
arg = '';
|
||
if (typeof arguments[i] === 'object') {
|
||
arg += '\n[' + i + '] ';
|
||
for (var key in arguments[0]) {
|
||
arg += key + ': ' + arguments[0][key] + ', ';
|
||
}
|
||
arg = arg.slice(0, -2); // Remove trailing comma and space
|
||
} else {
|
||
arg = arguments[i];
|
||
}
|
||
args.push(arg);
|
||
}
|
||
warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
|
||
firstTime = false;
|
||
}
|
||
return fn.apply(this, arguments);
|
||
}, fn);
|
||
}
|
||
|
||
var deprecations = {};
|
||
|
||
function deprecateSimple(name, msg) {
|
||
if (hooks.deprecationHandler != null) {
|
||
hooks.deprecationHandler(name, msg);
|
||
}
|
||
if (!deprecations[name]) {
|
||
warn(msg);
|
||
deprecations[name] = true;
|
||
}
|
||
}
|
||
|
||
hooks.suppressDeprecationWarnings = false;
|
||
hooks.deprecationHandler = null;
|
||
|
||
function isFunction(input) {
|
||
return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
|
||
}
|
||
|
||
function set (config) {
|
||
var prop, i;
|
||
for (i in config) {
|
||
prop = config[i];
|
||
if (isFunction(prop)) {
|
||
this[i] = prop;
|
||
} else {
|
||
this['_' + i] = prop;
|
||
}
|
||
}
|
||
this._config = config;
|
||
// Lenient ordinal parsing accepts just a number in addition to
|
||
// number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
|
||
// TODO: Remove "ordinalParse" fallback in next major release.
|
||
this._dayOfMonthOrdinalParseLenient = new RegExp(
|
||
(this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
|
||
'|' + (/\d{1,2}/).source);
|
||
}
|
||
|
||
function mergeConfigs(parentConfig, childConfig) {
|
||
var res = extend({}, parentConfig), prop;
|
||
for (prop in childConfig) {
|
||
if (hasOwnProp(childConfig, prop)) {
|
||
if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
|
||
res[prop] = {};
|
||
extend(res[prop], parentConfig[prop]);
|
||
extend(res[prop], childConfig[prop]);
|
||
} else if (childConfig[prop] != null) {
|
||
res[prop] = childConfig[prop];
|
||
} else {
|
||
delete res[prop];
|
||
}
|
||
}
|
||
}
|
||
for (prop in parentConfig) {
|
||
if (hasOwnProp(parentConfig, prop) &&
|
||
!hasOwnProp(childConfig, prop) &&
|
||
isObject(parentConfig[prop])) {
|
||
// make sure changes to properties don't modify parent config
|
||
res[prop] = extend({}, res[prop]);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
function Locale(config) {
|
||
if (config != null) {
|
||
this.set(config);
|
||
}
|
||
}
|
||
|
||
var keys;
|
||
|
||
if (Object.keys) {
|
||
keys = Object.keys;
|
||
} else {
|
||
keys = function (obj) {
|
||
var i, res = [];
|
||
for (i in obj) {
|
||
if (hasOwnProp(obj, i)) {
|
||
res.push(i);
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
}
|
||
|
||
var defaultCalendar = {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
};
|
||
|
||
function calendar (key, mom, now) {
|
||
var output = this._calendar[key] || this._calendar['sameElse'];
|
||
return isFunction(output) ? output.call(mom, now) : output;
|
||
}
|
||
|
||
var defaultLongDateFormat = {
|
||
LTS : 'h:mm:ss A',
|
||
LT : 'h:mm A',
|
||
L : 'MM/DD/YYYY',
|
||
LL : 'MMMM D, YYYY',
|
||
LLL : 'MMMM D, YYYY h:mm A',
|
||
LLLL : 'dddd, MMMM D, YYYY h:mm A'
|
||
};
|
||
|
||
function longDateFormat (key) {
|
||
var format = this._longDateFormat[key],
|
||
formatUpper = this._longDateFormat[key.toUpperCase()];
|
||
|
||
if (format || !formatUpper) {
|
||
return format;
|
||
}
|
||
|
||
this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
|
||
return val.slice(1);
|
||
});
|
||
|
||
return this._longDateFormat[key];
|
||
}
|
||
|
||
var defaultInvalidDate = 'Invalid date';
|
||
|
||
function invalidDate () {
|
||
return this._invalidDate;
|
||
}
|
||
|
||
var defaultOrdinal = '%d';
|
||
var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
|
||
|
||
function ordinal (number) {
|
||
return this._ordinal.replace('%d', number);
|
||
}
|
||
|
||
var defaultRelativeTime = {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
ss : '%d seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
};
|
||
|
||
function relativeTime (number, withoutSuffix, string, isFuture) {
|
||
var output = this._relativeTime[string];
|
||
return (isFunction(output)) ?
|
||
output(number, withoutSuffix, string, isFuture) :
|
||
output.replace(/%d/i, number);
|
||
}
|
||
|
||
function pastFuture (diff, output) {
|
||
var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
|
||
return isFunction(format) ? format(output) : format.replace(/%s/i, output);
|
||
}
|
||
|
||
var aliases = {};
|
||
|
||
function addUnitAlias (unit, shorthand) {
|
||
var lowerCase = unit.toLowerCase();
|
||
aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
|
||
}
|
||
|
||
function normalizeUnits(units) {
|
||
return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
|
||
}
|
||
|
||
function normalizeObjectUnits(inputObject) {
|
||
var normalizedInput = {},
|
||
normalizedProp,
|
||
prop;
|
||
|
||
for (prop in inputObject) {
|
||
if (hasOwnProp(inputObject, prop)) {
|
||
normalizedProp = normalizeUnits(prop);
|
||
if (normalizedProp) {
|
||
normalizedInput[normalizedProp] = inputObject[prop];
|
||
}
|
||
}
|
||
}
|
||
|
||
return normalizedInput;
|
||
}
|
||
|
||
var priorities = {};
|
||
|
||
function addUnitPriority(unit, priority) {
|
||
priorities[unit] = priority;
|
||
}
|
||
|
||
function getPrioritizedUnits(unitsObj) {
|
||
var units = [];
|
||
for (var u in unitsObj) {
|
||
units.push({unit: u, priority: priorities[u]});
|
||
}
|
||
units.sort(function (a, b) {
|
||
return a.priority - b.priority;
|
||
});
|
||
return units;
|
||
}
|
||
|
||
function zeroFill(number, targetLength, forceSign) {
|
||
var absNumber = '' + Math.abs(number),
|
||
zerosToFill = targetLength - absNumber.length,
|
||
sign = number >= 0;
|
||
return (sign ? (forceSign ? '+' : '') : '-') +
|
||
Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
|
||
}
|
||
|
||
var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
|
||
|
||
var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
|
||
|
||
var formatFunctions = {};
|
||
|
||
var formatTokenFunctions = {};
|
||
|
||
// token: 'M'
|
||
// padded: ['MM', 2]
|
||
// ordinal: 'Mo'
|
||
// callback: function () { this.month() + 1 }
|
||
function addFormatToken (token, padded, ordinal, callback) {
|
||
var func = callback;
|
||
if (typeof callback === 'string') {
|
||
func = function () {
|
||
return this[callback]();
|
||
};
|
||
}
|
||
if (token) {
|
||
formatTokenFunctions[token] = func;
|
||
}
|
||
if (padded) {
|
||
formatTokenFunctions[padded[0]] = function () {
|
||
return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
|
||
};
|
||
}
|
||
if (ordinal) {
|
||
formatTokenFunctions[ordinal] = function () {
|
||
return this.localeData().ordinal(func.apply(this, arguments), token);
|
||
};
|
||
}
|
||
}
|
||
|
||
function removeFormattingTokens(input) {
|
||
if (input.match(/\[[\s\S]/)) {
|
||
return input.replace(/^\[|\]$/g, '');
|
||
}
|
||
return input.replace(/\\/g, '');
|
||
}
|
||
|
||
function makeFormatFunction(format) {
|
||
var array = format.match(formattingTokens), i, length;
|
||
|
||
for (i = 0, length = array.length; i < length; i++) {
|
||
if (formatTokenFunctions[array[i]]) {
|
||
array[i] = formatTokenFunctions[array[i]];
|
||
} else {
|
||
array[i] = removeFormattingTokens(array[i]);
|
||
}
|
||
}
|
||
|
||
return function (mom) {
|
||
var output = '', i;
|
||
for (i = 0; i < length; i++) {
|
||
output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
|
||
}
|
||
return output;
|
||
};
|
||
}
|
||
|
||
// format date using native date object
|
||
function formatMoment(m, format) {
|
||
if (!m.isValid()) {
|
||
return m.localeData().invalidDate();
|
||
}
|
||
|
||
format = expandFormat(format, m.localeData());
|
||
formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
|
||
|
||
return formatFunctions[format](m);
|
||
}
|
||
|
||
function expandFormat(format, locale) {
|
||
var i = 5;
|
||
|
||
function replaceLongDateFormatTokens(input) {
|
||
return locale.longDateFormat(input) || input;
|
||
}
|
||
|
||
localFormattingTokens.lastIndex = 0;
|
||
while (i >= 0 && localFormattingTokens.test(format)) {
|
||
format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
|
||
localFormattingTokens.lastIndex = 0;
|
||
i -= 1;
|
||
}
|
||
|
||
return format;
|
||
}
|
||
|
||
var match1 = /\d/; // 0 - 9
|
||
var match2 = /\d\d/; // 00 - 99
|
||
var match3 = /\d{3}/; // 000 - 999
|
||
var match4 = /\d{4}/; // 0000 - 9999
|
||
var match6 = /[+-]?\d{6}/; // -999999 - 999999
|
||
var match1to2 = /\d\d?/; // 0 - 99
|
||
var match3to4 = /\d\d\d\d?/; // 999 - 9999
|
||
var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
|
||
var match1to3 = /\d{1,3}/; // 0 - 999
|
||
var match1to4 = /\d{1,4}/; // 0 - 9999
|
||
var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
|
||
|
||
var matchUnsigned = /\d+/; // 0 - inf
|
||
var matchSigned = /[+-]?\d+/; // -inf - inf
|
||
|
||
var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
|
||
var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
|
||
|
||
var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
|
||
|
||
// any word (or two) characters or numbers including two/three word month in arabic.
|
||
// includes scottish gaelic two word and hyphenated months
|
||
var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
|
||
|
||
|
||
var regexes = {};
|
||
|
||
function addRegexToken (token, regex, strictRegex) {
|
||
regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
|
||
return (isStrict && strictRegex) ? strictRegex : regex;
|
||
};
|
||
}
|
||
|
||
function getParseRegexForToken (token, config) {
|
||
if (!hasOwnProp(regexes, token)) {
|
||
return new RegExp(unescapeFormat(token));
|
||
}
|
||
|
||
return regexes[token](config._strict, config._locale);
|
||
}
|
||
|
||
// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
|
||
function unescapeFormat(s) {
|
||
return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
|
||
return p1 || p2 || p3 || p4;
|
||
}));
|
||
}
|
||
|
||
function regexEscape(s) {
|
||
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||
}
|
||
|
||
var tokens = {};
|
||
|
||
function addParseToken (token, callback) {
|
||
var i, func = callback;
|
||
if (typeof token === 'string') {
|
||
token = [token];
|
||
}
|
||
if (isNumber(callback)) {
|
||
func = function (input, array) {
|
||
array[callback] = toInt(input);
|
||
};
|
||
}
|
||
for (i = 0; i < token.length; i++) {
|
||
tokens[token[i]] = func;
|
||
}
|
||
}
|
||
|
||
function addWeekParseToken (token, callback) {
|
||
addParseToken(token, function (input, array, config, token) {
|
||
config._w = config._w || {};
|
||
callback(input, config._w, config, token);
|
||
});
|
||
}
|
||
|
||
function addTimeToArrayFromToken(token, input, config) {
|
||
if (input != null && hasOwnProp(tokens, token)) {
|
||
tokens[token](input, config._a, config, token);
|
||
}
|
||
}
|
||
|
||
var YEAR = 0;
|
||
var MONTH = 1;
|
||
var DATE = 2;
|
||
var HOUR = 3;
|
||
var MINUTE = 4;
|
||
var SECOND = 5;
|
||
var MILLISECOND = 6;
|
||
var WEEK = 7;
|
||
var WEEKDAY = 8;
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('Y', 0, 0, function () {
|
||
var y = this.year();
|
||
return y <= 9999 ? '' + y : '+' + y;
|
||
});
|
||
|
||
addFormatToken(0, ['YY', 2], 0, function () {
|
||
return this.year() % 100;
|
||
});
|
||
|
||
addFormatToken(0, ['YYYY', 4], 0, 'year');
|
||
addFormatToken(0, ['YYYYY', 5], 0, 'year');
|
||
addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('year', 'y');
|
||
|
||
// PRIORITIES
|
||
|
||
addUnitPriority('year', 1);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('Y', matchSigned);
|
||
addRegexToken('YY', match1to2, match2);
|
||
addRegexToken('YYYY', match1to4, match4);
|
||
addRegexToken('YYYYY', match1to6, match6);
|
||
addRegexToken('YYYYYY', match1to6, match6);
|
||
|
||
addParseToken(['YYYYY', 'YYYYYY'], YEAR);
|
||
addParseToken('YYYY', function (input, array) {
|
||
array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
|
||
});
|
||
addParseToken('YY', function (input, array) {
|
||
array[YEAR] = hooks.parseTwoDigitYear(input);
|
||
});
|
||
addParseToken('Y', function (input, array) {
|
||
array[YEAR] = parseInt(input, 10);
|
||
});
|
||
|
||
// HELPERS
|
||
|
||
function daysInYear(year) {
|
||
return isLeapYear(year) ? 366 : 365;
|
||
}
|
||
|
||
function isLeapYear(year) {
|
||
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
||
}
|
||
|
||
// HOOKS
|
||
|
||
hooks.parseTwoDigitYear = function (input) {
|
||
return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
|
||
};
|
||
|
||
// MOMENTS
|
||
|
||
var getSetYear = makeGetSet('FullYear', true);
|
||
|
||
function getIsLeapYear () {
|
||
return isLeapYear(this.year());
|
||
}
|
||
|
||
function makeGetSet (unit, keepTime) {
|
||
return function (value) {
|
||
if (value != null) {
|
||
set$1(this, unit, value);
|
||
hooks.updateOffset(this, keepTime);
|
||
return this;
|
||
} else {
|
||
return get(this, unit);
|
||
}
|
||
};
|
||
}
|
||
|
||
function get (mom, unit) {
|
||
return mom.isValid() ?
|
||
mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
|
||
}
|
||
|
||
function set$1 (mom, unit, value) {
|
||
if (mom.isValid() && !isNaN(value)) {
|
||
if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
|
||
mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
|
||
}
|
||
else {
|
||
mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
|
||
}
|
||
}
|
||
}
|
||
|
||
// MOMENTS
|
||
|
||
function stringGet (units) {
|
||
units = normalizeUnits(units);
|
||
if (isFunction(this[units])) {
|
||
return this[units]();
|
||
}
|
||
return this;
|
||
}
|
||
|
||
|
||
function stringSet (units, value) {
|
||
if (typeof units === 'object') {
|
||
units = normalizeObjectUnits(units);
|
||
var prioritized = getPrioritizedUnits(units);
|
||
for (var i = 0; i < prioritized.length; i++) {
|
||
this[prioritized[i].unit](units[prioritized[i].unit]);
|
||
}
|
||
} else {
|
||
units = normalizeUnits(units);
|
||
if (isFunction(this[units])) {
|
||
return this[units](value);
|
||
}
|
||
}
|
||
return this;
|
||
}
|
||
|
||
function mod(n, x) {
|
||
return ((n % x) + x) % x;
|
||
}
|
||
|
||
var indexOf;
|
||
|
||
if (Array.prototype.indexOf) {
|
||
indexOf = Array.prototype.indexOf;
|
||
} else {
|
||
indexOf = function (o) {
|
||
// I know
|
||
var i;
|
||
for (i = 0; i < this.length; ++i) {
|
||
if (this[i] === o) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
};
|
||
}
|
||
|
||
function daysInMonth(year, month) {
|
||
if (isNaN(year) || isNaN(month)) {
|
||
return NaN;
|
||
}
|
||
var modMonth = mod(month, 12);
|
||
year += (month - modMonth) / 12;
|
||
return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('M', ['MM', 2], 'Mo', function () {
|
||
return this.month() + 1;
|
||
});
|
||
|
||
addFormatToken('MMM', 0, 0, function (format) {
|
||
return this.localeData().monthsShort(this, format);
|
||
});
|
||
|
||
addFormatToken('MMMM', 0, 0, function (format) {
|
||
return this.localeData().months(this, format);
|
||
});
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('month', 'M');
|
||
|
||
// PRIORITY
|
||
|
||
addUnitPriority('month', 8);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('M', match1to2);
|
||
addRegexToken('MM', match1to2, match2);
|
||
addRegexToken('MMM', function (isStrict, locale) {
|
||
return locale.monthsShortRegex(isStrict);
|
||
});
|
||
addRegexToken('MMMM', function (isStrict, locale) {
|
||
return locale.monthsRegex(isStrict);
|
||
});
|
||
|
||
addParseToken(['M', 'MM'], function (input, array) {
|
||
array[MONTH] = toInt(input) - 1;
|
||
});
|
||
|
||
addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
|
||
var month = config._locale.monthsParse(input, token, config._strict);
|
||
// if we didn't find a month name, mark the date as invalid.
|
||
if (month != null) {
|
||
array[MONTH] = month;
|
||
} else {
|
||
getParsingFlags(config).invalidMonth = input;
|
||
}
|
||
});
|
||
|
||
// LOCALES
|
||
|
||
var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
|
||
var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
|
||
function localeMonths (m, format) {
|
||
if (!m) {
|
||
return isArray(this._months) ? this._months :
|
||
this._months['standalone'];
|
||
}
|
||
return isArray(this._months) ? this._months[m.month()] :
|
||
this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
|
||
}
|
||
|
||
var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
|
||
function localeMonthsShort (m, format) {
|
||
if (!m) {
|
||
return isArray(this._monthsShort) ? this._monthsShort :
|
||
this._monthsShort['standalone'];
|
||
}
|
||
return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
|
||
this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
|
||
}
|
||
|
||
function handleStrictParse(monthName, format, strict) {
|
||
var i, ii, mom, llc = monthName.toLocaleLowerCase();
|
||
if (!this._monthsParse) {
|
||
// this is not used
|
||
this._monthsParse = [];
|
||
this._longMonthsParse = [];
|
||
this._shortMonthsParse = [];
|
||
for (i = 0; i < 12; ++i) {
|
||
mom = createUTC([2000, i]);
|
||
this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
|
||
this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
|
||
}
|
||
}
|
||
|
||
if (strict) {
|
||
if (format === 'MMM') {
|
||
ii = indexOf.call(this._shortMonthsParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
} else {
|
||
ii = indexOf.call(this._longMonthsParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
}
|
||
} else {
|
||
if (format === 'MMM') {
|
||
ii = indexOf.call(this._shortMonthsParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._longMonthsParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
} else {
|
||
ii = indexOf.call(this._longMonthsParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._shortMonthsParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
}
|
||
}
|
||
}
|
||
|
||
function localeMonthsParse (monthName, format, strict) {
|
||
var i, mom, regex;
|
||
|
||
if (this._monthsParseExact) {
|
||
return handleStrictParse.call(this, monthName, format, strict);
|
||
}
|
||
|
||
if (!this._monthsParse) {
|
||
this._monthsParse = [];
|
||
this._longMonthsParse = [];
|
||
this._shortMonthsParse = [];
|
||
}
|
||
|
||
// TODO: add sorting
|
||
// Sorting makes sure if one month (or abbr) is a prefix of another
|
||
// see sorting in computeMonthsParse
|
||
for (i = 0; i < 12; i++) {
|
||
// make the regex if we don't have it already
|
||
mom = createUTC([2000, i]);
|
||
if (strict && !this._longMonthsParse[i]) {
|
||
this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
|
||
this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
|
||
}
|
||
if (!strict && !this._monthsParse[i]) {
|
||
regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
|
||
this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
||
}
|
||
// test the regex
|
||
if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
|
||
return i;
|
||
} else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
|
||
return i;
|
||
} else if (!strict && this._monthsParse[i].test(monthName)) {
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
|
||
// MOMENTS
|
||
|
||
function setMonth (mom, value) {
|
||
var dayOfMonth;
|
||
|
||
if (!mom.isValid()) {
|
||
// No op
|
||
return mom;
|
||
}
|
||
|
||
if (typeof value === 'string') {
|
||
if (/^\d+$/.test(value)) {
|
||
value = toInt(value);
|
||
} else {
|
||
value = mom.localeData().monthsParse(value);
|
||
// TODO: Another silent failure?
|
||
if (!isNumber(value)) {
|
||
return mom;
|
||
}
|
||
}
|
||
}
|
||
|
||
dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
|
||
mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
|
||
return mom;
|
||
}
|
||
|
||
function getSetMonth (value) {
|
||
if (value != null) {
|
||
setMonth(this, value);
|
||
hooks.updateOffset(this, true);
|
||
return this;
|
||
} else {
|
||
return get(this, 'Month');
|
||
}
|
||
}
|
||
|
||
function getDaysInMonth () {
|
||
return daysInMonth(this.year(), this.month());
|
||
}
|
||
|
||
var defaultMonthsShortRegex = matchWord;
|
||
function monthsShortRegex (isStrict) {
|
||
if (this._monthsParseExact) {
|
||
if (!hasOwnProp(this, '_monthsRegex')) {
|
||
computeMonthsParse.call(this);
|
||
}
|
||
if (isStrict) {
|
||
return this._monthsShortStrictRegex;
|
||
} else {
|
||
return this._monthsShortRegex;
|
||
}
|
||
} else {
|
||
if (!hasOwnProp(this, '_monthsShortRegex')) {
|
||
this._monthsShortRegex = defaultMonthsShortRegex;
|
||
}
|
||
return this._monthsShortStrictRegex && isStrict ?
|
||
this._monthsShortStrictRegex : this._monthsShortRegex;
|
||
}
|
||
}
|
||
|
||
var defaultMonthsRegex = matchWord;
|
||
function monthsRegex (isStrict) {
|
||
if (this._monthsParseExact) {
|
||
if (!hasOwnProp(this, '_monthsRegex')) {
|
||
computeMonthsParse.call(this);
|
||
}
|
||
if (isStrict) {
|
||
return this._monthsStrictRegex;
|
||
} else {
|
||
return this._monthsRegex;
|
||
}
|
||
} else {
|
||
if (!hasOwnProp(this, '_monthsRegex')) {
|
||
this._monthsRegex = defaultMonthsRegex;
|
||
}
|
||
return this._monthsStrictRegex && isStrict ?
|
||
this._monthsStrictRegex : this._monthsRegex;
|
||
}
|
||
}
|
||
|
||
function computeMonthsParse () {
|
||
function cmpLenRev(a, b) {
|
||
return b.length - a.length;
|
||
}
|
||
|
||
var shortPieces = [], longPieces = [], mixedPieces = [],
|
||
i, mom;
|
||
for (i = 0; i < 12; i++) {
|
||
// make the regex if we don't have it already
|
||
mom = createUTC([2000, i]);
|
||
shortPieces.push(this.monthsShort(mom, ''));
|
||
longPieces.push(this.months(mom, ''));
|
||
mixedPieces.push(this.months(mom, ''));
|
||
mixedPieces.push(this.monthsShort(mom, ''));
|
||
}
|
||
// Sorting makes sure if one month (or abbr) is a prefix of another it
|
||
// will match the longer piece.
|
||
shortPieces.sort(cmpLenRev);
|
||
longPieces.sort(cmpLenRev);
|
||
mixedPieces.sort(cmpLenRev);
|
||
for (i = 0; i < 12; i++) {
|
||
shortPieces[i] = regexEscape(shortPieces[i]);
|
||
longPieces[i] = regexEscape(longPieces[i]);
|
||
}
|
||
for (i = 0; i < 24; i++) {
|
||
mixedPieces[i] = regexEscape(mixedPieces[i]);
|
||
}
|
||
|
||
this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
|
||
this._monthsShortRegex = this._monthsRegex;
|
||
this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
|
||
this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
|
||
}
|
||
|
||
function createDate (y, m, d, h, M, s, ms) {
|
||
// can't just apply() to create a date:
|
||
// https://stackoverflow.com/q/181348
|
||
var date = new Date(y, m, d, h, M, s, ms);
|
||
|
||
// the date constructor remaps years 0-99 to 1900-1999
|
||
if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
|
||
date.setFullYear(y);
|
||
}
|
||
return date;
|
||
}
|
||
|
||
function createUTCDate (y) {
|
||
var date = new Date(Date.UTC.apply(null, arguments));
|
||
|
||
// the Date.UTC function remaps years 0-99 to 1900-1999
|
||
if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
|
||
date.setUTCFullYear(y);
|
||
}
|
||
return date;
|
||
}
|
||
|
||
// start-of-first-week - start-of-year
|
||
function firstWeekOffset(year, dow, doy) {
|
||
var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
|
||
fwd = 7 + dow - doy,
|
||
// first-week day local weekday -- which local weekday is fwd
|
||
fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
|
||
|
||
return -fwdlw + fwd - 1;
|
||
}
|
||
|
||
// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
|
||
function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
|
||
var localWeekday = (7 + weekday - dow) % 7,
|
||
weekOffset = firstWeekOffset(year, dow, doy),
|
||
dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
|
||
resYear, resDayOfYear;
|
||
|
||
if (dayOfYear <= 0) {
|
||
resYear = year - 1;
|
||
resDayOfYear = daysInYear(resYear) + dayOfYear;
|
||
} else if (dayOfYear > daysInYear(year)) {
|
||
resYear = year + 1;
|
||
resDayOfYear = dayOfYear - daysInYear(year);
|
||
} else {
|
||
resYear = year;
|
||
resDayOfYear = dayOfYear;
|
||
}
|
||
|
||
return {
|
||
year: resYear,
|
||
dayOfYear: resDayOfYear
|
||
};
|
||
}
|
||
|
||
function weekOfYear(mom, dow, doy) {
|
||
var weekOffset = firstWeekOffset(mom.year(), dow, doy),
|
||
week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
|
||
resWeek, resYear;
|
||
|
||
if (week < 1) {
|
||
resYear = mom.year() - 1;
|
||
resWeek = week + weeksInYear(resYear, dow, doy);
|
||
} else if (week > weeksInYear(mom.year(), dow, doy)) {
|
||
resWeek = week - weeksInYear(mom.year(), dow, doy);
|
||
resYear = mom.year() + 1;
|
||
} else {
|
||
resYear = mom.year();
|
||
resWeek = week;
|
||
}
|
||
|
||
return {
|
||
week: resWeek,
|
||
year: resYear
|
||
};
|
||
}
|
||
|
||
function weeksInYear(year, dow, doy) {
|
||
var weekOffset = firstWeekOffset(year, dow, doy),
|
||
weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
|
||
return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('w', ['ww', 2], 'wo', 'week');
|
||
addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('week', 'w');
|
||
addUnitAlias('isoWeek', 'W');
|
||
|
||
// PRIORITIES
|
||
|
||
addUnitPriority('week', 5);
|
||
addUnitPriority('isoWeek', 5);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('w', match1to2);
|
||
addRegexToken('ww', match1to2, match2);
|
||
addRegexToken('W', match1to2);
|
||
addRegexToken('WW', match1to2, match2);
|
||
|
||
addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
|
||
week[token.substr(0, 1)] = toInt(input);
|
||
});
|
||
|
||
// HELPERS
|
||
|
||
// LOCALES
|
||
|
||
function localeWeek (mom) {
|
||
return weekOfYear(mom, this._week.dow, this._week.doy).week;
|
||
}
|
||
|
||
var defaultLocaleWeek = {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
};
|
||
|
||
function localeFirstDayOfWeek () {
|
||
return this._week.dow;
|
||
}
|
||
|
||
function localeFirstDayOfYear () {
|
||
return this._week.doy;
|
||
}
|
||
|
||
// MOMENTS
|
||
|
||
function getSetWeek (input) {
|
||
var week = this.localeData().week(this);
|
||
return input == null ? week : this.add((input - week) * 7, 'd');
|
||
}
|
||
|
||
function getSetISOWeek (input) {
|
||
var week = weekOfYear(this, 1, 4).week;
|
||
return input == null ? week : this.add((input - week) * 7, 'd');
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('d', 0, 'do', 'day');
|
||
|
||
addFormatToken('dd', 0, 0, function (format) {
|
||
return this.localeData().weekdaysMin(this, format);
|
||
});
|
||
|
||
addFormatToken('ddd', 0, 0, function (format) {
|
||
return this.localeData().weekdaysShort(this, format);
|
||
});
|
||
|
||
addFormatToken('dddd', 0, 0, function (format) {
|
||
return this.localeData().weekdays(this, format);
|
||
});
|
||
|
||
addFormatToken('e', 0, 0, 'weekday');
|
||
addFormatToken('E', 0, 0, 'isoWeekday');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('day', 'd');
|
||
addUnitAlias('weekday', 'e');
|
||
addUnitAlias('isoWeekday', 'E');
|
||
|
||
// PRIORITY
|
||
addUnitPriority('day', 11);
|
||
addUnitPriority('weekday', 11);
|
||
addUnitPriority('isoWeekday', 11);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('d', match1to2);
|
||
addRegexToken('e', match1to2);
|
||
addRegexToken('E', match1to2);
|
||
addRegexToken('dd', function (isStrict, locale) {
|
||
return locale.weekdaysMinRegex(isStrict);
|
||
});
|
||
addRegexToken('ddd', function (isStrict, locale) {
|
||
return locale.weekdaysShortRegex(isStrict);
|
||
});
|
||
addRegexToken('dddd', function (isStrict, locale) {
|
||
return locale.weekdaysRegex(isStrict);
|
||
});
|
||
|
||
addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
|
||
var weekday = config._locale.weekdaysParse(input, token, config._strict);
|
||
// if we didn't get a weekday name, mark the date as invalid
|
||
if (weekday != null) {
|
||
week.d = weekday;
|
||
} else {
|
||
getParsingFlags(config).invalidWeekday = input;
|
||
}
|
||
});
|
||
|
||
addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
|
||
week[token] = toInt(input);
|
||
});
|
||
|
||
// HELPERS
|
||
|
||
function parseWeekday(input, locale) {
|
||
if (typeof input !== 'string') {
|
||
return input;
|
||
}
|
||
|
||
if (!isNaN(input)) {
|
||
return parseInt(input, 10);
|
||
}
|
||
|
||
input = locale.weekdaysParse(input);
|
||
if (typeof input === 'number') {
|
||
return input;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function parseIsoWeekday(input, locale) {
|
||
if (typeof input === 'string') {
|
||
return locale.weekdaysParse(input) % 7 || 7;
|
||
}
|
||
return isNaN(input) ? null : input;
|
||
}
|
||
|
||
// LOCALES
|
||
|
||
var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
|
||
function localeWeekdays (m, format) {
|
||
if (!m) {
|
||
return isArray(this._weekdays) ? this._weekdays :
|
||
this._weekdays['standalone'];
|
||
}
|
||
return isArray(this._weekdays) ? this._weekdays[m.day()] :
|
||
this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
|
||
}
|
||
|
||
var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
|
||
function localeWeekdaysShort (m) {
|
||
return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
|
||
}
|
||
|
||
var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
|
||
function localeWeekdaysMin (m) {
|
||
return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
|
||
}
|
||
|
||
function handleStrictParse$1(weekdayName, format, strict) {
|
||
var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
|
||
if (!this._weekdaysParse) {
|
||
this._weekdaysParse = [];
|
||
this._shortWeekdaysParse = [];
|
||
this._minWeekdaysParse = [];
|
||
|
||
for (i = 0; i < 7; ++i) {
|
||
mom = createUTC([2000, 1]).day(i);
|
||
this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
|
||
this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
|
||
this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
|
||
}
|
||
}
|
||
|
||
if (strict) {
|
||
if (format === 'dddd') {
|
||
ii = indexOf.call(this._weekdaysParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
} else if (format === 'ddd') {
|
||
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
} else {
|
||
ii = indexOf.call(this._minWeekdaysParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
}
|
||
} else {
|
||
if (format === 'dddd') {
|
||
ii = indexOf.call(this._weekdaysParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._minWeekdaysParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
} else if (format === 'ddd') {
|
||
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._weekdaysParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._minWeekdaysParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
} else {
|
||
ii = indexOf.call(this._minWeekdaysParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._weekdaysParse, llc);
|
||
if (ii !== -1) {
|
||
return ii;
|
||
}
|
||
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
||
return ii !== -1 ? ii : null;
|
||
}
|
||
}
|
||
}
|
||
|
||
function localeWeekdaysParse (weekdayName, format, strict) {
|
||
var i, mom, regex;
|
||
|
||
if (this._weekdaysParseExact) {
|
||
return handleStrictParse$1.call(this, weekdayName, format, strict);
|
||
}
|
||
|
||
if (!this._weekdaysParse) {
|
||
this._weekdaysParse = [];
|
||
this._minWeekdaysParse = [];
|
||
this._shortWeekdaysParse = [];
|
||
this._fullWeekdaysParse = [];
|
||
}
|
||
|
||
for (i = 0; i < 7; i++) {
|
||
// make the regex if we don't have it already
|
||
|
||
mom = createUTC([2000, 1]).day(i);
|
||
if (strict && !this._fullWeekdaysParse[i]) {
|
||
this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
|
||
this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
|
||
this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
|
||
}
|
||
if (!this._weekdaysParse[i]) {
|
||
regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
|
||
this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
||
}
|
||
// test the regex
|
||
if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
|
||
return i;
|
||
} else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
|
||
return i;
|
||
} else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
|
||
return i;
|
||
} else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
|
||
// MOMENTS
|
||
|
||
function getSetDayOfWeek (input) {
|
||
if (!this.isValid()) {
|
||
return input != null ? this : NaN;
|
||
}
|
||
var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
|
||
if (input != null) {
|
||
input = parseWeekday(input, this.localeData());
|
||
return this.add(input - day, 'd');
|
||
} else {
|
||
return day;
|
||
}
|
||
}
|
||
|
||
function getSetLocaleDayOfWeek (input) {
|
||
if (!this.isValid()) {
|
||
return input != null ? this : NaN;
|
||
}
|
||
var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
|
||
return input == null ? weekday : this.add(input - weekday, 'd');
|
||
}
|
||
|
||
function getSetISODayOfWeek (input) {
|
||
if (!this.isValid()) {
|
||
return input != null ? this : NaN;
|
||
}
|
||
|
||
// behaves the same as moment#day except
|
||
// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
|
||
// as a setter, sunday should belong to the previous week.
|
||
|
||
if (input != null) {
|
||
var weekday = parseIsoWeekday(input, this.localeData());
|
||
return this.day(this.day() % 7 ? weekday : weekday - 7);
|
||
} else {
|
||
return this.day() || 7;
|
||
}
|
||
}
|
||
|
||
var defaultWeekdaysRegex = matchWord;
|
||
function weekdaysRegex (isStrict) {
|
||
if (this._weekdaysParseExact) {
|
||
if (!hasOwnProp(this, '_weekdaysRegex')) {
|
||
computeWeekdaysParse.call(this);
|
||
}
|
||
if (isStrict) {
|
||
return this._weekdaysStrictRegex;
|
||
} else {
|
||
return this._weekdaysRegex;
|
||
}
|
||
} else {
|
||
if (!hasOwnProp(this, '_weekdaysRegex')) {
|
||
this._weekdaysRegex = defaultWeekdaysRegex;
|
||
}
|
||
return this._weekdaysStrictRegex && isStrict ?
|
||
this._weekdaysStrictRegex : this._weekdaysRegex;
|
||
}
|
||
}
|
||
|
||
var defaultWeekdaysShortRegex = matchWord;
|
||
function weekdaysShortRegex (isStrict) {
|
||
if (this._weekdaysParseExact) {
|
||
if (!hasOwnProp(this, '_weekdaysRegex')) {
|
||
computeWeekdaysParse.call(this);
|
||
}
|
||
if (isStrict) {
|
||
return this._weekdaysShortStrictRegex;
|
||
} else {
|
||
return this._weekdaysShortRegex;
|
||
}
|
||
} else {
|
||
if (!hasOwnProp(this, '_weekdaysShortRegex')) {
|
||
this._weekdaysShortRegex = defaultWeekdaysShortRegex;
|
||
}
|
||
return this._weekdaysShortStrictRegex && isStrict ?
|
||
this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
|
||
}
|
||
}
|
||
|
||
var defaultWeekdaysMinRegex = matchWord;
|
||
function weekdaysMinRegex (isStrict) {
|
||
if (this._weekdaysParseExact) {
|
||
if (!hasOwnProp(this, '_weekdaysRegex')) {
|
||
computeWeekdaysParse.call(this);
|
||
}
|
||
if (isStrict) {
|
||
return this._weekdaysMinStrictRegex;
|
||
} else {
|
||
return this._weekdaysMinRegex;
|
||
}
|
||
} else {
|
||
if (!hasOwnProp(this, '_weekdaysMinRegex')) {
|
||
this._weekdaysMinRegex = defaultWeekdaysMinRegex;
|
||
}
|
||
return this._weekdaysMinStrictRegex && isStrict ?
|
||
this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
|
||
}
|
||
}
|
||
|
||
|
||
function computeWeekdaysParse () {
|
||
function cmpLenRev(a, b) {
|
||
return b.length - a.length;
|
||
}
|
||
|
||
var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
|
||
i, mom, minp, shortp, longp;
|
||
for (i = 0; i < 7; i++) {
|
||
// make the regex if we don't have it already
|
||
mom = createUTC([2000, 1]).day(i);
|
||
minp = this.weekdaysMin(mom, '');
|
||
shortp = this.weekdaysShort(mom, '');
|
||
longp = this.weekdays(mom, '');
|
||
minPieces.push(minp);
|
||
shortPieces.push(shortp);
|
||
longPieces.push(longp);
|
||
mixedPieces.push(minp);
|
||
mixedPieces.push(shortp);
|
||
mixedPieces.push(longp);
|
||
}
|
||
// Sorting makes sure if one weekday (or abbr) is a prefix of another it
|
||
// will match the longer piece.
|
||
minPieces.sort(cmpLenRev);
|
||
shortPieces.sort(cmpLenRev);
|
||
longPieces.sort(cmpLenRev);
|
||
mixedPieces.sort(cmpLenRev);
|
||
for (i = 0; i < 7; i++) {
|
||
shortPieces[i] = regexEscape(shortPieces[i]);
|
||
longPieces[i] = regexEscape(longPieces[i]);
|
||
mixedPieces[i] = regexEscape(mixedPieces[i]);
|
||
}
|
||
|
||
this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
|
||
this._weekdaysShortRegex = this._weekdaysRegex;
|
||
this._weekdaysMinRegex = this._weekdaysRegex;
|
||
|
||
this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
|
||
this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
|
||
this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
function hFormat() {
|
||
return this.hours() % 12 || 12;
|
||
}
|
||
|
||
function kFormat() {
|
||
return this.hours() || 24;
|
||
}
|
||
|
||
addFormatToken('H', ['HH', 2], 0, 'hour');
|
||
addFormatToken('h', ['hh', 2], 0, hFormat);
|
||
addFormatToken('k', ['kk', 2], 0, kFormat);
|
||
|
||
addFormatToken('hmm', 0, 0, function () {
|
||
return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
|
||
});
|
||
|
||
addFormatToken('hmmss', 0, 0, function () {
|
||
return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
|
||
zeroFill(this.seconds(), 2);
|
||
});
|
||
|
||
addFormatToken('Hmm', 0, 0, function () {
|
||
return '' + this.hours() + zeroFill(this.minutes(), 2);
|
||
});
|
||
|
||
addFormatToken('Hmmss', 0, 0, function () {
|
||
return '' + this.hours() + zeroFill(this.minutes(), 2) +
|
||
zeroFill(this.seconds(), 2);
|
||
});
|
||
|
||
function meridiem (token, lowercase) {
|
||
addFormatToken(token, 0, 0, function () {
|
||
return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
|
||
});
|
||
}
|
||
|
||
meridiem('a', true);
|
||
meridiem('A', false);
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('hour', 'h');
|
||
|
||
// PRIORITY
|
||
addUnitPriority('hour', 13);
|
||
|
||
// PARSING
|
||
|
||
function matchMeridiem (isStrict, locale) {
|
||
return locale._meridiemParse;
|
||
}
|
||
|
||
addRegexToken('a', matchMeridiem);
|
||
addRegexToken('A', matchMeridiem);
|
||
addRegexToken('H', match1to2);
|
||
addRegexToken('h', match1to2);
|
||
addRegexToken('k', match1to2);
|
||
addRegexToken('HH', match1to2, match2);
|
||
addRegexToken('hh', match1to2, match2);
|
||
addRegexToken('kk', match1to2, match2);
|
||
|
||
addRegexToken('hmm', match3to4);
|
||
addRegexToken('hmmss', match5to6);
|
||
addRegexToken('Hmm', match3to4);
|
||
addRegexToken('Hmmss', match5to6);
|
||
|
||
addParseToken(['H', 'HH'], HOUR);
|
||
addParseToken(['k', 'kk'], function (input, array, config) {
|
||
var kInput = toInt(input);
|
||
array[HOUR] = kInput === 24 ? 0 : kInput;
|
||
});
|
||
addParseToken(['a', 'A'], function (input, array, config) {
|
||
config._isPm = config._locale.isPM(input);
|
||
config._meridiem = input;
|
||
});
|
||
addParseToken(['h', 'hh'], function (input, array, config) {
|
||
array[HOUR] = toInt(input);
|
||
getParsingFlags(config).bigHour = true;
|
||
});
|
||
addParseToken('hmm', function (input, array, config) {
|
||
var pos = input.length - 2;
|
||
array[HOUR] = toInt(input.substr(0, pos));
|
||
array[MINUTE] = toInt(input.substr(pos));
|
||
getParsingFlags(config).bigHour = true;
|
||
});
|
||
addParseToken('hmmss', function (input, array, config) {
|
||
var pos1 = input.length - 4;
|
||
var pos2 = input.length - 2;
|
||
array[HOUR] = toInt(input.substr(0, pos1));
|
||
array[MINUTE] = toInt(input.substr(pos1, 2));
|
||
array[SECOND] = toInt(input.substr(pos2));
|
||
getParsingFlags(config).bigHour = true;
|
||
});
|
||
addParseToken('Hmm', function (input, array, config) {
|
||
var pos = input.length - 2;
|
||
array[HOUR] = toInt(input.substr(0, pos));
|
||
array[MINUTE] = toInt(input.substr(pos));
|
||
});
|
||
addParseToken('Hmmss', function (input, array, config) {
|
||
var pos1 = input.length - 4;
|
||
var pos2 = input.length - 2;
|
||
array[HOUR] = toInt(input.substr(0, pos1));
|
||
array[MINUTE] = toInt(input.substr(pos1, 2));
|
||
array[SECOND] = toInt(input.substr(pos2));
|
||
});
|
||
|
||
// LOCALES
|
||
|
||
function localeIsPM (input) {
|
||
// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
|
||
// Using charAt should be more compatible.
|
||
return ((input + '').toLowerCase().charAt(0) === 'p');
|
||
}
|
||
|
||
var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
|
||
function localeMeridiem (hours, minutes, isLower) {
|
||
if (hours > 11) {
|
||
return isLower ? 'pm' : 'PM';
|
||
} else {
|
||
return isLower ? 'am' : 'AM';
|
||
}
|
||
}
|
||
|
||
|
||
// MOMENTS
|
||
|
||
// Setting the hour should keep the time, because the user explicitly
|
||
// specified which hour he wants. So trying to maintain the same hour (in
|
||
// a new timezone) makes sense. Adding/subtracting hours does not follow
|
||
// this rule.
|
||
var getSetHour = makeGetSet('Hours', true);
|
||
|
||
// months
|
||
// week
|
||
// weekdays
|
||
// meridiem
|
||
var baseConfig = {
|
||
calendar: defaultCalendar,
|
||
longDateFormat: defaultLongDateFormat,
|
||
invalidDate: defaultInvalidDate,
|
||
ordinal: defaultOrdinal,
|
||
dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
|
||
relativeTime: defaultRelativeTime,
|
||
|
||
months: defaultLocaleMonths,
|
||
monthsShort: defaultLocaleMonthsShort,
|
||
|
||
week: defaultLocaleWeek,
|
||
|
||
weekdays: defaultLocaleWeekdays,
|
||
weekdaysMin: defaultLocaleWeekdaysMin,
|
||
weekdaysShort: defaultLocaleWeekdaysShort,
|
||
|
||
meridiemParse: defaultLocaleMeridiemParse
|
||
};
|
||
|
||
// internal storage for locale config files
|
||
var locales = {};
|
||
var localeFamilies = {};
|
||
var globalLocale;
|
||
|
||
function normalizeLocale(key) {
|
||
return key ? key.toLowerCase().replace('_', '-') : key;
|
||
}
|
||
|
||
// pick the locale from the array
|
||
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
|
||
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
|
||
function chooseLocale(names) {
|
||
var i = 0, j, next, locale, split;
|
||
|
||
while (i < names.length) {
|
||
split = normalizeLocale(names[i]).split('-');
|
||
j = split.length;
|
||
next = normalizeLocale(names[i + 1]);
|
||
next = next ? next.split('-') : null;
|
||
while (j > 0) {
|
||
locale = loadLocale(split.slice(0, j).join('-'));
|
||
if (locale) {
|
||
return locale;
|
||
}
|
||
if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
|
||
//the next array item is better than a shallower substring of this one
|
||
break;
|
||
}
|
||
j--;
|
||
}
|
||
i++;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function loadLocale(name) {
|
||
var oldLocale = null;
|
||
// TODO: Find a better way to register and load all the locales in Node
|
||
if (!locales[name] && (typeof module !== 'undefined') &&
|
||
module && module.exports) {
|
||
try {
|
||
oldLocale = globalLocale._abbr;
|
||
var aliasedRequire = require;
|
||
aliasedRequire('./locale/' + name);
|
||
getSetGlobalLocale(oldLocale);
|
||
} catch (e) {}
|
||
}
|
||
return locales[name];
|
||
}
|
||
|
||
// This function will load locale and then set the global locale. If
|
||
// no arguments are passed in, it will simply return the current global
|
||
// locale key.
|
||
function getSetGlobalLocale (key, values) {
|
||
var data;
|
||
if (key) {
|
||
if (isUndefined(values)) {
|
||
data = getLocale(key);
|
||
}
|
||
else {
|
||
data = defineLocale(key, values);
|
||
}
|
||
|
||
if (data) {
|
||
// moment.duration._locale = moment._locale = data;
|
||
globalLocale = data;
|
||
}
|
||
}
|
||
|
||
return globalLocale._abbr;
|
||
}
|
||
|
||
function defineLocale (name, config) {
|
||
if (config !== null) {
|
||
var parentConfig = baseConfig;
|
||
config.abbr = name;
|
||
if (locales[name] != null) {
|
||
deprecateSimple('defineLocaleOverride',
|
||
'use moment.updateLocale(localeName, config) to change ' +
|
||
'an existing locale. moment.defineLocale(localeName, ' +
|
||
'config) should only be used for creating a new locale ' +
|
||
'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
|
||
parentConfig = locales[name]._config;
|
||
} else if (config.parentLocale != null) {
|
||
if (locales[config.parentLocale] != null) {
|
||
parentConfig = locales[config.parentLocale]._config;
|
||
} else {
|
||
if (!localeFamilies[config.parentLocale]) {
|
||
localeFamilies[config.parentLocale] = [];
|
||
}
|
||
localeFamilies[config.parentLocale].push({
|
||
name: name,
|
||
config: config
|
||
});
|
||
return null;
|
||
}
|
||
}
|
||
locales[name] = new Locale(mergeConfigs(parentConfig, config));
|
||
|
||
if (localeFamilies[name]) {
|
||
localeFamilies[name].forEach(function (x) {
|
||
defineLocale(x.name, x.config);
|
||
});
|
||
}
|
||
|
||
// backwards compat for now: also set the locale
|
||
// make sure we set the locale AFTER all child locales have been
|
||
// created, so we won't end up with the child locale set.
|
||
getSetGlobalLocale(name);
|
||
|
||
|
||
return locales[name];
|
||
} else {
|
||
// useful for testing
|
||
delete locales[name];
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function updateLocale(name, config) {
|
||
if (config != null) {
|
||
var locale, tmpLocale, parentConfig = baseConfig;
|
||
// MERGE
|
||
tmpLocale = loadLocale(name);
|
||
if (tmpLocale != null) {
|
||
parentConfig = tmpLocale._config;
|
||
}
|
||
config = mergeConfigs(parentConfig, config);
|
||
locale = new Locale(config);
|
||
locale.parentLocale = locales[name];
|
||
locales[name] = locale;
|
||
|
||
// backwards compat for now: also set the locale
|
||
getSetGlobalLocale(name);
|
||
} else {
|
||
// pass null for config to unupdate, useful for tests
|
||
if (locales[name] != null) {
|
||
if (locales[name].parentLocale != null) {
|
||
locales[name] = locales[name].parentLocale;
|
||
} else if (locales[name] != null) {
|
||
delete locales[name];
|
||
}
|
||
}
|
||
}
|
||
return locales[name];
|
||
}
|
||
|
||
// returns locale data
|
||
function getLocale (key) {
|
||
var locale;
|
||
|
||
if (key && key._locale && key._locale._abbr) {
|
||
key = key._locale._abbr;
|
||
}
|
||
|
||
if (!key) {
|
||
return globalLocale;
|
||
}
|
||
|
||
if (!isArray(key)) {
|
||
//short-circuit everything else
|
||
locale = loadLocale(key);
|
||
if (locale) {
|
||
return locale;
|
||
}
|
||
key = [key];
|
||
}
|
||
|
||
return chooseLocale(key);
|
||
}
|
||
|
||
function listLocales() {
|
||
return keys(locales);
|
||
}
|
||
|
||
function checkOverflow (m) {
|
||
var overflow;
|
||
var a = m._a;
|
||
|
||
if (a && getParsingFlags(m).overflow === -2) {
|
||
overflow =
|
||
a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
|
||
a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
|
||
a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
|
||
a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
|
||
a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
|
||
a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
|
||
-1;
|
||
|
||
if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
|
||
overflow = DATE;
|
||
}
|
||
if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
|
||
overflow = WEEK;
|
||
}
|
||
if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
|
||
overflow = WEEKDAY;
|
||
}
|
||
|
||
getParsingFlags(m).overflow = overflow;
|
||
}
|
||
|
||
return m;
|
||
}
|
||
|
||
// Pick the first defined of two or three arguments.
|
||
function defaults(a, b, c) {
|
||
if (a != null) {
|
||
return a;
|
||
}
|
||
if (b != null) {
|
||
return b;
|
||
}
|
||
return c;
|
||
}
|
||
|
||
function currentDateArray(config) {
|
||
// hooks is actually the exported moment object
|
||
var nowValue = new Date(hooks.now());
|
||
if (config._useUTC) {
|
||
return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
|
||
}
|
||
return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
|
||
}
|
||
|
||
// convert an array to a date.
|
||
// the array should mirror the parameters below
|
||
// note: all values past the year are optional and will default to the lowest possible value.
|
||
// [year, month, day , hour, minute, second, millisecond]
|
||
function configFromArray (config) {
|
||
var i, date, input = [], currentDate, expectedWeekday, yearToUse;
|
||
|
||
if (config._d) {
|
||
return;
|
||
}
|
||
|
||
currentDate = currentDateArray(config);
|
||
|
||
//compute day of the year from weeks and weekdays
|
||
if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
|
||
dayOfYearFromWeekInfo(config);
|
||
}
|
||
|
||
//if the day of the year is set, figure out what it is
|
||
if (config._dayOfYear != null) {
|
||
yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
|
||
|
||
if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
|
||
getParsingFlags(config)._overflowDayOfYear = true;
|
||
}
|
||
|
||
date = createUTCDate(yearToUse, 0, config._dayOfYear);
|
||
config._a[MONTH] = date.getUTCMonth();
|
||
config._a[DATE] = date.getUTCDate();
|
||
}
|
||
|
||
// Default to current date.
|
||
// * if no year, month, day of month are given, default to today
|
||
// * if day of month is given, default month and year
|
||
// * if month is given, default only year
|
||
// * if year is given, don't default anything
|
||
for (i = 0; i < 3 && config._a[i] == null; ++i) {
|
||
config._a[i] = input[i] = currentDate[i];
|
||
}
|
||
|
||
// Zero out whatever was not defaulted, including time
|
||
for (; i < 7; i++) {
|
||
config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
|
||
}
|
||
|
||
// Check for 24:00:00.000
|
||
if (config._a[HOUR] === 24 &&
|
||
config._a[MINUTE] === 0 &&
|
||
config._a[SECOND] === 0 &&
|
||
config._a[MILLISECOND] === 0) {
|
||
config._nextDay = true;
|
||
config._a[HOUR] = 0;
|
||
}
|
||
|
||
config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
|
||
expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
|
||
|
||
// Apply timezone offset from input. The actual utcOffset can be changed
|
||
// with parseZone.
|
||
if (config._tzm != null) {
|
||
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
|
||
}
|
||
|
||
if (config._nextDay) {
|
||
config._a[HOUR] = 24;
|
||
}
|
||
|
||
// check for mismatching day of week
|
||
if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
|
||
getParsingFlags(config).weekdayMismatch = true;
|
||
}
|
||
}
|
||
|
||
function dayOfYearFromWeekInfo(config) {
|
||
var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
|
||
|
||
w = config._w;
|
||
if (w.GG != null || w.W != null || w.E != null) {
|
||
dow = 1;
|
||
doy = 4;
|
||
|
||
// TODO: We need to take the current isoWeekYear, but that depends on
|
||
// how we interpret now (local, utc, fixed offset). So create
|
||
// a now version of current config (take local/utc/offset flags, and
|
||
// create now).
|
||
weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
|
||
week = defaults(w.W, 1);
|
||
weekday = defaults(w.E, 1);
|
||
if (weekday < 1 || weekday > 7) {
|
||
weekdayOverflow = true;
|
||
}
|
||
} else {
|
||
dow = config._locale._week.dow;
|
||
doy = config._locale._week.doy;
|
||
|
||
var curWeek = weekOfYear(createLocal(), dow, doy);
|
||
|
||
weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
|
||
|
||
// Default to current week.
|
||
week = defaults(w.w, curWeek.week);
|
||
|
||
if (w.d != null) {
|
||
// weekday -- low day numbers are considered next week
|
||
weekday = w.d;
|
||
if (weekday < 0 || weekday > 6) {
|
||
weekdayOverflow = true;
|
||
}
|
||
} else if (w.e != null) {
|
||
// local weekday -- counting starts from begining of week
|
||
weekday = w.e + dow;
|
||
if (w.e < 0 || w.e > 6) {
|
||
weekdayOverflow = true;
|
||
}
|
||
} else {
|
||
// default to begining of week
|
||
weekday = dow;
|
||
}
|
||
}
|
||
if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
|
||
getParsingFlags(config)._overflowWeeks = true;
|
||
} else if (weekdayOverflow != null) {
|
||
getParsingFlags(config)._overflowWeekday = true;
|
||
} else {
|
||
temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
|
||
config._a[YEAR] = temp.year;
|
||
config._dayOfYear = temp.dayOfYear;
|
||
}
|
||
}
|
||
|
||
// iso 8601 regex
|
||
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
|
||
var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
|
||
var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
|
||
|
||
var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
|
||
|
||
var isoDates = [
|
||
['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
|
||
['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
|
||
['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
|
||
['GGGG-[W]WW', /\d{4}-W\d\d/, false],
|
||
['YYYY-DDD', /\d{4}-\d{3}/],
|
||
['YYYY-MM', /\d{4}-\d\d/, false],
|
||
['YYYYYYMMDD', /[+-]\d{10}/],
|
||
['YYYYMMDD', /\d{8}/],
|
||
// YYYYMM is NOT allowed by the standard
|
||
['GGGG[W]WWE', /\d{4}W\d{3}/],
|
||
['GGGG[W]WW', /\d{4}W\d{2}/, false],
|
||
['YYYYDDD', /\d{7}/]
|
||
];
|
||
|
||
// iso time formats and regexes
|
||
var isoTimes = [
|
||
['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
|
||
['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
|
||
['HH:mm:ss', /\d\d:\d\d:\d\d/],
|
||
['HH:mm', /\d\d:\d\d/],
|
||
['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
|
||
['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
|
||
['HHmmss', /\d\d\d\d\d\d/],
|
||
['HHmm', /\d\d\d\d/],
|
||
['HH', /\d\d/]
|
||
];
|
||
|
||
var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
|
||
|
||
// date from iso format
|
||
function configFromISO(config) {
|
||
var i, l,
|
||
string = config._i,
|
||
match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
|
||
allowTime, dateFormat, timeFormat, tzFormat;
|
||
|
||
if (match) {
|
||
getParsingFlags(config).iso = true;
|
||
|
||
for (i = 0, l = isoDates.length; i < l; i++) {
|
||
if (isoDates[i][1].exec(match[1])) {
|
||
dateFormat = isoDates[i][0];
|
||
allowTime = isoDates[i][2] !== false;
|
||
break;
|
||
}
|
||
}
|
||
if (dateFormat == null) {
|
||
config._isValid = false;
|
||
return;
|
||
}
|
||
if (match[3]) {
|
||
for (i = 0, l = isoTimes.length; i < l; i++) {
|
||
if (isoTimes[i][1].exec(match[3])) {
|
||
// match[2] should be 'T' or space
|
||
timeFormat = (match[2] || ' ') + isoTimes[i][0];
|
||
break;
|
||
}
|
||
}
|
||
if (timeFormat == null) {
|
||
config._isValid = false;
|
||
return;
|
||
}
|
||
}
|
||
if (!allowTime && timeFormat != null) {
|
||
config._isValid = false;
|
||
return;
|
||
}
|
||
if (match[4]) {
|
||
if (tzRegex.exec(match[4])) {
|
||
tzFormat = 'Z';
|
||
} else {
|
||
config._isValid = false;
|
||
return;
|
||
}
|
||
}
|
||
config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
|
||
configFromStringAndFormat(config);
|
||
} else {
|
||
config._isValid = false;
|
||
}
|
||
}
|
||
|
||
// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
|
||
var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
|
||
|
||
function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
|
||
var result = [
|
||
untruncateYear(yearStr),
|
||
defaultLocaleMonthsShort.indexOf(monthStr),
|
||
parseInt(dayStr, 10),
|
||
parseInt(hourStr, 10),
|
||
parseInt(minuteStr, 10)
|
||
];
|
||
|
||
if (secondStr) {
|
||
result.push(parseInt(secondStr, 10));
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
function untruncateYear(yearStr) {
|
||
var year = parseInt(yearStr, 10);
|
||
if (year <= 49) {
|
||
return 2000 + year;
|
||
} else if (year <= 999) {
|
||
return 1900 + year;
|
||
}
|
||
return year;
|
||
}
|
||
|
||
function preprocessRFC2822(s) {
|
||
// Remove comments and folding whitespace and replace multiple-spaces with a single space
|
||
return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim();
|
||
}
|
||
|
||
function checkWeekday(weekdayStr, parsedInput, config) {
|
||
if (weekdayStr) {
|
||
// TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
|
||
var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
|
||
weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
|
||
if (weekdayProvided !== weekdayActual) {
|
||
getParsingFlags(config).weekdayMismatch = true;
|
||
config._isValid = false;
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
var obsOffsets = {
|
||
UT: 0,
|
||
GMT: 0,
|
||
EDT: -4 * 60,
|
||
EST: -5 * 60,
|
||
CDT: -5 * 60,
|
||
CST: -6 * 60,
|
||
MDT: -6 * 60,
|
||
MST: -7 * 60,
|
||
PDT: -7 * 60,
|
||
PST: -8 * 60
|
||
};
|
||
|
||
function calculateOffset(obsOffset, militaryOffset, numOffset) {
|
||
if (obsOffset) {
|
||
return obsOffsets[obsOffset];
|
||
} else if (militaryOffset) {
|
||
// the only allowed military tz is Z
|
||
return 0;
|
||
} else {
|
||
var hm = parseInt(numOffset, 10);
|
||
var m = hm % 100, h = (hm - m) / 100;
|
||
return h * 60 + m;
|
||
}
|
||
}
|
||
|
||
// date and time from ref 2822 format
|
||
function configFromRFC2822(config) {
|
||
var match = rfc2822.exec(preprocessRFC2822(config._i));
|
||
if (match) {
|
||
var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
|
||
if (!checkWeekday(match[1], parsedArray, config)) {
|
||
return;
|
||
}
|
||
|
||
config._a = parsedArray;
|
||
config._tzm = calculateOffset(match[8], match[9], match[10]);
|
||
|
||
config._d = createUTCDate.apply(null, config._a);
|
||
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
|
||
|
||
getParsingFlags(config).rfc2822 = true;
|
||
} else {
|
||
config._isValid = false;
|
||
}
|
||
}
|
||
|
||
// date from iso format or fallback
|
||
function configFromString(config) {
|
||
var matched = aspNetJsonRegex.exec(config._i);
|
||
|
||
if (matched !== null) {
|
||
config._d = new Date(+matched[1]);
|
||
return;
|
||
}
|
||
|
||
configFromISO(config);
|
||
if (config._isValid === false) {
|
||
delete config._isValid;
|
||
} else {
|
||
return;
|
||
}
|
||
|
||
configFromRFC2822(config);
|
||
if (config._isValid === false) {
|
||
delete config._isValid;
|
||
} else {
|
||
return;
|
||
}
|
||
|
||
// Final attempt, use Input Fallback
|
||
hooks.createFromInputFallback(config);
|
||
}
|
||
|
||
hooks.createFromInputFallback = deprecate(
|
||
'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
|
||
'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
|
||
'discouraged and will be removed in an upcoming major release. Please refer to ' +
|
||
'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
|
||
function (config) {
|
||
config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
|
||
}
|
||
);
|
||
|
||
// constant that refers to the ISO standard
|
||
hooks.ISO_8601 = function () {};
|
||
|
||
// constant that refers to the RFC 2822 form
|
||
hooks.RFC_2822 = function () {};
|
||
|
||
// date from string and format string
|
||
function configFromStringAndFormat(config) {
|
||
// TODO: Move this to another part of the creation flow to prevent circular deps
|
||
if (config._f === hooks.ISO_8601) {
|
||
configFromISO(config);
|
||
return;
|
||
}
|
||
if (config._f === hooks.RFC_2822) {
|
||
configFromRFC2822(config);
|
||
return;
|
||
}
|
||
config._a = [];
|
||
getParsingFlags(config).empty = true;
|
||
|
||
// This array is used to make a Date, either with `new Date` or `Date.UTC`
|
||
var string = '' + config._i,
|
||
i, parsedInput, tokens, token, skipped,
|
||
stringLength = string.length,
|
||
totalParsedInputLength = 0;
|
||
|
||
tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
|
||
|
||
for (i = 0; i < tokens.length; i++) {
|
||
token = tokens[i];
|
||
parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
|
||
// console.log('token', token, 'parsedInput', parsedInput,
|
||
// 'regex', getParseRegexForToken(token, config));
|
||
if (parsedInput) {
|
||
skipped = string.substr(0, string.indexOf(parsedInput));
|
||
if (skipped.length > 0) {
|
||
getParsingFlags(config).unusedInput.push(skipped);
|
||
}
|
||
string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
|
||
totalParsedInputLength += parsedInput.length;
|
||
}
|
||
// don't parse if it's not a known token
|
||
if (formatTokenFunctions[token]) {
|
||
if (parsedInput) {
|
||
getParsingFlags(config).empty = false;
|
||
}
|
||
else {
|
||
getParsingFlags(config).unusedTokens.push(token);
|
||
}
|
||
addTimeToArrayFromToken(token, parsedInput, config);
|
||
}
|
||
else if (config._strict && !parsedInput) {
|
||
getParsingFlags(config).unusedTokens.push(token);
|
||
}
|
||
}
|
||
|
||
// add remaining unparsed input length to the string
|
||
getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
|
||
if (string.length > 0) {
|
||
getParsingFlags(config).unusedInput.push(string);
|
||
}
|
||
|
||
// clear _12h flag if hour is <= 12
|
||
if (config._a[HOUR] <= 12 &&
|
||
getParsingFlags(config).bigHour === true &&
|
||
config._a[HOUR] > 0) {
|
||
getParsingFlags(config).bigHour = undefined;
|
||
}
|
||
|
||
getParsingFlags(config).parsedDateParts = config._a.slice(0);
|
||
getParsingFlags(config).meridiem = config._meridiem;
|
||
// handle meridiem
|
||
config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
|
||
|
||
configFromArray(config);
|
||
checkOverflow(config);
|
||
}
|
||
|
||
|
||
function meridiemFixWrap (locale, hour, meridiem) {
|
||
var isPm;
|
||
|
||
if (meridiem == null) {
|
||
// nothing to do
|
||
return hour;
|
||
}
|
||
if (locale.meridiemHour != null) {
|
||
return locale.meridiemHour(hour, meridiem);
|
||
} else if (locale.isPM != null) {
|
||
// Fallback
|
||
isPm = locale.isPM(meridiem);
|
||
if (isPm && hour < 12) {
|
||
hour += 12;
|
||
}
|
||
if (!isPm && hour === 12) {
|
||
hour = 0;
|
||
}
|
||
return hour;
|
||
} else {
|
||
// this is not supposed to happen
|
||
return hour;
|
||
}
|
||
}
|
||
|
||
// date from string and array of format strings
|
||
function configFromStringAndArray(config) {
|
||
var tempConfig,
|
||
bestMoment,
|
||
|
||
scoreToBeat,
|
||
i,
|
||
currentScore;
|
||
|
||
if (config._f.length === 0) {
|
||
getParsingFlags(config).invalidFormat = true;
|
||
config._d = new Date(NaN);
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < config._f.length; i++) {
|
||
currentScore = 0;
|
||
tempConfig = copyConfig({}, config);
|
||
if (config._useUTC != null) {
|
||
tempConfig._useUTC = config._useUTC;
|
||
}
|
||
tempConfig._f = config._f[i];
|
||
configFromStringAndFormat(tempConfig);
|
||
|
||
if (!isValid(tempConfig)) {
|
||
continue;
|
||
}
|
||
|
||
// if there is any input that was not parsed add a penalty for that format
|
||
currentScore += getParsingFlags(tempConfig).charsLeftOver;
|
||
|
||
//or tokens
|
||
currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
|
||
|
||
getParsingFlags(tempConfig).score = currentScore;
|
||
|
||
if (scoreToBeat == null || currentScore < scoreToBeat) {
|
||
scoreToBeat = currentScore;
|
||
bestMoment = tempConfig;
|
||
}
|
||
}
|
||
|
||
extend(config, bestMoment || tempConfig);
|
||
}
|
||
|
||
function configFromObject(config) {
|
||
if (config._d) {
|
||
return;
|
||
}
|
||
|
||
var i = normalizeObjectUnits(config._i);
|
||
config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
|
||
return obj && parseInt(obj, 10);
|
||
});
|
||
|
||
configFromArray(config);
|
||
}
|
||
|
||
function createFromConfig (config) {
|
||
var res = new Moment(checkOverflow(prepareConfig(config)));
|
||
if (res._nextDay) {
|
||
// Adding is smart enough around DST
|
||
res.add(1, 'd');
|
||
res._nextDay = undefined;
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
function prepareConfig (config) {
|
||
var input = config._i,
|
||
format = config._f;
|
||
|
||
config._locale = config._locale || getLocale(config._l);
|
||
|
||
if (input === null || (format === undefined && input === '')) {
|
||
return createInvalid({nullInput: true});
|
||
}
|
||
|
||
if (typeof input === 'string') {
|
||
config._i = input = config._locale.preparse(input);
|
||
}
|
||
|
||
if (isMoment(input)) {
|
||
return new Moment(checkOverflow(input));
|
||
} else if (isDate(input)) {
|
||
config._d = input;
|
||
} else if (isArray(format)) {
|
||
configFromStringAndArray(config);
|
||
} else if (format) {
|
||
configFromStringAndFormat(config);
|
||
} else {
|
||
configFromInput(config);
|
||
}
|
||
|
||
if (!isValid(config)) {
|
||
config._d = null;
|
||
}
|
||
|
||
return config;
|
||
}
|
||
|
||
function configFromInput(config) {
|
||
var input = config._i;
|
||
if (isUndefined(input)) {
|
||
config._d = new Date(hooks.now());
|
||
} else if (isDate(input)) {
|
||
config._d = new Date(input.valueOf());
|
||
} else if (typeof input === 'string') {
|
||
configFromString(config);
|
||
} else if (isArray(input)) {
|
||
config._a = map(input.slice(0), function (obj) {
|
||
return parseInt(obj, 10);
|
||
});
|
||
configFromArray(config);
|
||
} else if (isObject(input)) {
|
||
configFromObject(config);
|
||
} else if (isNumber(input)) {
|
||
// from milliseconds
|
||
config._d = new Date(input);
|
||
} else {
|
||
hooks.createFromInputFallback(config);
|
||
}
|
||
}
|
||
|
||
function createLocalOrUTC (input, format, locale, strict, isUTC) {
|
||
var c = {};
|
||
|
||
if (locale === true || locale === false) {
|
||
strict = locale;
|
||
locale = undefined;
|
||
}
|
||
|
||
if ((isObject(input) && isObjectEmpty(input)) ||
|
||
(isArray(input) && input.length === 0)) {
|
||
input = undefined;
|
||
}
|
||
// object construction must be done this way.
|
||
// https://github.com/moment/moment/issues/1423
|
||
c._isAMomentObject = true;
|
||
c._useUTC = c._isUTC = isUTC;
|
||
c._l = locale;
|
||
c._i = input;
|
||
c._f = format;
|
||
c._strict = strict;
|
||
|
||
return createFromConfig(c);
|
||
}
|
||
|
||
function createLocal (input, format, locale, strict) {
|
||
return createLocalOrUTC(input, format, locale, strict, false);
|
||
}
|
||
|
||
var prototypeMin = deprecate(
|
||
'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
|
||
function () {
|
||
var other = createLocal.apply(null, arguments);
|
||
if (this.isValid() && other.isValid()) {
|
||
return other < this ? this : other;
|
||
} else {
|
||
return createInvalid();
|
||
}
|
||
}
|
||
);
|
||
|
||
var prototypeMax = deprecate(
|
||
'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
|
||
function () {
|
||
var other = createLocal.apply(null, arguments);
|
||
if (this.isValid() && other.isValid()) {
|
||
return other > this ? this : other;
|
||
} else {
|
||
return createInvalid();
|
||
}
|
||
}
|
||
);
|
||
|
||
// Pick a moment m from moments so that m[fn](other) is true for all
|
||
// other. This relies on the function fn to be transitive.
|
||
//
|
||
// moments should either be an array of moment objects or an array, whose
|
||
// first element is an array of moment objects.
|
||
function pickBy(fn, moments) {
|
||
var res, i;
|
||
if (moments.length === 1 && isArray(moments[0])) {
|
||
moments = moments[0];
|
||
}
|
||
if (!moments.length) {
|
||
return createLocal();
|
||
}
|
||
res = moments[0];
|
||
for (i = 1; i < moments.length; ++i) {
|
||
if (!moments[i].isValid() || moments[i][fn](res)) {
|
||
res = moments[i];
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
// TODO: Use [].sort instead?
|
||
function min () {
|
||
var args = [].slice.call(arguments, 0);
|
||
|
||
return pickBy('isBefore', args);
|
||
}
|
||
|
||
function max () {
|
||
var args = [].slice.call(arguments, 0);
|
||
|
||
return pickBy('isAfter', args);
|
||
}
|
||
|
||
var now = function () {
|
||
return Date.now ? Date.now() : +(new Date());
|
||
};
|
||
|
||
var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
|
||
|
||
function isDurationValid(m) {
|
||
for (var key in m) {
|
||
if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
var unitHasDecimal = false;
|
||
for (var i = 0; i < ordering.length; ++i) {
|
||
if (m[ordering[i]]) {
|
||
if (unitHasDecimal) {
|
||
return false; // only allow non-integers for smallest unit
|
||
}
|
||
if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
|
||
unitHasDecimal = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
function isValid$1() {
|
||
return this._isValid;
|
||
}
|
||
|
||
function createInvalid$1() {
|
||
return createDuration(NaN);
|
||
}
|
||
|
||
function Duration (duration) {
|
||
var normalizedInput = normalizeObjectUnits(duration),
|
||
years = normalizedInput.year || 0,
|
||
quarters = normalizedInput.quarter || 0,
|
||
months = normalizedInput.month || 0,
|
||
weeks = normalizedInput.week || 0,
|
||
days = normalizedInput.day || 0,
|
||
hours = normalizedInput.hour || 0,
|
||
minutes = normalizedInput.minute || 0,
|
||
seconds = normalizedInput.second || 0,
|
||
milliseconds = normalizedInput.millisecond || 0;
|
||
|
||
this._isValid = isDurationValid(normalizedInput);
|
||
|
||
// representation for dateAddRemove
|
||
this._milliseconds = +milliseconds +
|
||
seconds * 1e3 + // 1000
|
||
minutes * 6e4 + // 1000 * 60
|
||
hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
|
||
// Because of dateAddRemove treats 24 hours as different from a
|
||
// day when working around DST, we need to store them separately
|
||
this._days = +days +
|
||
weeks * 7;
|
||
// It is impossible to translate months into days without knowing
|
||
// which months you are are talking about, so we have to store
|
||
// it separately.
|
||
this._months = +months +
|
||
quarters * 3 +
|
||
years * 12;
|
||
|
||
this._data = {};
|
||
|
||
this._locale = getLocale();
|
||
|
||
this._bubble();
|
||
}
|
||
|
||
function isDuration (obj) {
|
||
return obj instanceof Duration;
|
||
}
|
||
|
||
function absRound (number) {
|
||
if (number < 0) {
|
||
return Math.round(-1 * number) * -1;
|
||
} else {
|
||
return Math.round(number);
|
||
}
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
function offset (token, separator) {
|
||
addFormatToken(token, 0, 0, function () {
|
||
var offset = this.utcOffset();
|
||
var sign = '+';
|
||
if (offset < 0) {
|
||
offset = -offset;
|
||
sign = '-';
|
||
}
|
||
return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
|
||
});
|
||
}
|
||
|
||
offset('Z', ':');
|
||
offset('ZZ', '');
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('Z', matchShortOffset);
|
||
addRegexToken('ZZ', matchShortOffset);
|
||
addParseToken(['Z', 'ZZ'], function (input, array, config) {
|
||
config._useUTC = true;
|
||
config._tzm = offsetFromString(matchShortOffset, input);
|
||
});
|
||
|
||
// HELPERS
|
||
|
||
// timezone chunker
|
||
// '+10:00' > ['10', '00']
|
||
// '-1530' > ['-15', '30']
|
||
var chunkOffset = /([\+\-]|\d\d)/gi;
|
||
|
||
function offsetFromString(matcher, string) {
|
||
var matches = (string || '').match(matcher);
|
||
|
||
if (matches === null) {
|
||
return null;
|
||
}
|
||
|
||
var chunk = matches[matches.length - 1] || [];
|
||
var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
|
||
var minutes = +(parts[1] * 60) + toInt(parts[2]);
|
||
|
||
return minutes === 0 ?
|
||
0 :
|
||
parts[0] === '+' ? minutes : -minutes;
|
||
}
|
||
|
||
// Return a moment from input, that is local/utc/zone equivalent to model.
|
||
function cloneWithOffset(input, model) {
|
||
var res, diff;
|
||
if (model._isUTC) {
|
||
res = model.clone();
|
||
diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
|
||
// Use low-level api, because this fn is low-level api.
|
||
res._d.setTime(res._d.valueOf() + diff);
|
||
hooks.updateOffset(res, false);
|
||
return res;
|
||
} else {
|
||
return createLocal(input).local();
|
||
}
|
||
}
|
||
|
||
function getDateOffset (m) {
|
||
// On Firefox.24 Date#getTimezoneOffset returns a floating point.
|
||
// https://github.com/moment/moment/pull/1871
|
||
return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
|
||
}
|
||
|
||
// HOOKS
|
||
|
||
// This function will be called whenever a moment is mutated.
|
||
// It is intended to keep the offset in sync with the timezone.
|
||
hooks.updateOffset = function () {};
|
||
|
||
// MOMENTS
|
||
|
||
// keepLocalTime = true means only change the timezone, without
|
||
// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
|
||
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
|
||
// +0200, so we adjust the time as needed, to be valid.
|
||
//
|
||
// Keeping the time actually adds/subtracts (one hour)
|
||
// from the actual represented time. That is why we call updateOffset
|
||
// a second time. In case it wants us to change the offset again
|
||
// _changeInProgress == true case, then we have to adjust, because
|
||
// there is no such time in the given timezone.
|
||
function getSetOffset (input, keepLocalTime, keepMinutes) {
|
||
var offset = this._offset || 0,
|
||
localAdjust;
|
||
if (!this.isValid()) {
|
||
return input != null ? this : NaN;
|
||
}
|
||
if (input != null) {
|
||
if (typeof input === 'string') {
|
||
input = offsetFromString(matchShortOffset, input);
|
||
if (input === null) {
|
||
return this;
|
||
}
|
||
} else if (Math.abs(input) < 16 && !keepMinutes) {
|
||
input = input * 60;
|
||
}
|
||
if (!this._isUTC && keepLocalTime) {
|
||
localAdjust = getDateOffset(this);
|
||
}
|
||
this._offset = input;
|
||
this._isUTC = true;
|
||
if (localAdjust != null) {
|
||
this.add(localAdjust, 'm');
|
||
}
|
||
if (offset !== input) {
|
||
if (!keepLocalTime || this._changeInProgress) {
|
||
addSubtract(this, createDuration(input - offset, 'm'), 1, false);
|
||
} else if (!this._changeInProgress) {
|
||
this._changeInProgress = true;
|
||
hooks.updateOffset(this, true);
|
||
this._changeInProgress = null;
|
||
}
|
||
}
|
||
return this;
|
||
} else {
|
||
return this._isUTC ? offset : getDateOffset(this);
|
||
}
|
||
}
|
||
|
||
function getSetZone (input, keepLocalTime) {
|
||
if (input != null) {
|
||
if (typeof input !== 'string') {
|
||
input = -input;
|
||
}
|
||
|
||
this.utcOffset(input, keepLocalTime);
|
||
|
||
return this;
|
||
} else {
|
||
return -this.utcOffset();
|
||
}
|
||
}
|
||
|
||
function setOffsetToUTC (keepLocalTime) {
|
||
return this.utcOffset(0, keepLocalTime);
|
||
}
|
||
|
||
function setOffsetToLocal (keepLocalTime) {
|
||
if (this._isUTC) {
|
||
this.utcOffset(0, keepLocalTime);
|
||
this._isUTC = false;
|
||
|
||
if (keepLocalTime) {
|
||
this.subtract(getDateOffset(this), 'm');
|
||
}
|
||
}
|
||
return this;
|
||
}
|
||
|
||
function setOffsetToParsedOffset () {
|
||
if (this._tzm != null) {
|
||
this.utcOffset(this._tzm, false, true);
|
||
} else if (typeof this._i === 'string') {
|
||
var tZone = offsetFromString(matchOffset, this._i);
|
||
if (tZone != null) {
|
||
this.utcOffset(tZone);
|
||
}
|
||
else {
|
||
this.utcOffset(0, true);
|
||
}
|
||
}
|
||
return this;
|
||
}
|
||
|
||
function hasAlignedHourOffset (input) {
|
||
if (!this.isValid()) {
|
||
return false;
|
||
}
|
||
input = input ? createLocal(input).utcOffset() : 0;
|
||
|
||
return (this.utcOffset() - input) % 60 === 0;
|
||
}
|
||
|
||
function isDaylightSavingTime () {
|
||
return (
|
||
this.utcOffset() > this.clone().month(0).utcOffset() ||
|
||
this.utcOffset() > this.clone().month(5).utcOffset()
|
||
);
|
||
}
|
||
|
||
function isDaylightSavingTimeShifted () {
|
||
if (!isUndefined(this._isDSTShifted)) {
|
||
return this._isDSTShifted;
|
||
}
|
||
|
||
var c = {};
|
||
|
||
copyConfig(c, this);
|
||
c = prepareConfig(c);
|
||
|
||
if (c._a) {
|
||
var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
|
||
this._isDSTShifted = this.isValid() &&
|
||
compareArrays(c._a, other.toArray()) > 0;
|
||
} else {
|
||
this._isDSTShifted = false;
|
||
}
|
||
|
||
return this._isDSTShifted;
|
||
}
|
||
|
||
function isLocal () {
|
||
return this.isValid() ? !this._isUTC : false;
|
||
}
|
||
|
||
function isUtcOffset () {
|
||
return this.isValid() ? this._isUTC : false;
|
||
}
|
||
|
||
function isUtc () {
|
||
return this.isValid() ? this._isUTC && this._offset === 0 : false;
|
||
}
|
||
|
||
// ASP.NET json date format regex
|
||
var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
|
||
|
||
// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
|
||
// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
|
||
// and further modified to allow for strings containing both week and day
|
||
var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
|
||
|
||
function createDuration (input, key) {
|
||
var duration = input,
|
||
// matching against regexp is expensive, do it on demand
|
||
match = null,
|
||
sign,
|
||
ret,
|
||
diffRes;
|
||
|
||
if (isDuration(input)) {
|
||
duration = {
|
||
ms : input._milliseconds,
|
||
d : input._days,
|
||
M : input._months
|
||
};
|
||
} else if (isNumber(input)) {
|
||
duration = {};
|
||
if (key) {
|
||
duration[key] = input;
|
||
} else {
|
||
duration.milliseconds = input;
|
||
}
|
||
} else if (!!(match = aspNetRegex.exec(input))) {
|
||
sign = (match[1] === '-') ? -1 : 1;
|
||
duration = {
|
||
y : 0,
|
||
d : toInt(match[DATE]) * sign,
|
||
h : toInt(match[HOUR]) * sign,
|
||
m : toInt(match[MINUTE]) * sign,
|
||
s : toInt(match[SECOND]) * sign,
|
||
ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
|
||
};
|
||
} else if (!!(match = isoRegex.exec(input))) {
|
||
sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
|
||
duration = {
|
||
y : parseIso(match[2], sign),
|
||
M : parseIso(match[3], sign),
|
||
w : parseIso(match[4], sign),
|
||
d : parseIso(match[5], sign),
|
||
h : parseIso(match[6], sign),
|
||
m : parseIso(match[7], sign),
|
||
s : parseIso(match[8], sign)
|
||
};
|
||
} else if (duration == null) {// checks for null or undefined
|
||
duration = {};
|
||
} else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
|
||
diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
|
||
|
||
duration = {};
|
||
duration.ms = diffRes.milliseconds;
|
||
duration.M = diffRes.months;
|
||
}
|
||
|
||
ret = new Duration(duration);
|
||
|
||
if (isDuration(input) && hasOwnProp(input, '_locale')) {
|
||
ret._locale = input._locale;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
createDuration.fn = Duration.prototype;
|
||
createDuration.invalid = createInvalid$1;
|
||
|
||
function parseIso (inp, sign) {
|
||
// We'd normally use ~~inp for this, but unfortunately it also
|
||
// converts floats to ints.
|
||
// inp may be undefined, so careful calling replace on it.
|
||
var res = inp && parseFloat(inp.replace(',', '.'));
|
||
// apply sign while we're at it
|
||
return (isNaN(res) ? 0 : res) * sign;
|
||
}
|
||
|
||
function positiveMomentsDifference(base, other) {
|
||
var res = {milliseconds: 0, months: 0};
|
||
|
||
res.months = other.month() - base.month() +
|
||
(other.year() - base.year()) * 12;
|
||
if (base.clone().add(res.months, 'M').isAfter(other)) {
|
||
--res.months;
|
||
}
|
||
|
||
res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
|
||
|
||
return res;
|
||
}
|
||
|
||
function momentsDifference(base, other) {
|
||
var res;
|
||
if (!(base.isValid() && other.isValid())) {
|
||
return {milliseconds: 0, months: 0};
|
||
}
|
||
|
||
other = cloneWithOffset(other, base);
|
||
if (base.isBefore(other)) {
|
||
res = positiveMomentsDifference(base, other);
|
||
} else {
|
||
res = positiveMomentsDifference(other, base);
|
||
res.milliseconds = -res.milliseconds;
|
||
res.months = -res.months;
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
// TODO: remove 'name' arg after deprecation is removed
|
||
function createAdder(direction, name) {
|
||
return function (val, period) {
|
||
var dur, tmp;
|
||
//invert the arguments, but complain about it
|
||
if (period !== null && !isNaN(+period)) {
|
||
deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
|
||
'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
|
||
tmp = val; val = period; period = tmp;
|
||
}
|
||
|
||
val = typeof val === 'string' ? +val : val;
|
||
dur = createDuration(val, period);
|
||
addSubtract(this, dur, direction);
|
||
return this;
|
||
};
|
||
}
|
||
|
||
function addSubtract (mom, duration, isAdding, updateOffset) {
|
||
var milliseconds = duration._milliseconds,
|
||
days = absRound(duration._days),
|
||
months = absRound(duration._months);
|
||
|
||
if (!mom.isValid()) {
|
||
// No op
|
||
return;
|
||
}
|
||
|
||
updateOffset = updateOffset == null ? true : updateOffset;
|
||
|
||
if (months) {
|
||
setMonth(mom, get(mom, 'Month') + months * isAdding);
|
||
}
|
||
if (days) {
|
||
set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
|
||
}
|
||
if (milliseconds) {
|
||
mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
|
||
}
|
||
if (updateOffset) {
|
||
hooks.updateOffset(mom, days || months);
|
||
}
|
||
}
|
||
|
||
var add = createAdder(1, 'add');
|
||
var subtract = createAdder(-1, 'subtract');
|
||
|
||
function getCalendarFormat(myMoment, now) {
|
||
var diff = myMoment.diff(now, 'days', true);
|
||
return diff < -6 ? 'sameElse' :
|
||
diff < -1 ? 'lastWeek' :
|
||
diff < 0 ? 'lastDay' :
|
||
diff < 1 ? 'sameDay' :
|
||
diff < 2 ? 'nextDay' :
|
||
diff < 7 ? 'nextWeek' : 'sameElse';
|
||
}
|
||
|
||
function calendar$1 (time, formats) {
|
||
// We want to compare the start of today, vs this.
|
||
// Getting start-of-today depends on whether we're local/utc/offset or not.
|
||
var now = time || createLocal(),
|
||
sod = cloneWithOffset(now, this).startOf('day'),
|
||
format = hooks.calendarFormat(this, sod) || 'sameElse';
|
||
|
||
var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
|
||
|
||
return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
|
||
}
|
||
|
||
function clone () {
|
||
return new Moment(this);
|
||
}
|
||
|
||
function isAfter (input, units) {
|
||
var localInput = isMoment(input) ? input : createLocal(input);
|
||
if (!(this.isValid() && localInput.isValid())) {
|
||
return false;
|
||
}
|
||
units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
|
||
if (units === 'millisecond') {
|
||
return this.valueOf() > localInput.valueOf();
|
||
} else {
|
||
return localInput.valueOf() < this.clone().startOf(units).valueOf();
|
||
}
|
||
}
|
||
|
||
function isBefore (input, units) {
|
||
var localInput = isMoment(input) ? input : createLocal(input);
|
||
if (!(this.isValid() && localInput.isValid())) {
|
||
return false;
|
||
}
|
||
units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
|
||
if (units === 'millisecond') {
|
||
return this.valueOf() < localInput.valueOf();
|
||
} else {
|
||
return this.clone().endOf(units).valueOf() < localInput.valueOf();
|
||
}
|
||
}
|
||
|
||
function isBetween (from, to, units, inclusivity) {
|
||
inclusivity = inclusivity || '()';
|
||
return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
|
||
(inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
|
||
}
|
||
|
||
function isSame (input, units) {
|
||
var localInput = isMoment(input) ? input : createLocal(input),
|
||
inputMs;
|
||
if (!(this.isValid() && localInput.isValid())) {
|
||
return false;
|
||
}
|
||
units = normalizeUnits(units || 'millisecond');
|
||
if (units === 'millisecond') {
|
||
return this.valueOf() === localInput.valueOf();
|
||
} else {
|
||
inputMs = localInput.valueOf();
|
||
return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
|
||
}
|
||
}
|
||
|
||
function isSameOrAfter (input, units) {
|
||
return this.isSame(input, units) || this.isAfter(input,units);
|
||
}
|
||
|
||
function isSameOrBefore (input, units) {
|
||
return this.isSame(input, units) || this.isBefore(input,units);
|
||
}
|
||
|
||
function diff (input, units, asFloat) {
|
||
var that,
|
||
zoneDelta,
|
||
delta, output;
|
||
|
||
if (!this.isValid()) {
|
||
return NaN;
|
||
}
|
||
|
||
that = cloneWithOffset(input, this);
|
||
|
||
if (!that.isValid()) {
|
||
return NaN;
|
||
}
|
||
|
||
zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
|
||
|
||
units = normalizeUnits(units);
|
||
|
||
switch (units) {
|
||
case 'year': output = monthDiff(this, that) / 12; break;
|
||
case 'month': output = monthDiff(this, that); break;
|
||
case 'quarter': output = monthDiff(this, that) / 3; break;
|
||
case 'second': output = (this - that) / 1e3; break; // 1000
|
||
case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
|
||
case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
|
||
case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
|
||
case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
|
||
default: output = this - that;
|
||
}
|
||
|
||
return asFloat ? output : absFloor(output);
|
||
}
|
||
|
||
function monthDiff (a, b) {
|
||
// difference in months
|
||
var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
|
||
// b is in (anchor - 1 month, anchor + 1 month)
|
||
anchor = a.clone().add(wholeMonthDiff, 'months'),
|
||
anchor2, adjust;
|
||
|
||
if (b - anchor < 0) {
|
||
anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
|
||
// linear across the month
|
||
adjust = (b - anchor) / (anchor - anchor2);
|
||
} else {
|
||
anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
|
||
// linear across the month
|
||
adjust = (b - anchor) / (anchor2 - anchor);
|
||
}
|
||
|
||
//check for negative zero, return zero if negative zero
|
||
return -(wholeMonthDiff + adjust) || 0;
|
||
}
|
||
|
||
hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
|
||
hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
|
||
|
||
function toString () {
|
||
return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
|
||
}
|
||
|
||
function toISOString() {
|
||
if (!this.isValid()) {
|
||
return null;
|
||
}
|
||
var m = this.clone().utc();
|
||
if (m.year() < 0 || m.year() > 9999) {
|
||
return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
|
||
}
|
||
if (isFunction(Date.prototype.toISOString)) {
|
||
// native implementation is ~50x faster, use it when we can
|
||
return this.toDate().toISOString();
|
||
}
|
||
return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
|
||
}
|
||
|
||
/**
|
||
* Return a human readable representation of a moment that can
|
||
* also be evaluated to get a new moment which is the same
|
||
*
|
||
* @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
|
||
*/
|
||
function inspect () {
|
||
if (!this.isValid()) {
|
||
return 'moment.invalid(/* ' + this._i + ' */)';
|
||
}
|
||
var func = 'moment';
|
||
var zone = '';
|
||
if (!this.isLocal()) {
|
||
func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
|
||
zone = 'Z';
|
||
}
|
||
var prefix = '[' + func + '("]';
|
||
var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
|
||
var datetime = '-MM-DD[T]HH:mm:ss.SSS';
|
||
var suffix = zone + '[")]';
|
||
|
||
return this.format(prefix + year + datetime + suffix);
|
||
}
|
||
|
||
function format (inputString) {
|
||
if (!inputString) {
|
||
inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
|
||
}
|
||
var output = formatMoment(this, inputString);
|
||
return this.localeData().postformat(output);
|
||
}
|
||
|
||
function from (time, withoutSuffix) {
|
||
if (this.isValid() &&
|
||
((isMoment(time) && time.isValid()) ||
|
||
createLocal(time).isValid())) {
|
||
return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
|
||
} else {
|
||
return this.localeData().invalidDate();
|
||
}
|
||
}
|
||
|
||
function fromNow (withoutSuffix) {
|
||
return this.from(createLocal(), withoutSuffix);
|
||
}
|
||
|
||
function to (time, withoutSuffix) {
|
||
if (this.isValid() &&
|
||
((isMoment(time) && time.isValid()) ||
|
||
createLocal(time).isValid())) {
|
||
return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
|
||
} else {
|
||
return this.localeData().invalidDate();
|
||
}
|
||
}
|
||
|
||
function toNow (withoutSuffix) {
|
||
return this.to(createLocal(), withoutSuffix);
|
||
}
|
||
|
||
// If passed a locale key, it will set the locale for this
|
||
// instance. Otherwise, it will return the locale configuration
|
||
// variables for this instance.
|
||
function locale (key) {
|
||
var newLocaleData;
|
||
|
||
if (key === undefined) {
|
||
return this._locale._abbr;
|
||
} else {
|
||
newLocaleData = getLocale(key);
|
||
if (newLocaleData != null) {
|
||
this._locale = newLocaleData;
|
||
}
|
||
return this;
|
||
}
|
||
}
|
||
|
||
var lang = deprecate(
|
||
'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
|
||
function (key) {
|
||
if (key === undefined) {
|
||
return this.localeData();
|
||
} else {
|
||
return this.locale(key);
|
||
}
|
||
}
|
||
);
|
||
|
||
function localeData () {
|
||
return this._locale;
|
||
}
|
||
|
||
function startOf (units) {
|
||
units = normalizeUnits(units);
|
||
// the following switch intentionally omits break keywords
|
||
// to utilize falling through the cases.
|
||
switch (units) {
|
||
case 'year':
|
||
this.month(0);
|
||
/* falls through */
|
||
case 'quarter':
|
||
case 'month':
|
||
this.date(1);
|
||
/* falls through */
|
||
case 'week':
|
||
case 'isoWeek':
|
||
case 'day':
|
||
case 'date':
|
||
this.hours(0);
|
||
/* falls through */
|
||
case 'hour':
|
||
this.minutes(0);
|
||
/* falls through */
|
||
case 'minute':
|
||
this.seconds(0);
|
||
/* falls through */
|
||
case 'second':
|
||
this.milliseconds(0);
|
||
}
|
||
|
||
// weeks are a special case
|
||
if (units === 'week') {
|
||
this.weekday(0);
|
||
}
|
||
if (units === 'isoWeek') {
|
||
this.isoWeekday(1);
|
||
}
|
||
|
||
// quarters are also special
|
||
if (units === 'quarter') {
|
||
this.month(Math.floor(this.month() / 3) * 3);
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
function endOf (units) {
|
||
units = normalizeUnits(units);
|
||
if (units === undefined || units === 'millisecond') {
|
||
return this;
|
||
}
|
||
|
||
// 'date' is an alias for 'day', so it should be considered as such.
|
||
if (units === 'date') {
|
||
units = 'day';
|
||
}
|
||
|
||
return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
|
||
}
|
||
|
||
function valueOf () {
|
||
return this._d.valueOf() - ((this._offset || 0) * 60000);
|
||
}
|
||
|
||
function unix () {
|
||
return Math.floor(this.valueOf() / 1000);
|
||
}
|
||
|
||
function toDate () {
|
||
return new Date(this.valueOf());
|
||
}
|
||
|
||
function toArray () {
|
||
var m = this;
|
||
return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
|
||
}
|
||
|
||
function toObject () {
|
||
var m = this;
|
||
return {
|
||
years: m.year(),
|
||
months: m.month(),
|
||
date: m.date(),
|
||
hours: m.hours(),
|
||
minutes: m.minutes(),
|
||
seconds: m.seconds(),
|
||
milliseconds: m.milliseconds()
|
||
};
|
||
}
|
||
|
||
function toJSON () {
|
||
// new Date(NaN).toJSON() === null
|
||
return this.isValid() ? this.toISOString() : null;
|
||
}
|
||
|
||
function isValid$2 () {
|
||
return isValid(this);
|
||
}
|
||
|
||
function parsingFlags () {
|
||
return extend({}, getParsingFlags(this));
|
||
}
|
||
|
||
function invalidAt () {
|
||
return getParsingFlags(this).overflow;
|
||
}
|
||
|
||
function creationData() {
|
||
return {
|
||
input: this._i,
|
||
format: this._f,
|
||
locale: this._locale,
|
||
isUTC: this._isUTC,
|
||
strict: this._strict
|
||
};
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken(0, ['gg', 2], 0, function () {
|
||
return this.weekYear() % 100;
|
||
});
|
||
|
||
addFormatToken(0, ['GG', 2], 0, function () {
|
||
return this.isoWeekYear() % 100;
|
||
});
|
||
|
||
function addWeekYearFormatToken (token, getter) {
|
||
addFormatToken(0, [token, token.length], 0, getter);
|
||
}
|
||
|
||
addWeekYearFormatToken('gggg', 'weekYear');
|
||
addWeekYearFormatToken('ggggg', 'weekYear');
|
||
addWeekYearFormatToken('GGGG', 'isoWeekYear');
|
||
addWeekYearFormatToken('GGGGG', 'isoWeekYear');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('weekYear', 'gg');
|
||
addUnitAlias('isoWeekYear', 'GG');
|
||
|
||
// PRIORITY
|
||
|
||
addUnitPriority('weekYear', 1);
|
||
addUnitPriority('isoWeekYear', 1);
|
||
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('G', matchSigned);
|
||
addRegexToken('g', matchSigned);
|
||
addRegexToken('GG', match1to2, match2);
|
||
addRegexToken('gg', match1to2, match2);
|
||
addRegexToken('GGGG', match1to4, match4);
|
||
addRegexToken('gggg', match1to4, match4);
|
||
addRegexToken('GGGGG', match1to6, match6);
|
||
addRegexToken('ggggg', match1to6, match6);
|
||
|
||
addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
|
||
week[token.substr(0, 2)] = toInt(input);
|
||
});
|
||
|
||
addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
|
||
week[token] = hooks.parseTwoDigitYear(input);
|
||
});
|
||
|
||
// MOMENTS
|
||
|
||
function getSetWeekYear (input) {
|
||
return getSetWeekYearHelper.call(this,
|
||
input,
|
||
this.week(),
|
||
this.weekday(),
|
||
this.localeData()._week.dow,
|
||
this.localeData()._week.doy);
|
||
}
|
||
|
||
function getSetISOWeekYear (input) {
|
||
return getSetWeekYearHelper.call(this,
|
||
input, this.isoWeek(), this.isoWeekday(), 1, 4);
|
||
}
|
||
|
||
function getISOWeeksInYear () {
|
||
return weeksInYear(this.year(), 1, 4);
|
||
}
|
||
|
||
function getWeeksInYear () {
|
||
var weekInfo = this.localeData()._week;
|
||
return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
|
||
}
|
||
|
||
function getSetWeekYearHelper(input, week, weekday, dow, doy) {
|
||
var weeksTarget;
|
||
if (input == null) {
|
||
return weekOfYear(this, dow, doy).year;
|
||
} else {
|
||
weeksTarget = weeksInYear(input, dow, doy);
|
||
if (week > weeksTarget) {
|
||
week = weeksTarget;
|
||
}
|
||
return setWeekAll.call(this, input, week, weekday, dow, doy);
|
||
}
|
||
}
|
||
|
||
function setWeekAll(weekYear, week, weekday, dow, doy) {
|
||
var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
|
||
date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
|
||
|
||
this.year(date.getUTCFullYear());
|
||
this.month(date.getUTCMonth());
|
||
this.date(date.getUTCDate());
|
||
return this;
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('Q', 0, 'Qo', 'quarter');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('quarter', 'Q');
|
||
|
||
// PRIORITY
|
||
|
||
addUnitPriority('quarter', 7);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('Q', match1);
|
||
addParseToken('Q', function (input, array) {
|
||
array[MONTH] = (toInt(input) - 1) * 3;
|
||
});
|
||
|
||
// MOMENTS
|
||
|
||
function getSetQuarter (input) {
|
||
return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('D', ['DD', 2], 'Do', 'date');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('date', 'D');
|
||
|
||
// PRIOROITY
|
||
addUnitPriority('date', 9);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('D', match1to2);
|
||
addRegexToken('DD', match1to2, match2);
|
||
addRegexToken('Do', function (isStrict, locale) {
|
||
// TODO: Remove "ordinalParse" fallback in next major release.
|
||
return isStrict ?
|
||
(locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
|
||
locale._dayOfMonthOrdinalParseLenient;
|
||
});
|
||
|
||
addParseToken(['D', 'DD'], DATE);
|
||
addParseToken('Do', function (input, array) {
|
||
array[DATE] = toInt(input.match(match1to2)[0]);
|
||
});
|
||
|
||
// MOMENTS
|
||
|
||
var getSetDayOfMonth = makeGetSet('Date', true);
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('dayOfYear', 'DDD');
|
||
|
||
// PRIORITY
|
||
addUnitPriority('dayOfYear', 4);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('DDD', match1to3);
|
||
addRegexToken('DDDD', match3);
|
||
addParseToken(['DDD', 'DDDD'], function (input, array, config) {
|
||
config._dayOfYear = toInt(input);
|
||
});
|
||
|
||
// HELPERS
|
||
|
||
// MOMENTS
|
||
|
||
function getSetDayOfYear (input) {
|
||
var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
|
||
return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
|
||
}
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('m', ['mm', 2], 0, 'minute');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('minute', 'm');
|
||
|
||
// PRIORITY
|
||
|
||
addUnitPriority('minute', 14);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('m', match1to2);
|
||
addRegexToken('mm', match1to2, match2);
|
||
addParseToken(['m', 'mm'], MINUTE);
|
||
|
||
// MOMENTS
|
||
|
||
var getSetMinute = makeGetSet('Minutes', false);
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('s', ['ss', 2], 0, 'second');
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('second', 's');
|
||
|
||
// PRIORITY
|
||
|
||
addUnitPriority('second', 15);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('s', match1to2);
|
||
addRegexToken('ss', match1to2, match2);
|
||
addParseToken(['s', 'ss'], SECOND);
|
||
|
||
// MOMENTS
|
||
|
||
var getSetSecond = makeGetSet('Seconds', false);
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('S', 0, 0, function () {
|
||
return ~~(this.millisecond() / 100);
|
||
});
|
||
|
||
addFormatToken(0, ['SS', 2], 0, function () {
|
||
return ~~(this.millisecond() / 10);
|
||
});
|
||
|
||
addFormatToken(0, ['SSS', 3], 0, 'millisecond');
|
||
addFormatToken(0, ['SSSS', 4], 0, function () {
|
||
return this.millisecond() * 10;
|
||
});
|
||
addFormatToken(0, ['SSSSS', 5], 0, function () {
|
||
return this.millisecond() * 100;
|
||
});
|
||
addFormatToken(0, ['SSSSSS', 6], 0, function () {
|
||
return this.millisecond() * 1000;
|
||
});
|
||
addFormatToken(0, ['SSSSSSS', 7], 0, function () {
|
||
return this.millisecond() * 10000;
|
||
});
|
||
addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
|
||
return this.millisecond() * 100000;
|
||
});
|
||
addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
|
||
return this.millisecond() * 1000000;
|
||
});
|
||
|
||
|
||
// ALIASES
|
||
|
||
addUnitAlias('millisecond', 'ms');
|
||
|
||
// PRIORITY
|
||
|
||
addUnitPriority('millisecond', 16);
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('S', match1to3, match1);
|
||
addRegexToken('SS', match1to3, match2);
|
||
addRegexToken('SSS', match1to3, match3);
|
||
|
||
var token;
|
||
for (token = 'SSSS'; token.length <= 9; token += 'S') {
|
||
addRegexToken(token, matchUnsigned);
|
||
}
|
||
|
||
function parseMs(input, array) {
|
||
array[MILLISECOND] = toInt(('0.' + input) * 1000);
|
||
}
|
||
|
||
for (token = 'S'; token.length <= 9; token += 'S') {
|
||
addParseToken(token, parseMs);
|
||
}
|
||
// MOMENTS
|
||
|
||
var getSetMillisecond = makeGetSet('Milliseconds', false);
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('z', 0, 0, 'zoneAbbr');
|
||
addFormatToken('zz', 0, 0, 'zoneName');
|
||
|
||
// MOMENTS
|
||
|
||
function getZoneAbbr () {
|
||
return this._isUTC ? 'UTC' : '';
|
||
}
|
||
|
||
function getZoneName () {
|
||
return this._isUTC ? 'Coordinated Universal Time' : '';
|
||
}
|
||
|
||
var proto = Moment.prototype;
|
||
|
||
proto.add = add;
|
||
proto.calendar = calendar$1;
|
||
proto.clone = clone;
|
||
proto.diff = diff;
|
||
proto.endOf = endOf;
|
||
proto.format = format;
|
||
proto.from = from;
|
||
proto.fromNow = fromNow;
|
||
proto.to = to;
|
||
proto.toNow = toNow;
|
||
proto.get = stringGet;
|
||
proto.invalidAt = invalidAt;
|
||
proto.isAfter = isAfter;
|
||
proto.isBefore = isBefore;
|
||
proto.isBetween = isBetween;
|
||
proto.isSame = isSame;
|
||
proto.isSameOrAfter = isSameOrAfter;
|
||
proto.isSameOrBefore = isSameOrBefore;
|
||
proto.isValid = isValid$2;
|
||
proto.lang = lang;
|
||
proto.locale = locale;
|
||
proto.localeData = localeData;
|
||
proto.max = prototypeMax;
|
||
proto.min = prototypeMin;
|
||
proto.parsingFlags = parsingFlags;
|
||
proto.set = stringSet;
|
||
proto.startOf = startOf;
|
||
proto.subtract = subtract;
|
||
proto.toArray = toArray;
|
||
proto.toObject = toObject;
|
||
proto.toDate = toDate;
|
||
proto.toISOString = toISOString;
|
||
proto.inspect = inspect;
|
||
proto.toJSON = toJSON;
|
||
proto.toString = toString;
|
||
proto.unix = unix;
|
||
proto.valueOf = valueOf;
|
||
proto.creationData = creationData;
|
||
|
||
// Year
|
||
proto.year = getSetYear;
|
||
proto.isLeapYear = getIsLeapYear;
|
||
|
||
// Week Year
|
||
proto.weekYear = getSetWeekYear;
|
||
proto.isoWeekYear = getSetISOWeekYear;
|
||
|
||
// Quarter
|
||
proto.quarter = proto.quarters = getSetQuarter;
|
||
|
||
// Month
|
||
proto.month = getSetMonth;
|
||
proto.daysInMonth = getDaysInMonth;
|
||
|
||
// Week
|
||
proto.week = proto.weeks = getSetWeek;
|
||
proto.isoWeek = proto.isoWeeks = getSetISOWeek;
|
||
proto.weeksInYear = getWeeksInYear;
|
||
proto.isoWeeksInYear = getISOWeeksInYear;
|
||
|
||
// Day
|
||
proto.date = getSetDayOfMonth;
|
||
proto.day = proto.days = getSetDayOfWeek;
|
||
proto.weekday = getSetLocaleDayOfWeek;
|
||
proto.isoWeekday = getSetISODayOfWeek;
|
||
proto.dayOfYear = getSetDayOfYear;
|
||
|
||
// Hour
|
||
proto.hour = proto.hours = getSetHour;
|
||
|
||
// Minute
|
||
proto.minute = proto.minutes = getSetMinute;
|
||
|
||
// Second
|
||
proto.second = proto.seconds = getSetSecond;
|
||
|
||
// Millisecond
|
||
proto.millisecond = proto.milliseconds = getSetMillisecond;
|
||
|
||
// Offset
|
||
proto.utcOffset = getSetOffset;
|
||
proto.utc = setOffsetToUTC;
|
||
proto.local = setOffsetToLocal;
|
||
proto.parseZone = setOffsetToParsedOffset;
|
||
proto.hasAlignedHourOffset = hasAlignedHourOffset;
|
||
proto.isDST = isDaylightSavingTime;
|
||
proto.isLocal = isLocal;
|
||
proto.isUtcOffset = isUtcOffset;
|
||
proto.isUtc = isUtc;
|
||
proto.isUTC = isUtc;
|
||
|
||
// Timezone
|
||
proto.zoneAbbr = getZoneAbbr;
|
||
proto.zoneName = getZoneName;
|
||
|
||
// Deprecations
|
||
proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
|
||
proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
|
||
proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
|
||
proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
|
||
proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
|
||
|
||
function createUnix (input) {
|
||
return createLocal(input * 1000);
|
||
}
|
||
|
||
function createInZone () {
|
||
return createLocal.apply(null, arguments).parseZone();
|
||
}
|
||
|
||
function preParsePostFormat (string) {
|
||
return string;
|
||
}
|
||
|
||
var proto$1 = Locale.prototype;
|
||
|
||
proto$1.calendar = calendar;
|
||
proto$1.longDateFormat = longDateFormat;
|
||
proto$1.invalidDate = invalidDate;
|
||
proto$1.ordinal = ordinal;
|
||
proto$1.preparse = preParsePostFormat;
|
||
proto$1.postformat = preParsePostFormat;
|
||
proto$1.relativeTime = relativeTime;
|
||
proto$1.pastFuture = pastFuture;
|
||
proto$1.set = set;
|
||
|
||
// Month
|
||
proto$1.months = localeMonths;
|
||
proto$1.monthsShort = localeMonthsShort;
|
||
proto$1.monthsParse = localeMonthsParse;
|
||
proto$1.monthsRegex = monthsRegex;
|
||
proto$1.monthsShortRegex = monthsShortRegex;
|
||
|
||
// Week
|
||
proto$1.week = localeWeek;
|
||
proto$1.firstDayOfYear = localeFirstDayOfYear;
|
||
proto$1.firstDayOfWeek = localeFirstDayOfWeek;
|
||
|
||
// Day of Week
|
||
proto$1.weekdays = localeWeekdays;
|
||
proto$1.weekdaysMin = localeWeekdaysMin;
|
||
proto$1.weekdaysShort = localeWeekdaysShort;
|
||
proto$1.weekdaysParse = localeWeekdaysParse;
|
||
|
||
proto$1.weekdaysRegex = weekdaysRegex;
|
||
proto$1.weekdaysShortRegex = weekdaysShortRegex;
|
||
proto$1.weekdaysMinRegex = weekdaysMinRegex;
|
||
|
||
// Hours
|
||
proto$1.isPM = localeIsPM;
|
||
proto$1.meridiem = localeMeridiem;
|
||
|
||
function get$1 (format, index, field, setter) {
|
||
var locale = getLocale();
|
||
var utc = createUTC().set(setter, index);
|
||
return locale[field](utc, format);
|
||
}
|
||
|
||
function listMonthsImpl (format, index, field) {
|
||
if (isNumber(format)) {
|
||
index = format;
|
||
format = undefined;
|
||
}
|
||
|
||
format = format || '';
|
||
|
||
if (index != null) {
|
||
return get$1(format, index, field, 'month');
|
||
}
|
||
|
||
var i;
|
||
var out = [];
|
||
for (i = 0; i < 12; i++) {
|
||
out[i] = get$1(format, i, field, 'month');
|
||
}
|
||
return out;
|
||
}
|
||
|
||
// ()
|
||
// (5)
|
||
// (fmt, 5)
|
||
// (fmt)
|
||
// (true)
|
||
// (true, 5)
|
||
// (true, fmt, 5)
|
||
// (true, fmt)
|
||
function listWeekdaysImpl (localeSorted, format, index, field) {
|
||
if (typeof localeSorted === 'boolean') {
|
||
if (isNumber(format)) {
|
||
index = format;
|
||
format = undefined;
|
||
}
|
||
|
||
format = format || '';
|
||
} else {
|
||
format = localeSorted;
|
||
index = format;
|
||
localeSorted = false;
|
||
|
||
if (isNumber(format)) {
|
||
index = format;
|
||
format = undefined;
|
||
}
|
||
|
||
format = format || '';
|
||
}
|
||
|
||
var locale = getLocale(),
|
||
shift = localeSorted ? locale._week.dow : 0;
|
||
|
||
if (index != null) {
|
||
return get$1(format, (index + shift) % 7, field, 'day');
|
||
}
|
||
|
||
var i;
|
||
var out = [];
|
||
for (i = 0; i < 7; i++) {
|
||
out[i] = get$1(format, (i + shift) % 7, field, 'day');
|
||
}
|
||
return out;
|
||
}
|
||
|
||
function listMonths (format, index) {
|
||
return listMonthsImpl(format, index, 'months');
|
||
}
|
||
|
||
function listMonthsShort (format, index) {
|
||
return listMonthsImpl(format, index, 'monthsShort');
|
||
}
|
||
|
||
function listWeekdays (localeSorted, format, index) {
|
||
return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
|
||
}
|
||
|
||
function listWeekdaysShort (localeSorted, format, index) {
|
||
return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
|
||
}
|
||
|
||
function listWeekdaysMin (localeSorted, format, index) {
|
||
return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
|
||
}
|
||
|
||
getSetGlobalLocale('en', {
|
||
dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (toInt(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
}
|
||
});
|
||
|
||
// Side effect imports
|
||
hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
|
||
hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
|
||
|
||
var mathAbs = Math.abs;
|
||
|
||
function abs () {
|
||
var data = this._data;
|
||
|
||
this._milliseconds = mathAbs(this._milliseconds);
|
||
this._days = mathAbs(this._days);
|
||
this._months = mathAbs(this._months);
|
||
|
||
data.milliseconds = mathAbs(data.milliseconds);
|
||
data.seconds = mathAbs(data.seconds);
|
||
data.minutes = mathAbs(data.minutes);
|
||
data.hours = mathAbs(data.hours);
|
||
data.months = mathAbs(data.months);
|
||
data.years = mathAbs(data.years);
|
||
|
||
return this;
|
||
}
|
||
|
||
function addSubtract$1 (duration, input, value, direction) {
|
||
var other = createDuration(input, value);
|
||
|
||
duration._milliseconds += direction * other._milliseconds;
|
||
duration._days += direction * other._days;
|
||
duration._months += direction * other._months;
|
||
|
||
return duration._bubble();
|
||
}
|
||
|
||
// supports only 2.0-style add(1, 's') or add(duration)
|
||
function add$1 (input, value) {
|
||
return addSubtract$1(this, input, value, 1);
|
||
}
|
||
|
||
// supports only 2.0-style subtract(1, 's') or subtract(duration)
|
||
function subtract$1 (input, value) {
|
||
return addSubtract$1(this, input, value, -1);
|
||
}
|
||
|
||
function absCeil (number) {
|
||
if (number < 0) {
|
||
return Math.floor(number);
|
||
} else {
|
||
return Math.ceil(number);
|
||
}
|
||
}
|
||
|
||
function bubble () {
|
||
var milliseconds = this._milliseconds;
|
||
var days = this._days;
|
||
var months = this._months;
|
||
var data = this._data;
|
||
var seconds, minutes, hours, years, monthsFromDays;
|
||
|
||
// if we have a mix of positive and negative values, bubble down first
|
||
// check: https://github.com/moment/moment/issues/2166
|
||
if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
|
||
(milliseconds <= 0 && days <= 0 && months <= 0))) {
|
||
milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
|
||
days = 0;
|
||
months = 0;
|
||
}
|
||
|
||
// The following code bubbles up values, see the tests for
|
||
// examples of what that means.
|
||
data.milliseconds = milliseconds % 1000;
|
||
|
||
seconds = absFloor(milliseconds / 1000);
|
||
data.seconds = seconds % 60;
|
||
|
||
minutes = absFloor(seconds / 60);
|
||
data.minutes = minutes % 60;
|
||
|
||
hours = absFloor(minutes / 60);
|
||
data.hours = hours % 24;
|
||
|
||
days += absFloor(hours / 24);
|
||
|
||
// convert days to months
|
||
monthsFromDays = absFloor(daysToMonths(days));
|
||
months += monthsFromDays;
|
||
days -= absCeil(monthsToDays(monthsFromDays));
|
||
|
||
// 12 months -> 1 year
|
||
years = absFloor(months / 12);
|
||
months %= 12;
|
||
|
||
data.days = days;
|
||
data.months = months;
|
||
data.years = years;
|
||
|
||
return this;
|
||
}
|
||
|
||
function daysToMonths (days) {
|
||
// 400 years have 146097 days (taking into account leap year rules)
|
||
// 400 years have 12 months === 4800
|
||
return days * 4800 / 146097;
|
||
}
|
||
|
||
function monthsToDays (months) {
|
||
// the reverse of daysToMonths
|
||
return months * 146097 / 4800;
|
||
}
|
||
|
||
function as (units) {
|
||
if (!this.isValid()) {
|
||
return NaN;
|
||
}
|
||
var days;
|
||
var months;
|
||
var milliseconds = this._milliseconds;
|
||
|
||
units = normalizeUnits(units);
|
||
|
||
if (units === 'month' || units === 'year') {
|
||
days = this._days + milliseconds / 864e5;
|
||
months = this._months + daysToMonths(days);
|
||
return units === 'month' ? months : months / 12;
|
||
} else {
|
||
// handle milliseconds separately because of floating point math errors (issue #1867)
|
||
days = this._days + Math.round(monthsToDays(this._months));
|
||
switch (units) {
|
||
case 'week' : return days / 7 + milliseconds / 6048e5;
|
||
case 'day' : return days + milliseconds / 864e5;
|
||
case 'hour' : return days * 24 + milliseconds / 36e5;
|
||
case 'minute' : return days * 1440 + milliseconds / 6e4;
|
||
case 'second' : return days * 86400 + milliseconds / 1000;
|
||
// Math.floor prevents floating point math errors here
|
||
case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
|
||
default: throw new Error('Unknown unit ' + units);
|
||
}
|
||
}
|
||
}
|
||
|
||
// TODO: Use this.as('ms')?
|
||
function valueOf$1 () {
|
||
if (!this.isValid()) {
|
||
return NaN;
|
||
}
|
||
return (
|
||
this._milliseconds +
|
||
this._days * 864e5 +
|
||
(this._months % 12) * 2592e6 +
|
||
toInt(this._months / 12) * 31536e6
|
||
);
|
||
}
|
||
|
||
function makeAs (alias) {
|
||
return function () {
|
||
return this.as(alias);
|
||
};
|
||
}
|
||
|
||
var asMilliseconds = makeAs('ms');
|
||
var asSeconds = makeAs('s');
|
||
var asMinutes = makeAs('m');
|
||
var asHours = makeAs('h');
|
||
var asDays = makeAs('d');
|
||
var asWeeks = makeAs('w');
|
||
var asMonths = makeAs('M');
|
||
var asYears = makeAs('y');
|
||
|
||
function clone$1 () {
|
||
return createDuration(this);
|
||
}
|
||
|
||
function get$2 (units) {
|
||
units = normalizeUnits(units);
|
||
return this.isValid() ? this[units + 's']() : NaN;
|
||
}
|
||
|
||
function makeGetter(name) {
|
||
return function () {
|
||
return this.isValid() ? this._data[name] : NaN;
|
||
};
|
||
}
|
||
|
||
var milliseconds = makeGetter('milliseconds');
|
||
var seconds = makeGetter('seconds');
|
||
var minutes = makeGetter('minutes');
|
||
var hours = makeGetter('hours');
|
||
var days = makeGetter('days');
|
||
var months = makeGetter('months');
|
||
var years = makeGetter('years');
|
||
|
||
function weeks () {
|
||
return absFloor(this.days() / 7);
|
||
}
|
||
|
||
var round = Math.round;
|
||
var thresholds = {
|
||
ss: 44, // a few seconds to seconds
|
||
s : 45, // seconds to minute
|
||
m : 45, // minutes to hour
|
||
h : 22, // hours to day
|
||
d : 26, // days to month
|
||
M : 11 // months to year
|
||
};
|
||
|
||
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
|
||
function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
|
||
return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
|
||
}
|
||
|
||
function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
|
||
var duration = createDuration(posNegDuration).abs();
|
||
var seconds = round(duration.as('s'));
|
||
var minutes = round(duration.as('m'));
|
||
var hours = round(duration.as('h'));
|
||
var days = round(duration.as('d'));
|
||
var months = round(duration.as('M'));
|
||
var years = round(duration.as('y'));
|
||
|
||
var a = seconds <= thresholds.ss && ['s', seconds] ||
|
||
seconds < thresholds.s && ['ss', seconds] ||
|
||
minutes <= 1 && ['m'] ||
|
||
minutes < thresholds.m && ['mm', minutes] ||
|
||
hours <= 1 && ['h'] ||
|
||
hours < thresholds.h && ['hh', hours] ||
|
||
days <= 1 && ['d'] ||
|
||
days < thresholds.d && ['dd', days] ||
|
||
months <= 1 && ['M'] ||
|
||
months < thresholds.M && ['MM', months] ||
|
||
years <= 1 && ['y'] || ['yy', years];
|
||
|
||
a[2] = withoutSuffix;
|
||
a[3] = +posNegDuration > 0;
|
||
a[4] = locale;
|
||
return substituteTimeAgo.apply(null, a);
|
||
}
|
||
|
||
// This function allows you to set the rounding function for relative time strings
|
||
function getSetRelativeTimeRounding (roundingFunction) {
|
||
if (roundingFunction === undefined) {
|
||
return round;
|
||
}
|
||
if (typeof(roundingFunction) === 'function') {
|
||
round = roundingFunction;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// This function allows you to set a threshold for relative time strings
|
||
function getSetRelativeTimeThreshold (threshold, limit) {
|
||
if (thresholds[threshold] === undefined) {
|
||
return false;
|
||
}
|
||
if (limit === undefined) {
|
||
return thresholds[threshold];
|
||
}
|
||
thresholds[threshold] = limit;
|
||
if (threshold === 's') {
|
||
thresholds.ss = limit - 1;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
function humanize (withSuffix) {
|
||
if (!this.isValid()) {
|
||
return this.localeData().invalidDate();
|
||
}
|
||
|
||
var locale = this.localeData();
|
||
var output = relativeTime$1(this, !withSuffix, locale);
|
||
|
||
if (withSuffix) {
|
||
output = locale.pastFuture(+this, output);
|
||
}
|
||
|
||
return locale.postformat(output);
|
||
}
|
||
|
||
var abs$1 = Math.abs;
|
||
|
||
function sign(x) {
|
||
return ((x > 0) - (x < 0)) || +x;
|
||
}
|
||
|
||
function toISOString$1() {
|
||
// for ISO strings we do not use the normal bubbling rules:
|
||
// * milliseconds bubble up until they become hours
|
||
// * days do not bubble at all
|
||
// * months bubble up until they become years
|
||
// This is because there is no context-free conversion between hours and days
|
||
// (think of clock changes)
|
||
// and also not between days and months (28-31 days per month)
|
||
if (!this.isValid()) {
|
||
return this.localeData().invalidDate();
|
||
}
|
||
|
||
var seconds = abs$1(this._milliseconds) / 1000;
|
||
var days = abs$1(this._days);
|
||
var months = abs$1(this._months);
|
||
var minutes, hours, years;
|
||
|
||
// 3600 seconds -> 60 minutes -> 1 hour
|
||
minutes = absFloor(seconds / 60);
|
||
hours = absFloor(minutes / 60);
|
||
seconds %= 60;
|
||
minutes %= 60;
|
||
|
||
// 12 months -> 1 year
|
||
years = absFloor(months / 12);
|
||
months %= 12;
|
||
|
||
|
||
// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
|
||
var Y = years;
|
||
var M = months;
|
||
var D = days;
|
||
var h = hours;
|
||
var m = minutes;
|
||
var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
|
||
var total = this.asSeconds();
|
||
|
||
if (!total) {
|
||
// this is the same as C#'s (Noda) and python (isodate)...
|
||
// but not other JS (goog.date)
|
||
return 'P0D';
|
||
}
|
||
|
||
var totalSign = total < 0 ? '-' : '';
|
||
var ymSign = sign(this._months) !== sign(total) ? '-' : '';
|
||
var daysSign = sign(this._days) !== sign(total) ? '-' : '';
|
||
var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
|
||
|
||
return totalSign + 'P' +
|
||
(Y ? ymSign + Y + 'Y' : '') +
|
||
(M ? ymSign + M + 'M' : '') +
|
||
(D ? daysSign + D + 'D' : '') +
|
||
((h || m || s) ? 'T' : '') +
|
||
(h ? hmsSign + h + 'H' : '') +
|
||
(m ? hmsSign + m + 'M' : '') +
|
||
(s ? hmsSign + s + 'S' : '');
|
||
}
|
||
|
||
var proto$2 = Duration.prototype;
|
||
|
||
proto$2.isValid = isValid$1;
|
||
proto$2.abs = abs;
|
||
proto$2.add = add$1;
|
||
proto$2.subtract = subtract$1;
|
||
proto$2.as = as;
|
||
proto$2.asMilliseconds = asMilliseconds;
|
||
proto$2.asSeconds = asSeconds;
|
||
proto$2.asMinutes = asMinutes;
|
||
proto$2.asHours = asHours;
|
||
proto$2.asDays = asDays;
|
||
proto$2.asWeeks = asWeeks;
|
||
proto$2.asMonths = asMonths;
|
||
proto$2.asYears = asYears;
|
||
proto$2.valueOf = valueOf$1;
|
||
proto$2._bubble = bubble;
|
||
proto$2.clone = clone$1;
|
||
proto$2.get = get$2;
|
||
proto$2.milliseconds = milliseconds;
|
||
proto$2.seconds = seconds;
|
||
proto$2.minutes = minutes;
|
||
proto$2.hours = hours;
|
||
proto$2.days = days;
|
||
proto$2.weeks = weeks;
|
||
proto$2.months = months;
|
||
proto$2.years = years;
|
||
proto$2.humanize = humanize;
|
||
proto$2.toISOString = toISOString$1;
|
||
proto$2.toString = toISOString$1;
|
||
proto$2.toJSON = toISOString$1;
|
||
proto$2.locale = locale;
|
||
proto$2.localeData = localeData;
|
||
|
||
// Deprecations
|
||
proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
|
||
proto$2.lang = lang;
|
||
|
||
// Side effect imports
|
||
|
||
// FORMATTING
|
||
|
||
addFormatToken('X', 0, 0, 'unix');
|
||
addFormatToken('x', 0, 0, 'valueOf');
|
||
|
||
// PARSING
|
||
|
||
addRegexToken('x', matchSigned);
|
||
addRegexToken('X', matchTimestamp);
|
||
addParseToken('X', function (input, array, config) {
|
||
config._d = new Date(parseFloat(input, 10) * 1000);
|
||
});
|
||
addParseToken('x', function (input, array, config) {
|
||
config._d = new Date(toInt(input));
|
||
});
|
||
|
||
// Side effect imports
|
||
|
||
//! moment.js
|
||
//! version : 2.19.4
|
||
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
|
||
//! license : MIT
|
||
//! momentjs.com
|
||
|
||
hooks.version = '2.19.4';
|
||
|
||
setHookCallback(createLocal);
|
||
|
||
hooks.fn = proto;
|
||
hooks.min = min;
|
||
hooks.max = max;
|
||
hooks.now = now;
|
||
hooks.utc = createUTC;
|
||
hooks.unix = createUnix;
|
||
hooks.months = listMonths;
|
||
hooks.isDate = isDate;
|
||
hooks.locale = getSetGlobalLocale;
|
||
hooks.invalid = createInvalid;
|
||
hooks.duration = createDuration;
|
||
hooks.isMoment = isMoment;
|
||
hooks.weekdays = listWeekdays;
|
||
hooks.parseZone = createInZone;
|
||
hooks.localeData = getLocale;
|
||
hooks.isDuration = isDuration;
|
||
hooks.monthsShort = listMonthsShort;
|
||
hooks.weekdaysMin = listWeekdaysMin;
|
||
hooks.defineLocale = defineLocale;
|
||
hooks.updateLocale = updateLocale;
|
||
hooks.locales = listLocales;
|
||
hooks.weekdaysShort = listWeekdaysShort;
|
||
hooks.normalizeUnits = normalizeUnits;
|
||
hooks.relativeTimeRounding = getSetRelativeTimeRounding;
|
||
hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
|
||
hooks.calendarFormat = getCalendarFormat;
|
||
hooks.prototype = proto;
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Afrikaans [af]
|
||
//! author : Werner Mollentze : https://github.com/wernerm
|
||
|
||
hooks.defineLocale('af', {
|
||
months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),
|
||
weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'),
|
||
weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),
|
||
weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),
|
||
meridiemParse: /vm|nm/i,
|
||
isPM : function (input) {
|
||
return /^nm$/i.test(input);
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 12) {
|
||
return isLower ? 'vm' : 'VM';
|
||
} else {
|
||
return isLower ? 'nm' : 'NM';
|
||
}
|
||
},
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Vandag om] LT',
|
||
nextDay : '[Môre om] LT',
|
||
nextWeek : 'dddd [om] LT',
|
||
lastDay : '[Gister om] LT',
|
||
lastWeek : '[Laas] dddd [om] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'oor %s',
|
||
past : '%s gelede',
|
||
s : '\'n paar sekondes',
|
||
m : '\'n minuut',
|
||
mm : '%d minute',
|
||
h : '\'n uur',
|
||
hh : '%d ure',
|
||
d : '\'n dag',
|
||
dd : '%d dae',
|
||
M : '\'n maand',
|
||
MM : '%d maande',
|
||
y : '\'n jaar',
|
||
yy : '%d jaar'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/,
|
||
ordinal : function (number) {
|
||
return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter
|
||
},
|
||
week : {
|
||
dow : 1, // Maandag is die eerste dag van die week.
|
||
doy : 4 // Die week wat die 4de Januarie bevat is die eerste week van die jaar.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic (Algeria) [ar-dz]
|
||
//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
|
||
|
||
hooks.defineLocale('ar-dz', {
|
||
months : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
|
||
monthsShort : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
|
||
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort : 'احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin : 'أح_إث_ثلا_أر_خم_جم_سب'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[اليوم على الساعة] LT',
|
||
nextDay: '[غدا على الساعة] LT',
|
||
nextWeek: 'dddd [على الساعة] LT',
|
||
lastDay: '[أمس على الساعة] LT',
|
||
lastWeek: 'dddd [على الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'في %s',
|
||
past : 'منذ %s',
|
||
s : 'ثوان',
|
||
m : 'دقيقة',
|
||
mm : '%d دقائق',
|
||
h : 'ساعة',
|
||
hh : '%d ساعات',
|
||
d : 'يوم',
|
||
dd : '%d أيام',
|
||
M : 'شهر',
|
||
MM : '%d أشهر',
|
||
y : 'سنة',
|
||
yy : '%d سنوات'
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic (Kuwait) [ar-kw]
|
||
//! author : Nusret Parlak: https://github.com/nusretparlak
|
||
|
||
hooks.defineLocale('ar-kw', {
|
||
months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
|
||
monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
|
||
weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[اليوم على الساعة] LT',
|
||
nextDay: '[غدا على الساعة] LT',
|
||
nextWeek: 'dddd [على الساعة] LT',
|
||
lastDay: '[أمس على الساعة] LT',
|
||
lastWeek: 'dddd [على الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'في %s',
|
||
past : 'منذ %s',
|
||
s : 'ثوان',
|
||
m : 'دقيقة',
|
||
mm : '%d دقائق',
|
||
h : 'ساعة',
|
||
hh : '%d ساعات',
|
||
d : 'يوم',
|
||
dd : '%d أيام',
|
||
M : 'شهر',
|
||
MM : '%d أشهر',
|
||
y : 'سنة',
|
||
yy : '%d سنوات'
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic (Lybia) [ar-ly]
|
||
//! author : Ali Hmer: https://github.com/kikoanis
|
||
|
||
var symbolMap = {
|
||
'1': '1',
|
||
'2': '2',
|
||
'3': '3',
|
||
'4': '4',
|
||
'5': '5',
|
||
'6': '6',
|
||
'7': '7',
|
||
'8': '8',
|
||
'9': '9',
|
||
'0': '0'
|
||
};
|
||
var pluralForm = function (n) {
|
||
return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
|
||
};
|
||
var plurals = {
|
||
s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
|
||
m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
|
||
h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
|
||
d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
|
||
M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
|
||
y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
|
||
};
|
||
var pluralize = function (u) {
|
||
return function (number, withoutSuffix, string, isFuture) {
|
||
var f = pluralForm(number),
|
||
str = plurals[u][pluralForm(number)];
|
||
if (f === 2) {
|
||
str = str[withoutSuffix ? 0 : 1];
|
||
}
|
||
return str.replace(/%d/i, number);
|
||
};
|
||
};
|
||
var months$1 = [
|
||
'يناير',
|
||
'فبراير',
|
||
'مارس',
|
||
'أبريل',
|
||
'مايو',
|
||
'يونيو',
|
||
'يوليو',
|
||
'أغسطس',
|
||
'سبتمبر',
|
||
'أكتوبر',
|
||
'نوفمبر',
|
||
'ديسمبر'
|
||
];
|
||
|
||
hooks.defineLocale('ar-ly', {
|
||
months : months$1,
|
||
monthsShort : months$1,
|
||
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'D/\u200FM/\u200FYYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /ص|م/,
|
||
isPM : function (input) {
|
||
return 'م' === input;
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'ص';
|
||
} else {
|
||
return 'م';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay: '[اليوم عند الساعة] LT',
|
||
nextDay: '[غدًا عند الساعة] LT',
|
||
nextWeek: 'dddd [عند الساعة] LT',
|
||
lastDay: '[أمس عند الساعة] LT',
|
||
lastWeek: 'dddd [عند الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'بعد %s',
|
||
past : 'منذ %s',
|
||
s : pluralize('s'),
|
||
m : pluralize('m'),
|
||
mm : pluralize('m'),
|
||
h : pluralize('h'),
|
||
hh : pluralize('h'),
|
||
d : pluralize('d'),
|
||
dd : pluralize('d'),
|
||
M : pluralize('M'),
|
||
MM : pluralize('M'),
|
||
y : pluralize('y'),
|
||
yy : pluralize('y')
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap[match];
|
||
}).replace(/,/g, '،');
|
||
},
|
||
week : {
|
||
dow : 6, // Saturday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic (Morocco) [ar-ma]
|
||
//! author : ElFadili Yassine : https://github.com/ElFadiliY
|
||
//! author : Abdel Said : https://github.com/abdelsaid
|
||
|
||
hooks.defineLocale('ar-ma', {
|
||
months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
|
||
monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
|
||
weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[اليوم على الساعة] LT',
|
||
nextDay: '[غدا على الساعة] LT',
|
||
nextWeek: 'dddd [على الساعة] LT',
|
||
lastDay: '[أمس على الساعة] LT',
|
||
lastWeek: 'dddd [على الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'في %s',
|
||
past : 'منذ %s',
|
||
s : 'ثوان',
|
||
m : 'دقيقة',
|
||
mm : '%d دقائق',
|
||
h : 'ساعة',
|
||
hh : '%d ساعات',
|
||
d : 'يوم',
|
||
dd : '%d أيام',
|
||
M : 'شهر',
|
||
MM : '%d أشهر',
|
||
y : 'سنة',
|
||
yy : '%d سنوات'
|
||
},
|
||
week : {
|
||
dow : 6, // Saturday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic (Saudi Arabia) [ar-sa]
|
||
//! author : Suhail Alkowaileet : https://github.com/xsoh
|
||
|
||
var symbolMap$1 = {
|
||
'1': '١',
|
||
'2': '٢',
|
||
'3': '٣',
|
||
'4': '٤',
|
||
'5': '٥',
|
||
'6': '٦',
|
||
'7': '٧',
|
||
'8': '٨',
|
||
'9': '٩',
|
||
'0': '٠'
|
||
};
|
||
var numberMap = {
|
||
'١': '1',
|
||
'٢': '2',
|
||
'٣': '3',
|
||
'٤': '4',
|
||
'٥': '5',
|
||
'٦': '6',
|
||
'٧': '7',
|
||
'٨': '8',
|
||
'٩': '9',
|
||
'٠': '0'
|
||
};
|
||
|
||
hooks.defineLocale('ar-sa', {
|
||
months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
|
||
monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
|
||
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /ص|م/,
|
||
isPM : function (input) {
|
||
return 'م' === input;
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'ص';
|
||
} else {
|
||
return 'م';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay: '[اليوم على الساعة] LT',
|
||
nextDay: '[غدا على الساعة] LT',
|
||
nextWeek: 'dddd [على الساعة] LT',
|
||
lastDay: '[أمس على الساعة] LT',
|
||
lastWeek: 'dddd [على الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'في %s',
|
||
past : 'منذ %s',
|
||
s : 'ثوان',
|
||
m : 'دقيقة',
|
||
mm : '%d دقائق',
|
||
h : 'ساعة',
|
||
hh : '%d ساعات',
|
||
d : 'يوم',
|
||
dd : '%d أيام',
|
||
M : 'شهر',
|
||
MM : '%d أشهر',
|
||
y : 'سنة',
|
||
yy : '%d سنوات'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
|
||
return numberMap[match];
|
||
}).replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$1[match];
|
||
}).replace(/,/g, '،');
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic (Tunisia) [ar-tn]
|
||
//! author : Nader Toukabri : https://github.com/naderio
|
||
|
||
hooks.defineLocale('ar-tn', {
|
||
months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
|
||
monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
|
||
weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat: {
|
||
LT: 'HH:mm',
|
||
LTS: 'HH:mm:ss',
|
||
L: 'DD/MM/YYYY',
|
||
LL: 'D MMMM YYYY',
|
||
LLL: 'D MMMM YYYY HH:mm',
|
||
LLLL: 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[اليوم على الساعة] LT',
|
||
nextDay: '[غدا على الساعة] LT',
|
||
nextWeek: 'dddd [على الساعة] LT',
|
||
lastDay: '[أمس على الساعة] LT',
|
||
lastWeek: 'dddd [على الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime: {
|
||
future: 'في %s',
|
||
past: 'منذ %s',
|
||
s: 'ثوان',
|
||
m: 'دقيقة',
|
||
mm: '%d دقائق',
|
||
h: 'ساعة',
|
||
hh: '%d ساعات',
|
||
d: 'يوم',
|
||
dd: '%d أيام',
|
||
M: 'شهر',
|
||
MM: '%d أشهر',
|
||
y: 'سنة',
|
||
yy: '%d سنوات'
|
||
},
|
||
week: {
|
||
dow: 1, // Monday is the first day of the week.
|
||
doy: 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Arabic [ar]
|
||
//! author : Abdel Said: https://github.com/abdelsaid
|
||
//! author : Ahmed Elkhatib
|
||
//! author : forabi https://github.com/forabi
|
||
|
||
var symbolMap$2 = {
|
||
'1': '١',
|
||
'2': '٢',
|
||
'3': '٣',
|
||
'4': '٤',
|
||
'5': '٥',
|
||
'6': '٦',
|
||
'7': '٧',
|
||
'8': '٨',
|
||
'9': '٩',
|
||
'0': '٠'
|
||
};
|
||
var numberMap$1 = {
|
||
'١': '1',
|
||
'٢': '2',
|
||
'٣': '3',
|
||
'٤': '4',
|
||
'٥': '5',
|
||
'٦': '6',
|
||
'٧': '7',
|
||
'٨': '8',
|
||
'٩': '9',
|
||
'٠': '0'
|
||
};
|
||
var pluralForm$1 = function (n) {
|
||
return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
|
||
};
|
||
var plurals$1 = {
|
||
s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
|
||
m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
|
||
h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
|
||
d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
|
||
M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
|
||
y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
|
||
};
|
||
var pluralize$1 = function (u) {
|
||
return function (number, withoutSuffix, string, isFuture) {
|
||
var f = pluralForm$1(number),
|
||
str = plurals$1[u][pluralForm$1(number)];
|
||
if (f === 2) {
|
||
str = str[withoutSuffix ? 0 : 1];
|
||
}
|
||
return str.replace(/%d/i, number);
|
||
};
|
||
};
|
||
var months$2 = [
|
||
'كانون الثاني يناير',
|
||
'شباط فبراير',
|
||
'آذار مارس',
|
||
'نيسان أبريل',
|
||
'أيار مايو',
|
||
'حزيران يونيو',
|
||
'تموز يوليو',
|
||
'آب أغسطس',
|
||
'أيلول سبتمبر',
|
||
'تشرين الأول أكتوبر',
|
||
'تشرين الثاني نوفمبر',
|
||
'كانون الأول ديسمبر'
|
||
];
|
||
|
||
hooks.defineLocale('ar', {
|
||
months : months$2,
|
||
monthsShort : months$2,
|
||
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||
weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
|
||
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'D/\u200FM/\u200FYYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /ص|م/,
|
||
isPM : function (input) {
|
||
return 'م' === input;
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'ص';
|
||
} else {
|
||
return 'م';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay: '[اليوم عند الساعة] LT',
|
||
nextDay: '[غدًا عند الساعة] LT',
|
||
nextWeek: 'dddd [عند الساعة] LT',
|
||
lastDay: '[أمس عند الساعة] LT',
|
||
lastWeek: 'dddd [عند الساعة] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'بعد %s',
|
||
past : 'منذ %s',
|
||
s : pluralize$1('s'),
|
||
m : pluralize$1('m'),
|
||
mm : pluralize$1('m'),
|
||
h : pluralize$1('h'),
|
||
hh : pluralize$1('h'),
|
||
d : pluralize$1('d'),
|
||
dd : pluralize$1('d'),
|
||
M : pluralize$1('M'),
|
||
MM : pluralize$1('M'),
|
||
y : pluralize$1('y'),
|
||
yy : pluralize$1('y')
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
|
||
return numberMap$1[match];
|
||
}).replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$2[match];
|
||
}).replace(/,/g, '،');
|
||
},
|
||
week : {
|
||
dow : 6, // Saturday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Azerbaijani [az]
|
||
//! author : topchiyev : https://github.com/topchiyev
|
||
|
||
var suffixes = {
|
||
1: '-inci',
|
||
5: '-inci',
|
||
8: '-inci',
|
||
70: '-inci',
|
||
80: '-inci',
|
||
2: '-nci',
|
||
7: '-nci',
|
||
20: '-nci',
|
||
50: '-nci',
|
||
3: '-üncü',
|
||
4: '-üncü',
|
||
100: '-üncü',
|
||
6: '-ncı',
|
||
9: '-uncu',
|
||
10: '-uncu',
|
||
30: '-uncu',
|
||
60: '-ıncı',
|
||
90: '-ıncı'
|
||
};
|
||
|
||
hooks.defineLocale('az', {
|
||
months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'),
|
||
monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'),
|
||
weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),
|
||
weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),
|
||
weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[bugün saat] LT',
|
||
nextDay : '[sabah saat] LT',
|
||
nextWeek : '[gələn həftə] dddd [saat] LT',
|
||
lastDay : '[dünən] LT',
|
||
lastWeek : '[keçən həftə] dddd [saat] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s sonra',
|
||
past : '%s əvvəl',
|
||
s : 'birneçə saniyyə',
|
||
m : 'bir dəqiqə',
|
||
mm : '%d dəqiqə',
|
||
h : 'bir saat',
|
||
hh : '%d saat',
|
||
d : 'bir gün',
|
||
dd : '%d gün',
|
||
M : 'bir ay',
|
||
MM : '%d ay',
|
||
y : 'bir il',
|
||
yy : '%d il'
|
||
},
|
||
meridiemParse: /gecə|səhər|gündüz|axşam/,
|
||
isPM : function (input) {
|
||
return /^(gündüz|axşam)$/.test(input);
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'gecə';
|
||
} else if (hour < 12) {
|
||
return 'səhər';
|
||
} else if (hour < 17) {
|
||
return 'gündüz';
|
||
} else {
|
||
return 'axşam';
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,
|
||
ordinal : function (number) {
|
||
if (number === 0) { // special case for zero
|
||
return number + '-ıncı';
|
||
}
|
||
var a = number % 10,
|
||
b = number % 100 - a,
|
||
c = number >= 100 ? 100 : null;
|
||
return number + (suffixes[a] || suffixes[b] || suffixes[c]);
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Belarusian [be]
|
||
//! author : Dmitry Demidov : https://github.com/demidov91
|
||
//! author: Praleska: http://praleska.pro/
|
||
//! Author : Menelion Elensúle : https://github.com/Oire
|
||
|
||
function plural(word, num) {
|
||
var forms = word.split('_');
|
||
return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
|
||
}
|
||
function relativeTimeWithPlural(number, withoutSuffix, key) {
|
||
var format = {
|
||
'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
|
||
'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
|
||
'dd': 'дзень_дні_дзён',
|
||
'MM': 'месяц_месяцы_месяцаў',
|
||
'yy': 'год_гады_гадоў'
|
||
};
|
||
if (key === 'm') {
|
||
return withoutSuffix ? 'хвіліна' : 'хвіліну';
|
||
}
|
||
else if (key === 'h') {
|
||
return withoutSuffix ? 'гадзіна' : 'гадзіну';
|
||
}
|
||
else {
|
||
return number + ' ' + plural(format[key], +number);
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('be', {
|
||
months : {
|
||
format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
|
||
standalone: 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
|
||
},
|
||
monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
|
||
weekdays : {
|
||
format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
|
||
standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
|
||
isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
|
||
},
|
||
weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
|
||
weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY г.',
|
||
LLL : 'D MMMM YYYY г., HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY г., HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Сёння ў] LT',
|
||
nextDay: '[Заўтра ў] LT',
|
||
lastDay: '[Учора ў] LT',
|
||
nextWeek: function () {
|
||
return '[У] dddd [ў] LT';
|
||
},
|
||
lastWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
case 3:
|
||
case 5:
|
||
case 6:
|
||
return '[У мінулую] dddd [ў] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
return '[У мінулы] dddd [ў] LT';
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'праз %s',
|
||
past : '%s таму',
|
||
s : 'некалькі секунд',
|
||
m : relativeTimeWithPlural,
|
||
mm : relativeTimeWithPlural,
|
||
h : relativeTimeWithPlural,
|
||
hh : relativeTimeWithPlural,
|
||
d : 'дзень',
|
||
dd : relativeTimeWithPlural,
|
||
M : 'месяц',
|
||
MM : relativeTimeWithPlural,
|
||
y : 'год',
|
||
yy : relativeTimeWithPlural
|
||
},
|
||
meridiemParse: /ночы|раніцы|дня|вечара/,
|
||
isPM : function (input) {
|
||
return /^(дня|вечара)$/.test(input);
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'ночы';
|
||
} else if (hour < 12) {
|
||
return 'раніцы';
|
||
} else if (hour < 17) {
|
||
return 'дня';
|
||
} else {
|
||
return 'вечара';
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(і|ы|га)/,
|
||
ordinal: function (number, period) {
|
||
switch (period) {
|
||
case 'M':
|
||
case 'd':
|
||
case 'DDD':
|
||
case 'w':
|
||
case 'W':
|
||
return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-і' : number + '-ы';
|
||
case 'D':
|
||
return number + '-га';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Bulgarian [bg]
|
||
//! author : Krasen Borisov : https://github.com/kraz
|
||
|
||
hooks.defineLocale('bg', {
|
||
months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
|
||
monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
|
||
weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),
|
||
weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
|
||
weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'D.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Днес в] LT',
|
||
nextDay : '[Утре в] LT',
|
||
nextWeek : 'dddd [в] LT',
|
||
lastDay : '[Вчера в] LT',
|
||
lastWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
case 3:
|
||
case 6:
|
||
return '[В изминалата] dddd [в] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[В изминалия] dddd [в] LT';
|
||
}
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'след %s',
|
||
past : 'преди %s',
|
||
s : 'няколко секунди',
|
||
m : 'минута',
|
||
mm : '%d минути',
|
||
h : 'час',
|
||
hh : '%d часа',
|
||
d : 'ден',
|
||
dd : '%d дни',
|
||
M : 'месец',
|
||
MM : '%d месеца',
|
||
y : 'година',
|
||
yy : '%d години'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
|
||
ordinal : function (number) {
|
||
var lastDigit = number % 10,
|
||
last2Digits = number % 100;
|
||
if (number === 0) {
|
||
return number + '-ев';
|
||
} else if (last2Digits === 0) {
|
||
return number + '-ен';
|
||
} else if (last2Digits > 10 && last2Digits < 20) {
|
||
return number + '-ти';
|
||
} else if (lastDigit === 1) {
|
||
return number + '-ви';
|
||
} else if (lastDigit === 2) {
|
||
return number + '-ри';
|
||
} else if (lastDigit === 7 || lastDigit === 8) {
|
||
return number + '-ми';
|
||
} else {
|
||
return number + '-ти';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Bambara [bm]
|
||
//! author : Estelle Comment : https://github.com/estellecomment
|
||
// Language contact person : Abdoufata Kane : https://github.com/abdoufata
|
||
|
||
hooks.defineLocale('bm', {
|
||
months : 'Zanwuyekalo_Fewuruyekalo_Marisikalo_Awirilikalo_Mɛkalo_Zuwɛnkalo_Zuluyekalo_Utikalo_Sɛtanburukalo_ɔkutɔburukalo_Nowanburukalo_Desanburukalo'.split('_'),
|
||
monthsShort : 'Zan_Few_Mar_Awi_Mɛ_Zuw_Zul_Uti_Sɛt_ɔku_Now_Des'.split('_'),
|
||
weekdays : 'Kari_Ntɛnɛn_Tarata_Araba_Alamisa_Juma_Sibiri'.split('_'),
|
||
weekdaysShort : 'Kar_Ntɛ_Tar_Ara_Ala_Jum_Sib'.split('_'),
|
||
weekdaysMin : 'Ka_Nt_Ta_Ar_Al_Ju_Si'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'MMMM [tile] D [san] YYYY',
|
||
LLL : 'MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm',
|
||
LLLL : 'dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Bi lɛrɛ] LT',
|
||
nextDay : '[Sini lɛrɛ] LT',
|
||
nextWeek : 'dddd [don lɛrɛ] LT',
|
||
lastDay : '[Kunu lɛrɛ] LT',
|
||
lastWeek : 'dddd [tɛmɛnen lɛrɛ] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s kɔnɔ',
|
||
past : 'a bɛ %s bɔ',
|
||
s : 'sanga dama dama',
|
||
m : 'miniti kelen',
|
||
mm : 'miniti %d',
|
||
h : 'lɛrɛ kelen',
|
||
hh : 'lɛrɛ %d',
|
||
d : 'tile kelen',
|
||
dd : 'tile %d',
|
||
M : 'kalo kelen',
|
||
MM : 'kalo %d',
|
||
y : 'san kelen',
|
||
yy : 'san %d'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Bengali [bn]
|
||
//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
|
||
|
||
var symbolMap$3 = {
|
||
'1': '১',
|
||
'2': '২',
|
||
'3': '৩',
|
||
'4': '৪',
|
||
'5': '৫',
|
||
'6': '৬',
|
||
'7': '৭',
|
||
'8': '৮',
|
||
'9': '৯',
|
||
'0': '০'
|
||
};
|
||
var numberMap$2 = {
|
||
'১': '1',
|
||
'২': '2',
|
||
'৩': '3',
|
||
'৪': '4',
|
||
'৫': '5',
|
||
'৬': '6',
|
||
'৭': '7',
|
||
'৮': '8',
|
||
'৯': '9',
|
||
'০': '0'
|
||
};
|
||
|
||
hooks.defineLocale('bn', {
|
||
months : 'জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'),
|
||
monthsShort : 'জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে'.split('_'),
|
||
weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split('_'),
|
||
weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'),
|
||
weekdaysMin : 'রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm সময়',
|
||
LTS : 'A h:mm:ss সময়',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm সময়',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm সময়'
|
||
},
|
||
calendar : {
|
||
sameDay : '[আজ] LT',
|
||
nextDay : '[আগামীকাল] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[গতকাল] LT',
|
||
lastWeek : '[গত] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s পরে',
|
||
past : '%s আগে',
|
||
s : 'কয়েক সেকেন্ড',
|
||
m : 'এক মিনিট',
|
||
mm : '%d মিনিট',
|
||
h : 'এক ঘন্টা',
|
||
hh : '%d ঘন্টা',
|
||
d : 'এক দিন',
|
||
dd : '%d দিন',
|
||
M : 'এক মাস',
|
||
MM : '%d মাস',
|
||
y : 'এক বছর',
|
||
yy : '%d বছর'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) {
|
||
return numberMap$2[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$3[match];
|
||
});
|
||
},
|
||
meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if ((meridiem === 'রাত' && hour >= 4) ||
|
||
(meridiem === 'দুপুর' && hour < 5) ||
|
||
meridiem === 'বিকাল') {
|
||
return hour + 12;
|
||
} else {
|
||
return hour;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'রাত';
|
||
} else if (hour < 10) {
|
||
return 'সকাল';
|
||
} else if (hour < 17) {
|
||
return 'দুপুর';
|
||
} else if (hour < 20) {
|
||
return 'বিকাল';
|
||
} else {
|
||
return 'রাত';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Tibetan [bo]
|
||
//! author : Thupten N. Chakrishar : https://github.com/vajradog
|
||
|
||
var symbolMap$4 = {
|
||
'1': '༡',
|
||
'2': '༢',
|
||
'3': '༣',
|
||
'4': '༤',
|
||
'5': '༥',
|
||
'6': '༦',
|
||
'7': '༧',
|
||
'8': '༨',
|
||
'9': '༩',
|
||
'0': '༠'
|
||
};
|
||
var numberMap$3 = {
|
||
'༡': '1',
|
||
'༢': '2',
|
||
'༣': '3',
|
||
'༤': '4',
|
||
'༥': '5',
|
||
'༦': '6',
|
||
'༧': '7',
|
||
'༨': '8',
|
||
'༩': '9',
|
||
'༠': '0'
|
||
};
|
||
|
||
hooks.defineLocale('bo', {
|
||
months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
|
||
monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
|
||
weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'),
|
||
weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
|
||
weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm',
|
||
LTS : 'A h:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[དི་རིང] LT',
|
||
nextDay : '[སང་ཉིན] LT',
|
||
nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT',
|
||
lastDay : '[ཁ་སང] LT',
|
||
lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s ལ་',
|
||
past : '%s སྔན་ལ',
|
||
s : 'ལམ་སང',
|
||
m : 'སྐར་མ་གཅིག',
|
||
mm : '%d སྐར་མ',
|
||
h : 'ཆུ་ཚོད་གཅིག',
|
||
hh : '%d ཆུ་ཚོད',
|
||
d : 'ཉིན་གཅིག',
|
||
dd : '%d ཉིན་',
|
||
M : 'ཟླ་བ་གཅིག',
|
||
MM : '%d ཟླ་བ',
|
||
y : 'ལོ་གཅིག',
|
||
yy : '%d ལོ'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) {
|
||
return numberMap$3[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$4[match];
|
||
});
|
||
},
|
||
meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if ((meridiem === 'མཚན་མོ' && hour >= 4) ||
|
||
(meridiem === 'ཉིན་གུང' && hour < 5) ||
|
||
meridiem === 'དགོང་དག') {
|
||
return hour + 12;
|
||
} else {
|
||
return hour;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'མཚན་མོ';
|
||
} else if (hour < 10) {
|
||
return 'ཞོགས་ཀས';
|
||
} else if (hour < 17) {
|
||
return 'ཉིན་གུང';
|
||
} else if (hour < 20) {
|
||
return 'དགོང་དག';
|
||
} else {
|
||
return 'མཚན་མོ';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Breton [br]
|
||
//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
|
||
|
||
function relativeTimeWithMutation(number, withoutSuffix, key) {
|
||
var format = {
|
||
'mm': 'munutenn',
|
||
'MM': 'miz',
|
||
'dd': 'devezh'
|
||
};
|
||
return number + ' ' + mutation(format[key], number);
|
||
}
|
||
function specialMutationForYears(number) {
|
||
switch (lastNumber(number)) {
|
||
case 1:
|
||
case 3:
|
||
case 4:
|
||
case 5:
|
||
case 9:
|
||
return number + ' bloaz';
|
||
default:
|
||
return number + ' vloaz';
|
||
}
|
||
}
|
||
function lastNumber(number) {
|
||
if (number > 9) {
|
||
return lastNumber(number % 10);
|
||
}
|
||
return number;
|
||
}
|
||
function mutation(text, number) {
|
||
if (number === 2) {
|
||
return softMutation(text);
|
||
}
|
||
return text;
|
||
}
|
||
function softMutation(text) {
|
||
var mutationTable = {
|
||
'm': 'v',
|
||
'b': 'v',
|
||
'd': 'z'
|
||
};
|
||
if (mutationTable[text.charAt(0)] === undefined) {
|
||
return text;
|
||
}
|
||
return mutationTable[text.charAt(0)] + text.substring(1);
|
||
}
|
||
|
||
hooks.defineLocale('br', {
|
||
months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'),
|
||
monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'),
|
||
weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'),
|
||
weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),
|
||
weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'h[e]mm A',
|
||
LTS : 'h[e]mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [a viz] MMMM YYYY',
|
||
LLL : 'D [a viz] MMMM YYYY h[e]mm A',
|
||
LLLL : 'dddd, D [a viz] MMMM YYYY h[e]mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Hiziv da] LT',
|
||
nextDay : '[Warc\'hoazh da] LT',
|
||
nextWeek : 'dddd [da] LT',
|
||
lastDay : '[Dec\'h da] LT',
|
||
lastWeek : 'dddd [paset da] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'a-benn %s',
|
||
past : '%s \'zo',
|
||
s : 'un nebeud segondennoù',
|
||
m : 'ur vunutenn',
|
||
mm : relativeTimeWithMutation,
|
||
h : 'un eur',
|
||
hh : '%d eur',
|
||
d : 'un devezh',
|
||
dd : relativeTimeWithMutation,
|
||
M : 'ur miz',
|
||
MM : relativeTimeWithMutation,
|
||
y : 'ur bloaz',
|
||
yy : specialMutationForYears
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(añ|vet)/,
|
||
ordinal : function (number) {
|
||
var output = (number === 1) ? 'añ' : 'vet';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Bosnian [bs]
|
||
//! author : Nedim Cholich : https://github.com/frontyard
|
||
//! based on (hr) translation by Bojan Marković
|
||
|
||
function translate(number, withoutSuffix, key) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 'm':
|
||
return withoutSuffix ? 'jedna minuta' : 'jedne minute';
|
||
case 'mm':
|
||
if (number === 1) {
|
||
result += 'minuta';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'minute';
|
||
} else {
|
||
result += 'minuta';
|
||
}
|
||
return result;
|
||
case 'h':
|
||
return withoutSuffix ? 'jedan sat' : 'jednog sata';
|
||
case 'hh':
|
||
if (number === 1) {
|
||
result += 'sat';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'sata';
|
||
} else {
|
||
result += 'sati';
|
||
}
|
||
return result;
|
||
case 'dd':
|
||
if (number === 1) {
|
||
result += 'dan';
|
||
} else {
|
||
result += 'dana';
|
||
}
|
||
return result;
|
||
case 'MM':
|
||
if (number === 1) {
|
||
result += 'mjesec';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'mjeseca';
|
||
} else {
|
||
result += 'mjeseci';
|
||
}
|
||
return result;
|
||
case 'yy':
|
||
if (number === 1) {
|
||
result += 'godina';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'godine';
|
||
} else {
|
||
result += 'godina';
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('bs', {
|
||
months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
|
||
monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
|
||
weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
|
||
weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[danas u] LT',
|
||
nextDay : '[sutra u] LT',
|
||
nextWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[u] [nedjelju] [u] LT';
|
||
case 3:
|
||
return '[u] [srijedu] [u] LT';
|
||
case 6:
|
||
return '[u] [subotu] [u] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[u] dddd [u] LT';
|
||
}
|
||
},
|
||
lastDay : '[jučer u] LT',
|
||
lastWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
case 3:
|
||
return '[prošlu] dddd [u] LT';
|
||
case 6:
|
||
return '[prošle] [subote] [u] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[prošli] dddd [u] LT';
|
||
}
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : 'prije %s',
|
||
s : 'par sekundi',
|
||
m : translate,
|
||
mm : translate,
|
||
h : translate,
|
||
hh : translate,
|
||
d : 'dan',
|
||
dd : translate,
|
||
M : 'mjesec',
|
||
MM : translate,
|
||
y : 'godinu',
|
||
yy : translate
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Catalan [ca]
|
||
//! author : Juan G. Hurtado : https://github.com/juanghurtado
|
||
|
||
hooks.defineLocale('ca', {
|
||
months : {
|
||
standalone: 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'),
|
||
format: 'de gener_de febrer_de març_d\'abril_de maig_de juny_de juliol_d\'agost_de setembre_d\'octubre_de novembre_de desembre'.split('_'),
|
||
isFormat: /D[oD]?(\s)+MMMM/
|
||
},
|
||
monthsShort : 'gen._febr._març_abr._maig_juny_jul._ag._set._oct._nov._des.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'),
|
||
weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'),
|
||
weekdaysMin : 'dg_dl_dt_dc_dj_dv_ds'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM [de] YYYY',
|
||
ll : 'D MMM YYYY',
|
||
LLL : 'D MMMM [de] YYYY [a les] H:mm',
|
||
lll : 'D MMM YYYY, H:mm',
|
||
LLLL : 'dddd D MMMM [de] YYYY [a les] H:mm',
|
||
llll : 'ddd D MMM YYYY, H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : function () {
|
||
return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
|
||
},
|
||
nextDay : function () {
|
||
return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
|
||
},
|
||
nextWeek : function () {
|
||
return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
|
||
},
|
||
lastDay : function () {
|
||
return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
|
||
},
|
||
lastWeek : function () {
|
||
return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'd\'aquí %s',
|
||
past : 'fa %s',
|
||
s : 'uns segons',
|
||
m : 'un minut',
|
||
mm : '%d minuts',
|
||
h : 'una hora',
|
||
hh : '%d hores',
|
||
d : 'un dia',
|
||
dd : '%d dies',
|
||
M : 'un mes',
|
||
MM : '%d mesos',
|
||
y : 'un any',
|
||
yy : '%d anys'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(r|n|t|è|a)/,
|
||
ordinal : function (number, period) {
|
||
var output = (number === 1) ? 'r' :
|
||
(number === 2) ? 'n' :
|
||
(number === 3) ? 'r' :
|
||
(number === 4) ? 't' : 'è';
|
||
if (period === 'w' || period === 'W') {
|
||
output = 'a';
|
||
}
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Czech [cs]
|
||
//! author : petrbela : https://github.com/petrbela
|
||
|
||
var months$3 = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_');
|
||
var monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_');
|
||
function plural$1(n) {
|
||
return (n > 1) && (n < 5) && (~~(n / 10) !== 1);
|
||
}
|
||
function translate$1(number, withoutSuffix, key, isFuture) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 's': // a few seconds / in a few seconds / a few seconds ago
|
||
return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami';
|
||
case 'm': // a minute / in a minute / a minute ago
|
||
return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou');
|
||
case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$1(number) ? 'minuty' : 'minut');
|
||
} else {
|
||
return result + 'minutami';
|
||
}
|
||
break;
|
||
case 'h': // an hour / in an hour / an hour ago
|
||
return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
|
||
case 'hh': // 9 hours / in 9 hours / 9 hours ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$1(number) ? 'hodiny' : 'hodin');
|
||
} else {
|
||
return result + 'hodinami';
|
||
}
|
||
break;
|
||
case 'd': // a day / in a day / a day ago
|
||
return (withoutSuffix || isFuture) ? 'den' : 'dnem';
|
||
case 'dd': // 9 days / in 9 days / 9 days ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$1(number) ? 'dny' : 'dní');
|
||
} else {
|
||
return result + 'dny';
|
||
}
|
||
break;
|
||
case 'M': // a month / in a month / a month ago
|
||
return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem';
|
||
case 'MM': // 9 months / in 9 months / 9 months ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$1(number) ? 'měsíce' : 'měsíců');
|
||
} else {
|
||
return result + 'měsíci';
|
||
}
|
||
break;
|
||
case 'y': // a year / in a year / a year ago
|
||
return (withoutSuffix || isFuture) ? 'rok' : 'rokem';
|
||
case 'yy': // 9 years / in 9 years / 9 years ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$1(number) ? 'roky' : 'let');
|
||
} else {
|
||
return result + 'lety';
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('cs', {
|
||
months : months$3,
|
||
monthsShort : monthsShort,
|
||
monthsParse : (function (months, monthsShort) {
|
||
var i, _monthsParse = [];
|
||
for (i = 0; i < 12; i++) {
|
||
// use custom parser to solve problem with July (červenec)
|
||
_monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');
|
||
}
|
||
return _monthsParse;
|
||
}(months$3, monthsShort)),
|
||
shortMonthsParse : (function (monthsShort) {
|
||
var i, _shortMonthsParse = [];
|
||
for (i = 0; i < 12; i++) {
|
||
_shortMonthsParse[i] = new RegExp('^' + monthsShort[i] + '$', 'i');
|
||
}
|
||
return _shortMonthsParse;
|
||
}(monthsShort)),
|
||
longMonthsParse : (function (months) {
|
||
var i, _longMonthsParse = [];
|
||
for (i = 0; i < 12; i++) {
|
||
_longMonthsParse[i] = new RegExp('^' + months[i] + '$', 'i');
|
||
}
|
||
return _longMonthsParse;
|
||
}(months$3)),
|
||
weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),
|
||
weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'),
|
||
weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),
|
||
longDateFormat : {
|
||
LT: 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY H:mm',
|
||
LLLL : 'dddd D. MMMM YYYY H:mm',
|
||
l : 'D. M. YYYY'
|
||
},
|
||
calendar : {
|
||
sameDay: '[dnes v] LT',
|
||
nextDay: '[zítra v] LT',
|
||
nextWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[v neděli v] LT';
|
||
case 1:
|
||
case 2:
|
||
return '[v] dddd [v] LT';
|
||
case 3:
|
||
return '[ve středu v] LT';
|
||
case 4:
|
||
return '[ve čtvrtek v] LT';
|
||
case 5:
|
||
return '[v pátek v] LT';
|
||
case 6:
|
||
return '[v sobotu v] LT';
|
||
}
|
||
},
|
||
lastDay: '[včera v] LT',
|
||
lastWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[minulou neděli v] LT';
|
||
case 1:
|
||
case 2:
|
||
return '[minulé] dddd [v] LT';
|
||
case 3:
|
||
return '[minulou středu v] LT';
|
||
case 4:
|
||
case 5:
|
||
return '[minulý] dddd [v] LT';
|
||
case 6:
|
||
return '[minulou sobotu v] LT';
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : 'před %s',
|
||
s : translate$1,
|
||
m : translate$1,
|
||
mm : translate$1,
|
||
h : translate$1,
|
||
hh : translate$1,
|
||
d : translate$1,
|
||
dd : translate$1,
|
||
M : translate$1,
|
||
MM : translate$1,
|
||
y : translate$1,
|
||
yy : translate$1
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Chuvash [cv]
|
||
//! author : Anatoly Mironov : https://github.com/mirontoli
|
||
|
||
hooks.defineLocale('cv', {
|
||
months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'),
|
||
monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'),
|
||
weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'),
|
||
weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'),
|
||
weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD-MM-YYYY',
|
||
LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',
|
||
LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',
|
||
LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Паян] LT [сехетре]',
|
||
nextDay: '[Ыран] LT [сехетре]',
|
||
lastDay: '[Ӗнер] LT [сехетре]',
|
||
nextWeek: '[Ҫитес] dddd LT [сехетре]',
|
||
lastWeek: '[Иртнӗ] dddd LT [сехетре]',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : function (output) {
|
||
var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран';
|
||
return output + affix;
|
||
},
|
||
past : '%s каялла',
|
||
s : 'пӗр-ик ҫеккунт',
|
||
m : 'пӗр минут',
|
||
mm : '%d минут',
|
||
h : 'пӗр сехет',
|
||
hh : '%d сехет',
|
||
d : 'пӗр кун',
|
||
dd : '%d кун',
|
||
M : 'пӗр уйӑх',
|
||
MM : '%d уйӑх',
|
||
y : 'пӗр ҫул',
|
||
yy : '%d ҫул'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-мӗш/,
|
||
ordinal : '%d-мӗш',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Welsh [cy]
|
||
//! author : Robert Allen : https://github.com/robgallen
|
||
//! author : https://github.com/ryangreaves
|
||
|
||
hooks.defineLocale('cy', {
|
||
months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'),
|
||
monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'),
|
||
weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'),
|
||
weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'),
|
||
weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
// time formats are the same as en-gb
|
||
longDateFormat: {
|
||
LT: 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L: 'DD/MM/YYYY',
|
||
LL: 'D MMMM YYYY',
|
||
LLL: 'D MMMM YYYY HH:mm',
|
||
LLLL: 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[Heddiw am] LT',
|
||
nextDay: '[Yfory am] LT',
|
||
nextWeek: 'dddd [am] LT',
|
||
lastDay: '[Ddoe am] LT',
|
||
lastWeek: 'dddd [diwethaf am] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime: {
|
||
future: 'mewn %s',
|
||
past: '%s yn ôl',
|
||
s: 'ychydig eiliadau',
|
||
m: 'munud',
|
||
mm: '%d munud',
|
||
h: 'awr',
|
||
hh: '%d awr',
|
||
d: 'diwrnod',
|
||
dd: '%d diwrnod',
|
||
M: 'mis',
|
||
MM: '%d mis',
|
||
y: 'blwyddyn',
|
||
yy: '%d flynedd'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
|
||
// traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
|
||
ordinal: function (number) {
|
||
var b = number,
|
||
output = '',
|
||
lookup = [
|
||
'', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed
|
||
'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed
|
||
];
|
||
if (b > 20) {
|
||
if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) {
|
||
output = 'fed'; // not 30ain, 70ain or 90ain
|
||
} else {
|
||
output = 'ain';
|
||
}
|
||
} else if (b > 0) {
|
||
output = lookup[b];
|
||
}
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Danish [da]
|
||
//! author : Ulrik Nielsen : https://github.com/mrbase
|
||
|
||
hooks.defineLocale('da', {
|
||
months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
|
||
weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
|
||
weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
|
||
weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY HH:mm',
|
||
LLLL : 'dddd [d.] D. MMMM YYYY [kl.] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[i dag kl.] LT',
|
||
nextDay : '[i morgen kl.] LT',
|
||
nextWeek : 'på dddd [kl.] LT',
|
||
lastDay : '[i går kl.] LT',
|
||
lastWeek : '[i] dddd[s kl.] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'om %s',
|
||
past : '%s siden',
|
||
s : 'få sekunder',
|
||
m : 'et minut',
|
||
mm : '%d minutter',
|
||
h : 'en time',
|
||
hh : '%d timer',
|
||
d : 'en dag',
|
||
dd : '%d dage',
|
||
M : 'en måned',
|
||
MM : '%d måneder',
|
||
y : 'et år',
|
||
yy : '%d år'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : German (Austria) [de-at]
|
||
//! author : lluchs : https://github.com/lluchs
|
||
//! author: Menelion Elensúle: https://github.com/Oire
|
||
//! author : Martin Groller : https://github.com/MadMG
|
||
//! author : Mikolaj Dadela : https://github.com/mik01aj
|
||
|
||
function processRelativeTime(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
'm': ['eine Minute', 'einer Minute'],
|
||
'h': ['eine Stunde', 'einer Stunde'],
|
||
'd': ['ein Tag', 'einem Tag'],
|
||
'dd': [number + ' Tage', number + ' Tagen'],
|
||
'M': ['ein Monat', 'einem Monat'],
|
||
'MM': [number + ' Monate', number + ' Monaten'],
|
||
'y': ['ein Jahr', 'einem Jahr'],
|
||
'yy': [number + ' Jahre', number + ' Jahren']
|
||
};
|
||
return withoutSuffix ? format[key][0] : format[key][1];
|
||
}
|
||
|
||
hooks.defineLocale('de-at', {
|
||
months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
|
||
monthsShort : 'Jän._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
|
||
weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
|
||
weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT: 'HH:mm',
|
||
LTS: 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[heute um] LT [Uhr]',
|
||
sameElse: 'L',
|
||
nextDay: '[morgen um] LT [Uhr]',
|
||
nextWeek: 'dddd [um] LT [Uhr]',
|
||
lastDay: '[gestern um] LT [Uhr]',
|
||
lastWeek: '[letzten] dddd [um] LT [Uhr]'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : 'vor %s',
|
||
s : 'ein paar Sekunden',
|
||
m : processRelativeTime,
|
||
mm : '%d Minuten',
|
||
h : processRelativeTime,
|
||
hh : '%d Stunden',
|
||
d : processRelativeTime,
|
||
dd : processRelativeTime,
|
||
M : processRelativeTime,
|
||
MM : processRelativeTime,
|
||
y : processRelativeTime,
|
||
yy : processRelativeTime
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : German (Switzerland) [de-ch]
|
||
//! author : sschueller : https://github.com/sschueller
|
||
|
||
// based on: https://www.bk.admin.ch/dokumentation/sprachen/04915/05016/index.html?lang=de#
|
||
|
||
function processRelativeTime$1(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
'm': ['eine Minute', 'einer Minute'],
|
||
'h': ['eine Stunde', 'einer Stunde'],
|
||
'd': ['ein Tag', 'einem Tag'],
|
||
'dd': [number + ' Tage', number + ' Tagen'],
|
||
'M': ['ein Monat', 'einem Monat'],
|
||
'MM': [number + ' Monate', number + ' Monaten'],
|
||
'y': ['ein Jahr', 'einem Jahr'],
|
||
'yy': [number + ' Jahre', number + ' Jahren']
|
||
};
|
||
return withoutSuffix ? format[key][0] : format[key][1];
|
||
}
|
||
|
||
hooks.defineLocale('de-ch', {
|
||
months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
|
||
monthsShort : 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
|
||
weekdaysShort : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
|
||
weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT: 'HH.mm',
|
||
LTS: 'HH.mm.ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY HH.mm',
|
||
LLLL : 'dddd, D. MMMM YYYY HH.mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[heute um] LT [Uhr]',
|
||
sameElse: 'L',
|
||
nextDay: '[morgen um] LT [Uhr]',
|
||
nextWeek: 'dddd [um] LT [Uhr]',
|
||
lastDay: '[gestern um] LT [Uhr]',
|
||
lastWeek: '[letzten] dddd [um] LT [Uhr]'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : 'vor %s',
|
||
s : 'ein paar Sekunden',
|
||
m : processRelativeTime$1,
|
||
mm : '%d Minuten',
|
||
h : processRelativeTime$1,
|
||
hh : '%d Stunden',
|
||
d : processRelativeTime$1,
|
||
dd : processRelativeTime$1,
|
||
M : processRelativeTime$1,
|
||
MM : processRelativeTime$1,
|
||
y : processRelativeTime$1,
|
||
yy : processRelativeTime$1
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : German [de]
|
||
//! author : lluchs : https://github.com/lluchs
|
||
//! author: Menelion Elensúle: https://github.com/Oire
|
||
//! author : Mikolaj Dadela : https://github.com/mik01aj
|
||
|
||
function processRelativeTime$2(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
'm': ['eine Minute', 'einer Minute'],
|
||
'h': ['eine Stunde', 'einer Stunde'],
|
||
'd': ['ein Tag', 'einem Tag'],
|
||
'dd': [number + ' Tage', number + ' Tagen'],
|
||
'M': ['ein Monat', 'einem Monat'],
|
||
'MM': [number + ' Monate', number + ' Monaten'],
|
||
'y': ['ein Jahr', 'einem Jahr'],
|
||
'yy': [number + ' Jahre', number + ' Jahren']
|
||
};
|
||
return withoutSuffix ? format[key][0] : format[key][1];
|
||
}
|
||
|
||
hooks.defineLocale('de', {
|
||
months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
|
||
monthsShort : 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
|
||
weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
|
||
weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT: 'HH:mm',
|
||
LTS: 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[heute um] LT [Uhr]',
|
||
sameElse: 'L',
|
||
nextDay: '[morgen um] LT [Uhr]',
|
||
nextWeek: 'dddd [um] LT [Uhr]',
|
||
lastDay: '[gestern um] LT [Uhr]',
|
||
lastWeek: '[letzten] dddd [um] LT [Uhr]'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : 'vor %s',
|
||
s : 'ein paar Sekunden',
|
||
m : processRelativeTime$2,
|
||
mm : '%d Minuten',
|
||
h : processRelativeTime$2,
|
||
hh : '%d Stunden',
|
||
d : processRelativeTime$2,
|
||
dd : processRelativeTime$2,
|
||
M : processRelativeTime$2,
|
||
MM : processRelativeTime$2,
|
||
y : processRelativeTime$2,
|
||
yy : processRelativeTime$2
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Maldivian [dv]
|
||
//! author : Jawish Hameed : https://github.com/jawish
|
||
|
||
var months$4 = [
|
||
'ޖެނުއަރީ',
|
||
'ފެބްރުއަރީ',
|
||
'މާރިޗު',
|
||
'އޭޕްރީލު',
|
||
'މޭ',
|
||
'ޖޫން',
|
||
'ޖުލައި',
|
||
'އޯގަސްޓު',
|
||
'ސެޕްޓެމްބަރު',
|
||
'އޮކްޓޯބަރު',
|
||
'ނޮވެމްބަރު',
|
||
'ޑިސެމްބަރު'
|
||
];
|
||
var weekdays = [
|
||
'އާދިއްތަ',
|
||
'ހޯމަ',
|
||
'އަންގާރަ',
|
||
'ބުދަ',
|
||
'ބުރާސްފަތި',
|
||
'ހުކުރު',
|
||
'ހޮނިހިރު'
|
||
];
|
||
|
||
hooks.defineLocale('dv', {
|
||
months : months$4,
|
||
monthsShort : months$4,
|
||
weekdays : weekdays,
|
||
weekdaysShort : weekdays,
|
||
weekdaysMin : 'އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި'.split('_'),
|
||
longDateFormat : {
|
||
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'D/M/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /މކ|މފ/,
|
||
isPM : function (input) {
|
||
return 'މފ' === input;
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'މކ';
|
||
} else {
|
||
return 'މފ';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[މިއަދު] LT',
|
||
nextDay : '[މާދަމާ] LT',
|
||
nextWeek : 'dddd LT',
|
||
lastDay : '[އިއްޔެ] LT',
|
||
lastWeek : '[ފާއިތުވި] dddd LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'ތެރޭގައި %s',
|
||
past : 'ކުރިން %s',
|
||
s : 'ސިކުންތުކޮޅެއް',
|
||
m : 'މިނިޓެއް',
|
||
mm : 'މިނިޓު %d',
|
||
h : 'ގަޑިއިރެއް',
|
||
hh : 'ގަޑިއިރު %d',
|
||
d : 'ދުވަހެއް',
|
||
dd : 'ދުވަސް %d',
|
||
M : 'މަހެއް',
|
||
MM : 'މަސް %d',
|
||
y : 'އަހަރެއް',
|
||
yy : 'އަހަރު %d'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/,/g, '،');
|
||
},
|
||
week : {
|
||
dow : 7, // Sunday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Greek [el]
|
||
//! author : Aggelos Karalias : https://github.com/mehiel
|
||
|
||
hooks.defineLocale('el', {
|
||
monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
|
||
monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'),
|
||
months : function (momentToFormat, format) {
|
||
if (!momentToFormat) {
|
||
return this._monthsNominativeEl;
|
||
} else if (typeof format === 'string' && /D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM'
|
||
return this._monthsGenitiveEl[momentToFormat.month()];
|
||
} else {
|
||
return this._monthsNominativeEl[momentToFormat.month()];
|
||
}
|
||
},
|
||
monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
|
||
weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
|
||
weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
|
||
weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'),
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours > 11) {
|
||
return isLower ? 'μμ' : 'ΜΜ';
|
||
} else {
|
||
return isLower ? 'πμ' : 'ΠΜ';
|
||
}
|
||
},
|
||
isPM : function (input) {
|
||
return ((input + '').toLowerCase()[0] === 'μ');
|
||
},
|
||
meridiemParse : /[ΠΜ]\.?Μ?\.?/i,
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY h:mm A',
|
||
LLLL : 'dddd, D MMMM YYYY h:mm A'
|
||
},
|
||
calendarEl : {
|
||
sameDay : '[Σήμερα {}] LT',
|
||
nextDay : '[Αύριο {}] LT',
|
||
nextWeek : 'dddd [{}] LT',
|
||
lastDay : '[Χθες {}] LT',
|
||
lastWeek : function () {
|
||
switch (this.day()) {
|
||
case 6:
|
||
return '[το προηγούμενο] dddd [{}] LT';
|
||
default:
|
||
return '[την προηγούμενη] dddd [{}] LT';
|
||
}
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
calendar : function (key, mom) {
|
||
var output = this._calendarEl[key],
|
||
hours = mom && mom.hours();
|
||
if (isFunction(output)) {
|
||
output = output.apply(mom);
|
||
}
|
||
return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις'));
|
||
},
|
||
relativeTime : {
|
||
future : 'σε %s',
|
||
past : '%s πριν',
|
||
s : 'λίγα δευτερόλεπτα',
|
||
m : 'ένα λεπτό',
|
||
mm : '%d λεπτά',
|
||
h : 'μία ώρα',
|
||
hh : '%d ώρες',
|
||
d : 'μία μέρα',
|
||
dd : '%d μέρες',
|
||
M : 'ένας μήνας',
|
||
MM : '%d μήνες',
|
||
y : 'ένας χρόνος',
|
||
yy : '%d χρόνια'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}η/,
|
||
ordinal: '%dη',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : English (Australia) [en-au]
|
||
//! author : Jared Morse : https://github.com/jarcoal
|
||
|
||
hooks.defineLocale('en-au', {
|
||
months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
|
||
weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
|
||
weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
|
||
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY h:mm A',
|
||
LLLL : 'dddd, D MMMM YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : English (Canada) [en-ca]
|
||
//! author : Jonathan Abourbih : https://github.com/jonbca
|
||
|
||
hooks.defineLocale('en-ca', {
|
||
months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
|
||
weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
|
||
weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
|
||
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'YYYY-MM-DD',
|
||
LL : 'MMMM D, YYYY',
|
||
LLL : 'MMMM D, YYYY h:mm A',
|
||
LLLL : 'dddd, MMMM D, YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : English (United Kingdom) [en-gb]
|
||
//! author : Chris Gedrim : https://github.com/chrisgedrim
|
||
|
||
hooks.defineLocale('en-gb', {
|
||
months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
|
||
weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
|
||
weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
|
||
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : English (Ireland) [en-ie]
|
||
//! author : Chris Cartlidge : https://github.com/chriscartlidge
|
||
|
||
hooks.defineLocale('en-ie', {
|
||
months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
|
||
weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
|
||
weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
|
||
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD-MM-YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : English (New Zealand) [en-nz]
|
||
//! author : Luke McGregor : https://github.com/lukemcgregor
|
||
|
||
hooks.defineLocale('en-nz', {
|
||
months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
|
||
weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
|
||
weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
|
||
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY h:mm A',
|
||
LLLL : 'dddd, D MMMM YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Esperanto [eo]
|
||
//! author : Colin Dean : https://github.com/colindean
|
||
//! author : Mia Nordentoft Imperatori : https://github.com/miestasmia
|
||
//! comment : miestasmia corrected the translation by colindean
|
||
|
||
hooks.defineLocale('eo', {
|
||
months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec'.split('_'),
|
||
weekdays : 'dimanĉo_lundo_mardo_merkredo_ĵaŭdo_vendredo_sabato'.split('_'),
|
||
weekdaysShort : 'dim_lun_mard_merk_ĵaŭ_ven_sab'.split('_'),
|
||
weekdaysMin : 'di_lu_ma_me_ĵa_ve_sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY-MM-DD',
|
||
LL : 'D[-a de] MMMM, YYYY',
|
||
LLL : 'D[-a de] MMMM, YYYY HH:mm',
|
||
LLLL : 'dddd, [la] D[-a de] MMMM, YYYY HH:mm'
|
||
},
|
||
meridiemParse: /[ap]\.t\.m/i,
|
||
isPM: function (input) {
|
||
return input.charAt(0).toLowerCase() === 'p';
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours > 11) {
|
||
return isLower ? 'p.t.m.' : 'P.T.M.';
|
||
} else {
|
||
return isLower ? 'a.t.m.' : 'A.T.M.';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[Hodiaŭ je] LT',
|
||
nextDay : '[Morgaŭ je] LT',
|
||
nextWeek : 'dddd [je] LT',
|
||
lastDay : '[Hieraŭ je] LT',
|
||
lastWeek : '[pasinta] dddd [je] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'post %s',
|
||
past : 'antaŭ %s',
|
||
s : 'sekundoj',
|
||
m : 'minuto',
|
||
mm : '%d minutoj',
|
||
h : 'horo',
|
||
hh : '%d horoj',
|
||
d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo
|
||
dd : '%d tagoj',
|
||
M : 'monato',
|
||
MM : '%d monatoj',
|
||
y : 'jaro',
|
||
yy : '%d jaroj'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}a/,
|
||
ordinal : '%da',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Spanish (Dominican Republic) [es-do]
|
||
|
||
var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
|
||
var monthsShort$1 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
|
||
|
||
var monthsParse = [/^ene/i, /^feb/i, /^mar/i, /^abr/i, /^may/i, /^jun/i, /^jul/i, /^ago/i, /^sep/i, /^oct/i, /^nov/i, /^dic/i];
|
||
var monthsRegex$1 = /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;
|
||
|
||
hooks.defineLocale('es-do', {
|
||
months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
|
||
monthsShort : function (m, format) {
|
||
if (!m) {
|
||
return monthsShortDot;
|
||
} else if (/-MMM-/.test(format)) {
|
||
return monthsShort$1[m.month()];
|
||
} else {
|
||
return monthsShortDot[m.month()];
|
||
}
|
||
},
|
||
monthsRegex: monthsRegex$1,
|
||
monthsShortRegex: monthsRegex$1,
|
||
monthsStrictRegex: /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,
|
||
monthsShortStrictRegex: /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,
|
||
monthsParse: monthsParse,
|
||
longMonthsParse: monthsParse,
|
||
shortMonthsParse: monthsParse,
|
||
weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
|
||
weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
|
||
weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [de] MMMM [de] YYYY',
|
||
LLL : 'D [de] MMMM [de] YYYY h:mm A',
|
||
LLLL : 'dddd, D [de] MMMM [de] YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : function () {
|
||
return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
nextDay : function () {
|
||
return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
nextWeek : function () {
|
||
return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
lastDay : function () {
|
||
return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
lastWeek : function () {
|
||
return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'en %s',
|
||
past : 'hace %s',
|
||
s : 'unos segundos',
|
||
m : 'un minuto',
|
||
mm : '%d minutos',
|
||
h : 'una hora',
|
||
hh : '%d horas',
|
||
d : 'un día',
|
||
dd : '%d días',
|
||
M : 'un mes',
|
||
MM : '%d meses',
|
||
y : 'un año',
|
||
yy : '%d años'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}º/,
|
||
ordinal : '%dº',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Spanish (United States) [es-us]
|
||
//! author : bustta : https://github.com/bustta
|
||
|
||
var monthsShortDot$1 = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
|
||
var monthsShort$2 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
|
||
|
||
hooks.defineLocale('es-us', {
|
||
months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
|
||
monthsShort : function (m, format) {
|
||
if (!m) {
|
||
return monthsShortDot$1;
|
||
} else if (/-MMM-/.test(format)) {
|
||
return monthsShort$2[m.month()];
|
||
} else {
|
||
return monthsShortDot$1[m.month()];
|
||
}
|
||
},
|
||
monthsParseExact : true,
|
||
weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
|
||
weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
|
||
weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'MM/DD/YYYY',
|
||
LL : 'MMMM [de] D [de] YYYY',
|
||
LLL : 'MMMM [de] D [de] YYYY H:mm',
|
||
LLLL : 'dddd, MMMM [de] D [de] YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : function () {
|
||
return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
nextDay : function () {
|
||
return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
nextWeek : function () {
|
||
return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
lastDay : function () {
|
||
return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
lastWeek : function () {
|
||
return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'en %s',
|
||
past : 'hace %s',
|
||
s : 'unos segundos',
|
||
m : 'un minuto',
|
||
mm : '%d minutos',
|
||
h : 'una hora',
|
||
hh : '%d horas',
|
||
d : 'un día',
|
||
dd : '%d días',
|
||
M : 'un mes',
|
||
MM : '%d meses',
|
||
y : 'un año',
|
||
yy : '%d años'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}º/,
|
||
ordinal : '%dº',
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Spanish [es]
|
||
//! author : Julio Napurí : https://github.com/julionc
|
||
|
||
var monthsShortDot$2 = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
|
||
var monthsShort$3 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
|
||
|
||
var monthsParse$1 = [/^ene/i, /^feb/i, /^mar/i, /^abr/i, /^may/i, /^jun/i, /^jul/i, /^ago/i, /^sep/i, /^oct/i, /^nov/i, /^dic/i];
|
||
var monthsRegex$2 = /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;
|
||
|
||
hooks.defineLocale('es', {
|
||
months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
|
||
monthsShort : function (m, format) {
|
||
if (!m) {
|
||
return monthsShortDot$2;
|
||
} else if (/-MMM-/.test(format)) {
|
||
return monthsShort$3[m.month()];
|
||
} else {
|
||
return monthsShortDot$2[m.month()];
|
||
}
|
||
},
|
||
monthsRegex : monthsRegex$2,
|
||
monthsShortRegex : monthsRegex$2,
|
||
monthsStrictRegex : /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,
|
||
monthsShortStrictRegex : /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,
|
||
monthsParse : monthsParse$1,
|
||
longMonthsParse : monthsParse$1,
|
||
shortMonthsParse : monthsParse$1,
|
||
weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
|
||
weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
|
||
weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [de] MMMM [de] YYYY',
|
||
LLL : 'D [de] MMMM [de] YYYY H:mm',
|
||
LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : function () {
|
||
return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
nextDay : function () {
|
||
return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
nextWeek : function () {
|
||
return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
lastDay : function () {
|
||
return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
lastWeek : function () {
|
||
return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'en %s',
|
||
past : 'hace %s',
|
||
s : 'unos segundos',
|
||
m : 'un minuto',
|
||
mm : '%d minutos',
|
||
h : 'una hora',
|
||
hh : '%d horas',
|
||
d : 'un día',
|
||
dd : '%d días',
|
||
M : 'un mes',
|
||
MM : '%d meses',
|
||
y : 'un año',
|
||
yy : '%d años'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}º/,
|
||
ordinal : '%dº',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Estonian [et]
|
||
//! author : Henry Kehlmann : https://github.com/madhenry
|
||
//! improvements : Illimar Tambek : https://github.com/ragulka
|
||
|
||
function processRelativeTime$3(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'],
|
||
'm' : ['ühe minuti', 'üks minut'],
|
||
'mm': [number + ' minuti', number + ' minutit'],
|
||
'h' : ['ühe tunni', 'tund aega', 'üks tund'],
|
||
'hh': [number + ' tunni', number + ' tundi'],
|
||
'd' : ['ühe päeva', 'üks päev'],
|
||
'M' : ['kuu aja', 'kuu aega', 'üks kuu'],
|
||
'MM': [number + ' kuu', number + ' kuud'],
|
||
'y' : ['ühe aasta', 'aasta', 'üks aasta'],
|
||
'yy': [number + ' aasta', number + ' aastat']
|
||
};
|
||
if (withoutSuffix) {
|
||
return format[key][2] ? format[key][2] : format[key][1];
|
||
}
|
||
return isFuture ? format[key][0] : format[key][1];
|
||
}
|
||
|
||
hooks.defineLocale('et', {
|
||
months : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'),
|
||
monthsShort : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'),
|
||
weekdays : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'),
|
||
weekdaysShort : 'P_E_T_K_N_R_L'.split('_'),
|
||
weekdaysMin : 'P_E_T_K_N_R_L'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Täna,] LT',
|
||
nextDay : '[Homme,] LT',
|
||
nextWeek : '[Järgmine] dddd LT',
|
||
lastDay : '[Eile,] LT',
|
||
lastWeek : '[Eelmine] dddd LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s pärast',
|
||
past : '%s tagasi',
|
||
s : processRelativeTime$3,
|
||
m : processRelativeTime$3,
|
||
mm : processRelativeTime$3,
|
||
h : processRelativeTime$3,
|
||
hh : processRelativeTime$3,
|
||
d : processRelativeTime$3,
|
||
dd : '%d päeva',
|
||
M : processRelativeTime$3,
|
||
MM : processRelativeTime$3,
|
||
y : processRelativeTime$3,
|
||
yy : processRelativeTime$3
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Basque [eu]
|
||
//! author : Eneko Illarramendi : https://github.com/eillarra
|
||
|
||
hooks.defineLocale('eu', {
|
||
months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),
|
||
monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),
|
||
weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'),
|
||
weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY-MM-DD',
|
||
LL : 'YYYY[ko] MMMM[ren] D[a]',
|
||
LLL : 'YYYY[ko] MMMM[ren] D[a] HH:mm',
|
||
LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',
|
||
l : 'YYYY-M-D',
|
||
ll : 'YYYY[ko] MMM D[a]',
|
||
lll : 'YYYY[ko] MMM D[a] HH:mm',
|
||
llll : 'ddd, YYYY[ko] MMM D[a] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[gaur] LT[etan]',
|
||
nextDay : '[bihar] LT[etan]',
|
||
nextWeek : 'dddd LT[etan]',
|
||
lastDay : '[atzo] LT[etan]',
|
||
lastWeek : '[aurreko] dddd LT[etan]',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s barru',
|
||
past : 'duela %s',
|
||
s : 'segundo batzuk',
|
||
m : 'minutu bat',
|
||
mm : '%d minutu',
|
||
h : 'ordu bat',
|
||
hh : '%d ordu',
|
||
d : 'egun bat',
|
||
dd : '%d egun',
|
||
M : 'hilabete bat',
|
||
MM : '%d hilabete',
|
||
y : 'urte bat',
|
||
yy : '%d urte'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Persian [fa]
|
||
//! author : Ebrahim Byagowi : https://github.com/ebraminio
|
||
|
||
var symbolMap$5 = {
|
||
'1': '۱',
|
||
'2': '۲',
|
||
'3': '۳',
|
||
'4': '۴',
|
||
'5': '۵',
|
||
'6': '۶',
|
||
'7': '۷',
|
||
'8': '۸',
|
||
'9': '۹',
|
||
'0': '۰'
|
||
};
|
||
var numberMap$4 = {
|
||
'۱': '1',
|
||
'۲': '2',
|
||
'۳': '3',
|
||
'۴': '4',
|
||
'۵': '5',
|
||
'۶': '6',
|
||
'۷': '7',
|
||
'۸': '8',
|
||
'۹': '9',
|
||
'۰': '0'
|
||
};
|
||
|
||
hooks.defineLocale('fa', {
|
||
months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
|
||
monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
|
||
weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
|
||
weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
|
||
weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /قبل از ظهر|بعد از ظهر/,
|
||
isPM: function (input) {
|
||
return /بعد از ظهر/.test(input);
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'قبل از ظهر';
|
||
} else {
|
||
return 'بعد از ظهر';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[امروز ساعت] LT',
|
||
nextDay : '[فردا ساعت] LT',
|
||
nextWeek : 'dddd [ساعت] LT',
|
||
lastDay : '[دیروز ساعت] LT',
|
||
lastWeek : 'dddd [پیش] [ساعت] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'در %s',
|
||
past : '%s پیش',
|
||
s : 'چند ثانیه',
|
||
m : 'یک دقیقه',
|
||
mm : '%d دقیقه',
|
||
h : 'یک ساعت',
|
||
hh : '%d ساعت',
|
||
d : 'یک روز',
|
||
dd : '%d روز',
|
||
M : 'یک ماه',
|
||
MM : '%d ماه',
|
||
y : 'یک سال',
|
||
yy : '%d سال'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[۰-۹]/g, function (match) {
|
||
return numberMap$4[match];
|
||
}).replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$5[match];
|
||
}).replace(/,/g, '،');
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}م/,
|
||
ordinal : '%dم',
|
||
week : {
|
||
dow : 6, // Saturday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Finnish [fi]
|
||
//! author : Tarmo Aidantausta : https://github.com/bleadof
|
||
|
||
var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' ');
|
||
var numbersFuture = [
|
||
'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden',
|
||
numbersPast[7], numbersPast[8], numbersPast[9]
|
||
];
|
||
function translate$2(number, withoutSuffix, key, isFuture) {
|
||
var result = '';
|
||
switch (key) {
|
||
case 's':
|
||
return isFuture ? 'muutaman sekunnin' : 'muutama sekunti';
|
||
case 'm':
|
||
return isFuture ? 'minuutin' : 'minuutti';
|
||
case 'mm':
|
||
result = isFuture ? 'minuutin' : 'minuuttia';
|
||
break;
|
||
case 'h':
|
||
return isFuture ? 'tunnin' : 'tunti';
|
||
case 'hh':
|
||
result = isFuture ? 'tunnin' : 'tuntia';
|
||
break;
|
||
case 'd':
|
||
return isFuture ? 'päivän' : 'päivä';
|
||
case 'dd':
|
||
result = isFuture ? 'päivän' : 'päivää';
|
||
break;
|
||
case 'M':
|
||
return isFuture ? 'kuukauden' : 'kuukausi';
|
||
case 'MM':
|
||
result = isFuture ? 'kuukauden' : 'kuukautta';
|
||
break;
|
||
case 'y':
|
||
return isFuture ? 'vuoden' : 'vuosi';
|
||
case 'yy':
|
||
result = isFuture ? 'vuoden' : 'vuotta';
|
||
break;
|
||
}
|
||
result = verbalNumber(number, isFuture) + ' ' + result;
|
||
return result;
|
||
}
|
||
function verbalNumber(number, isFuture) {
|
||
return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number;
|
||
}
|
||
|
||
hooks.defineLocale('fi', {
|
||
months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'),
|
||
monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'),
|
||
weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'),
|
||
weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'),
|
||
weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH.mm',
|
||
LTS : 'HH.mm.ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'Do MMMM[ta] YYYY',
|
||
LLL : 'Do MMMM[ta] YYYY, [klo] HH.mm',
|
||
LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',
|
||
l : 'D.M.YYYY',
|
||
ll : 'Do MMM YYYY',
|
||
lll : 'Do MMM YYYY, [klo] HH.mm',
|
||
llll : 'ddd, Do MMM YYYY, [klo] HH.mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[tänään] [klo] LT',
|
||
nextDay : '[huomenna] [klo] LT',
|
||
nextWeek : 'dddd [klo] LT',
|
||
lastDay : '[eilen] [klo] LT',
|
||
lastWeek : '[viime] dddd[na] [klo] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s päästä',
|
||
past : '%s sitten',
|
||
s : translate$2,
|
||
m : translate$2,
|
||
mm : translate$2,
|
||
h : translate$2,
|
||
hh : translate$2,
|
||
d : translate$2,
|
||
dd : translate$2,
|
||
M : translate$2,
|
||
MM : translate$2,
|
||
y : translate$2,
|
||
yy : translate$2
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Faroese [fo]
|
||
//! author : Ragnar Johannesen : https://github.com/ragnar123
|
||
|
||
hooks.defineLocale('fo', {
|
||
months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
|
||
weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),
|
||
weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'),
|
||
weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D. MMMM, YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Í dag kl.] LT',
|
||
nextDay : '[Í morgin kl.] LT',
|
||
nextWeek : 'dddd [kl.] LT',
|
||
lastDay : '[Í gjár kl.] LT',
|
||
lastWeek : '[síðstu] dddd [kl] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'um %s',
|
||
past : '%s síðani',
|
||
s : 'fá sekund',
|
||
m : 'ein minutt',
|
||
mm : '%d minuttir',
|
||
h : 'ein tími',
|
||
hh : '%d tímar',
|
||
d : 'ein dagur',
|
||
dd : '%d dagar',
|
||
M : 'ein mánaði',
|
||
MM : '%d mánaðir',
|
||
y : 'eitt ár',
|
||
yy : '%d ár'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : French (Canada) [fr-ca]
|
||
//! author : Jonathan Abourbih : https://github.com/jonbca
|
||
|
||
hooks.defineLocale('fr-ca', {
|
||
months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
|
||
monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
|
||
weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
|
||
weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY-MM-DD',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Aujourd’hui à] LT',
|
||
nextDay : '[Demain à] LT',
|
||
nextWeek : 'dddd [à] LT',
|
||
lastDay : '[Hier à] LT',
|
||
lastWeek : 'dddd [dernier à] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dans %s',
|
||
past : 'il y a %s',
|
||
s : 'quelques secondes',
|
||
m : 'une minute',
|
||
mm : '%d minutes',
|
||
h : 'une heure',
|
||
hh : '%d heures',
|
||
d : 'un jour',
|
||
dd : '%d jours',
|
||
M : 'un mois',
|
||
MM : '%d mois',
|
||
y : 'un an',
|
||
yy : '%d ans'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(er|e)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
// Words with masculine grammatical gender: mois, trimestre, jour
|
||
default:
|
||
case 'M':
|
||
case 'Q':
|
||
case 'D':
|
||
case 'DDD':
|
||
case 'd':
|
||
return number + (number === 1 ? 'er' : 'e');
|
||
|
||
// Words with feminine grammatical gender: semaine
|
||
case 'w':
|
||
case 'W':
|
||
return number + (number === 1 ? 're' : 'e');
|
||
}
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : French (Switzerland) [fr-ch]
|
||
//! author : Gaspard Bucher : https://github.com/gaspard
|
||
|
||
hooks.defineLocale('fr-ch', {
|
||
months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
|
||
monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
|
||
weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
|
||
weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Aujourd’hui à] LT',
|
||
nextDay : '[Demain à] LT',
|
||
nextWeek : 'dddd [à] LT',
|
||
lastDay : '[Hier à] LT',
|
||
lastWeek : 'dddd [dernier à] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dans %s',
|
||
past : 'il y a %s',
|
||
s : 'quelques secondes',
|
||
m : 'une minute',
|
||
mm : '%d minutes',
|
||
h : 'une heure',
|
||
hh : '%d heures',
|
||
d : 'un jour',
|
||
dd : '%d jours',
|
||
M : 'un mois',
|
||
MM : '%d mois',
|
||
y : 'un an',
|
||
yy : '%d ans'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(er|e)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
// Words with masculine grammatical gender: mois, trimestre, jour
|
||
default:
|
||
case 'M':
|
||
case 'Q':
|
||
case 'D':
|
||
case 'DDD':
|
||
case 'd':
|
||
return number + (number === 1 ? 'er' : 'e');
|
||
|
||
// Words with feminine grammatical gender: semaine
|
||
case 'w':
|
||
case 'W':
|
||
return number + (number === 1 ? 're' : 'e');
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : French [fr]
|
||
//! author : John Fischer : https://github.com/jfroffice
|
||
|
||
hooks.defineLocale('fr', {
|
||
months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
|
||
monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
|
||
weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
|
||
weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Aujourd’hui à] LT',
|
||
nextDay : '[Demain à] LT',
|
||
nextWeek : 'dddd [à] LT',
|
||
lastDay : '[Hier à] LT',
|
||
lastWeek : 'dddd [dernier à] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dans %s',
|
||
past : 'il y a %s',
|
||
s : 'quelques secondes',
|
||
m : 'une minute',
|
||
mm : '%d minutes',
|
||
h : 'une heure',
|
||
hh : '%d heures',
|
||
d : 'un jour',
|
||
dd : '%d jours',
|
||
M : 'un mois',
|
||
MM : '%d mois',
|
||
y : 'un an',
|
||
yy : '%d ans'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(er|)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
// TODO: Return 'e' when day of month > 1. Move this case inside
|
||
// block for masculine words below.
|
||
// See https://github.com/moment/moment/issues/3375
|
||
case 'D':
|
||
return number + (number === 1 ? 'er' : '');
|
||
|
||
// Words with masculine grammatical gender: mois, trimestre, jour
|
||
default:
|
||
case 'M':
|
||
case 'Q':
|
||
case 'DDD':
|
||
case 'd':
|
||
return number + (number === 1 ? 'er' : 'e');
|
||
|
||
// Words with feminine grammatical gender: semaine
|
||
case 'w':
|
||
case 'W':
|
||
return number + (number === 1 ? 're' : 'e');
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Frisian [fy]
|
||
//! author : Robin van der Vliet : https://github.com/robin0van0der0v
|
||
|
||
var monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_');
|
||
var monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_');
|
||
|
||
hooks.defineLocale('fy', {
|
||
months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'),
|
||
monthsShort : function (m, format) {
|
||
if (!m) {
|
||
return monthsShortWithDots;
|
||
} else if (/-MMM-/.test(format)) {
|
||
return monthsShortWithoutDots[m.month()];
|
||
} else {
|
||
return monthsShortWithDots[m.month()];
|
||
}
|
||
},
|
||
monthsParseExact : true,
|
||
weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'),
|
||
weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'),
|
||
weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD-MM-YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[hjoed om] LT',
|
||
nextDay: '[moarn om] LT',
|
||
nextWeek: 'dddd [om] LT',
|
||
lastDay: '[juster om] LT',
|
||
lastWeek: '[ôfrûne] dddd [om] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'oer %s',
|
||
past : '%s lyn',
|
||
s : 'in pear sekonden',
|
||
m : 'ien minút',
|
||
mm : '%d minuten',
|
||
h : 'ien oere',
|
||
hh : '%d oeren',
|
||
d : 'ien dei',
|
||
dd : '%d dagen',
|
||
M : 'ien moanne',
|
||
MM : '%d moannen',
|
||
y : 'ien jier',
|
||
yy : '%d jierren'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/,
|
||
ordinal : function (number) {
|
||
return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Scottish Gaelic [gd]
|
||
//! author : Jon Ashdown : https://github.com/jonashdown
|
||
|
||
var months$5 = [
|
||
'Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'
|
||
];
|
||
|
||
var monthsShort$4 = ['Faoi', 'Gear', 'Màrt', 'Gibl', 'Cèit', 'Ògmh', 'Iuch', 'Lùn', 'Sult', 'Dàmh', 'Samh', 'Dùbh'];
|
||
|
||
var weekdays$1 = ['Didòmhnaich', 'Diluain', 'Dimàirt', 'Diciadain', 'Diardaoin', 'Dihaoine', 'Disathairne'];
|
||
|
||
var weekdaysShort = ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'];
|
||
|
||
var weekdaysMin = ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa'];
|
||
|
||
hooks.defineLocale('gd', {
|
||
months : months$5,
|
||
monthsShort : monthsShort$4,
|
||
monthsParseExact : true,
|
||
weekdays : weekdays$1,
|
||
weekdaysShort : weekdaysShort,
|
||
weekdaysMin : weekdaysMin,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[An-diugh aig] LT',
|
||
nextDay : '[A-màireach aig] LT',
|
||
nextWeek : 'dddd [aig] LT',
|
||
lastDay : '[An-dè aig] LT',
|
||
lastWeek : 'dddd [seo chaidh] [aig] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'ann an %s',
|
||
past : 'bho chionn %s',
|
||
s : 'beagan diogan',
|
||
m : 'mionaid',
|
||
mm : '%d mionaidean',
|
||
h : 'uair',
|
||
hh : '%d uairean',
|
||
d : 'latha',
|
||
dd : '%d latha',
|
||
M : 'mìos',
|
||
MM : '%d mìosan',
|
||
y : 'bliadhna',
|
||
yy : '%d bliadhna'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}(d|na|mh)/,
|
||
ordinal : function (number) {
|
||
var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Galician [gl]
|
||
//! author : Juan G. Hurtado : https://github.com/juanghurtado
|
||
|
||
hooks.defineLocale('gl', {
|
||
months : 'xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro'.split('_'),
|
||
monthsShort : 'xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'domingo_luns_martes_mércores_xoves_venres_sábado'.split('_'),
|
||
weekdaysShort : 'dom._lun._mar._mér._xov._ven._sáb.'.split('_'),
|
||
weekdaysMin : 'do_lu_ma_mé_xo_ve_sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [de] MMMM [de] YYYY',
|
||
LLL : 'D [de] MMMM [de] YYYY H:mm',
|
||
LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : function () {
|
||
return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
|
||
},
|
||
nextDay : function () {
|
||
return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
|
||
},
|
||
nextWeek : function () {
|
||
return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
|
||
},
|
||
lastDay : function () {
|
||
return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT';
|
||
},
|
||
lastWeek : function () {
|
||
return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : function (str) {
|
||
if (str.indexOf('un') === 0) {
|
||
return 'n' + str;
|
||
}
|
||
return 'en ' + str;
|
||
},
|
||
past : 'hai %s',
|
||
s : 'uns segundos',
|
||
m : 'un minuto',
|
||
mm : '%d minutos',
|
||
h : 'unha hora',
|
||
hh : '%d horas',
|
||
d : 'un día',
|
||
dd : '%d días',
|
||
M : 'un mes',
|
||
MM : '%d meses',
|
||
y : 'un ano',
|
||
yy : '%d anos'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}º/,
|
||
ordinal : '%dº',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Konkani Latin script [gom-latn]
|
||
//! author : The Discoverer : https://github.com/WikiDiscoverer
|
||
|
||
function processRelativeTime$4(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
's': ['thodde secondanim', 'thodde second'],
|
||
'm': ['eka mintan', 'ek minute'],
|
||
'mm': [number + ' mintanim', number + ' mintam'],
|
||
'h': ['eka horan', 'ek hor'],
|
||
'hh': [number + ' horanim', number + ' hor'],
|
||
'd': ['eka disan', 'ek dis'],
|
||
'dd': [number + ' disanim', number + ' dis'],
|
||
'M': ['eka mhoinean', 'ek mhoino'],
|
||
'MM': [number + ' mhoineanim', number + ' mhoine'],
|
||
'y': ['eka vorsan', 'ek voros'],
|
||
'yy': [number + ' vorsanim', number + ' vorsam']
|
||
};
|
||
return withoutSuffix ? format[key][0] : format[key][1];
|
||
}
|
||
|
||
hooks.defineLocale('gom-latn', {
|
||
months : 'Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr'.split('_'),
|
||
monthsShort : 'Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'Aitar_Somar_Mongllar_Budvar_Brestar_Sukrar_Son\'var'.split('_'),
|
||
weekdaysShort : 'Ait._Som._Mon._Bud._Bre._Suk._Son.'.split('_'),
|
||
weekdaysMin : 'Ai_Sm_Mo_Bu_Br_Su_Sn'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'A h:mm [vazta]',
|
||
LTS : 'A h:mm:ss [vazta]',
|
||
L : 'DD-MM-YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY A h:mm [vazta]',
|
||
LLLL : 'dddd, MMMM[achea] Do, YYYY, A h:mm [vazta]',
|
||
llll: 'ddd, D MMM YYYY, A h:mm [vazta]'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Aiz] LT',
|
||
nextDay: '[Faleam] LT',
|
||
nextWeek: '[Ieta to] dddd[,] LT',
|
||
lastDay: '[Kal] LT',
|
||
lastWeek: '[Fatlo] dddd[,] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s',
|
||
past : '%s adim',
|
||
s : processRelativeTime$4,
|
||
m : processRelativeTime$4,
|
||
mm : processRelativeTime$4,
|
||
h : processRelativeTime$4,
|
||
hh : processRelativeTime$4,
|
||
d : processRelativeTime$4,
|
||
dd : processRelativeTime$4,
|
||
M : processRelativeTime$4,
|
||
MM : processRelativeTime$4,
|
||
y : processRelativeTime$4,
|
||
yy : processRelativeTime$4
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}(er)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
// the ordinal 'er' only applies to day of the month
|
||
case 'D':
|
||
return number + 'er';
|
||
default:
|
||
case 'M':
|
||
case 'Q':
|
||
case 'DDD':
|
||
case 'd':
|
||
case 'w':
|
||
case 'W':
|
||
return number;
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
},
|
||
meridiemParse: /rati|sokalli|donparam|sanje/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'rati') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'sokalli') {
|
||
return hour;
|
||
} else if (meridiem === 'donparam') {
|
||
return hour > 12 ? hour : hour + 12;
|
||
} else if (meridiem === 'sanje') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'rati';
|
||
} else if (hour < 12) {
|
||
return 'sokalli';
|
||
} else if (hour < 16) {
|
||
return 'donparam';
|
||
} else if (hour < 20) {
|
||
return 'sanje';
|
||
} else {
|
||
return 'rati';
|
||
}
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Gujarati [gu]
|
||
//! author : Kaushik Thanki : https://github.com/Kaushik1987
|
||
|
||
var symbolMap$6 = {
|
||
'1': '૧',
|
||
'2': '૨',
|
||
'3': '૩',
|
||
'4': '૪',
|
||
'5': '૫',
|
||
'6': '૬',
|
||
'7': '૭',
|
||
'8': '૮',
|
||
'9': '૯',
|
||
'0': '૦'
|
||
};
|
||
var numberMap$5 = {
|
||
'૧': '1',
|
||
'૨': '2',
|
||
'૩': '3',
|
||
'૪': '4',
|
||
'૫': '5',
|
||
'૬': '6',
|
||
'૭': '7',
|
||
'૮': '8',
|
||
'૯': '9',
|
||
'૦': '0'
|
||
};
|
||
|
||
hooks.defineLocale('gu', {
|
||
months: 'જાન્યુઆરી_ફેબ્રુઆરી_માર્ચ_એપ્રિલ_મે_જૂન_જુલાઈ_ઑગસ્ટ_સપ્ટેમ્બર_ઑક્ટ્બર_નવેમ્બર_ડિસેમ્બર'.split('_'),
|
||
monthsShort: 'જાન્યુ._ફેબ્રુ._માર્ચ_એપ્રિ._મે_જૂન_જુલા._ઑગ._સપ્ટે._ઑક્ટ્._નવે._ડિસે.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays: 'રવિવાર_સોમવાર_મંગળવાર_બુધ્વાર_ગુરુવાર_શુક્રવાર_શનિવાર'.split('_'),
|
||
weekdaysShort: 'રવિ_સોમ_મંગળ_બુધ્_ગુરુ_શુક્ર_શનિ'.split('_'),
|
||
weekdaysMin: 'ર_સો_મં_બુ_ગુ_શુ_શ'.split('_'),
|
||
longDateFormat: {
|
||
LT: 'A h:mm વાગ્યે',
|
||
LTS: 'A h:mm:ss વાગ્યે',
|
||
L: 'DD/MM/YYYY',
|
||
LL: 'D MMMM YYYY',
|
||
LLL: 'D MMMM YYYY, A h:mm વાગ્યે',
|
||
LLLL: 'dddd, D MMMM YYYY, A h:mm વાગ્યે'
|
||
},
|
||
calendar: {
|
||
sameDay: '[આજ] LT',
|
||
nextDay: '[કાલે] LT',
|
||
nextWeek: 'dddd, LT',
|
||
lastDay: '[ગઇકાલે] LT',
|
||
lastWeek: '[પાછલા] dddd, LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime: {
|
||
future: '%s મા',
|
||
past: '%s પેહલા',
|
||
s: 'અમુક પળો',
|
||
m: 'એક મિનિટ',
|
||
mm: '%d મિનિટ',
|
||
h: 'એક કલાક',
|
||
hh: '%d કલાક',
|
||
d: 'એક દિવસ',
|
||
dd: '%d દિવસ',
|
||
M: 'એક મહિનો',
|
||
MM: '%d મહિનો',
|
||
y: 'એક વર્ષ',
|
||
yy: '%d વર્ષ'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[૧૨૩૪૫૬૭૮૯૦]/g, function (match) {
|
||
return numberMap$5[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$6[match];
|
||
});
|
||
},
|
||
// Gujarati notation for meridiems are quite fuzzy in practice. While there exists
|
||
// a rigid notion of a 'Pahar' it is not used as rigidly in modern Gujarati.
|
||
meridiemParse: /રાત|બપોર|સવાર|સાંજ/,
|
||
meridiemHour: function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'રાત') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'સવાર') {
|
||
return hour;
|
||
} else if (meridiem === 'બપોર') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'સાંજ') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem: function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'રાત';
|
||
} else if (hour < 10) {
|
||
return 'સવાર';
|
||
} else if (hour < 17) {
|
||
return 'બપોર';
|
||
} else if (hour < 20) {
|
||
return 'સાંજ';
|
||
} else {
|
||
return 'રાત';
|
||
}
|
||
},
|
||
week: {
|
||
dow: 0, // Sunday is the first day of the week.
|
||
doy: 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Hebrew [he]
|
||
//! author : Tomer Cohen : https://github.com/tomer
|
||
//! author : Moshe Simantov : https://github.com/DevelopmentIL
|
||
//! author : Tal Ater : https://github.com/TalAter
|
||
|
||
hooks.defineLocale('he', {
|
||
months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'),
|
||
monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'),
|
||
weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'),
|
||
weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'),
|
||
weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [ב]MMMM YYYY',
|
||
LLL : 'D [ב]MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D [ב]MMMM YYYY HH:mm',
|
||
l : 'D/M/YYYY',
|
||
ll : 'D MMM YYYY',
|
||
lll : 'D MMM YYYY HH:mm',
|
||
llll : 'ddd, D MMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[היום ב־]LT',
|
||
nextDay : '[מחר ב־]LT',
|
||
nextWeek : 'dddd [בשעה] LT',
|
||
lastDay : '[אתמול ב־]LT',
|
||
lastWeek : '[ביום] dddd [האחרון בשעה] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'בעוד %s',
|
||
past : 'לפני %s',
|
||
s : 'מספר שניות',
|
||
m : 'דקה',
|
||
mm : '%d דקות',
|
||
h : 'שעה',
|
||
hh : function (number) {
|
||
if (number === 2) {
|
||
return 'שעתיים';
|
||
}
|
||
return number + ' שעות';
|
||
},
|
||
d : 'יום',
|
||
dd : function (number) {
|
||
if (number === 2) {
|
||
return 'יומיים';
|
||
}
|
||
return number + ' ימים';
|
||
},
|
||
M : 'חודש',
|
||
MM : function (number) {
|
||
if (number === 2) {
|
||
return 'חודשיים';
|
||
}
|
||
return number + ' חודשים';
|
||
},
|
||
y : 'שנה',
|
||
yy : function (number) {
|
||
if (number === 2) {
|
||
return 'שנתיים';
|
||
} else if (number % 10 === 0 && number !== 10) {
|
||
return number + ' שנה';
|
||
}
|
||
return number + ' שנים';
|
||
}
|
||
},
|
||
meridiemParse: /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,
|
||
isPM : function (input) {
|
||
return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(input);
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 5) {
|
||
return 'לפנות בוקר';
|
||
} else if (hour < 10) {
|
||
return 'בבוקר';
|
||
} else if (hour < 12) {
|
||
return isLower ? 'לפנה"צ' : 'לפני הצהריים';
|
||
} else if (hour < 18) {
|
||
return isLower ? 'אחה"צ' : 'אחרי הצהריים';
|
||
} else {
|
||
return 'בערב';
|
||
}
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Hindi [hi]
|
||
//! author : Mayank Singhal : https://github.com/mayanksinghal
|
||
|
||
var symbolMap$7 = {
|
||
'1': '१',
|
||
'2': '२',
|
||
'3': '३',
|
||
'4': '४',
|
||
'5': '५',
|
||
'6': '६',
|
||
'7': '७',
|
||
'8': '८',
|
||
'9': '९',
|
||
'0': '०'
|
||
};
|
||
var numberMap$6 = {
|
||
'१': '1',
|
||
'२': '2',
|
||
'३': '3',
|
||
'४': '4',
|
||
'५': '5',
|
||
'६': '6',
|
||
'७': '7',
|
||
'८': '8',
|
||
'९': '9',
|
||
'०': '0'
|
||
};
|
||
|
||
hooks.defineLocale('hi', {
|
||
months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'),
|
||
monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
|
||
weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'),
|
||
weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm बजे',
|
||
LTS : 'A h:mm:ss बजे',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm बजे',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm बजे'
|
||
},
|
||
calendar : {
|
||
sameDay : '[आज] LT',
|
||
nextDay : '[कल] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[कल] LT',
|
||
lastWeek : '[पिछले] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s में',
|
||
past : '%s पहले',
|
||
s : 'कुछ ही क्षण',
|
||
m : 'एक मिनट',
|
||
mm : '%d मिनट',
|
||
h : 'एक घंटा',
|
||
hh : '%d घंटे',
|
||
d : 'एक दिन',
|
||
dd : '%d दिन',
|
||
M : 'एक महीने',
|
||
MM : '%d महीने',
|
||
y : 'एक वर्ष',
|
||
yy : '%d वर्ष'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[१२३४५६७८९०]/g, function (match) {
|
||
return numberMap$6[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$7[match];
|
||
});
|
||
},
|
||
// Hindi notation for meridiems are quite fuzzy in practice. While there exists
|
||
// a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
|
||
meridiemParse: /रात|सुबह|दोपहर|शाम/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'रात') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'सुबह') {
|
||
return hour;
|
||
} else if (meridiem === 'दोपहर') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'शाम') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'रात';
|
||
} else if (hour < 10) {
|
||
return 'सुबह';
|
||
} else if (hour < 17) {
|
||
return 'दोपहर';
|
||
} else if (hour < 20) {
|
||
return 'शाम';
|
||
} else {
|
||
return 'रात';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Croatian [hr]
|
||
//! author : Bojan Marković : https://github.com/bmarkovic
|
||
|
||
function translate$3(number, withoutSuffix, key) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 'm':
|
||
return withoutSuffix ? 'jedna minuta' : 'jedne minute';
|
||
case 'mm':
|
||
if (number === 1) {
|
||
result += 'minuta';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'minute';
|
||
} else {
|
||
result += 'minuta';
|
||
}
|
||
return result;
|
||
case 'h':
|
||
return withoutSuffix ? 'jedan sat' : 'jednog sata';
|
||
case 'hh':
|
||
if (number === 1) {
|
||
result += 'sat';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'sata';
|
||
} else {
|
||
result += 'sati';
|
||
}
|
||
return result;
|
||
case 'dd':
|
||
if (number === 1) {
|
||
result += 'dan';
|
||
} else {
|
||
result += 'dana';
|
||
}
|
||
return result;
|
||
case 'MM':
|
||
if (number === 1) {
|
||
result += 'mjesec';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'mjeseca';
|
||
} else {
|
||
result += 'mjeseci';
|
||
}
|
||
return result;
|
||
case 'yy':
|
||
if (number === 1) {
|
||
result += 'godina';
|
||
} else if (number === 2 || number === 3 || number === 4) {
|
||
result += 'godine';
|
||
} else {
|
||
result += 'godina';
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('hr', {
|
||
months : {
|
||
format: 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split('_'),
|
||
standalone: 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_')
|
||
},
|
||
monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
|
||
weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
|
||
weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[danas u] LT',
|
||
nextDay : '[sutra u] LT',
|
||
nextWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[u] [nedjelju] [u] LT';
|
||
case 3:
|
||
return '[u] [srijedu] [u] LT';
|
||
case 6:
|
||
return '[u] [subotu] [u] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[u] dddd [u] LT';
|
||
}
|
||
},
|
||
lastDay : '[jučer u] LT',
|
||
lastWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
case 3:
|
||
return '[prošlu] dddd [u] LT';
|
||
case 6:
|
||
return '[prošle] [subote] [u] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[prošli] dddd [u] LT';
|
||
}
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : 'prije %s',
|
||
s : 'par sekundi',
|
||
m : translate$3,
|
||
mm : translate$3,
|
||
h : translate$3,
|
||
hh : translate$3,
|
||
d : 'dan',
|
||
dd : translate$3,
|
||
M : 'mjesec',
|
||
MM : translate$3,
|
||
y : 'godinu',
|
||
yy : translate$3
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Hungarian [hu]
|
||
//! author : Adam Brunner : https://github.com/adambrunner
|
||
|
||
var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');
|
||
function translate$4(number, withoutSuffix, key, isFuture) {
|
||
var num = number;
|
||
switch (key) {
|
||
case 's':
|
||
return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce';
|
||
case 'm':
|
||
return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce');
|
||
case 'mm':
|
||
return num + (isFuture || withoutSuffix ? ' perc' : ' perce');
|
||
case 'h':
|
||
return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája');
|
||
case 'hh':
|
||
return num + (isFuture || withoutSuffix ? ' óra' : ' órája');
|
||
case 'd':
|
||
return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja');
|
||
case 'dd':
|
||
return num + (isFuture || withoutSuffix ? ' nap' : ' napja');
|
||
case 'M':
|
||
return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
|
||
case 'MM':
|
||
return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
|
||
case 'y':
|
||
return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve');
|
||
case 'yy':
|
||
return num + (isFuture || withoutSuffix ? ' év' : ' éve');
|
||
}
|
||
return '';
|
||
}
|
||
function week(isFuture) {
|
||
return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]';
|
||
}
|
||
|
||
hooks.defineLocale('hu', {
|
||
months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'),
|
||
monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'),
|
||
weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'),
|
||
weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'),
|
||
weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'YYYY.MM.DD.',
|
||
LL : 'YYYY. MMMM D.',
|
||
LLL : 'YYYY. MMMM D. H:mm',
|
||
LLLL : 'YYYY. MMMM D., dddd H:mm'
|
||
},
|
||
meridiemParse: /de|du/i,
|
||
isPM: function (input) {
|
||
return input.charAt(1).toLowerCase() === 'u';
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 12) {
|
||
return isLower === true ? 'de' : 'DE';
|
||
} else {
|
||
return isLower === true ? 'du' : 'DU';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[ma] LT[-kor]',
|
||
nextDay : '[holnap] LT[-kor]',
|
||
nextWeek : function () {
|
||
return week.call(this, true);
|
||
},
|
||
lastDay : '[tegnap] LT[-kor]',
|
||
lastWeek : function () {
|
||
return week.call(this, false);
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s múlva',
|
||
past : '%s',
|
||
s : translate$4,
|
||
m : translate$4,
|
||
mm : translate$4,
|
||
h : translate$4,
|
||
hh : translate$4,
|
||
d : translate$4,
|
||
dd : translate$4,
|
||
M : translate$4,
|
||
MM : translate$4,
|
||
y : translate$4,
|
||
yy : translate$4
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Armenian [hy-am]
|
||
//! author : Armendarabyan : https://github.com/armendarabyan
|
||
|
||
hooks.defineLocale('hy-am', {
|
||
months : {
|
||
format: 'հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի'.split('_'),
|
||
standalone: 'հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր'.split('_')
|
||
},
|
||
monthsShort : 'հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ'.split('_'),
|
||
weekdays : 'կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ'.split('_'),
|
||
weekdaysShort : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'),
|
||
weekdaysMin : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY թ.',
|
||
LLL : 'D MMMM YYYY թ., HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY թ., HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[այսօր] LT',
|
||
nextDay: '[վաղը] LT',
|
||
lastDay: '[երեկ] LT',
|
||
nextWeek: function () {
|
||
return 'dddd [օրը ժամը] LT';
|
||
},
|
||
lastWeek: function () {
|
||
return '[անցած] dddd [օրը ժամը] LT';
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s հետո',
|
||
past : '%s առաջ',
|
||
s : 'մի քանի վայրկյան',
|
||
m : 'րոպե',
|
||
mm : '%d րոպե',
|
||
h : 'ժամ',
|
||
hh : '%d ժամ',
|
||
d : 'օր',
|
||
dd : '%d օր',
|
||
M : 'ամիս',
|
||
MM : '%d ամիս',
|
||
y : 'տարի',
|
||
yy : '%d տարի'
|
||
},
|
||
meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,
|
||
isPM: function (input) {
|
||
return /^(ցերեկվա|երեկոյան)$/.test(input);
|
||
},
|
||
meridiem : function (hour) {
|
||
if (hour < 4) {
|
||
return 'գիշերվա';
|
||
} else if (hour < 12) {
|
||
return 'առավոտվա';
|
||
} else if (hour < 17) {
|
||
return 'ցերեկվա';
|
||
} else {
|
||
return 'երեկոյան';
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}|\d{1,2}-(ին|րդ)/,
|
||
ordinal: function (number, period) {
|
||
switch (period) {
|
||
case 'DDD':
|
||
case 'w':
|
||
case 'W':
|
||
case 'DDDo':
|
||
if (number === 1) {
|
||
return number + '-ին';
|
||
}
|
||
return number + '-րդ';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Indonesian [id]
|
||
//! author : Mohammad Satrio Utomo : https://github.com/tyok
|
||
//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
|
||
|
||
hooks.defineLocale('id', {
|
||
months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'),
|
||
weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'),
|
||
weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'),
|
||
weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH.mm',
|
||
LTS : 'HH.mm.ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY [pukul] HH.mm',
|
||
LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
|
||
},
|
||
meridiemParse: /pagi|siang|sore|malam/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'pagi') {
|
||
return hour;
|
||
} else if (meridiem === 'siang') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === 'sore' || meridiem === 'malam') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 11) {
|
||
return 'pagi';
|
||
} else if (hours < 15) {
|
||
return 'siang';
|
||
} else if (hours < 19) {
|
||
return 'sore';
|
||
} else {
|
||
return 'malam';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[Hari ini pukul] LT',
|
||
nextDay : '[Besok pukul] LT',
|
||
nextWeek : 'dddd [pukul] LT',
|
||
lastDay : '[Kemarin pukul] LT',
|
||
lastWeek : 'dddd [lalu pukul] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dalam %s',
|
||
past : '%s yang lalu',
|
||
s : 'beberapa detik',
|
||
m : 'semenit',
|
||
mm : '%d menit',
|
||
h : 'sejam',
|
||
hh : '%d jam',
|
||
d : 'sehari',
|
||
dd : '%d hari',
|
||
M : 'sebulan',
|
||
MM : '%d bulan',
|
||
y : 'setahun',
|
||
yy : '%d tahun'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Icelandic [is]
|
||
//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
|
||
|
||
function plural$2(n) {
|
||
if (n % 100 === 11) {
|
||
return true;
|
||
} else if (n % 10 === 1) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
function translate$5(number, withoutSuffix, key, isFuture) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 's':
|
||
return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum';
|
||
case 'm':
|
||
return withoutSuffix ? 'mínúta' : 'mínútu';
|
||
case 'mm':
|
||
if (plural$2(number)) {
|
||
return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum');
|
||
} else if (withoutSuffix) {
|
||
return result + 'mínúta';
|
||
}
|
||
return result + 'mínútu';
|
||
case 'hh':
|
||
if (plural$2(number)) {
|
||
return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum');
|
||
}
|
||
return result + 'klukkustund';
|
||
case 'd':
|
||
if (withoutSuffix) {
|
||
return 'dagur';
|
||
}
|
||
return isFuture ? 'dag' : 'degi';
|
||
case 'dd':
|
||
if (plural$2(number)) {
|
||
if (withoutSuffix) {
|
||
return result + 'dagar';
|
||
}
|
||
return result + (isFuture ? 'daga' : 'dögum');
|
||
} else if (withoutSuffix) {
|
||
return result + 'dagur';
|
||
}
|
||
return result + (isFuture ? 'dag' : 'degi');
|
||
case 'M':
|
||
if (withoutSuffix) {
|
||
return 'mánuður';
|
||
}
|
||
return isFuture ? 'mánuð' : 'mánuði';
|
||
case 'MM':
|
||
if (plural$2(number)) {
|
||
if (withoutSuffix) {
|
||
return result + 'mánuðir';
|
||
}
|
||
return result + (isFuture ? 'mánuði' : 'mánuðum');
|
||
} else if (withoutSuffix) {
|
||
return result + 'mánuður';
|
||
}
|
||
return result + (isFuture ? 'mánuð' : 'mánuði');
|
||
case 'y':
|
||
return withoutSuffix || isFuture ? 'ár' : 'ári';
|
||
case 'yy':
|
||
if (plural$2(number)) {
|
||
return result + (withoutSuffix || isFuture ? 'ár' : 'árum');
|
||
}
|
||
return result + (withoutSuffix || isFuture ? 'ár' : 'ári');
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('is', {
|
||
months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'),
|
||
weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'),
|
||
weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'),
|
||
weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY [kl.] H:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY [kl.] H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[í dag kl.] LT',
|
||
nextDay : '[á morgun kl.] LT',
|
||
nextWeek : 'dddd [kl.] LT',
|
||
lastDay : '[í gær kl.] LT',
|
||
lastWeek : '[síðasta] dddd [kl.] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'eftir %s',
|
||
past : 'fyrir %s síðan',
|
||
s : translate$5,
|
||
m : translate$5,
|
||
mm : translate$5,
|
||
h : 'klukkustund',
|
||
hh : translate$5,
|
||
d : translate$5,
|
||
dd : translate$5,
|
||
M : translate$5,
|
||
MM : translate$5,
|
||
y : translate$5,
|
||
yy : translate$5
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Italian [it]
|
||
//! author : Lorenzo : https://github.com/aliem
|
||
//! author: Mattia Larentis: https://github.com/nostalgiaz
|
||
|
||
hooks.defineLocale('it', {
|
||
months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'),
|
||
monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'),
|
||
weekdays : 'domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato'.split('_'),
|
||
weekdaysShort : 'dom_lun_mar_mer_gio_ven_sab'.split('_'),
|
||
weekdaysMin : 'do_lu_ma_me_gi_ve_sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Oggi alle] LT',
|
||
nextDay: '[Domani alle] LT',
|
||
nextWeek: 'dddd [alle] LT',
|
||
lastDay: '[Ieri alle] LT',
|
||
lastWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[la scorsa] dddd [alle] LT';
|
||
default:
|
||
return '[lo scorso] dddd [alle] LT';
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : function (s) {
|
||
return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s;
|
||
},
|
||
past : '%s fa',
|
||
s : 'alcuni secondi',
|
||
m : 'un minuto',
|
||
mm : '%d minuti',
|
||
h : 'un\'ora',
|
||
hh : '%d ore',
|
||
d : 'un giorno',
|
||
dd : '%d giorni',
|
||
M : 'un mese',
|
||
MM : '%d mesi',
|
||
y : 'un anno',
|
||
yy : '%d anni'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}º/,
|
||
ordinal: '%dº',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Japanese [ja]
|
||
//! author : LI Long : https://github.com/baryon
|
||
|
||
hooks.defineLocale('ja', {
|
||
months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
|
||
monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
|
||
weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'),
|
||
weekdaysShort : '日_月_火_水_木_金_土'.split('_'),
|
||
weekdaysMin : '日_月_火_水_木_金_土'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY/MM/DD',
|
||
LL : 'YYYY年M月D日',
|
||
LLL : 'YYYY年M月D日 HH:mm',
|
||
LLLL : 'YYYY年M月D日 HH:mm dddd',
|
||
l : 'YYYY/MM/DD',
|
||
ll : 'YYYY年M月D日',
|
||
lll : 'YYYY年M月D日 HH:mm',
|
||
llll : 'YYYY年M月D日 HH:mm dddd'
|
||
},
|
||
meridiemParse: /午前|午後/i,
|
||
isPM : function (input) {
|
||
return input === '午後';
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return '午前';
|
||
} else {
|
||
return '午後';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[今日] LT',
|
||
nextDay : '[明日] LT',
|
||
nextWeek : '[来週]dddd LT',
|
||
lastDay : '[昨日] LT',
|
||
lastWeek : '[前週]dddd LT',
|
||
sameElse : 'L'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}日/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
case 'd':
|
||
case 'D':
|
||
case 'DDD':
|
||
return number + '日';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
relativeTime : {
|
||
future : '%s後',
|
||
past : '%s前',
|
||
s : '数秒',
|
||
m : '1分',
|
||
mm : '%d分',
|
||
h : '1時間',
|
||
hh : '%d時間',
|
||
d : '1日',
|
||
dd : '%d日',
|
||
M : '1ヶ月',
|
||
MM : '%dヶ月',
|
||
y : '1年',
|
||
yy : '%d年'
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Javanese [jv]
|
||
//! author : Rony Lantip : https://github.com/lantip
|
||
//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
|
||
|
||
hooks.defineLocale('jv', {
|
||
months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'),
|
||
weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'),
|
||
weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'),
|
||
weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH.mm',
|
||
LTS : 'HH.mm.ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY [pukul] HH.mm',
|
||
LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
|
||
},
|
||
meridiemParse: /enjing|siyang|sonten|ndalu/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'enjing') {
|
||
return hour;
|
||
} else if (meridiem === 'siyang') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === 'sonten' || meridiem === 'ndalu') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 11) {
|
||
return 'enjing';
|
||
} else if (hours < 15) {
|
||
return 'siyang';
|
||
} else if (hours < 19) {
|
||
return 'sonten';
|
||
} else {
|
||
return 'ndalu';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[Dinten puniko pukul] LT',
|
||
nextDay : '[Mbenjang pukul] LT',
|
||
nextWeek : 'dddd [pukul] LT',
|
||
lastDay : '[Kala wingi pukul] LT',
|
||
lastWeek : 'dddd [kepengker pukul] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'wonten ing %s',
|
||
past : '%s ingkang kepengker',
|
||
s : 'sawetawis detik',
|
||
m : 'setunggal menit',
|
||
mm : '%d menit',
|
||
h : 'setunggal jam',
|
||
hh : '%d jam',
|
||
d : 'sedinten',
|
||
dd : '%d dinten',
|
||
M : 'sewulan',
|
||
MM : '%d wulan',
|
||
y : 'setaun',
|
||
yy : '%d taun'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Georgian [ka]
|
||
//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
|
||
|
||
hooks.defineLocale('ka', {
|
||
months : {
|
||
standalone: 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'),
|
||
format: 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_')
|
||
},
|
||
monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'),
|
||
weekdays : {
|
||
standalone: 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'),
|
||
format: 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_'),
|
||
isFormat: /(წინა|შემდეგ)/
|
||
},
|
||
weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'),
|
||
weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY h:mm A',
|
||
LLLL : 'dddd, D MMMM YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[დღეს] LT[-ზე]',
|
||
nextDay : '[ხვალ] LT[-ზე]',
|
||
lastDay : '[გუშინ] LT[-ზე]',
|
||
nextWeek : '[შემდეგ] dddd LT[-ზე]',
|
||
lastWeek : '[წინა] dddd LT-ზე',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : function (s) {
|
||
return (/(წამი|წუთი|საათი|წელი)/).test(s) ?
|
||
s.replace(/ი$/, 'ში') :
|
||
s + 'ში';
|
||
},
|
||
past : function (s) {
|
||
if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) {
|
||
return s.replace(/(ი|ე)$/, 'ის უკან');
|
||
}
|
||
if ((/წელი/).test(s)) {
|
||
return s.replace(/წელი$/, 'წლის უკან');
|
||
}
|
||
},
|
||
s : 'რამდენიმე წამი',
|
||
m : 'წუთი',
|
||
mm : '%d წუთი',
|
||
h : 'საათი',
|
||
hh : '%d საათი',
|
||
d : 'დღე',
|
||
dd : '%d დღე',
|
||
M : 'თვე',
|
||
MM : '%d თვე',
|
||
y : 'წელი',
|
||
yy : '%d წელი'
|
||
},
|
||
dayOfMonthOrdinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,
|
||
ordinal : function (number) {
|
||
if (number === 0) {
|
||
return number;
|
||
}
|
||
if (number === 1) {
|
||
return number + '-ლი';
|
||
}
|
||
if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) {
|
||
return 'მე-' + number;
|
||
}
|
||
return number + '-ე';
|
||
},
|
||
week : {
|
||
dow : 1,
|
||
doy : 7
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Kazakh [kk]
|
||
//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
|
||
|
||
var suffixes$1 = {
|
||
0: '-ші',
|
||
1: '-ші',
|
||
2: '-ші',
|
||
3: '-ші',
|
||
4: '-ші',
|
||
5: '-ші',
|
||
6: '-шы',
|
||
7: '-ші',
|
||
8: '-ші',
|
||
9: '-шы',
|
||
10: '-шы',
|
||
20: '-шы',
|
||
30: '-шы',
|
||
40: '-шы',
|
||
50: '-ші',
|
||
60: '-шы',
|
||
70: '-ші',
|
||
80: '-ші',
|
||
90: '-шы',
|
||
100: '-ші'
|
||
};
|
||
|
||
hooks.defineLocale('kk', {
|
||
months : 'қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан'.split('_'),
|
||
monthsShort : 'қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел'.split('_'),
|
||
weekdays : 'жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі'.split('_'),
|
||
weekdaysShort : 'жек_дүй_сей_сәр_бей_жұм_сен'.split('_'),
|
||
weekdaysMin : 'жк_дй_сй_ср_бй_жм_сн'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Бүгін сағат] LT',
|
||
nextDay : '[Ертең сағат] LT',
|
||
nextWeek : 'dddd [сағат] LT',
|
||
lastDay : '[Кеше сағат] LT',
|
||
lastWeek : '[Өткен аптаның] dddd [сағат] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s ішінде',
|
||
past : '%s бұрын',
|
||
s : 'бірнеше секунд',
|
||
m : 'бір минут',
|
||
mm : '%d минут',
|
||
h : 'бір сағат',
|
||
hh : '%d сағат',
|
||
d : 'бір күн',
|
||
dd : '%d күн',
|
||
M : 'бір ай',
|
||
MM : '%d ай',
|
||
y : 'бір жыл',
|
||
yy : '%d жыл'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(ші|шы)/,
|
||
ordinal : function (number) {
|
||
var a = number % 10,
|
||
b = number >= 100 ? 100 : null;
|
||
return number + (suffixes$1[number] || suffixes$1[a] || suffixes$1[b]);
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Cambodian [km]
|
||
//! author : Kruy Vanna : https://github.com/kruyvanna
|
||
|
||
hooks.defineLocale('km', {
|
||
months: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
|
||
monthsShort: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
|
||
weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
|
||
weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
|
||
weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
|
||
longDateFormat: {
|
||
LT: 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L: 'DD/MM/YYYY',
|
||
LL: 'D MMMM YYYY',
|
||
LLL: 'D MMMM YYYY HH:mm',
|
||
LLLL: 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[ថ្ងៃនេះ ម៉ោង] LT',
|
||
nextDay: '[ស្អែក ម៉ោង] LT',
|
||
nextWeek: 'dddd [ម៉ោង] LT',
|
||
lastDay: '[ម្សិលមិញ ម៉ោង] LT',
|
||
lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime: {
|
||
future: '%sទៀត',
|
||
past: '%sមុន',
|
||
s: 'ប៉ុន្មានវិនាទី',
|
||
m: 'មួយនាទី',
|
||
mm: '%d នាទី',
|
||
h: 'មួយម៉ោង',
|
||
hh: '%d ម៉ោង',
|
||
d: 'មួយថ្ងៃ',
|
||
dd: '%d ថ្ងៃ',
|
||
M: 'មួយខែ',
|
||
MM: '%d ខែ',
|
||
y: 'មួយឆ្នាំ',
|
||
yy: '%d ឆ្នាំ'
|
||
},
|
||
week: {
|
||
dow: 1, // Monday is the first day of the week.
|
||
doy: 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Kannada [kn]
|
||
//! author : Rajeev Naik : https://github.com/rajeevnaikte
|
||
|
||
var symbolMap$8 = {
|
||
'1': '೧',
|
||
'2': '೨',
|
||
'3': '೩',
|
||
'4': '೪',
|
||
'5': '೫',
|
||
'6': '೬',
|
||
'7': '೭',
|
||
'8': '೮',
|
||
'9': '೯',
|
||
'0': '೦'
|
||
};
|
||
var numberMap$7 = {
|
||
'೧': '1',
|
||
'೨': '2',
|
||
'೩': '3',
|
||
'೪': '4',
|
||
'೫': '5',
|
||
'೬': '6',
|
||
'೭': '7',
|
||
'೮': '8',
|
||
'೯': '9',
|
||
'೦': '0'
|
||
};
|
||
|
||
hooks.defineLocale('kn', {
|
||
months : 'ಜನವರಿ_ಫೆಬ್ರವರಿ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬರ್_ಅಕ್ಟೋಬರ್_ನವೆಂಬರ್_ಡಿಸೆಂಬರ್'.split('_'),
|
||
monthsShort : 'ಜನ_ಫೆಬ್ರ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬ_ಅಕ್ಟೋಬ_ನವೆಂಬ_ಡಿಸೆಂಬ'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'ಭಾನುವಾರ_ಸೋಮವಾರ_ಮಂಗಳವಾರ_ಬುಧವಾರ_ಗುರುವಾರ_ಶುಕ್ರವಾರ_ಶನಿವಾರ'.split('_'),
|
||
weekdaysShort : 'ಭಾನು_ಸೋಮ_ಮಂಗಳ_ಬುಧ_ಗುರು_ಶುಕ್ರ_ಶನಿ'.split('_'),
|
||
weekdaysMin : 'ಭಾ_ಸೋ_ಮಂ_ಬು_ಗು_ಶು_ಶ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm',
|
||
LTS : 'A h:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[ಇಂದು] LT',
|
||
nextDay : '[ನಾಳೆ] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[ನಿನ್ನೆ] LT',
|
||
lastWeek : '[ಕೊನೆಯ] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s ನಂತರ',
|
||
past : '%s ಹಿಂದೆ',
|
||
s : 'ಕೆಲವು ಕ್ಷಣಗಳು',
|
||
m : 'ಒಂದು ನಿಮಿಷ',
|
||
mm : '%d ನಿಮಿಷ',
|
||
h : 'ಒಂದು ಗಂಟೆ',
|
||
hh : '%d ಗಂಟೆ',
|
||
d : 'ಒಂದು ದಿನ',
|
||
dd : '%d ದಿನ',
|
||
M : 'ಒಂದು ತಿಂಗಳು',
|
||
MM : '%d ತಿಂಗಳು',
|
||
y : 'ಒಂದು ವರ್ಷ',
|
||
yy : '%d ವರ್ಷ'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[೧೨೩೪೫೬೭೮೯೦]/g, function (match) {
|
||
return numberMap$7[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$8[match];
|
||
});
|
||
},
|
||
meridiemParse: /ರಾತ್ರಿ|ಬೆಳಿಗ್ಗೆ|ಮಧ್ಯಾಹ್ನ|ಸಂಜೆ/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'ರಾತ್ರಿ') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'ಬೆಳಿಗ್ಗೆ') {
|
||
return hour;
|
||
} else if (meridiem === 'ಮಧ್ಯಾಹ್ನ') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'ಸಂಜೆ') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'ರಾತ್ರಿ';
|
||
} else if (hour < 10) {
|
||
return 'ಬೆಳಿಗ್ಗೆ';
|
||
} else if (hour < 17) {
|
||
return 'ಮಧ್ಯಾಹ್ನ';
|
||
} else if (hour < 20) {
|
||
return 'ಸಂಜೆ';
|
||
} else {
|
||
return 'ರಾತ್ರಿ';
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(ನೇ)/,
|
||
ordinal : function (number) {
|
||
return number + 'ನೇ';
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Korean [ko]
|
||
//! author : Kyungwook, Park : https://github.com/kyungw00k
|
||
//! author : Jeeeyul Lee <jeeeyul@gmail.com>
|
||
|
||
hooks.defineLocale('ko', {
|
||
months : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'),
|
||
monthsShort : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'),
|
||
weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),
|
||
weekdaysShort : '일_월_화_수_목_금_토'.split('_'),
|
||
weekdaysMin : '일_월_화_수_목_금_토'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm',
|
||
LTS : 'A h:mm:ss',
|
||
L : 'YYYY.MM.DD',
|
||
LL : 'YYYY년 MMMM D일',
|
||
LLL : 'YYYY년 MMMM D일 A h:mm',
|
||
LLLL : 'YYYY년 MMMM D일 dddd A h:mm',
|
||
l : 'YYYY.MM.DD',
|
||
ll : 'YYYY년 MMMM D일',
|
||
lll : 'YYYY년 MMMM D일 A h:mm',
|
||
llll : 'YYYY년 MMMM D일 dddd A h:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '오늘 LT',
|
||
nextDay : '내일 LT',
|
||
nextWeek : 'dddd LT',
|
||
lastDay : '어제 LT',
|
||
lastWeek : '지난주 dddd LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s 후',
|
||
past : '%s 전',
|
||
s : '몇 초',
|
||
ss : '%d초',
|
||
m : '1분',
|
||
mm : '%d분',
|
||
h : '한 시간',
|
||
hh : '%d시간',
|
||
d : '하루',
|
||
dd : '%d일',
|
||
M : '한 달',
|
||
MM : '%d달',
|
||
y : '일 년',
|
||
yy : '%d년'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}(일|월|주)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
case 'd':
|
||
case 'D':
|
||
case 'DDD':
|
||
return number + '일';
|
||
case 'M':
|
||
return number + '월';
|
||
case 'w':
|
||
case 'W':
|
||
return number + '주';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
meridiemParse : /오전|오후/,
|
||
isPM : function (token) {
|
||
return token === '오후';
|
||
},
|
||
meridiem : function (hour, minute, isUpper) {
|
||
return hour < 12 ? '오전' : '오후';
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Kyrgyz [ky]
|
||
//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
|
||
|
||
|
||
var suffixes$2 = {
|
||
0: '-чү',
|
||
1: '-чи',
|
||
2: '-чи',
|
||
3: '-чү',
|
||
4: '-чү',
|
||
5: '-чи',
|
||
6: '-чы',
|
||
7: '-чи',
|
||
8: '-чи',
|
||
9: '-чу',
|
||
10: '-чу',
|
||
20: '-чы',
|
||
30: '-чу',
|
||
40: '-чы',
|
||
50: '-чү',
|
||
60: '-чы',
|
||
70: '-чи',
|
||
80: '-чи',
|
||
90: '-чу',
|
||
100: '-чү'
|
||
};
|
||
|
||
hooks.defineLocale('ky', {
|
||
months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
|
||
monthsShort : 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
|
||
weekdays : 'Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби'.split('_'),
|
||
weekdaysShort : 'Жек_Дүй_Шей_Шар_Бей_Жум_Ише'.split('_'),
|
||
weekdaysMin : 'Жк_Дй_Шй_Шр_Бй_Жм_Иш'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Бүгүн саат] LT',
|
||
nextDay : '[Эртең саат] LT',
|
||
nextWeek : 'dddd [саат] LT',
|
||
lastDay : '[Кече саат] LT',
|
||
lastWeek : '[Өткен аптанын] dddd [күнү] [саат] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s ичинде',
|
||
past : '%s мурун',
|
||
s : 'бирнече секунд',
|
||
m : 'бир мүнөт',
|
||
mm : '%d мүнөт',
|
||
h : 'бир саат',
|
||
hh : '%d саат',
|
||
d : 'бир күн',
|
||
dd : '%d күн',
|
||
M : 'бир ай',
|
||
MM : '%d ай',
|
||
y : 'бир жыл',
|
||
yy : '%d жыл'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(чи|чы|чү|чу)/,
|
||
ordinal : function (number) {
|
||
var a = number % 10,
|
||
b = number >= 100 ? 100 : null;
|
||
return number + (suffixes$2[number] || suffixes$2[a] || suffixes$2[b]);
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Luxembourgish [lb]
|
||
//! author : mweimerskirch : https://github.com/mweimerskirch
|
||
//! author : David Raison : https://github.com/kwisatz
|
||
|
||
function processRelativeTime$5(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
'm': ['eng Minutt', 'enger Minutt'],
|
||
'h': ['eng Stonn', 'enger Stonn'],
|
||
'd': ['een Dag', 'engem Dag'],
|
||
'M': ['ee Mount', 'engem Mount'],
|
||
'y': ['ee Joer', 'engem Joer']
|
||
};
|
||
return withoutSuffix ? format[key][0] : format[key][1];
|
||
}
|
||
function processFutureTime(string) {
|
||
var number = string.substr(0, string.indexOf(' '));
|
||
if (eifelerRegelAppliesToNumber(number)) {
|
||
return 'a ' + string;
|
||
}
|
||
return 'an ' + string;
|
||
}
|
||
function processPastTime(string) {
|
||
var number = string.substr(0, string.indexOf(' '));
|
||
if (eifelerRegelAppliesToNumber(number)) {
|
||
return 'viru ' + string;
|
||
}
|
||
return 'virun ' + string;
|
||
}
|
||
/**
|
||
* Returns true if the word before the given number loses the '-n' ending.
|
||
* e.g. 'an 10 Deeg' but 'a 5 Deeg'
|
||
*
|
||
* @param number {integer}
|
||
* @returns {boolean}
|
||
*/
|
||
function eifelerRegelAppliesToNumber(number) {
|
||
number = parseInt(number, 10);
|
||
if (isNaN(number)) {
|
||
return false;
|
||
}
|
||
if (number < 0) {
|
||
// Negative Number --> always true
|
||
return true;
|
||
} else if (number < 10) {
|
||
// Only 1 digit
|
||
if (4 <= number && number <= 7) {
|
||
return true;
|
||
}
|
||
return false;
|
||
} else if (number < 100) {
|
||
// 2 digits
|
||
var lastDigit = number % 10, firstDigit = number / 10;
|
||
if (lastDigit === 0) {
|
||
return eifelerRegelAppliesToNumber(firstDigit);
|
||
}
|
||
return eifelerRegelAppliesToNumber(lastDigit);
|
||
} else if (number < 10000) {
|
||
// 3 or 4 digits --> recursively check first digit
|
||
while (number >= 10) {
|
||
number = number / 10;
|
||
}
|
||
return eifelerRegelAppliesToNumber(number);
|
||
} else {
|
||
// Anything larger than 4 digits: recursively check first n-3 digits
|
||
number = number / 1000;
|
||
return eifelerRegelAppliesToNumber(number);
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('lb', {
|
||
months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
|
||
monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'),
|
||
weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'),
|
||
weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat: {
|
||
LT: 'H:mm [Auer]',
|
||
LTS: 'H:mm:ss [Auer]',
|
||
L: 'DD.MM.YYYY',
|
||
LL: 'D. MMMM YYYY',
|
||
LLL: 'D. MMMM YYYY H:mm [Auer]',
|
||
LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]'
|
||
},
|
||
calendar: {
|
||
sameDay: '[Haut um] LT',
|
||
sameElse: 'L',
|
||
nextDay: '[Muer um] LT',
|
||
nextWeek: 'dddd [um] LT',
|
||
lastDay: '[Gëschter um] LT',
|
||
lastWeek: function () {
|
||
// Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
|
||
switch (this.day()) {
|
||
case 2:
|
||
case 4:
|
||
return '[Leschten] dddd [um] LT';
|
||
default:
|
||
return '[Leschte] dddd [um] LT';
|
||
}
|
||
}
|
||
},
|
||
relativeTime : {
|
||
future : processFutureTime,
|
||
past : processPastTime,
|
||
s : 'e puer Sekonnen',
|
||
m : processRelativeTime$5,
|
||
mm : '%d Minutten',
|
||
h : processRelativeTime$5,
|
||
hh : '%d Stonnen',
|
||
d : processRelativeTime$5,
|
||
dd : '%d Deeg',
|
||
M : processRelativeTime$5,
|
||
MM : '%d Méint',
|
||
y : processRelativeTime$5,
|
||
yy : '%d Joer'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal: '%d.',
|
||
week: {
|
||
dow: 1, // Monday is the first day of the week.
|
||
doy: 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Lao [lo]
|
||
//! author : Ryan Hart : https://github.com/ryanhart2
|
||
|
||
hooks.defineLocale('lo', {
|
||
months : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
|
||
monthsShort : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
|
||
weekdays : 'ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
|
||
weekdaysShort : 'ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
|
||
weekdaysMin : 'ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'ວັນdddd D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/,
|
||
isPM: function (input) {
|
||
return input === 'ຕອນແລງ';
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'ຕອນເຊົ້າ';
|
||
} else {
|
||
return 'ຕອນແລງ';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[ມື້ນີ້ເວລາ] LT',
|
||
nextDay : '[ມື້ອື່ນເວລາ] LT',
|
||
nextWeek : '[ວັນ]dddd[ໜ້າເວລາ] LT',
|
||
lastDay : '[ມື້ວານນີ້ເວລາ] LT',
|
||
lastWeek : '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'ອີກ %s',
|
||
past : '%sຜ່ານມາ',
|
||
s : 'ບໍ່ເທົ່າໃດວິນາທີ',
|
||
m : '1 ນາທີ',
|
||
mm : '%d ນາທີ',
|
||
h : '1 ຊົ່ວໂມງ',
|
||
hh : '%d ຊົ່ວໂມງ',
|
||
d : '1 ມື້',
|
||
dd : '%d ມື້',
|
||
M : '1 ເດືອນ',
|
||
MM : '%d ເດືອນ',
|
||
y : '1 ປີ',
|
||
yy : '%d ປີ'
|
||
},
|
||
dayOfMonthOrdinalParse: /(ທີ່)\d{1,2}/,
|
||
ordinal : function (number) {
|
||
return 'ທີ່' + number;
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Lithuanian [lt]
|
||
//! author : Mindaugas Mozūras : https://github.com/mmozuras
|
||
|
||
var units = {
|
||
'm' : 'minutė_minutės_minutę',
|
||
'mm': 'minutės_minučių_minutes',
|
||
'h' : 'valanda_valandos_valandą',
|
||
'hh': 'valandos_valandų_valandas',
|
||
'd' : 'diena_dienos_dieną',
|
||
'dd': 'dienos_dienų_dienas',
|
||
'M' : 'mėnuo_mėnesio_mėnesį',
|
||
'MM': 'mėnesiai_mėnesių_mėnesius',
|
||
'y' : 'metai_metų_metus',
|
||
'yy': 'metai_metų_metus'
|
||
};
|
||
function translateSeconds(number, withoutSuffix, key, isFuture) {
|
||
if (withoutSuffix) {
|
||
return 'kelios sekundės';
|
||
} else {
|
||
return isFuture ? 'kelių sekundžių' : 'kelias sekundes';
|
||
}
|
||
}
|
||
function translateSingular(number, withoutSuffix, key, isFuture) {
|
||
return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]);
|
||
}
|
||
function special(number) {
|
||
return number % 10 === 0 || (number > 10 && number < 20);
|
||
}
|
||
function forms(key) {
|
||
return units[key].split('_');
|
||
}
|
||
function translate$6(number, withoutSuffix, key, isFuture) {
|
||
var result = number + ' ';
|
||
if (number === 1) {
|
||
return result + translateSingular(number, withoutSuffix, key[0], isFuture);
|
||
} else if (withoutSuffix) {
|
||
return result + (special(number) ? forms(key)[1] : forms(key)[0]);
|
||
} else {
|
||
if (isFuture) {
|
||
return result + forms(key)[1];
|
||
} else {
|
||
return result + (special(number) ? forms(key)[1] : forms(key)[2]);
|
||
}
|
||
}
|
||
}
|
||
hooks.defineLocale('lt', {
|
||
months : {
|
||
format: 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'),
|
||
standalone: 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),
|
||
isFormat: /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/
|
||
},
|
||
monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),
|
||
weekdays : {
|
||
format: 'sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį'.split('_'),
|
||
standalone: 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'),
|
||
isFormat: /dddd HH:mm/
|
||
},
|
||
weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'),
|
||
weekdaysMin : 'S_P_A_T_K_Pn_Š'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY-MM-DD',
|
||
LL : 'YYYY [m.] MMMM D [d.]',
|
||
LLL : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
|
||
LLLL : 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]',
|
||
l : 'YYYY-MM-DD',
|
||
ll : 'YYYY [m.] MMMM D [d.]',
|
||
lll : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
|
||
llll : 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Šiandien] LT',
|
||
nextDay : '[Rytoj] LT',
|
||
nextWeek : 'dddd LT',
|
||
lastDay : '[Vakar] LT',
|
||
lastWeek : '[Praėjusį] dddd LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'po %s',
|
||
past : 'prieš %s',
|
||
s : translateSeconds,
|
||
m : translateSingular,
|
||
mm : translate$6,
|
||
h : translateSingular,
|
||
hh : translate$6,
|
||
d : translateSingular,
|
||
dd : translate$6,
|
||
M : translateSingular,
|
||
MM : translate$6,
|
||
y : translateSingular,
|
||
yy : translate$6
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-oji/,
|
||
ordinal : function (number) {
|
||
return number + '-oji';
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Latvian [lv]
|
||
//! author : Kristaps Karlsons : https://github.com/skakri
|
||
//! author : Jānis Elmeris : https://github.com/JanisE
|
||
|
||
var units$1 = {
|
||
'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
|
||
'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
|
||
'h': 'stundas_stundām_stunda_stundas'.split('_'),
|
||
'hh': 'stundas_stundām_stunda_stundas'.split('_'),
|
||
'd': 'dienas_dienām_diena_dienas'.split('_'),
|
||
'dd': 'dienas_dienām_diena_dienas'.split('_'),
|
||
'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
|
||
'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
|
||
'y': 'gada_gadiem_gads_gadi'.split('_'),
|
||
'yy': 'gada_gadiem_gads_gadi'.split('_')
|
||
};
|
||
/**
|
||
* @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
|
||
*/
|
||
function format$1(forms, number, withoutSuffix) {
|
||
if (withoutSuffix) {
|
||
// E.g. "21 minūte", "3 minūtes".
|
||
return number % 10 === 1 && number % 100 !== 11 ? forms[2] : forms[3];
|
||
} else {
|
||
// E.g. "21 minūtes" as in "pēc 21 minūtes".
|
||
// E.g. "3 minūtēm" as in "pēc 3 minūtēm".
|
||
return number % 10 === 1 && number % 100 !== 11 ? forms[0] : forms[1];
|
||
}
|
||
}
|
||
function relativeTimeWithPlural$1(number, withoutSuffix, key) {
|
||
return number + ' ' + format$1(units$1[key], number, withoutSuffix);
|
||
}
|
||
function relativeTimeWithSingular(number, withoutSuffix, key) {
|
||
return format$1(units$1[key], number, withoutSuffix);
|
||
}
|
||
function relativeSeconds(number, withoutSuffix) {
|
||
return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm';
|
||
}
|
||
|
||
hooks.defineLocale('lv', {
|
||
months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'),
|
||
weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'),
|
||
weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'),
|
||
weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY.',
|
||
LL : 'YYYY. [gada] D. MMMM',
|
||
LLL : 'YYYY. [gada] D. MMMM, HH:mm',
|
||
LLLL : 'YYYY. [gada] D. MMMM, dddd, HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Šodien pulksten] LT',
|
||
nextDay : '[Rīt pulksten] LT',
|
||
nextWeek : 'dddd [pulksten] LT',
|
||
lastDay : '[Vakar pulksten] LT',
|
||
lastWeek : '[Pagājušā] dddd [pulksten] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'pēc %s',
|
||
past : 'pirms %s',
|
||
s : relativeSeconds,
|
||
m : relativeTimeWithSingular,
|
||
mm : relativeTimeWithPlural$1,
|
||
h : relativeTimeWithSingular,
|
||
hh : relativeTimeWithPlural$1,
|
||
d : relativeTimeWithSingular,
|
||
dd : relativeTimeWithPlural$1,
|
||
M : relativeTimeWithSingular,
|
||
MM : relativeTimeWithPlural$1,
|
||
y : relativeTimeWithSingular,
|
||
yy : relativeTimeWithPlural$1
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Montenegrin [me]
|
||
//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
|
||
|
||
var translator = {
|
||
words: { //Different grammatical cases
|
||
m: ['jedan minut', 'jednog minuta'],
|
||
mm: ['minut', 'minuta', 'minuta'],
|
||
h: ['jedan sat', 'jednog sata'],
|
||
hh: ['sat', 'sata', 'sati'],
|
||
dd: ['dan', 'dana', 'dana'],
|
||
MM: ['mjesec', 'mjeseca', 'mjeseci'],
|
||
yy: ['godina', 'godine', 'godina']
|
||
},
|
||
correctGrammaticalCase: function (number, wordKey) {
|
||
return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
|
||
},
|
||
translate: function (number, withoutSuffix, key) {
|
||
var wordKey = translator.words[key];
|
||
if (key.length === 1) {
|
||
return withoutSuffix ? wordKey[0] : wordKey[1];
|
||
} else {
|
||
return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
|
||
}
|
||
}
|
||
};
|
||
|
||
hooks.defineLocale('me', {
|
||
months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
|
||
monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
|
||
weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
|
||
weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat: {
|
||
LT: 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L: 'DD.MM.YYYY',
|
||
LL: 'D. MMMM YYYY',
|
||
LLL: 'D. MMMM YYYY H:mm',
|
||
LLLL: 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[danas u] LT',
|
||
nextDay: '[sjutra u] LT',
|
||
|
||
nextWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[u] [nedjelju] [u] LT';
|
||
case 3:
|
||
return '[u] [srijedu] [u] LT';
|
||
case 6:
|
||
return '[u] [subotu] [u] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[u] dddd [u] LT';
|
||
}
|
||
},
|
||
lastDay : '[juče u] LT',
|
||
lastWeek : function () {
|
||
var lastWeekDays = [
|
||
'[prošle] [nedjelje] [u] LT',
|
||
'[prošlog] [ponedjeljka] [u] LT',
|
||
'[prošlog] [utorka] [u] LT',
|
||
'[prošle] [srijede] [u] LT',
|
||
'[prošlog] [četvrtka] [u] LT',
|
||
'[prošlog] [petka] [u] LT',
|
||
'[prošle] [subote] [u] LT'
|
||
];
|
||
return lastWeekDays[this.day()];
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : 'prije %s',
|
||
s : 'nekoliko sekundi',
|
||
m : translator.translate,
|
||
mm : translator.translate,
|
||
h : translator.translate,
|
||
hh : translator.translate,
|
||
d : 'dan',
|
||
dd : translator.translate,
|
||
M : 'mjesec',
|
||
MM : translator.translate,
|
||
y : 'godinu',
|
||
yy : translator.translate
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Maori [mi]
|
||
//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
|
||
|
||
hooks.defineLocale('mi', {
|
||
months: 'Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea'.split('_'),
|
||
monthsShort: 'Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki'.split('_'),
|
||
monthsRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
|
||
monthsStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
|
||
monthsShortRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
|
||
monthsShortStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,
|
||
weekdays: 'Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei'.split('_'),
|
||
weekdaysShort: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
|
||
weekdaysMin: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
|
||
longDateFormat: {
|
||
LT: 'HH:mm',
|
||
LTS: 'HH:mm:ss',
|
||
L: 'DD/MM/YYYY',
|
||
LL: 'D MMMM YYYY',
|
||
LLL: 'D MMMM YYYY [i] HH:mm',
|
||
LLLL: 'dddd, D MMMM YYYY [i] HH:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[i teie mahana, i] LT',
|
||
nextDay: '[apopo i] LT',
|
||
nextWeek: 'dddd [i] LT',
|
||
lastDay: '[inanahi i] LT',
|
||
lastWeek: 'dddd [whakamutunga i] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime: {
|
||
future: 'i roto i %s',
|
||
past: '%s i mua',
|
||
s: 'te hēkona ruarua',
|
||
m: 'he meneti',
|
||
mm: '%d meneti',
|
||
h: 'te haora',
|
||
hh: '%d haora',
|
||
d: 'he ra',
|
||
dd: '%d ra',
|
||
M: 'he marama',
|
||
MM: '%d marama',
|
||
y: 'he tau',
|
||
yy: '%d tau'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}º/,
|
||
ordinal: '%dº',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Macedonian [mk]
|
||
//! author : Borislav Mickov : https://github.com/B0k0
|
||
|
||
hooks.defineLocale('mk', {
|
||
months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'),
|
||
monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'),
|
||
weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'),
|
||
weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'),
|
||
weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'D.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Денес во] LT',
|
||
nextDay : '[Утре во] LT',
|
||
nextWeek : '[Во] dddd [во] LT',
|
||
lastDay : '[Вчера во] LT',
|
||
lastWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
case 3:
|
||
case 6:
|
||
return '[Изминатата] dddd [во] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[Изминатиот] dddd [во] LT';
|
||
}
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'после %s',
|
||
past : 'пред %s',
|
||
s : 'неколку секунди',
|
||
m : 'минута',
|
||
mm : '%d минути',
|
||
h : 'час',
|
||
hh : '%d часа',
|
||
d : 'ден',
|
||
dd : '%d дена',
|
||
M : 'месец',
|
||
MM : '%d месеци',
|
||
y : 'година',
|
||
yy : '%d години'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
|
||
ordinal : function (number) {
|
||
var lastDigit = number % 10,
|
||
last2Digits = number % 100;
|
||
if (number === 0) {
|
||
return number + '-ев';
|
||
} else if (last2Digits === 0) {
|
||
return number + '-ен';
|
||
} else if (last2Digits > 10 && last2Digits < 20) {
|
||
return number + '-ти';
|
||
} else if (lastDigit === 1) {
|
||
return number + '-ви';
|
||
} else if (lastDigit === 2) {
|
||
return number + '-ри';
|
||
} else if (lastDigit === 7 || lastDigit === 8) {
|
||
return number + '-ми';
|
||
} else {
|
||
return number + '-ти';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Malayalam [ml]
|
||
//! author : Floyd Pink : https://github.com/floydpink
|
||
|
||
hooks.defineLocale('ml', {
|
||
months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'),
|
||
monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'),
|
||
weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'),
|
||
weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm -നു',
|
||
LTS : 'A h:mm:ss -നു',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm -നു',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm -നു'
|
||
},
|
||
calendar : {
|
||
sameDay : '[ഇന്ന്] LT',
|
||
nextDay : '[നാളെ] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[ഇന്നലെ] LT',
|
||
lastWeek : '[കഴിഞ്ഞ] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s കഴിഞ്ഞ്',
|
||
past : '%s മുൻപ്',
|
||
s : 'അൽപ നിമിഷങ്ങൾ',
|
||
m : 'ഒരു മിനിറ്റ്',
|
||
mm : '%d മിനിറ്റ്',
|
||
h : 'ഒരു മണിക്കൂർ',
|
||
hh : '%d മണിക്കൂർ',
|
||
d : 'ഒരു ദിവസം',
|
||
dd : '%d ദിവസം',
|
||
M : 'ഒരു മാസം',
|
||
MM : '%d മാസം',
|
||
y : 'ഒരു വർഷം',
|
||
yy : '%d വർഷം'
|
||
},
|
||
meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if ((meridiem === 'രാത്രി' && hour >= 4) ||
|
||
meridiem === 'ഉച്ച കഴിഞ്ഞ്' ||
|
||
meridiem === 'വൈകുന്നേരം') {
|
||
return hour + 12;
|
||
} else {
|
||
return hour;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'രാത്രി';
|
||
} else if (hour < 12) {
|
||
return 'രാവിലെ';
|
||
} else if (hour < 17) {
|
||
return 'ഉച്ച കഴിഞ്ഞ്';
|
||
} else if (hour < 20) {
|
||
return 'വൈകുന്നേരം';
|
||
} else {
|
||
return 'രാത്രി';
|
||
}
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Marathi [mr]
|
||
//! author : Harshad Kale : https://github.com/kalehv
|
||
//! author : Vivek Athalye : https://github.com/vnathalye
|
||
|
||
var symbolMap$9 = {
|
||
'1': '१',
|
||
'2': '२',
|
||
'3': '३',
|
||
'4': '४',
|
||
'5': '५',
|
||
'6': '६',
|
||
'7': '७',
|
||
'8': '८',
|
||
'9': '९',
|
||
'0': '०'
|
||
};
|
||
var numberMap$8 = {
|
||
'१': '1',
|
||
'२': '2',
|
||
'३': '3',
|
||
'४': '4',
|
||
'५': '5',
|
||
'६': '6',
|
||
'७': '7',
|
||
'८': '8',
|
||
'९': '9',
|
||
'०': '0'
|
||
};
|
||
|
||
function relativeTimeMr(number, withoutSuffix, string, isFuture)
|
||
{
|
||
var output = '';
|
||
if (withoutSuffix) {
|
||
switch (string) {
|
||
case 's': output = 'काही सेकंद'; break;
|
||
case 'm': output = 'एक मिनिट'; break;
|
||
case 'mm': output = '%d मिनिटे'; break;
|
||
case 'h': output = 'एक तास'; break;
|
||
case 'hh': output = '%d तास'; break;
|
||
case 'd': output = 'एक दिवस'; break;
|
||
case 'dd': output = '%d दिवस'; break;
|
||
case 'M': output = 'एक महिना'; break;
|
||
case 'MM': output = '%d महिने'; break;
|
||
case 'y': output = 'एक वर्ष'; break;
|
||
case 'yy': output = '%d वर्षे'; break;
|
||
}
|
||
}
|
||
else {
|
||
switch (string) {
|
||
case 's': output = 'काही सेकंदां'; break;
|
||
case 'm': output = 'एका मिनिटा'; break;
|
||
case 'mm': output = '%d मिनिटां'; break;
|
||
case 'h': output = 'एका तासा'; break;
|
||
case 'hh': output = '%d तासां'; break;
|
||
case 'd': output = 'एका दिवसा'; break;
|
||
case 'dd': output = '%d दिवसां'; break;
|
||
case 'M': output = 'एका महिन्या'; break;
|
||
case 'MM': output = '%d महिन्यां'; break;
|
||
case 'y': output = 'एका वर्षा'; break;
|
||
case 'yy': output = '%d वर्षां'; break;
|
||
}
|
||
}
|
||
return output.replace(/%d/i, number);
|
||
}
|
||
|
||
hooks.defineLocale('mr', {
|
||
months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
|
||
monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
|
||
weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
|
||
weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm वाजता',
|
||
LTS : 'A h:mm:ss वाजता',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm वाजता',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
|
||
},
|
||
calendar : {
|
||
sameDay : '[आज] LT',
|
||
nextDay : '[उद्या] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[काल] LT',
|
||
lastWeek: '[मागील] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future: '%sमध्ये',
|
||
past: '%sपूर्वी',
|
||
s: relativeTimeMr,
|
||
m: relativeTimeMr,
|
||
mm: relativeTimeMr,
|
||
h: relativeTimeMr,
|
||
hh: relativeTimeMr,
|
||
d: relativeTimeMr,
|
||
dd: relativeTimeMr,
|
||
M: relativeTimeMr,
|
||
MM: relativeTimeMr,
|
||
y: relativeTimeMr,
|
||
yy: relativeTimeMr
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[१२३४५६७८९०]/g, function (match) {
|
||
return numberMap$8[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$9[match];
|
||
});
|
||
},
|
||
meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'रात्री') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'सकाळी') {
|
||
return hour;
|
||
} else if (meridiem === 'दुपारी') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'सायंकाळी') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem: function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'रात्री';
|
||
} else if (hour < 10) {
|
||
return 'सकाळी';
|
||
} else if (hour < 17) {
|
||
return 'दुपारी';
|
||
} else if (hour < 20) {
|
||
return 'सायंकाळी';
|
||
} else {
|
||
return 'रात्री';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Malay [ms-my]
|
||
//! note : DEPRECATED, the correct one is [ms]
|
||
//! author : Weldan Jamili : https://github.com/weldan
|
||
|
||
hooks.defineLocale('ms-my', {
|
||
months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
|
||
weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
|
||
weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
|
||
weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH.mm',
|
||
LTS : 'HH.mm.ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY [pukul] HH.mm',
|
||
LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
|
||
},
|
||
meridiemParse: /pagi|tengahari|petang|malam/,
|
||
meridiemHour: function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'pagi') {
|
||
return hour;
|
||
} else if (meridiem === 'tengahari') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === 'petang' || meridiem === 'malam') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 11) {
|
||
return 'pagi';
|
||
} else if (hours < 15) {
|
||
return 'tengahari';
|
||
} else if (hours < 19) {
|
||
return 'petang';
|
||
} else {
|
||
return 'malam';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[Hari ini pukul] LT',
|
||
nextDay : '[Esok pukul] LT',
|
||
nextWeek : 'dddd [pukul] LT',
|
||
lastDay : '[Kelmarin pukul] LT',
|
||
lastWeek : 'dddd [lepas pukul] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dalam %s',
|
||
past : '%s yang lepas',
|
||
s : 'beberapa saat',
|
||
m : 'seminit',
|
||
mm : '%d minit',
|
||
h : 'sejam',
|
||
hh : '%d jam',
|
||
d : 'sehari',
|
||
dd : '%d hari',
|
||
M : 'sebulan',
|
||
MM : '%d bulan',
|
||
y : 'setahun',
|
||
yy : '%d tahun'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Malay [ms]
|
||
//! author : Weldan Jamili : https://github.com/weldan
|
||
|
||
hooks.defineLocale('ms', {
|
||
months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
|
||
weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
|
||
weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
|
||
weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH.mm',
|
||
LTS : 'HH.mm.ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY [pukul] HH.mm',
|
||
LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
|
||
},
|
||
meridiemParse: /pagi|tengahari|petang|malam/,
|
||
meridiemHour: function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'pagi') {
|
||
return hour;
|
||
} else if (meridiem === 'tengahari') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === 'petang' || meridiem === 'malam') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 11) {
|
||
return 'pagi';
|
||
} else if (hours < 15) {
|
||
return 'tengahari';
|
||
} else if (hours < 19) {
|
||
return 'petang';
|
||
} else {
|
||
return 'malam';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[Hari ini pukul] LT',
|
||
nextDay : '[Esok pukul] LT',
|
||
nextWeek : 'dddd [pukul] LT',
|
||
lastDay : '[Kelmarin pukul] LT',
|
||
lastWeek : 'dddd [lepas pukul] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dalam %s',
|
||
past : '%s yang lepas',
|
||
s : 'beberapa saat',
|
||
m : 'seminit',
|
||
mm : '%d minit',
|
||
h : 'sejam',
|
||
hh : '%d jam',
|
||
d : 'sehari',
|
||
dd : '%d hari',
|
||
M : 'sebulan',
|
||
MM : '%d bulan',
|
||
y : 'setahun',
|
||
yy : '%d tahun'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Burmese [my]
|
||
//! author : Squar team, mysquar.com
|
||
//! author : David Rossellat : https://github.com/gholadr
|
||
//! author : Tin Aung Lin : https://github.com/thanyawzinmin
|
||
|
||
var symbolMap$10 = {
|
||
'1': '၁',
|
||
'2': '၂',
|
||
'3': '၃',
|
||
'4': '၄',
|
||
'5': '၅',
|
||
'6': '၆',
|
||
'7': '၇',
|
||
'8': '၈',
|
||
'9': '၉',
|
||
'0': '၀'
|
||
};
|
||
var numberMap$9 = {
|
||
'၁': '1',
|
||
'၂': '2',
|
||
'၃': '3',
|
||
'၄': '4',
|
||
'၅': '5',
|
||
'၆': '6',
|
||
'၇': '7',
|
||
'၈': '8',
|
||
'၉': '9',
|
||
'၀': '0'
|
||
};
|
||
|
||
hooks.defineLocale('my', {
|
||
months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'),
|
||
monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'),
|
||
weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'),
|
||
weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
|
||
weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
|
||
|
||
longDateFormat: {
|
||
LT: 'HH:mm',
|
||
LTS: 'HH:mm:ss',
|
||
L: 'DD/MM/YYYY',
|
||
LL: 'D MMMM YYYY',
|
||
LLL: 'D MMMM YYYY HH:mm',
|
||
LLLL: 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[ယနေ.] LT [မှာ]',
|
||
nextDay: '[မနက်ဖြန်] LT [မှာ]',
|
||
nextWeek: 'dddd LT [မှာ]',
|
||
lastDay: '[မနေ.က] LT [မှာ]',
|
||
lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime: {
|
||
future: 'လာမည့် %s မှာ',
|
||
past: 'လွန်ခဲ့သော %s က',
|
||
s: 'စက္ကန်.အနည်းငယ်',
|
||
m: 'တစ်မိနစ်',
|
||
mm: '%d မိနစ်',
|
||
h: 'တစ်နာရီ',
|
||
hh: '%d နာရီ',
|
||
d: 'တစ်ရက်',
|
||
dd: '%d ရက်',
|
||
M: 'တစ်လ',
|
||
MM: '%d လ',
|
||
y: 'တစ်နှစ်',
|
||
yy: '%d နှစ်'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) {
|
||
return numberMap$9[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$10[match];
|
||
});
|
||
},
|
||
week: {
|
||
dow: 1, // Monday is the first day of the week.
|
||
doy: 4 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Norwegian Bokmål [nb]
|
||
//! authors : Espen Hovlandsdal : https://github.com/rexxars
|
||
//! Sigurd Gartmann : https://github.com/sigurdga
|
||
|
||
hooks.defineLocale('nb', {
|
||
months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
|
||
monthsShort : 'jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
|
||
weekdaysShort : 'sø._ma._ti._on._to._fr._lø.'.split('_'),
|
||
weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY [kl.] HH:mm',
|
||
LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[i dag kl.] LT',
|
||
nextDay: '[i morgen kl.] LT',
|
||
nextWeek: 'dddd [kl.] LT',
|
||
lastDay: '[i går kl.] LT',
|
||
lastWeek: '[forrige] dddd [kl.] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'om %s',
|
||
past : '%s siden',
|
||
s : 'noen sekunder',
|
||
m : 'ett minutt',
|
||
mm : '%d minutter',
|
||
h : 'en time',
|
||
hh : '%d timer',
|
||
d : 'en dag',
|
||
dd : '%d dager',
|
||
M : 'en måned',
|
||
MM : '%d måneder',
|
||
y : 'ett år',
|
||
yy : '%d år'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Nepalese [ne]
|
||
//! author : suvash : https://github.com/suvash
|
||
|
||
var symbolMap$11 = {
|
||
'1': '१',
|
||
'2': '२',
|
||
'3': '३',
|
||
'4': '४',
|
||
'5': '५',
|
||
'6': '६',
|
||
'7': '७',
|
||
'8': '८',
|
||
'9': '९',
|
||
'0': '०'
|
||
};
|
||
var numberMap$10 = {
|
||
'१': '1',
|
||
'२': '2',
|
||
'३': '3',
|
||
'४': '4',
|
||
'५': '5',
|
||
'६': '6',
|
||
'७': '7',
|
||
'८': '8',
|
||
'९': '9',
|
||
'०': '0'
|
||
};
|
||
|
||
hooks.defineLocale('ne', {
|
||
months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'),
|
||
monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'),
|
||
weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'),
|
||
weekdaysMin : 'आ._सो._मं._बु._बि._शु._श.'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'Aको h:mm बजे',
|
||
LTS : 'Aको h:mm:ss बजे',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, Aको h:mm बजे',
|
||
LLLL : 'dddd, D MMMM YYYY, Aको h:mm बजे'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[१२३४५६७८९०]/g, function (match) {
|
||
return numberMap$10[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$11[match];
|
||
});
|
||
},
|
||
meridiemParse: /राति|बिहान|दिउँसो|साँझ/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'राति') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'बिहान') {
|
||
return hour;
|
||
} else if (meridiem === 'दिउँसो') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'साँझ') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 3) {
|
||
return 'राति';
|
||
} else if (hour < 12) {
|
||
return 'बिहान';
|
||
} else if (hour < 16) {
|
||
return 'दिउँसो';
|
||
} else if (hour < 20) {
|
||
return 'साँझ';
|
||
} else {
|
||
return 'राति';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[आज] LT',
|
||
nextDay : '[भोलि] LT',
|
||
nextWeek : '[आउँदो] dddd[,] LT',
|
||
lastDay : '[हिजो] LT',
|
||
lastWeek : '[गएको] dddd[,] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%sमा',
|
||
past : '%s अगाडि',
|
||
s : 'केही क्षण',
|
||
m : 'एक मिनेट',
|
||
mm : '%d मिनेट',
|
||
h : 'एक घण्टा',
|
||
hh : '%d घण्टा',
|
||
d : 'एक दिन',
|
||
dd : '%d दिन',
|
||
M : 'एक महिना',
|
||
MM : '%d महिना',
|
||
y : 'एक बर्ष',
|
||
yy : '%d बर्ष'
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Dutch (Belgium) [nl-be]
|
||
//! author : Joris Röling : https://github.com/jorisroling
|
||
//! author : Jacob Middag : https://github.com/middagj
|
||
|
||
var monthsShortWithDots$1 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
|
||
var monthsShortWithoutDots$1 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
|
||
|
||
var monthsParse$2 = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
|
||
var monthsRegex$3 = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
|
||
|
||
hooks.defineLocale('nl-be', {
|
||
months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
|
||
monthsShort : function (m, format) {
|
||
if (!m) {
|
||
return monthsShortWithDots$1;
|
||
} else if (/-MMM-/.test(format)) {
|
||
return monthsShortWithoutDots$1[m.month()];
|
||
} else {
|
||
return monthsShortWithDots$1[m.month()];
|
||
}
|
||
},
|
||
|
||
monthsRegex: monthsRegex$3,
|
||
monthsShortRegex: monthsRegex$3,
|
||
monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
|
||
monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
|
||
|
||
monthsParse : monthsParse$2,
|
||
longMonthsParse : monthsParse$2,
|
||
shortMonthsParse : monthsParse$2,
|
||
|
||
weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
|
||
weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
|
||
weekdaysMin : 'zo_ma_di_wo_do_vr_za'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[vandaag om] LT',
|
||
nextDay: '[morgen om] LT',
|
||
nextWeek: 'dddd [om] LT',
|
||
lastDay: '[gisteren om] LT',
|
||
lastWeek: '[afgelopen] dddd [om] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'over %s',
|
||
past : '%s geleden',
|
||
s : 'een paar seconden',
|
||
m : 'één minuut',
|
||
mm : '%d minuten',
|
||
h : 'één uur',
|
||
hh : '%d uur',
|
||
d : 'één dag',
|
||
dd : '%d dagen',
|
||
M : 'één maand',
|
||
MM : '%d maanden',
|
||
y : 'één jaar',
|
||
yy : '%d jaar'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/,
|
||
ordinal : function (number) {
|
||
return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Dutch [nl]
|
||
//! author : Joris Röling : https://github.com/jorisroling
|
||
//! author : Jacob Middag : https://github.com/middagj
|
||
|
||
var monthsShortWithDots$2 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
|
||
var monthsShortWithoutDots$2 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
|
||
|
||
var monthsParse$3 = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
|
||
var monthsRegex$4 = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
|
||
|
||
hooks.defineLocale('nl', {
|
||
months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
|
||
monthsShort : function (m, format) {
|
||
if (!m) {
|
||
return monthsShortWithDots$2;
|
||
} else if (/-MMM-/.test(format)) {
|
||
return monthsShortWithoutDots$2[m.month()];
|
||
} else {
|
||
return monthsShortWithDots$2[m.month()];
|
||
}
|
||
},
|
||
|
||
monthsRegex: monthsRegex$4,
|
||
monthsShortRegex: monthsRegex$4,
|
||
monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
|
||
monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
|
||
|
||
monthsParse : monthsParse$3,
|
||
longMonthsParse : monthsParse$3,
|
||
shortMonthsParse : monthsParse$3,
|
||
|
||
weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
|
||
weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
|
||
weekdaysMin : 'zo_ma_di_wo_do_vr_za'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD-MM-YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[vandaag om] LT',
|
||
nextDay: '[morgen om] LT',
|
||
nextWeek: 'dddd [om] LT',
|
||
lastDay: '[gisteren om] LT',
|
||
lastWeek: '[afgelopen] dddd [om] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'over %s',
|
||
past : '%s geleden',
|
||
s : 'een paar seconden',
|
||
m : 'één minuut',
|
||
mm : '%d minuten',
|
||
h : 'één uur',
|
||
hh : '%d uur',
|
||
d : 'één dag',
|
||
dd : '%d dagen',
|
||
M : 'één maand',
|
||
MM : '%d maanden',
|
||
y : 'één jaar',
|
||
yy : '%d jaar'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/,
|
||
ordinal : function (number) {
|
||
return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Nynorsk [nn]
|
||
//! author : https://github.com/mechuwind
|
||
|
||
hooks.defineLocale('nn', {
|
||
months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
|
||
weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'),
|
||
weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'),
|
||
weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY [kl.] H:mm',
|
||
LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[I dag klokka] LT',
|
||
nextDay: '[I morgon klokka] LT',
|
||
nextWeek: 'dddd [klokka] LT',
|
||
lastDay: '[I går klokka] LT',
|
||
lastWeek: '[Føregåande] dddd [klokka] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'om %s',
|
||
past : '%s sidan',
|
||
s : 'nokre sekund',
|
||
m : 'eit minutt',
|
||
mm : '%d minutt',
|
||
h : 'ein time',
|
||
hh : '%d timar',
|
||
d : 'ein dag',
|
||
dd : '%d dagar',
|
||
M : 'ein månad',
|
||
MM : '%d månader',
|
||
y : 'eit år',
|
||
yy : '%d år'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Punjabi (India) [pa-in]
|
||
//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
|
||
|
||
var symbolMap$12 = {
|
||
'1': '੧',
|
||
'2': '੨',
|
||
'3': '੩',
|
||
'4': '੪',
|
||
'5': '੫',
|
||
'6': '੬',
|
||
'7': '੭',
|
||
'8': '੮',
|
||
'9': '੯',
|
||
'0': '੦'
|
||
};
|
||
var numberMap$11 = {
|
||
'੧': '1',
|
||
'੨': '2',
|
||
'੩': '3',
|
||
'੪': '4',
|
||
'੫': '5',
|
||
'੬': '6',
|
||
'੭': '7',
|
||
'੮': '8',
|
||
'੯': '9',
|
||
'੦': '0'
|
||
};
|
||
|
||
hooks.defineLocale('pa-in', {
|
||
// There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
|
||
months : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
|
||
monthsShort : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
|
||
weekdays : 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split('_'),
|
||
weekdaysShort : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
|
||
weekdaysMin : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm ਵਜੇ',
|
||
LTS : 'A h:mm:ss ਵਜੇ',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm ਵਜੇ',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm ਵਜੇ'
|
||
},
|
||
calendar : {
|
||
sameDay : '[ਅਜ] LT',
|
||
nextDay : '[ਕਲ] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[ਕਲ] LT',
|
||
lastWeek : '[ਪਿਛਲੇ] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s ਵਿੱਚ',
|
||
past : '%s ਪਿਛਲੇ',
|
||
s : 'ਕੁਝ ਸਕਿੰਟ',
|
||
m : 'ਇਕ ਮਿੰਟ',
|
||
mm : '%d ਮਿੰਟ',
|
||
h : 'ਇੱਕ ਘੰਟਾ',
|
||
hh : '%d ਘੰਟੇ',
|
||
d : 'ਇੱਕ ਦਿਨ',
|
||
dd : '%d ਦਿਨ',
|
||
M : 'ਇੱਕ ਮਹੀਨਾ',
|
||
MM : '%d ਮਹੀਨੇ',
|
||
y : 'ਇੱਕ ਸਾਲ',
|
||
yy : '%d ਸਾਲ'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (match) {
|
||
return numberMap$11[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$12[match];
|
||
});
|
||
},
|
||
// Punjabi notation for meridiems are quite fuzzy in practice. While there exists
|
||
// a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
|
||
meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'ਰਾਤ') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'ਸਵੇਰ') {
|
||
return hour;
|
||
} else if (meridiem === 'ਦੁਪਹਿਰ') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'ਸ਼ਾਮ') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'ਰਾਤ';
|
||
} else if (hour < 10) {
|
||
return 'ਸਵੇਰ';
|
||
} else if (hour < 17) {
|
||
return 'ਦੁਪਹਿਰ';
|
||
} else if (hour < 20) {
|
||
return 'ਸ਼ਾਮ';
|
||
} else {
|
||
return 'ਰਾਤ';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Polish [pl]
|
||
//! author : Rafal Hirsz : https://github.com/evoL
|
||
|
||
var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_');
|
||
var monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_');
|
||
function plural$3(n) {
|
||
return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1);
|
||
}
|
||
function translate$7(number, withoutSuffix, key) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 'm':
|
||
return withoutSuffix ? 'minuta' : 'minutę';
|
||
case 'mm':
|
||
return result + (plural$3(number) ? 'minuty' : 'minut');
|
||
case 'h':
|
||
return withoutSuffix ? 'godzina' : 'godzinę';
|
||
case 'hh':
|
||
return result + (plural$3(number) ? 'godziny' : 'godzin');
|
||
case 'MM':
|
||
return result + (plural$3(number) ? 'miesiące' : 'miesięcy');
|
||
case 'yy':
|
||
return result + (plural$3(number) ? 'lata' : 'lat');
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('pl', {
|
||
months : function (momentToFormat, format) {
|
||
if (!momentToFormat) {
|
||
return monthsNominative;
|
||
} else if (format === '') {
|
||
// Hack: if format empty we know this is used to generate
|
||
// RegExp by moment. Give then back both valid forms of months
|
||
// in RegExp ready format.
|
||
return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')';
|
||
} else if (/D MMMM/.test(format)) {
|
||
return monthsSubjective[momentToFormat.month()];
|
||
} else {
|
||
return monthsNominative[momentToFormat.month()];
|
||
}
|
||
},
|
||
monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),
|
||
weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),
|
||
weekdaysShort : 'ndz_pon_wt_śr_czw_pt_sob'.split('_'),
|
||
weekdaysMin : 'Nd_Pn_Wt_Śr_Cz_Pt_So'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Dziś o] LT',
|
||
nextDay: '[Jutro o] LT',
|
||
nextWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[W niedzielę o] LT';
|
||
|
||
case 2:
|
||
return '[We wtorek o] LT';
|
||
|
||
case 3:
|
||
return '[W środę o] LT';
|
||
|
||
case 6:
|
||
return '[W sobotę o] LT';
|
||
|
||
default:
|
||
return '[W] dddd [o] LT';
|
||
}
|
||
},
|
||
lastDay: '[Wczoraj o] LT',
|
||
lastWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[W zeszłą niedzielę o] LT';
|
||
case 3:
|
||
return '[W zeszłą środę o] LT';
|
||
case 6:
|
||
return '[W zeszłą sobotę o] LT';
|
||
default:
|
||
return '[W zeszły] dddd [o] LT';
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : '%s temu',
|
||
s : 'kilka sekund',
|
||
m : translate$7,
|
||
mm : translate$7,
|
||
h : translate$7,
|
||
hh : translate$7,
|
||
d : '1 dzień',
|
||
dd : '%d dni',
|
||
M : 'miesiąc',
|
||
MM : translate$7,
|
||
y : 'rok',
|
||
yy : translate$7
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Portuguese (Brazil) [pt-br]
|
||
//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
|
||
|
||
hooks.defineLocale('pt-br', {
|
||
months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'),
|
||
monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'),
|
||
weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
|
||
weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
|
||
weekdaysMin : 'Do_2ª_3ª_4ª_5ª_6ª_Sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [de] MMMM [de] YYYY',
|
||
LLL : 'D [de] MMMM [de] YYYY [às] HH:mm',
|
||
LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Hoje às] LT',
|
||
nextDay: '[Amanhã às] LT',
|
||
nextWeek: 'dddd [às] LT',
|
||
lastDay: '[Ontem às] LT',
|
||
lastWeek: function () {
|
||
return (this.day() === 0 || this.day() === 6) ?
|
||
'[Último] dddd [às] LT' : // Saturday + Sunday
|
||
'[Última] dddd [às] LT'; // Monday - Friday
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'em %s',
|
||
past : '%s atrás',
|
||
s : 'poucos segundos',
|
||
ss : '%d segundos',
|
||
m : 'um minuto',
|
||
mm : '%d minutos',
|
||
h : 'uma hora',
|
||
hh : '%d horas',
|
||
d : 'um dia',
|
||
dd : '%d dias',
|
||
M : 'um mês',
|
||
MM : '%d meses',
|
||
y : 'um ano',
|
||
yy : '%d anos'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}º/,
|
||
ordinal : '%dº'
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Portuguese [pt]
|
||
//! author : Jefferson : https://github.com/jalex79
|
||
|
||
hooks.defineLocale('pt', {
|
||
months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'),
|
||
monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'),
|
||
weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
|
||
weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
|
||
weekdaysMin : 'Do_2ª_3ª_4ª_5ª_6ª_Sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D [de] MMMM [de] YYYY',
|
||
LLL : 'D [de] MMMM [de] YYYY HH:mm',
|
||
LLLL : 'dddd, D [de] MMMM [de] YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Hoje às] LT',
|
||
nextDay: '[Amanhã às] LT',
|
||
nextWeek: 'dddd [às] LT',
|
||
lastDay: '[Ontem às] LT',
|
||
lastWeek: function () {
|
||
return (this.day() === 0 || this.day() === 6) ?
|
||
'[Último] dddd [às] LT' : // Saturday + Sunday
|
||
'[Última] dddd [às] LT'; // Monday - Friday
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'em %s',
|
||
past : 'há %s',
|
||
s : 'segundos',
|
||
m : 'um minuto',
|
||
mm : '%d minutos',
|
||
h : 'uma hora',
|
||
hh : '%d horas',
|
||
d : 'um dia',
|
||
dd : '%d dias',
|
||
M : 'um mês',
|
||
MM : '%d meses',
|
||
y : 'um ano',
|
||
yy : '%d anos'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}º/,
|
||
ordinal : '%dº',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Romanian [ro]
|
||
//! author : Vlad Gurdiga : https://github.com/gurdiga
|
||
//! author : Valentin Agachi : https://github.com/avaly
|
||
|
||
function relativeTimeWithPlural$2(number, withoutSuffix, key) {
|
||
var format = {
|
||
'mm': 'minute',
|
||
'hh': 'ore',
|
||
'dd': 'zile',
|
||
'MM': 'luni',
|
||
'yy': 'ani'
|
||
},
|
||
separator = ' ';
|
||
if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) {
|
||
separator = ' de ';
|
||
}
|
||
return number + separator + format[key];
|
||
}
|
||
|
||
hooks.defineLocale('ro', {
|
||
months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'),
|
||
monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'),
|
||
weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'),
|
||
weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[azi la] LT',
|
||
nextDay: '[mâine la] LT',
|
||
nextWeek: 'dddd [la] LT',
|
||
lastDay: '[ieri la] LT',
|
||
lastWeek: '[fosta] dddd [la] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'peste %s',
|
||
past : '%s în urmă',
|
||
s : 'câteva secunde',
|
||
m : 'un minut',
|
||
mm : relativeTimeWithPlural$2,
|
||
h : 'o oră',
|
||
hh : relativeTimeWithPlural$2,
|
||
d : 'o zi',
|
||
dd : relativeTimeWithPlural$2,
|
||
M : 'o lună',
|
||
MM : relativeTimeWithPlural$2,
|
||
y : 'un an',
|
||
yy : relativeTimeWithPlural$2
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Russian [ru]
|
||
//! author : Viktorminator : https://github.com/Viktorminator
|
||
//! Author : Menelion Elensúle : https://github.com/Oire
|
||
//! author : Коренберг Марк : https://github.com/socketpair
|
||
|
||
function plural$4(word, num) {
|
||
var forms = word.split('_');
|
||
return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
|
||
}
|
||
function relativeTimeWithPlural$3(number, withoutSuffix, key) {
|
||
var format = {
|
||
'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
|
||
'hh': 'час_часа_часов',
|
||
'dd': 'день_дня_дней',
|
||
'MM': 'месяц_месяца_месяцев',
|
||
'yy': 'год_года_лет'
|
||
};
|
||
if (key === 'm') {
|
||
return withoutSuffix ? 'минута' : 'минуту';
|
||
}
|
||
else {
|
||
return number + ' ' + plural$4(format[key], +number);
|
||
}
|
||
}
|
||
var monthsParse$4 = [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[йя]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i];
|
||
|
||
// http://new.gramota.ru/spravka/rules/139-prop : § 103
|
||
// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
|
||
// CLDR data: http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
|
||
hooks.defineLocale('ru', {
|
||
months : {
|
||
format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_'),
|
||
standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_')
|
||
},
|
||
monthsShort : {
|
||
// по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
|
||
format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split('_'),
|
||
standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')
|
||
},
|
||
weekdays : {
|
||
standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
|
||
format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_'),
|
||
isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/
|
||
},
|
||
weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
|
||
weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
|
||
monthsParse : monthsParse$4,
|
||
longMonthsParse : monthsParse$4,
|
||
shortMonthsParse : monthsParse$4,
|
||
|
||
// полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
|
||
monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
|
||
|
||
// копия предыдущего
|
||
monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
|
||
|
||
// полные названия с падежами
|
||
monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
|
||
|
||
// Выражение, которое соотвествует только сокращённым формам
|
||
monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY г.',
|
||
LLL : 'D MMMM YYYY г., HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY г., HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Сегодня в] LT',
|
||
nextDay: '[Завтра в] LT',
|
||
lastDay: '[Вчера в] LT',
|
||
nextWeek: function (now) {
|
||
if (now.week() !== this.week()) {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[В следующее] dddd [в] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
return '[В следующий] dddd [в] LT';
|
||
case 3:
|
||
case 5:
|
||
case 6:
|
||
return '[В следующую] dddd [в] LT';
|
||
}
|
||
} else {
|
||
if (this.day() === 2) {
|
||
return '[Во] dddd [в] LT';
|
||
} else {
|
||
return '[В] dddd [в] LT';
|
||
}
|
||
}
|
||
},
|
||
lastWeek: function (now) {
|
||
if (now.week() !== this.week()) {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[В прошлое] dddd [в] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
return '[В прошлый] dddd [в] LT';
|
||
case 3:
|
||
case 5:
|
||
case 6:
|
||
return '[В прошлую] dddd [в] LT';
|
||
}
|
||
} else {
|
||
if (this.day() === 2) {
|
||
return '[Во] dddd [в] LT';
|
||
} else {
|
||
return '[В] dddd [в] LT';
|
||
}
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'через %s',
|
||
past : '%s назад',
|
||
s : 'несколько секунд',
|
||
m : relativeTimeWithPlural$3,
|
||
mm : relativeTimeWithPlural$3,
|
||
h : 'час',
|
||
hh : relativeTimeWithPlural$3,
|
||
d : 'день',
|
||
dd : relativeTimeWithPlural$3,
|
||
M : 'месяц',
|
||
MM : relativeTimeWithPlural$3,
|
||
y : 'год',
|
||
yy : relativeTimeWithPlural$3
|
||
},
|
||
meridiemParse: /ночи|утра|дня|вечера/i,
|
||
isPM : function (input) {
|
||
return /^(дня|вечера)$/.test(input);
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'ночи';
|
||
} else if (hour < 12) {
|
||
return 'утра';
|
||
} else if (hour < 17) {
|
||
return 'дня';
|
||
} else {
|
||
return 'вечера';
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(й|го|я)/,
|
||
ordinal: function (number, period) {
|
||
switch (period) {
|
||
case 'M':
|
||
case 'd':
|
||
case 'DDD':
|
||
return number + '-й';
|
||
case 'D':
|
||
return number + '-го';
|
||
case 'w':
|
||
case 'W':
|
||
return number + '-я';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Sindhi [sd]
|
||
//! author : Narain Sagar : https://github.com/narainsagar
|
||
|
||
var months$6 = [
|
||
'جنوري',
|
||
'فيبروري',
|
||
'مارچ',
|
||
'اپريل',
|
||
'مئي',
|
||
'جون',
|
||
'جولاءِ',
|
||
'آگسٽ',
|
||
'سيپٽمبر',
|
||
'آڪٽوبر',
|
||
'نومبر',
|
||
'ڊسمبر'
|
||
];
|
||
var days$1 = [
|
||
'آچر',
|
||
'سومر',
|
||
'اڱارو',
|
||
'اربع',
|
||
'خميس',
|
||
'جمع',
|
||
'ڇنڇر'
|
||
];
|
||
|
||
hooks.defineLocale('sd', {
|
||
months : months$6,
|
||
monthsShort : months$6,
|
||
weekdays : days$1,
|
||
weekdaysShort : days$1,
|
||
weekdaysMin : days$1,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd، D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /صبح|شام/,
|
||
isPM : function (input) {
|
||
return 'شام' === input;
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'صبح';
|
||
}
|
||
return 'شام';
|
||
},
|
||
calendar : {
|
||
sameDay : '[اڄ] LT',
|
||
nextDay : '[سڀاڻي] LT',
|
||
nextWeek : 'dddd [اڳين هفتي تي] LT',
|
||
lastDay : '[ڪالهه] LT',
|
||
lastWeek : '[گزريل هفتي] dddd [تي] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s پوء',
|
||
past : '%s اڳ',
|
||
s : 'چند سيڪنڊ',
|
||
m : 'هڪ منٽ',
|
||
mm : '%d منٽ',
|
||
h : 'هڪ ڪلاڪ',
|
||
hh : '%d ڪلاڪ',
|
||
d : 'هڪ ڏينهن',
|
||
dd : '%d ڏينهن',
|
||
M : 'هڪ مهينو',
|
||
MM : '%d مهينا',
|
||
y : 'هڪ سال',
|
||
yy : '%d سال'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/,/g, '،');
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Northern Sami [se]
|
||
//! authors : Bård Rolstad Henriksen : https://github.com/karamell
|
||
|
||
|
||
hooks.defineLocale('se', {
|
||
months : 'ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu'.split('_'),
|
||
monthsShort : 'ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov'.split('_'),
|
||
weekdays : 'sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat'.split('_'),
|
||
weekdaysShort : 'sotn_vuos_maŋ_gask_duor_bear_láv'.split('_'),
|
||
weekdaysMin : 's_v_m_g_d_b_L'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'MMMM D. [b.] YYYY',
|
||
LLL : 'MMMM D. [b.] YYYY [ti.] HH:mm',
|
||
LLLL : 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[otne ti] LT',
|
||
nextDay: '[ihttin ti] LT',
|
||
nextWeek: 'dddd [ti] LT',
|
||
lastDay: '[ikte ti] LT',
|
||
lastWeek: '[ovddit] dddd [ti] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s geažes',
|
||
past : 'maŋit %s',
|
||
s : 'moadde sekunddat',
|
||
m : 'okta minuhta',
|
||
mm : '%d minuhtat',
|
||
h : 'okta diimmu',
|
||
hh : '%d diimmut',
|
||
d : 'okta beaivi',
|
||
dd : '%d beaivvit',
|
||
M : 'okta mánnu',
|
||
MM : '%d mánut',
|
||
y : 'okta jahki',
|
||
yy : '%d jagit'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Sinhalese [si]
|
||
//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
|
||
|
||
/*jshint -W100*/
|
||
hooks.defineLocale('si', {
|
||
months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'),
|
||
monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'),
|
||
weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'),
|
||
weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්රහ_සිකු_සෙන'.split('_'),
|
||
weekdaysMin : 'ඉ_ස_අ_බ_බ්ර_සි_සෙ'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'a h:mm',
|
||
LTS : 'a h:mm:ss',
|
||
L : 'YYYY/MM/DD',
|
||
LL : 'YYYY MMMM D',
|
||
LLL : 'YYYY MMMM D, a h:mm',
|
||
LLLL : 'YYYY MMMM D [වැනි] dddd, a h:mm:ss'
|
||
},
|
||
calendar : {
|
||
sameDay : '[අද] LT[ට]',
|
||
nextDay : '[හෙට] LT[ට]',
|
||
nextWeek : 'dddd LT[ට]',
|
||
lastDay : '[ඊයේ] LT[ට]',
|
||
lastWeek : '[පසුගිය] dddd LT[ට]',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%sකින්',
|
||
past : '%sකට පෙර',
|
||
s : 'තත්පර කිහිපය',
|
||
m : 'මිනිත්තුව',
|
||
mm : 'මිනිත්තු %d',
|
||
h : 'පැය',
|
||
hh : 'පැය %d',
|
||
d : 'දිනය',
|
||
dd : 'දින %d',
|
||
M : 'මාසය',
|
||
MM : 'මාස %d',
|
||
y : 'වසර',
|
||
yy : 'වසර %d'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2} වැනි/,
|
||
ordinal : function (number) {
|
||
return number + ' වැනි';
|
||
},
|
||
meridiemParse : /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,
|
||
isPM : function (input) {
|
||
return input === 'ප.ව.' || input === 'පස් වරු';
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours > 11) {
|
||
return isLower ? 'ප.ව.' : 'පස් වරු';
|
||
} else {
|
||
return isLower ? 'පෙ.ව.' : 'පෙර වරු';
|
||
}
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Slovak [sk]
|
||
//! author : Martin Minka : https://github.com/k2s
|
||
//! based on work of petrbela : https://github.com/petrbela
|
||
|
||
var months$7 = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_');
|
||
var monthsShort$5 = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');
|
||
function plural$5(n) {
|
||
return (n > 1) && (n < 5);
|
||
}
|
||
function translate$8(number, withoutSuffix, key, isFuture) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 's': // a few seconds / in a few seconds / a few seconds ago
|
||
return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';
|
||
case 'm': // a minute / in a minute / a minute ago
|
||
return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');
|
||
case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$5(number) ? 'minúty' : 'minút');
|
||
} else {
|
||
return result + 'minútami';
|
||
}
|
||
break;
|
||
case 'h': // an hour / in an hour / an hour ago
|
||
return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
|
||
case 'hh': // 9 hours / in 9 hours / 9 hours ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$5(number) ? 'hodiny' : 'hodín');
|
||
} else {
|
||
return result + 'hodinami';
|
||
}
|
||
break;
|
||
case 'd': // a day / in a day / a day ago
|
||
return (withoutSuffix || isFuture) ? 'deň' : 'dňom';
|
||
case 'dd': // 9 days / in 9 days / 9 days ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$5(number) ? 'dni' : 'dní');
|
||
} else {
|
||
return result + 'dňami';
|
||
}
|
||
break;
|
||
case 'M': // a month / in a month / a month ago
|
||
return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';
|
||
case 'MM': // 9 months / in 9 months / 9 months ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$5(number) ? 'mesiace' : 'mesiacov');
|
||
} else {
|
||
return result + 'mesiacmi';
|
||
}
|
||
break;
|
||
case 'y': // a year / in a year / a year ago
|
||
return (withoutSuffix || isFuture) ? 'rok' : 'rokom';
|
||
case 'yy': // 9 years / in 9 years / 9 years ago
|
||
if (withoutSuffix || isFuture) {
|
||
return result + (plural$5(number) ? 'roky' : 'rokov');
|
||
} else {
|
||
return result + 'rokmi';
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('sk', {
|
||
months : months$7,
|
||
monthsShort : monthsShort$5,
|
||
weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),
|
||
weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),
|
||
weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
|
||
longDateFormat : {
|
||
LT: 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY H:mm',
|
||
LLLL : 'dddd D. MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[dnes o] LT',
|
||
nextDay: '[zajtra o] LT',
|
||
nextWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[v nedeľu o] LT';
|
||
case 1:
|
||
case 2:
|
||
return '[v] dddd [o] LT';
|
||
case 3:
|
||
return '[v stredu o] LT';
|
||
case 4:
|
||
return '[vo štvrtok o] LT';
|
||
case 5:
|
||
return '[v piatok o] LT';
|
||
case 6:
|
||
return '[v sobotu o] LT';
|
||
}
|
||
},
|
||
lastDay: '[včera o] LT',
|
||
lastWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[minulú nedeľu o] LT';
|
||
case 1:
|
||
case 2:
|
||
return '[minulý] dddd [o] LT';
|
||
case 3:
|
||
return '[minulú stredu o] LT';
|
||
case 4:
|
||
case 5:
|
||
return '[minulý] dddd [o] LT';
|
||
case 6:
|
||
return '[minulú sobotu o] LT';
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : 'pred %s',
|
||
s : translate$8,
|
||
m : translate$8,
|
||
mm : translate$8,
|
||
h : translate$8,
|
||
hh : translate$8,
|
||
d : translate$8,
|
||
dd : translate$8,
|
||
M : translate$8,
|
||
MM : translate$8,
|
||
y : translate$8,
|
||
yy : translate$8
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Slovenian [sl]
|
||
//! author : Robert Sedovšek : https://github.com/sedovsek
|
||
|
||
function processRelativeTime$6(number, withoutSuffix, key, isFuture) {
|
||
var result = number + ' ';
|
||
switch (key) {
|
||
case 's':
|
||
return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami';
|
||
case 'm':
|
||
return withoutSuffix ? 'ena minuta' : 'eno minuto';
|
||
case 'mm':
|
||
if (number === 1) {
|
||
result += withoutSuffix ? 'minuta' : 'minuto';
|
||
} else if (number === 2) {
|
||
result += withoutSuffix || isFuture ? 'minuti' : 'minutama';
|
||
} else if (number < 5) {
|
||
result += withoutSuffix || isFuture ? 'minute' : 'minutami';
|
||
} else {
|
||
result += withoutSuffix || isFuture ? 'minut' : 'minutami';
|
||
}
|
||
return result;
|
||
case 'h':
|
||
return withoutSuffix ? 'ena ura' : 'eno uro';
|
||
case 'hh':
|
||
if (number === 1) {
|
||
result += withoutSuffix ? 'ura' : 'uro';
|
||
} else if (number === 2) {
|
||
result += withoutSuffix || isFuture ? 'uri' : 'urama';
|
||
} else if (number < 5) {
|
||
result += withoutSuffix || isFuture ? 'ure' : 'urami';
|
||
} else {
|
||
result += withoutSuffix || isFuture ? 'ur' : 'urami';
|
||
}
|
||
return result;
|
||
case 'd':
|
||
return withoutSuffix || isFuture ? 'en dan' : 'enim dnem';
|
||
case 'dd':
|
||
if (number === 1) {
|
||
result += withoutSuffix || isFuture ? 'dan' : 'dnem';
|
||
} else if (number === 2) {
|
||
result += withoutSuffix || isFuture ? 'dni' : 'dnevoma';
|
||
} else {
|
||
result += withoutSuffix || isFuture ? 'dni' : 'dnevi';
|
||
}
|
||
return result;
|
||
case 'M':
|
||
return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem';
|
||
case 'MM':
|
||
if (number === 1) {
|
||
result += withoutSuffix || isFuture ? 'mesec' : 'mesecem';
|
||
} else if (number === 2) {
|
||
result += withoutSuffix || isFuture ? 'meseca' : 'mesecema';
|
||
} else if (number < 5) {
|
||
result += withoutSuffix || isFuture ? 'mesece' : 'meseci';
|
||
} else {
|
||
result += withoutSuffix || isFuture ? 'mesecev' : 'meseci';
|
||
}
|
||
return result;
|
||
case 'y':
|
||
return withoutSuffix || isFuture ? 'eno leto' : 'enim letom';
|
||
case 'yy':
|
||
if (number === 1) {
|
||
result += withoutSuffix || isFuture ? 'leto' : 'letom';
|
||
} else if (number === 2) {
|
||
result += withoutSuffix || isFuture ? 'leti' : 'letoma';
|
||
} else if (number < 5) {
|
||
result += withoutSuffix || isFuture ? 'leta' : 'leti';
|
||
} else {
|
||
result += withoutSuffix || isFuture ? 'let' : 'leti';
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
|
||
hooks.defineLocale('sl', {
|
||
months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'),
|
||
monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'),
|
||
weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'),
|
||
weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM YYYY',
|
||
LLL : 'D. MMMM YYYY H:mm',
|
||
LLLL : 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[danes ob] LT',
|
||
nextDay : '[jutri ob] LT',
|
||
|
||
nextWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[v] [nedeljo] [ob] LT';
|
||
case 3:
|
||
return '[v] [sredo] [ob] LT';
|
||
case 6:
|
||
return '[v] [soboto] [ob] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[v] dddd [ob] LT';
|
||
}
|
||
},
|
||
lastDay : '[včeraj ob] LT',
|
||
lastWeek : function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[prejšnjo] [nedeljo] [ob] LT';
|
||
case 3:
|
||
return '[prejšnjo] [sredo] [ob] LT';
|
||
case 6:
|
||
return '[prejšnjo] [soboto] [ob] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[prejšnji] dddd [ob] LT';
|
||
}
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'čez %s',
|
||
past : 'pred %s',
|
||
s : processRelativeTime$6,
|
||
m : processRelativeTime$6,
|
||
mm : processRelativeTime$6,
|
||
h : processRelativeTime$6,
|
||
hh : processRelativeTime$6,
|
||
d : processRelativeTime$6,
|
||
dd : processRelativeTime$6,
|
||
M : processRelativeTime$6,
|
||
MM : processRelativeTime$6,
|
||
y : processRelativeTime$6,
|
||
yy : processRelativeTime$6
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Albanian [sq]
|
||
//! author : Flakërim Ismani : https://github.com/flakerimi
|
||
//! author : Menelion Elensúle : https://github.com/Oire
|
||
//! author : Oerd Cukalla : https://github.com/oerd
|
||
|
||
hooks.defineLocale('sq', {
|
||
months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),
|
||
monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),
|
||
weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),
|
||
weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),
|
||
weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),
|
||
weekdaysParseExact : true,
|
||
meridiemParse: /PD|MD/,
|
||
isPM: function (input) {
|
||
return input.charAt(0) === 'M';
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
return hours < 12 ? 'PD' : 'MD';
|
||
},
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Sot në] LT',
|
||
nextDay : '[Nesër në] LT',
|
||
nextWeek : 'dddd [në] LT',
|
||
lastDay : '[Dje në] LT',
|
||
lastWeek : 'dddd [e kaluar në] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'në %s',
|
||
past : '%s më parë',
|
||
s : 'disa sekonda',
|
||
m : 'një minutë',
|
||
mm : '%d minuta',
|
||
h : 'një orë',
|
||
hh : '%d orë',
|
||
d : 'një ditë',
|
||
dd : '%d ditë',
|
||
M : 'një muaj',
|
||
MM : '%d muaj',
|
||
y : 'një vit',
|
||
yy : '%d vite'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Serbian Cyrillic [sr-cyrl]
|
||
//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
|
||
|
||
var translator$1 = {
|
||
words: { //Different grammatical cases
|
||
m: ['један минут', 'једне минуте'],
|
||
mm: ['минут', 'минуте', 'минута'],
|
||
h: ['један сат', 'једног сата'],
|
||
hh: ['сат', 'сата', 'сати'],
|
||
dd: ['дан', 'дана', 'дана'],
|
||
MM: ['месец', 'месеца', 'месеци'],
|
||
yy: ['година', 'године', 'година']
|
||
},
|
||
correctGrammaticalCase: function (number, wordKey) {
|
||
return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
|
||
},
|
||
translate: function (number, withoutSuffix, key) {
|
||
var wordKey = translator$1.words[key];
|
||
if (key.length === 1) {
|
||
return withoutSuffix ? wordKey[0] : wordKey[1];
|
||
} else {
|
||
return number + ' ' + translator$1.correctGrammaticalCase(number, wordKey);
|
||
}
|
||
}
|
||
};
|
||
|
||
hooks.defineLocale('sr-cyrl', {
|
||
months: 'јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар'.split('_'),
|
||
monthsShort: 'јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays: 'недеља_понедељак_уторак_среда_четвртак_петак_субота'.split('_'),
|
||
weekdaysShort: 'нед._пон._уто._сре._чет._пет._суб.'.split('_'),
|
||
weekdaysMin: 'не_по_ут_ср_че_пе_су'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat: {
|
||
LT: 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L: 'DD.MM.YYYY',
|
||
LL: 'D. MMMM YYYY',
|
||
LLL: 'D. MMMM YYYY H:mm',
|
||
LLLL: 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[данас у] LT',
|
||
nextDay: '[сутра у] LT',
|
||
nextWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[у] [недељу] [у] LT';
|
||
case 3:
|
||
return '[у] [среду] [у] LT';
|
||
case 6:
|
||
return '[у] [суботу] [у] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[у] dddd [у] LT';
|
||
}
|
||
},
|
||
lastDay : '[јуче у] LT',
|
||
lastWeek : function () {
|
||
var lastWeekDays = [
|
||
'[прошле] [недеље] [у] LT',
|
||
'[прошлог] [понедељка] [у] LT',
|
||
'[прошлог] [уторка] [у] LT',
|
||
'[прошле] [среде] [у] LT',
|
||
'[прошлог] [четвртка] [у] LT',
|
||
'[прошлог] [петка] [у] LT',
|
||
'[прошле] [суботе] [у] LT'
|
||
];
|
||
return lastWeekDays[this.day()];
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'за %s',
|
||
past : 'пре %s',
|
||
s : 'неколико секунди',
|
||
m : translator$1.translate,
|
||
mm : translator$1.translate,
|
||
h : translator$1.translate,
|
||
hh : translator$1.translate,
|
||
d : 'дан',
|
||
dd : translator$1.translate,
|
||
M : 'месец',
|
||
MM : translator$1.translate,
|
||
y : 'годину',
|
||
yy : translator$1.translate
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Serbian [sr]
|
||
//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
|
||
|
||
var translator$2 = {
|
||
words: { //Different grammatical cases
|
||
m: ['jedan minut', 'jedne minute'],
|
||
mm: ['minut', 'minute', 'minuta'],
|
||
h: ['jedan sat', 'jednog sata'],
|
||
hh: ['sat', 'sata', 'sati'],
|
||
dd: ['dan', 'dana', 'dana'],
|
||
MM: ['mesec', 'meseca', 'meseci'],
|
||
yy: ['godina', 'godine', 'godina']
|
||
},
|
||
correctGrammaticalCase: function (number, wordKey) {
|
||
return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
|
||
},
|
||
translate: function (number, withoutSuffix, key) {
|
||
var wordKey = translator$2.words[key];
|
||
if (key.length === 1) {
|
||
return withoutSuffix ? wordKey[0] : wordKey[1];
|
||
} else {
|
||
return number + ' ' + translator$2.correctGrammaticalCase(number, wordKey);
|
||
}
|
||
}
|
||
};
|
||
|
||
hooks.defineLocale('sr', {
|
||
months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
|
||
monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays: 'nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota'.split('_'),
|
||
weekdaysShort: 'ned._pon._uto._sre._čet._pet._sub.'.split('_'),
|
||
weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat: {
|
||
LT: 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L: 'DD.MM.YYYY',
|
||
LL: 'D. MMMM YYYY',
|
||
LLL: 'D. MMMM YYYY H:mm',
|
||
LLLL: 'dddd, D. MMMM YYYY H:mm'
|
||
},
|
||
calendar: {
|
||
sameDay: '[danas u] LT',
|
||
nextDay: '[sutra u] LT',
|
||
nextWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
return '[u] [nedelju] [u] LT';
|
||
case 3:
|
||
return '[u] [sredu] [u] LT';
|
||
case 6:
|
||
return '[u] [subotu] [u] LT';
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
case 5:
|
||
return '[u] dddd [u] LT';
|
||
}
|
||
},
|
||
lastDay : '[juče u] LT',
|
||
lastWeek : function () {
|
||
var lastWeekDays = [
|
||
'[prošle] [nedelje] [u] LT',
|
||
'[prošlog] [ponedeljka] [u] LT',
|
||
'[prošlog] [utorka] [u] LT',
|
||
'[prošle] [srede] [u] LT',
|
||
'[prošlog] [četvrtka] [u] LT',
|
||
'[prošlog] [petka] [u] LT',
|
||
'[prošle] [subote] [u] LT'
|
||
];
|
||
return lastWeekDays[this.day()];
|
||
},
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'za %s',
|
||
past : 'pre %s',
|
||
s : 'nekoliko sekundi',
|
||
m : translator$2.translate,
|
||
mm : translator$2.translate,
|
||
h : translator$2.translate,
|
||
hh : translator$2.translate,
|
||
d : 'dan',
|
||
dd : translator$2.translate,
|
||
M : 'mesec',
|
||
MM : translator$2.translate,
|
||
y : 'godinu',
|
||
yy : translator$2.translate
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : siSwati [ss]
|
||
//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
|
||
|
||
|
||
hooks.defineLocale('ss', {
|
||
months : "Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split('_'),
|
||
monthsShort : 'Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo'.split('_'),
|
||
weekdays : 'Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo'.split('_'),
|
||
weekdaysShort : 'Lis_Umb_Lsb_Les_Lsi_Lsh_Umg'.split('_'),
|
||
weekdaysMin : 'Li_Us_Lb_Lt_Ls_Lh_Ug'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY h:mm A',
|
||
LLLL : 'dddd, D MMMM YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Namuhla nga] LT',
|
||
nextDay : '[Kusasa nga] LT',
|
||
nextWeek : 'dddd [nga] LT',
|
||
lastDay : '[Itolo nga] LT',
|
||
lastWeek : 'dddd [leliphelile] [nga] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'nga %s',
|
||
past : 'wenteka nga %s',
|
||
s : 'emizuzwana lomcane',
|
||
m : 'umzuzu',
|
||
mm : '%d emizuzu',
|
||
h : 'lihora',
|
||
hh : '%d emahora',
|
||
d : 'lilanga',
|
||
dd : '%d emalanga',
|
||
M : 'inyanga',
|
||
MM : '%d tinyanga',
|
||
y : 'umnyaka',
|
||
yy : '%d iminyaka'
|
||
},
|
||
meridiemParse: /ekuseni|emini|entsambama|ebusuku/,
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 11) {
|
||
return 'ekuseni';
|
||
} else if (hours < 15) {
|
||
return 'emini';
|
||
} else if (hours < 19) {
|
||
return 'entsambama';
|
||
} else {
|
||
return 'ebusuku';
|
||
}
|
||
},
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'ekuseni') {
|
||
return hour;
|
||
} else if (meridiem === 'emini') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === 'entsambama' || meridiem === 'ebusuku') {
|
||
if (hour === 0) {
|
||
return 0;
|
||
}
|
||
return hour + 12;
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}/,
|
||
ordinal : '%d',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Swedish [sv]
|
||
//! author : Jens Alm : https://github.com/ulmus
|
||
|
||
hooks.defineLocale('sv', {
|
||
months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),
|
||
monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
|
||
weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),
|
||
weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'),
|
||
weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY-MM-DD',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY [kl.] HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY [kl.] HH:mm',
|
||
lll : 'D MMM YYYY HH:mm',
|
||
llll : 'ddd D MMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Idag] LT',
|
||
nextDay: '[Imorgon] LT',
|
||
lastDay: '[Igår] LT',
|
||
nextWeek: '[På] dddd LT',
|
||
lastWeek: '[I] dddd[s] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'om %s',
|
||
past : 'för %s sedan',
|
||
s : 'några sekunder',
|
||
m : 'en minut',
|
||
mm : '%d minuter',
|
||
h : 'en timme',
|
||
hh : '%d timmar',
|
||
d : 'en dag',
|
||
dd : '%d dagar',
|
||
M : 'en månad',
|
||
MM : '%d månader',
|
||
y : 'ett år',
|
||
yy : '%d år'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(e|a)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'e' :
|
||
(b === 1) ? 'a' :
|
||
(b === 2) ? 'a' :
|
||
(b === 3) ? 'e' : 'e';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Swahili [sw]
|
||
//! author : Fahad Kassim : https://github.com/fadsel
|
||
|
||
hooks.defineLocale('sw', {
|
||
months : 'Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba'.split('_'),
|
||
monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des'.split('_'),
|
||
weekdays : 'Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi'.split('_'),
|
||
weekdaysShort : 'Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos'.split('_'),
|
||
weekdaysMin : 'J2_J3_J4_J5_Al_Ij_J1'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[leo saa] LT',
|
||
nextDay : '[kesho saa] LT',
|
||
nextWeek : '[wiki ijayo] dddd [saat] LT',
|
||
lastDay : '[jana] LT',
|
||
lastWeek : '[wiki iliyopita] dddd [saat] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s baadaye',
|
||
past : 'tokea %s',
|
||
s : 'hivi punde',
|
||
m : 'dakika moja',
|
||
mm : 'dakika %d',
|
||
h : 'saa limoja',
|
||
hh : 'masaa %d',
|
||
d : 'siku moja',
|
||
dd : 'masiku %d',
|
||
M : 'mwezi mmoja',
|
||
MM : 'miezi %d',
|
||
y : 'mwaka mmoja',
|
||
yy : 'miaka %d'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Tamil [ta]
|
||
//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
|
||
|
||
var symbolMap$13 = {
|
||
'1': '௧',
|
||
'2': '௨',
|
||
'3': '௩',
|
||
'4': '௪',
|
||
'5': '௫',
|
||
'6': '௬',
|
||
'7': '௭',
|
||
'8': '௮',
|
||
'9': '௯',
|
||
'0': '௦'
|
||
};
|
||
var numberMap$12 = {
|
||
'௧': '1',
|
||
'௨': '2',
|
||
'௩': '3',
|
||
'௪': '4',
|
||
'௫': '5',
|
||
'௬': '6',
|
||
'௭': '7',
|
||
'௮': '8',
|
||
'௯': '9',
|
||
'௦': '0'
|
||
};
|
||
|
||
hooks.defineLocale('ta', {
|
||
months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
|
||
monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
|
||
weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'),
|
||
weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'),
|
||
weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY, HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[இன்று] LT',
|
||
nextDay : '[நாளை] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[நேற்று] LT',
|
||
lastWeek : '[கடந்த வாரம்] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s இல்',
|
||
past : '%s முன்',
|
||
s : 'ஒரு சில விநாடிகள்',
|
||
m : 'ஒரு நிமிடம்',
|
||
mm : '%d நிமிடங்கள்',
|
||
h : 'ஒரு மணி நேரம்',
|
||
hh : '%d மணி நேரம்',
|
||
d : 'ஒரு நாள்',
|
||
dd : '%d நாட்கள்',
|
||
M : 'ஒரு மாதம்',
|
||
MM : '%d மாதங்கள்',
|
||
y : 'ஒரு வருடம்',
|
||
yy : '%d ஆண்டுகள்'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}வது/,
|
||
ordinal : function (number) {
|
||
return number + 'வது';
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) {
|
||
return numberMap$12[match];
|
||
});
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/\d/g, function (match) {
|
||
return symbolMap$13[match];
|
||
});
|
||
},
|
||
// refer http://ta.wikipedia.org/s/1er1
|
||
meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 2) {
|
||
return ' யாமம்';
|
||
} else if (hour < 6) {
|
||
return ' வைகறை'; // வைகறை
|
||
} else if (hour < 10) {
|
||
return ' காலை'; // காலை
|
||
} else if (hour < 14) {
|
||
return ' நண்பகல்'; // நண்பகல்
|
||
} else if (hour < 18) {
|
||
return ' எற்பாடு'; // எற்பாடு
|
||
} else if (hour < 22) {
|
||
return ' மாலை'; // மாலை
|
||
} else {
|
||
return ' யாமம்';
|
||
}
|
||
},
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'யாமம்') {
|
||
return hour < 2 ? hour : hour + 12;
|
||
} else if (meridiem === 'வைகறை' || meridiem === 'காலை') {
|
||
return hour;
|
||
} else if (meridiem === 'நண்பகல்') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Telugu [te]
|
||
//! author : Krishna Chaitanya Thota : https://github.com/kcthota
|
||
|
||
hooks.defineLocale('te', {
|
||
months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'),
|
||
monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split('_'),
|
||
weekdaysShort : 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'),
|
||
weekdaysMin : 'ఆ_సో_మం_బు_గు_శు_శ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'A h:mm',
|
||
LTS : 'A h:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY, A h:mm',
|
||
LLLL : 'dddd, D MMMM YYYY, A h:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[నేడు] LT',
|
||
nextDay : '[రేపు] LT',
|
||
nextWeek : 'dddd, LT',
|
||
lastDay : '[నిన్న] LT',
|
||
lastWeek : '[గత] dddd, LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s లో',
|
||
past : '%s క్రితం',
|
||
s : 'కొన్ని క్షణాలు',
|
||
m : 'ఒక నిమిషం',
|
||
mm : '%d నిమిషాలు',
|
||
h : 'ఒక గంట',
|
||
hh : '%d గంటలు',
|
||
d : 'ఒక రోజు',
|
||
dd : '%d రోజులు',
|
||
M : 'ఒక నెల',
|
||
MM : '%d నెలలు',
|
||
y : 'ఒక సంవత్సరం',
|
||
yy : '%d సంవత్సరాలు'
|
||
},
|
||
dayOfMonthOrdinalParse : /\d{1,2}వ/,
|
||
ordinal : '%dవ',
|
||
meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === 'రాత్రి') {
|
||
return hour < 4 ? hour : hour + 12;
|
||
} else if (meridiem === 'ఉదయం') {
|
||
return hour;
|
||
} else if (meridiem === 'మధ్యాహ్నం') {
|
||
return hour >= 10 ? hour : hour + 12;
|
||
} else if (meridiem === 'సాయంత్రం') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'రాత్రి';
|
||
} else if (hour < 10) {
|
||
return 'ఉదయం';
|
||
} else if (hour < 17) {
|
||
return 'మధ్యాహ్నం';
|
||
} else if (hour < 20) {
|
||
return 'సాయంత్రం';
|
||
} else {
|
||
return 'రాత్రి';
|
||
}
|
||
},
|
||
week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Tetun Dili (East Timor) [tet]
|
||
//! author : Joshua Brooks : https://github.com/joshbrooks
|
||
//! author : Onorio De J. Afonso : https://github.com/marobo
|
||
|
||
hooks.defineLocale('tet', {
|
||
months : 'Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru'.split('_'),
|
||
monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez'.split('_'),
|
||
weekdays : 'Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu'.split('_'),
|
||
weekdaysShort : 'Dom_Seg_Ters_Kua_Kint_Sext_Sab'.split('_'),
|
||
weekdaysMin : 'Do_Seg_Te_Ku_Ki_Sex_Sa'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Ohin iha] LT',
|
||
nextDay: '[Aban iha] LT',
|
||
nextWeek: 'dddd [iha] LT',
|
||
lastDay: '[Horiseik iha] LT',
|
||
lastWeek: 'dddd [semana kotuk] [iha] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'iha %s',
|
||
past : '%s liuba',
|
||
s : 'minutu balun',
|
||
m : 'minutu ida',
|
||
mm : 'minutus %d',
|
||
h : 'horas ida',
|
||
hh : 'horas %d',
|
||
d : 'loron ida',
|
||
dd : 'loron %d',
|
||
M : 'fulan ida',
|
||
MM : 'fulan %d',
|
||
y : 'tinan ida',
|
||
yy : 'tinan %d'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Thai [th]
|
||
//! author : Kridsada Thanabulpong : https://github.com/sirn
|
||
|
||
hooks.defineLocale('th', {
|
||
months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'),
|
||
monthsShort : 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split('_'),
|
||
monthsParseExact: true,
|
||
weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'),
|
||
weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference
|
||
weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'H:mm',
|
||
LTS : 'H:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY เวลา H:mm',
|
||
LLLL : 'วันddddที่ D MMMM YYYY เวลา H:mm'
|
||
},
|
||
meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/,
|
||
isPM: function (input) {
|
||
return input === 'หลังเที่ยง';
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'ก่อนเที่ยง';
|
||
} else {
|
||
return 'หลังเที่ยง';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[วันนี้ เวลา] LT',
|
||
nextDay : '[พรุ่งนี้ เวลา] LT',
|
||
nextWeek : 'dddd[หน้า เวลา] LT',
|
||
lastDay : '[เมื่อวานนี้ เวลา] LT',
|
||
lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'อีก %s',
|
||
past : '%sที่แล้ว',
|
||
s : 'ไม่กี่วินาที',
|
||
m : '1 นาที',
|
||
mm : '%d นาที',
|
||
h : '1 ชั่วโมง',
|
||
hh : '%d ชั่วโมง',
|
||
d : '1 วัน',
|
||
dd : '%d วัน',
|
||
M : '1 เดือน',
|
||
MM : '%d เดือน',
|
||
y : '1 ปี',
|
||
yy : '%d ปี'
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Tagalog (Philippines) [tl-ph]
|
||
//! author : Dan Hagman : https://github.com/hagmandan
|
||
|
||
hooks.defineLocale('tl-ph', {
|
||
months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'),
|
||
monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'),
|
||
weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'),
|
||
weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'),
|
||
weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'MM/D/YYYY',
|
||
LL : 'MMMM D, YYYY',
|
||
LLL : 'MMMM D, YYYY HH:mm',
|
||
LLLL : 'dddd, MMMM DD, YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: 'LT [ngayong araw]',
|
||
nextDay: '[Bukas ng] LT',
|
||
nextWeek: 'LT [sa susunod na] dddd',
|
||
lastDay: 'LT [kahapon]',
|
||
lastWeek: 'LT [noong nakaraang] dddd',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'sa loob ng %s',
|
||
past : '%s ang nakalipas',
|
||
s : 'ilang segundo',
|
||
m : 'isang minuto',
|
||
mm : '%d minuto',
|
||
h : 'isang oras',
|
||
hh : '%d oras',
|
||
d : 'isang araw',
|
||
dd : '%d araw',
|
||
M : 'isang buwan',
|
||
MM : '%d buwan',
|
||
y : 'isang taon',
|
||
yy : '%d taon'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}/,
|
||
ordinal : function (number) {
|
||
return number;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Klingon [tlh]
|
||
//! author : Dominika Kruk : https://github.com/amaranthrose
|
||
|
||
var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_');
|
||
|
||
function translateFuture(output) {
|
||
var time = output;
|
||
time = (output.indexOf('jaj') !== -1) ?
|
||
time.slice(0, -3) + 'leS' :
|
||
(output.indexOf('jar') !== -1) ?
|
||
time.slice(0, -3) + 'waQ' :
|
||
(output.indexOf('DIS') !== -1) ?
|
||
time.slice(0, -3) + 'nem' :
|
||
time + ' pIq';
|
||
return time;
|
||
}
|
||
|
||
function translatePast(output) {
|
||
var time = output;
|
||
time = (output.indexOf('jaj') !== -1) ?
|
||
time.slice(0, -3) + 'Hu’' :
|
||
(output.indexOf('jar') !== -1) ?
|
||
time.slice(0, -3) + 'wen' :
|
||
(output.indexOf('DIS') !== -1) ?
|
||
time.slice(0, -3) + 'ben' :
|
||
time + ' ret';
|
||
return time;
|
||
}
|
||
|
||
function translate$9(number, withoutSuffix, string, isFuture) {
|
||
var numberNoun = numberAsNoun(number);
|
||
switch (string) {
|
||
case 'mm':
|
||
return numberNoun + ' tup';
|
||
case 'hh':
|
||
return numberNoun + ' rep';
|
||
case 'dd':
|
||
return numberNoun + ' jaj';
|
||
case 'MM':
|
||
return numberNoun + ' jar';
|
||
case 'yy':
|
||
return numberNoun + ' DIS';
|
||
}
|
||
}
|
||
|
||
function numberAsNoun(number) {
|
||
var hundred = Math.floor((number % 1000) / 100),
|
||
ten = Math.floor((number % 100) / 10),
|
||
one = number % 10,
|
||
word = '';
|
||
if (hundred > 0) {
|
||
word += numbersNouns[hundred] + 'vatlh';
|
||
}
|
||
if (ten > 0) {
|
||
word += ((word !== '') ? ' ' : '') + numbersNouns[ten] + 'maH';
|
||
}
|
||
if (one > 0) {
|
||
word += ((word !== '') ? ' ' : '') + numbersNouns[one];
|
||
}
|
||
return (word === '') ? 'pagh' : word;
|
||
}
|
||
|
||
hooks.defineLocale('tlh', {
|
||
months : 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split('_'),
|
||
monthsShort : 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
|
||
weekdaysShort : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
|
||
weekdaysMin : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[DaHjaj] LT',
|
||
nextDay: '[wa’leS] LT',
|
||
nextWeek: 'LLL',
|
||
lastDay: '[wa’Hu’] LT',
|
||
lastWeek: 'LLL',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : translateFuture,
|
||
past : translatePast,
|
||
s : 'puS lup',
|
||
m : 'wa’ tup',
|
||
mm : translate$9,
|
||
h : 'wa’ rep',
|
||
hh : translate$9,
|
||
d : 'wa’ jaj',
|
||
dd : translate$9,
|
||
M : 'wa’ jar',
|
||
MM : translate$9,
|
||
y : 'wa’ DIS',
|
||
yy : translate$9
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Turkish [tr]
|
||
//! authors : Erhan Gundogan : https://github.com/erhangundogan,
|
||
//! Burak Yiğit Kaya: https://github.com/BYK
|
||
|
||
var suffixes$3 = {
|
||
1: '\'inci',
|
||
5: '\'inci',
|
||
8: '\'inci',
|
||
70: '\'inci',
|
||
80: '\'inci',
|
||
2: '\'nci',
|
||
7: '\'nci',
|
||
20: '\'nci',
|
||
50: '\'nci',
|
||
3: '\'üncü',
|
||
4: '\'üncü',
|
||
100: '\'üncü',
|
||
6: '\'ncı',
|
||
9: '\'uncu',
|
||
10: '\'uncu',
|
||
30: '\'uncu',
|
||
60: '\'ıncı',
|
||
90: '\'ıncı'
|
||
};
|
||
|
||
hooks.defineLocale('tr', {
|
||
months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),
|
||
monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'),
|
||
weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),
|
||
weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),
|
||
weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[bugün saat] LT',
|
||
nextDay : '[yarın saat] LT',
|
||
nextWeek : '[gelecek] dddd [saat] LT',
|
||
lastDay : '[dün] LT',
|
||
lastWeek : '[geçen] dddd [saat] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s sonra',
|
||
past : '%s önce',
|
||
s : 'birkaç saniye',
|
||
m : 'bir dakika',
|
||
mm : '%d dakika',
|
||
h : 'bir saat',
|
||
hh : '%d saat',
|
||
d : 'bir gün',
|
||
dd : '%d gün',
|
||
M : 'bir ay',
|
||
MM : '%d ay',
|
||
y : 'bir yıl',
|
||
yy : '%d yıl'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,
|
||
ordinal : function (number) {
|
||
if (number === 0) { // special case for zero
|
||
return number + '\'ıncı';
|
||
}
|
||
var a = number % 10,
|
||
b = number % 100 - a,
|
||
c = number >= 100 ? 100 : null;
|
||
return number + (suffixes$3[a] || suffixes$3[b] || suffixes$3[c]);
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Talossan [tzl]
|
||
//! author : Robin van der Vliet : https://github.com/robin0van0der0v
|
||
//! author : Iustì Canun
|
||
|
||
// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
|
||
// This is currently too difficult (maybe even impossible) to add.
|
||
hooks.defineLocale('tzl', {
|
||
months : 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split('_'),
|
||
monthsShort : 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'),
|
||
weekdays : 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'),
|
||
weekdaysShort : 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'),
|
||
weekdaysMin : 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH.mm',
|
||
LTS : 'HH.mm.ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D. MMMM [dallas] YYYY',
|
||
LLL : 'D. MMMM [dallas] YYYY HH.mm',
|
||
LLLL : 'dddd, [li] D. MMMM [dallas] YYYY HH.mm'
|
||
},
|
||
meridiemParse: /d\'o|d\'a/i,
|
||
isPM : function (input) {
|
||
return 'd\'o' === input.toLowerCase();
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours > 11) {
|
||
return isLower ? 'd\'o' : 'D\'O';
|
||
} else {
|
||
return isLower ? 'd\'a' : 'D\'A';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[oxhi à] LT',
|
||
nextDay : '[demà à] LT',
|
||
nextWeek : 'dddd [à] LT',
|
||
lastDay : '[ieiri à] LT',
|
||
lastWeek : '[sür el] dddd [lasteu à] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'osprei %s',
|
||
past : 'ja%s',
|
||
s : processRelativeTime$7,
|
||
m : processRelativeTime$7,
|
||
mm : processRelativeTime$7,
|
||
h : processRelativeTime$7,
|
||
hh : processRelativeTime$7,
|
||
d : processRelativeTime$7,
|
||
dd : processRelativeTime$7,
|
||
M : processRelativeTime$7,
|
||
MM : processRelativeTime$7,
|
||
y : processRelativeTime$7,
|
||
yy : processRelativeTime$7
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||
ordinal : '%d.',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
function processRelativeTime$7(number, withoutSuffix, key, isFuture) {
|
||
var format = {
|
||
's': ['viensas secunds', '\'iensas secunds'],
|
||
'm': ['\'n míut', '\'iens míut'],
|
||
'mm': [number + ' míuts', '' + number + ' míuts'],
|
||
'h': ['\'n þora', '\'iensa þora'],
|
||
'hh': [number + ' þoras', '' + number + ' þoras'],
|
||
'd': ['\'n ziua', '\'iensa ziua'],
|
||
'dd': [number + ' ziuas', '' + number + ' ziuas'],
|
||
'M': ['\'n mes', '\'iens mes'],
|
||
'MM': [number + ' mesen', '' + number + ' mesen'],
|
||
'y': ['\'n ar', '\'iens ar'],
|
||
'yy': [number + ' ars', '' + number + ' ars']
|
||
};
|
||
return isFuture ? format[key][0] : (withoutSuffix ? format[key][0] : format[key][1]);
|
||
}
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Central Atlas Tamazight Latin [tzm-latn]
|
||
//! author : Abdel Said : https://github.com/abdelsaid
|
||
|
||
hooks.defineLocale('tzm-latn', {
|
||
months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
|
||
monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
|
||
weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
|
||
weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
|
||
weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[asdkh g] LT',
|
||
nextDay: '[aska g] LT',
|
||
nextWeek: 'dddd [g] LT',
|
||
lastDay: '[assant g] LT',
|
||
lastWeek: 'dddd [g] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'dadkh s yan %s',
|
||
past : 'yan %s',
|
||
s : 'imik',
|
||
m : 'minuḍ',
|
||
mm : '%d minuḍ',
|
||
h : 'saɛa',
|
||
hh : '%d tassaɛin',
|
||
d : 'ass',
|
||
dd : '%d ossan',
|
||
M : 'ayowr',
|
||
MM : '%d iyyirn',
|
||
y : 'asgas',
|
||
yy : '%d isgasn'
|
||
},
|
||
week : {
|
||
dow : 6, // Saturday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Central Atlas Tamazight [tzm]
|
||
//! author : Abdel Said : https://github.com/abdelsaid
|
||
|
||
hooks.defineLocale('tzm', {
|
||
months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
|
||
monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
|
||
weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
|
||
weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
|
||
weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS: 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[ⴰⵙⴷⵅ ⴴ] LT',
|
||
nextDay: '[ⴰⵙⴽⴰ ⴴ] LT',
|
||
nextWeek: 'dddd [ⴴ] LT',
|
||
lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT',
|
||
lastWeek: 'dddd [ⴴ] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s',
|
||
past : 'ⵢⴰⵏ %s',
|
||
s : 'ⵉⵎⵉⴽ',
|
||
m : 'ⵎⵉⵏⵓⴺ',
|
||
mm : '%d ⵎⵉⵏⵓⴺ',
|
||
h : 'ⵙⴰⵄⴰ',
|
||
hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ',
|
||
d : 'ⴰⵙⵙ',
|
||
dd : '%d oⵙⵙⴰⵏ',
|
||
M : 'ⴰⵢoⵓⵔ',
|
||
MM : '%d ⵉⵢⵢⵉⵔⵏ',
|
||
y : 'ⴰⵙⴳⴰⵙ',
|
||
yy : '%d ⵉⵙⴳⴰⵙⵏ'
|
||
},
|
||
week : {
|
||
dow : 6, // Saturday is the first day of the week.
|
||
doy : 12 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Ukrainian [uk]
|
||
//! author : zemlanin : https://github.com/zemlanin
|
||
//! Author : Menelion Elensúle : https://github.com/Oire
|
||
|
||
function plural$6(word, num) {
|
||
var forms = word.split('_');
|
||
return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
|
||
}
|
||
function relativeTimeWithPlural$4(number, withoutSuffix, key) {
|
||
var format = {
|
||
'mm': withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
|
||
'hh': withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
|
||
'dd': 'день_дні_днів',
|
||
'MM': 'місяць_місяці_місяців',
|
||
'yy': 'рік_роки_років'
|
||
};
|
||
if (key === 'm') {
|
||
return withoutSuffix ? 'хвилина' : 'хвилину';
|
||
}
|
||
else if (key === 'h') {
|
||
return withoutSuffix ? 'година' : 'годину';
|
||
}
|
||
else {
|
||
return number + ' ' + plural$6(format[key], +number);
|
||
}
|
||
}
|
||
function weekdaysCaseReplace(m, format) {
|
||
var weekdays = {
|
||
'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
|
||
'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'),
|
||
'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_')
|
||
};
|
||
|
||
if (!m) {
|
||
return weekdays['nominative'];
|
||
}
|
||
|
||
var nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ?
|
||
'accusative' :
|
||
((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ?
|
||
'genitive' :
|
||
'nominative');
|
||
return weekdays[nounCase][m.day()];
|
||
}
|
||
function processHoursFunction(str) {
|
||
return function () {
|
||
return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT';
|
||
};
|
||
}
|
||
|
||
hooks.defineLocale('uk', {
|
||
months : {
|
||
'format': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_'),
|
||
'standalone': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_')
|
||
},
|
||
monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
|
||
weekdays : weekdaysCaseReplace,
|
||
weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
|
||
weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD.MM.YYYY',
|
||
LL : 'D MMMM YYYY р.',
|
||
LLL : 'D MMMM YYYY р., HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY р., HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: processHoursFunction('[Сьогодні '),
|
||
nextDay: processHoursFunction('[Завтра '),
|
||
lastDay: processHoursFunction('[Вчора '),
|
||
nextWeek: processHoursFunction('[У] dddd ['),
|
||
lastWeek: function () {
|
||
switch (this.day()) {
|
||
case 0:
|
||
case 3:
|
||
case 5:
|
||
case 6:
|
||
return processHoursFunction('[Минулої] dddd [').call(this);
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
return processHoursFunction('[Минулого] dddd [').call(this);
|
||
}
|
||
},
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'за %s',
|
||
past : '%s тому',
|
||
s : 'декілька секунд',
|
||
m : relativeTimeWithPlural$4,
|
||
mm : relativeTimeWithPlural$4,
|
||
h : 'годину',
|
||
hh : relativeTimeWithPlural$4,
|
||
d : 'день',
|
||
dd : relativeTimeWithPlural$4,
|
||
M : 'місяць',
|
||
MM : relativeTimeWithPlural$4,
|
||
y : 'рік',
|
||
yy : relativeTimeWithPlural$4
|
||
},
|
||
// M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
|
||
meridiemParse: /ночі|ранку|дня|вечора/,
|
||
isPM: function (input) {
|
||
return /^(дня|вечора)$/.test(input);
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 4) {
|
||
return 'ночі';
|
||
} else if (hour < 12) {
|
||
return 'ранку';
|
||
} else if (hour < 17) {
|
||
return 'дня';
|
||
} else {
|
||
return 'вечора';
|
||
}
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}-(й|го)/,
|
||
ordinal: function (number, period) {
|
||
switch (period) {
|
||
case 'M':
|
||
case 'd':
|
||
case 'DDD':
|
||
case 'w':
|
||
case 'W':
|
||
return number + '-й';
|
||
case 'D':
|
||
return number + '-го';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Urdu [ur]
|
||
//! author : Sawood Alam : https://github.com/ibnesayeed
|
||
//! author : Zack : https://github.com/ZackVision
|
||
|
||
var months$8 = [
|
||
'جنوری',
|
||
'فروری',
|
||
'مارچ',
|
||
'اپریل',
|
||
'مئی',
|
||
'جون',
|
||
'جولائی',
|
||
'اگست',
|
||
'ستمبر',
|
||
'اکتوبر',
|
||
'نومبر',
|
||
'دسمبر'
|
||
];
|
||
var days$2 = [
|
||
'اتوار',
|
||
'پیر',
|
||
'منگل',
|
||
'بدھ',
|
||
'جمعرات',
|
||
'جمعہ',
|
||
'ہفتہ'
|
||
];
|
||
|
||
hooks.defineLocale('ur', {
|
||
months : months$8,
|
||
monthsShort : months$8,
|
||
weekdays : days$2,
|
||
weekdaysShort : days$2,
|
||
weekdaysMin : days$2,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd، D MMMM YYYY HH:mm'
|
||
},
|
||
meridiemParse: /صبح|شام/,
|
||
isPM : function (input) {
|
||
return 'شام' === input;
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
if (hour < 12) {
|
||
return 'صبح';
|
||
}
|
||
return 'شام';
|
||
},
|
||
calendar : {
|
||
sameDay : '[آج بوقت] LT',
|
||
nextDay : '[کل بوقت] LT',
|
||
nextWeek : 'dddd [بوقت] LT',
|
||
lastDay : '[گذشتہ روز بوقت] LT',
|
||
lastWeek : '[گذشتہ] dddd [بوقت] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s بعد',
|
||
past : '%s قبل',
|
||
s : 'چند سیکنڈ',
|
||
m : 'ایک منٹ',
|
||
mm : '%d منٹ',
|
||
h : 'ایک گھنٹہ',
|
||
hh : '%d گھنٹے',
|
||
d : 'ایک دن',
|
||
dd : '%d دن',
|
||
M : 'ایک ماہ',
|
||
MM : '%d ماہ',
|
||
y : 'ایک سال',
|
||
yy : '%d سال'
|
||
},
|
||
preparse: function (string) {
|
||
return string.replace(/،/g, ',');
|
||
},
|
||
postformat: function (string) {
|
||
return string.replace(/,/g, '،');
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Uzbek Latin [uz-latn]
|
||
//! author : Rasulbek Mirzayev : github.com/Rasulbeeek
|
||
|
||
hooks.defineLocale('uz-latn', {
|
||
months : 'Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr'.split('_'),
|
||
monthsShort : 'Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek'.split('_'),
|
||
weekdays : 'Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba'.split('_'),
|
||
weekdaysShort : 'Yak_Dush_Sesh_Chor_Pay_Jum_Shan'.split('_'),
|
||
weekdaysMin : 'Ya_Du_Se_Cho_Pa_Ju_Sha'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'D MMMM YYYY, dddd HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Bugun soat] LT [da]',
|
||
nextDay : '[Ertaga] LT [da]',
|
||
nextWeek : 'dddd [kuni soat] LT [da]',
|
||
lastDay : '[Kecha soat] LT [da]',
|
||
lastWeek : '[O\'tgan] dddd [kuni soat] LT [da]',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'Yaqin %s ichida',
|
||
past : 'Bir necha %s oldin',
|
||
s : 'soniya',
|
||
m : 'bir daqiqa',
|
||
mm : '%d daqiqa',
|
||
h : 'bir soat',
|
||
hh : '%d soat',
|
||
d : 'bir kun',
|
||
dd : '%d kun',
|
||
M : 'bir oy',
|
||
MM : '%d oy',
|
||
y : 'bir yil',
|
||
yy : '%d yil'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 1st is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Uzbek [uz]
|
||
//! author : Sardor Muminov : https://github.com/muminoff
|
||
|
||
hooks.defineLocale('uz', {
|
||
months : 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split('_'),
|
||
monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'),
|
||
weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'),
|
||
weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'),
|
||
weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'D MMMM YYYY, dddd HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Бугун соат] LT [да]',
|
||
nextDay : '[Эртага] LT [да]',
|
||
nextWeek : 'dddd [куни соат] LT [да]',
|
||
lastDay : '[Кеча соат] LT [да]',
|
||
lastWeek : '[Утган] dddd [куни соат] LT [да]',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'Якин %s ичида',
|
||
past : 'Бир неча %s олдин',
|
||
s : 'фурсат',
|
||
m : 'бир дакика',
|
||
mm : '%d дакика',
|
||
h : 'бир соат',
|
||
hh : '%d соат',
|
||
d : 'бир кун',
|
||
dd : '%d кун',
|
||
M : 'бир ой',
|
||
MM : '%d ой',
|
||
y : 'бир йил',
|
||
yy : '%d йил'
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 7 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Vietnamese [vi]
|
||
//! author : Bang Nguyen : https://github.com/bangnk
|
||
|
||
hooks.defineLocale('vi', {
|
||
months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'),
|
||
monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'),
|
||
weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
|
||
weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
|
||
weekdaysParseExact : true,
|
||
meridiemParse: /sa|ch/i,
|
||
isPM : function (input) {
|
||
return /^ch$/i.test(input);
|
||
},
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours < 12) {
|
||
return isLower ? 'sa' : 'SA';
|
||
} else {
|
||
return isLower ? 'ch' : 'CH';
|
||
}
|
||
},
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM [năm] YYYY',
|
||
LLL : 'D MMMM [năm] YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM [năm] YYYY HH:mm',
|
||
l : 'DD/M/YYYY',
|
||
ll : 'D MMM YYYY',
|
||
lll : 'D MMM YYYY HH:mm',
|
||
llll : 'ddd, D MMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay: '[Hôm nay lúc] LT',
|
||
nextDay: '[Ngày mai lúc] LT',
|
||
nextWeek: 'dddd [tuần tới lúc] LT',
|
||
lastDay: '[Hôm qua lúc] LT',
|
||
lastWeek: 'dddd [tuần rồi lúc] LT',
|
||
sameElse: 'L'
|
||
},
|
||
relativeTime : {
|
||
future : '%s tới',
|
||
past : '%s trước',
|
||
s : 'vài giây',
|
||
m : 'một phút',
|
||
mm : '%d phút',
|
||
h : 'một giờ',
|
||
hh : '%d giờ',
|
||
d : 'một ngày',
|
||
dd : '%d ngày',
|
||
M : 'một tháng',
|
||
MM : '%d tháng',
|
||
y : 'một năm',
|
||
yy : '%d năm'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}/,
|
||
ordinal : function (number) {
|
||
return number;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Pseudo [x-pseudo]
|
||
//! author : Andrew Hood : https://github.com/andrewhood125
|
||
|
||
hooks.defineLocale('x-pseudo', {
|
||
months : 'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split('_'),
|
||
monthsShort : 'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split('_'),
|
||
monthsParseExact : true,
|
||
weekdays : 'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split('_'),
|
||
weekdaysShort : 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'),
|
||
weekdaysMin : 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'),
|
||
weekdaysParseExact : true,
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY HH:mm',
|
||
LLLL : 'dddd, D MMMM YYYY HH:mm'
|
||
},
|
||
calendar : {
|
||
sameDay : '[T~ódá~ý át] LT',
|
||
nextDay : '[T~ómó~rró~w át] LT',
|
||
nextWeek : 'dddd [át] LT',
|
||
lastDay : '[Ý~ést~érdá~ý át] LT',
|
||
lastWeek : '[L~ást] dddd [át] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'í~ñ %s',
|
||
past : '%s á~gó',
|
||
s : 'á ~féw ~sécó~ñds',
|
||
m : 'á ~míñ~úté',
|
||
mm : '%d m~íñú~tés',
|
||
h : 'á~ñ hó~úr',
|
||
hh : '%d h~óúrs',
|
||
d : 'á ~dáý',
|
||
dd : '%d d~áýs',
|
||
M : 'á ~móñ~th',
|
||
MM : '%d m~óñt~hs',
|
||
y : 'á ~ýéár',
|
||
yy : '%d ý~éárs'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (~~(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
},
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Yoruba Nigeria [yo]
|
||
//! author : Atolagbe Abisoye : https://github.com/andela-batolagbe
|
||
|
||
hooks.defineLocale('yo', {
|
||
months : 'Sẹ́rẹ́_Èrèlè_Ẹrẹ̀nà_Ìgbé_Èbibi_Òkùdu_Agẹmo_Ògún_Owewe_Ọ̀wàrà_Bélú_Ọ̀pẹ̀̀'.split('_'),
|
||
monthsShort : 'Sẹ́r_Èrl_Ẹrn_Ìgb_Èbi_Òkù_Agẹ_Ògú_Owe_Ọ̀wà_Bél_Ọ̀pẹ̀̀'.split('_'),
|
||
weekdays : 'Àìkú_Ajé_Ìsẹ́gun_Ọjọ́rú_Ọjọ́bọ_Ẹtì_Àbámẹ́ta'.split('_'),
|
||
weekdaysShort : 'Àìk_Ajé_Ìsẹ́_Ọjr_Ọjb_Ẹtì_Àbá'.split('_'),
|
||
weekdaysMin : 'Àì_Aj_Ìs_Ọr_Ọb_Ẹt_Àb'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'h:mm A',
|
||
LTS : 'h:mm:ss A',
|
||
L : 'DD/MM/YYYY',
|
||
LL : 'D MMMM YYYY',
|
||
LLL : 'D MMMM YYYY h:mm A',
|
||
LLLL : 'dddd, D MMMM YYYY h:mm A'
|
||
},
|
||
calendar : {
|
||
sameDay : '[Ònì ni] LT',
|
||
nextDay : '[Ọ̀la ni] LT',
|
||
nextWeek : 'dddd [Ọsẹ̀ tón\'bọ] [ni] LT',
|
||
lastDay : '[Àna ni] LT',
|
||
lastWeek : 'dddd [Ọsẹ̀ tólọ́] [ni] LT',
|
||
sameElse : 'L'
|
||
},
|
||
relativeTime : {
|
||
future : 'ní %s',
|
||
past : '%s kọjá',
|
||
s : 'ìsẹjú aayá die',
|
||
m : 'ìsẹjú kan',
|
||
mm : 'ìsẹjú %d',
|
||
h : 'wákati kan',
|
||
hh : 'wákati %d',
|
||
d : 'ọjọ́ kan',
|
||
dd : 'ọjọ́ %d',
|
||
M : 'osù kan',
|
||
MM : 'osù %d',
|
||
y : 'ọdún kan',
|
||
yy : 'ọdún %d'
|
||
},
|
||
dayOfMonthOrdinalParse : /ọjọ́\s\d{1,2}/,
|
||
ordinal : 'ọjọ́ %d',
|
||
week : {
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Chinese (China) [zh-cn]
|
||
//! author : suupic : https://github.com/suupic
|
||
//! author : Zeno Zeng : https://github.com/zenozeng
|
||
|
||
hooks.defineLocale('zh-cn', {
|
||
months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
|
||
monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
|
||
weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
|
||
weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'),
|
||
weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY年MMMD日',
|
||
LL : 'YYYY年MMMD日',
|
||
LLL : 'YYYY年MMMD日Ah点mm分',
|
||
LLLL : 'YYYY年MMMD日ddddAh点mm分',
|
||
l : 'YYYY年MMMD日',
|
||
ll : 'YYYY年MMMD日',
|
||
lll : 'YYYY年MMMD日 HH:mm',
|
||
llll : 'YYYY年MMMD日dddd HH:mm'
|
||
},
|
||
meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
|
||
meridiemHour: function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === '凌晨' || meridiem === '早上' ||
|
||
meridiem === '上午') {
|
||
return hour;
|
||
} else if (meridiem === '下午' || meridiem === '晚上') {
|
||
return hour + 12;
|
||
} else {
|
||
// '中午'
|
||
return hour >= 11 ? hour : hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
var hm = hour * 100 + minute;
|
||
if (hm < 600) {
|
||
return '凌晨';
|
||
} else if (hm < 900) {
|
||
return '早上';
|
||
} else if (hm < 1130) {
|
||
return '上午';
|
||
} else if (hm < 1230) {
|
||
return '中午';
|
||
} else if (hm < 1800) {
|
||
return '下午';
|
||
} else {
|
||
return '晚上';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[今天]LT',
|
||
nextDay : '[明天]LT',
|
||
nextWeek : '[下]ddddLT',
|
||
lastDay : '[昨天]LT',
|
||
lastWeek : '[上]ddddLT',
|
||
sameElse : 'L'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(日|月|周)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
case 'd':
|
||
case 'D':
|
||
case 'DDD':
|
||
return number + '日';
|
||
case 'M':
|
||
return number + '月';
|
||
case 'w':
|
||
case 'W':
|
||
return number + '周';
|
||
default:
|
||
return number;
|
||
}
|
||
},
|
||
relativeTime : {
|
||
future : '%s内',
|
||
past : '%s前',
|
||
s : '几秒',
|
||
m : '1 分钟',
|
||
mm : '%d 分钟',
|
||
h : '1 小时',
|
||
hh : '%d 小时',
|
||
d : '1 天',
|
||
dd : '%d 天',
|
||
M : '1 个月',
|
||
MM : '%d 个月',
|
||
y : '1 年',
|
||
yy : '%d 年'
|
||
},
|
||
week : {
|
||
// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
|
||
dow : 1, // Monday is the first day of the week.
|
||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Chinese (Hong Kong) [zh-hk]
|
||
//! author : Ben : https://github.com/ben-lin
|
||
//! author : Chris Lam : https://github.com/hehachris
|
||
//! author : Konstantin : https://github.com/skfd
|
||
|
||
hooks.defineLocale('zh-hk', {
|
||
months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
|
||
monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
|
||
weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
|
||
weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
|
||
weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY年MMMD日',
|
||
LL : 'YYYY年MMMD日',
|
||
LLL : 'YYYY年MMMD日 HH:mm',
|
||
LLLL : 'YYYY年MMMD日dddd HH:mm',
|
||
l : 'YYYY年MMMD日',
|
||
ll : 'YYYY年MMMD日',
|
||
lll : 'YYYY年MMMD日 HH:mm',
|
||
llll : 'YYYY年MMMD日dddd HH:mm'
|
||
},
|
||
meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
|
||
return hour;
|
||
} else if (meridiem === '中午') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === '下午' || meridiem === '晚上') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
var hm = hour * 100 + minute;
|
||
if (hm < 600) {
|
||
return '凌晨';
|
||
} else if (hm < 900) {
|
||
return '早上';
|
||
} else if (hm < 1130) {
|
||
return '上午';
|
||
} else if (hm < 1230) {
|
||
return '中午';
|
||
} else if (hm < 1800) {
|
||
return '下午';
|
||
} else {
|
||
return '晚上';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[今天]LT',
|
||
nextDay : '[明天]LT',
|
||
nextWeek : '[下]ddddLT',
|
||
lastDay : '[昨天]LT',
|
||
lastWeek : '[上]ddddLT',
|
||
sameElse : 'L'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(日|月|週)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
case 'd' :
|
||
case 'D' :
|
||
case 'DDD' :
|
||
return number + '日';
|
||
case 'M' :
|
||
return number + '月';
|
||
case 'w' :
|
||
case 'W' :
|
||
return number + '週';
|
||
default :
|
||
return number;
|
||
}
|
||
},
|
||
relativeTime : {
|
||
future : '%s內',
|
||
past : '%s前',
|
||
s : '幾秒',
|
||
m : '1 分鐘',
|
||
mm : '%d 分鐘',
|
||
h : '1 小時',
|
||
hh : '%d 小時',
|
||
d : '1 天',
|
||
dd : '%d 天',
|
||
M : '1 個月',
|
||
MM : '%d 個月',
|
||
y : '1 年',
|
||
yy : '%d 年'
|
||
}
|
||
});
|
||
|
||
//! moment.js locale configuration
|
||
//! locale : Chinese (Taiwan) [zh-tw]
|
||
//! author : Ben : https://github.com/ben-lin
|
||
//! author : Chris Lam : https://github.com/hehachris
|
||
|
||
hooks.defineLocale('zh-tw', {
|
||
months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
|
||
monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
|
||
weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
|
||
weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
|
||
weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
|
||
longDateFormat : {
|
||
LT : 'HH:mm',
|
||
LTS : 'HH:mm:ss',
|
||
L : 'YYYY年MMMD日',
|
||
LL : 'YYYY年MMMD日',
|
||
LLL : 'YYYY年MMMD日 HH:mm',
|
||
LLLL : 'YYYY年MMMD日dddd HH:mm',
|
||
l : 'YYYY年MMMD日',
|
||
ll : 'YYYY年MMMD日',
|
||
lll : 'YYYY年MMMD日 HH:mm',
|
||
llll : 'YYYY年MMMD日dddd HH:mm'
|
||
},
|
||
meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
|
||
meridiemHour : function (hour, meridiem) {
|
||
if (hour === 12) {
|
||
hour = 0;
|
||
}
|
||
if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
|
||
return hour;
|
||
} else if (meridiem === '中午') {
|
||
return hour >= 11 ? hour : hour + 12;
|
||
} else if (meridiem === '下午' || meridiem === '晚上') {
|
||
return hour + 12;
|
||
}
|
||
},
|
||
meridiem : function (hour, minute, isLower) {
|
||
var hm = hour * 100 + minute;
|
||
if (hm < 600) {
|
||
return '凌晨';
|
||
} else if (hm < 900) {
|
||
return '早上';
|
||
} else if (hm < 1130) {
|
||
return '上午';
|
||
} else if (hm < 1230) {
|
||
return '中午';
|
||
} else if (hm < 1800) {
|
||
return '下午';
|
||
} else {
|
||
return '晚上';
|
||
}
|
||
},
|
||
calendar : {
|
||
sameDay : '[今天]LT',
|
||
nextDay : '[明天]LT',
|
||
nextWeek : '[下]ddddLT',
|
||
lastDay : '[昨天]LT',
|
||
lastWeek : '[上]ddddLT',
|
||
sameElse : 'L'
|
||
},
|
||
dayOfMonthOrdinalParse: /\d{1,2}(日|月|週)/,
|
||
ordinal : function (number, period) {
|
||
switch (period) {
|
||
case 'd' :
|
||
case 'D' :
|
||
case 'DDD' :
|
||
return number + '日';
|
||
case 'M' :
|
||
return number + '月';
|
||
case 'w' :
|
||
case 'W' :
|
||
return number + '週';
|
||
default :
|
||
return number;
|
||
}
|
||
},
|
||
relativeTime : {
|
||
future : '%s內',
|
||
past : '%s前',
|
||
s : '幾秒',
|
||
m : '1 分鐘',
|
||
mm : '%d 分鐘',
|
||
h : '1 小時',
|
||
hh : '%d 小時',
|
||
d : '1 天',
|
||
dd : '%d 天',
|
||
M : '1 個月',
|
||
MM : '%d 個月',
|
||
y : '1 年',
|
||
yy : '%d 年'
|
||
}
|
||
});
|
||
|
||
hooks.locale('en');
|
||
|
||
return hooks;
|
||
|
||
})));
|
||
|
||
// Underscore.js 1.8.3
|
||
// http://underscorejs.org
|
||
// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||
// Underscore may be freely distributed under the MIT license.
|
||
(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])<u?i=a+1:o=a}return i},m.indexOf=r(1,m.findIndex,m.sortedIndex),m.lastIndexOf=r(-1,m.findLastIndex),m.range=function(n,t,r){null==t&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e<arguments.length;)i.push(arguments[e++]);return E(n,r,this,this,i)};return r},m.bindAll=function(n){var t,r,e=arguments.length;if(1>=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this);
|
||
//# sourceMappingURL=underscore-min.map;
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../lib/codemirror"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/mode/meta',["../lib/codemirror"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
"use strict";
|
||
|
||
CodeMirror.modeInfo = [
|
||
{name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
|
||
{name: "PGP", mimes: ["application/pgp", "application/pgp-encrypted", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["asc", "pgp", "sig"]},
|
||
{name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]},
|
||
{name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i},
|
||
{name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]},
|
||
{name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]},
|
||
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
|
||
{name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
|
||
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp", "cs"]},
|
||
{name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
|
||
{name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
|
||
{name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
|
||
{name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
|
||
{name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
|
||
{name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
|
||
{name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
|
||
{name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
|
||
{name: "Crystal", mime: "text/x-crystal", mode: "crystal", ext: ["cr"]},
|
||
{name: "CSS", mime: "text/css", mode: "css", ext: ["css"]},
|
||
{name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]},
|
||
{name: "D", mime: "text/x-d", mode: "d", ext: ["d"]},
|
||
{name: "Dart", mimes: ["application/dart", "text/x-dart"], mode: "dart", ext: ["dart"]},
|
||
{name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]},
|
||
{name: "Django", mime: "text/x-django", mode: "django"},
|
||
{name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile", file: /^Dockerfile$/},
|
||
{name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]},
|
||
{name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
|
||
{name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
|
||
{name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
|
||
{name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]},
|
||
{name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
|
||
{name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
|
||
{name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
|
||
{name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]},
|
||
{name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
|
||
{name: "Esper", mime: "text/x-esper", mode: "sql"},
|
||
{name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
|
||
{name: "FCL", mime: "text/x-fcl", mode: "fcl"},
|
||
{name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
|
||
{name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90", "f95"]},
|
||
{name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
|
||
{name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
|
||
{name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
|
||
{name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
|
||
{name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
|
||
{name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/},
|
||
{name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
|
||
{name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
|
||
{name: "Haskell (Literate)", mime: "text/x-literate-haskell", mode: "haskell-literate", ext: ["lhs"]},
|
||
{name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
|
||
{name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
|
||
{name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
|
||
{name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm", "handlebars", "hbs"], alias: ["xhtml"]},
|
||
{name: "HTTP", mime: "message/http", mode: "http"},
|
||
{name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
|
||
{name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]},
|
||
{name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
|
||
{name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
|
||
{name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
|
||
mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]},
|
||
{name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
|
||
{name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
|
||
{name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
|
||
{name: "Jinja2", mime: "text/jinja2", mode: "jinja2", ext: ["j2", "jinja", "jinja2"]},
|
||
{name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
|
||
{name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
|
||
{name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
|
||
{name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]},
|
||
{name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]},
|
||
{name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
|
||
{name: "mIRC", mime: "text/mirc", mode: "mirc"},
|
||
{name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
|
||
{name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb", "wl", "wls"]},
|
||
{name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
|
||
{name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
|
||
{name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
|
||
{name: "mbox", mime: "application/mbox", mode: "mbox", ext: ["mbox"]},
|
||
{name: "MySQL", mime: "text/x-mysql", mode: "sql"},
|
||
{name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
|
||
{name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
|
||
{name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"],
|
||
mode: "ntriples", ext: ["nt", "nq"]},
|
||
{name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m"], alias: ["objective-c", "objc"]},
|
||
{name: "Objective-C++", mime: "text/x-objectivec++", mode: "clike", ext: ["mm"], alias: ["objective-c++", "objc++"]},
|
||
{name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
|
||
{name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
|
||
{name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
|
||
{name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
|
||
{name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]},
|
||
{name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
|
||
{name: "PHP", mimes: ["text/x-php", "application/x-httpd-php", "application/x-httpd-php-open"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]},
|
||
{name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
|
||
{name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
|
||
{name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
|
||
{name: "PostgreSQL", mime: "text/x-pgsql", mode: "sql"},
|
||
{name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]},
|
||
{name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
|
||
{name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
|
||
{name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/},
|
||
{name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
|
||
{name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
|
||
{name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r", "R"], alias: ["rscript"]},
|
||
{name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
|
||
{name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
|
||
{name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
|
||
{name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
|
||
{name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
|
||
{name: "SAS", mime: "text/x-sas", mode: "sas", ext: ["sas"]},
|
||
{name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
|
||
{name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
|
||
{name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
|
||
{name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
|
||
{name: "Shell", mimes: ["text/x-sh", "application/x-sh"], mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/},
|
||
{name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]},
|
||
{name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]},
|
||
{name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
|
||
{name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
|
||
{name: "Solr", mime: "text/x-solr", mode: "solr"},
|
||
{name: "SML", mime: "text/x-sml", mode: "mllike", ext: ["sml", "sig", "fun", "smackspec"]},
|
||
{name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]},
|
||
{name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
|
||
{name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
|
||
{name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
|
||
{name: "SQLite", mime: "text/x-sqlite", mode: "sql"},
|
||
{name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
|
||
{name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]},
|
||
{name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
|
||
{name: "sTeX", mime: "text/x-stex", mode: "stex"},
|
||
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx", "tex"], alias: ["tex"]},
|
||
{name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]},
|
||
{name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
|
||
{name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
|
||
{name: "TiddlyWiki", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
|
||
{name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
|
||
{name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
|
||
{name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
|
||
{name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
|
||
{name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
|
||
{name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
|
||
{name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
|
||
{name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
|
||
{name: "TypeScript-JSX", mime: "text/typescript-jsx", mode: "jsx", ext: ["tsx"], alias: ["tsx"]},
|
||
{name: "Twig", mime: "text/x-twig", mode: "twig"},
|
||
{name: "Web IDL", mime: "text/x-webidl", mode: "webidl", ext: ["webidl"]},
|
||
{name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
|
||
{name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]},
|
||
{name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
|
||
{name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
|
||
{name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]},
|
||
{name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]},
|
||
{name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd", "svg"], alias: ["rss", "wsdl", "xsd"]},
|
||
{name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
|
||
{name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]},
|
||
{name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]},
|
||
{name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
|
||
{name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
|
||
{name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
|
||
{name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]}
|
||
];
|
||
// Ensure all modes have a mime property for backwards compatibility
|
||
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
|
||
var info = CodeMirror.modeInfo[i];
|
||
if (info.mimes) info.mime = info.mimes[0];
|
||
}
|
||
|
||
CodeMirror.findModeByMIME = function(mime) {
|
||
mime = mime.toLowerCase();
|
||
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
|
||
var info = CodeMirror.modeInfo[i];
|
||
if (info.mime == mime) return info;
|
||
if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
|
||
if (info.mimes[j] == mime) return info;
|
||
}
|
||
if (/\+xml$/.test(mime)) return CodeMirror.findModeByMIME("application/xml")
|
||
if (/\+json$/.test(mime)) return CodeMirror.findModeByMIME("application/json")
|
||
};
|
||
|
||
CodeMirror.findModeByExtension = function(ext) {
|
||
ext = ext.toLowerCase();
|
||
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
|
||
var info = CodeMirror.modeInfo[i];
|
||
if (info.ext) for (var j = 0; j < info.ext.length; j++)
|
||
if (info.ext[j] == ext) return info;
|
||
}
|
||
};
|
||
|
||
CodeMirror.findModeByFileName = function(filename) {
|
||
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
|
||
var info = CodeMirror.modeInfo[i];
|
||
if (info.file && info.file.test(filename)) return info;
|
||
}
|
||
var dot = filename.lastIndexOf(".");
|
||
var ext = dot > -1 && filename.substring(dot + 1, filename.length);
|
||
if (ext) return CodeMirror.findModeByExtension(ext);
|
||
};
|
||
|
||
CodeMirror.findModeByName = function(name) {
|
||
name = name.toLowerCase();
|
||
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
|
||
var info = CodeMirror.modeInfo[i];
|
||
if (info.name.toLowerCase() == name) return info;
|
||
if (info.alias) for (var j = 0; j < info.alias.length; j++)
|
||
if (info.alias[j].toLowerCase() == name) return info;
|
||
}
|
||
};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('base/js/utils',[
|
||
'jquery',
|
||
'codemirror/lib/codemirror',
|
||
'moment',
|
||
'underscore',
|
||
// silently upgrades CodeMirror
|
||
'codemirror/mode/meta',
|
||
], function($, CodeMirror, moment, _){
|
||
"use strict";
|
||
|
||
// keep track of which extensions have been loaded already
|
||
var extensions_loaded = [];
|
||
|
||
/**
|
||
* Whether or not an extension has been loaded
|
||
* @param {string} extension - name of the extension
|
||
* @return {boolean} true if loaded already
|
||
*/
|
||
var is_loaded = function(extension) {
|
||
var ext_path = "nbextensions/" + extension;
|
||
return extensions_loaded.indexOf(ext_path) >= 0;
|
||
};
|
||
|
||
/**
|
||
* Load a single extension.
|
||
* @param {string} extension - extension path.
|
||
* @return {Promise} that resolves to an extension module handle
|
||
*/
|
||
var load_extension = function (extension) {
|
||
return new Promise(function(resolve, reject) {
|
||
var ext_path = "nbextensions/" + extension;
|
||
requirejs([ext_path], function(module) {
|
||
if (!is_loaded(extension)) {
|
||
console.log("Loading extension: " + extension);
|
||
if (module && module.load_ipython_extension) {
|
||
Promise.resolve(module.load_ipython_extension()).then(function() {
|
||
resolve(module);
|
||
}).catch(reject);
|
||
}
|
||
extensions_loaded.push(ext_path);
|
||
} else {
|
||
console.log("Loaded extension already: " + extension);
|
||
resolve(module);
|
||
}
|
||
}, function(err) {
|
||
reject(err);
|
||
});
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Load multiple extensions.
|
||
* Takes n-args, where each arg is a string path to the extension.
|
||
* @return {Promise} that resolves to a list of loaded module handles.
|
||
*/
|
||
var load_extensions = function () {
|
||
console.log('load_extensions', arguments);
|
||
return Promise.all(Array.prototype.map.call(arguments, load_extension)).catch(function(err) {
|
||
console.error("Failed to load extension" + (err.requireModules.length>1?'s':'') + ":", err.requireModules, err);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Return a list of extensions that should be active
|
||
* The config for nbextensions comes in as a dict where keys are
|
||
* nbextensions paths and the values are a bool indicating if it
|
||
* should be active. This returns a list of nbextension paths
|
||
* where the value is true
|
||
*/
|
||
function filter_extensions(nbext_config) {
|
||
var active = [];
|
||
Object.keys(nbext_config).forEach(function (nbext) {
|
||
if (nbext_config[nbext]) {active.push(nbext);}
|
||
});
|
||
return active;
|
||
}
|
||
|
||
/**
|
||
* Wait for a config section to load, and then load the extensions specified
|
||
* in a 'load_extensions' key inside it.
|
||
*/
|
||
function load_extensions_from_config(section) {
|
||
return section.loaded.then(function() {
|
||
if (section.data.load_extensions) {
|
||
var active = filter_extensions(section.data.load_extensions);
|
||
return load_extensions.apply(this, active);
|
||
}
|
||
}).catch(utils.reject('Could not load nbextensions from ' + section.section_name + ' config file'));
|
||
}
|
||
|
||
//============================================================================
|
||
// Cross-browser RegEx Split
|
||
//============================================================================
|
||
|
||
// This code has been MODIFIED from the code licensed below to not replace the
|
||
// default browser split. The license is reproduced here.
|
||
|
||
// see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
|
||
/*!
|
||
* Cross-Browser Split 1.1.1
|
||
* Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
|
||
* Available under the MIT License
|
||
* ECMAScript compliant, uniform cross-browser split method
|
||
*/
|
||
|
||
/**
|
||
* Splits a string into an array of strings using a regex or string
|
||
* separator. Matches of the separator are not included in the result array.
|
||
* However, if `separator` is a regex that contains capturing groups,
|
||
* backreferences are spliced into the result each time `separator` is
|
||
* matched. Fixes browser bugs compared to the native
|
||
* `String.prototype.split` and can be used reliably cross-browser.
|
||
* @param {String} str String to split.
|
||
* @param {RegExp} separator Regex to use for separating
|
||
* the string.
|
||
* @param {Number} [limit] Maximum number of items to include in the result
|
||
* array.
|
||
* @returns {Array} Array of substrings.
|
||
* @example
|
||
*
|
||
* // Basic use
|
||
* regex_split('a b c d', ' ');
|
||
* // -> ['a', 'b', 'c', 'd']
|
||
*
|
||
* // With limit
|
||
* regex_split('a b c d', ' ', 2);
|
||
* // -> ['a', 'b']
|
||
*
|
||
* // Backreferences in result array
|
||
* regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
|
||
* // -> ['..', 'word', '1', ' ', 'word', '2', '..']
|
||
*/
|
||
var regex_split = function (str, separator, limit) {
|
||
var output = [],
|
||
flags = (separator.ignoreCase ? "i" : "") +
|
||
(separator.multiline ? "m" : "") +
|
||
(separator.extended ? "x" : "") + // Proposed for ES6
|
||
(separator.sticky ? "y" : ""), // Firefox 3+
|
||
lastLastIndex = 0,
|
||
separator2, match, lastIndex, lastLength;
|
||
// Make `global` and avoid `lastIndex` issues by working with a copy
|
||
separator = new RegExp(separator.source, flags + "g");
|
||
|
||
var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
|
||
if (!compliantExecNpcg) {
|
||
// Doesn't need flags gy, but they don't hurt
|
||
separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
|
||
}
|
||
/* Values for `limit`, per the spec:
|
||
* If undefined: 4294967295 // Math.pow(2, 32) - 1
|
||
* If 0, Infinity, or NaN: 0
|
||
* If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
|
||
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
|
||
* If other: Type-convert, then use the above rules
|
||
*/
|
||
limit = typeof(limit) === "undefined" ?
|
||
-1 >>> 0 : // Math.pow(2, 32) - 1
|
||
limit >>> 0; // ToUint32(limit)
|
||
for (match = separator.exec(str); match; match = separator.exec(str)) {
|
||
// `separator.lastIndex` is not reliable cross-browser
|
||
lastIndex = match.index + match[0].length;
|
||
if (lastIndex > lastLastIndex) {
|
||
output.push(str.slice(lastLastIndex, match.index));
|
||
// Fix browsers whose `exec` methods don't consistently return `undefined` for
|
||
// nonparticipating capturing groups
|
||
if (!compliantExecNpcg && match.length > 1) {
|
||
match[0].replace(separator2, function () {
|
||
for (var i = 1; i < arguments.length - 2; i++) {
|
||
if (typeof(arguments[i]) === "undefined") {
|
||
match[i] = undefined;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
if (match.length > 1 && match.index < str.length) {
|
||
Array.prototype.push.apply(output, match.slice(1));
|
||
}
|
||
lastLength = match[0].length;
|
||
lastLastIndex = lastIndex;
|
||
if (output.length >= limit) {
|
||
break;
|
||
}
|
||
}
|
||
if (separator.lastIndex === match.index) {
|
||
separator.lastIndex++; // Avoid an infinite loop
|
||
}
|
||
}
|
||
if (lastLastIndex === str.length) {
|
||
if (lastLength || !separator.test("")) {
|
||
output.push("");
|
||
}
|
||
} else {
|
||
output.push(str.slice(lastLastIndex));
|
||
}
|
||
return output.length > limit ? output.slice(0, limit) : output;
|
||
};
|
||
|
||
//============================================================================
|
||
// End contributed Cross-browser RegEx Split
|
||
//============================================================================
|
||
|
||
|
||
var uuid = function () {
|
||
/**
|
||
* http://www.ietf.org/rfc/rfc4122.txt
|
||
*/
|
||
var s = [];
|
||
var hexDigits = "0123456789abcdef";
|
||
for (var i = 0; i < 32; i++) {
|
||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||
}
|
||
s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
|
||
s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
|
||
|
||
var uuid = s.join("");
|
||
return uuid;
|
||
};
|
||
|
||
var _ANSI_COLORS = [
|
||
"ansi-black",
|
||
"ansi-red",
|
||
"ansi-green",
|
||
"ansi-yellow",
|
||
"ansi-blue",
|
||
"ansi-magenta",
|
||
"ansi-cyan",
|
||
"ansi-white",
|
||
"ansi-black-intense",
|
||
"ansi-red-intense",
|
||
"ansi-green-intense",
|
||
"ansi-yellow-intense",
|
||
"ansi-blue-intense",
|
||
"ansi-magenta-intense",
|
||
"ansi-cyan-intense",
|
||
"ansi-white-intense",
|
||
];
|
||
|
||
function _pushColoredChunk(chunk, fg, bg, bold, underline, inverse, out) {
|
||
if (chunk) {
|
||
var classes = [];
|
||
var styles = [];
|
||
|
||
if (bold && typeof fg === "number" && 0 <= fg && fg < 8) {
|
||
fg += 8; // Bold text uses "intense" colors
|
||
}
|
||
if (inverse) {
|
||
[fg, bg] = [bg, fg];
|
||
}
|
||
|
||
if (typeof fg === "number") {
|
||
classes.push(_ANSI_COLORS[fg] + "-fg");
|
||
} else if (fg.length) {
|
||
styles.push("color: rgb(" + fg + ")");
|
||
} else if (inverse) {
|
||
classes.push("ansi-default-inverse-fg");
|
||
}
|
||
|
||
if (typeof bg === "number") {
|
||
classes.push(_ANSI_COLORS[bg] + "-bg");
|
||
} else if (bg.length) {
|
||
styles.push("background-color: rgb(" + bg + ")");
|
||
} else if (inverse) {
|
||
classes.push("ansi-default-inverse-bg");
|
||
}
|
||
|
||
if (bold) {
|
||
classes.push("ansi-bold");
|
||
}
|
||
|
||
if (underline) {
|
||
classes.push("ansi-underline");
|
||
}
|
||
|
||
if (classes.length || styles.length) {
|
||
out.push("<span");
|
||
if (classes.length) {
|
||
out.push(' class="' + classes.join(" ") + '"');
|
||
}
|
||
if (styles.length) {
|
||
out.push(' style="' + styles.join("; ") + '"');
|
||
}
|
||
out.push(">");
|
||
out.push(chunk);
|
||
out.push("</span>");
|
||
} else {
|
||
out.push(chunk);
|
||
}
|
||
}
|
||
}
|
||
|
||
function _getExtendedColors(numbers) {
|
||
var r, g, b;
|
||
var n = numbers.shift();
|
||
if (n === 2 && numbers.length >= 3) {
|
||
// 24-bit RGB
|
||
r = numbers.shift();
|
||
g = numbers.shift();
|
||
b = numbers.shift();
|
||
if ([r, g, b].some(function (c) { return c < 0 || 255 < c; })) {
|
||
throw new RangeError("Invalid range for RGB colors");
|
||
}
|
||
} else if (n === 5 && numbers.length >= 1) {
|
||
// 256 colors
|
||
var idx = numbers.shift();
|
||
if (idx < 0) {
|
||
throw new RangeError("Color index must be >= 0");
|
||
} else if (idx < 16) {
|
||
// 16 default terminal colors
|
||
return idx;
|
||
} else if (idx < 232) {
|
||
// 6x6x6 color cube, see https://stackoverflow.com/a/27165165/500098
|
||
r = Math.floor((idx - 16) / 36);
|
||
r = r > 0 ? 55 + r * 40 : 0;
|
||
g = Math.floor(((idx - 16) % 36) / 6);
|
||
g = g > 0 ? 55 + g * 40 : 0;
|
||
b = (idx - 16) % 6;
|
||
b = b > 0 ? 55 + b * 40 : 0;
|
||
} else if (idx < 256) {
|
||
// grayscale, see https://stackoverflow.com/a/27165165/500098
|
||
r = g = b = (idx - 232) * 10 + 8;
|
||
} else {
|
||
throw new RangeError("Color index must be < 256");
|
||
}
|
||
} else {
|
||
throw new RangeError("Invalid extended color specification");
|
||
}
|
||
return [r, g, b];
|
||
}
|
||
|
||
function _ansispan(str) {
|
||
var ansi_re = /\x1b\[(.*?)([@-~])/g;
|
||
var fg = [];
|
||
var bg = [];
|
||
var bold = false;
|
||
var underline = false;
|
||
var inverse = false;
|
||
var match;
|
||
var out = [];
|
||
var numbers = [];
|
||
var start = 0;
|
||
|
||
str += "\x1b[m"; // Ensure markup for trailing text
|
||
while ((match = ansi_re.exec(str))) {
|
||
if (match[2] === "m") {
|
||
var items = match[1].split(";");
|
||
for (var i = 0; i < items.length; i++) {
|
||
var item = items[i];
|
||
if (item === "") {
|
||
numbers.push(0);
|
||
} else if (item.search(/^\d+$/) !== -1) {
|
||
numbers.push(parseInt(item));
|
||
} else {
|
||
// Ignored: Invalid color specification
|
||
numbers.length = 0;
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
// Ignored: Not a color code
|
||
}
|
||
var chunk = str.substring(start, match.index);
|
||
_pushColoredChunk(chunk, fg, bg, bold, underline, inverse, out);
|
||
start = ansi_re.lastIndex;
|
||
|
||
while (numbers.length) {
|
||
var n = numbers.shift();
|
||
switch (n) {
|
||
case 0:
|
||
fg = bg = [];
|
||
bold = false;
|
||
underline = false;
|
||
inverse = false;
|
||
break;
|
||
case 1:
|
||
case 5:
|
||
bold = true;
|
||
break;
|
||
case 4:
|
||
underline = true;
|
||
break;
|
||
case 7:
|
||
inverse = true;
|
||
break;
|
||
case 21:
|
||
case 22:
|
||
bold = false;
|
||
break;
|
||
case 24:
|
||
underline = false;
|
||
break;
|
||
case 27:
|
||
inverse = false;
|
||
break;
|
||
case 30:
|
||
case 31:
|
||
case 32:
|
||
case 33:
|
||
case 34:
|
||
case 35:
|
||
case 36:
|
||
case 37:
|
||
fg = n - 30;
|
||
break;
|
||
case 38:
|
||
try {
|
||
fg = _getExtendedColors(numbers);
|
||
} catch(e) {
|
||
numbers.length = 0;
|
||
}
|
||
break;
|
||
case 39:
|
||
fg = [];
|
||
break;
|
||
case 40:
|
||
case 41:
|
||
case 42:
|
||
case 43:
|
||
case 44:
|
||
case 45:
|
||
case 46:
|
||
case 47:
|
||
bg = n - 40;
|
||
break;
|
||
case 48:
|
||
try {
|
||
bg = _getExtendedColors(numbers);
|
||
} catch(e) {
|
||
numbers.length = 0;
|
||
}
|
||
break;
|
||
case 49:
|
||
bg = [];
|
||
break;
|
||
case 90:
|
||
case 91:
|
||
case 92:
|
||
case 93:
|
||
case 94:
|
||
case 95:
|
||
case 96:
|
||
case 97:
|
||
fg = n - 90 + 8;
|
||
break;
|
||
case 100:
|
||
case 101:
|
||
case 102:
|
||
case 103:
|
||
case 104:
|
||
case 105:
|
||
case 106:
|
||
case 107:
|
||
bg = n - 100 + 8;
|
||
break;
|
||
default:
|
||
// Unknown codes are ignored
|
||
}
|
||
}
|
||
}
|
||
return out.join("");
|
||
}
|
||
|
||
// Transform ANSI color escape codes into HTML <span> tags with CSS
|
||
// classes such as "ansi-green-intense-fg".
|
||
// The actual colors used are set in the CSS file.
|
||
// This is supposed to have the same behavior as nbconvert.filters.ansi2html()
|
||
function fixConsole(txt) {
|
||
txt = _.escape(txt);
|
||
|
||
// color ansi codes (and remove non-color escape sequences)
|
||
txt = _ansispan(txt);
|
||
return txt;
|
||
}
|
||
|
||
// Remove chunks that should be overridden by the effect of
|
||
// carriage return characters
|
||
function fixCarriageReturn(txt) {
|
||
txt = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
|
||
while (txt.search(/\r[^$]/g) > -1) {
|
||
var base = txt.match(/^(.*)\r+/m)[1];
|
||
var insert = txt.match(/\r+(.*)$/m)[1];
|
||
insert = insert + base.slice(insert.length, base.length);
|
||
txt = txt.replace(/\r+.*$/m, '\r').replace(/^.*\r/m, insert);
|
||
}
|
||
return txt;
|
||
}
|
||
|
||
// Remove characters that are overridden by backspace characters
|
||
function fixBackspace(txt) {
|
||
var tmp = txt;
|
||
do {
|
||
txt = tmp;
|
||
// Cancel out anything-but-newline followed by backspace
|
||
tmp = txt.replace(/[^\n]\x08/gm, '');
|
||
} while (tmp.length < txt.length);
|
||
return txt;
|
||
}
|
||
|
||
// Remove characters overridden by backspace and carriage return
|
||
function fixOverwrittenChars(txt) {
|
||
return fixCarriageReturn(fixBackspace(txt));
|
||
}
|
||
|
||
// Locate any URLs and convert them to an anchor tag
|
||
function autoLinkUrls(txt) {
|
||
return txt.replace(/(^|\s)(https?|ftp)(:[^'"<>\s]+)/gi,
|
||
"$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
|
||
}
|
||
|
||
var points_to_pixels = function (points) {
|
||
/**
|
||
* A reasonably good way of converting between points and pixels.
|
||
*/
|
||
var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
|
||
$('body').append(test);
|
||
var pixel_per_point = test.width()/10000;
|
||
test.remove();
|
||
return Math.floor(points*pixel_per_point);
|
||
};
|
||
|
||
var always_new = function (constructor) {
|
||
/**
|
||
* wrapper around contructor to avoid requiring `var a = new constructor()`
|
||
* useful for passing constructors as callbacks,
|
||
* not for programmer laziness.
|
||
* from https://programmers.stackexchange.com/questions/118798
|
||
*/
|
||
return function () {
|
||
var obj = Object.create(constructor.prototype);
|
||
constructor.apply(obj, arguments);
|
||
return obj;
|
||
};
|
||
};
|
||
|
||
var url_path_join = function () {
|
||
/**
|
||
* join a sequence of url components with '/'
|
||
*/
|
||
var url = '';
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
if (arguments[i] === '') {
|
||
continue;
|
||
}
|
||
if (url.length > 0 && url[url.length-1] != '/') {
|
||
url = url + '/' + arguments[i];
|
||
} else {
|
||
url = url + arguments[i];
|
||
}
|
||
}
|
||
url = url.replace(/\/\/+/, '/');
|
||
return url;
|
||
};
|
||
|
||
var url_path_split = function (path) {
|
||
/**
|
||
* Like os.path.split for URLs.
|
||
* Always returns two strings, the directory path and the base filename
|
||
*/
|
||
|
||
var idx = path.lastIndexOf('/');
|
||
if (idx === -1) {
|
||
return ['', path];
|
||
} else {
|
||
return [ path.slice(0, idx), path.slice(idx + 1) ];
|
||
}
|
||
};
|
||
|
||
var parse_url = function (url) {
|
||
/**
|
||
* an `a` element with an href allows attr-access to the parsed segments of a URL
|
||
* a = parse_url("http://localhost:8888/path/name#hash")
|
||
* a.protocol = "http:"
|
||
* a.host = "localhost:8888"
|
||
* a.hostname = "localhost"
|
||
* a.port = 8888
|
||
* a.pathname = "/path/name"
|
||
* a.hash = "#hash"
|
||
*/
|
||
var a = document.createElement("a");
|
||
a.href = url;
|
||
return a;
|
||
};
|
||
|
||
var encode_uri_components = function (uri) {
|
||
/**
|
||
* encode just the components of a multi-segment uri,
|
||
* leaving '/' separators
|
||
*/
|
||
return uri.split('/').map(encodeURIComponent).join('/');
|
||
};
|
||
|
||
var url_join_encode = function () {
|
||
/**
|
||
* join a sequence of url components with '/',
|
||
* encoding each component with encodeURIComponent
|
||
*/
|
||
return encode_uri_components(url_path_join.apply(null, arguments));
|
||
};
|
||
|
||
|
||
var splitext = function (filename) {
|
||
/**
|
||
* mimic Python os.path.splitext
|
||
* Returns ['base', '.ext']
|
||
*/
|
||
var idx = filename.lastIndexOf('.');
|
||
if (idx > 0) {
|
||
return [filename.slice(0, idx), filename.slice(idx)];
|
||
} else {
|
||
return [filename, ''];
|
||
}
|
||
};
|
||
|
||
|
||
var escape_html = function (text) {
|
||
/**
|
||
* escape text to HTML
|
||
*/
|
||
return $("<div/>").text(text).html();
|
||
};
|
||
|
||
|
||
var get_body_data = function(key) {
|
||
/**
|
||
* get a url-encoded item from body.data and decode it
|
||
* we should never have any encoded URLs anywhere else in code
|
||
* until we are building an actual request
|
||
*/
|
||
var val = $('body').data(key);
|
||
if (typeof val === 'undefined')
|
||
return val;
|
||
return decodeURIComponent(val);
|
||
};
|
||
|
||
var to_absolute_cursor_pos = function (cm, cursor) {
|
||
console.warn('`utils.to_absolute_cursor_pos(cm, pos)` is deprecated. Use `cm.indexFromPos(cursor)`');
|
||
return cm.indexFromPos(cursor);
|
||
};
|
||
|
||
var from_absolute_cursor_pos = function (cm, cursor_pos) {
|
||
console.warn('`utils.from_absolute_cursor_pos(cm, pos)` is deprecated. Use `cm.posFromIndex(index)`');
|
||
return cm.posFromIndex(cursor_pos);
|
||
};
|
||
|
||
// https://stackoverflow.com/questions/2400935/browser-detection-in-javascript
|
||
var browser = (function() {
|
||
if (typeof navigator === 'undefined') {
|
||
// navigator undefined in node
|
||
return 'None';
|
||
}
|
||
var N= navigator.appName, ua= navigator.userAgent, tem;
|
||
var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
|
||
if (M && (tem= ua.match(/version\/([\.\d]+)/i)) !== null) M[2]= tem[1];
|
||
M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
|
||
return M;
|
||
})();
|
||
|
||
// https://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
|
||
var platform = (function () {
|
||
if (typeof navigator === 'undefined') {
|
||
// navigator undefined in node
|
||
return 'None';
|
||
}
|
||
var OSName="None";
|
||
if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
|
||
if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
|
||
if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
|
||
if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
|
||
return OSName;
|
||
})();
|
||
|
||
var get_url_param = function (name) {
|
||
// get a URL parameter. I cannot believe we actually need this.
|
||
// Based on https://stackoverflow.com/a/25359264/938949
|
||
var match = new RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
|
||
if (match){
|
||
return decodeURIComponent(match[1] || '');
|
||
}
|
||
};
|
||
|
||
var is_or_has = function (a, b) {
|
||
/**
|
||
* Is b a child of a or a itself?
|
||
*/
|
||
return a.has(b).length !==0 || a.is(b);
|
||
};
|
||
|
||
var is_focused = function (e) {
|
||
/**
|
||
* Is element e, or one of its children focused?
|
||
*/
|
||
e = $(e);
|
||
var target = $(document.activeElement);
|
||
if (target.length > 0) {
|
||
if (is_or_has(e, target)) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
} else {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
var mergeopt = function(_class, options, overwrite){
|
||
options = options || {};
|
||
overwrite = overwrite || {};
|
||
return $.extend(true, {}, _class.options_default, options, overwrite);
|
||
};
|
||
|
||
var ajax_error_msg = function (jqXHR) {
|
||
/**
|
||
* Return a JSON error message if there is one,
|
||
* otherwise the basic HTTP status text.
|
||
*/
|
||
if (jqXHR.responseJSON && jqXHR.responseJSON.traceback) {
|
||
return jqXHR.responseJSON.traceback;
|
||
} else if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
|
||
return jqXHR.responseJSON.message;
|
||
} else {
|
||
return jqXHR.statusText;
|
||
}
|
||
};
|
||
var log_ajax_error = function (jqXHR, status, error) {
|
||
/**
|
||
* log ajax failures with informative messages
|
||
*/
|
||
var msg = "API request failed (" + jqXHR.status + "): ";
|
||
console.log(jqXHR);
|
||
msg += ajax_error_msg(jqXHR);
|
||
console.log(msg);
|
||
};
|
||
|
||
var requireCodeMirrorMode = function (mode, callback, errback) {
|
||
/**
|
||
* find a predefined mode or detect from CM metadata then
|
||
* require and callback with the resolvable mode string: mime or
|
||
* custom name
|
||
*/
|
||
|
||
var modename = (typeof mode == "string") ? mode :
|
||
mode.mode || mode.name;
|
||
|
||
// simplest, cheapest check by mode name: mode may also have config
|
||
if (CodeMirror.modes.hasOwnProperty(modename)) {
|
||
// return the full mode object, if it has a name
|
||
callback(mode.name ? mode : modename);
|
||
return;
|
||
}
|
||
|
||
// *somehow* get back a CM.modeInfo-like object that has .mode and
|
||
// .mime
|
||
var info = (mode && mode.mode && mode.mime && mode) ||
|
||
CodeMirror.findModeByName(modename) ||
|
||
CodeMirror.findModeByExtension(modename.split(".").slice(-1)[0]) ||
|
||
CodeMirror.findModeByMIME(modename) ||
|
||
{mode: modename, mime: modename};
|
||
|
||
requirejs([
|
||
// might want to use CodeMirror.modeURL here
|
||
['codemirror/mode', info.mode, info.mode].join('/'),
|
||
], function() {
|
||
// return the original mode, as from a kernelspec on first load
|
||
// or the mimetype, as for most highlighting
|
||
callback(mode.name ? mode : info.mime);
|
||
}, errback
|
||
);
|
||
};
|
||
|
||
/** Error type for wrapped XHR errors. */
|
||
var XHR_ERROR = 'XhrError';
|
||
|
||
/**
|
||
* Wraps an AJAX error as an Error object.
|
||
*/
|
||
var wrap_ajax_error = function (jqXHR, status, error) {
|
||
var wrapped_error = new Error(ajax_error_msg(jqXHR));
|
||
wrapped_error.name = XHR_ERROR;
|
||
// provide xhr response
|
||
wrapped_error.xhr = jqXHR;
|
||
wrapped_error.xhr_status = status;
|
||
wrapped_error.xhr_error = error;
|
||
return wrapped_error;
|
||
};
|
||
|
||
var ajax = function (url, settings) {
|
||
// like $.ajax, but ensure XSRF or Authorization header is set
|
||
if (typeof url === "object") {
|
||
// called with single argument: $.ajax({url: '...'})
|
||
settings = url;
|
||
url = settings.url;
|
||
delete settings.url;
|
||
}
|
||
settings = _add_auth_header(settings);
|
||
return $.ajax(url, settings);
|
||
};
|
||
|
||
var _get_cookie = function (name) {
|
||
// from tornado docs: http://www.tornadoweb.org/en/stable/guide/security.html
|
||
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
|
||
return r ? r[1] : undefined;
|
||
}
|
||
|
||
var _add_auth_header = function (settings) {
|
||
/**
|
||
* Adds auth header to jquery ajax settings
|
||
*/
|
||
settings = settings || {};
|
||
if (!settings.headers) {
|
||
settings.headers = {};
|
||
}
|
||
if (!settings.headers.Authorization) {
|
||
var xsrf_token = _get_cookie('_xsrf');
|
||
if (xsrf_token) {
|
||
settings.headers['X-XSRFToken'] = xsrf_token;
|
||
}
|
||
}
|
||
return settings;
|
||
};
|
||
|
||
var promising_ajax = function(url, settings) {
|
||
/**
|
||
* Like $.ajax, but returning an ES6 promise. success and error settings
|
||
* will be ignored.
|
||
*/
|
||
settings = settings || {};
|
||
return new Promise(function(resolve, reject) {
|
||
settings.success = function(data, status, jqXHR) {
|
||
resolve(data);
|
||
};
|
||
settings.error = function(jqXHR, status, error) {
|
||
log_ajax_error(jqXHR, status, error);
|
||
reject(wrap_ajax_error(jqXHR, status, error));
|
||
};
|
||
ajax(url, settings);
|
||
});
|
||
};
|
||
|
||
var WrappedError = function(message, error){
|
||
/**
|
||
* Wrappable Error class
|
||
*
|
||
* The Error class doesn't actually act on `this`. Instead it always
|
||
* returns a new instance of Error. Here we capture that instance so we
|
||
* can apply it's properties to `this`.
|
||
*/
|
||
var tmp = Error.apply(this, [message]);
|
||
|
||
// Copy the properties of the error over to this.
|
||
var properties = Object.getOwnPropertyNames(tmp);
|
||
for (var i = 0; i < properties.length; i++) {
|
||
this[properties[i]] = tmp[properties[i]];
|
||
}
|
||
|
||
// Keep a stack of the original error messages.
|
||
if (error instanceof WrappedError) {
|
||
this.error_stack = error.error_stack;
|
||
} else {
|
||
this.error_stack = [error];
|
||
}
|
||
this.error_stack.push(tmp);
|
||
|
||
return this;
|
||
};
|
||
|
||
WrappedError.prototype = Object.create(Error.prototype, {});
|
||
|
||
|
||
var load_class = function(class_name, module_name, registry) {
|
||
/**
|
||
* Tries to load a class
|
||
*
|
||
* Tries to load a class from a module using require.js, if a module
|
||
* is specified, otherwise tries to load a class from the global
|
||
* registry, if the global registry is provided.
|
||
*/
|
||
return new Promise(function(resolve, reject) {
|
||
|
||
// Try loading the view module using require.js
|
||
if (module_name) {
|
||
requirejs([module_name], function(module) {
|
||
if (module[class_name] === undefined) {
|
||
reject(new Error('Class '+class_name+' not found in module '+module_name));
|
||
} else {
|
||
resolve(module[class_name]);
|
||
}
|
||
}, reject);
|
||
} else {
|
||
if (registry && registry[class_name]) {
|
||
resolve(registry[class_name]);
|
||
} else {
|
||
reject(new Error('Class '+class_name+' not found in registry '));
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
var resolve_promises_dict = function(d) {
|
||
/**
|
||
* Resolve a promiseful dictionary.
|
||
* Returns a single Promise.
|
||
*/
|
||
var keys = Object.keys(d);
|
||
var values = [];
|
||
keys.forEach(function(key) {
|
||
values.push(d[key]);
|
||
});
|
||
return Promise.all(values).then(function(v) {
|
||
d = {};
|
||
for(var i=0; i<keys.length; i++) {
|
||
d[keys[i]] = v[i];
|
||
}
|
||
return d;
|
||
});
|
||
};
|
||
|
||
var reject = function(message, log) {
|
||
/**
|
||
* Creates a wrappable Promise rejection function.
|
||
*
|
||
* Creates a function that returns a Promise.reject with a new WrappedError
|
||
* that has the provided message and wraps the original error that
|
||
* caused the promise to reject.
|
||
*/
|
||
return function(error) {
|
||
var wrapped_error = new WrappedError(message, error);
|
||
if (log) {
|
||
console.error(message, " -- ", error);
|
||
}
|
||
return Promise.reject(wrapped_error);
|
||
};
|
||
};
|
||
|
||
var typeset = function(element, text) {
|
||
/**
|
||
* Apply MathJax rendering to an element, and optionally set its text
|
||
*
|
||
* If MathJax is not available, make no changes.
|
||
*
|
||
* Returns the output any number of typeset elements, or undefined if
|
||
* MathJax was not available.
|
||
*
|
||
* Parameters
|
||
* ----------
|
||
* element: Node, NodeList, or jQuery selection
|
||
* text: option string
|
||
*/
|
||
var $el = element.jquery ? element : $(element);
|
||
if(arguments.length > 1){
|
||
$el.text(text);
|
||
}
|
||
if(!window.MathJax){
|
||
return;
|
||
}
|
||
$el.map(function(){
|
||
// MathJax takes a DOM node: $.map makes `this` the context
|
||
MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]);
|
||
try {
|
||
MathJax.Hub.Queue(
|
||
["Require", MathJax.Ajax, "[MathJax]/extensions/TeX/AMSmath.js"],
|
||
function() { MathJax.InputJax.TeX.resetEquationNumbers(); }
|
||
);
|
||
} catch (e) {
|
||
console.error("Error queueing resetEquationNumbers:", e);
|
||
}
|
||
});
|
||
};
|
||
|
||
var parse_b64_data_uri = function(uri) {
|
||
/**
|
||
* Parses a base64 encoded data-uri to extract mimetype and the
|
||
* base64 string.
|
||
*
|
||
* For example, given 'data:image/png;base64,iVBORw', it will return
|
||
* ["image/png", "iVBORw"]
|
||
*
|
||
* Parameters
|
||
*/
|
||
// For performance reasons, the non-greedy ? qualifiers are crucial so
|
||
// that the matcher stops early on big blobs. Without them, it will try
|
||
// to match the whole blob which can take ages
|
||
var regex = /^data:(.+?\/.+?);base64,/;
|
||
var matches = uri.match(regex);
|
||
var mime = matches[1];
|
||
// matches[0] contains the whole data-uri prefix
|
||
var b64_data = uri.slice(matches[0].length);
|
||
return [mime, b64_data];
|
||
};
|
||
|
||
var time = {};
|
||
time.milliseconds = {};
|
||
time.milliseconds.s = 1000;
|
||
time.milliseconds.m = 60 * time.milliseconds.s;
|
||
time.milliseconds.h = 60 * time.milliseconds.m;
|
||
time.milliseconds.d = 24 * time.milliseconds.h;
|
||
|
||
time.thresholds = {
|
||
// moment.js thresholds in milliseconds
|
||
s: moment.relativeTimeThreshold('s') * time.milliseconds.s,
|
||
m: moment.relativeTimeThreshold('m') * time.milliseconds.m,
|
||
h: moment.relativeTimeThreshold('h') * time.milliseconds.h,
|
||
d: moment.relativeTimeThreshold('d') * time.milliseconds.d,
|
||
};
|
||
|
||
time.timeout_from_dt = function (dt) {
|
||
/** compute a timeout based on dt
|
||
|
||
input and output both in milliseconds
|
||
|
||
use moment's relative time thresholds:
|
||
|
||
- 10 seconds if in 'seconds ago' territory
|
||
- 1 minute if in 'minutes ago'
|
||
- 1 hour otherwise
|
||
*/
|
||
if (dt < time.thresholds.s) {
|
||
return 10 * time.milliseconds.s;
|
||
} else if (dt < time.thresholds.m) {
|
||
return time.milliseconds.m;
|
||
} else {
|
||
return time.milliseconds.h;
|
||
}
|
||
};
|
||
|
||
var format_datetime = function(date) {
|
||
var text = moment(date).fromNow();
|
||
return text === 'a few seconds ago' ? 'seconds ago' : text;
|
||
};
|
||
|
||
var datetime_sort_helper = function(a, b, order) {
|
||
if (moment(a).isBefore(moment(b))) {
|
||
return (order == 1) ? -1 : 1;
|
||
} else if (moment(a).isSame(moment(b))) {
|
||
return 0;
|
||
} else {
|
||
return (order == 1) ? 1 : -1;
|
||
}
|
||
};
|
||
|
||
/**
|
||
source: https://github.com/sindresorhus/pretty-bytes
|
||
The MIT License (MIT)
|
||
|
||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||
|
||
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.
|
||
**/
|
||
var format_filesize = function(num) {
|
||
if (num === undefined || num === null)
|
||
return;
|
||
|
||
var UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||
|
||
if (!Number.isFinite(num)) {
|
||
console.error("Expected finite number, got ", typeof(num) + ": " + num);
|
||
}
|
||
|
||
var neg = num < 0;
|
||
|
||
if (neg) {
|
||
num = -num;
|
||
}
|
||
|
||
if (num < 1) {
|
||
return (neg ? '-' : '') + num + ' B';
|
||
}
|
||
|
||
var exponent = Math.min(Math.floor(Math.log10(num) / 3), UNITS.length - 1);
|
||
var numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3));
|
||
var unit = UNITS[exponent];
|
||
|
||
return (neg ? '-' : '') + numStr + ' ' + unit;
|
||
}
|
||
|
||
// javascript stores text as utf16 and string indices use "code units",
|
||
// which stores high-codepoint characters as "surrogate pairs",
|
||
// which occupy two indices in the javascript string.
|
||
// We need to translate cursor_pos in the protocol (in characters)
|
||
// to js offset (with surrogate pairs taking two spots).
|
||
function js_idx_to_char_idx (js_idx, text) {
|
||
var char_idx = js_idx;
|
||
for (var i = 0; i + 1 < text.length && i < js_idx; i++) {
|
||
var char_code = text.charCodeAt(i);
|
||
// check for surrogate pair
|
||
if (char_code >= 0xD800 && char_code <= 0xDBFF) {
|
||
var next_char_code = text.charCodeAt(i+1);
|
||
if (next_char_code >= 0xDC00 && next_char_code <= 0xDFFF) {
|
||
char_idx--;
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
return char_idx;
|
||
}
|
||
|
||
function char_idx_to_js_idx (char_idx, text) {
|
||
var js_idx = char_idx;
|
||
for (var i = 0; i + 1 < text.length && i < js_idx; i++) {
|
||
var char_code = text.charCodeAt(i);
|
||
// check for surrogate pair
|
||
if (char_code >= 0xD800 && char_code <= 0xDBFF) {
|
||
var next_char_code = text.charCodeAt(i+1);
|
||
if (next_char_code >= 0xDC00 && next_char_code <= 0xDFFF) {
|
||
js_idx++;
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
return js_idx;
|
||
}
|
||
|
||
if ('𝐚'.length === 1) {
|
||
// If javascript fixes string indices of non-BMP characters,
|
||
// don't keep shifting offsets to compensate for surrogate pairs
|
||
char_idx_to_js_idx = js_idx_to_char_idx = function (idx, text) { return idx; };
|
||
}
|
||
|
||
// Test if a drag'n'drop event contains a file (as opposed to an HTML
|
||
// element/text from the document)
|
||
var dnd_contain_file = function(event) {
|
||
// As per the HTML5 drag'n'drop spec, the dataTransfer.types should
|
||
// contain one "Files" type if a file is being dragged
|
||
// https://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#dom-datatransfer-types
|
||
if (event.dataTransfer.types) {
|
||
for (var i = 0; i < event.dataTransfer.types.length; i++) {
|
||
if (event.dataTransfer.types[i] == "Files") {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
var throttle = function(fn, time) {
|
||
var pending = null;
|
||
|
||
return function () {
|
||
if (pending) return;
|
||
pending = setTimeout(run, time);
|
||
|
||
return function () {
|
||
clearTimeout(pending);
|
||
pending = null;
|
||
}
|
||
}
|
||
|
||
function run () {
|
||
pending = null;
|
||
fn();
|
||
}
|
||
}
|
||
|
||
var change_favicon = function (src) {
|
||
var link = document.createElement('link'),
|
||
oldLink = document.getElementById('favicon');
|
||
link.id = 'favicon';
|
||
link.type = 'image/x-icon';
|
||
link.rel = 'shortcut icon';
|
||
link.href = utils.url_path_join(utils.get_body_data('baseUrl'), src);
|
||
if (oldLink && (link.href === oldLink.href)) {
|
||
// This favicon is already set, don't modify the DOM.
|
||
return;
|
||
}
|
||
if (oldLink) document.head.removeChild(oldLink);
|
||
document.head.appendChild(link);
|
||
};
|
||
|
||
var utils = {
|
||
throttle: throttle,
|
||
is_loaded: is_loaded,
|
||
load_extension: load_extension,
|
||
load_extensions: load_extensions,
|
||
filter_extensions: filter_extensions,
|
||
load_extensions_from_config: load_extensions_from_config,
|
||
regex_split : regex_split,
|
||
uuid : uuid,
|
||
fixConsole : fixConsole,
|
||
fixCarriageReturn : fixCarriageReturn,
|
||
fixBackspace : fixBackspace,
|
||
fixOverwrittenChars: fixOverwrittenChars,
|
||
autoLinkUrls : autoLinkUrls,
|
||
points_to_pixels : points_to_pixels,
|
||
get_body_data : get_body_data,
|
||
parse_url : parse_url,
|
||
url_path_split : url_path_split,
|
||
url_path_join : url_path_join,
|
||
url_join_encode : url_join_encode,
|
||
encode_uri_components : encode_uri_components,
|
||
splitext : splitext,
|
||
escape_html : escape_html,
|
||
always_new : always_new,
|
||
to_absolute_cursor_pos : to_absolute_cursor_pos,
|
||
from_absolute_cursor_pos : from_absolute_cursor_pos,
|
||
browser : browser,
|
||
platform: platform,
|
||
get_url_param: get_url_param,
|
||
is_or_has : is_or_has,
|
||
is_focused : is_focused,
|
||
mergeopt: mergeopt,
|
||
requireCodeMirrorMode : requireCodeMirrorMode,
|
||
XHR_ERROR : XHR_ERROR,
|
||
ajax : ajax,
|
||
ajax_error_msg : ajax_error_msg,
|
||
log_ajax_error : log_ajax_error,
|
||
wrap_ajax_error : wrap_ajax_error,
|
||
promising_ajax : promising_ajax,
|
||
WrappedError: WrappedError,
|
||
load_class: load_class,
|
||
resolve_promises_dict: resolve_promises_dict,
|
||
reject: reject,
|
||
typeset: typeset,
|
||
parse_b64_data_uri: parse_b64_data_uri,
|
||
time: time,
|
||
format_datetime: format_datetime,
|
||
format_filesize: format_filesize,
|
||
datetime_sort_helper: datetime_sort_helper,
|
||
dnd_contain_file: dnd_contain_file,
|
||
js_idx_to_char_idx: js_idx_to_char_idx,
|
||
char_idx_to_js_idx: char_idx_to_js_idx,
|
||
_ansispan:_ansispan,
|
||
change_favicon: change_favicon
|
||
};
|
||
|
||
return utils;
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
// Give us an object to bind all events to. This object should be created
|
||
// before all other objects so it exists when others register event handlers.
|
||
// To register an event handler:
|
||
//
|
||
// requirejs(['base/js/events'], function (events) {
|
||
// events.on("event.Namespace", function () { do_stuff(); });
|
||
// });
|
||
|
||
define('base/js/events',['jquery', 'base/js/namespace'], function($, Jupyter) {
|
||
"use strict";
|
||
|
||
// Events singleton
|
||
if (!window._Events) {
|
||
window._Events = function () {};
|
||
window._events = new window._Events();
|
||
}
|
||
|
||
// Backwards compatibility.
|
||
Jupyter.Events = window._Events;
|
||
Jupyter.events = window._events;
|
||
|
||
var events = $([window._events]);
|
||
|
||
// catch and log errors in triggered events
|
||
events._original_trigger = events.trigger;
|
||
events.trigger = function (name, data) {
|
||
try {
|
||
this._original_trigger.apply(this, arguments);
|
||
} catch (e) {
|
||
console.error("Exception in event handler for " + name, e, arguments);
|
||
}
|
||
}
|
||
return events;
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('base/js/page',[
|
||
'jquery',
|
||
'base/js/events',
|
||
], function($, events){
|
||
"use strict";
|
||
|
||
var Page = function (header_div_selector, site_div_selector) {
|
||
/**
|
||
* Constructor
|
||
*
|
||
* Parameters
|
||
* header_div_selector: string
|
||
* site_div_selector: string
|
||
*/
|
||
this.header_div_element = $(header_div_selector || 'div#header');
|
||
this.site_div_element = $(site_div_selector || 'div#site');
|
||
|
||
this.bind_events();
|
||
};
|
||
|
||
Page.prototype.bind_events = function () {
|
||
// resize site on:
|
||
// - window resize
|
||
// - header change
|
||
// - page load
|
||
var _handle_resize = $.proxy(this._resize_site, this);
|
||
|
||
$(window).resize(_handle_resize);
|
||
|
||
// On document ready, resize codemirror.
|
||
$(document).ready(_handle_resize);
|
||
events.on('resize-header.Page', _handle_resize);
|
||
};
|
||
|
||
Page.prototype.show = function () {
|
||
/**
|
||
* The header and site divs start out hidden to prevent FLOUC.
|
||
* Main scripts should call this method after styling everything.
|
||
*/
|
||
this.show_header();
|
||
this.show_site();
|
||
};
|
||
|
||
Page.prototype.show_header = function () {
|
||
/**
|
||
* The header and site divs start out hidden to prevent FLOUC.
|
||
* Main scripts should call this method after styling everything.
|
||
*/
|
||
this.header_div_element.css('display','block');
|
||
};
|
||
|
||
Page.prototype.show_site = function () {
|
||
/**
|
||
* The header and site divs start out hidden to prevent FLOUC.
|
||
* Main scripts should call this method after styling everything.
|
||
*/
|
||
this.site_div_element.css('display', 'block');
|
||
this._resize_site();
|
||
};
|
||
|
||
Page.prototype._resize_site = function(e) {
|
||
/**
|
||
* Update the site's size.
|
||
*/
|
||
|
||
// In the case an event is passed in, only trigger if the event does
|
||
// *not* have a target DOM node (i.e., it is not bubbling up). See
|
||
// https://bugs.jquery.com/ticket/9841#comment:8
|
||
if (!(e && e.target && e.target.tagName)) {
|
||
$('div#site').height($(window).height() - $('#header').height());
|
||
}
|
||
};
|
||
|
||
return {'Page': Page};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('services/config',[
|
||
'base/js/utils',
|
||
],
|
||
function(utils) {
|
||
"use strict";
|
||
var ConfigSection = function(section_name, options) {
|
||
this.section_name = section_name;
|
||
this.base_url = options.base_url;
|
||
this.data = {};
|
||
|
||
var that = this;
|
||
|
||
/* .loaded is a promise, fulfilled the first time the config is loaded
|
||
* from the server. Code can do:
|
||
* conf.loaded.then(function() { ... using conf.data ... });
|
||
*/
|
||
this._one_load_finished = false;
|
||
this.loaded = new Promise(function(resolve, reject) {
|
||
that._finish_firstload = resolve;
|
||
});
|
||
};
|
||
|
||
ConfigSection.prototype.api_url = function() {
|
||
return utils.url_path_join(this.base_url, 'api/config',
|
||
utils.encode_uri_components(this.section_name));
|
||
};
|
||
|
||
ConfigSection.prototype._load_done = function() {
|
||
if (!this._one_load_finished) {
|
||
this._one_load_finished = true;
|
||
this._finish_firstload();
|
||
}
|
||
};
|
||
|
||
ConfigSection.prototype.load = function() {
|
||
var that = this;
|
||
return utils.promising_ajax(this.api_url(), {
|
||
cache: false,
|
||
type: "GET",
|
||
dataType: "json",
|
||
}).then(function(data) {
|
||
that.data = data;
|
||
that._load_done();
|
||
return data;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Modify the config values stored. Update the local data immediately,
|
||
* send the change to the server, and use the updated data from the server
|
||
* when the reply comes.
|
||
*/
|
||
ConfigSection.prototype.update = function(newdata) {
|
||
$.extend(true, this.data, newdata); // true -> recursive update
|
||
|
||
var that = this;
|
||
return utils.promising_ajax(this.api_url(), {
|
||
processData: false,
|
||
type : "PATCH",
|
||
data: JSON.stringify(newdata),
|
||
dataType : "json",
|
||
contentType: 'application/json',
|
||
}).then(function(data) {
|
||
that.data = data;
|
||
that._load_done();
|
||
return data;
|
||
});
|
||
};
|
||
|
||
|
||
var ConfigWithDefaults = function(section, defaults, classname) {
|
||
this.section = section;
|
||
this.defaults = defaults;
|
||
this.classname = classname;
|
||
};
|
||
|
||
ConfigWithDefaults.prototype._class_data = function() {
|
||
if (this.classname) {
|
||
return this.section.data[this.classname] || {};
|
||
} else {
|
||
return this.section.data;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Wait for config to have loaded, then get a value or the default.
|
||
* Returns a promise.
|
||
*/
|
||
ConfigWithDefaults.prototype.get = function(key) {
|
||
var that = this;
|
||
return this.section.loaded.then(function() {
|
||
return that.get_sync(key);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Return a config value. If config is not yet loaded, return the default
|
||
* instead of waiting for it to load.
|
||
*/
|
||
ConfigWithDefaults.prototype.get_sync = function(key) {
|
||
var data = this._class_data();
|
||
if (key === undefined) {
|
||
// no key specified, return full config data
|
||
return $.extend(true, {}, this.defaults, data);
|
||
}
|
||
|
||
var value = data[key];
|
||
if (value !== undefined) {
|
||
if (typeof value == 'object') {
|
||
// merge with defaults if it's an object
|
||
return $.extend(true, {}, this.defaults[key], value);
|
||
} else {
|
||
return value;
|
||
}
|
||
}
|
||
return this.defaults[key];
|
||
};
|
||
|
||
/**
|
||
* Set a config value. Send the update to the server, and change our
|
||
* local copy of the data immediately.
|
||
* Returns a promise which is fulfilled when the server replies to the
|
||
* change.
|
||
*/
|
||
ConfigWithDefaults.prototype.set = function(key, value) {
|
||
var d = {};
|
||
d[key] = value;
|
||
if (this.classname) {
|
||
var d2 = {};
|
||
d2[this.classname] = d;
|
||
return this.section.update(d2);
|
||
} else {
|
||
return this.section.update(d);
|
||
}
|
||
};
|
||
|
||
return {ConfigSection: ConfigSection,
|
||
ConfigWithDefaults: ConfigWithDefaults,
|
||
};
|
||
|
||
});
|
||
|
||
/**
|
||
* @preserve jed.js https://github.com/SlexAxton/Jed
|
||
*/
|
||
/*
|
||
-----------
|
||
A gettext compatible i18n library for modern JavaScript Applications
|
||
|
||
by Alex Sexton - AlexSexton [at] gmail - @SlexAxton
|
||
|
||
MIT License
|
||
|
||
A jQuery Foundation project - requires CLA to contribute -
|
||
https://contribute.jquery.org/CLA/
|
||
|
||
|
||
|
||
Jed offers the entire applicable GNU gettext spec'd set of
|
||
functions, but also offers some nicer wrappers around them.
|
||
The api for gettext was written for a language with no function
|
||
overloading, so Jed allows a little more of that.
|
||
|
||
Many thanks to Joshua I. Miller - unrtst@cpan.org - who wrote
|
||
gettext.js back in 2008. I was able to vet a lot of my ideas
|
||
against his. I also made sure Jed passed against his tests
|
||
in order to offer easy upgrades -- jsgettext.berlios.de
|
||
*/
|
||
(function (root, undef) {
|
||
|
||
// Set up some underscore-style functions, if you already have
|
||
// underscore, feel free to delete this section, and use it
|
||
// directly, however, the amount of functions used doesn't
|
||
// warrant having underscore as a full dependency.
|
||
// Underscore 1.3.0 was used to port and is licensed
|
||
// under the MIT License by Jeremy Ashkenas.
|
||
var ArrayProto = Array.prototype,
|
||
ObjProto = Object.prototype,
|
||
slice = ArrayProto.slice,
|
||
hasOwnProp = ObjProto.hasOwnProperty,
|
||
nativeForEach = ArrayProto.forEach,
|
||
breaker = {};
|
||
|
||
// We're not using the OOP style _ so we don't need the
|
||
// extra level of indirection. This still means that you
|
||
// sub out for real `_` though.
|
||
var _ = {
|
||
forEach : function( obj, iterator, context ) {
|
||
var i, l, key;
|
||
if ( obj === null ) {
|
||
return;
|
||
}
|
||
|
||
if ( nativeForEach && obj.forEach === nativeForEach ) {
|
||
obj.forEach( iterator, context );
|
||
}
|
||
else if ( obj.length === +obj.length ) {
|
||
for ( i = 0, l = obj.length; i < l; i++ ) {
|
||
if ( i in obj && iterator.call( context, obj[i], i, obj ) === breaker ) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
for ( key in obj) {
|
||
if ( hasOwnProp.call( obj, key ) ) {
|
||
if ( iterator.call (context, obj[key], key, obj ) === breaker ) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
extend : function( obj ) {
|
||
this.forEach( slice.call( arguments, 1 ), function ( source ) {
|
||
for ( var prop in source ) {
|
||
obj[prop] = source[prop];
|
||
}
|
||
});
|
||
return obj;
|
||
}
|
||
};
|
||
// END Miniature underscore impl
|
||
|
||
// Jed is a constructor function
|
||
var Jed = function ( options ) {
|
||
// Some minimal defaults
|
||
this.defaults = {
|
||
"locale_data" : {
|
||
"messages" : {
|
||
"" : {
|
||
"domain" : "messages",
|
||
"lang" : "en",
|
||
"plural_forms" : "nplurals=2; plural=(n != 1);"
|
||
}
|
||
// There are no default keys, though
|
||
}
|
||
},
|
||
// The default domain if one is missing
|
||
"domain" : "messages",
|
||
// enable debug mode to log untranslated strings to the console
|
||
"debug" : false
|
||
};
|
||
|
||
// Mix in the sent options with the default options
|
||
this.options = _.extend( {}, this.defaults, options );
|
||
this.textdomain( this.options.domain );
|
||
|
||
if ( options.domain && ! this.options.locale_data[ this.options.domain ] ) {
|
||
throw new Error('Text domain set to non-existent domain: `' + options.domain + '`');
|
||
}
|
||
};
|
||
|
||
// The gettext spec sets this character as the default
|
||
// delimiter for context lookups.
|
||
// e.g.: context\u0004key
|
||
// If your translation company uses something different,
|
||
// just change this at any time and it will use that instead.
|
||
Jed.context_delimiter = String.fromCharCode( 4 );
|
||
|
||
function getPluralFormFunc ( plural_form_string ) {
|
||
return Jed.PF.compile( plural_form_string || "nplurals=2; plural=(n != 1);");
|
||
}
|
||
|
||
function Chain( key, i18n ){
|
||
this._key = key;
|
||
this._i18n = i18n;
|
||
}
|
||
|
||
// Create a chainable api for adding args prettily
|
||
_.extend( Chain.prototype, {
|
||
onDomain : function ( domain ) {
|
||
this._domain = domain;
|
||
return this;
|
||
},
|
||
withContext : function ( context ) {
|
||
this._context = context;
|
||
return this;
|
||
},
|
||
ifPlural : function ( num, pkey ) {
|
||
this._val = num;
|
||
this._pkey = pkey;
|
||
return this;
|
||
},
|
||
fetch : function ( sArr ) {
|
||
if ( {}.toString.call( sArr ) != '[object Array]' ) {
|
||
sArr = [].slice.call(arguments, 0);
|
||
}
|
||
return ( sArr && sArr.length ? Jed.sprintf : function(x){ return x; } )(
|
||
this._i18n.dcnpgettext(this._domain, this._context, this._key, this._pkey, this._val),
|
||
sArr
|
||
);
|
||
}
|
||
});
|
||
|
||
// Add functions to the Jed prototype.
|
||
// These will be the functions on the object that's returned
|
||
// from creating a `new Jed()`
|
||
// These seem redundant, but they gzip pretty well.
|
||
_.extend( Jed.prototype, {
|
||
// The sexier api start point
|
||
translate : function ( key ) {
|
||
return new Chain( key, this );
|
||
},
|
||
|
||
textdomain : function ( domain ) {
|
||
if ( ! domain ) {
|
||
return this._textdomain;
|
||
}
|
||
this._textdomain = domain;
|
||
},
|
||
|
||
gettext : function ( key ) {
|
||
return this.dcnpgettext.call( this, undef, undef, key );
|
||
},
|
||
|
||
dgettext : function ( domain, key ) {
|
||
return this.dcnpgettext.call( this, domain, undef, key );
|
||
},
|
||
|
||
dcgettext : function ( domain , key /*, category */ ) {
|
||
// Ignores the category anyways
|
||
return this.dcnpgettext.call( this, domain, undef, key );
|
||
},
|
||
|
||
ngettext : function ( skey, pkey, val ) {
|
||
return this.dcnpgettext.call( this, undef, undef, skey, pkey, val );
|
||
},
|
||
|
||
dngettext : function ( domain, skey, pkey, val ) {
|
||
return this.dcnpgettext.call( this, domain, undef, skey, pkey, val );
|
||
},
|
||
|
||
dcngettext : function ( domain, skey, pkey, val/*, category */) {
|
||
return this.dcnpgettext.call( this, domain, undef, skey, pkey, val );
|
||
},
|
||
|
||
pgettext : function ( context, key ) {
|
||
return this.dcnpgettext.call( this, undef, context, key );
|
||
},
|
||
|
||
dpgettext : function ( domain, context, key ) {
|
||
return this.dcnpgettext.call( this, domain, context, key );
|
||
},
|
||
|
||
dcpgettext : function ( domain, context, key/*, category */) {
|
||
return this.dcnpgettext.call( this, domain, context, key );
|
||
},
|
||
|
||
npgettext : function ( context, skey, pkey, val ) {
|
||
return this.dcnpgettext.call( this, undef, context, skey, pkey, val );
|
||
},
|
||
|
||
dnpgettext : function ( domain, context, skey, pkey, val ) {
|
||
return this.dcnpgettext.call( this, domain, context, skey, pkey, val );
|
||
},
|
||
|
||
// The most fully qualified gettext function. It has every option.
|
||
// Since it has every option, we can use it from every other method.
|
||
// This is the bread and butter.
|
||
// Technically there should be one more argument in this function for 'Category',
|
||
// but since we never use it, we might as well not waste the bytes to define it.
|
||
dcnpgettext : function ( domain, context, singular_key, plural_key, val ) {
|
||
// Set some defaults
|
||
|
||
plural_key = plural_key || singular_key;
|
||
|
||
// Use the global domain default if one
|
||
// isn't explicitly passed in
|
||
domain = domain || this._textdomain;
|
||
|
||
var fallback;
|
||
|
||
// Handle special cases
|
||
|
||
// No options found
|
||
if ( ! this.options ) {
|
||
// There's likely something wrong, but we'll return the correct key for english
|
||
// We do this by instantiating a brand new Jed instance with the default set
|
||
// for everything that could be broken.
|
||
fallback = new Jed();
|
||
return fallback.dcnpgettext.call( fallback, undefined, undefined, singular_key, plural_key, val );
|
||
}
|
||
|
||
// No translation data provided
|
||
if ( ! this.options.locale_data ) {
|
||
throw new Error('No locale data provided.');
|
||
}
|
||
|
||
if ( ! this.options.locale_data[ domain ] ) {
|
||
throw new Error('Domain `' + domain + '` was not found.');
|
||
}
|
||
|
||
if ( ! this.options.locale_data[ domain ][ "" ] ) {
|
||
throw new Error('No locale meta information provided.');
|
||
}
|
||
|
||
// Make sure we have a truthy key. Otherwise we might start looking
|
||
// into the empty string key, which is the options for the locale
|
||
// data.
|
||
if ( ! singular_key ) {
|
||
throw new Error('No translation key found.');
|
||
}
|
||
|
||
var key = context ? context + Jed.context_delimiter + singular_key : singular_key,
|
||
locale_data = this.options.locale_data,
|
||
dict = locale_data[ domain ],
|
||
defaultConf = (locale_data.messages || this.defaults.locale_data.messages)[""],
|
||
pluralForms = dict[""].plural_forms || dict[""]["Plural-Forms"] || dict[""]["plural-forms"] || defaultConf.plural_forms || defaultConf["Plural-Forms"] || defaultConf["plural-forms"],
|
||
val_list,
|
||
res;
|
||
|
||
var val_idx;
|
||
if (val === undefined) {
|
||
// No value passed in; assume singular key lookup.
|
||
val_idx = 0;
|
||
|
||
} else {
|
||
// Value has been passed in; use plural-forms calculations.
|
||
|
||
// Handle invalid numbers, but try casting strings for good measure
|
||
if ( typeof val != 'number' ) {
|
||
val = parseInt( val, 10 );
|
||
|
||
if ( isNaN( val ) ) {
|
||
throw new Error('The number that was passed in is not a number.');
|
||
}
|
||
}
|
||
|
||
val_idx = getPluralFormFunc(pluralForms)(val);
|
||
}
|
||
|
||
// Throw an error if a domain isn't found
|
||
if ( ! dict ) {
|
||
throw new Error('No domain named `' + domain + '` could be found.');
|
||
}
|
||
|
||
val_list = dict[ key ];
|
||
|
||
// If there is no match, then revert back to
|
||
// english style singular/plural with the keys passed in.
|
||
if ( ! val_list || val_idx > val_list.length ) {
|
||
if (this.options.missing_key_callback) {
|
||
this.options.missing_key_callback(key, domain);
|
||
}
|
||
res = [ singular_key, plural_key ];
|
||
|
||
// collect untranslated strings
|
||
if (this.options.debug===true) {
|
||
console.log(res[ getPluralFormFunc(pluralForms)( val ) ]);
|
||
}
|
||
return res[ getPluralFormFunc()( val ) ];
|
||
}
|
||
|
||
res = val_list[ val_idx ];
|
||
|
||
// This includes empty strings on purpose
|
||
if ( ! res ) {
|
||
res = [ singular_key, plural_key ];
|
||
return res[ getPluralFormFunc()( val ) ];
|
||
}
|
||
return res;
|
||
}
|
||
});
|
||
|
||
|
||
// We add in sprintf capabilities for post translation value interolation
|
||
// This is not internally used, so you can remove it if you have this
|
||
// available somewhere else, or want to use a different system.
|
||
|
||
// We _slightly_ modify the normal sprintf behavior to more gracefully handle
|
||
// undefined values.
|
||
|
||
/**
|
||
sprintf() for JavaScript 0.7-beta1
|
||
http://www.diveintojavascript.com/projects/javascript-sprintf
|
||
|
||
Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
|
||
All rights reserved.
|
||
|
||
Redistribution and use in source and binary forms, with or without
|
||
modification, are permitted provided that the following conditions are met:
|
||
* Redistributions of source code must retain the above copyright
|
||
notice, this list of conditions and the following disclaimer.
|
||
* Redistributions in binary form must reproduce the above copyright
|
||
notice, this list of conditions and the following disclaimer in the
|
||
documentation and/or other materials provided with the distribution.
|
||
* Neither the name of sprintf() for JavaScript nor the
|
||
names of its contributors may be used to endorse or promote products
|
||
derived from this software without specific prior written permission.
|
||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||
DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
|
||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
*/
|
||
var sprintf = (function() {
|
||
function get_type(variable) {
|
||
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
|
||
}
|
||
function str_repeat(input, multiplier) {
|
||
for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
|
||
return output.join('');
|
||
}
|
||
|
||
var str_format = function() {
|
||
if (!str_format.cache.hasOwnProperty(arguments[0])) {
|
||
str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
|
||
}
|
||
return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
|
||
};
|
||
|
||
str_format.format = function(parse_tree, argv) {
|
||
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
|
||
for (i = 0; i < tree_length; i++) {
|
||
node_type = get_type(parse_tree[i]);
|
||
if (node_type === 'string') {
|
||
output.push(parse_tree[i]);
|
||
}
|
||
else if (node_type === 'array') {
|
||
match = parse_tree[i]; // convenience purposes only
|
||
if (match[2]) { // keyword argument
|
||
arg = argv[cursor];
|
||
for (k = 0; k < match[2].length; k++) {
|
||
if (!arg.hasOwnProperty(match[2][k])) {
|
||
throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
|
||
}
|
||
arg = arg[match[2][k]];
|
||
}
|
||
}
|
||
else if (match[1]) { // positional argument (explicit)
|
||
arg = argv[match[1]];
|
||
}
|
||
else { // positional argument (implicit)
|
||
arg = argv[cursor++];
|
||
}
|
||
|
||
if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
|
||
throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
|
||
}
|
||
|
||
// Jed EDIT
|
||
if ( typeof arg == 'undefined' || arg === null ) {
|
||
arg = '';
|
||
}
|
||
// Jed EDIT
|
||
|
||
switch (match[8]) {
|
||
case 'b': arg = arg.toString(2); break;
|
||
case 'c': arg = String.fromCharCode(arg); break;
|
||
case 'd': arg = parseInt(arg, 10); break;
|
||
case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
|
||
case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
|
||
case 'o': arg = arg.toString(8); break;
|
||
case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
|
||
case 'u': arg = Math.abs(arg); break;
|
||
case 'x': arg = arg.toString(16); break;
|
||
case 'X': arg = arg.toString(16).toUpperCase(); break;
|
||
}
|
||
arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
|
||
pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
|
||
pad_length = match[6] - String(arg).length;
|
||
pad = match[6] ? str_repeat(pad_character, pad_length) : '';
|
||
output.push(match[5] ? arg + pad : pad + arg);
|
||
}
|
||
}
|
||
return output.join('');
|
||
};
|
||
|
||
str_format.cache = {};
|
||
|
||
str_format.parse = function(fmt) {
|
||
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
|
||
while (_fmt) {
|
||
if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
|
||
parse_tree.push(match[0]);
|
||
}
|
||
else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
|
||
parse_tree.push('%');
|
||
}
|
||
else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
|
||
if (match[2]) {
|
||
arg_names |= 1;
|
||
var field_list = [], replacement_field = match[2], field_match = [];
|
||
if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
|
||
field_list.push(field_match[1]);
|
||
while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
|
||
if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
|
||
field_list.push(field_match[1]);
|
||
}
|
||
else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
|
||
field_list.push(field_match[1]);
|
||
}
|
||
else {
|
||
throw('[sprintf] huh?');
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
throw('[sprintf] huh?');
|
||
}
|
||
match[2] = field_list;
|
||
}
|
||
else {
|
||
arg_names |= 2;
|
||
}
|
||
if (arg_names === 3) {
|
||
throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
|
||
}
|
||
parse_tree.push(match);
|
||
}
|
||
else {
|
||
throw('[sprintf] huh?');
|
||
}
|
||
_fmt = _fmt.substring(match[0].length);
|
||
}
|
||
return parse_tree;
|
||
};
|
||
|
||
return str_format;
|
||
})();
|
||
|
||
var vsprintf = function(fmt, argv) {
|
||
argv.unshift(fmt);
|
||
return sprintf.apply(null, argv);
|
||
};
|
||
|
||
Jed.parse_plural = function ( plural_forms, n ) {
|
||
plural_forms = plural_forms.replace(/n/g, n);
|
||
return Jed.parse_expression(plural_forms);
|
||
};
|
||
|
||
Jed.sprintf = function ( fmt, args ) {
|
||
if ( {}.toString.call( args ) == '[object Array]' ) {
|
||
return vsprintf( fmt, [].slice.call(args) );
|
||
}
|
||
return sprintf.apply(this, [].slice.call(arguments) );
|
||
};
|
||
|
||
Jed.prototype.sprintf = function () {
|
||
return Jed.sprintf.apply(this, arguments);
|
||
};
|
||
// END sprintf Implementation
|
||
|
||
// Start the Plural forms section
|
||
// This is a full plural form expression parser. It is used to avoid
|
||
// running 'eval' or 'new Function' directly against the plural
|
||
// forms.
|
||
//
|
||
// This can be important if you get translations done through a 3rd
|
||
// party vendor. I encourage you to use this instead, however, I
|
||
// also will provide a 'precompiler' that you can use at build time
|
||
// to output valid/safe function representations of the plural form
|
||
// expressions. This means you can build this code out for the most
|
||
// part.
|
||
Jed.PF = {};
|
||
|
||
Jed.PF.parse = function ( p ) {
|
||
var plural_str = Jed.PF.extractPluralExpr( p );
|
||
return Jed.PF.parser.parse.call(Jed.PF.parser, plural_str);
|
||
};
|
||
|
||
Jed.PF.compile = function ( p ) {
|
||
// Handle trues and falses as 0 and 1
|
||
function imply( val ) {
|
||
return (val === true ? 1 : val ? val : 0);
|
||
}
|
||
|
||
var ast = Jed.PF.parse( p );
|
||
return function ( n ) {
|
||
return imply( Jed.PF.interpreter( ast )( n ) );
|
||
};
|
||
};
|
||
|
||
Jed.PF.interpreter = function ( ast ) {
|
||
return function ( n ) {
|
||
var res;
|
||
switch ( ast.type ) {
|
||
case 'GROUP':
|
||
return Jed.PF.interpreter( ast.expr )( n );
|
||
case 'TERNARY':
|
||
if ( Jed.PF.interpreter( ast.expr )( n ) ) {
|
||
return Jed.PF.interpreter( ast.truthy )( n );
|
||
}
|
||
return Jed.PF.interpreter( ast.falsey )( n );
|
||
case 'OR':
|
||
return Jed.PF.interpreter( ast.left )( n ) || Jed.PF.interpreter( ast.right )( n );
|
||
case 'AND':
|
||
return Jed.PF.interpreter( ast.left )( n ) && Jed.PF.interpreter( ast.right )( n );
|
||
case 'LT':
|
||
return Jed.PF.interpreter( ast.left )( n ) < Jed.PF.interpreter( ast.right )( n );
|
||
case 'GT':
|
||
return Jed.PF.interpreter( ast.left )( n ) > Jed.PF.interpreter( ast.right )( n );
|
||
case 'LTE':
|
||
return Jed.PF.interpreter( ast.left )( n ) <= Jed.PF.interpreter( ast.right )( n );
|
||
case 'GTE':
|
||
return Jed.PF.interpreter( ast.left )( n ) >= Jed.PF.interpreter( ast.right )( n );
|
||
case 'EQ':
|
||
return Jed.PF.interpreter( ast.left )( n ) == Jed.PF.interpreter( ast.right )( n );
|
||
case 'NEQ':
|
||
return Jed.PF.interpreter( ast.left )( n ) != Jed.PF.interpreter( ast.right )( n );
|
||
case 'MOD':
|
||
return Jed.PF.interpreter( ast.left )( n ) % Jed.PF.interpreter( ast.right )( n );
|
||
case 'VAR':
|
||
return n;
|
||
case 'NUM':
|
||
return ast.val;
|
||
default:
|
||
throw new Error("Invalid Token found.");
|
||
}
|
||
};
|
||
};
|
||
|
||
Jed.PF.extractPluralExpr = function ( p ) {
|
||
// trim first
|
||
p = p.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
||
|
||
if (! /;\s*$/.test(p)) {
|
||
p = p.concat(';');
|
||
}
|
||
|
||
var nplurals_re = /nplurals\=(\d+);/,
|
||
plural_re = /plural\=(.*);/,
|
||
nplurals_matches = p.match( nplurals_re ),
|
||
res = {},
|
||
plural_matches;
|
||
|
||
// Find the nplurals number
|
||
if ( nplurals_matches.length > 1 ) {
|
||
res.nplurals = nplurals_matches[1];
|
||
}
|
||
else {
|
||
throw new Error('nplurals not found in plural_forms string: ' + p );
|
||
}
|
||
|
||
// remove that data to get to the formula
|
||
p = p.replace( nplurals_re, "" );
|
||
plural_matches = p.match( plural_re );
|
||
|
||
if (!( plural_matches && plural_matches.length > 1 ) ) {
|
||
throw new Error('`plural` expression not found: ' + p);
|
||
}
|
||
return plural_matches[ 1 ];
|
||
};
|
||
|
||
/* Jison generated parser */
|
||
Jed.PF.parser = (function(){
|
||
|
||
var parser = {trace: function trace() { },
|
||
yy: {},
|
||
symbols_: {"error":2,"expressions":3,"e":4,"EOF":5,"?":6,":":7,"||":8,"&&":9,"<":10,"<=":11,">":12,">=":13,"!=":14,"==":15,"%":16,"(":17,")":18,"n":19,"NUMBER":20,"$accept":0,"$end":1},
|
||
terminals_: {2:"error",5:"EOF",6:"?",7:":",8:"||",9:"&&",10:"<",11:"<=",12:">",13:">=",14:"!=",15:"==",16:"%",17:"(",18:")",19:"n",20:"NUMBER"},
|
||
productions_: [0,[3,2],[4,5],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,1],[4,1]],
|
||
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
||
|
||
var $0 = $$.length - 1;
|
||
switch (yystate) {
|
||
case 1: return { type : 'GROUP', expr: $$[$0-1] };
|
||
break;
|
||
case 2:this.$ = { type: 'TERNARY', expr: $$[$0-4], truthy : $$[$0-2], falsey: $$[$0] };
|
||
break;
|
||
case 3:this.$ = { type: "OR", left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 4:this.$ = { type: "AND", left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 5:this.$ = { type: 'LT', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 6:this.$ = { type: 'LTE', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 7:this.$ = { type: 'GT', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 8:this.$ = { type: 'GTE', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 9:this.$ = { type: 'NEQ', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 10:this.$ = { type: 'EQ', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 11:this.$ = { type: 'MOD', left: $$[$0-2], right: $$[$0] };
|
||
break;
|
||
case 12:this.$ = { type: 'GROUP', expr: $$[$0-1] };
|
||
break;
|
||
case 13:this.$ = { type: 'VAR' };
|
||
break;
|
||
case 14:this.$ = { type: 'NUM', val: Number(yytext) };
|
||
break;
|
||
}
|
||
},
|
||
table: [{3:1,4:2,17:[1,3],19:[1,4],20:[1,5]},{1:[3]},{5:[1,6],6:[1,7],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16]},{4:17,17:[1,3],19:[1,4],20:[1,5]},{5:[2,13],6:[2,13],7:[2,13],8:[2,13],9:[2,13],10:[2,13],11:[2,13],12:[2,13],13:[2,13],14:[2,13],15:[2,13],16:[2,13],18:[2,13]},{5:[2,14],6:[2,14],7:[2,14],8:[2,14],9:[2,14],10:[2,14],11:[2,14],12:[2,14],13:[2,14],14:[2,14],15:[2,14],16:[2,14],18:[2,14]},{1:[2,1]},{4:18,17:[1,3],19:[1,4],20:[1,5]},{4:19,17:[1,3],19:[1,4],20:[1,5]},{4:20,17:[1,3],19:[1,4],20:[1,5]},{4:21,17:[1,3],19:[1,4],20:[1,5]},{4:22,17:[1,3],19:[1,4],20:[1,5]},{4:23,17:[1,3],19:[1,4],20:[1,5]},{4:24,17:[1,3],19:[1,4],20:[1,5]},{4:25,17:[1,3],19:[1,4],20:[1,5]},{4:26,17:[1,3],19:[1,4],20:[1,5]},{4:27,17:[1,3],19:[1,4],20:[1,5]},{6:[1,7],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[1,28]},{6:[1,7],7:[1,29],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16]},{5:[2,3],6:[2,3],7:[2,3],8:[2,3],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,3]},{5:[2,4],6:[2,4],7:[2,4],8:[2,4],9:[2,4],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,4]},{5:[2,5],6:[2,5],7:[2,5],8:[2,5],9:[2,5],10:[2,5],11:[2,5],12:[2,5],13:[2,5],14:[2,5],15:[2,5],16:[1,16],18:[2,5]},{5:[2,6],6:[2,6],7:[2,6],8:[2,6],9:[2,6],10:[2,6],11:[2,6],12:[2,6],13:[2,6],14:[2,6],15:[2,6],16:[1,16],18:[2,6]},{5:[2,7],6:[2,7],7:[2,7],8:[2,7],9:[2,7],10:[2,7],11:[2,7],12:[2,7],13:[2,7],14:[2,7],15:[2,7],16:[1,16],18:[2,7]},{5:[2,8],6:[2,8],7:[2,8],8:[2,8],9:[2,8],10:[2,8],11:[2,8],12:[2,8],13:[2,8],14:[2,8],15:[2,8],16:[1,16],18:[2,8]},{5:[2,9],6:[2,9],7:[2,9],8:[2,9],9:[2,9],10:[2,9],11:[2,9],12:[2,9],13:[2,9],14:[2,9],15:[2,9],16:[1,16],18:[2,9]},{5:[2,10],6:[2,10],7:[2,10],8:[2,10],9:[2,10],10:[2,10],11:[2,10],12:[2,10],13:[2,10],14:[2,10],15:[2,10],16:[1,16],18:[2,10]},{5:[2,11],6:[2,11],7:[2,11],8:[2,11],9:[2,11],10:[2,11],11:[2,11],12:[2,11],13:[2,11],14:[2,11],15:[2,11],16:[2,11],18:[2,11]},{5:[2,12],6:[2,12],7:[2,12],8:[2,12],9:[2,12],10:[2,12],11:[2,12],12:[2,12],13:[2,12],14:[2,12],15:[2,12],16:[2,12],18:[2,12]},{4:30,17:[1,3],19:[1,4],20:[1,5]},{5:[2,2],6:[1,7],7:[2,2],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,2]}],
|
||
defaultActions: {6:[2,1]},
|
||
parseError: function parseError(str, hash) {
|
||
throw new Error(str);
|
||
},
|
||
parse: function parse(input) {
|
||
var self = this,
|
||
stack = [0],
|
||
vstack = [null], // semantic value stack
|
||
lstack = [], // location stack
|
||
table = this.table,
|
||
yytext = '',
|
||
yylineno = 0,
|
||
yyleng = 0,
|
||
recovering = 0,
|
||
TERROR = 2,
|
||
EOF = 1;
|
||
|
||
//this.reductionCount = this.shiftCount = 0;
|
||
|
||
this.lexer.setInput(input);
|
||
this.lexer.yy = this.yy;
|
||
this.yy.lexer = this.lexer;
|
||
if (typeof this.lexer.yylloc == 'undefined')
|
||
this.lexer.yylloc = {};
|
||
var yyloc = this.lexer.yylloc;
|
||
lstack.push(yyloc);
|
||
|
||
if (typeof this.yy.parseError === 'function')
|
||
this.parseError = this.yy.parseError;
|
||
|
||
function popStack (n) {
|
||
stack.length = stack.length - 2*n;
|
||
vstack.length = vstack.length - n;
|
||
lstack.length = lstack.length - n;
|
||
}
|
||
|
||
function lex() {
|
||
var token;
|
||
token = self.lexer.lex() || 1; // $end = 1
|
||
// if token isn't its numeric value, convert
|
||
if (typeof token !== 'number') {
|
||
token = self.symbols_[token] || token;
|
||
}
|
||
return token;
|
||
}
|
||
|
||
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
|
||
while (true) {
|
||
// retreive state number from top of stack
|
||
state = stack[stack.length-1];
|
||
|
||
// use default actions if available
|
||
if (this.defaultActions[state]) {
|
||
action = this.defaultActions[state];
|
||
} else {
|
||
if (symbol == null)
|
||
symbol = lex();
|
||
// read action for current state and first input
|
||
action = table[state] && table[state][symbol];
|
||
}
|
||
|
||
// handle parse error
|
||
_handle_error:
|
||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||
|
||
if (!recovering) {
|
||
// Report error
|
||
expected = [];
|
||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||
expected.push("'"+this.terminals_[p]+"'");
|
||
}
|
||
var errStr = '';
|
||
if (this.lexer.showPosition) {
|
||
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
|
||
} else {
|
||
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
|
||
(symbol == 1 /*EOF*/ ? "end of input" :
|
||
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
||
}
|
||
this.parseError(errStr,
|
||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||
}
|
||
|
||
// just recovered from another error
|
||
if (recovering == 3) {
|
||
if (symbol == EOF) {
|
||
throw new Error(errStr || 'Parsing halted.');
|
||
}
|
||
|
||
// discard current lookahead and grab another
|
||
yyleng = this.lexer.yyleng;
|
||
yytext = this.lexer.yytext;
|
||
yylineno = this.lexer.yylineno;
|
||
yyloc = this.lexer.yylloc;
|
||
symbol = lex();
|
||
}
|
||
|
||
// try to recover from error
|
||
while (1) {
|
||
// check for error recovery rule in this state
|
||
if ((TERROR.toString()) in table[state]) {
|
||
break;
|
||
}
|
||
if (state == 0) {
|
||
throw new Error(errStr || 'Parsing halted.');
|
||
}
|
||
popStack(1);
|
||
state = stack[stack.length-1];
|
||
}
|
||
|
||
preErrorSymbol = symbol; // save the lookahead token
|
||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||
state = stack[stack.length-1];
|
||
action = table[state] && table[state][TERROR];
|
||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||
}
|
||
|
||
// this shouldn't happen, unless resolve defaults are off
|
||
if (action[0] instanceof Array && action.length > 1) {
|
||
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
||
}
|
||
|
||
switch (action[0]) {
|
||
|
||
case 1: // shift
|
||
//this.shiftCount++;
|
||
|
||
stack.push(symbol);
|
||
vstack.push(this.lexer.yytext);
|
||
lstack.push(this.lexer.yylloc);
|
||
stack.push(action[1]); // push state
|
||
symbol = null;
|
||
if (!preErrorSymbol) { // normal execution/no error
|
||
yyleng = this.lexer.yyleng;
|
||
yytext = this.lexer.yytext;
|
||
yylineno = this.lexer.yylineno;
|
||
yyloc = this.lexer.yylloc;
|
||
if (recovering > 0)
|
||
recovering--;
|
||
} else { // error just occurred, resume old lookahead f/ before error
|
||
symbol = preErrorSymbol;
|
||
preErrorSymbol = null;
|
||
}
|
||
break;
|
||
|
||
case 2: // reduce
|
||
//this.reductionCount++;
|
||
|
||
len = this.productions_[action[1]][1];
|
||
|
||
// perform semantic action
|
||
yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
|
||
// default location, uses first token for firsts, last for lasts
|
||
yyval._$ = {
|
||
first_line: lstack[lstack.length-(len||1)].first_line,
|
||
last_line: lstack[lstack.length-1].last_line,
|
||
first_column: lstack[lstack.length-(len||1)].first_column,
|
||
last_column: lstack[lstack.length-1].last_column
|
||
};
|
||
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
||
|
||
if (typeof r !== 'undefined') {
|
||
return r;
|
||
}
|
||
|
||
// pop off stack
|
||
if (len) {
|
||
stack = stack.slice(0,-1*len*2);
|
||
vstack = vstack.slice(0, -1*len);
|
||
lstack = lstack.slice(0, -1*len);
|
||
}
|
||
|
||
stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
|
||
vstack.push(yyval.$);
|
||
lstack.push(yyval._$);
|
||
// goto new state = table[STATE][NONTERMINAL]
|
||
newState = table[stack[stack.length-2]][stack[stack.length-1]];
|
||
stack.push(newState);
|
||
break;
|
||
|
||
case 3: // accept
|
||
return true;
|
||
}
|
||
|
||
}
|
||
|
||
return true;
|
||
}};/* Jison generated lexer */
|
||
var lexer = (function(){
|
||
|
||
var lexer = ({EOF:1,
|
||
parseError:function parseError(str, hash) {
|
||
if (this.yy.parseError) {
|
||
this.yy.parseError(str, hash);
|
||
} else {
|
||
throw new Error(str);
|
||
}
|
||
},
|
||
setInput:function (input) {
|
||
this._input = input;
|
||
this._more = this._less = this.done = false;
|
||
this.yylineno = this.yyleng = 0;
|
||
this.yytext = this.matched = this.match = '';
|
||
this.conditionStack = ['INITIAL'];
|
||
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
|
||
return this;
|
||
},
|
||
input:function () {
|
||
var ch = this._input[0];
|
||
this.yytext+=ch;
|
||
this.yyleng++;
|
||
this.match+=ch;
|
||
this.matched+=ch;
|
||
var lines = ch.match(/\n/);
|
||
if (lines) this.yylineno++;
|
||
this._input = this._input.slice(1);
|
||
return ch;
|
||
},
|
||
unput:function (ch) {
|
||
this._input = ch + this._input;
|
||
return this;
|
||
},
|
||
more:function () {
|
||
this._more = true;
|
||
return this;
|
||
},
|
||
pastInput:function () {
|
||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
||
},
|
||
upcomingInput:function () {
|
||
var next = this.match;
|
||
if (next.length < 20) {
|
||
next += this._input.substr(0, 20-next.length);
|
||
}
|
||
return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
|
||
},
|
||
showPosition:function () {
|
||
var pre = this.pastInput();
|
||
var c = new Array(pre.length + 1).join("-");
|
||
return pre + this.upcomingInput() + "\n" + c+"^";
|
||
},
|
||
next:function () {
|
||
if (this.done) {
|
||
return this.EOF;
|
||
}
|
||
if (!this._input) this.done = true;
|
||
|
||
var token,
|
||
match,
|
||
col,
|
||
lines;
|
||
if (!this._more) {
|
||
this.yytext = '';
|
||
this.match = '';
|
||
}
|
||
var rules = this._currentRules();
|
||
for (var i=0;i < rules.length; i++) {
|
||
match = this._input.match(this.rules[rules[i]]);
|
||
if (match) {
|
||
lines = match[0].match(/\n.*/g);
|
||
if (lines) this.yylineno += lines.length;
|
||
this.yylloc = {first_line: this.yylloc.last_line,
|
||
last_line: this.yylineno+1,
|
||
first_column: this.yylloc.last_column,
|
||
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
|
||
this.yytext += match[0];
|
||
this.match += match[0];
|
||
this.matches = match;
|
||
this.yyleng = this.yytext.length;
|
||
this._more = false;
|
||
this._input = this._input.slice(match[0].length);
|
||
this.matched += match[0];
|
||
token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
|
||
if (token) return token;
|
||
else return;
|
||
}
|
||
}
|
||
if (this._input === "") {
|
||
return this.EOF;
|
||
} else {
|
||
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
||
{text: "", token: null, line: this.yylineno});
|
||
}
|
||
},
|
||
lex:function lex() {
|
||
var r = this.next();
|
||
if (typeof r !== 'undefined') {
|
||
return r;
|
||
} else {
|
||
return this.lex();
|
||
}
|
||
},
|
||
begin:function begin(condition) {
|
||
this.conditionStack.push(condition);
|
||
},
|
||
popState:function popState() {
|
||
return this.conditionStack.pop();
|
||
},
|
||
_currentRules:function _currentRules() {
|
||
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
|
||
},
|
||
topState:function () {
|
||
return this.conditionStack[this.conditionStack.length-2];
|
||
},
|
||
pushState:function begin(condition) {
|
||
this.begin(condition);
|
||
}});
|
||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||
|
||
var YYSTATE=YY_START;
|
||
switch($avoiding_name_collisions) {
|
||
case 0:/* skip whitespace */
|
||
break;
|
||
case 1:return 20
|
||
break;
|
||
case 2:return 19
|
||
break;
|
||
case 3:return 8
|
||
break;
|
||
case 4:return 9
|
||
break;
|
||
case 5:return 6
|
||
break;
|
||
case 6:return 7
|
||
break;
|
||
case 7:return 11
|
||
break;
|
||
case 8:return 13
|
||
break;
|
||
case 9:return 10
|
||
break;
|
||
case 10:return 12
|
||
break;
|
||
case 11:return 14
|
||
break;
|
||
case 12:return 15
|
||
break;
|
||
case 13:return 16
|
||
break;
|
||
case 14:return 17
|
||
break;
|
||
case 15:return 18
|
||
break;
|
||
case 16:return 5
|
||
break;
|
||
case 17:return 'INVALID'
|
||
break;
|
||
}
|
||
};
|
||
lexer.rules = [/^\s+/,/^[0-9]+(\.[0-9]+)?\b/,/^n\b/,/^\|\|/,/^&&/,/^\?/,/^:/,/^<=/,/^>=/,/^</,/^>/,/^!=/,/^==/,/^%/,/^\(/,/^\)/,/^$/,/^./];
|
||
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"inclusive":true}};return lexer;})()
|
||
parser.lexer = lexer;
|
||
return parser;
|
||
})();
|
||
// End parser
|
||
|
||
// Handle node, amd, and global systems
|
||
if (typeof exports !== 'undefined') {
|
||
if (typeof module !== 'undefined' && module.exports) {
|
||
exports = module.exports = Jed;
|
||
}
|
||
exports.Jed = Jed;
|
||
}
|
||
else {
|
||
if (typeof define === 'function' && define.amd) {
|
||
define('jed',[],function() {
|
||
return Jed;
|
||
});
|
||
}
|
||
// Leak a global regardless of module system
|
||
root['Jed'] = Jed;
|
||
}
|
||
|
||
})(this);
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
// Module to handle i18n ( Internationalization ) and translated UI
|
||
|
||
define('base/js/i18n',[
|
||
'jed'
|
||
], function(Jed) {
|
||
"use strict";
|
||
|
||
var i18n = new Jed(document.nbjs_translations);
|
||
i18n._ = i18n.gettext;
|
||
i18n.msg = i18n; // Just a place holder until the init promise resolves.
|
||
|
||
return i18n;
|
||
});
|
||
|
||
/*!
|
||
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
||
* Copyright 2011-2019 Twitter, Inc.
|
||
* Licensed under the MIT license
|
||
*/
|
||
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");!function(t){"use strict";var e=jQuery.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||3<e[0])throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(),function(n){"use strict";n.fn.emulateTransitionEnd=function(t){var e=!1,i=this;n(this).one("bsTransitionEnd",function(){e=!0});return setTimeout(function(){e||n(i).trigger(n.support.transition.end)},t),this},n(function(){n.support.transition=function o(){var t=document.createElement("bootstrap"),e={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var i in e)if(t.style[i]!==undefined)return{end:e[i]};return!1}(),n.support.transition&&(n.event.special.bsTransitionEnd={bindType:n.support.transition.end,delegateType:n.support.transition.end,handle:function(t){if(n(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(s){"use strict";var e='[data-dismiss="alert"]',a=function(t){s(t).on("click",e,this.close)};a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.close=function(t){var e=s(this),i=e.attr("data-target");i||(i=(i=e.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),i="#"===i?[]:i;var o=s(document).find(i);function n(){o.detach().trigger("closed.bs.alert").remove()}t&&t.preventDefault(),o.length||(o=e.closest(".alert")),o.trigger(t=s.Event("close.bs.alert")),t.isDefaultPrevented()||(o.removeClass("in"),s.support.transition&&o.hasClass("fade")?o.one("bsTransitionEnd",n).emulateTransitionEnd(a.TRANSITION_DURATION):n())};var t=s.fn.alert;s.fn.alert=function o(i){return this.each(function(){var t=s(this),e=t.data("bs.alert");e||t.data("bs.alert",e=new a(this)),"string"==typeof i&&e[i].call(t)})},s.fn.alert.Constructor=a,s.fn.alert.noConflict=function(){return s.fn.alert=t,this},s(document).on("click.bs.alert.data-api",e,a.prototype.close)}(jQuery),function(s){"use strict";var n=function(t,e){this.$element=s(t),this.options=s.extend({},n.DEFAULTS,e),this.isLoading=!1};function i(o){return this.each(function(){var t=s(this),e=t.data("bs.button"),i="object"==typeof o&&o;e||t.data("bs.button",e=new n(this,i)),"toggle"==o?e.toggle():o&&e.setState(o)})}n.VERSION="3.4.1",n.DEFAULTS={loadingText:"loading..."},n.prototype.setState=function(t){var e="disabled",i=this.$element,o=i.is("input")?"val":"html",n=i.data();t+="Text",null==n.resetText&&i.data("resetText",i[o]()),setTimeout(s.proxy(function(){i[o](null==n[t]?this.options[t]:n[t]),"loadingText"==t?(this.isLoading=!0,i.addClass(e).attr(e,e).prop(e,!0)):this.isLoading&&(this.isLoading=!1,i.removeClass(e).removeAttr(e).prop(e,!1))},this),0)},n.prototype.toggle=function(){var t=!0,e=this.$element.closest('[data-toggle="buttons"]');if(e.length){var i=this.$element.find("input");"radio"==i.prop("type")?(i.prop("checked")&&(t=!1),e.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==i.prop("type")&&(i.prop("checked")!==this.$element.hasClass("active")&&(t=!1),this.$element.toggleClass("active")),i.prop("checked",this.$element.hasClass("active")),t&&i.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var t=s.fn.button;s.fn.button=i,s.fn.button.Constructor=n,s.fn.button.noConflict=function(){return s.fn.button=t,this},s(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(t){var e=s(t.target).closest(".btn");i.call(e,"toggle"),s(t.target).is('input[type="radio"], input[type="checkbox"]')||(t.preventDefault(),e.is("input,button")?e.trigger("focus"):e.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(t){s(t.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(t.type))})}(jQuery),function(p){"use strict";var c=function(t,e){this.$element=p(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=e,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",p.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",p.proxy(this.pause,this)).on("mouseleave.bs.carousel",p.proxy(this.cycle,this))};function r(n){return this.each(function(){var t=p(this),e=t.data("bs.carousel"),i=p.extend({},c.DEFAULTS,t.data(),"object"==typeof n&&n),o="string"==typeof n?n:i.slide;e||t.data("bs.carousel",e=new c(this,i)),"number"==typeof n?e.to(n):o?e[o]():i.interval&&e.pause().cycle()})}c.VERSION="3.4.1",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(t){if(!/input|textarea/i.test(t.target.tagName)){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()}},c.prototype.cycle=function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(p.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},c.prototype.getItemForDirection=function(t,e){var i=this.getItemIndex(e);if(("prev"==t&&0===i||"next"==t&&i==this.$items.length-1)&&!this.options.wrap)return e;var o=(i+("prev"==t?-1:1))%this.$items.length;return this.$items.eq(o)},c.prototype.to=function(t){var e=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(t>this.$items.length-1||t<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(i<t?"next":"prev",this.$items.eq(t))},c.prototype.pause=function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&p.support.transition&&(this.$element.trigger(p.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(t,e){var i=this.$element.find(".item.active"),o=e||this.getItemForDirection(t,i),n=this.interval,s="next"==t?"left":"right",a=this;if(o.hasClass("active"))return this.sliding=!1;var r=o[0],l=p.Event("slide.bs.carousel",{relatedTarget:r,direction:s});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,n&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var h=p(this.$indicators.children()[this.getItemIndex(o)]);h&&h.addClass("active")}var d=p.Event("slid.bs.carousel",{relatedTarget:r,direction:s});return p.support.transition&&this.$element.hasClass("slide")?(o.addClass(t),"object"==typeof o&&o.length&&o[0].offsetWidth,i.addClass(s),o.addClass(s),i.one("bsTransitionEnd",function(){o.removeClass([t,s].join(" ")).addClass("active"),i.removeClass(["active",s].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger(d)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(i.removeClass("active"),o.addClass("active"),this.sliding=!1,this.$element.trigger(d)),n&&this.cycle(),this}};var t=p.fn.carousel;p.fn.carousel=r,p.fn.carousel.Constructor=c,p.fn.carousel.noConflict=function(){return p.fn.carousel=t,this};var e=function(t){var e=p(this),i=e.attr("href");i&&(i=i.replace(/.*(?=#[^\s]+$)/,""));var o=e.attr("data-target")||i,n=p(document).find(o);if(n.hasClass("carousel")){var s=p.extend({},n.data(),e.data()),a=e.attr("data-slide-to");a&&(s.interval=!1),r.call(n,s),a&&n.data("bs.carousel").to(a),t.preventDefault()}};p(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),p(window).on("load",function(){p('[data-ride="carousel"]').each(function(){var t=p(this);r.call(t,t.data())})})}(jQuery),function(a){"use strict";var r=function(t,e){this.$element=a(t),this.options=a.extend({},r.DEFAULTS,e),this.$trigger=a('[data-toggle="collapse"][href="#'+t.id+'"],[data-toggle="collapse"][data-target="#'+t.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};function n(t){var e,i=t.attr("data-target")||(e=t.attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"");return a(document).find(i)}function l(o){return this.each(function(){var t=a(this),e=t.data("bs.collapse"),i=a.extend({},r.DEFAULTS,t.data(),"object"==typeof o&&o);!e&&i.toggle&&/show|hide/.test(o)&&(i.toggle=!1),e||t.data("bs.collapse",e=new r(this,i)),"string"==typeof o&&e[o]()})}r.VERSION="3.4.1",r.TRANSITION_DURATION=350,r.DEFAULTS={toggle:!0},r.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},r.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var t,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(t=e.data("bs.collapse"))&&t.transitioning)){var i=a.Event("show.bs.collapse");if(this.$element.trigger(i),!i.isDefaultPrevented()){e&&e.length&&(l.call(e,"hide"),t||e.data("bs.collapse",null));var o=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[o](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var n=function(){this.$element.removeClass("collapsing").addClass("collapse in")[o](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return n.call(this);var s=a.camelCase(["scroll",o].join("-"));this.$element.one("bsTransitionEnd",a.proxy(n,this)).emulateTransitionEnd(r.TRANSITION_DURATION)[o](this.$element[0][s])}}}},r.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var t=a.Event("hide.bs.collapse");if(this.$element.trigger(t),!t.isDefaultPrevented()){var e=this.dimension();this.$element[e](this.$element[e]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var i=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!a.support.transition)return i.call(this);this.$element[e](0).one("bsTransitionEnd",a.proxy(i,this)).emulateTransitionEnd(r.TRANSITION_DURATION)}}},r.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},r.prototype.getParent=function(){return a(document).find(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(t,e){var i=a(e);this.addAriaAndCollapsedClass(n(i),i)},this)).end()},r.prototype.addAriaAndCollapsedClass=function(t,e){var i=t.hasClass("in");t.attr("aria-expanded",i),e.toggleClass("collapsed",!i).attr("aria-expanded",i)};var t=a.fn.collapse;a.fn.collapse=l,a.fn.collapse.Constructor=r,a.fn.collapse.noConflict=function(){return a.fn.collapse=t,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(t){var e=a(this);e.attr("data-target")||t.preventDefault();var i=n(e),o=i.data("bs.collapse")?"toggle":e.data();l.call(i,o)})}(jQuery),function(a){"use strict";var r='[data-toggle="dropdown"]',o=function(t){a(t).on("click.bs.dropdown",this.toggle)};function l(t){var e=t.attr("data-target");e||(e=(e=t.attr("href"))&&/#[A-Za-z]/.test(e)&&e.replace(/.*(?=#[^\s]*$)/,""));var i="#"!==e?a(document).find(e):null;return i&&i.length?i:t.parent()}function s(o){o&&3===o.which||(a(".dropdown-backdrop").remove(),a(r).each(function(){var t=a(this),e=l(t),i={relatedTarget:this};e.hasClass("open")&&(o&&"click"==o.type&&/input|textarea/i.test(o.target.tagName)&&a.contains(e[0],o.target)||(e.trigger(o=a.Event("hide.bs.dropdown",i)),o.isDefaultPrevented()||(t.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",i)))))}))}o.VERSION="3.4.1",o.prototype.toggle=function(t){var e=a(this);if(!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(s(),!o){"ontouchstart"in document.documentElement&&!i.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",s);var n={relatedTarget:this};if(i.trigger(t=a.Event("show.bs.dropdown",n)),t.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),i.toggleClass("open").trigger(a.Event("shown.bs.dropdown",n))}return!1}},o.prototype.keydown=function(t){if(/(38|40|27|32)/.test(t.which)&&!/input|textarea/i.test(t.target.tagName)){var e=a(this);if(t.preventDefault(),t.stopPropagation(),!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(!o&&27!=t.which||o&&27==t.which)return 27==t.which&&i.find(r).trigger("focus"),e.trigger("click");var n=i.find(".dropdown-menu li:not(.disabled):visible a");if(n.length){var s=n.index(t.target);38==t.which&&0<s&&s--,40==t.which&&s<n.length-1&&s++,~s||(s=0),n.eq(s).trigger("focus")}}}};var t=a.fn.dropdown;a.fn.dropdown=function e(i){return this.each(function(){var t=a(this),e=t.data("bs.dropdown");e||t.data("bs.dropdown",e=new o(this)),"string"==typeof i&&e[i].call(t)})},a.fn.dropdown.Constructor=o,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=t,this},a(document).on("click.bs.dropdown.data-api",s).on("click.bs.dropdown.data-api",".dropdown form",function(t){t.stopPropagation()}).on("click.bs.dropdown.data-api",r,o.prototype.toggle).on("keydown.bs.dropdown.data-api",r,o.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",o.prototype.keydown)}(jQuery),function(a){"use strict";var s=function(t,e){this.options=e,this.$body=a(document.body),this.$element=a(t),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.fixedContent=".navbar-fixed-top, .navbar-fixed-bottom",this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};function r(o,n){return this.each(function(){var t=a(this),e=t.data("bs.modal"),i=a.extend({},s.DEFAULTS,t.data(),"object"==typeof o&&o);e||t.data("bs.modal",e=new s(this,i)),"string"==typeof o?e[o](n):i.show&&e.show(n)})}s.VERSION="3.4.1",s.TRANSITION_DURATION=300,s.BACKDROP_TRANSITION_DURATION=150,s.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},s.prototype.toggle=function(t){return this.isShown?this.hide():this.show(t)},s.prototype.show=function(i){var o=this,t=a.Event("show.bs.modal",{relatedTarget:i});this.$element.trigger(t),this.isShown||t.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){o.$element.one("mouseup.dismiss.bs.modal",function(t){a(t.target).is(o.$element)&&(o.ignoreBackdropClick=!0)})}),this.backdrop(function(){var t=a.support.transition&&o.$element.hasClass("fade");o.$element.parent().length||o.$element.appendTo(o.$body),o.$element.show().scrollTop(0),o.adjustDialog(),t&&o.$element[0].offsetWidth,o.$element.addClass("in"),o.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:i});t?o.$dialog.one("bsTransitionEnd",function(){o.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(s.TRANSITION_DURATION):o.$element.trigger("focus").trigger(e)}))},s.prototype.hide=function(t){t&&t.preventDefault(),t=a.Event("hide.bs.modal"),this.$element.trigger(t),this.isShown&&!t.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(s.TRANSITION_DURATION):this.hideModal())},s.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(t){document===t.target||this.$element[0]===t.target||this.$element.has(t.target).length||this.$element.trigger("focus")},this))},s.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(t){27==t.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},s.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},s.prototype.hideModal=function(){var t=this;this.$element.hide(),this.backdrop(function(){t.$body.removeClass("modal-open"),t.resetAdjustments(),t.resetScrollbar(),t.$element.trigger("hidden.bs.modal")})},s.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},s.prototype.backdrop=function(t){var e=this,i=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var o=a.support.transition&&i;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+i).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(t){this.ignoreBackdropClick?this.ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide())},this)),o&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!t)return;o?this.$backdrop.one("bsTransitionEnd",t).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):t()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var n=function(){e.removeBackdrop(),t&&t()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",n).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):n()}else t&&t()},s.prototype.handleUpdate=function(){this.adjustDialog()},s.prototype.adjustDialog=function(){var t=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},s.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},s.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth<t,this.scrollbarWidth=this.measureScrollbar()},s.prototype.setScrollbar=function(){var t=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"";var n=this.scrollbarWidth;this.bodyIsOverflowing&&(this.$body.css("padding-right",t+n),a(this.fixedContent).each(function(t,e){var i=e.style.paddingRight,o=a(e).css("padding-right");a(e).data("padding-right",i).css("padding-right",parseFloat(o)+n+"px")}))},s.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad),a(this.fixedContent).each(function(t,e){var i=a(e).data("padding-right");a(e).removeData("padding-right"),e.style.paddingRight=i||""})},s.prototype.measureScrollbar=function(){var t=document.createElement("div");t.className="modal-scrollbar-measure",this.$body.append(t);var e=t.offsetWidth-t.clientWidth;return this.$body[0].removeChild(t),e};var t=a.fn.modal;a.fn.modal=r,a.fn.modal.Constructor=s,a.fn.modal.noConflict=function(){return a.fn.modal=t,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(t){var e=a(this),i=e.attr("href"),o=e.attr("data-target")||i&&i.replace(/.*(?=#[^\s]+$)/,""),n=a(document).find(o),s=n.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(i)&&i},n.data(),e.data());e.is("a")&&t.preventDefault(),n.one("show.bs.modal",function(t){t.isDefaultPrevented()||n.one("hidden.bs.modal",function(){e.is(":visible")&&e.trigger("focus")})}),r.call(n,s,this)})}(jQuery),function(g){"use strict";var o=["sanitize","whiteList","sanitizeFn"],a=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],t={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},r=/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi,l=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;function u(t,e){var i=t.nodeName.toLowerCase();if(-1!==g.inArray(i,e))return-1===g.inArray(i,a)||Boolean(t.nodeValue.match(r)||t.nodeValue.match(l));for(var o=g(e).filter(function(t,e){return e instanceof RegExp}),n=0,s=o.length;n<s;n++)if(i.match(o[n]))return!0;return!1}function n(t,e,i){if(0===t.length)return t;if(i&&"function"==typeof i)return i(t);if(!document.implementation||!document.implementation.createHTMLDocument)return t;var o=document.implementation.createHTMLDocument("sanitization");o.body.innerHTML=t;for(var n=g.map(e,function(t,e){return e}),s=g(o.body).find("*"),a=0,r=s.length;a<r;a++){var l=s[a],h=l.nodeName.toLowerCase();if(-1!==g.inArray(h,n))for(var d=g.map(l.attributes,function(t){return t}),p=[].concat(e["*"]||[],e[h]||[]),c=0,f=d.length;c<f;c++)u(d[c],p)||l.removeAttribute(d[c].nodeName);else l.parentNode.removeChild(l)}return o.body.innerHTML}var m=function(t,e){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",t,e)};m.VERSION="3.4.1",m.TRANSITION_DURATION=150,m.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:t},m.prototype.init=function(t,e,i){if(this.enabled=!0,this.type=t,this.$element=g(e),this.options=this.getOptions(i),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var o=this.options.trigger.split(" "),n=o.length;n--;){var s=o[n];if("click"==s)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=s){var a="hover"==s?"mouseenter":"focusin",r="hover"==s?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(r+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},m.prototype.getDefaults=function(){return m.DEFAULTS},m.prototype.getOptions=function(t){var e=this.$element.data();for(var i in e)e.hasOwnProperty(i)&&-1!==g.inArray(i,o)&&delete e[i];return(t=g.extend({},this.getDefaults(),e,t)).delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.sanitize&&(t.template=n(t.template,t.whiteList,t.sanitizeFn)),t},m.prototype.getDelegateOptions=function(){var i={},o=this.getDefaults();return this._options&&g.each(this._options,function(t,e){o[t]!=e&&(i[t]=e)}),i},m.prototype.enter=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusin"==t.type?"focus":"hover"]=!0),e.tip().hasClass("in")||"in"==e.hoverState)e.hoverState="in";else{if(clearTimeout(e.timeout),e.hoverState="in",!e.options.delay||!e.options.delay.show)return e.show();e.timeout=setTimeout(function(){"in"==e.hoverState&&e.show()},e.options.delay.show)}},m.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},m.prototype.leave=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusout"==t.type?"focus":"hover"]=!1),!e.isInStateTrue()){if(clearTimeout(e.timeout),e.hoverState="out",!e.options.delay||!e.options.delay.hide)return e.hide();e.timeout=setTimeout(function(){"out"==e.hoverState&&e.hide()},e.options.delay.hide)}},m.prototype.show=function(){var t=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(t);var e=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(t.isDefaultPrevented()||!e)return;var i=this,o=this.tip(),n=this.getUID(this.type);this.setContent(),o.attr("id",n),this.$element.attr("aria-describedby",n),this.options.animation&&o.addClass("fade");var s="function"==typeof this.options.placement?this.options.placement.call(this,o[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,r=a.test(s);r&&(s=s.replace(a,"")||"top"),o.detach().css({top:0,left:0,display:"block"}).addClass(s).data("bs."+this.type,this),this.options.container?o.appendTo(g(document).find(this.options.container)):o.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),h=o[0].offsetWidth,d=o[0].offsetHeight;if(r){var p=s,c=this.getPosition(this.$viewport);s="bottom"==s&&l.bottom+d>c.bottom?"top":"top"==s&&l.top-d<c.top?"bottom":"right"==s&&l.right+h>c.width?"left":"left"==s&&l.left-h<c.left?"right":s,o.removeClass(p).addClass(s)}var f=this.getCalculatedOffset(s,l,h,d);this.applyPlacement(f,s);var u=function(){var t=i.hoverState;i.$element.trigger("shown.bs."+i.type),i.hoverState=null,"out"==t&&i.leave(i)};g.support.transition&&this.$tip.hasClass("fade")?o.one("bsTransitionEnd",u).emulateTransitionEnd(m.TRANSITION_DURATION):u()}},m.prototype.applyPlacement=function(t,e){var i=this.tip(),o=i[0].offsetWidth,n=i[0].offsetHeight,s=parseInt(i.css("margin-top"),10),a=parseInt(i.css("margin-left"),10);isNaN(s)&&(s=0),isNaN(a)&&(a=0),t.top+=s,t.left+=a,g.offset.setOffset(i[0],g.extend({using:function(t){i.css({top:Math.round(t.top),left:Math.round(t.left)})}},t),0),i.addClass("in");var r=i[0].offsetWidth,l=i[0].offsetHeight;"top"==e&&l!=n&&(t.top=t.top+n-l);var h=this.getViewportAdjustedDelta(e,t,r,l);h.left?t.left+=h.left:t.top+=h.top;var d=/top|bottom/.test(e),p=d?2*h.left-o+r:2*h.top-n+l,c=d?"offsetWidth":"offsetHeight";i.offset(t),this.replaceArrow(p,i[0][c],d)},m.prototype.replaceArrow=function(t,e,i){this.arrow().css(i?"left":"top",50*(1-t/e)+"%").css(i?"top":"left","")},m.prototype.setContent=function(){var t=this.tip(),e=this.getTitle();this.options.html?(this.options.sanitize&&(e=n(e,this.options.whiteList,this.options.sanitizeFn)),t.find(".tooltip-inner").html(e)):t.find(".tooltip-inner").text(e),t.removeClass("fade in top bottom left right")},m.prototype.hide=function(t){var e=this,i=g(this.$tip),o=g.Event("hide.bs."+this.type);function n(){"in"!=e.hoverState&&i.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),t&&t()}if(this.$element.trigger(o),!o.isDefaultPrevented())return i.removeClass("in"),g.support.transition&&i.hasClass("fade")?i.one("bsTransitionEnd",n).emulateTransitionEnd(m.TRANSITION_DURATION):n(),this.hoverState=null,this},m.prototype.fixTitle=function(){var t=this.$element;(t.attr("title")||"string"!=typeof t.attr("data-original-title"))&&t.attr("data-original-title",t.attr("title")||"").attr("title","")},m.prototype.hasContent=function(){return this.getTitle()},m.prototype.getPosition=function(t){var e=(t=t||this.$element)[0],i="BODY"==e.tagName,o=e.getBoundingClientRect();null==o.width&&(o=g.extend({},o,{width:o.right-o.left,height:o.bottom-o.top}));var n=window.SVGElement&&e instanceof window.SVGElement,s=i?{top:0,left:0}:n?null:t.offset(),a={scroll:i?document.documentElement.scrollTop||document.body.scrollTop:t.scrollTop()},r=i?{width:g(window).width(),height:g(window).height()}:null;return g.extend({},o,a,r,s)},m.prototype.getCalculatedOffset=function(t,e,i,o){return"bottom"==t?{top:e.top+e.height,left:e.left+e.width/2-i/2}:"top"==t?{top:e.top-o,left:e.left+e.width/2-i/2}:"left"==t?{top:e.top+e.height/2-o/2,left:e.left-i}:{top:e.top+e.height/2-o/2,left:e.left+e.width}},m.prototype.getViewportAdjustedDelta=function(t,e,i,o){var n={top:0,left:0};if(!this.$viewport)return n;var s=this.options.viewport&&this.options.viewport.padding||0,a=this.getPosition(this.$viewport);if(/right|left/.test(t)){var r=e.top-s-a.scroll,l=e.top+s-a.scroll+o;r<a.top?n.top=a.top-r:l>a.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;h<a.left?n.left=a.left-h:d>a.right&&(n.left=a.left+a.width-d)}return n},m.prototype.getTitle=function(){var t=this.$element,e=this.options;return t.attr("data-original-title")||("function"==typeof e.title?e.title.call(t[0]):e.title)},m.prototype.getUID=function(t){for(;t+=~~(1e6*Math.random()),document.getElementById(t););return t},m.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},m.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},m.prototype.enable=function(){this.enabled=!0},m.prototype.disable=function(){this.enabled=!1},m.prototype.toggleEnabled=function(){this.enabled=!this.enabled},m.prototype.toggle=function(t){var e=this;t&&((e=g(t.currentTarget).data("bs."+this.type))||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e))),t?(e.inState.click=!e.inState.click,e.isInStateTrue()?e.enter(e):e.leave(e)):e.tip().hasClass("in")?e.leave(e):e.enter(e)},m.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})},m.prototype.sanitizeHtml=function(t){return n(t,this.options.whiteList,this.options.sanitizeFn)};var e=g.fn.tooltip;g.fn.tooltip=function i(o){return this.each(function(){var t=g(this),e=t.data("bs.tooltip"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.tooltip",e=new m(this,i)),"string"==typeof o&&e[o]())})},g.fn.tooltip.Constructor=m,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=e,this}}(jQuery),function(n){"use strict";var s=function(t,e){this.init("popover",t,e)};if(!n.fn.tooltip)throw new Error("Popover requires tooltip.js");s.VERSION="3.4.1",s.DEFAULTS=n.extend({},n.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),((s.prototype=n.extend({},n.fn.tooltip.Constructor.prototype)).constructor=s).prototype.getDefaults=function(){return s.DEFAULTS},s.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();if(this.options.html){var o=typeof i;this.options.sanitize&&(e=this.sanitizeHtml(e),"string"===o&&(i=this.sanitizeHtml(i))),t.find(".popover-title").html(e),t.find(".popover-content").children().detach().end()["string"===o?"html":"append"](i)}else t.find(".popover-title").text(e),t.find(".popover-content").children().detach().end().text(i);t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},s.prototype.hasContent=function(){return this.getTitle()||this.getContent()},s.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},s.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var t=n.fn.popover;n.fn.popover=function e(o){return this.each(function(){var t=n(this),e=t.data("bs.popover"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.popover",e=new s(this,i)),"string"==typeof o&&e[o]())})},n.fn.popover.Constructor=s,n.fn.popover.noConflict=function(){return n.fn.popover=t,this}}(jQuery),function(s){"use strict";function n(t,e){this.$body=s(document.body),this.$scrollElement=s(t).is(document.body)?s(window):s(t),this.options=s.extend({},n.DEFAULTS,e),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",s.proxy(this.process,this)),this.refresh(),this.process()}function e(o){return this.each(function(){var t=s(this),e=t.data("bs.scrollspy"),i="object"==typeof o&&o;e||t.data("bs.scrollspy",e=new n(this,i)),"string"==typeof o&&e[o]()})}n.VERSION="3.4.1",n.DEFAULTS={offset:10},n.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},n.prototype.refresh=function(){var t=this,o="offset",n=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),s.isWindow(this.$scrollElement[0])||(o="position",n=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var t=s(this),e=t.data("target")||t.attr("href"),i=/^#./.test(e)&&s(e);return i&&i.length&&i.is(":visible")&&[[i[o]().top+n,e]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},n.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),o<=e)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e<n[0])return this.activeTarget=null,this.clear();for(t=n.length;t--;)a!=s[t]&&e>=n[t]&&(n[t+1]===undefined||e<n[t+1])&&this.activate(s[t])},n.prototype.activate=function(t){this.activeTarget=t,this.clear();var e=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',i=s(e).parents("li").addClass("active");i.parent(".dropdown-menu").length&&(i=i.closest("li.dropdown").addClass("active")),i.trigger("activate.bs.scrollspy")},n.prototype.clear=function(){s(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var t=s.fn.scrollspy;s.fn.scrollspy=e,s.fn.scrollspy.Constructor=n,s.fn.scrollspy.noConflict=function(){return s.fn.scrollspy=t,this},s(window).on("load.bs.scrollspy.data-api",function(){s('[data-spy="scroll"]').each(function(){var t=s(this);e.call(t,t.data())})})}(jQuery),function(r){"use strict";var a=function(t){this.element=r(t)};function e(i){return this.each(function(){var t=r(this),e=t.data("bs.tab");e||t.data("bs.tab",e=new a(this)),"string"==typeof i&&e[i]()})}a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.show=function(){var t=this.element,e=t.closest("ul:not(.dropdown-menu)"),i=t.data("target");if(i||(i=(i=t.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),!t.parent("li").hasClass("active")){var o=e.find(".active:last a"),n=r.Event("hide.bs.tab",{relatedTarget:t[0]}),s=r.Event("show.bs.tab",{relatedTarget:o[0]});if(o.trigger(n),t.trigger(s),!s.isDefaultPrevented()&&!n.isDefaultPrevented()){var a=r(document).find(i);this.activate(t.closest("li"),e),this.activate(a,a.parent(),function(){o.trigger({type:"hidden.bs.tab",relatedTarget:t[0]}),t.trigger({type:"shown.bs.tab",relatedTarget:o[0]})})}}},a.prototype.activate=function(t,e,i){var o=e.find("> .active"),n=i&&r.support.transition&&(o.length&&o.hasClass("fade")||!!e.find("> .fade").length);function s(){o.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),t.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),n?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu").length&&t.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),i&&i()}o.length&&n?o.one("bsTransitionEnd",s).emulateTransitionEnd(a.TRANSITION_DURATION):s(),o.removeClass("in")};var t=r.fn.tab;r.fn.tab=e,r.fn.tab.Constructor=a,r.fn.tab.noConflict=function(){return r.fn.tab=t,this};var i=function(t){t.preventDefault(),e.call(r(this),"show")};r(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',i).on("click.bs.tab.data-api",'[data-toggle="pill"]',i)}(jQuery),function(l){"use strict";var h=function(t,e){this.options=l.extend({},h.DEFAULTS,e);var i=this.options.target===h.DEFAULTS.target?l(this.options.target):l(document).find(this.options.target);this.$target=i.on("scroll.bs.affix.data-api",l.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",l.proxy(this.checkPositionWithEventLoop,this)),this.$element=l(t),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};function i(o){return this.each(function(){var t=l(this),e=t.data("bs.affix"),i="object"==typeof o&&o;e||t.data("bs.affix",e=new h(this,i)),"string"==typeof o&&e[o]()})}h.VERSION="3.4.1",h.RESET="affix affix-top affix-bottom",h.DEFAULTS={offset:0,target:window},h.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return n<i&&"top";if("bottom"==this.affixed)return null!=i?!(n+this.unpin<=s.top)&&"bottom":!(n+a<=t-o)&&"bottom";var r=null==this.affixed,l=r?n:s.top;return null!=i&&n<=i?"top":null!=o&&t-o<=l+(r?a:e)&&"bottom"},h.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(h.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},h.prototype.checkPositionWithEventLoop=function(){setTimeout(l.proxy(this.checkPosition,this),1)},h.prototype.checkPosition=function(){if(this.$element.is(":visible")){var t=this.$element.height(),e=this.options.offset,i=e.top,o=e.bottom,n=Math.max(l(document).height(),l(document.body).height());"object"!=typeof e&&(o=i=e),"function"==typeof i&&(i=e.top(this.$element)),"function"==typeof o&&(o=e.bottom(this.$element));var s=this.getState(n,t,i,o);if(this.affixed!=s){null!=this.unpin&&this.$element.css("top","");var a="affix"+(s?"-"+s:""),r=l.Event(a+".bs.affix");if(this.$element.trigger(r),r.isDefaultPrevented())return;this.affixed=s,this.unpin="bottom"==s?this.getPinnedOffset():null,this.$element.removeClass(h.RESET).addClass(a).trigger(a.replace("affix","affixed")+".bs.affix")}"bottom"==s&&this.$element.offset({top:n-t-o})}};var t=l.fn.affix;l.fn.affix=i,l.fn.affix.Constructor=h,l.fn.affix.noConflict=function(){return l.fn.affix=t,this},l(window).on("load",function(){l('[data-spy="affix"]').each(function(){var t=l(this),e=t.data();e.offset=e.offset||{},null!=e.offsetBottom&&(e.offset.bottom=e.offsetBottom),null!=e.offsetTop&&(e.offset.top=e.offsetTop),i.call(t,e)})})}(jQuery);
|
||
define("bootstrap", ["jquery"], (function (global) {
|
||
return function () {
|
||
var ret, fn;
|
||
return ret || global.bootstrap;
|
||
};
|
||
}(this)));
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('base/js/dialog',['jquery',
|
||
'codemirror/lib/codemirror',
|
||
'bootstrap',
|
||
'base/js/i18n'],
|
||
function($, CodeMirror, bs, i18n) {
|
||
"use strict";
|
||
|
||
/**
|
||
* A wrapper around bootstrap modal for easier use
|
||
* Pass it an option dictionary with the following properties:
|
||
*
|
||
* - body : <string> or <DOM node>, main content of the dialog
|
||
* if pass a <string> it will be wrapped in a p tag and
|
||
* html element escaped, unless you specify sanitize=false
|
||
* option.
|
||
* - title : Dialog title, default to empty string.
|
||
* - buttons : dict of btn_options who keys are button label.
|
||
* see btn_options below for description
|
||
* - open : callback to trigger on dialog open.
|
||
* - destroy:
|
||
* - notebook : notebook instance
|
||
* - keyboard_manager: keyboard manager instance.
|
||
*
|
||
* Unlike bootstrap modals, the backdrop options is set by default
|
||
* to 'static'.
|
||
*
|
||
* The rest of the options are passed as is to bootstrap modals.
|
||
*
|
||
* btn_options: dict with the following property:
|
||
*
|
||
* - click : callback to trigger on click
|
||
* - class : css classes to add to button.
|
||
*
|
||
*
|
||
*
|
||
**/
|
||
var modal = function (options) {
|
||
|
||
var modal = $("<div/>")
|
||
.addClass("modal")
|
||
.addClass("fade")
|
||
.attr("role", "dialog");
|
||
var dialog = $("<div/>")
|
||
.addClass("modal-dialog")
|
||
.appendTo(modal);
|
||
var dialog_content = $("<div/>")
|
||
.addClass("modal-content")
|
||
.appendTo(dialog);
|
||
if(typeof(options.body) === 'string' && options.sanitize !== false){
|
||
options.body = $("<p/>").text(options.body);
|
||
}
|
||
dialog_content.append(
|
||
$("<div/>")
|
||
.addClass("modal-header")
|
||
.mousedown(function() {
|
||
$(".modal").draggable({handle: '.modal-header'});
|
||
})
|
||
.append($("<button>")
|
||
.attr("type", "button")
|
||
.attr("aria-label", i18n.msg._("close"))
|
||
.addClass("close")
|
||
.attr("data-dismiss", "modal")
|
||
.attr("aria-hidden", "true")
|
||
.html("×")
|
||
).append(
|
||
$("<h4/>")
|
||
.addClass('modal-title')
|
||
.text(options.title || "")
|
||
)
|
||
).append(
|
||
$("<div/>")
|
||
.addClass("modal-body")
|
||
.append(
|
||
options.body || $("<p/>")
|
||
)
|
||
);
|
||
|
||
var footer = $("<div/>").addClass("modal-footer");
|
||
|
||
var default_button;
|
||
|
||
for (var label in options.buttons) {
|
||
var btn_opts = options.buttons[label];
|
||
var button = $("<button/>")
|
||
.addClass("btn btn-default btn-sm")
|
||
.attr("data-dismiss", "modal")
|
||
.text(i18n.msg.translate(label).fetch());
|
||
if (btn_opts.id) {
|
||
button.attr('id', btn_opts.id);
|
||
}
|
||
if (btn_opts.click) {
|
||
button.click($.proxy(btn_opts.click, dialog_content));
|
||
}
|
||
if (btn_opts.class) {
|
||
button.addClass(btn_opts.class);
|
||
}
|
||
footer.append(button);
|
||
if (options.default_button && label === options.default_button) {
|
||
default_button = button;
|
||
}
|
||
}
|
||
if (!options.default_button) {
|
||
default_button = footer.find("button").last();
|
||
}
|
||
dialog_content.append(footer);
|
||
// hook up on-open event
|
||
modal.on("shown.bs.modal", function () {
|
||
setTimeout(function () {
|
||
default_button.focus();
|
||
if (options.open) {
|
||
$.proxy(options.open, modal)();
|
||
}
|
||
}, 0);
|
||
});
|
||
|
||
// destroy modal on hide, unless explicitly asked not to
|
||
if (options.destroy === undefined || options.destroy) {
|
||
modal.on("hidden.bs.modal", function () {
|
||
modal.remove();
|
||
});
|
||
}
|
||
modal.on("hidden.bs.modal", function () {
|
||
if (options.notebook) {
|
||
var cell = options.notebook.get_selected_cell();
|
||
if (cell) cell.select();
|
||
}
|
||
if (options.keyboard_manager) {
|
||
options.keyboard_manager.enable();
|
||
options.keyboard_manager.command_mode();
|
||
}
|
||
if (options.focus_button) {
|
||
$(options.focus_button).focus();
|
||
}
|
||
});
|
||
|
||
if (options.keyboard_manager) {
|
||
options.keyboard_manager.disable();
|
||
}
|
||
|
||
if(options.backdrop === undefined){
|
||
options.backdrop = 'static';
|
||
}
|
||
|
||
return modal.modal(options);
|
||
};
|
||
|
||
var kernel_modal = function (options) {
|
||
/**
|
||
* only one kernel dialog should be open at a time -- but
|
||
* other modal dialogs can still be open
|
||
*/
|
||
$('.kernel-modal').modal('hide');
|
||
var dialog = modal(options);
|
||
dialog.addClass('kernel-modal');
|
||
return dialog;
|
||
};
|
||
|
||
var edit_metadata = function (options) {
|
||
options.name = options.name || "Cell";
|
||
var error_div = $('<div/>').css('color', 'red');
|
||
var message_cell =
|
||
i18n.msg._("Manually edit the JSON below to manipulate the metadata for this cell.");
|
||
var message_notebook =
|
||
i18n.msg._("Manually edit the JSON below to manipulate the metadata for this notebook.");
|
||
var message_end =
|
||
i18n.msg._(" We recommend putting custom metadata attributes in an appropriately named substructure," +
|
||
" so they don't conflict with those of others.");
|
||
|
||
var message;
|
||
if (options.name === 'Notebook') {
|
||
message = message_notebook + message_end;
|
||
} else {
|
||
message = message_cell + message_end;
|
||
}
|
||
var textarea = $('<textarea/>')
|
||
.attr('rows', '13')
|
||
.attr('cols', '80')
|
||
.attr('name', 'metadata')
|
||
.text(JSON.stringify(options.md || {}, null, 2));
|
||
|
||
var dialogform = $('<div/>').attr('title', i18n.msg._('Edit the metadata'))
|
||
.append(
|
||
$('<form/>').append(
|
||
$('<fieldset/>').append(
|
||
$('<label/>')
|
||
.attr('for','metadata')
|
||
.text(message)
|
||
)
|
||
.append(error_div)
|
||
.append($('<br/>'))
|
||
.append(textarea)
|
||
)
|
||
);
|
||
var editor = CodeMirror.fromTextArea(textarea[0], {
|
||
lineNumbers: true,
|
||
matchBrackets: true,
|
||
indentUnit: 2,
|
||
autoIndent: true,
|
||
mode: 'application/json',
|
||
});
|
||
var title_msg;
|
||
if (options.name === "Notebook") {
|
||
title_msg = i18n.msg._("Edit Notebook Metadata");
|
||
} else {
|
||
title_msg = i18n.msg._("Edit Cell Metadata");
|
||
}
|
||
// This statement is used simply so that message extraction
|
||
// will pick up the strings.
|
||
var button_labels = [ i18n.msg._("Cancel"), i18n.msg._("Edit"), i18n.msg._("OK"), i18n.msg._("Apply")];
|
||
var modal_obj = modal({
|
||
title: title_msg,
|
||
body: dialogform,
|
||
default_button: "Cancel",
|
||
buttons: {
|
||
Cancel: {},
|
||
Edit: { class : "btn-primary",
|
||
click: function() {
|
||
/**
|
||
* validate json and set it
|
||
*/
|
||
var new_md;
|
||
try {
|
||
new_md = JSON.parse(editor.getValue());
|
||
} catch(e) {
|
||
console.log(e);
|
||
error_div.text(i18n.msg._('WARNING: Could not save invalid JSON.'));
|
||
return false;
|
||
}
|
||
options.callback(new_md);
|
||
options.notebook.apply_directionality();
|
||
}
|
||
}
|
||
},
|
||
notebook: options.notebook,
|
||
keyboard_manager: options.keyboard_manager,
|
||
});
|
||
|
||
modal_obj.on('shown.bs.modal', function(){ editor.refresh(); });
|
||
modal_obj.on('hide.bs.modal', function(){
|
||
options.edit_metadata_button ? options.edit_metadata_button.focus() : "";});
|
||
};
|
||
|
||
var edit_attachments = function (options) {
|
||
// This shows the Edit Attachments dialog. This dialog allows the
|
||
// user to delete attachments. We show a list of attachments to
|
||
// the user and he can mark some of them for deletion. The deletion
|
||
// is applied when the 'Apply' button of this dialog is pressed.
|
||
var message;
|
||
var attachments_list;
|
||
if (Object.keys(options.attachments).length == 0) {
|
||
message = i18n.msg._("There are no attachments for this cell.");
|
||
attachments_list = $('<div>');
|
||
} else {
|
||
message = i18n.msg._("Current cell attachments");
|
||
|
||
attachments_list = $('<div>')
|
||
.addClass('list_container')
|
||
.append(
|
||
$('<div>')
|
||
.addClass('row list_header')
|
||
.append(
|
||
$('<div>')
|
||
.text(i18n.msg._('Attachments'))
|
||
)
|
||
);
|
||
|
||
// This is a set containing keys of attachments to be deleted when
|
||
// the Apply button is clicked
|
||
var to_delete = {};
|
||
|
||
var refresh_attachments_list = function() {
|
||
$(attachments_list).find('.row').remove();
|
||
for (var key in options.attachments) {
|
||
var mime = Object.keys(options.attachments[key])[0];
|
||
var deleted = key in to_delete;
|
||
|
||
// This ensures the current value of key is captured since
|
||
// javascript only has function scope
|
||
var btn;
|
||
// Trash/restore button
|
||
(function(){
|
||
var _key = key;
|
||
btn = $('<button>')
|
||
.addClass('btn btn-default btn-xs')
|
||
.css('display', 'inline-block');
|
||
if (deleted) {
|
||
btn.attr('title', i18n.msg._('Restore'))
|
||
.append(
|
||
$('<i>')
|
||
.addClass('fa fa-plus')
|
||
);
|
||
btn.click(function() {
|
||
delete to_delete[_key];
|
||
refresh_attachments_list();
|
||
});
|
||
} else {
|
||
btn.attr('title', i18n.msg._('Delete'))
|
||
.addClass('btn-danger')
|
||
.append(
|
||
$('<i>')
|
||
.addClass('fa fa-trash')
|
||
);
|
||
btn.click(function() {
|
||
to_delete[_key] = true;
|
||
refresh_attachments_list();
|
||
});
|
||
}
|
||
return btn;
|
||
})();
|
||
var row = $('<div>')
|
||
.addClass('col-md-12 att_row')
|
||
.append(
|
||
$('<div>')
|
||
.addClass('row')
|
||
.append(
|
||
$('<div>')
|
||
.addClass('att-name col-xs-4')
|
||
.text(key)
|
||
)
|
||
.append(
|
||
$('<div>')
|
||
.addClass('col-xs-4 text-muted')
|
||
.text(mime)
|
||
)
|
||
.append(
|
||
$('<div>')
|
||
.addClass('item-buttons pull-right')
|
||
.append(btn)
|
||
)
|
||
);
|
||
if (deleted) {
|
||
row.find('.att-name')
|
||
.css('text-decoration', 'line-through');
|
||
}
|
||
|
||
attachments_list.append($('<div>')
|
||
.addClass('list_item row')
|
||
.append(row)
|
||
);
|
||
}
|
||
};
|
||
refresh_attachments_list();
|
||
}
|
||
|
||
var dialogform = $('<div/>')
|
||
.attr('title', i18n.msg._('Edit attachments'))
|
||
.append(message)
|
||
.append('<br />')
|
||
.append(attachments_list);
|
||
var title_msg;
|
||
if ( options.name === "Notebook" ) {
|
||
title_msg = i18n.msg._("Edit Notebook Attachments");
|
||
} else {
|
||
title_msg = i18n.msg._("Edit Cell Attachments");
|
||
}
|
||
var modal_obj = modal({
|
||
title: title_msg,
|
||
body: dialogform,
|
||
buttons: {
|
||
Apply: { class : "btn-primary",
|
||
click: function() {
|
||
for (var key in to_delete) {
|
||
delete options.attachments[key];
|
||
}
|
||
options.callback(options.attachments);
|
||
}
|
||
},
|
||
Cancel: {}
|
||
},
|
||
notebook: options.notebook,
|
||
keyboard_manager: options.keyboard_manager,
|
||
});
|
||
};
|
||
|
||
var insert_image = function (options) {
|
||
var message =
|
||
i18n.msg._("Select a file to insert.");
|
||
var file_input = $('<input/>')
|
||
.attr('type', 'file')
|
||
.attr('accept', 'image/*')
|
||
.attr('name', 'file')
|
||
.on('change', function(file) {
|
||
var $btn = $(modal_obj).find('#btn_ok');
|
||
if (this.files.length > 0) {
|
||
$btn.removeClass('disabled');
|
||
} else {
|
||
$btn.addClass('disabled');
|
||
}
|
||
});
|
||
var dialogform = $('<div/>').attr('title', i18n.msg._('Edit attachments'))
|
||
.append(
|
||
$('<form id="insert-image-form" />').append(
|
||
$('<fieldset/>').append(
|
||
$('<label/>')
|
||
.attr('for','file')
|
||
.text(message)
|
||
)
|
||
.append($('<br/>'))
|
||
.append(file_input)
|
||
)
|
||
);
|
||
var modal_obj = modal({
|
||
title: i18n.msg._("Select a file"),
|
||
body: dialogform,
|
||
buttons: {
|
||
OK: {
|
||
id : 'btn_ok',
|
||
class : "btn-primary disabled",
|
||
click: function() {
|
||
options.callback(file_input[0].files[0]);
|
||
}
|
||
},
|
||
Cancel: {}
|
||
},
|
||
notebook: options.notebook,
|
||
keyboard_manager: options.keyboard_manager,
|
||
});
|
||
};
|
||
|
||
|
||
var dialog = {
|
||
modal : modal,
|
||
kernel_modal : kernel_modal,
|
||
edit_metadata : edit_metadata,
|
||
edit_attachments : edit_attachments,
|
||
insert_image : insert_image
|
||
};
|
||
|
||
return dialog;
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../../lib/codemirror"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/addon/comment/comment',["../../lib/codemirror"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
"use strict";
|
||
|
||
var noOptions = {};
|
||
var nonWS = /[^\s\u00a0]/;
|
||
var Pos = CodeMirror.Pos;
|
||
|
||
function firstNonWS(str) {
|
||
var found = str.search(nonWS);
|
||
return found == -1 ? 0 : found;
|
||
}
|
||
|
||
CodeMirror.commands.toggleComment = function(cm) {
|
||
cm.toggleComment();
|
||
};
|
||
|
||
CodeMirror.defineExtension("toggleComment", function(options) {
|
||
if (!options) options = noOptions;
|
||
var cm = this;
|
||
var minLine = Infinity, ranges = this.listSelections(), mode = null;
|
||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||
var from = ranges[i].from(), to = ranges[i].to();
|
||
if (from.line >= minLine) continue;
|
||
if (to.line >= minLine) to = Pos(minLine, 0);
|
||
minLine = from.line;
|
||
if (mode == null) {
|
||
if (cm.uncomment(from, to, options)) mode = "un";
|
||
else { cm.lineComment(from, to, options); mode = "line"; }
|
||
} else if (mode == "un") {
|
||
cm.uncomment(from, to, options);
|
||
} else {
|
||
cm.lineComment(from, to, options);
|
||
}
|
||
}
|
||
});
|
||
|
||
// Rough heuristic to try and detect lines that are part of multi-line string
|
||
function probablyInsideString(cm, pos, line) {
|
||
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line)
|
||
}
|
||
|
||
function getMode(cm, pos) {
|
||
var mode = cm.getMode()
|
||
return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos)
|
||
}
|
||
|
||
CodeMirror.defineExtension("lineComment", function(from, to, options) {
|
||
if (!options) options = noOptions;
|
||
var self = this, mode = getMode(self, from);
|
||
var firstLine = self.getLine(from.line);
|
||
if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
|
||
|
||
var commentString = options.lineComment || mode.lineComment;
|
||
if (!commentString) {
|
||
if (options.blockCommentStart || mode.blockCommentStart) {
|
||
options.fullLines = true;
|
||
self.blockComment(from, to, options);
|
||
}
|
||
return;
|
||
}
|
||
|
||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
|
||
var pad = options.padding == null ? " " : options.padding;
|
||
var blankLines = options.commentBlankLines || from.line == to.line;
|
||
|
||
self.operation(function() {
|
||
if (options.indent) {
|
||
var baseString = null;
|
||
for (var i = from.line; i < end; ++i) {
|
||
var line = self.getLine(i);
|
||
var whitespace = line.slice(0, firstNonWS(line));
|
||
if (baseString == null || baseString.length > whitespace.length) {
|
||
baseString = whitespace;
|
||
}
|
||
}
|
||
for (var i = from.line; i < end; ++i) {
|
||
var line = self.getLine(i), cut = baseString.length;
|
||
if (!blankLines && !nonWS.test(line)) continue;
|
||
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
|
||
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
|
||
}
|
||
} else {
|
||
for (var i = from.line; i < end; ++i) {
|
||
if (blankLines || nonWS.test(self.getLine(i)))
|
||
self.replaceRange(commentString + pad, Pos(i, 0));
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
CodeMirror.defineExtension("blockComment", function(from, to, options) {
|
||
if (!options) options = noOptions;
|
||
var self = this, mode = getMode(self, from);
|
||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||
if (!startString || !endString) {
|
||
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
|
||
self.lineComment(from, to, options);
|
||
return;
|
||
}
|
||
if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
|
||
|
||
var end = Math.min(to.line, self.lastLine());
|
||
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
|
||
|
||
var pad = options.padding == null ? " " : options.padding;
|
||
if (from.line > end) return;
|
||
|
||
self.operation(function() {
|
||
if (options.fullLines != false) {
|
||
var lastLineHasText = nonWS.test(self.getLine(end));
|
||
self.replaceRange(pad + endString, Pos(end));
|
||
self.replaceRange(startString + pad, Pos(from.line, 0));
|
||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
|
||
if (i != end || lastLineHasText)
|
||
self.replaceRange(lead + pad, Pos(i, 0));
|
||
} else {
|
||
self.replaceRange(endString, to);
|
||
self.replaceRange(startString, from);
|
||
}
|
||
});
|
||
});
|
||
|
||
CodeMirror.defineExtension("uncomment", function(from, to, options) {
|
||
if (!options) options = noOptions;
|
||
var self = this, mode = getMode(self, from);
|
||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
|
||
|
||
// Try finding line comments
|
||
var lineString = options.lineComment || mode.lineComment, lines = [];
|
||
var pad = options.padding == null ? " " : options.padding, didSomething;
|
||
lineComment: {
|
||
if (!lineString) break lineComment;
|
||
for (var i = start; i <= end; ++i) {
|
||
var line = self.getLine(i);
|
||
var found = line.indexOf(lineString);
|
||
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
|
||
if (found == -1 && nonWS.test(line)) break lineComment;
|
||
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
||
lines.push(line);
|
||
}
|
||
self.operation(function() {
|
||
for (var i = start; i <= end; ++i) {
|
||
var line = lines[i - start];
|
||
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
|
||
if (pos < 0) continue;
|
||
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
|
||
didSomething = true;
|
||
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
|
||
}
|
||
});
|
||
if (didSomething) return true;
|
||
}
|
||
|
||
// Try block comments
|
||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||
if (!startString || !endString) return false;
|
||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||
var startLine = self.getLine(start), open = startLine.indexOf(startString)
|
||
if (open == -1) return false
|
||
var endLine = end == start ? startLine : self.getLine(end)
|
||
var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
|
||
var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1)
|
||
if (close == -1 ||
|
||
!/comment/.test(self.getTokenTypeAt(insideStart)) ||
|
||
!/comment/.test(self.getTokenTypeAt(insideEnd)) ||
|
||
self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1)
|
||
return false;
|
||
|
||
// Avoid killing block comments completely outside the selection.
|
||
// Positions of the last startString before the start of the selection, and the first endString after it.
|
||
var lastStart = startLine.lastIndexOf(startString, from.ch);
|
||
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
|
||
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
|
||
// Positions of the first endString after the end of the selection, and the last startString before it.
|
||
firstEnd = endLine.indexOf(endString, to.ch);
|
||
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
|
||
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
|
||
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
|
||
|
||
self.operation(function() {
|
||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
|
||
Pos(end, close + endString.length));
|
||
var openEnd = open + startString.length;
|
||
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
|
||
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
|
||
if (lead) for (var i = start + 1; i <= end; ++i) {
|
||
var line = self.getLine(i), found = line.indexOf(lead);
|
||
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
|
||
var foundEnd = found + lead.length;
|
||
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
|
||
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
|
||
}
|
||
});
|
||
return true;
|
||
});
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../../lib/codemirror"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/addon/dialog/dialog',["../../lib/codemirror"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
function dialogDiv(cm, template, bottom) {
|
||
var wrap = cm.getWrapperElement();
|
||
var dialog;
|
||
dialog = wrap.appendChild(document.createElement("div"));
|
||
if (bottom)
|
||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||
else
|
||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||
|
||
if (typeof template == "string") {
|
||
dialog.innerHTML = template;
|
||
} else { // Assuming it's a detached DOM element.
|
||
dialog.appendChild(template);
|
||
}
|
||
CodeMirror.addClass(wrap, 'dialog-opened');
|
||
return dialog;
|
||
}
|
||
|
||
function closeNotification(cm, newVal) {
|
||
if (cm.state.currentNotificationClose)
|
||
cm.state.currentNotificationClose();
|
||
cm.state.currentNotificationClose = newVal;
|
||
}
|
||
|
||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||
if (!options) options = {};
|
||
|
||
closeNotification(this, null);
|
||
|
||
var dialog = dialogDiv(this, template, options.bottom);
|
||
var closed = false, me = this;
|
||
function close(newVal) {
|
||
if (typeof newVal == 'string') {
|
||
inp.value = newVal;
|
||
} else {
|
||
if (closed) return;
|
||
closed = true;
|
||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
|
||
dialog.parentNode.removeChild(dialog);
|
||
me.focus();
|
||
|
||
if (options.onClose) options.onClose(dialog);
|
||
}
|
||
}
|
||
|
||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||
if (inp) {
|
||
inp.focus();
|
||
|
||
if (options.value) {
|
||
inp.value = options.value;
|
||
if (options.selectValueOnOpen !== false) {
|
||
inp.select();
|
||
}
|
||
}
|
||
|
||
if (options.onInput)
|
||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||
if (options.onKeyUp)
|
||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||
|
||
CodeMirror.on(inp, "keydown", function(e) {
|
||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||
inp.blur();
|
||
CodeMirror.e_stop(e);
|
||
close();
|
||
}
|
||
if (e.keyCode == 13) callback(inp.value, e);
|
||
});
|
||
|
||
if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) {
|
||
if (evt.relatedTarget !== null) close();
|
||
});
|
||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||
CodeMirror.on(button, "click", function() {
|
||
close();
|
||
me.focus();
|
||
});
|
||
|
||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||
|
||
button.focus();
|
||
}
|
||
return close;
|
||
});
|
||
|
||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||
closeNotification(this, null);
|
||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||
var buttons = dialog.getElementsByTagName("button");
|
||
var closed = false, me = this, blurring = 1;
|
||
function close() {
|
||
if (closed) return;
|
||
closed = true;
|
||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
|
||
dialog.parentNode.removeChild(dialog);
|
||
me.focus();
|
||
}
|
||
buttons[0].focus();
|
||
for (var i = 0; i < buttons.length; ++i) {
|
||
var b = buttons[i];
|
||
(function(callback) {
|
||
CodeMirror.on(b, "click", function(e) {
|
||
CodeMirror.e_preventDefault(e);
|
||
close();
|
||
if (callback) callback(me);
|
||
});
|
||
})(callbacks[i]);
|
||
CodeMirror.on(b, "blur", function() {
|
||
--blurring;
|
||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||
});
|
||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||
}
|
||
});
|
||
|
||
/*
|
||
* openNotification
|
||
* Opens a notification, that can be closed with an optional timer
|
||
* (default 5000ms timer) and always closes on click.
|
||
*
|
||
* If a notification is opened while another is opened, it will close the
|
||
* currently opened one and open the new one immediately.
|
||
*/
|
||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||
closeNotification(this, close);
|
||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||
var closed = false, doneTimer;
|
||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
|
||
|
||
function close() {
|
||
if (closed) return;
|
||
closed = true;
|
||
clearTimeout(doneTimer);
|
||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
|
||
dialog.parentNode.removeChild(dialog);
|
||
}
|
||
|
||
CodeMirror.on(dialog, 'click', function(e) {
|
||
CodeMirror.e_preventDefault(e);
|
||
close();
|
||
});
|
||
|
||
if (duration)
|
||
doneTimer = setTimeout(close, duration);
|
||
|
||
return close;
|
||
});
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../../lib/codemirror"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/addon/edit/closebrackets',["../../lib/codemirror"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
var defaults = {
|
||
pairs: "()[]{}''\"\"",
|
||
closeBefore: ")]}'\":;>",
|
||
triples: "",
|
||
explode: "[]{}"
|
||
};
|
||
|
||
var Pos = CodeMirror.Pos;
|
||
|
||
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
||
if (old && old != CodeMirror.Init) {
|
||
cm.removeKeyMap(keyMap);
|
||
cm.state.closeBrackets = null;
|
||
}
|
||
if (val) {
|
||
ensureBound(getOption(val, "pairs"))
|
||
cm.state.closeBrackets = val;
|
||
cm.addKeyMap(keyMap);
|
||
}
|
||
});
|
||
|
||
function getOption(conf, name) {
|
||
if (name == "pairs" && typeof conf == "string") return conf;
|
||
if (typeof conf == "object" && conf[name] != null) return conf[name];
|
||
return defaults[name];
|
||
}
|
||
|
||
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
|
||
function ensureBound(chars) {
|
||
for (var i = 0; i < chars.length; i++) {
|
||
var ch = chars.charAt(i), key = "'" + ch + "'"
|
||
if (!keyMap[key]) keyMap[key] = handler(ch)
|
||
}
|
||
}
|
||
ensureBound(defaults.pairs + "`")
|
||
|
||
function handler(ch) {
|
||
return function(cm) { return handleChar(cm, ch); };
|
||
}
|
||
|
||
function getConfig(cm) {
|
||
var deflt = cm.state.closeBrackets;
|
||
if (!deflt || deflt.override) return deflt;
|
||
var mode = cm.getModeAt(cm.getCursor());
|
||
return mode.closeBrackets || deflt;
|
||
}
|
||
|
||
function handleBackspace(cm) {
|
||
var conf = getConfig(cm);
|
||
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||
|
||
var pairs = getOption(conf, "pairs");
|
||
var ranges = cm.listSelections();
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||
var around = charsAround(cm, ranges[i].head);
|
||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||
}
|
||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||
var cur = ranges[i].head;
|
||
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
|
||
}
|
||
}
|
||
|
||
function handleEnter(cm) {
|
||
var conf = getConfig(cm);
|
||
var explode = conf && getOption(conf, "explode");
|
||
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||
|
||
var ranges = cm.listSelections();
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||
var around = charsAround(cm, ranges[i].head);
|
||
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||
}
|
||
cm.operation(function() {
|
||
var linesep = cm.lineSeparator() || "\n";
|
||
cm.replaceSelection(linesep + linesep, null);
|
||
cm.execCommand("goCharLeft");
|
||
ranges = cm.listSelections();
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var line = ranges[i].head.line;
|
||
cm.indentLine(line, null, true);
|
||
cm.indentLine(line + 1, null, true);
|
||
}
|
||
});
|
||
}
|
||
|
||
function contractSelection(sel) {
|
||
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
|
||
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
|
||
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
|
||
}
|
||
|
||
function handleChar(cm, ch) {
|
||
var conf = getConfig(cm);
|
||
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||
|
||
var pairs = getOption(conf, "pairs");
|
||
var pos = pairs.indexOf(ch);
|
||
if (pos == -1) return CodeMirror.Pass;
|
||
|
||
var closeBefore = getOption(conf,"closeBefore");
|
||
|
||
var triples = getOption(conf, "triples");
|
||
|
||
var identical = pairs.charAt(pos + 1) == ch;
|
||
var ranges = cm.listSelections();
|
||
var opening = pos % 2 == 0;
|
||
|
||
var type;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i], cur = range.head, curType;
|
||
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
|
||
if (opening && !range.empty()) {
|
||
curType = "surround";
|
||
} else if ((identical || !opening) && next == ch) {
|
||
if (identical && stringStartsAfter(cm, cur))
|
||
curType = "both";
|
||
else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
|
||
curType = "skipThree";
|
||
else
|
||
curType = "skip";
|
||
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
|
||
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
|
||
if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
|
||
curType = "addFour";
|
||
} else if (identical) {
|
||
var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
|
||
if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both";
|
||
else return CodeMirror.Pass;
|
||
} else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) {
|
||
curType = "both";
|
||
} else {
|
||
return CodeMirror.Pass;
|
||
}
|
||
if (!type) type = curType;
|
||
else if (type != curType) return CodeMirror.Pass;
|
||
}
|
||
|
||
var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
|
||
var right = pos % 2 ? ch : pairs.charAt(pos + 1);
|
||
cm.operation(function() {
|
||
if (type == "skip") {
|
||
cm.execCommand("goCharRight");
|
||
} else if (type == "skipThree") {
|
||
for (var i = 0; i < 3; i++)
|
||
cm.execCommand("goCharRight");
|
||
} else if (type == "surround") {
|
||
var sels = cm.getSelections();
|
||
for (var i = 0; i < sels.length; i++)
|
||
sels[i] = left + sels[i] + right;
|
||
cm.replaceSelections(sels, "around");
|
||
sels = cm.listSelections().slice();
|
||
for (var i = 0; i < sels.length; i++)
|
||
sels[i] = contractSelection(sels[i]);
|
||
cm.setSelections(sels);
|
||
} else if (type == "both") {
|
||
cm.replaceSelection(left + right, null);
|
||
cm.triggerElectric(left + right);
|
||
cm.execCommand("goCharLeft");
|
||
} else if (type == "addFour") {
|
||
cm.replaceSelection(left + left + left + left, "before");
|
||
cm.execCommand("goCharRight");
|
||
}
|
||
});
|
||
}
|
||
|
||
function charsAround(cm, pos) {
|
||
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
|
||
Pos(pos.line, pos.ch + 1));
|
||
return str.length == 2 ? str : null;
|
||
}
|
||
|
||
function stringStartsAfter(cm, pos) {
|
||
var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
|
||
return /\bstring/.test(token.type) && token.start == pos.ch &&
|
||
(pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos)))
|
||
}
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../../lib/codemirror"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/addon/edit/matchbrackets',["../../lib/codemirror"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
|
||
(document.documentMode == null || document.documentMode < 8);
|
||
|
||
var Pos = CodeMirror.Pos;
|
||
|
||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
|
||
|
||
function bracketRegex(config) {
|
||
return config && config.bracketRegex || /[(){}[\]]/
|
||
}
|
||
|
||
function findMatchingBracket(cm, where, config) {
|
||
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
|
||
var afterCursor = config && config.afterCursor
|
||
if (afterCursor == null)
|
||
afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
|
||
var re = bracketRegex(config)
|
||
|
||
// A cursor is defined as between two characters, but in in vim command mode
|
||
// (i.e. not insert mode), the cursor is visually represented as a
|
||
// highlighted box on top of the 2nd character. Otherwise, we allow matches
|
||
// from before or after the cursor.
|
||
var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) ||
|
||
re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)];
|
||
if (!match) return null;
|
||
var dir = match.charAt(1) == ">" ? 1 : -1;
|
||
if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
|
||
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
|
||
|
||
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
|
||
if (found == null) return null;
|
||
return {from: Pos(where.line, pos), to: found && found.pos,
|
||
match: found && found.ch == match.charAt(0), forward: dir > 0};
|
||
}
|
||
|
||
// bracketRegex is used to specify which type of bracket to scan
|
||
// should be a regexp, e.g. /[[\]]/
|
||
//
|
||
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
||
//
|
||
// Returns false when no bracket was found, null when it reached
|
||
// maxScanLines and gave up
|
||
function scanForBracket(cm, where, dir, style, config) {
|
||
var maxScanLen = (config && config.maxScanLineLength) || 10000;
|
||
var maxScanLines = (config && config.maxScanLines) || 1000;
|
||
|
||
var stack = [];
|
||
var re = bracketRegex(config)
|
||
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
|
||
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
|
||
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
|
||
var line = cm.getLine(lineNo);
|
||
if (!line) continue;
|
||
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
|
||
if (line.length > maxScanLen) continue;
|
||
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
|
||
for (; pos != end; pos += dir) {
|
||
var ch = line.charAt(pos);
|
||
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
|
||
var match = matching[ch];
|
||
if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
|
||
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
|
||
else stack.pop();
|
||
}
|
||
}
|
||
}
|
||
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
|
||
}
|
||
|
||
function matchBrackets(cm, autoclear, config) {
|
||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
|
||
var marks = [], ranges = cm.listSelections();
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
|
||
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
|
||
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
||
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
|
||
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
|
||
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
|
||
}
|
||
}
|
||
|
||
if (marks.length) {
|
||
// Kludge to work around the IE bug from issue #1193, where text
|
||
// input stops going to the textare whever this fires.
|
||
if (ie_lt8 && cm.state.focused) cm.focus();
|
||
|
||
var clear = function() {
|
||
cm.operation(function() {
|
||
for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||
});
|
||
};
|
||
if (autoclear) setTimeout(clear, 800);
|
||
else return clear;
|
||
}
|
||
}
|
||
|
||
function doMatchBrackets(cm) {
|
||
cm.operation(function() {
|
||
if (cm.state.matchBrackets.currentlyHighlighted) {
|
||
cm.state.matchBrackets.currentlyHighlighted();
|
||
cm.state.matchBrackets.currentlyHighlighted = null;
|
||
}
|
||
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
|
||
});
|
||
}
|
||
|
||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
|
||
function clear(cm) {
|
||
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
|
||
cm.state.matchBrackets.currentlyHighlighted();
|
||
cm.state.matchBrackets.currentlyHighlighted = null;
|
||
}
|
||
}
|
||
|
||
if (old && old != CodeMirror.Init) {
|
||
cm.off("cursorActivity", doMatchBrackets);
|
||
cm.off("focus", doMatchBrackets)
|
||
cm.off("blur", clear)
|
||
clear(cm);
|
||
}
|
||
if (val) {
|
||
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
||
cm.on("cursorActivity", doMatchBrackets);
|
||
cm.on("focus", doMatchBrackets)
|
||
cm.on("blur", clear)
|
||
}
|
||
});
|
||
|
||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
||
CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
|
||
// Backwards-compatibility kludge
|
||
if (oldConfig || typeof config == "boolean") {
|
||
if (!oldConfig) {
|
||
config = config ? {strict: true} : null
|
||
} else {
|
||
oldConfig.strict = config
|
||
config = oldConfig
|
||
}
|
||
}
|
||
return findMatchingBracket(this, pos, config)
|
||
});
|
||
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
|
||
return scanForBracket(this, pos, dir, style, config);
|
||
});
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../../lib/codemirror"))
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/addon/search/searchcursor',["../../lib/codemirror"], mod)
|
||
else // Plain browser env
|
||
mod(CodeMirror)
|
||
})(function(CodeMirror) {
|
||
"use strict"
|
||
var Pos = CodeMirror.Pos
|
||
|
||
function regexpFlags(regexp) {
|
||
var flags = regexp.flags
|
||
return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
|
||
+ (regexp.global ? "g" : "")
|
||
+ (regexp.multiline ? "m" : "")
|
||
}
|
||
|
||
function ensureFlags(regexp, flags) {
|
||
var current = regexpFlags(regexp), target = current
|
||
for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
|
||
target += flags.charAt(i)
|
||
return current == target ? regexp : new RegExp(regexp.source, target)
|
||
}
|
||
|
||
function maybeMultiline(regexp) {
|
||
return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
|
||
}
|
||
|
||
function searchRegexpForward(doc, regexp, start) {
|
||
regexp = ensureFlags(regexp, "g")
|
||
for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
|
||
regexp.lastIndex = ch
|
||
var string = doc.getLine(line), match = regexp.exec(string)
|
||
if (match)
|
||
return {from: Pos(line, match.index),
|
||
to: Pos(line, match.index + match[0].length),
|
||
match: match}
|
||
}
|
||
}
|
||
|
||
function searchRegexpForwardMultiline(doc, regexp, start) {
|
||
if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
|
||
|
||
regexp = ensureFlags(regexp, "gm")
|
||
var string, chunk = 1
|
||
for (var line = start.line, last = doc.lastLine(); line <= last;) {
|
||
// This grows the search buffer in exponentially-sized chunks
|
||
// between matches, so that nearby matches are fast and don't
|
||
// require concatenating the whole document (in case we're
|
||
// searching for something that has tons of matches), but at the
|
||
// same time, the amount of retries is limited.
|
||
for (var i = 0; i < chunk; i++) {
|
||
if (line > last) break
|
||
var curLine = doc.getLine(line++)
|
||
string = string == null ? curLine : string + "\n" + curLine
|
||
}
|
||
chunk = chunk * 2
|
||
regexp.lastIndex = start.ch
|
||
var match = regexp.exec(string)
|
||
if (match) {
|
||
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
|
||
var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length
|
||
return {from: Pos(startLine, startCh),
|
||
to: Pos(startLine + inside.length - 1,
|
||
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
|
||
match: match}
|
||
}
|
||
}
|
||
}
|
||
|
||
function lastMatchIn(string, regexp, endMargin) {
|
||
var match, from = 0
|
||
while (from <= string.length) {
|
||
regexp.lastIndex = from
|
||
var newMatch = regexp.exec(string)
|
||
if (!newMatch) break
|
||
var end = newMatch.index + newMatch[0].length
|
||
if (end > string.length - endMargin) break
|
||
if (!match || end > match.index + match[0].length)
|
||
match = newMatch
|
||
from = newMatch.index + 1
|
||
}
|
||
return match
|
||
}
|
||
|
||
function searchRegexpBackward(doc, regexp, start) {
|
||
regexp = ensureFlags(regexp, "g")
|
||
for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
|
||
var string = doc.getLine(line)
|
||
var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch)
|
||
if (match)
|
||
return {from: Pos(line, match.index),
|
||
to: Pos(line, match.index + match[0].length),
|
||
match: match}
|
||
}
|
||
}
|
||
|
||
function searchRegexpBackwardMultiline(doc, regexp, start) {
|
||
if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start)
|
||
regexp = ensureFlags(regexp, "gm")
|
||
var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch
|
||
for (var line = start.line, first = doc.firstLine(); line >= first;) {
|
||
for (var i = 0; i < chunkSize && line >= first; i++) {
|
||
var curLine = doc.getLine(line--)
|
||
string = string == null ? curLine : curLine + "\n" + string
|
||
}
|
||
chunkSize *= 2
|
||
|
||
var match = lastMatchIn(string, regexp, endMargin)
|
||
if (match) {
|
||
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
|
||
var startLine = line + before.length, startCh = before[before.length - 1].length
|
||
return {from: Pos(startLine, startCh),
|
||
to: Pos(startLine + inside.length - 1,
|
||
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
|
||
match: match}
|
||
}
|
||
}
|
||
}
|
||
|
||
var doFold, noFold
|
||
if (String.prototype.normalize) {
|
||
doFold = function(str) { return str.normalize("NFD").toLowerCase() }
|
||
noFold = function(str) { return str.normalize("NFD") }
|
||
} else {
|
||
doFold = function(str) { return str.toLowerCase() }
|
||
noFold = function(str) { return str }
|
||
}
|
||
|
||
// Maps a position in a case-folded line back to a position in the original line
|
||
// (compensating for codepoints increasing in number during folding)
|
||
function adjustPos(orig, folded, pos, foldFunc) {
|
||
if (orig.length == folded.length) return pos
|
||
for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) {
|
||
if (min == max) return min
|
||
var mid = (min + max) >> 1
|
||
var len = foldFunc(orig.slice(0, mid)).length
|
||
if (len == pos) return mid
|
||
else if (len > pos) max = mid
|
||
else min = mid + 1
|
||
}
|
||
}
|
||
|
||
function searchStringForward(doc, query, start, caseFold) {
|
||
// Empty string would match anything and never progress, so we
|
||
// define it to match nothing instead.
|
||
if (!query.length) return null
|
||
var fold = caseFold ? doFold : noFold
|
||
var lines = fold(query).split(/\r|\n\r?/)
|
||
|
||
search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) {
|
||
var orig = doc.getLine(line).slice(ch), string = fold(orig)
|
||
if (lines.length == 1) {
|
||
var found = string.indexOf(lines[0])
|
||
if (found == -1) continue search
|
||
var start = adjustPos(orig, string, found, fold) + ch
|
||
return {from: Pos(line, adjustPos(orig, string, found, fold) + ch),
|
||
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)}
|
||
} else {
|
||
var cutFrom = string.length - lines[0].length
|
||
if (string.slice(cutFrom) != lines[0]) continue search
|
||
for (var i = 1; i < lines.length - 1; i++)
|
||
if (fold(doc.getLine(line + i)) != lines[i]) continue search
|
||
var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1]
|
||
if (endString.slice(0, lastLine.length) != lastLine) continue search
|
||
return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch),
|
||
to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))}
|
||
}
|
||
}
|
||
}
|
||
|
||
function searchStringBackward(doc, query, start, caseFold) {
|
||
if (!query.length) return null
|
||
var fold = caseFold ? doFold : noFold
|
||
var lines = fold(query).split(/\r|\n\r?/)
|
||
|
||
search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) {
|
||
var orig = doc.getLine(line)
|
||
if (ch > -1) orig = orig.slice(0, ch)
|
||
var string = fold(orig)
|
||
if (lines.length == 1) {
|
||
var found = string.lastIndexOf(lines[0])
|
||
if (found == -1) continue search
|
||
return {from: Pos(line, adjustPos(orig, string, found, fold)),
|
||
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))}
|
||
} else {
|
||
var lastLine = lines[lines.length - 1]
|
||
if (string.slice(0, lastLine.length) != lastLine) continue search
|
||
for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++)
|
||
if (fold(doc.getLine(start + i)) != lines[i]) continue search
|
||
var top = doc.getLine(line + 1 - lines.length), topString = fold(top)
|
||
if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search
|
||
return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)),
|
||
to: Pos(line, adjustPos(orig, string, lastLine.length, fold))}
|
||
}
|
||
}
|
||
}
|
||
|
||
function SearchCursor(doc, query, pos, options) {
|
||
this.atOccurrence = false
|
||
this.doc = doc
|
||
pos = pos ? doc.clipPos(pos) : Pos(0, 0)
|
||
this.pos = {from: pos, to: pos}
|
||
|
||
var caseFold
|
||
if (typeof options == "object") {
|
||
caseFold = options.caseFold
|
||
} else { // Backwards compat for when caseFold was the 4th argument
|
||
caseFold = options
|
||
options = null
|
||
}
|
||
|
||
if (typeof query == "string") {
|
||
if (caseFold == null) caseFold = false
|
||
this.matches = function(reverse, pos) {
|
||
return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
|
||
}
|
||
} else {
|
||
query = ensureFlags(query, "gm")
|
||
if (!options || options.multiline !== false)
|
||
this.matches = function(reverse, pos) {
|
||
return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
|
||
}
|
||
else
|
||
this.matches = function(reverse, pos) {
|
||
return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
|
||
}
|
||
}
|
||
}
|
||
|
||
SearchCursor.prototype = {
|
||
findNext: function() {return this.find(false)},
|
||
findPrevious: function() {return this.find(true)},
|
||
|
||
find: function(reverse) {
|
||
var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to))
|
||
|
||
// Implements weird auto-growing behavior on null-matches for
|
||
// backwards-compatibility with the vim code (unfortunately)
|
||
while (result && CodeMirror.cmpPos(result.from, result.to) == 0) {
|
||
if (reverse) {
|
||
if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1)
|
||
else if (result.from.line == this.doc.firstLine()) result = null
|
||
else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1)))
|
||
} else {
|
||
if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1)
|
||
else if (result.to.line == this.doc.lastLine()) result = null
|
||
else result = this.matches(reverse, Pos(result.to.line + 1, 0))
|
||
}
|
||
}
|
||
|
||
if (result) {
|
||
this.pos = result
|
||
this.atOccurrence = true
|
||
return this.pos.match || true
|
||
} else {
|
||
var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0)
|
||
this.pos = {from: end, to: end}
|
||
return this.atOccurrence = false
|
||
}
|
||
},
|
||
|
||
from: function() {if (this.atOccurrence) return this.pos.from},
|
||
to: function() {if (this.atOccurrence) return this.pos.to},
|
||
|
||
replace: function(newText, origin) {
|
||
if (!this.atOccurrence) return
|
||
var lines = CodeMirror.splitLines(newText)
|
||
this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin)
|
||
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
|
||
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0))
|
||
}
|
||
}
|
||
|
||
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
|
||
return new SearchCursor(this.doc, query, pos, caseFold)
|
||
})
|
||
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
|
||
return new SearchCursor(this, query, pos, caseFold)
|
||
})
|
||
|
||
CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
|
||
var ranges = []
|
||
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold)
|
||
while (cur.findNext()) {
|
||
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break
|
||
ranges.push({anchor: cur.from(), head: cur.to()})
|
||
}
|
||
if (ranges.length)
|
||
this.setSelections(ranges, 0)
|
||
})
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
// Define search commands. Depends on dialog.js or another
|
||
// implementation of the openDialog method.
|
||
|
||
// Replace works a little oddly -- it will do the replace on the next
|
||
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
|
||
// replace by making sure the match is no longer selected when hitting
|
||
// Ctrl-G.
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/addon/search/search',["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
"use strict";
|
||
|
||
function searchOverlay(query, caseInsensitive) {
|
||
if (typeof query == "string")
|
||
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
|
||
else if (!query.global)
|
||
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
|
||
|
||
return {token: function(stream) {
|
||
query.lastIndex = stream.pos;
|
||
var match = query.exec(stream.string);
|
||
if (match && match.index == stream.pos) {
|
||
stream.pos += match[0].length || 1;
|
||
return "searching";
|
||
} else if (match) {
|
||
stream.pos = match.index;
|
||
} else {
|
||
stream.skipToEnd();
|
||
}
|
||
}};
|
||
}
|
||
|
||
function SearchState() {
|
||
this.posFrom = this.posTo = this.lastQuery = this.query = null;
|
||
this.overlay = null;
|
||
}
|
||
|
||
function getSearchState(cm) {
|
||
return cm.state.search || (cm.state.search = new SearchState());
|
||
}
|
||
|
||
function queryCaseInsensitive(query) {
|
||
return typeof query == "string" && query == query.toLowerCase();
|
||
}
|
||
|
||
function getSearchCursor(cm, query, pos) {
|
||
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
||
return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
|
||
}
|
||
|
||
function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
|
||
cm.openDialog(text, onEnter, {
|
||
value: deflt,
|
||
selectValueOnOpen: true,
|
||
closeOnEnter: false,
|
||
onClose: function() { clearSearch(cm); },
|
||
onKeyDown: onKeyDown
|
||
});
|
||
}
|
||
|
||
function dialog(cm, text, shortText, deflt, f) {
|
||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
|
||
else f(prompt(shortText, deflt));
|
||
}
|
||
|
||
function confirmDialog(cm, text, shortText, fs) {
|
||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||
else if (confirm(shortText)) fs[0]();
|
||
}
|
||
|
||
function parseString(string) {
|
||
return string.replace(/\\([nrt\\])/g, function(match, ch) {
|
||
if (ch == "n") return "\n"
|
||
if (ch == "r") return "\r"
|
||
if (ch == "t") return "\t"
|
||
if (ch == "\\") return "\\"
|
||
return match
|
||
})
|
||
}
|
||
|
||
function parseQuery(query) {
|
||
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
||
if (isRE) {
|
||
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
|
||
catch(e) {} // Not a regular expression after all, do a string search
|
||
} else {
|
||
query = parseString(query)
|
||
}
|
||
if (typeof query == "string" ? query == "" : query.test(""))
|
||
query = /x^/;
|
||
return query;
|
||
}
|
||
|
||
function startSearch(cm, state, query) {
|
||
state.queryText = query;
|
||
state.query = parseQuery(query);
|
||
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
||
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
||
cm.addOverlay(state.overlay);
|
||
if (cm.showMatchesOnScrollbar) {
|
||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
|
||
}
|
||
}
|
||
|
||
function doSearch(cm, rev, persistent, immediate) {
|
||
var state = getSearchState(cm);
|
||
if (state.query) return findNext(cm, rev);
|
||
var q = cm.getSelection() || state.lastQuery;
|
||
if (q instanceof RegExp && q.source == "x^") q = null
|
||
if (persistent && cm.openDialog) {
|
||
var hiding = null
|
||
var searchNext = function(query, event) {
|
||
CodeMirror.e_stop(event);
|
||
if (!query) return;
|
||
if (query != state.queryText) {
|
||
startSearch(cm, state, query);
|
||
state.posFrom = state.posTo = cm.getCursor();
|
||
}
|
||
if (hiding) hiding.style.opacity = 1
|
||
findNext(cm, event.shiftKey, function(_, to) {
|
||
var dialog
|
||
if (to.line < 3 && document.querySelector &&
|
||
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
|
||
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
|
||
(hiding = dialog).style.opacity = .4
|
||
})
|
||
};
|
||
persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) {
|
||
var keyName = CodeMirror.keyName(event)
|
||
var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
|
||
if (cmd == "findNext" || cmd == "findPrev" ||
|
||
cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
|
||
CodeMirror.e_stop(event);
|
||
startSearch(cm, getSearchState(cm), query);
|
||
cm.execCommand(cmd);
|
||
} else if (cmd == "find" || cmd == "findPersistent") {
|
||
CodeMirror.e_stop(event);
|
||
searchNext(query, event);
|
||
}
|
||
});
|
||
if (immediate && q) {
|
||
startSearch(cm, state, q);
|
||
findNext(cm, rev);
|
||
}
|
||
} else {
|
||
dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) {
|
||
if (query && !state.query) cm.operation(function() {
|
||
startSearch(cm, state, query);
|
||
state.posFrom = state.posTo = cm.getCursor();
|
||
findNext(cm, rev);
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
function findNext(cm, rev, callback) {cm.operation(function() {
|
||
var state = getSearchState(cm);
|
||
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
|
||
if (!cursor.find(rev)) {
|
||
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
|
||
if (!cursor.find(rev)) return;
|
||
}
|
||
cm.setSelection(cursor.from(), cursor.to());
|
||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
|
||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||
if (callback) callback(cursor.from(), cursor.to())
|
||
});}
|
||
|
||
function clearSearch(cm) {cm.operation(function() {
|
||
var state = getSearchState(cm);
|
||
state.lastQuery = state.query;
|
||
if (!state.query) return;
|
||
state.query = state.queryText = null;
|
||
cm.removeOverlay(state.overlay);
|
||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||
});}
|
||
|
||
|
||
function getQueryDialog(cm) {
|
||
return '<span class="CodeMirror-search-label">' + cm.phrase("Search:") + '</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">' + cm.phrase("(Use /re/ syntax for regexp search)") + '</span>';
|
||
}
|
||
function getReplaceQueryDialog(cm) {
|
||
return ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">' + cm.phrase("(Use /re/ syntax for regexp search)") + '</span>';
|
||
}
|
||
function getReplacementQueryDialog(cm) {
|
||
return '<span class="CodeMirror-search-label">' + cm.phrase("With:") + '</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
||
}
|
||
function getDoReplaceConfirm(cm) {
|
||
return '<span class="CodeMirror-search-label">' + cm.phrase("Replace?") + '</span> <button>' + cm.phrase("Yes") + '</button> <button>' + cm.phrase("No") + '</button> <button>' + cm.phrase("All") + '</button> <button>' + cm.phrase("Stop") + '</button> ';
|
||
}
|
||
|
||
function replaceAll(cm, query, text) {
|
||
cm.operation(function() {
|
||
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
||
if (typeof query != "string") {
|
||
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
||
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||
} else cursor.replace(text);
|
||
}
|
||
});
|
||
}
|
||
|
||
function replace(cm, all) {
|
||
if (cm.getOption("readOnly")) return;
|
||
var query = cm.getSelection() || getSearchState(cm).lastQuery;
|
||
var dialogText = '<span class="CodeMirror-search-label">' + (all ? cm.phrase("Replace all:") : cm.phrase("Replace:")) + '</span>';
|
||
dialog(cm, dialogText + getReplaceQueryDialog(cm), dialogText, query, function(query) {
|
||
if (!query) return;
|
||
query = parseQuery(query);
|
||
dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) {
|
||
text = parseString(text)
|
||
if (all) {
|
||
replaceAll(cm, query, text)
|
||
} else {
|
||
clearSearch(cm);
|
||
var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
|
||
var advance = function() {
|
||
var start = cursor.from(), match;
|
||
if (!(match = cursor.findNext())) {
|
||
cursor = getSearchCursor(cm, query);
|
||
if (!(match = cursor.findNext()) ||
|
||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
||
}
|
||
cm.setSelection(cursor.from(), cursor.to());
|
||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
|
||
confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"),
|
||
[function() {doReplace(match);}, advance,
|
||
function() {replaceAll(cm, query, text)}]);
|
||
};
|
||
var doReplace = function(match) {
|
||
cursor.replace(typeof query == "string" ? text :
|
||
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||
advance();
|
||
};
|
||
advance();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
||
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
|
||
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
|
||
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
|
||
CodeMirror.commands.findNext = doSearch;
|
||
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
||
CodeMirror.commands.clearSearch = clearSearch;
|
||
CodeMirror.commands.replace = replace;
|
||
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../lib/codemirror"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/keymap/emacs',["../lib/codemirror"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
"use strict";
|
||
|
||
var Pos = CodeMirror.Pos;
|
||
function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }
|
||
|
||
// Kill 'ring'
|
||
|
||
var killRing = [];
|
||
function addToRing(str) {
|
||
killRing.push(str);
|
||
if (killRing.length > 50) killRing.shift();
|
||
}
|
||
function growRingTop(str) {
|
||
if (!killRing.length) return addToRing(str);
|
||
killRing[killRing.length - 1] += str;
|
||
}
|
||
function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; }
|
||
function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
|
||
|
||
var lastKill = null;
|
||
|
||
function kill(cm, from, to, ring, text) {
|
||
if (text == null) text = cm.getRange(from, to);
|
||
|
||
if (ring == "grow" && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen))
|
||
growRingTop(text);
|
||
else if (ring !== false)
|
||
addToRing(text);
|
||
cm.replaceRange("", from, to, "+delete");
|
||
|
||
if (ring == "grow") lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()};
|
||
else lastKill = null;
|
||
}
|
||
|
||
// Boundaries of various units
|
||
|
||
function byChar(cm, pos, dir) {
|
||
return cm.findPosH(pos, dir, "char", true);
|
||
}
|
||
|
||
function byWord(cm, pos, dir) {
|
||
return cm.findPosH(pos, dir, "word", true);
|
||
}
|
||
|
||
function byLine(cm, pos, dir) {
|
||
return cm.findPosV(pos, dir, "line", cm.doc.sel.goalColumn);
|
||
}
|
||
|
||
function byPage(cm, pos, dir) {
|
||
return cm.findPosV(pos, dir, "page", cm.doc.sel.goalColumn);
|
||
}
|
||
|
||
function byParagraph(cm, pos, dir) {
|
||
var no = pos.line, line = cm.getLine(no);
|
||
var sawText = /\S/.test(dir < 0 ? line.slice(0, pos.ch) : line.slice(pos.ch));
|
||
var fst = cm.firstLine(), lst = cm.lastLine();
|
||
for (;;) {
|
||
no += dir;
|
||
if (no < fst || no > lst)
|
||
return cm.clipPos(Pos(no - dir, dir < 0 ? 0 : null));
|
||
line = cm.getLine(no);
|
||
var hasText = /\S/.test(line);
|
||
if (hasText) sawText = true;
|
||
else if (sawText) return Pos(no, 0);
|
||
}
|
||
}
|
||
|
||
function bySentence(cm, pos, dir) {
|
||
var line = pos.line, ch = pos.ch;
|
||
var text = cm.getLine(pos.line), sawWord = false;
|
||
for (;;) {
|
||
var next = text.charAt(ch + (dir < 0 ? -1 : 0));
|
||
if (!next) { // End/beginning of line reached
|
||
if (line == (dir < 0 ? cm.firstLine() : cm.lastLine())) return Pos(line, ch);
|
||
text = cm.getLine(line + dir);
|
||
if (!/\S/.test(text)) return Pos(line, ch);
|
||
line += dir;
|
||
ch = dir < 0 ? text.length : 0;
|
||
continue;
|
||
}
|
||
if (sawWord && /[!?.]/.test(next)) return Pos(line, ch + (dir > 0 ? 1 : 0));
|
||
if (!sawWord) sawWord = /\w/.test(next);
|
||
ch += dir;
|
||
}
|
||
}
|
||
|
||
function byExpr(cm, pos, dir) {
|
||
var wrap;
|
||
if (cm.findMatchingBracket && (wrap = cm.findMatchingBracket(pos, {strict: true}))
|
||
&& wrap.match && (wrap.forward ? 1 : -1) == dir)
|
||
return dir > 0 ? Pos(wrap.to.line, wrap.to.ch + 1) : wrap.to;
|
||
|
||
for (var first = true;; first = false) {
|
||
var token = cm.getTokenAt(pos);
|
||
var after = Pos(pos.line, dir < 0 ? token.start : token.end);
|
||
if (first && dir > 0 && token.end == pos.ch || !/\w/.test(token.string)) {
|
||
var newPos = cm.findPosH(after, dir, "char");
|
||
if (posEq(after, newPos)) return pos;
|
||
else pos = newPos;
|
||
} else {
|
||
return after;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Prefixes (only crudely supported)
|
||
|
||
function getPrefix(cm, precise) {
|
||
var digits = cm.state.emacsPrefix;
|
||
if (!digits) return precise ? null : 1;
|
||
clearPrefix(cm);
|
||
return digits == "-" ? -1 : Number(digits);
|
||
}
|
||
|
||
function repeated(cmd) {
|
||
var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd;
|
||
return function(cm) {
|
||
var prefix = getPrefix(cm);
|
||
f(cm);
|
||
for (var i = 1; i < prefix; ++i) f(cm);
|
||
};
|
||
}
|
||
|
||
function findEnd(cm, pos, by, dir) {
|
||
var prefix = getPrefix(cm);
|
||
if (prefix < 0) { dir = -dir; prefix = -prefix; }
|
||
for (var i = 0; i < prefix; ++i) {
|
||
var newPos = by(cm, pos, dir);
|
||
if (posEq(newPos, pos)) break;
|
||
pos = newPos;
|
||
}
|
||
return pos;
|
||
}
|
||
|
||
function move(by, dir) {
|
||
var f = function(cm) {
|
||
cm.extendSelection(findEnd(cm, cm.getCursor(), by, dir));
|
||
};
|
||
f.motion = true;
|
||
return f;
|
||
}
|
||
|
||
function killTo(cm, by, dir, ring) {
|
||
var selections = cm.listSelections(), cursor;
|
||
var i = selections.length;
|
||
while (i--) {
|
||
cursor = selections[i].head;
|
||
kill(cm, cursor, findEnd(cm, cursor, by, dir), ring);
|
||
}
|
||
}
|
||
|
||
function killRegion(cm, ring) {
|
||
if (cm.somethingSelected()) {
|
||
var selections = cm.listSelections(), selection;
|
||
var i = selections.length;
|
||
while (i--) {
|
||
selection = selections[i];
|
||
kill(cm, selection.anchor, selection.head, ring);
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
function addPrefix(cm, digit) {
|
||
if (cm.state.emacsPrefix) {
|
||
if (digit != "-") cm.state.emacsPrefix += digit;
|
||
return;
|
||
}
|
||
// Not active yet
|
||
cm.state.emacsPrefix = digit;
|
||
cm.on("keyHandled", maybeClearPrefix);
|
||
cm.on("inputRead", maybeDuplicateInput);
|
||
}
|
||
|
||
var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true};
|
||
|
||
function maybeClearPrefix(cm, arg) {
|
||
if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg))
|
||
clearPrefix(cm);
|
||
}
|
||
|
||
function clearPrefix(cm) {
|
||
cm.state.emacsPrefix = null;
|
||
cm.off("keyHandled", maybeClearPrefix);
|
||
cm.off("inputRead", maybeDuplicateInput);
|
||
}
|
||
|
||
function maybeDuplicateInput(cm, event) {
|
||
var dup = getPrefix(cm);
|
||
if (dup > 1 && event.origin == "+input") {
|
||
var one = event.text.join("\n"), txt = "";
|
||
for (var i = 1; i < dup; ++i) txt += one;
|
||
cm.replaceSelection(txt);
|
||
}
|
||
}
|
||
|
||
function addPrefixMap(cm) {
|
||
cm.state.emacsPrefixMap = true;
|
||
cm.addKeyMap(prefixMap);
|
||
cm.on("keyHandled", maybeRemovePrefixMap);
|
||
cm.on("inputRead", maybeRemovePrefixMap);
|
||
}
|
||
|
||
function maybeRemovePrefixMap(cm, arg) {
|
||
if (typeof arg == "string" && (/^\d$/.test(arg) || arg == "Ctrl-U")) return;
|
||
cm.removeKeyMap(prefixMap);
|
||
cm.state.emacsPrefixMap = false;
|
||
cm.off("keyHandled", maybeRemovePrefixMap);
|
||
cm.off("inputRead", maybeRemovePrefixMap);
|
||
}
|
||
|
||
// Utilities
|
||
|
||
function setMark(cm) {
|
||
cm.setCursor(cm.getCursor());
|
||
cm.setExtending(!cm.getExtending());
|
||
cm.on("change", function() { cm.setExtending(false); });
|
||
}
|
||
|
||
function clearMark(cm) {
|
||
cm.setExtending(false);
|
||
cm.setCursor(cm.getCursor());
|
||
}
|
||
|
||
function getInput(cm, msg, f) {
|
||
if (cm.openDialog)
|
||
cm.openDialog(msg + ": <input type=\"text\" style=\"width: 10em\"/>", f, {bottom: true});
|
||
else
|
||
f(prompt(msg, ""));
|
||
}
|
||
|
||
function operateOnWord(cm, op) {
|
||
var start = cm.getCursor(), end = cm.findPosH(start, 1, "word");
|
||
cm.replaceRange(op(cm.getRange(start, end)), start, end);
|
||
cm.setCursor(end);
|
||
}
|
||
|
||
function toEnclosingExpr(cm) {
|
||
var pos = cm.getCursor(), line = pos.line, ch = pos.ch;
|
||
var stack = [];
|
||
while (line >= cm.firstLine()) {
|
||
var text = cm.getLine(line);
|
||
for (var i = ch == null ? text.length : ch; i > 0;) {
|
||
var ch = text.charAt(--i);
|
||
if (ch == ")")
|
||
stack.push("(");
|
||
else if (ch == "]")
|
||
stack.push("[");
|
||
else if (ch == "}")
|
||
stack.push("{");
|
||
else if (/[\(\{\[]/.test(ch) && (!stack.length || stack.pop() != ch))
|
||
return cm.extendSelection(Pos(line, i));
|
||
}
|
||
--line; ch = null;
|
||
}
|
||
}
|
||
|
||
function quit(cm) {
|
||
cm.execCommand("clearSearch");
|
||
clearMark(cm);
|
||
}
|
||
|
||
CodeMirror.emacs = {kill: kill, killRegion: killRegion, repeated: repeated};
|
||
|
||
// Actual keymap
|
||
|
||
var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({
|
||
"Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"), true);},
|
||
"Ctrl-K": repeated(function(cm) {
|
||
var start = cm.getCursor(), end = cm.clipPos(Pos(start.line));
|
||
var text = cm.getRange(start, end);
|
||
if (!/\S/.test(text)) {
|
||
text += "\n";
|
||
end = Pos(start.line + 1, 0);
|
||
}
|
||
kill(cm, start, end, "grow", text);
|
||
}),
|
||
"Alt-W": function(cm) {
|
||
addToRing(cm.getSelection());
|
||
clearMark(cm);
|
||
},
|
||
"Ctrl-Y": function(cm) {
|
||
var start = cm.getCursor();
|
||
cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste");
|
||
cm.setSelection(start, cm.getCursor());
|
||
},
|
||
"Alt-Y": function(cm) {cm.replaceSelection(popFromRing(), "around", "paste");},
|
||
|
||
"Ctrl-Space": setMark, "Ctrl-Shift-2": setMark,
|
||
|
||
"Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1),
|
||
"Right": move(byChar, 1), "Left": move(byChar, -1),
|
||
"Ctrl-D": function(cm) { killTo(cm, byChar, 1, false); },
|
||
"Delete": function(cm) { killRegion(cm, false) || killTo(cm, byChar, 1, false); },
|
||
"Ctrl-H": function(cm) { killTo(cm, byChar, -1, false); },
|
||
"Backspace": function(cm) { killRegion(cm, false) || killTo(cm, byChar, -1, false); },
|
||
|
||
"Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1),
|
||
"Alt-Right": move(byWord, 1), "Alt-Left": move(byWord, -1),
|
||
"Alt-D": function(cm) { killTo(cm, byWord, 1, "grow"); },
|
||
"Alt-Backspace": function(cm) { killTo(cm, byWord, -1, "grow"); },
|
||
|
||
"Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1),
|
||
"Down": move(byLine, 1), "Up": move(byLine, -1),
|
||
"Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
|
||
"End": "goLineEnd", "Home": "goLineStart",
|
||
|
||
"Alt-V": move(byPage, -1), "Ctrl-V": move(byPage, 1),
|
||
"PageUp": move(byPage, -1), "PageDown": move(byPage, 1),
|
||
|
||
"Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1),
|
||
|
||
"Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1),
|
||
"Alt-K": function(cm) { killTo(cm, bySentence, 1, "grow"); },
|
||
|
||
"Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1, "grow"); },
|
||
"Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1, "grow"); },
|
||
"Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1, "grow"),
|
||
|
||
"Shift-Ctrl-Alt-2": function(cm) {
|
||
var cursor = cm.getCursor();
|
||
cm.setSelection(findEnd(cm, cursor, byExpr, 1), cursor);
|
||
},
|
||
"Ctrl-Alt-T": function(cm) {
|
||
var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1);
|
||
var rightEnd = byExpr(cm, leftEnd, 1), rightStart = byExpr(cm, rightEnd, -1);
|
||
cm.replaceRange(cm.getRange(rightStart, rightEnd) + cm.getRange(leftEnd, rightStart) +
|
||
cm.getRange(leftStart, leftEnd), leftStart, rightEnd);
|
||
},
|
||
"Ctrl-Alt-U": repeated(toEnclosingExpr),
|
||
|
||
"Alt-Space": function(cm) {
|
||
var pos = cm.getCursor(), from = pos.ch, to = pos.ch, text = cm.getLine(pos.line);
|
||
while (from && /\s/.test(text.charAt(from - 1))) --from;
|
||
while (to < text.length && /\s/.test(text.charAt(to))) ++to;
|
||
cm.replaceRange(" ", Pos(pos.line, from), Pos(pos.line, to));
|
||
},
|
||
"Ctrl-O": repeated(function(cm) { cm.replaceSelection("\n", "start"); }),
|
||
"Ctrl-T": repeated(function(cm) {
|
||
cm.execCommand("transposeChars");
|
||
}),
|
||
|
||
"Alt-C": repeated(function(cm) {
|
||
operateOnWord(cm, function(w) {
|
||
var letter = w.search(/\w/);
|
||
if (letter == -1) return w;
|
||
return w.slice(0, letter) + w.charAt(letter).toUpperCase() + w.slice(letter + 1).toLowerCase();
|
||
});
|
||
}),
|
||
"Alt-U": repeated(function(cm) {
|
||
operateOnWord(cm, function(w) { return w.toUpperCase(); });
|
||
}),
|
||
"Alt-L": repeated(function(cm) {
|
||
operateOnWord(cm, function(w) { return w.toLowerCase(); });
|
||
}),
|
||
|
||
"Alt-;": "toggleComment",
|
||
|
||
"Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"),
|
||
"Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"),
|
||
"Shift-Ctrl-Z": "redo",
|
||
"Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
|
||
"Ctrl-S": "findPersistentNext", "Ctrl-R": "findPersistentPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace",
|
||
"Alt-/": "autocomplete",
|
||
"Enter": "newlineAndIndent",
|
||
"Ctrl-J": repeated(function(cm) { cm.replaceSelection("\n", "end"); }),
|
||
"Tab": "indentAuto",
|
||
|
||
"Alt-G G": function(cm) {
|
||
var prefix = getPrefix(cm, true);
|
||
if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1);
|
||
|
||
getInput(cm, "Goto line", function(str) {
|
||
var num;
|
||
if (str && !isNaN(num = Number(str)) && num == (num|0) && num > 0)
|
||
cm.setCursor(num - 1);
|
||
});
|
||
},
|
||
|
||
"Ctrl-X Tab": function(cm) {
|
||
cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit"));
|
||
},
|
||
"Ctrl-X Ctrl-X": function(cm) {
|
||
cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor"));
|
||
},
|
||
"Ctrl-X Ctrl-S": "save",
|
||
"Ctrl-X Ctrl-W": "save",
|
||
"Ctrl-X S": "saveAll",
|
||
"Ctrl-X F": "open",
|
||
"Ctrl-X U": repeated("undo"),
|
||
"Ctrl-X K": "close",
|
||
"Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), "grow"); },
|
||
"Ctrl-X H": "selectAll",
|
||
|
||
"Ctrl-Q Tab": repeated("insertTab"),
|
||
"Ctrl-U": addPrefixMap,
|
||
"fallthrough": "default"
|
||
});
|
||
|
||
var prefixMap = {"Ctrl-G": clearPrefix};
|
||
function regPrefix(d) {
|
||
prefixMap[d] = function(cm) { addPrefix(cm, d); };
|
||
keyMap["Ctrl-" + d] = function(cm) { addPrefix(cm, d); };
|
||
prefixPreservingKeys["Ctrl-" + d] = true;
|
||
}
|
||
for (var i = 0; i < 10; ++i) regPrefix(String(i));
|
||
regPrefix("-");
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
// A rough approximation of Sublime Text's keybindings
|
||
// Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/edit/matchbrackets"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/keymap/sublime',["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
"use strict";
|
||
|
||
var cmds = CodeMirror.commands;
|
||
var Pos = CodeMirror.Pos;
|
||
|
||
// This is not exactly Sublime's algorithm. I couldn't make heads or tails of that.
|
||
function findPosSubword(doc, start, dir) {
|
||
if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1));
|
||
var line = doc.getLine(start.line);
|
||
if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0));
|
||
var state = "start", type, startPos = start.ch;
|
||
for (var pos = startPos, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) {
|
||
var next = line.charAt(dir < 0 ? pos - 1 : pos);
|
||
var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o";
|
||
if (cat == "w" && next.toUpperCase() == next) cat = "W";
|
||
if (state == "start") {
|
||
if (cat != "o") { state = "in"; type = cat; }
|
||
else startPos = pos + dir
|
||
} else if (state == "in") {
|
||
if (type != cat) {
|
||
if (type == "w" && cat == "W" && dir < 0) pos--;
|
||
if (type == "W" && cat == "w" && dir > 0) { // From uppercase to lowercase
|
||
if (pos == startPos + 1) { type = "w"; continue; }
|
||
else pos--;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return Pos(start.line, pos);
|
||
}
|
||
|
||
function moveSubword(cm, dir) {
|
||
cm.extendSelectionsBy(function(range) {
|
||
if (cm.display.shift || cm.doc.extend || range.empty())
|
||
return findPosSubword(cm.doc, range.head, dir);
|
||
else
|
||
return dir < 0 ? range.from() : range.to();
|
||
});
|
||
}
|
||
|
||
cmds.goSubwordLeft = function(cm) { moveSubword(cm, -1); };
|
||
cmds.goSubwordRight = function(cm) { moveSubword(cm, 1); };
|
||
|
||
cmds.scrollLineUp = function(cm) {
|
||
var info = cm.getScrollInfo();
|
||
if (!cm.somethingSelected()) {
|
||
var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local");
|
||
if (cm.getCursor().line >= visibleBottomLine)
|
||
cm.execCommand("goLineUp");
|
||
}
|
||
cm.scrollTo(null, info.top - cm.defaultTextHeight());
|
||
};
|
||
cmds.scrollLineDown = function(cm) {
|
||
var info = cm.getScrollInfo();
|
||
if (!cm.somethingSelected()) {
|
||
var visibleTopLine = cm.lineAtHeight(info.top, "local")+1;
|
||
if (cm.getCursor().line <= visibleTopLine)
|
||
cm.execCommand("goLineDown");
|
||
}
|
||
cm.scrollTo(null, info.top + cm.defaultTextHeight());
|
||
};
|
||
|
||
cmds.splitSelectionByLine = function(cm) {
|
||
var ranges = cm.listSelections(), lineRanges = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var from = ranges[i].from(), to = ranges[i].to();
|
||
for (var line = from.line; line <= to.line; ++line)
|
||
if (!(to.line > from.line && line == to.line && to.ch == 0))
|
||
lineRanges.push({anchor: line == from.line ? from : Pos(line, 0),
|
||
head: line == to.line ? to : Pos(line)});
|
||
}
|
||
cm.setSelections(lineRanges, 0);
|
||
};
|
||
|
||
cmds.singleSelectionTop = function(cm) {
|
||
var range = cm.listSelections()[0];
|
||
cm.setSelection(range.anchor, range.head, {scroll: false});
|
||
};
|
||
|
||
cmds.selectLine = function(cm) {
|
||
var ranges = cm.listSelections(), extended = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i];
|
||
extended.push({anchor: Pos(range.from().line, 0),
|
||
head: Pos(range.to().line + 1, 0)});
|
||
}
|
||
cm.setSelections(extended);
|
||
};
|
||
|
||
function insertLine(cm, above) {
|
||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||
cm.operation(function() {
|
||
var len = cm.listSelections().length, newSelection = [], last = -1;
|
||
for (var i = 0; i < len; i++) {
|
||
var head = cm.listSelections()[i].head;
|
||
if (head.line <= last) continue;
|
||
var at = Pos(head.line + (above ? 0 : 1), 0);
|
||
cm.replaceRange("\n", at, null, "+insertLine");
|
||
cm.indentLine(at.line, null, true);
|
||
newSelection.push({head: at, anchor: at});
|
||
last = head.line + 1;
|
||
}
|
||
cm.setSelections(newSelection);
|
||
});
|
||
cm.execCommand("indentAuto");
|
||
}
|
||
|
||
cmds.insertLineAfter = function(cm) { return insertLine(cm, false); };
|
||
|
||
cmds.insertLineBefore = function(cm) { return insertLine(cm, true); };
|
||
|
||
function wordAt(cm, pos) {
|
||
var start = pos.ch, end = start, line = cm.getLine(pos.line);
|
||
while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start;
|
||
while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end;
|
||
return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)};
|
||
}
|
||
|
||
cmds.selectNextOccurrence = function(cm) {
|
||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||
var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel;
|
||
if (CodeMirror.cmpPos(from, to) == 0) {
|
||
var word = wordAt(cm, from);
|
||
if (!word.word) return;
|
||
cm.setSelection(word.from, word.to);
|
||
fullWord = true;
|
||
} else {
|
||
var text = cm.getRange(from, to);
|
||
var query = fullWord ? new RegExp("\\b" + text + "\\b") : text;
|
||
var cur = cm.getSearchCursor(query, to);
|
||
var found = cur.findNext();
|
||
if (!found) {
|
||
cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0));
|
||
found = cur.findNext();
|
||
}
|
||
if (!found || isSelectedRange(cm.listSelections(), cur.from(), cur.to())) return
|
||
cm.addSelection(cur.from(), cur.to());
|
||
}
|
||
if (fullWord)
|
||
cm.state.sublimeFindFullWord = cm.doc.sel;
|
||
};
|
||
|
||
cmds.skipAndSelectNextOccurrence = function(cm) {
|
||
var prevAnchor = cm.getCursor("anchor"), prevHead = cm.getCursor("head");
|
||
cmds.selectNextOccurrence(cm);
|
||
if (CodeMirror.cmpPos(prevAnchor, prevHead) != 0) {
|
||
cm.doc.setSelections(cm.doc.listSelections()
|
||
.filter(function (sel) {
|
||
return sel.anchor != prevAnchor || sel.head != prevHead;
|
||
}));
|
||
}
|
||
}
|
||
|
||
function addCursorToSelection(cm, dir) {
|
||
var ranges = cm.listSelections(), newRanges = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i];
|
||
var newAnchor = cm.findPosV(
|
||
range.anchor, dir, "line", range.anchor.goalColumn);
|
||
var newHead = cm.findPosV(
|
||
range.head, dir, "line", range.head.goalColumn);
|
||
newAnchor.goalColumn = range.anchor.goalColumn != null ?
|
||
range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left;
|
||
newHead.goalColumn = range.head.goalColumn != null ?
|
||
range.head.goalColumn : cm.cursorCoords(range.head, "div").left;
|
||
var newRange = {anchor: newAnchor, head: newHead};
|
||
newRanges.push(range);
|
||
newRanges.push(newRange);
|
||
}
|
||
cm.setSelections(newRanges);
|
||
}
|
||
cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); };
|
||
cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); };
|
||
|
||
function isSelectedRange(ranges, from, to) {
|
||
for (var i = 0; i < ranges.length; i++)
|
||
if (CodeMirror.cmpPos(ranges[i].from(), from) == 0 &&
|
||
CodeMirror.cmpPos(ranges[i].to(), to) == 0) return true
|
||
return false
|
||
}
|
||
|
||
var mirror = "(){}[]";
|
||
function selectBetweenBrackets(cm) {
|
||
var ranges = cm.listSelections(), newRanges = []
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1);
|
||
if (!opening) return false;
|
||
for (;;) {
|
||
var closing = cm.scanForBracket(pos, 1);
|
||
if (!closing) return false;
|
||
if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) {
|
||
var startPos = Pos(opening.pos.line, opening.pos.ch + 1);
|
||
if (CodeMirror.cmpPos(startPos, range.from()) == 0 &&
|
||
CodeMirror.cmpPos(closing.pos, range.to()) == 0) {
|
||
opening = cm.scanForBracket(opening.pos, -1);
|
||
if (!opening) return false;
|
||
} else {
|
||
newRanges.push({anchor: startPos, head: closing.pos});
|
||
break;
|
||
}
|
||
}
|
||
pos = Pos(closing.pos.line, closing.pos.ch + 1);
|
||
}
|
||
}
|
||
cm.setSelections(newRanges);
|
||
return true;
|
||
}
|
||
|
||
cmds.selectScope = function(cm) {
|
||
selectBetweenBrackets(cm) || cm.execCommand("selectAll");
|
||
};
|
||
cmds.selectBetweenBrackets = function(cm) {
|
||
if (!selectBetweenBrackets(cm)) return CodeMirror.Pass;
|
||
};
|
||
|
||
function puncType(type) {
|
||
return !type ? null : /\bpunctuation\b/.test(type) ? type : undefined
|
||
}
|
||
|
||
cmds.goToBracket = function(cm) {
|
||
cm.extendSelectionsBy(function(range) {
|
||
var next = cm.scanForBracket(range.head, 1, puncType(cm.getTokenTypeAt(range.head)));
|
||
if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos;
|
||
var prev = cm.scanForBracket(range.head, -1, puncType(cm.getTokenTypeAt(Pos(range.head.line, range.head.ch + 1))));
|
||
return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head;
|
||
});
|
||
};
|
||
|
||
cmds.swapLineUp = function(cm) {
|
||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||
var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i], from = range.from().line - 1, to = range.to().line;
|
||
newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch),
|
||
head: Pos(range.head.line - 1, range.head.ch)});
|
||
if (range.to().ch == 0 && !range.empty()) --to;
|
||
if (from > at) linesToMove.push(from, to);
|
||
else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to;
|
||
at = to;
|
||
}
|
||
cm.operation(function() {
|
||
for (var i = 0; i < linesToMove.length; i += 2) {
|
||
var from = linesToMove[i], to = linesToMove[i + 1];
|
||
var line = cm.getLine(from);
|
||
cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine");
|
||
if (to > cm.lastLine())
|
||
cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine");
|
||
else
|
||
cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine");
|
||
}
|
||
cm.setSelections(newSels);
|
||
cm.scrollIntoView();
|
||
});
|
||
};
|
||
|
||
cmds.swapLineDown = function(cm) {
|
||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||
var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1;
|
||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||
var range = ranges[i], from = range.to().line + 1, to = range.from().line;
|
||
if (range.to().ch == 0 && !range.empty()) from--;
|
||
if (from < at) linesToMove.push(from, to);
|
||
else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to;
|
||
at = to;
|
||
}
|
||
cm.operation(function() {
|
||
for (var i = linesToMove.length - 2; i >= 0; i -= 2) {
|
||
var from = linesToMove[i], to = linesToMove[i + 1];
|
||
var line = cm.getLine(from);
|
||
if (from == cm.lastLine())
|
||
cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine");
|
||
else
|
||
cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine");
|
||
cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine");
|
||
}
|
||
cm.scrollIntoView();
|
||
});
|
||
};
|
||
|
||
cmds.toggleCommentIndented = function(cm) {
|
||
cm.toggleComment({ indent: true });
|
||
}
|
||
|
||
cmds.joinLines = function(cm) {
|
||
var ranges = cm.listSelections(), joined = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i], from = range.from();
|
||
var start = from.line, end = range.to().line;
|
||
while (i < ranges.length - 1 && ranges[i + 1].from().line == end)
|
||
end = ranges[++i].to().line;
|
||
joined.push({start: start, end: end, anchor: !range.empty() && from});
|
||
}
|
||
cm.operation(function() {
|
||
var offset = 0, ranges = [];
|
||
for (var i = 0; i < joined.length; i++) {
|
||
var obj = joined[i];
|
||
var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head;
|
||
for (var line = obj.start; line <= obj.end; line++) {
|
||
var actual = line - offset;
|
||
if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1);
|
||
if (actual < cm.lastLine()) {
|
||
cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length));
|
||
++offset;
|
||
}
|
||
}
|
||
ranges.push({anchor: anchor || head, head: head});
|
||
}
|
||
cm.setSelections(ranges, 0);
|
||
});
|
||
};
|
||
|
||
cmds.duplicateLine = function(cm) {
|
||
cm.operation(function() {
|
||
var rangeCount = cm.listSelections().length;
|
||
for (var i = 0; i < rangeCount; i++) {
|
||
var range = cm.listSelections()[i];
|
||
if (range.empty())
|
||
cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0));
|
||
else
|
||
cm.replaceRange(cm.getRange(range.from(), range.to()), range.from());
|
||
}
|
||
cm.scrollIntoView();
|
||
});
|
||
};
|
||
|
||
|
||
function sortLines(cm, caseSensitive) {
|
||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||
var ranges = cm.listSelections(), toSort = [], selected;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i];
|
||
if (range.empty()) continue;
|
||
var from = range.from().line, to = range.to().line;
|
||
while (i < ranges.length - 1 && ranges[i + 1].from().line == to)
|
||
to = ranges[++i].to().line;
|
||
if (!ranges[i].to().ch) to--;
|
||
toSort.push(from, to);
|
||
}
|
||
if (toSort.length) selected = true;
|
||
else toSort.push(cm.firstLine(), cm.lastLine());
|
||
|
||
cm.operation(function() {
|
||
var ranges = [];
|
||
for (var i = 0; i < toSort.length; i += 2) {
|
||
var from = toSort[i], to = toSort[i + 1];
|
||
var start = Pos(from, 0), end = Pos(to);
|
||
var lines = cm.getRange(start, end, false);
|
||
if (caseSensitive)
|
||
lines.sort();
|
||
else
|
||
lines.sort(function(a, b) {
|
||
var au = a.toUpperCase(), bu = b.toUpperCase();
|
||
if (au != bu) { a = au; b = bu; }
|
||
return a < b ? -1 : a == b ? 0 : 1;
|
||
});
|
||
cm.replaceRange(lines, start, end);
|
||
if (selected) ranges.push({anchor: start, head: Pos(to + 1, 0)});
|
||
}
|
||
if (selected) cm.setSelections(ranges, 0);
|
||
});
|
||
}
|
||
|
||
cmds.sortLines = function(cm) { sortLines(cm, true); };
|
||
cmds.sortLinesInsensitive = function(cm) { sortLines(cm, false); };
|
||
|
||
cmds.nextBookmark = function(cm) {
|
||
var marks = cm.state.sublimeBookmarks;
|
||
if (marks) while (marks.length) {
|
||
var current = marks.shift();
|
||
var found = current.find();
|
||
if (found) {
|
||
marks.push(current);
|
||
return cm.setSelection(found.from, found.to);
|
||
}
|
||
}
|
||
};
|
||
|
||
cmds.prevBookmark = function(cm) {
|
||
var marks = cm.state.sublimeBookmarks;
|
||
if (marks) while (marks.length) {
|
||
marks.unshift(marks.pop());
|
||
var found = marks[marks.length - 1].find();
|
||
if (!found)
|
||
marks.pop();
|
||
else
|
||
return cm.setSelection(found.from, found.to);
|
||
}
|
||
};
|
||
|
||
cmds.toggleBookmark = function(cm) {
|
||
var ranges = cm.listSelections();
|
||
var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []);
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var from = ranges[i].from(), to = ranges[i].to();
|
||
var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to);
|
||
for (var j = 0; j < found.length; j++) {
|
||
if (found[j].sublimeBookmark) {
|
||
found[j].clear();
|
||
for (var k = 0; k < marks.length; k++)
|
||
if (marks[k] == found[j])
|
||
marks.splice(k--, 1);
|
||
break;
|
||
}
|
||
}
|
||
if (j == found.length)
|
||
marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false}));
|
||
}
|
||
};
|
||
|
||
cmds.clearBookmarks = function(cm) {
|
||
var marks = cm.state.sublimeBookmarks;
|
||
if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||
marks.length = 0;
|
||
};
|
||
|
||
cmds.selectBookmarks = function(cm) {
|
||
var marks = cm.state.sublimeBookmarks, ranges = [];
|
||
if (marks) for (var i = 0; i < marks.length; i++) {
|
||
var found = marks[i].find();
|
||
if (!found)
|
||
marks.splice(i--, 0);
|
||
else
|
||
ranges.push({anchor: found.from, head: found.to});
|
||
}
|
||
if (ranges.length)
|
||
cm.setSelections(ranges, 0);
|
||
};
|
||
|
||
function modifyWordOrSelection(cm, mod) {
|
||
cm.operation(function() {
|
||
var ranges = cm.listSelections(), indices = [], replacements = [];
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i];
|
||
if (range.empty()) { indices.push(i); replacements.push(""); }
|
||
else replacements.push(mod(cm.getRange(range.from(), range.to())));
|
||
}
|
||
cm.replaceSelections(replacements, "around", "case");
|
||
for (var i = indices.length - 1, at; i >= 0; i--) {
|
||
var range = ranges[indices[i]];
|
||
if (at && CodeMirror.cmpPos(range.head, at) > 0) continue;
|
||
var word = wordAt(cm, range.head);
|
||
at = word.from;
|
||
cm.replaceRange(mod(word.word), word.from, word.to);
|
||
}
|
||
});
|
||
}
|
||
|
||
cmds.smartBackspace = function(cm) {
|
||
if (cm.somethingSelected()) return CodeMirror.Pass;
|
||
|
||
cm.operation(function() {
|
||
var cursors = cm.listSelections();
|
||
var indentUnit = cm.getOption("indentUnit");
|
||
|
||
for (var i = cursors.length - 1; i >= 0; i--) {
|
||
var cursor = cursors[i].head;
|
||
var toStartOfLine = cm.getRange({line: cursor.line, ch: 0}, cursor);
|
||
var column = CodeMirror.countColumn(toStartOfLine, null, cm.getOption("tabSize"));
|
||
|
||
// Delete by one character by default
|
||
var deletePos = cm.findPosH(cursor, -1, "char", false);
|
||
|
||
if (toStartOfLine && !/\S/.test(toStartOfLine) && column % indentUnit == 0) {
|
||
var prevIndent = new Pos(cursor.line,
|
||
CodeMirror.findColumn(toStartOfLine, column - indentUnit, indentUnit));
|
||
|
||
// Smart delete only if we found a valid prevIndent location
|
||
if (prevIndent.ch != cursor.ch) deletePos = prevIndent;
|
||
}
|
||
|
||
cm.replaceRange("", deletePos, cursor, "+delete");
|
||
}
|
||
});
|
||
};
|
||
|
||
cmds.delLineRight = function(cm) {
|
||
cm.operation(function() {
|
||
var ranges = cm.listSelections();
|
||
for (var i = ranges.length - 1; i >= 0; i--)
|
||
cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete");
|
||
cm.scrollIntoView();
|
||
});
|
||
};
|
||
|
||
cmds.upcaseAtCursor = function(cm) {
|
||
modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); });
|
||
};
|
||
cmds.downcaseAtCursor = function(cm) {
|
||
modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); });
|
||
};
|
||
|
||
cmds.setSublimeMark = function(cm) {
|
||
if (cm.state.sublimeMark) cm.state.sublimeMark.clear();
|
||
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
|
||
};
|
||
cmds.selectToSublimeMark = function(cm) {
|
||
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
|
||
if (found) cm.setSelection(cm.getCursor(), found);
|
||
};
|
||
cmds.deleteToSublimeMark = function(cm) {
|
||
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
|
||
if (found) {
|
||
var from = cm.getCursor(), to = found;
|
||
if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; }
|
||
cm.state.sublimeKilled = cm.getRange(from, to);
|
||
cm.replaceRange("", from, to);
|
||
}
|
||
};
|
||
cmds.swapWithSublimeMark = function(cm) {
|
||
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
|
||
if (found) {
|
||
cm.state.sublimeMark.clear();
|
||
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
|
||
cm.setCursor(found);
|
||
}
|
||
};
|
||
cmds.sublimeYank = function(cm) {
|
||
if (cm.state.sublimeKilled != null)
|
||
cm.replaceSelection(cm.state.sublimeKilled, null, "paste");
|
||
};
|
||
|
||
cmds.showInCenter = function(cm) {
|
||
var pos = cm.cursorCoords(null, "local");
|
||
cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2);
|
||
};
|
||
|
||
function getTarget(cm) {
|
||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||
if (CodeMirror.cmpPos(from, to) == 0) {
|
||
var word = wordAt(cm, from);
|
||
if (!word.word) return;
|
||
from = word.from;
|
||
to = word.to;
|
||
}
|
||
return {from: from, to: to, query: cm.getRange(from, to), word: word};
|
||
}
|
||
|
||
function findAndGoTo(cm, forward) {
|
||
var target = getTarget(cm);
|
||
if (!target) return;
|
||
var query = target.query;
|
||
var cur = cm.getSearchCursor(query, forward ? target.to : target.from);
|
||
|
||
if (forward ? cur.findNext() : cur.findPrevious()) {
|
||
cm.setSelection(cur.from(), cur.to());
|
||
} else {
|
||
cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0)
|
||
: cm.clipPos(Pos(cm.lastLine())));
|
||
if (forward ? cur.findNext() : cur.findPrevious())
|
||
cm.setSelection(cur.from(), cur.to());
|
||
else if (target.word)
|
||
cm.setSelection(target.from, target.to);
|
||
}
|
||
};
|
||
cmds.findUnder = function(cm) { findAndGoTo(cm, true); };
|
||
cmds.findUnderPrevious = function(cm) { findAndGoTo(cm,false); };
|
||
cmds.findAllUnder = function(cm) {
|
||
var target = getTarget(cm);
|
||
if (!target) return;
|
||
var cur = cm.getSearchCursor(target.query);
|
||
var matches = [];
|
||
var primaryIndex = -1;
|
||
while (cur.findNext()) {
|
||
matches.push({anchor: cur.from(), head: cur.to()});
|
||
if (cur.from().line <= target.from.line && cur.from().ch <= target.from.ch)
|
||
primaryIndex++;
|
||
}
|
||
cm.setSelections(matches, primaryIndex);
|
||
};
|
||
|
||
|
||
var keyMap = CodeMirror.keyMap;
|
||
keyMap.macSublime = {
|
||
"Cmd-Left": "goLineStartSmart",
|
||
"Shift-Tab": "indentLess",
|
||
"Shift-Ctrl-K": "deleteLine",
|
||
"Alt-Q": "wrapLines",
|
||
"Ctrl-Left": "goSubwordLeft",
|
||
"Ctrl-Right": "goSubwordRight",
|
||
"Ctrl-Alt-Up": "scrollLineUp",
|
||
"Ctrl-Alt-Down": "scrollLineDown",
|
||
"Cmd-L": "selectLine",
|
||
"Shift-Cmd-L": "splitSelectionByLine",
|
||
"Esc": "singleSelectionTop",
|
||
"Cmd-Enter": "insertLineAfter",
|
||
"Shift-Cmd-Enter": "insertLineBefore",
|
||
"Cmd-D": "selectNextOccurrence",
|
||
"Shift-Cmd-Space": "selectScope",
|
||
"Shift-Cmd-M": "selectBetweenBrackets",
|
||
"Cmd-M": "goToBracket",
|
||
"Cmd-Ctrl-Up": "swapLineUp",
|
||
"Cmd-Ctrl-Down": "swapLineDown",
|
||
"Cmd-/": "toggleCommentIndented",
|
||
"Cmd-J": "joinLines",
|
||
"Shift-Cmd-D": "duplicateLine",
|
||
"F5": "sortLines",
|
||
"Cmd-F5": "sortLinesInsensitive",
|
||
"F2": "nextBookmark",
|
||
"Shift-F2": "prevBookmark",
|
||
"Cmd-F2": "toggleBookmark",
|
||
"Shift-Cmd-F2": "clearBookmarks",
|
||
"Alt-F2": "selectBookmarks",
|
||
"Backspace": "smartBackspace",
|
||
"Cmd-K Cmd-D": "skipAndSelectNextOccurrence",
|
||
"Cmd-K Cmd-K": "delLineRight",
|
||
"Cmd-K Cmd-U": "upcaseAtCursor",
|
||
"Cmd-K Cmd-L": "downcaseAtCursor",
|
||
"Cmd-K Cmd-Space": "setSublimeMark",
|
||
"Cmd-K Cmd-A": "selectToSublimeMark",
|
||
"Cmd-K Cmd-W": "deleteToSublimeMark",
|
||
"Cmd-K Cmd-X": "swapWithSublimeMark",
|
||
"Cmd-K Cmd-Y": "sublimeYank",
|
||
"Cmd-K Cmd-C": "showInCenter",
|
||
"Cmd-K Cmd-G": "clearBookmarks",
|
||
"Cmd-K Cmd-Backspace": "delLineLeft",
|
||
"Cmd-K Cmd-1": "foldAll",
|
||
"Cmd-K Cmd-0": "unfoldAll",
|
||
"Cmd-K Cmd-J": "unfoldAll",
|
||
"Ctrl-Shift-Up": "addCursorToPrevLine",
|
||
"Ctrl-Shift-Down": "addCursorToNextLine",
|
||
"Cmd-F3": "findUnder",
|
||
"Shift-Cmd-F3": "findUnderPrevious",
|
||
"Alt-F3": "findAllUnder",
|
||
"Shift-Cmd-[": "fold",
|
||
"Shift-Cmd-]": "unfold",
|
||
"Cmd-I": "findIncremental",
|
||
"Shift-Cmd-I": "findIncrementalReverse",
|
||
"Cmd-H": "replace",
|
||
"F3": "findNext",
|
||
"Shift-F3": "findPrev",
|
||
"fallthrough": "macDefault"
|
||
};
|
||
CodeMirror.normalizeKeyMap(keyMap.macSublime);
|
||
|
||
keyMap.pcSublime = {
|
||
"Shift-Tab": "indentLess",
|
||
"Shift-Ctrl-K": "deleteLine",
|
||
"Alt-Q": "wrapLines",
|
||
"Ctrl-T": "transposeChars",
|
||
"Alt-Left": "goSubwordLeft",
|
||
"Alt-Right": "goSubwordRight",
|
||
"Ctrl-Up": "scrollLineUp",
|
||
"Ctrl-Down": "scrollLineDown",
|
||
"Ctrl-L": "selectLine",
|
||
"Shift-Ctrl-L": "splitSelectionByLine",
|
||
"Esc": "singleSelectionTop",
|
||
"Ctrl-Enter": "insertLineAfter",
|
||
"Shift-Ctrl-Enter": "insertLineBefore",
|
||
"Ctrl-D": "selectNextOccurrence",
|
||
"Shift-Ctrl-Space": "selectScope",
|
||
"Shift-Ctrl-M": "selectBetweenBrackets",
|
||
"Ctrl-M": "goToBracket",
|
||
"Shift-Ctrl-Up": "swapLineUp",
|
||
"Shift-Ctrl-Down": "swapLineDown",
|
||
"Ctrl-/": "toggleCommentIndented",
|
||
"Ctrl-J": "joinLines",
|
||
"Shift-Ctrl-D": "duplicateLine",
|
||
"F9": "sortLines",
|
||
"Ctrl-F9": "sortLinesInsensitive",
|
||
"F2": "nextBookmark",
|
||
"Shift-F2": "prevBookmark",
|
||
"Ctrl-F2": "toggleBookmark",
|
||
"Shift-Ctrl-F2": "clearBookmarks",
|
||
"Alt-F2": "selectBookmarks",
|
||
"Backspace": "smartBackspace",
|
||
"Ctrl-K Ctrl-D": "skipAndSelectNextOccurrence",
|
||
"Ctrl-K Ctrl-K": "delLineRight",
|
||
"Ctrl-K Ctrl-U": "upcaseAtCursor",
|
||
"Ctrl-K Ctrl-L": "downcaseAtCursor",
|
||
"Ctrl-K Ctrl-Space": "setSublimeMark",
|
||
"Ctrl-K Ctrl-A": "selectToSublimeMark",
|
||
"Ctrl-K Ctrl-W": "deleteToSublimeMark",
|
||
"Ctrl-K Ctrl-X": "swapWithSublimeMark",
|
||
"Ctrl-K Ctrl-Y": "sublimeYank",
|
||
"Ctrl-K Ctrl-C": "showInCenter",
|
||
"Ctrl-K Ctrl-G": "clearBookmarks",
|
||
"Ctrl-K Ctrl-Backspace": "delLineLeft",
|
||
"Ctrl-K Ctrl-1": "foldAll",
|
||
"Ctrl-K Ctrl-0": "unfoldAll",
|
||
"Ctrl-K Ctrl-J": "unfoldAll",
|
||
"Ctrl-Alt-Up": "addCursorToPrevLine",
|
||
"Ctrl-Alt-Down": "addCursorToNextLine",
|
||
"Ctrl-F3": "findUnder",
|
||
"Shift-Ctrl-F3": "findUnderPrevious",
|
||
"Alt-F3": "findAllUnder",
|
||
"Shift-Ctrl-[": "fold",
|
||
"Shift-Ctrl-]": "unfold",
|
||
"Ctrl-I": "findIncremental",
|
||
"Shift-Ctrl-I": "findIncrementalReverse",
|
||
"Ctrl-H": "replace",
|
||
"F3": "findNext",
|
||
"Shift-F3": "findPrev",
|
||
"fallthrough": "pcDefault"
|
||
};
|
||
CodeMirror.normalizeKeyMap(keyMap.pcSublime);
|
||
|
||
var mac = keyMap.default == keyMap.macDefault;
|
||
keyMap.sublime = mac ? keyMap.macSublime : keyMap.pcSublime;
|
||
});
|
||
|
||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||
|
||
/**
|
||
* Supported keybindings:
|
||
* Too many to list. Refer to defaultKeymap below.
|
||
*
|
||
* Supported Ex commands:
|
||
* Refer to defaultExCommandMap below.
|
||
*
|
||
* Registers: unnamed, -, a-z, A-Z, 0-9
|
||
* (Does not respect the special case for number registers when delete
|
||
* operator is made with these commands: %, (, ), , /, ?, n, N, {, } )
|
||
* TODO: Implement the remaining registers.
|
||
*
|
||
* Marks: a-z, A-Z, and 0-9
|
||
* TODO: Implement the remaining special marks. They have more complex
|
||
* behavior.
|
||
*
|
||
* Events:
|
||
* 'vim-mode-change' - raised on the editor anytime the current mode changes,
|
||
* Event object: {mode: "visual", subMode: "linewise"}
|
||
*
|
||
* Code structure:
|
||
* 1. Default keymap
|
||
* 2. Variable declarations and short basic helpers
|
||
* 3. Instance (External API) implementation
|
||
* 4. Internal state tracking objects (input state, counter) implementation
|
||
* and instantiation
|
||
* 5. Key handler (the main command dispatcher) implementation
|
||
* 6. Motion, operator, and action implementations
|
||
* 7. Helper functions for the key handler, motions, operators, and actions
|
||
* 8. Set up Vim to work as a keymap for CodeMirror.
|
||
* 9. Ex command implementations.
|
||
*/
|
||
|
||
(function(mod) {
|
||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||
mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/dialog/dialog"), require("../addon/edit/matchbrackets.js"));
|
||
else if (typeof define == "function" && define.amd) // AMD
|
||
define('codemirror/keymap/vim',["../lib/codemirror", "../addon/search/searchcursor", "../addon/dialog/dialog", "../addon/edit/matchbrackets"], mod);
|
||
else // Plain browser env
|
||
mod(CodeMirror);
|
||
})(function(CodeMirror) {
|
||
'use strict';
|
||
|
||
var defaultKeymap = [
|
||
// Key to key mapping. This goes first to make it possible to override
|
||
// existing mappings.
|
||
{ keys: '<Left>', type: 'keyToKey', toKeys: 'h' },
|
||
{ keys: '<Right>', type: 'keyToKey', toKeys: 'l' },
|
||
{ keys: '<Up>', type: 'keyToKey', toKeys: 'k' },
|
||
{ keys: '<Down>', type: 'keyToKey', toKeys: 'j' },
|
||
{ keys: '<Space>', type: 'keyToKey', toKeys: 'l' },
|
||
{ keys: '<BS>', type: 'keyToKey', toKeys: 'h', context: 'normal'},
|
||
{ keys: '<Del>', type: 'keyToKey', toKeys: 'x', context: 'normal'},
|
||
{ keys: '<C-Space>', type: 'keyToKey', toKeys: 'W' },
|
||
{ keys: '<C-BS>', type: 'keyToKey', toKeys: 'B', context: 'normal' },
|
||
{ keys: '<S-Space>', type: 'keyToKey', toKeys: 'w' },
|
||
{ keys: '<S-BS>', type: 'keyToKey', toKeys: 'b', context: 'normal' },
|
||
{ keys: '<C-n>', type: 'keyToKey', toKeys: 'j' },
|
||
{ keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },
|
||
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },
|
||
{ keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>' },
|
||
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },
|
||
{ keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },
|
||
{ keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' },
|
||
{ keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'},
|
||
{ keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' },
|
||
{ keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' },
|
||
{ keys: '<Home>', type: 'keyToKey', toKeys: '0' },
|
||
{ keys: '<End>', type: 'keyToKey', toKeys: '$' },
|
||
{ keys: '<PageUp>', type: 'keyToKey', toKeys: '<C-b>' },
|
||
{ keys: '<PageDown>', type: 'keyToKey', toKeys: '<C-f>' },
|
||
{ keys: '<CR>', type: 'keyToKey', toKeys: 'j^', context: 'normal' },
|
||
{ keys: '<Ins>', type: 'action', action: 'toggleOverwrite', context: 'insert' },
|
||
// Motions
|
||
{ keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true }},
|
||
{ keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true }},
|
||
{ keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true }},
|
||
{ keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }},
|
||
{ keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true }},
|
||
{ keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true }},
|
||
{ keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }},
|
||
{ keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true }},
|
||
{ keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false }},
|
||
{ keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }},
|
||
{ keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true }},
|
||
{ keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true }},
|
||
{ keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true }},
|
||
{ keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }},
|
||
{ keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true }},
|
||
{ keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true }},
|
||
{ keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }},
|
||
{ keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }},
|
||
{ keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }},
|
||
{ keys: '(', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: false }},
|
||
{ keys: ')', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: true }},
|
||
{ keys: '<C-f>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }},
|
||
{ keys: '<C-b>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }},
|
||
{ keys: '<C-d>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }},
|
||
{ keys: '<C-u>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }},
|
||
{ keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }},
|
||
{ keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }},
|
||
{ keys: '0', type: 'motion', motion: 'moveToStartOfLine' },
|
||
{ keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
||
{ keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }},
|
||
{ keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar:true }},
|
||
{ keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }},
|
||
{ keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true }},
|
||
{ keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true }},
|
||
{ keys: 'f<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }},
|
||
{ keys: 'F<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false }},
|
||
{ keys: 't<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true }},
|
||
{ keys: 'T<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }},
|
||
{ keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true }},
|
||
{ keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }},
|
||
{ keys: '\'<character>', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true, linewise: true}},
|
||
{ keys: '`<character>', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}},
|
||
{ keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
|
||
{ keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
|
||
{ keys: ']\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
|
||
{ keys: '[\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
|
||
// the next two aren't motions but must come before more general motion declarations
|
||
{ keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true}},
|
||
{ keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true}},
|
||
{ keys: ']<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true}},
|
||
{ keys: '[<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true}},
|
||
{ keys: '|', type: 'motion', motion: 'moveToColumn'},
|
||
{ keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context:'visual'},
|
||
{ keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'},
|
||
// Operators
|
||
{ keys: 'd', type: 'operator', operator: 'delete' },
|
||
{ keys: 'y', type: 'operator', operator: 'yank' },
|
||
{ keys: 'c', type: 'operator', operator: 'change' },
|
||
{ keys: '=', type: 'operator', operator: 'indentAuto' },
|
||
{ keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }},
|
||
{ keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }},
|
||
{ keys: 'g~', type: 'operator', operator: 'changeCase' },
|
||
{ keys: 'gu', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, isEdit: true },
|
||
{ keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true },
|
||
{ keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }},
|
||
{ keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }},
|
||
// Operator-Motion dual commands
|
||
{ keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }},
|
||
{ keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }},
|
||
{ keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'},
|
||
{ keys: 'D', type: 'operator', operator: 'delete', operatorArgs: { linewise: true }, context: 'visual'},
|
||
{ keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'expandToLine', motionArgs: { linewise: true }, context: 'normal'},
|
||
{ keys: 'Y', type: 'operator', operator: 'yank', operatorArgs: { linewise: true }, context: 'visual'},
|
||
{ keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'},
|
||
{ keys: 'C', type: 'operator', operator: 'change', operatorArgs: { linewise: true }, context: 'visual'},
|
||
{ keys: '~', type: 'operatorMotion', operator: 'changeCase', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: 'normal'},
|
||
{ keys: '~', type: 'operator', operator: 'changeCase', context: 'visual'},
|
||
{ keys: '<C-w>', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' },
|
||
//ignore C-w in normal mode
|
||
{ keys: '<C-w>', type: 'idle', context: 'normal' },
|
||
// Actions
|
||
{ keys: '<C-i>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }},
|
||
{ keys: '<C-o>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }},
|
||
{ keys: '<C-e>', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true }},
|
||
{ keys: '<C-y>', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true }},
|
||
{ keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' },
|
||
{ keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' },
|
||
{ keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' },
|
||
{ keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' },
|
||
{ keys: 'gi', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'lastEdit' }, context: 'normal' },
|
||
{ keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank'}, context: 'normal' },
|
||
{ keys: 'gI', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'bol'}, context: 'normal' },
|
||
{ keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' },
|
||
{ keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' },
|
||
{ keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' },
|
||
{ keys: 'v', type: 'action', action: 'toggleVisualMode' },
|
||
{ keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }},
|
||
{ keys: '<C-v>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},
|
||
{ keys: '<C-q>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},
|
||
{ keys: 'gv', type: 'action', action: 'reselectLastSelection' },
|
||
{ keys: 'J', type: 'action', action: 'joinLines', isEdit: true },
|
||
{ keys: 'gJ', type: 'action', action: 'joinLines', actionArgs: { keepSpaces: true }, isEdit: true },
|
||
{ keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }},
|
||
{ keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }},
|
||
{ keys: 'r<character>', type: 'action', action: 'replace', isEdit: true },
|
||
{ keys: '@<character>', type: 'action', action: 'replayMacro' },
|
||
{ keys: 'q<character>', type: 'action', action: 'enterMacroRecordMode' },
|
||
// Handle Replace-mode as a special case of insert mode.
|
||
{ keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }, context: 'normal'},
|
||
{ keys: 'R', type: 'operator', operator: 'change', operatorArgs: { linewise: true, fullLine: true }, context: 'visual', exitVisualBlock: true},
|
||
{ keys: 'u', type: 'action', action: 'undo', context: 'normal' },
|
||
{ keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, context: 'visual', isEdit: true },
|
||
{ keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, context: 'visual', isEdit: true },
|
||
{ keys: '<C-r>', type: 'action', action: 'redo' },
|
||
{ keys: 'm<character>', type: 'action', action: 'setMark' },
|
||
{ keys: '"<character>', type: 'action', action: 'setRegister' },
|
||
{ keys: 'zz', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }},
|
||
{ keys: 'z.', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
||
{ keys: 'zt', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }},
|
||
{ keys: 'z<CR>', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
||
{ keys: 'z-', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }},
|
||
{ keys: 'zb', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },
|
||
{ keys: '.', type: 'action', action: 'repeatLastEdit' },
|
||
{ keys: '<C-a>', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}},
|
||
{ keys: '<C-x>', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}},
|
||
{ keys: '<C-t>', type: 'action', action: 'indent', actionArgs: { indentRight: true }, context: 'insert' },
|
||
{ keys: '<C-d>', type: 'action', action: 'indent', actionArgs: { indentRight: false }, context: 'insert' },
|
||
// Text object motions
|
||
{ keys: 'a<character>', type: 'motion', motion: 'textObjectManipulation' },
|
||
{ keys: 'i<character>', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }},
|
||
// Search
|
||
{ keys: '/', type: 'search', searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }},
|
||
{ keys: '?', type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }},
|
||
{ keys: '*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},
|
||
{ keys: '#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},
|
||
{ keys: 'g*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }},
|
||
{ keys: 'g#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }},
|
||
// Ex command
|
||
{ keys: ':', type: 'ex' }
|
||
];
|
||
var defaultKeymapLength = defaultKeymap.length;
|
||
|
||
/**
|
||
* Ex commands
|
||
* Care must be taken when adding to the default Ex command map. For any
|
||
* pair of commands that have a shared prefix, at least one of their
|
||
* shortNames must not match the prefix of the other command.
|
||
*/
|
||
var defaultExCommandMap = [
|
||
{ name: 'colorscheme', shortName: 'colo' },
|
||
{ name: 'map' },
|
||
{ name: 'imap', shortName: 'im' },
|
||
{ name: 'nmap', shortName: 'nm' },
|
||
{ name: 'vmap', shortName: 'vm' },
|
||
{ name: 'unmap' },
|
||
{ name: 'write', shortName: 'w' },
|
||
{ name: 'undo', shortName: 'u' },
|
||
{ name: 'redo', shortName: 'red' },
|
||
{ name: 'set', shortName: 'se' },
|
||
{ name: 'setlocal', shortName: 'setl' },
|
||
{ name: 'setglobal', shortName: 'setg' },
|
||
{ name: 'sort', shortName: 'sor' },
|
||
{ name: 'substitute', shortName: 's', possiblyAsync: true },
|
||
{ name: 'nohlsearch', shortName: 'noh' },
|
||
{ name: 'yank', shortName: 'y' },
|
||
{ name: 'delmarks', shortName: 'delm' },
|
||
{ name: 'registers', shortName: 'reg', excludeFromCommandHistory: true },
|
||
{ name: 'global', shortName: 'g' }
|
||
];
|
||
|
||
var Pos = CodeMirror.Pos;
|
||
|
||
var Vim = function() {
|
||
function enterVimMode(cm) {
|
||
cm.setOption('disableInput', true);
|
||
cm.setOption('showCursorWhenSelecting', false);
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||
cm.on('cursorActivity', onCursorActivity);
|
||
maybeInitVimState(cm);
|
||
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||
}
|
||
|
||
function leaveVimMode(cm) {
|
||
cm.setOption('disableInput', false);
|
||
cm.off('cursorActivity', onCursorActivity);
|
||
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||
cm.state.vim = null;
|
||
}
|
||
|
||
function detachVimMap(cm, next) {
|
||
if (this == CodeMirror.keyMap.vim) {
|
||
CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor");
|
||
if (cm.getOption("inputStyle") == "contenteditable" && document.body.style.caretColor != null) {
|
||
disableFatCursorMark(cm);
|
||
cm.getInputField().style.caretColor = "";
|
||
}
|
||
}
|
||
|
||
if (!next || next.attach != attachVimMap)
|
||
leaveVimMode(cm);
|
||
}
|
||
function attachVimMap(cm, prev) {
|
||
if (this == CodeMirror.keyMap.vim) {
|
||
CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor");
|
||
if (cm.getOption("inputStyle") == "contenteditable" && document.body.style.caretColor != null) {
|
||
enableFatCursorMark(cm);
|
||
cm.getInputField().style.caretColor = "transparent";
|
||
}
|
||
}
|
||
|
||
if (!prev || prev.attach != attachVimMap)
|
||
enterVimMode(cm);
|
||
}
|
||
|
||
function updateFatCursorMark(cm) {
|
||
if (!cm.state.fatCursorMarks) return;
|
||
clearFatCursorMark(cm);
|
||
var ranges = cm.listSelections(), result = []
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var range = ranges[i];
|
||
if (range.empty()) {
|
||
var lineLength = cm.getLine(range.anchor.line).length;
|
||
if (range.anchor.ch < lineLength) {
|
||
result.push(cm.markText(range.anchor, Pos(range.anchor.line, range.anchor.ch + 1),
|
||
{className: "cm-fat-cursor-mark"}));
|
||
} else {
|
||
result.push(cm.markText(Pos(range.anchor.line, lineLength - 1),
|
||
Pos(range.anchor.line, lineLength),
|
||
{className: "cm-fat-cursor-mark"}));
|
||
}
|
||
}
|
||
}
|
||
cm.state.fatCursorMarks = result;
|
||
}
|
||
|
||
function clearFatCursorMark(cm) {
|
||
var marks = cm.state.fatCursorMarks;
|
||
if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||
}
|
||
|
||
function enableFatCursorMark(cm) {
|
||
cm.state.fatCursorMarks = [];
|
||
updateFatCursorMark(cm)
|
||
cm.on("cursorActivity", updateFatCursorMark)
|
||
}
|
||
|
||
function disableFatCursorMark(cm) {
|
||
clearFatCursorMark(cm);
|
||
cm.off("cursorActivity", updateFatCursorMark);
|
||
// explicitly set fatCursorMarks to null because event listener above
|
||
// can be invoke after removing it, if off is called from operation
|
||
cm.state.fatCursorMarks = null;
|
||
}
|
||
|
||
// Deprecated, simply setting the keymap works again.
|
||
CodeMirror.defineOption('vimMode', false, function(cm, val, prev) {
|
||
if (val && cm.getOption("keyMap") != "vim")
|
||
cm.setOption("keyMap", "vim");
|
||
else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap")))
|
||
cm.setOption("keyMap", "default");
|
||
});
|
||
|
||
function cmKey(key, cm) {
|
||
if (!cm) { return undefined; }
|
||
if (this[key]) { return this[key]; }
|
||
var vimKey = cmKeyToVimKey(key);
|
||
if (!vimKey) {
|
||
return false;
|
||
}
|
||
var cmd = CodeMirror.Vim.findKey(cm, vimKey);
|
||
if (typeof cmd == 'function') {
|
||
CodeMirror.signal(cm, 'vim-keypress', vimKey);
|
||
}
|
||
return cmd;
|
||
}
|
||
|
||
var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'};
|
||
var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'};
|
||
function cmKeyToVimKey(key) {
|
||
if (key.charAt(0) == '\'') {
|
||
// Keypress character binding of format "'a'"
|
||
return key.charAt(1);
|
||
}
|
||
var pieces = key.split(/-(?!$)/);
|
||
var lastPiece = pieces[pieces.length - 1];
|
||
if (pieces.length == 1 && pieces[0].length == 1) {
|
||
// No-modifier bindings use literal character bindings above. Skip.
|
||
return false;
|
||
} else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) {
|
||
// Ignore Shift+char bindings as they should be handled by literal character.
|
||
return false;
|
||
}
|
||
var hasCharacter = false;
|
||
for (var i = 0; i < pieces.length; i++) {
|
||
var piece = pieces[i];
|
||
if (piece in modifiers) { pieces[i] = modifiers[piece]; }
|
||
else { hasCharacter = true; }
|
||
if (piece in specialKeys) { pieces[i] = specialKeys[piece]; }
|
||
}
|
||
if (!hasCharacter) {
|
||
// Vim does not support modifier only keys.
|
||
return false;
|
||
}
|
||
// TODO: Current bindings expect the character to be lower case, but
|
||
// it looks like vim key notation uses upper case.
|
||
if (isUpperCase(lastPiece)) {
|
||
pieces[pieces.length - 1] = lastPiece.toLowerCase();
|
||
}
|
||
return '<' + pieces.join('-') + '>';
|
||
}
|
||
|
||
function getOnPasteFn(cm) {
|
||
var vim = cm.state.vim;
|
||
if (!vim.onPasteFn) {
|
||
vim.onPasteFn = function() {
|
||
if (!vim.insertMode) {
|
||
cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
|
||
actions.enterInsertMode(cm, {}, vim);
|
||
}
|
||
};
|
||
}
|
||
return vim.onPasteFn;
|
||
}
|
||
|
||
var numberRegex = /[\d]/;
|
||
var wordCharTest = [CodeMirror.isWordChar, function(ch) {
|
||
return ch && !CodeMirror.isWordChar(ch) && !/\s/.test(ch);
|
||
}], bigWordCharTest = [function(ch) {
|
||
return /\S/.test(ch);
|
||
}];
|
||
function makeKeyRange(start, size) {
|
||
var keys = [];
|
||
for (var i = start; i < start + size; i++) {
|
||
keys.push(String.fromCharCode(i));
|
||
}
|
||
return keys;
|
||
}
|
||
var upperCaseAlphabet = makeKeyRange(65, 26);
|
||
var lowerCaseAlphabet = makeKeyRange(97, 26);
|
||
var numbers = makeKeyRange(48, 10);
|
||
var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']);
|
||
var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']);
|
||
|
||
function isLine(cm, line) {
|
||
return line >= cm.firstLine() && line <= cm.lastLine();
|
||
}
|
||
function isLowerCase(k) {
|
||
return (/^[a-z]$/).test(k);
|
||
}
|
||
function isMatchableSymbol(k) {
|
||
return '()[]{}'.indexOf(k) != -1;
|
||
}
|
||
function isNumber(k) {
|
||
return numberRegex.test(k);
|
||
}
|
||
function isUpperCase(k) {
|
||
return (/^[A-Z]$/).test(k);
|
||
}
|
||
function isWhiteSpaceString(k) {
|
||
return (/^\s*$/).test(k);
|
||
}
|
||
function isEndOfSentenceSymbol(k) {
|
||
return '.?!'.indexOf(k) != -1;
|
||
}
|
||
function inArray(val, arr) {
|
||
for (var i = 0; i < arr.length; i++) {
|
||
if (arr[i] == val) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
var options = {};
|
||
function defineOption(name, defaultValue, type, aliases, callback) {
|
||
if (defaultValue === undefined && !callback) {
|
||
throw Error('defaultValue is required unless callback is provided');
|
||
}
|
||
if (!type) { type = 'string'; }
|
||
options[name] = {
|
||
type: type,
|
||
defaultValue: defaultValue,
|
||
callback: callback
|
||
};
|
||
if (aliases) {
|
||
for (var i = 0; i < aliases.length; i++) {
|
||
options[aliases[i]] = options[name];
|
||
}
|
||
}
|
||
if (defaultValue) {
|
||
setOption(name, defaultValue);
|
||
}
|
||
}
|
||
|
||
function setOption(name, value, cm, cfg) {
|
||
var option = options[name];
|
||
cfg = cfg || {};
|
||
var scope = cfg.scope;
|
||
if (!option) {
|
||
return new Error('Unknown option: ' + name);
|
||
}
|
||
if (option.type == 'boolean') {
|
||
if (value && value !== true) {
|
||
return new Error('Invalid argument: ' + name + '=' + value);
|
||
} else if (value !== false) {
|
||
// Boolean options are set to true if value is not defined.
|
||
value = true;
|
||
}
|
||
}
|
||
if (option.callback) {
|
||
if (scope !== 'local') {
|
||
option.callback(value, undefined);
|
||
}
|
||
if (scope !== 'global' && cm) {
|
||
option.callback(value, cm);
|
||
}
|
||
} else {
|
||
if (scope !== 'local') {
|
||
option.value = option.type == 'boolean' ? !!value : value;
|
||
}
|
||
if (scope !== 'global' && cm) {
|
||
cm.state.vim.options[name] = {value: value};
|
||
}
|
||
}
|
||
}
|
||
|
||
function getOption(name, cm, cfg) {
|
||
var option = options[name];
|
||
cfg = cfg || {};
|
||
var scope = cfg.scope;
|
||
if (!option) {
|
||
return new Error('Unknown option: ' + name);
|
||
}
|
||
if (option.callback) {
|
||
var local = cm && option.callback(undefined, cm);
|
||
if (scope !== 'global' && local !== undefined) {
|
||
return local;
|
||
}
|
||
if (scope !== 'local') {
|
||
return option.callback();
|
||
}
|
||
return;
|
||
} else {
|
||
var local = (scope !== 'global') && (cm && cm.state.vim.options[name]);
|
||
return (local || (scope !== 'local') && option || {}).value;
|
||
}
|
||
}
|
||
|
||
defineOption('filetype', undefined, 'string', ['ft'], function(name, cm) {
|
||
// Option is local. Do nothing for global.
|
||
if (cm === undefined) {
|
||
return;
|
||
}
|
||
// The 'filetype' option proxies to the CodeMirror 'mode' option.
|
||
if (name === undefined) {
|
||
var mode = cm.getOption('mode');
|
||
return mode == 'null' ? '' : mode;
|
||
} else {
|
||
var mode = name == '' ? 'null' : name;
|
||
cm.setOption('mode', mode);
|
||
}
|
||
});
|
||
|
||
var createCircularJumpList = function() {
|
||
var size = 100;
|
||
var pointer = -1;
|
||
var head = 0;
|
||
var tail = 0;
|
||
var buffer = new Array(size);
|
||
function add(cm, oldCur, newCur) {
|
||
var current = pointer % size;
|
||
var curMark = buffer[current];
|
||
function useNextSlot(cursor) {
|
||
var next = ++pointer % size;
|
||
var trashMark = buffer[next];
|
||
if (trashMark) {
|
||
trashMark.clear();
|
||
}
|
||
buffer[next] = cm.setBookmark(cursor);
|
||
}
|
||
if (curMark) {
|
||
var markPos = curMark.find();
|
||
// avoid recording redundant cursor position
|
||
if (markPos && !cursorEqual(markPos, oldCur)) {
|
||
useNextSlot(oldCur);
|
||
}
|
||
} else {
|
||
useNextSlot(oldCur);
|
||
}
|
||
useNextSlot(newCur);
|
||
head = pointer;
|
||
tail = pointer - size + 1;
|
||
if (tail < 0) {
|
||
tail = 0;
|
||
}
|
||
}
|
||
function move(cm, offset) {
|
||
pointer += offset;
|
||
if (pointer > head) {
|
||
pointer = head;
|
||
} else if (pointer < tail) {
|
||
pointer = tail;
|
||
}
|
||
var mark = buffer[(size + pointer) % size];
|
||
// skip marks that are temporarily removed from text buffer
|
||
if (mark && !mark.find()) {
|
||
var inc = offset > 0 ? 1 : -1;
|
||
var newCur;
|
||
var oldCur = cm.getCursor();
|
||
do {
|
||
pointer += inc;
|
||
mark = buffer[(size + pointer) % size];
|
||
// skip marks that are the same as current position
|
||
if (mark &&
|
||
(newCur = mark.find()) &&
|
||
!cursorEqual(oldCur, newCur)) {
|
||
break;
|
||
}
|
||
} while (pointer < head && pointer > tail);
|
||
}
|
||
return mark;
|
||
}
|
||
function find(cm, offset) {
|
||
var oldPointer = pointer;
|
||
var mark = move(cm, offset);
|
||
pointer = oldPointer;
|
||
return mark && mark.find();
|
||
}
|
||
return {
|
||
cachedCursor: undefined, //used for # and * jumps
|
||
add: add,
|
||
find: find,
|
||
move: move
|
||
};
|
||
};
|
||
|
||
// Returns an object to track the changes associated insert mode. It
|
||
// clones the object that is passed in, or creates an empty object one if
|
||
// none is provided.
|
||
var createInsertModeChanges = function(c) {
|
||
if (c) {
|
||
// Copy construction
|
||
return {
|
||
changes: c.changes,
|
||
expectCursorActivityForChange: c.expectCursorActivityForChange
|
||
};
|
||
}
|
||
return {
|
||
// Change list
|
||
changes: [],
|
||
// Set to true on change, false on cursorActivity.
|
||
expectCursorActivityForChange: false
|
||
};
|
||
};
|
||
|
||
function MacroModeState() {
|
||
this.latestRegister = undefined;
|
||
this.isPlaying = false;
|
||
this.isRecording = false;
|
||
this.replaySearchQueries = [];
|
||
this.onRecordingDone = undefined;
|
||
this.lastInsertModeChanges = createInsertModeChanges();
|
||
}
|
||
MacroModeState.prototype = {
|
||
exitMacroRecordMode: function() {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (macroModeState.onRecordingDone) {
|
||
macroModeState.onRecordingDone(); // close dialog
|
||
}
|
||
macroModeState.onRecordingDone = undefined;
|
||
macroModeState.isRecording = false;
|
||
},
|
||
enterMacroRecordMode: function(cm, registerName) {
|
||
var register =
|
||
vimGlobalState.registerController.getRegister(registerName);
|
||
if (register) {
|
||
register.clear();
|
||
this.latestRegister = registerName;
|
||
if (cm.openDialog) {
|
||
this.onRecordingDone = cm.openDialog(
|
||
'(recording)['+registerName+']', null, {bottom:true});
|
||
}
|
||
this.isRecording = true;
|
||
}
|
||
}
|
||
};
|
||
|
||
function maybeInitVimState(cm) {
|
||
if (!cm.state.vim) {
|
||
// Store instance state in the CodeMirror object.
|
||
cm.state.vim = {
|
||
inputState: new InputState(),
|
||
// Vim's input state that triggered the last edit, used to repeat
|
||
// motions and operators with '.'.
|
||
lastEditInputState: undefined,
|
||
// Vim's action command before the last edit, used to repeat actions
|
||
// with '.' and insert mode repeat.
|
||
lastEditActionCommand: undefined,
|
||
// When using jk for navigation, if you move from a longer line to a
|
||
// shorter line, the cursor may clip to the end of the shorter line.
|
||
// If j is pressed again and cursor goes to the next line, the
|
||
// cursor should go back to its horizontal position on the longer
|
||
// line if it can. This is to keep track of the horizontal position.
|
||
lastHPos: -1,
|
||
// Doing the same with screen-position for gj/gk
|
||
lastHSPos: -1,
|
||
// The last motion command run. Cleared if a non-motion command gets
|
||
// executed in between.
|
||
lastMotion: null,
|
||
marks: {},
|
||
// Mark for rendering fake cursor for visual mode.
|
||
fakeCursor: null,
|
||
insertMode: false,
|
||
// Repeat count for changes made in insert mode, triggered by key
|
||
// sequences like 3,i. Only exists when insertMode is true.
|
||
insertModeRepeat: undefined,
|
||
visualMode: false,
|
||
// If we are in visual line mode. No effect if visualMode is false.
|
||
visualLine: false,
|
||
visualBlock: false,
|
||
lastSelection: null,
|
||
lastPastedText: null,
|
||
sel: {},
|
||
// Buffer-local/window-local values of vim options.
|
||
options: {}
|
||
};
|
||
}
|
||
return cm.state.vim;
|
||
}
|
||
var vimGlobalState;
|
||
function resetVimGlobalState() {
|
||
vimGlobalState = {
|
||
// The current search query.
|
||
searchQuery: null,
|
||
// Whether we are searching backwards.
|
||
searchIsReversed: false,
|
||
// Replace part of the last substituted pattern
|
||
lastSubstituteReplacePart: undefined,
|
||
jumpList: createCircularJumpList(),
|
||
macroModeState: new MacroModeState,
|
||
// Recording latest f, t, F or T motion command.
|
||
lastCharacterSearch: {increment:0, forward:true, selectedCharacter:''},
|
||
registerController: new RegisterController({}),
|
||
// search history buffer
|
||
searchHistoryController: new HistoryController(),
|
||
// ex Command history buffer
|
||
exCommandHistoryController : new HistoryController()
|
||
};
|
||
for (var optionName in options) {
|
||
var option = options[optionName];
|
||
option.value = option.defaultValue;
|
||
}
|
||
}
|
||
|
||
var lastInsertModeKeyTimer;
|
||
var vimApi= {
|
||
buildKeyMap: function() {
|
||
// TODO: Convert keymap into dictionary format for fast lookup.
|
||
},
|
||
// Testing hook, though it might be useful to expose the register
|
||
// controller anyways.
|
||
getRegisterController: function() {
|
||
return vimGlobalState.registerController;
|
||
},
|
||
// Testing hook.
|
||
resetVimGlobalState_: resetVimGlobalState,
|
||
|
||
// Testing hook.
|
||
getVimGlobalState_: function() {
|
||
return vimGlobalState;
|
||
},
|
||
|
||
// Testing hook.
|
||
maybeInitVimState_: maybeInitVimState,
|
||
|
||
suppressErrorLogging: false,
|
||
|
||
InsertModeKey: InsertModeKey,
|
||
map: function(lhs, rhs, ctx) {
|
||
// Add user defined key bindings.
|
||
exCommandDispatcher.map(lhs, rhs, ctx);
|
||
},
|
||
unmap: function(lhs, ctx) {
|
||
exCommandDispatcher.unmap(lhs, ctx);
|
||
},
|
||
// Non-recursive map function.
|
||
// NOTE: This will not create mappings to key maps that aren't present
|
||
// in the default key map. See TODO at bottom of function.
|
||
noremap: function(lhs, rhs, ctx) {
|
||
function toCtxArray(ctx) {
|
||
return ctx ? [ctx] : ['normal', 'insert', 'visual'];
|
||
}
|
||
var ctxsToMap = toCtxArray(ctx);
|
||
// Look through all actual defaults to find a map candidate.
|
||
var actualLength = defaultKeymap.length, origLength = defaultKeymapLength;
|
||
for (var i = actualLength - origLength;
|
||
i < actualLength && ctxsToMap.length;
|
||
i++) {
|
||
var mapping = defaultKeymap[i];
|
||
// Omit mappings that operate in the wrong context(s) and those of invalid type.
|
||
if (mapping.keys == rhs &&
|
||
(!ctx || !mapping.context || mapping.context === ctx) &&
|
||
mapping.type.substr(0, 2) !== 'ex' &&
|
||
mapping.type.substr(0, 3) !== 'key') {
|
||
// Make a shallow copy of the original keymap entry.
|
||
var newMapping = {};
|
||
for (var key in mapping) {
|
||
newMapping[key] = mapping[key];
|
||
}
|
||
// Modify it point to the new mapping with the proper context.
|
||
newMapping.keys = lhs;
|
||
if (ctx && !newMapping.context) {
|
||
newMapping.context = ctx;
|
||
}
|
||
// Add it to the keymap with a higher priority than the original.
|
||
this._mapCommand(newMapping);
|
||
// Record the mapped contexts as complete.
|
||
var mappedCtxs = toCtxArray(mapping.context);
|
||
ctxsToMap = ctxsToMap.filter(function(el) { return mappedCtxs.indexOf(el) === -1; });
|
||
}
|
||
}
|
||
// TODO: Create non-recursive keyToKey mappings for the unmapped contexts once those exist.
|
||
},
|
||
// Remove all user-defined mappings for the provided context.
|
||
mapclear: function(ctx) {
|
||
// Partition the existing keymap into user-defined and true defaults.
|
||
var actualLength = defaultKeymap.length,
|
||
origLength = defaultKeymapLength;
|
||
var userKeymap = defaultKeymap.slice(0, actualLength - origLength);
|
||
defaultKeymap = defaultKeymap.slice(actualLength - origLength);
|
||
if (ctx) {
|
||
// If a specific context is being cleared, we need to keep mappings
|
||
// from all other contexts.
|
||
for (var i = userKeymap.length - 1; i >= 0; i--) {
|
||
var mapping = userKeymap[i];
|
||
if (ctx !== mapping.context) {
|
||
if (mapping.context) {
|
||
this._mapCommand(mapping);
|
||
} else {
|
||
// `mapping` applies to all contexts so create keymap copies
|
||
// for each context except the one being cleared.
|
||
var contexts = ['normal', 'insert', 'visual'];
|
||
for (var j in contexts) {
|
||
if (contexts[j] !== ctx) {
|
||
var newMapping = {};
|
||
for (var key in mapping) {
|
||
newMapping[key] = mapping[key];
|
||
}
|
||
newMapping.context = contexts[j];
|
||
this._mapCommand(newMapping);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
// TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace
|
||
// them, or somehow make them work with the existing CodeMirror setOption/getOption API.
|
||
setOption: setOption,
|
||
getOption: getOption,
|
||
defineOption: defineOption,
|
||
defineEx: function(name, prefix, func){
|
||
if (!prefix) {
|
||
prefix = name;
|
||
} else if (name.indexOf(prefix) !== 0) {
|
||
throw new Error('(Vim.defineEx) "'+prefix+'" is not a prefix of "'+name+'", command not registered');
|
||
}
|
||
exCommands[name]=func;
|
||
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
|
||
},
|
||
handleKey: function (cm, key, origin) {
|
||
var command = this.findKey(cm, key, origin);
|
||
if (typeof command === 'function') {
|
||
return command();
|
||
}
|
||
},
|
||
/**
|
||
* This is the outermost function called by CodeMirror, after keys have
|
||
* been mapped to their Vim equivalents.
|
||
*
|
||
* Finds a command based on the key (and cached keys if there is a
|
||
* multi-key sequence). Returns `undefined` if no key is matched, a noop
|
||
* function if a partial match is found (multi-key), and a function to
|
||
* execute the bound command if a a key is matched. The function always
|
||
* returns true.
|
||
*/
|
||
findKey: function(cm, key, origin) {
|
||
var vim = maybeInitVimState(cm);
|
||
function handleMacroRecording() {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (macroModeState.isRecording) {
|
||
if (key == 'q') {
|
||
macroModeState.exitMacroRecordMode();
|
||
clearInputState(cm);
|
||
return true;
|
||
}
|
||
if (origin != 'mapping') {
|
||
logKey(macroModeState, key);
|
||
}
|
||
}
|
||
}
|
||
function handleEsc() {
|
||
if (key == '<Esc>') {
|
||
// Clear input state and get back to normal mode.
|
||
clearInputState(cm);
|
||
if (vim.visualMode) {
|
||
exitVisualMode(cm);
|
||
} else if (vim.insertMode) {
|
||
exitInsertMode(cm);
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
function doKeyToKey(keys) {
|
||
// TODO: prevent infinite recursion.
|
||
var match;
|
||
while (keys) {
|
||
// Pull off one command key, which is either a single character
|
||
// or a special sequence wrapped in '<' and '>', e.g. '<Space>'.
|
||
match = (/<\w+-.+?>|<\w+>|./).exec(keys);
|
||
key = match[0];
|
||
keys = keys.substring(match.index + key.length);
|
||
CodeMirror.Vim.handleKey(cm, key, 'mapping');
|
||
}
|
||
}
|
||
|
||
function handleKeyInsertMode() {
|
||
if (handleEsc()) { return true; }
|
||
var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;
|
||
var keysAreChars = key.length == 1;
|
||
var match = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert');
|
||
// Need to check all key substrings in insert mode.
|
||
while (keys.length > 1 && match.type != 'full') {
|
||
var keys = vim.inputState.keyBuffer = keys.slice(1);
|
||
var thisMatch = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert');
|
||
if (thisMatch.type != 'none') { match = thisMatch; }
|
||
}
|
||
if (match.type == 'none') { clearInputState(cm); return false; }
|
||
else if (match.type == 'partial') {
|
||
if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); }
|
||
lastInsertModeKeyTimer = window.setTimeout(
|
||
function() { if (vim.insertMode && vim.inputState.keyBuffer) { clearInputState(cm); } },
|
||
getOption('insertModeEscKeysTimeout'));
|
||
return !keysAreChars;
|
||
}
|
||
|
||
if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); }
|
||
if (keysAreChars) {
|
||
var selections = cm.listSelections();
|
||
for (var i = 0; i < selections.length; i++) {
|
||
var here = selections[i].head;
|
||
cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');
|
||
}
|
||
vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop();
|
||
}
|
||
clearInputState(cm);
|
||
return match.command;
|
||
}
|
||
|
||
function handleKeyNonInsertMode() {
|
||
if (handleMacroRecording() || handleEsc()) { return true; }
|
||
|
||
var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;
|
||
if (/^[1-9]\d*$/.test(keys)) { return true; }
|
||
|
||
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
||
if (!keysMatcher) { clearInputState(cm); return false; }
|
||
var context = vim.visualMode ? 'visual' :
|
||
'normal';
|
||
var match = commandDispatcher.matchCommand(keysMatcher[2] || keysMatcher[1], defaultKeymap, vim.inputState, context);
|
||
if (match.type == 'none') { clearInputState(cm); return false; }
|
||
else if (match.type == 'partial') { return true; }
|
||
|
||
vim.inputState.keyBuffer = '';
|
||
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
||
if (keysMatcher[1] && keysMatcher[1] != '0') {
|
||
vim.inputState.pushRepeatDigit(keysMatcher[1]);
|
||
}
|
||
return match.command;
|
||
}
|
||
|
||
var command;
|
||
if (vim.insertMode) { command = handleKeyInsertMode(); }
|
||
else { command = handleKeyNonInsertMode(); }
|
||
if (command === false) {
|
||
return !vim.insertMode && key.length === 1 ? function() { return true; } : undefined;
|
||
} else if (command === true) {
|
||
// TODO: Look into using CodeMirror's multi-key handling.
|
||
// Return no-op since we are caching the key. Counts as handled, but
|
||
// don't want act on it just yet.
|
||
return function() { return true; };
|
||
} else {
|
||
return function() {
|
||
return cm.operation(function() {
|
||
cm.curOp.isVimOp = true;
|
||
try {
|
||
if (command.type == 'keyToKey') {
|
||
doKeyToKey(command.toKeys);
|
||
} else {
|
||
commandDispatcher.processCommand(cm, vim, command);
|
||
}
|
||
} catch (e) {
|
||
// clear VIM state in case it's in a bad state.
|
||
cm.state.vim = undefined;
|
||
maybeInitVimState(cm);
|
||
if (!CodeMirror.Vim.suppressErrorLogging) {
|
||
console['log'](e);
|
||
}
|
||
throw e;
|
||
}
|
||
return true;
|
||
});
|
||
};
|
||
}
|
||
},
|
||
handleEx: function(cm, input) {
|
||
exCommandDispatcher.processCommand(cm, input);
|
||
},
|
||
|
||
defineMotion: defineMotion,
|
||
defineAction: defineAction,
|
||
defineOperator: defineOperator,
|
||
mapCommand: mapCommand,
|
||
_mapCommand: _mapCommand,
|
||
|
||
defineRegister: defineRegister,
|
||
|
||
exitVisualMode: exitVisualMode,
|
||
exitInsertMode: exitInsertMode
|
||
};
|
||
|
||
// Represents the current input state.
|
||
function InputState() {
|
||
this.prefixRepeat = [];
|
||
this.motionRepeat = [];
|
||
|
||
this.operator = null;
|
||
this.operatorArgs = null;
|
||
this.motion = null;
|
||
this.motionArgs = null;
|
||
this.keyBuffer = []; // For matching multi-key commands.
|
||
this.registerName = null; // Defaults to the unnamed register.
|
||
}
|
||
InputState.prototype.pushRepeatDigit = function(n) {
|
||
if (!this.operator) {
|
||
this.prefixRepeat = this.prefixRepeat.concat(n);
|
||
} else {
|
||
this.motionRepeat = this.motionRepeat.concat(n);
|
||
}
|
||
};
|
||
InputState.prototype.getRepeat = function() {
|
||
var repeat = 0;
|
||
if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) {
|
||
repeat = 1;
|
||
if (this.prefixRepeat.length > 0) {
|
||
repeat *= parseInt(this.prefixRepeat.join(''), 10);
|
||
}
|
||
if (this.motionRepeat.length > 0) {
|
||
repeat *= parseInt(this.motionRepeat.join(''), 10);
|
||
}
|
||
}
|
||
return repeat;
|
||
};
|
||
|
||
function clearInputState(cm, reason) {
|
||
cm.state.vim.inputState = new InputState();
|
||
CodeMirror.signal(cm, 'vim-command-done', reason);
|
||
}
|
||
|
||
/*
|
||
* Register stores information about copy and paste registers. Besides
|
||
* text, a register must store whether it is linewise (i.e., when it is
|
||
* pasted, should it insert itself into a new line, or should the text be
|
||
* inserted at the cursor position.)
|
||
*/
|
||
function Register(text, linewise, blockwise) {
|
||
this.clear();
|
||
this.keyBuffer = [text || ''];
|
||
this.insertModeChanges = [];
|
||
this.searchQueries = [];
|
||
this.linewise = !!linewise;
|
||
this.blockwise = !!blockwise;
|
||
}
|
||
Register.prototype = {
|
||
setText: function(text, linewise, blockwise) {
|
||
this.keyBuffer = [text || ''];
|
||
this.linewise = !!linewise;
|
||
this.blockwise = !!blockwise;
|
||
},
|
||
pushText: function(text, linewise) {
|
||
// if this register has ever been set to linewise, use linewise.
|
||
if (linewise) {
|
||
if (!this.linewise) {
|
||
this.keyBuffer.push('\n');
|
||
}
|
||
this.linewise = true;
|
||
}
|
||
this.keyBuffer.push(text);
|
||
},
|
||
pushInsertModeChanges: function(changes) {
|
||
this.insertModeChanges.push(createInsertModeChanges(changes));
|
||
},
|
||
pushSearchQuery: function(query) {
|
||
this.searchQueries.push(query);
|
||
},
|
||
clear: function() {
|
||
this.keyBuffer = [];
|
||
this.insertModeChanges = [];
|
||
this.searchQueries = [];
|
||
this.linewise = false;
|
||
},
|
||
toString: function() {
|
||
return this.keyBuffer.join('');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Defines an external register.
|
||
*
|
||
* The name should be a single character that will be used to reference the register.
|
||
* The register should support setText, pushText, clear, and toString(). See Register
|
||
* for a reference implementation.
|
||
*/
|
||
function defineRegister(name, register) {
|
||
var registers = vimGlobalState.registerController.registers;
|
||
if (!name || name.length != 1) {
|
||
throw Error('Register name must be 1 character');
|
||
}
|
||
if (registers[name]) {
|
||
throw Error('Register already defined ' + name);
|
||
}
|
||
registers[name] = register;
|
||
validRegisters.push(name);
|
||
}
|
||
|
||
/*
|
||
* vim registers allow you to keep many independent copy and paste buffers.
|
||
* See http://usevim.com/2012/04/13/registers/ for an introduction.
|
||
*
|
||
* RegisterController keeps the state of all the registers. An initial
|
||
* state may be passed in. The unnamed register '"' will always be
|
||
* overridden.
|
||
*/
|
||
function RegisterController(registers) {
|
||
this.registers = registers;
|
||
this.unnamedRegister = registers['"'] = new Register();
|
||
registers['.'] = new Register();
|
||
registers[':'] = new Register();
|
||
registers['/'] = new Register();
|
||
}
|
||
RegisterController.prototype = {
|
||
pushText: function(registerName, operator, text, linewise, blockwise) {
|
||
if (linewise && text.charAt(text.length - 1) !== '\n'){
|
||
text += '\n';
|
||
}
|
||
// Lowercase and uppercase registers refer to the same register.
|
||
// Uppercase just means append.
|
||
var register = this.isValidRegister(registerName) ?
|
||
this.getRegister(registerName) : null;
|
||
// if no register/an invalid register was specified, things go to the
|
||
// default registers
|
||
if (!register) {
|
||
switch (operator) {
|
||
case 'yank':
|
||
// The 0 register contains the text from the most recent yank.
|
||
this.registers['0'] = new Register(text, linewise, blockwise);
|
||
break;
|
||
case 'delete':
|
||
case 'change':
|
||
if (text.indexOf('\n') == -1) {
|
||
// Delete less than 1 line. Update the small delete register.
|
||
this.registers['-'] = new Register(text, linewise);
|
||
} else {
|
||
// Shift down the contents of the numbered registers and put the
|
||
// deleted text into register 1.
|
||
this.shiftNumericRegisters_();
|
||
this.registers['1'] = new Register(text, linewise);
|
||
}
|
||
break;
|
||
}
|
||
// Make sure the unnamed register is set to what just happened
|
||
this.unnamedRegister.setText(text, linewise, blockwise);
|
||
return;
|
||
}
|
||
|
||
// If we've gotten to this point, we've actually specified a register
|
||
var append = isUpperCase(registerName);
|
||
if (append) {
|
||
register.pushText(text, linewise);
|
||
} else {
|
||
register.setText(text, linewise, blockwise);
|
||
}
|
||
// The unnamed register always has the same value as the last used
|
||
// register.
|
||
this.unnamedRegister.setText(register.toString(), linewise);
|
||
},
|
||
// Gets the register named @name. If one of @name doesn't already exist,
|
||
// create it. If @name is invalid, return the unnamedRegister.
|
||
getRegister: function(name) {
|
||
if (!this.isValidRegister(name)) {
|
||
return this.unnamedRegister;
|
||
}
|
||
name = name.toLowerCase();
|
||
if (!this.registers[name]) {
|
||
this.registers[name] = new Register();
|
||
}
|
||
return this.registers[name];
|
||
},
|
||
isValidRegister: function(name) {
|
||
return name && inArray(name, validRegisters);
|
||
},
|
||
shiftNumericRegisters_: function() {
|
||
for (var i = 9; i >= 2; i--) {
|
||
this.registers[i] = this.getRegister('' + (i - 1));
|
||
}
|
||
}
|
||
};
|
||
function HistoryController() {
|
||
this.historyBuffer = [];
|
||
this.iterator = 0;
|
||
this.initialPrefix = null;
|
||
}
|
||
HistoryController.prototype = {
|
||
// the input argument here acts a user entered prefix for a small time
|
||
// until we start autocompletion in which case it is the autocompleted.
|
||
nextMatch: function (input, up) {
|
||
var historyBuffer = this.historyBuffer;
|
||
var dir = up ? -1 : 1;
|
||
if (this.initialPrefix === null) this.initialPrefix = input;
|
||
for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i+= dir) {
|
||
var element = historyBuffer[i];
|
||
for (var j = 0; j <= element.length; j++) {
|
||
if (this.initialPrefix == element.substring(0, j)) {
|
||
this.iterator = i;
|
||
return element;
|
||
}
|
||
}
|
||
}
|
||
// should return the user input in case we reach the end of buffer.
|
||
if (i >= historyBuffer.length) {
|
||
this.iterator = historyBuffer.length;
|
||
return this.initialPrefix;
|
||
}
|
||
// return the last autocompleted query or exCommand as it is.
|
||
if (i < 0 ) return input;
|
||
},
|
||
pushInput: function(input) {
|
||
var index = this.historyBuffer.indexOf(input);
|
||
if (index > -1) this.historyBuffer.splice(index, 1);
|
||
if (input.length) this.historyBuffer.push(input);
|
||
},
|
||
reset: function() {
|
||
this.initialPrefix = null;
|
||
this.iterator = this.historyBuffer.length;
|
||
}
|
||
};
|
||
var commandDispatcher = {
|
||
matchCommand: function(keys, keyMap, inputState, context) {
|
||
var matches = commandMatches(keys, keyMap, context, inputState);
|
||
if (!matches.full && !matches.partial) {
|
||
return {type: 'none'};
|
||
} else if (!matches.full && matches.partial) {
|
||
return {type: 'partial'};
|
||
}
|
||
|
||
var bestMatch;
|
||
for (var i = 0; i < matches.full.length; i++) {
|
||
var match = matches.full[i];
|
||
if (!bestMatch) {
|
||
bestMatch = match;
|
||
}
|
||
}
|
||
if (bestMatch.keys.slice(-11) == '<character>') {
|
||
var character = lastChar(keys);
|
||
if (!character) return {type: 'none'};
|
||
inputState.selectedCharacter = character;
|
||
}
|
||
return {type: 'full', command: bestMatch};
|
||
},
|
||
processCommand: function(cm, vim, command) {
|
||
vim.inputState.repeatOverride = command.repeatOverride;
|
||
switch (command.type) {
|
||
case 'motion':
|
||
this.processMotion(cm, vim, command);
|
||
break;
|
||
case 'operator':
|
||
this.processOperator(cm, vim, command);
|
||
break;
|
||
case 'operatorMotion':
|
||
this.processOperatorMotion(cm, vim, command);
|
||
break;
|
||
case 'action':
|
||
this.processAction(cm, vim, command);
|
||
break;
|
||
case 'search':
|
||
this.processSearch(cm, vim, command);
|
||
break;
|
||
case 'ex':
|
||
case 'keyToEx':
|
||
this.processEx(cm, vim, command);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
},
|
||
processMotion: function(cm, vim, command) {
|
||
vim.inputState.motion = command.motion;
|
||
vim.inputState.motionArgs = copyArgs(command.motionArgs);
|
||
this.evalInput(cm, vim);
|
||
},
|
||
processOperator: function(cm, vim, command) {
|
||
var inputState = vim.inputState;
|
||
if (inputState.operator) {
|
||
if (inputState.operator == command.operator) {
|
||
// Typing an operator twice like 'dd' makes the operator operate
|
||
// linewise
|
||
inputState.motion = 'expandToLine';
|
||
inputState.motionArgs = { linewise: true };
|
||
this.evalInput(cm, vim);
|
||
return;
|
||
} else {
|
||
// 2 different operators in a row doesn't make sense.
|
||
clearInputState(cm);
|
||
}
|
||
}
|
||
inputState.operator = command.operator;
|
||
inputState.operatorArgs = copyArgs(command.operatorArgs);
|
||
if (command.exitVisualBlock) {
|
||
vim.visualBlock = false;
|
||
updateCmSelection(cm);
|
||
}
|
||
if (vim.visualMode) {
|
||
// Operating on a selection in visual mode. We don't need a motion.
|
||
this.evalInput(cm, vim);
|
||
}
|
||
},
|
||
processOperatorMotion: function(cm, vim, command) {
|
||
var visualMode = vim.visualMode;
|
||
var operatorMotionArgs = copyArgs(command.operatorMotionArgs);
|
||
if (operatorMotionArgs) {
|
||
// Operator motions may have special behavior in visual mode.
|
||
if (visualMode && operatorMotionArgs.visualLine) {
|
||
vim.visualLine = true;
|
||
}
|
||
}
|
||
this.processOperator(cm, vim, command);
|
||
if (!visualMode) {
|
||
this.processMotion(cm, vim, command);
|
||
}
|
||
},
|
||
processAction: function(cm, vim, command) {
|
||
var inputState = vim.inputState;
|
||
var repeat = inputState.getRepeat();
|
||
var repeatIsExplicit = !!repeat;
|
||
var actionArgs = copyArgs(command.actionArgs) || {};
|
||
if (inputState.selectedCharacter) {
|
||
actionArgs.selectedCharacter = inputState.selectedCharacter;
|
||
}
|
||
// Actions may or may not have motions and operators. Do these first.
|
||
if (command.operator) {
|
||
this.processOperator(cm, vim, command);
|
||
}
|
||
if (command.motion) {
|
||
this.processMotion(cm, vim, command);
|
||
}
|
||
if (command.motion || command.operator) {
|
||
this.evalInput(cm, vim);
|
||
}
|
||
actionArgs.repeat = repeat || 1;
|
||
actionArgs.repeatIsExplicit = repeatIsExplicit;
|
||
actionArgs.registerName = inputState.registerName;
|
||
clearInputState(cm);
|
||
vim.lastMotion = null;
|
||
if (command.isEdit) {
|
||
this.recordLastEdit(vim, inputState, command);
|
||
}
|
||
actions[command.action](cm, actionArgs, vim);
|
||
},
|
||
processSearch: function(cm, vim, command) {
|
||
if (!cm.getSearchCursor) {
|
||
// Search depends on SearchCursor.
|
||
return;
|
||
}
|
||
var forward = command.searchArgs.forward;
|
||
var wholeWordOnly = command.searchArgs.wholeWordOnly;
|
||
getSearchState(cm).setReversed(!forward);
|
||
var promptPrefix = (forward) ? '/' : '?';
|
||
var originalQuery = getSearchState(cm).getQuery();
|
||
var originalScrollPos = cm.getScrollInfo();
|
||
function handleQuery(query, ignoreCase, smartCase) {
|
||
vimGlobalState.searchHistoryController.pushInput(query);
|
||
vimGlobalState.searchHistoryController.reset();
|
||
try {
|
||
updateSearchQuery(cm, query, ignoreCase, smartCase);
|
||
} catch (e) {
|
||
showConfirm(cm, 'Invalid regex: ' + query);
|
||
clearInputState(cm);
|
||
return;
|
||
}
|
||
commandDispatcher.processMotion(cm, vim, {
|
||
type: 'motion',
|
||
motion: 'findNext',
|
||
motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist }
|
||
});
|
||
}
|
||
function onPromptClose(query) {
|
||
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
|
||
handleQuery(query, true /** ignoreCase */, true /** smartCase */);
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (macroModeState.isRecording) {
|
||
logSearchQuery(macroModeState, query);
|
||
}
|
||
}
|
||
function onPromptKeyUp(e, query, close) {
|
||
var keyName = CodeMirror.keyName(e), up, offset;
|
||
if (keyName == 'Up' || keyName == 'Down') {
|
||
up = keyName == 'Up' ? true : false;
|
||
offset = e.target ? e.target.selectionEnd : 0;
|
||
query = vimGlobalState.searchHistoryController.nextMatch(query, up) || '';
|
||
close(query);
|
||
if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length);
|
||
} else {
|
||
if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift')
|
||
vimGlobalState.searchHistoryController.reset();
|
||
}
|
||
var parsedQuery;
|
||
try {
|
||
parsedQuery = updateSearchQuery(cm, query,
|
||
true /** ignoreCase */, true /** smartCase */);
|
||
} catch (e) {
|
||
// Swallow bad regexes for incremental search.
|
||
}
|
||
if (parsedQuery) {
|
||
cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30);
|
||
} else {
|
||
clearSearchHighlight(cm);
|
||
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
|
||
}
|
||
}
|
||
function onPromptKeyDown(e, query, close) {
|
||
var keyName = CodeMirror.keyName(e);
|
||
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' ||
|
||
(keyName == 'Backspace' && query == '')) {
|
||
vimGlobalState.searchHistoryController.pushInput(query);
|
||
vimGlobalState.searchHistoryController.reset();
|
||
updateSearchQuery(cm, originalQuery);
|
||
clearSearchHighlight(cm);
|
||
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
|
||
CodeMirror.e_stop(e);
|
||
clearInputState(cm);
|
||
close();
|
||
cm.focus();
|
||
} else if (keyName == 'Up' || keyName == 'Down') {
|
||
CodeMirror.e_stop(e);
|
||
} else if (keyName == 'Ctrl-U') {
|
||
// Ctrl-U clears input.
|
||
CodeMirror.e_stop(e);
|
||
close('');
|
||
}
|
||
}
|
||
switch (command.searchArgs.querySrc) {
|
||
case 'prompt':
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (macroModeState.isPlaying) {
|
||
var query = macroModeState.replaySearchQueries.shift();
|
||
handleQuery(query, true /** ignoreCase */, false /** smartCase */);
|
||
} else {
|
||
showPrompt(cm, {
|
||
onClose: onPromptClose,
|
||
prefix: promptPrefix,
|
||
desc: searchPromptDesc,
|
||
onKeyUp: onPromptKeyUp,
|
||
onKeyDown: onPromptKeyDown
|
||
});
|
||
}
|
||
break;
|
||
case 'wordUnderCursor':
|
||
var word = expandWordUnderCursor(cm, false /** inclusive */,
|
||
true /** forward */, false /** bigWord */,
|
||
true /** noSymbol */);
|
||
var isKeyword = true;
|
||
if (!word) {
|
||
word = expandWordUnderCursor(cm, false /** inclusive */,
|
||
true /** forward */, false /** bigWord */,
|
||
false /** noSymbol */);
|
||
isKeyword = false;
|
||
}
|
||
if (!word) {
|
||
return;
|
||
}
|
||
var query = cm.getLine(word.start.line).substring(word.start.ch,
|
||
word.end.ch);
|
||
if (isKeyword && wholeWordOnly) {
|
||
query = '\\b' + query + '\\b';
|
||
} else {
|
||
query = escapeRegex(query);
|
||
}
|
||
|
||
// cachedCursor is used to save the old position of the cursor
|
||
// when * or # causes vim to seek for the nearest word and shift
|
||
// the cursor before entering the motion.
|
||
vimGlobalState.jumpList.cachedCursor = cm.getCursor();
|
||
cm.setCursor(word.start);
|
||
|
||
handleQuery(query, true /** ignoreCase */, false /** smartCase */);
|
||
break;
|
||
}
|
||
},
|
||
processEx: function(cm, vim, command) {
|
||
function onPromptClose(input) {
|
||
// Give the prompt some time to close so that if processCommand shows
|
||
// an error, the elements don't overlap.
|
||
vimGlobalState.exCommandHistoryController.pushInput(input);
|
||
vimGlobalState.exCommandHistoryController.reset();
|
||
exCommandDispatcher.processCommand(cm, input);
|
||
}
|
||
function onPromptKeyDown(e, input, close) {
|
||
var keyName = CodeMirror.keyName(e), up, offset;
|
||
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' ||
|
||
(keyName == 'Backspace' && input == '')) {
|
||
vimGlobalState.exCommandHistoryController.pushInput(input);
|
||
vimGlobalState.exCommandHistoryController.reset();
|
||
CodeMirror.e_stop(e);
|
||
clearInputState(cm);
|
||
close();
|
||
cm.focus();
|
||
}
|
||
if (keyName == 'Up' || keyName == 'Down') {
|
||
CodeMirror.e_stop(e);
|
||
up = keyName == 'Up' ? true : false;
|
||
offset = e.target ? e.target.selectionEnd : 0;
|
||
input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || '';
|
||
close(input);
|
||
if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length);
|
||
} else if (keyName == 'Ctrl-U') {
|
||
// Ctrl-U clears input.
|
||
CodeMirror.e_stop(e);
|
||
close('');
|
||
} else {
|
||
if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift')
|
||
vimGlobalState.exCommandHistoryController.reset();
|
||
}
|
||
}
|
||
if (command.type == 'keyToEx') {
|
||
// Handle user defined Ex to Ex mappings
|
||
exCommandDispatcher.processCommand(cm, command.exArgs.input);
|
||
} else {
|
||
if (vim.visualMode) {
|
||
showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
|
||
onKeyDown: onPromptKeyDown, selectValueOnOpen: false});
|
||
} else {
|
||
showPrompt(cm, { onClose: onPromptClose, prefix: ':',
|
||
onKeyDown: onPromptKeyDown});
|
||
}
|
||
}
|
||
},
|
||
evalInput: function(cm, vim) {
|
||
// If the motion command is set, execute both the operator and motion.
|
||
// Otherwise return.
|
||
var inputState = vim.inputState;
|
||
var motion = inputState.motion;
|
||
var motionArgs = inputState.motionArgs || {};
|
||
var operator = inputState.operator;
|
||
var operatorArgs = inputState.operatorArgs || {};
|
||
var registerName = inputState.registerName;
|
||
var sel = vim.sel;
|
||
// TODO: Make sure cm and vim selections are identical outside visual mode.
|
||
var origHead = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.head): cm.getCursor('head'));
|
||
var origAnchor = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.anchor) : cm.getCursor('anchor'));
|
||
var oldHead = copyCursor(origHead);
|
||
var oldAnchor = copyCursor(origAnchor);
|
||
var newHead, newAnchor;
|
||
var repeat;
|
||
if (operator) {
|
||
this.recordLastEdit(vim, inputState);
|
||
}
|
||
if (inputState.repeatOverride !== undefined) {
|
||
// If repeatOverride is specified, that takes precedence over the
|
||
// input state's repeat. Used by Ex mode and can be user defined.
|
||
repeat = inputState.repeatOverride;
|
||
} else {
|
||
repeat = inputState.getRepeat();
|
||
}
|
||
if (repeat > 0 && motionArgs.explicitRepeat) {
|
||
motionArgs.repeatIsExplicit = true;
|
||
} else if (motionArgs.noRepeat ||
|
||
(!motionArgs.explicitRepeat && repeat === 0)) {
|
||
repeat = 1;
|
||
motionArgs.repeatIsExplicit = false;
|
||
}
|
||
if (inputState.selectedCharacter) {
|
||
// If there is a character input, stick it in all of the arg arrays.
|
||
motionArgs.selectedCharacter = operatorArgs.selectedCharacter =
|
||
inputState.selectedCharacter;
|
||
}
|
||
motionArgs.repeat = repeat;
|
||
clearInputState(cm);
|
||
if (motion) {
|
||
var motionResult = motions[motion](cm, origHead, motionArgs, vim);
|
||
vim.lastMotion = motions[motion];
|
||
if (!motionResult) {
|
||
return;
|
||
}
|
||
if (motionArgs.toJumplist) {
|
||
var jumpList = vimGlobalState.jumpList;
|
||
// if the current motion is # or *, use cachedCursor
|
||
var cachedCursor = jumpList.cachedCursor;
|
||
if (cachedCursor) {
|
||
recordJumpPosition(cm, cachedCursor, motionResult);
|
||
delete jumpList.cachedCursor;
|
||
} else {
|
||
recordJumpPosition(cm, origHead, motionResult);
|
||
}
|
||
}
|
||
if (motionResult instanceof Array) {
|
||
newAnchor = motionResult[0];
|
||
newHead = motionResult[1];
|
||
} else {
|
||
newHead = motionResult;
|
||
}
|
||
// TODO: Handle null returns from motion commands better.
|
||
if (!newHead) {
|
||
newHead = copyCursor(origHead);
|
||
}
|
||
if (vim.visualMode) {
|
||
if (!(vim.visualBlock && newHead.ch === Infinity)) {
|
||
newHead = clipCursorToContent(cm, newHead);
|
||
}
|
||
if (newAnchor) {
|
||
newAnchor = clipCursorToContent(cm, newAnchor);
|
||
}
|
||
newAnchor = newAnchor || oldAnchor;
|
||
sel.anchor = newAnchor;
|
||
sel.head = newHead;
|
||
updateCmSelection(cm);
|
||
updateMark(cm, vim, '<',
|
||
cursorIsBefore(newAnchor, newHead) ? newAnchor
|
||
: newHead);
|
||
updateMark(cm, vim, '>',
|
||
cursorIsBefore(newAnchor, newHead) ? newHead
|
||
: newAnchor);
|
||
} else if (!operator) {
|
||
newHead = clipCursorToContent(cm, newHead);
|
||
cm.setCursor(newHead.line, newHead.ch);
|
||
}
|
||
}
|
||
if (operator) {
|
||
if (operatorArgs.lastSel) {
|
||
// Replaying a visual mode operation
|
||
newAnchor = oldAnchor;
|
||
var lastSel = operatorArgs.lastSel;
|
||
var lineOffset = Math.abs(lastSel.head.line - lastSel.anchor.line);
|
||
var chOffset = Math.abs(lastSel.head.ch - lastSel.anchor.ch);
|
||
if (lastSel.visualLine) {
|
||
// Linewise Visual mode: The same number of lines.
|
||
newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch);
|
||
} else if (lastSel.visualBlock) {
|
||
// Blockwise Visual mode: The same number of lines and columns.
|
||
newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset);
|
||
} else if (lastSel.head.line == lastSel.anchor.line) {
|
||
// Normal Visual mode within one line: The same number of characters.
|
||
newHead = Pos(oldAnchor.line, oldAnchor.ch + chOffset);
|
||
} else {
|
||
// Normal Visual mode with several lines: The same number of lines, in the
|
||
// last line the same number of characters as in the last line the last time.
|
||
newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch);
|
||
}
|
||
vim.visualMode = true;
|
||
vim.visualLine = lastSel.visualLine;
|
||
vim.visualBlock = lastSel.visualBlock;
|
||
sel = vim.sel = {
|
||
anchor: newAnchor,
|
||
head: newHead
|
||
};
|
||
updateCmSelection(cm);
|
||
} else if (vim.visualMode) {
|
||
operatorArgs.lastSel = {
|
||
anchor: copyCursor(sel.anchor),
|
||
head: copyCursor(sel.head),
|
||
visualBlock: vim.visualBlock,
|
||
visualLine: vim.visualLine
|
||
};
|
||
}
|
||
var curStart, curEnd, linewise, mode;
|
||
var cmSel;
|
||
if (vim.visualMode) {
|
||
// Init visual op
|
||
curStart = cursorMin(sel.head, sel.anchor);
|
||
curEnd = cursorMax(sel.head, sel.anchor);
|
||
linewise = vim.visualLine || operatorArgs.linewise;
|
||
mode = vim.visualBlock ? 'block' :
|
||
linewise ? 'line' :
|
||
'char';
|
||
cmSel = makeCmSelection(cm, {
|
||
anchor: curStart,
|
||
head: curEnd
|
||
}, mode);
|
||
if (linewise) {
|
||
var ranges = cmSel.ranges;
|
||
if (mode == 'block') {
|
||
// Linewise operators in visual block mode extend to end of line
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
ranges[i].head.ch = lineLength(cm, ranges[i].head.line);
|
||
}
|
||
} else if (mode == 'line') {
|
||
ranges[0].head = Pos(ranges[0].head.line + 1, 0);
|
||
}
|
||
}
|
||
} else {
|
||
// Init motion op
|
||
curStart = copyCursor(newAnchor || oldAnchor);
|
||
curEnd = copyCursor(newHead || oldHead);
|
||
if (cursorIsBefore(curEnd, curStart)) {
|
||
var tmp = curStart;
|
||
curStart = curEnd;
|
||
curEnd = tmp;
|
||
}
|
||
linewise = motionArgs.linewise || operatorArgs.linewise;
|
||
if (linewise) {
|
||
// Expand selection to entire line.
|
||
expandSelectionToLine(cm, curStart, curEnd);
|
||
} else if (motionArgs.forward) {
|
||
// Clip to trailing newlines only if the motion goes forward.
|
||
clipToLine(cm, curStart, curEnd);
|
||
}
|
||
mode = 'char';
|
||
var exclusive = !motionArgs.inclusive || linewise;
|
||
cmSel = makeCmSelection(cm, {
|
||
anchor: curStart,
|
||
head: curEnd
|
||
}, mode, exclusive);
|
||
}
|
||
cm.setSelections(cmSel.ranges, cmSel.primary);
|
||
vim.lastMotion = null;
|
||
operatorArgs.repeat = repeat; // For indent in visual mode.
|
||
operatorArgs.registerName = registerName;
|
||
// Keep track of linewise as it affects how paste and change behave.
|
||
operatorArgs.linewise = linewise;
|
||
var operatorMoveTo = operators[operator](
|
||
cm, operatorArgs, cmSel.ranges, oldAnchor, newHead);
|
||
if (vim.visualMode) {
|
||
exitVisualMode(cm, operatorMoveTo != null);
|
||
}
|
||
if (operatorMoveTo) {
|
||
cm.setCursor(operatorMoveTo);
|
||
}
|
||
}
|
||
},
|
||
recordLastEdit: function(vim, inputState, actionCommand) {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (macroModeState.isPlaying) { return; }
|
||
vim.lastEditInputState = inputState;
|
||
vim.lastEditActionCommand = actionCommand;
|
||
macroModeState.lastInsertModeChanges.changes = [];
|
||
macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false;
|
||
macroModeState.lastInsertModeChanges.visualBlock = vim.visualBlock ? vim.sel.head.line - vim.sel.anchor.line : 0;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* typedef {Object{line:number,ch:number}} Cursor An object containing the
|
||
* position of the cursor.
|
||
*/
|
||
// All of the functions below return Cursor objects.
|
||
var motions = {
|
||
moveToTopLine: function(cm, _head, motionArgs) {
|
||
var line = getUserVisibleLines(cm).top + motionArgs.repeat -1;
|
||
return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line)));
|
||
},
|
||
moveToMiddleLine: function(cm) {
|
||
var range = getUserVisibleLines(cm);
|
||
var line = Math.floor((range.top + range.bottom) * 0.5);
|
||
return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line)));
|
||
},
|
||
moveToBottomLine: function(cm, _head, motionArgs) {
|
||
var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1;
|
||
return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line)));
|
||
},
|
||
expandToLine: function(_cm, head, motionArgs) {
|
||
// Expands forward to end of line, and then to next line if repeat is
|
||
// >1. Does not handle backward motion!
|
||
var cur = head;
|
||
return Pos(cur.line + motionArgs.repeat - 1, Infinity);
|
||
},
|
||
findNext: function(cm, _head, motionArgs) {
|
||
var state = getSearchState(cm);
|
||
var query = state.getQuery();
|
||
if (!query) {
|
||
return;
|
||
}
|
||
var prev = !motionArgs.forward;
|
||
// If search is initiated with ? instead of /, negate direction.
|
||
prev = (state.isReversed()) ? !prev : prev;
|
||
highlightSearchMatches(cm, query);
|
||
return findNext(cm, prev/** prev */, query, motionArgs.repeat);
|
||
},
|
||
goToMark: function(cm, _head, motionArgs, vim) {
|
||
var pos = getMarkPos(cm, vim, motionArgs.selectedCharacter);
|
||
if (pos) {
|
||
return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos;
|
||
}
|
||
return null;
|
||
},
|
||
moveToOtherHighlightedEnd: function(cm, _head, motionArgs, vim) {
|
||
if (vim.visualBlock && motionArgs.sameLine) {
|
||
var sel = vim.sel;
|
||
return [
|
||
clipCursorToContent(cm, Pos(sel.anchor.line, sel.head.ch)),
|
||
clipCursorToContent(cm, Pos(sel.head.line, sel.anchor.ch))
|
||
];
|
||
} else {
|
||
return ([vim.sel.head, vim.sel.anchor]);
|
||
}
|
||
},
|
||
jumpToMark: function(cm, head, motionArgs, vim) {
|
||
var best = head;
|
||
for (var i = 0; i < motionArgs.repeat; i++) {
|
||
var cursor = best;
|
||
for (var key in vim.marks) {
|
||
if (!isLowerCase(key)) {
|
||
continue;
|
||
}
|
||
var mark = vim.marks[key].find();
|
||
var isWrongDirection = (motionArgs.forward) ?
|
||
cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark);
|
||
|
||
if (isWrongDirection) {
|
||
continue;
|
||
}
|
||
if (motionArgs.linewise && (mark.line == cursor.line)) {
|
||
continue;
|
||
}
|
||
|
||
var equal = cursorEqual(cursor, best);
|
||
var between = (motionArgs.forward) ?
|
||
cursorIsBetween(cursor, mark, best) :
|
||
cursorIsBetween(best, mark, cursor);
|
||
|
||
if (equal || between) {
|
||
best = mark;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (motionArgs.linewise) {
|
||
// Vim places the cursor on the first non-whitespace character of
|
||
// the line if there is one, else it places the cursor at the end
|
||
// of the line, regardless of whether a mark was found.
|
||
best = Pos(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line)));
|
||
}
|
||
return best;
|
||
},
|
||
moveByCharacters: function(_cm, head, motionArgs) {
|
||
var cur = head;
|
||
var repeat = motionArgs.repeat;
|
||
var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat;
|
||
return Pos(cur.line, ch);
|
||
},
|
||
moveByLines: function(cm, head, motionArgs, vim) {
|
||
var cur = head;
|
||
var endCh = cur.ch;
|
||
// Depending what our last motion was, we may want to do different
|
||
// things. If our last motion was moving vertically, we want to
|
||
// preserve the HPos from our last horizontal move. If our last motion
|
||
// was going to the end of a line, moving vertically we should go to
|
||
// the end of the line, etc.
|
||
switch (vim.lastMotion) {
|
||
case this.moveByLines:
|
||
case this.moveByDisplayLines:
|
||
case this.moveByScroll:
|
||
case this.moveToColumn:
|
||
case this.moveToEol:
|
||
endCh = vim.lastHPos;
|
||
break;
|
||
default:
|
||
vim.lastHPos = endCh;
|
||
}
|
||
var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);
|
||
var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
|
||
var first = cm.firstLine();
|
||
var last = cm.lastLine();
|
||
var posV = cm.findPosV(cur, (motionArgs.forward ? repeat : -repeat), 'line', vim.lastHSPos);
|
||
var hasMarkedText = motionArgs.forward ? posV.line > line : posV.line < line;
|
||
if (hasMarkedText) {
|
||
line = posV.line;
|
||
endCh = posV.ch;
|
||
}
|
||
// Vim go to line begin or line end when cursor at first/last line and
|
||
// move to previous/next line is triggered.
|
||
if (line < first && cur.line == first){
|
||
return this.moveToStartOfLine(cm, head, motionArgs, vim);
|
||
}else if (line > last && cur.line == last){
|
||
return this.moveToEol(cm, head, motionArgs, vim, true);
|
||
}
|
||
if (motionArgs.toFirstChar){
|
||
endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
|
||
vim.lastHPos = endCh;
|
||
}
|
||
vim.lastHSPos = cm.charCoords(Pos(line, endCh),'div').left;
|
||
return Pos(line, endCh);
|
||
},
|
||
moveByDisplayLines: function(cm, head, motionArgs, vim) {
|
||
var cur = head;
|
||
switch (vim.lastMotion) {
|
||
case this.moveByDisplayLines:
|
||
case this.moveByScroll:
|
||
case this.moveByLines:
|
||
case this.moveToColumn:
|
||
case this.moveToEol:
|
||
break;
|
||
default:
|
||
vim.lastHSPos = cm.charCoords(cur,'div').left;
|
||
}
|
||
var repeat = motionArgs.repeat;
|
||
var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos);
|
||
if (res.hitSide) {
|
||
if (motionArgs.forward) {
|
||
var lastCharCoords = cm.charCoords(res, 'div');
|
||
var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos };
|
||
var res = cm.coordsChar(goalCoords, 'div');
|
||
} else {
|
||
var resCoords = cm.charCoords(Pos(cm.firstLine(), 0), 'div');
|
||
resCoords.left = vim.lastHSPos;
|
||
res = cm.coordsChar(resCoords, 'div');
|
||
}
|
||
}
|
||
vim.lastHPos = res.ch;
|
||
return res;
|
||
},
|
||
moveByPage: function(cm, head, motionArgs) {
|
||
// CodeMirror only exposes functions that move the cursor page down, so
|
||
// doing this bad hack to move the cursor and move it back. evalInput
|
||
// will move the cursor to where it should be in the end.
|
||
var curStart = head;
|
||
var repeat = motionArgs.repeat;
|
||
return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page');
|
||
},
|
||
moveByParagraph: function(cm, head, motionArgs) {
|
||
var dir = motionArgs.forward ? 1 : -1;
|
||
return findParagraph(cm, head, motionArgs.repeat, dir);
|
||
},
|
||
moveBySentence: function(cm, head, motionArgs) {
|
||
var dir = motionArgs.forward ? 1 : -1;
|
||
return findSentence(cm, head, motionArgs.repeat, dir);
|
||
},
|
||
moveByScroll: function(cm, head, motionArgs, vim) {
|
||
var scrollbox = cm.getScrollInfo();
|
||
var curEnd = null;
|
||
var repeat = motionArgs.repeat;
|
||
if (!repeat) {
|
||
repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight());
|
||
}
|
||
var orig = cm.charCoords(head, 'local');
|
||
motionArgs.repeat = repeat;
|
||
var curEnd = motions.moveByDisplayLines(cm, head, motionArgs, vim);
|
||
if (!curEnd) {
|
||
return null;
|
||
}
|
||
var dest = cm.charCoords(curEnd, 'local');
|
||
cm.scrollTo(null, scrollbox.top + dest.top - orig.top);
|
||
return curEnd;
|
||
},
|
||
moveByWords: function(cm, head, motionArgs) {
|
||
return moveToWord(cm, head, motionArgs.repeat, !!motionArgs.forward,
|
||
!!motionArgs.wordEnd, !!motionArgs.bigWord);
|
||
},
|
||
moveTillCharacter: function(cm, _head, motionArgs) {
|
||
var repeat = motionArgs.repeat;
|
||
var curEnd = moveToCharacter(cm, repeat, motionArgs.forward,
|
||
motionArgs.selectedCharacter);
|
||
var increment = motionArgs.forward ? -1 : 1;
|
||
recordLastCharacterSearch(increment, motionArgs);
|
||
if (!curEnd) return null;
|
||
curEnd.ch += increment;
|
||
return curEnd;
|
||
},
|
||
moveToCharacter: function(cm, head, motionArgs) {
|
||
var repeat = motionArgs.repeat;
|
||
recordLastCharacterSearch(0, motionArgs);
|
||
return moveToCharacter(cm, repeat, motionArgs.forward,
|
||
motionArgs.selectedCharacter) || head;
|
||
},
|
||
moveToSymbol: function(cm, head, motionArgs) {
|
||
var repeat = motionArgs.repeat;
|
||
return findSymbol(cm, repeat, motionArgs.forward,
|
||
motionArgs.selectedCharacter) || head;
|
||
},
|
||
moveToColumn: function(cm, head, motionArgs, vim) {
|
||
var repeat = motionArgs.repeat;
|
||
// repeat is equivalent to which column we want to move to!
|
||
vim.lastHPos = repeat - 1;
|
||
vim.lastHSPos = cm.charCoords(head,'div').left;
|
||
return moveToColumn(cm, repeat);
|
||
},
|
||
moveToEol: function(cm, head, motionArgs, vim, keepHPos) {
|
||
var cur = head;
|
||
var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity);
|
||
var end=cm.clipPos(retval);
|
||
end.ch--;
|
||
if (!keepHPos) {
|
||
vim.lastHPos = Infinity;
|
||
vim.lastHSPos = cm.charCoords(end,'div').left;
|
||
}
|
||
return retval;
|
||
},
|
||
moveToFirstNonWhiteSpaceCharacter: function(cm, head) {
|
||
// Go to the start of the line where the text begins, or the end for
|
||
// whitespace-only lines
|
||
var cursor = head;
|
||
return Pos(cursor.line,
|
||
findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line)));
|
||
},
|
||
moveToMatchedSymbol: function(cm, head) {
|
||
var cursor = head;
|
||
var line = cursor.line;
|
||
var ch = cursor.ch;
|
||
var lineText = cm.getLine(line);
|
||
var symbol;
|
||
for (; ch < lineText.length; ch++) {
|
||
symbol = lineText.charAt(ch);
|
||
if (symbol && isMatchableSymbol(symbol)) {
|
||
var style = cm.getTokenTypeAt(Pos(line, ch + 1));
|
||
if (style !== "string" && style !== "comment") {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (ch < lineText.length) {
|
||
// Only include angle brackets in analysis if they are being matched.
|
||
var re = (ch === '<' || ch === '>') ? /[(){}[\]<>]/ : /[(){}[\]]/;
|
||
var matched = cm.findMatchingBracket(Pos(line, ch), {bracketRegex: re});
|
||
return matched.to;
|
||
} else {
|
||
return cursor;
|
||
}
|
||
},
|
||
moveToStartOfLine: function(_cm, head) {
|
||
return Pos(head.line, 0);
|
||
},
|
||
moveToLineOrEdgeOfDocument: function(cm, _head, motionArgs) {
|
||
var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine();
|
||
if (motionArgs.repeatIsExplicit) {
|
||
lineNum = motionArgs.repeat - cm.getOption('firstLineNumber');
|
||
}
|
||
return Pos(lineNum,
|
||
findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)));
|
||
},
|
||
textObjectManipulation: function(cm, head, motionArgs, vim) {
|
||
// TODO: lots of possible exceptions that can be thrown here. Try da(
|
||
// outside of a () block.
|
||
var mirroredPairs = {'(': ')', ')': '(',
|
||
'{': '}', '}': '{',
|
||
'[': ']', ']': '[',
|
||
'<': '>', '>': '<'};
|
||
var selfPaired = {'\'': true, '"': true, '`': true};
|
||
|
||
var character = motionArgs.selectedCharacter;
|
||
// 'b' refers to '()' block.
|
||
// 'B' refers to '{}' block.
|
||
if (character == 'b') {
|
||
character = '(';
|
||
} else if (character == 'B') {
|
||
character = '{';
|
||
}
|
||
|
||
// Inclusive is the difference between a and i
|
||
// TODO: Instead of using the additional text object map to perform text
|
||
// object operations, merge the map into the defaultKeyMap and use
|
||
// motionArgs to define behavior. Define separate entries for 'aw',
|
||
// 'iw', 'a[', 'i[', etc.
|
||
var inclusive = !motionArgs.textObjectInner;
|
||
|
||
var tmp;
|
||
if (mirroredPairs[character]) {
|
||
tmp = selectCompanionObject(cm, head, character, inclusive);
|
||
} else if (selfPaired[character]) {
|
||
tmp = findBeginningAndEnd(cm, head, character, inclusive);
|
||
} else if (character === 'W') {
|
||
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
||
true /** bigWord */);
|
||
} else if (character === 'w') {
|
||
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
||
false /** bigWord */);
|
||
} else if (character === 'p') {
|
||
tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive);
|
||
motionArgs.linewise = true;
|
||
if (vim.visualMode) {
|
||
if (!vim.visualLine) { vim.visualLine = true; }
|
||
} else {
|
||
var operatorArgs = vim.inputState.operatorArgs;
|
||
if (operatorArgs) { operatorArgs.linewise = true; }
|
||
tmp.end.line--;
|
||
}
|
||
} else {
|
||
// No text object defined for this, don't move.
|
||
return null;
|
||
}
|
||
|
||
if (!cm.state.vim.visualMode) {
|
||
return [tmp.start, tmp.end];
|
||
} else {
|
||
return expandSelection(cm, tmp.start, tmp.end);
|
||
}
|
||
},
|
||
|
||
repeatLastCharacterSearch: function(cm, head, motionArgs) {
|
||
var lastSearch = vimGlobalState.lastCharacterSearch;
|
||
var repeat = motionArgs.repeat;
|
||
var forward = motionArgs.forward === lastSearch.forward;
|
||
var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);
|
||
cm.moveH(-increment, 'char');
|
||
motionArgs.inclusive = forward ? true : false;
|
||
var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter);
|
||
if (!curEnd) {
|
||
cm.moveH(increment, 'char');
|
||
return head;
|
||
}
|
||
curEnd.ch += increment;
|
||
return curEnd;
|
||
}
|
||
};
|
||
|
||
function defineMotion(name, fn) {
|
||
motions[name] = fn;
|
||
}
|
||
|
||
function fillArray(val, times) {
|
||
var arr = [];
|
||
for (var i = 0; i < times; i++) {
|
||
arr.push(val);
|
||
}
|
||
return arr;
|
||
}
|
||
/**
|
||
* An operator acts on a text selection. It receives the list of selections
|
||
* as input. The corresponding CodeMirror selection is guaranteed to
|
||
* match the input selection.
|
||
*/
|
||
var operators = {
|
||
change: function(cm, args, ranges) {
|
||
var finalHead, text;
|
||
var vim = cm.state.vim;
|
||
var anchor = ranges[0].anchor,
|
||
head = ranges[0].head;
|
||
if (!vim.visualMode) {
|
||
text = cm.getRange(anchor, head);
|
||
var lastState = vim.lastEditInputState || {};
|
||
if (lastState.motion == "moveByWords" && !isWhiteSpaceString(text)) {
|
||
// Exclude trailing whitespace if the range is not all whitespace.
|
||
var match = (/\s+$/).exec(text);
|
||
if (match && lastState.motionArgs && lastState.motionArgs.forward) {
|
||
head = offsetCursor(head, 0, - match[0].length);
|
||
text = text.slice(0, - match[0].length);
|
||
}
|
||
}
|
||
var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE);
|
||
var wasLastLine = cm.firstLine() == cm.lastLine();
|
||
if (head.line > cm.lastLine() && args.linewise && !wasLastLine) {
|
||
cm.replaceRange('', prevLineEnd, head);
|
||
} else {
|
||
cm.replaceRange('', anchor, head);
|
||
}
|
||
if (args.linewise) {
|
||
// Push the next line back down, if there is a next line.
|
||
if (!wasLastLine) {
|
||
cm.setCursor(prevLineEnd);
|
||
CodeMirror.commands.newlineAndIndent(cm);
|
||
}
|
||
// make sure cursor ends up at the end of the line.
|
||
anchor.ch = Number.MAX_VALUE;
|
||
}
|
||
finalHead = anchor;
|
||
} else if (args.fullLine) {
|
||
head.ch = Number.MAX_VALUE;
|
||
head.line--;
|
||
cm.setSelection(anchor, head)
|
||
text = cm.getSelection();
|
||
cm.replaceSelection("");
|
||
finalHead = anchor;
|
||
} else {
|
||
text = cm.getSelection();
|
||
var replacement = fillArray('', ranges.length);
|
||
cm.replaceSelections(replacement);
|
||
finalHead = cursorMin(ranges[0].head, ranges[0].anchor);
|
||
}
|
||
vimGlobalState.registerController.pushText(
|
||
args.registerName, 'change', text,
|
||
args.linewise, ranges.length > 1);
|
||
actions.enterInsertMode(cm, {head: finalHead}, cm.state.vim);
|
||
},
|
||
// delete is a javascript keyword.
|
||
'delete': function(cm, args, ranges) {
|
||
var finalHead, text;
|
||
var vim = cm.state.vim;
|
||
if (!vim.visualBlock) {
|
||
var anchor = ranges[0].anchor,
|
||
head = ranges[0].head;
|
||
if (args.linewise &&
|
||
head.line != cm.firstLine() &&
|
||
anchor.line == cm.lastLine() &&
|
||
anchor.line == head.line - 1) {
|
||
// Special case for dd on last line (and first line).
|
||
if (anchor.line == cm.firstLine()) {
|
||
anchor.ch = 0;
|
||
} else {
|
||
anchor = Pos(anchor.line - 1, lineLength(cm, anchor.line - 1));
|
||
}
|
||
}
|
||
text = cm.getRange(anchor, head);
|
||
cm.replaceRange('', anchor, head);
|
||
finalHead = anchor;
|
||
if (args.linewise) {
|
||
finalHead = motions.moveToFirstNonWhiteSpaceCharacter(cm, anchor);
|
||
}
|
||
} else {
|
||
text = cm.getSelection();
|
||
var replacement = fillArray('', ranges.length);
|
||
cm.replaceSelections(replacement);
|
||
finalHead = ranges[0].anchor;
|
||
}
|
||
vimGlobalState.registerController.pushText(
|
||
args.registerName, 'delete', text,
|
||
args.linewise, vim.visualBlock);
|
||
return clipCursorToContent(cm, finalHead);
|
||
},
|
||
indent: function(cm, args, ranges) {
|
||
var vim = cm.state.vim;
|
||
var startLine = ranges[0].anchor.line;
|
||
var endLine = vim.visualBlock ?
|
||
ranges[ranges.length - 1].anchor.line :
|
||
ranges[0].head.line;
|
||
// In visual mode, n> shifts the selection right n times, instead of
|
||
// shifting n lines right once.
|
||
var repeat = (vim.visualMode) ? args.repeat : 1;
|
||
if (args.linewise) {
|
||
// The only way to delete a newline is to delete until the start of
|
||
// the next line, so in linewise mode evalInput will include the next
|
||
// line. We don't want this in indent, so we go back a line.
|
||
endLine--;
|
||
}
|
||
for (var i = startLine; i <= endLine; i++) {
|
||
for (var j = 0; j < repeat; j++) {
|
||
cm.indentLine(i, args.indentRight);
|
||
}
|
||
}
|
||
return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor);
|
||
},
|
||
indentAuto: function(cm, _args, ranges) {
|
||
cm.execCommand("indentAuto");
|
||
return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor);
|
||
},
|
||
changeCase: function(cm, args, ranges, oldAnchor, newHead) {
|
||
var selections = cm.getSelections();
|
||
var swapped = [];
|
||
var toLower = args.toLower;
|
||
for (var j = 0; j < selections.length; j++) {
|
||
var toSwap = selections[j];
|
||
var text = '';
|
||
if (toLower === true) {
|
||
text = toSwap.toLowerCase();
|
||
} else if (toLower === false) {
|
||
text = toSwap.toUpperCase();
|
||
} else {
|
||
for (var i = 0; i < toSwap.length; i++) {
|
||
var character = toSwap.charAt(i);
|
||
text += isUpperCase(character) ? character.toLowerCase() :
|
||
character.toUpperCase();
|
||
}
|
||
}
|
||
swapped.push(text);
|
||
}
|
||
cm.replaceSelections(swapped);
|
||
if (args.shouldMoveCursor){
|
||
return newHead;
|
||
} else if (!cm.state.vim.visualMode && args.linewise && ranges[0].anchor.line + 1 == ranges[0].head.line) {
|
||
return motions.moveToFirstNonWhiteSpaceCharacter(cm, oldAnchor);
|
||
} else if (args.linewise){
|
||
return oldAnchor;
|
||
} else {
|
||
return cursorMin(ranges[0].anchor, ranges[0].head);
|
||
}
|
||
},
|
||
yank: function(cm, args, ranges, oldAnchor) {
|
||
var vim = cm.state.vim;
|
||
var text = cm.getSelection();
|
||
var endPos = vim.visualMode
|
||
? cursorMin(vim.sel.anchor, vim.sel.head, ranges[0].head, ranges[0].anchor)
|
||
: oldAnchor;
|
||
vimGlobalState.registerController.pushText(
|
||
args.registerName, 'yank',
|
||
text, args.linewise, vim.visualBlock);
|
||
return endPos;
|
||
}
|
||
};
|
||
|
||
function defineOperator(name, fn) {
|
||
operators[name] = fn;
|
||
}
|
||
|
||
var actions = {
|
||
jumpListWalk: function(cm, actionArgs, vim) {
|
||
if (vim.visualMode) {
|
||
return;
|
||
}
|
||
var repeat = actionArgs.repeat;
|
||
var forward = actionArgs.forward;
|
||
var jumpList = vimGlobalState.jumpList;
|
||
|
||
var mark = jumpList.move(cm, forward ? repeat : -repeat);
|
||
var markPos = mark ? mark.find() : undefined;
|
||
markPos = markPos ? markPos : cm.getCursor();
|
||
cm.setCursor(markPos);
|
||
},
|
||
scroll: function(cm, actionArgs, vim) {
|
||
if (vim.visualMode) {
|
||
return;
|
||
}
|
||
var repeat = actionArgs.repeat || 1;
|
||
var lineHeight = cm.defaultTextHeight();
|
||
var top = cm.getScrollInfo().top;
|
||
var delta = lineHeight * repeat;
|
||
var newPos = actionArgs.forward ? top + delta : top - delta;
|
||
var cursor = copyCursor(cm.getCursor());
|
||
var cursorCoords = cm.charCoords(cursor, 'local');
|
||
if (actionArgs.forward) {
|
||
if (newPos > cursorCoords.top) {
|
||
cursor.line += (newPos - cursorCoords.top) / lineHeight;
|
||
cursor.line = Math.ceil(cursor.line);
|
||
cm.setCursor(cursor);
|
||
cursorCoords = cm.charCoords(cursor, 'local');
|
||
cm.scrollTo(null, cursorCoords.top);
|
||
} else {
|
||
// Cursor stays within bounds. Just reposition the scroll window.
|
||
cm.scrollTo(null, newPos);
|
||
}
|
||
} else {
|
||
var newBottom = newPos + cm.getScrollInfo().clientHeight;
|
||
if (newBottom < cursorCoords.bottom) {
|
||
cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight;
|
||
cursor.line = Math.floor(cursor.line);
|
||
cm.setCursor(cursor);
|
||
cursorCoords = cm.charCoords(cursor, 'local');
|
||
cm.scrollTo(
|
||
null, cursorCoords.bottom - cm.getScrollInfo().clientHeight);
|
||
} else {
|
||
// Cursor stays within bounds. Just reposition the scroll window.
|
||
cm.scrollTo(null, newPos);
|
||
}
|
||
}
|
||
},
|
||
scrollToCursor: function(cm, actionArgs) {
|
||
var lineNum = cm.getCursor().line;
|
||
var charCoords = cm.charCoords(Pos(lineNum, 0), 'local');
|
||
var height = cm.getScrollInfo().clientHeight;
|
||
var y = charCoords.top;
|
||
var lineHeight = charCoords.bottom - y;
|
||
switch (actionArgs.position) {
|
||
case 'center': y = y - (height / 2) + lineHeight;
|
||
break;
|
||
case 'bottom': y = y - height + lineHeight;
|
||
break;
|
||
}
|
||
cm.scrollTo(null, y);
|
||
},
|
||
replayMacro: function(cm, actionArgs, vim) {
|
||
var registerName = actionArgs.selectedCharacter;
|
||
var repeat = actionArgs.repeat;
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (registerName == '@') {
|
||
registerName = macroModeState.latestRegister;
|
||
} else {
|
||
macroModeState.latestRegister = registerName;
|
||
}
|
||
while(repeat--){
|
||
executeMacroRegister(cm, vim, macroModeState, registerName);
|
||
}
|
||
},
|
||
enterMacroRecordMode: function(cm, actionArgs) {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
var registerName = actionArgs.selectedCharacter;
|
||
if (vimGlobalState.registerController.isValidRegister(registerName)) {
|
||
macroModeState.enterMacroRecordMode(cm, registerName);
|
||
}
|
||
},
|
||
toggleOverwrite: function(cm) {
|
||
if (!cm.state.overwrite) {
|
||
cm.toggleOverwrite(true);
|
||
cm.setOption('keyMap', 'vim-replace');
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"});
|
||
} else {
|
||
cm.toggleOverwrite(false);
|
||
cm.setOption('keyMap', 'vim-insert');
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"});
|
||
}
|
||
},
|
||
enterInsertMode: function(cm, actionArgs, vim) {
|
||
if (cm.getOption('readOnly')) { return; }
|
||
vim.insertMode = true;
|
||
vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;
|
||
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
|
||
var sel = vim.sel;
|
||
var head = actionArgs.head || cm.getCursor('head');
|
||
var height = cm.listSelections().length;
|
||
if (insertAt == 'eol') {
|
||
head = Pos(head.line, lineLength(cm, head.line));
|
||
} else if (insertAt == 'bol') {
|
||
head = Pos(head.line, 0);
|
||
} else if (insertAt == 'charAfter') {
|
||
head = offsetCursor(head, 0, 1);
|
||
} else if (insertAt == 'firstNonBlank') {
|
||
head = motions.moveToFirstNonWhiteSpaceCharacter(cm, head);
|
||
} else if (insertAt == 'startOfSelectedArea') {
|
||
if (!vim.visualMode)
|
||
return;
|
||
if (!vim.visualBlock) {
|
||
if (sel.head.line < sel.anchor.line) {
|
||
head = sel.head;
|
||
} else {
|
||
head = Pos(sel.anchor.line, 0);
|
||
}
|
||
} else {
|
||
head = Pos(
|
||
Math.min(sel.head.line, sel.anchor.line),
|
||
Math.min(sel.head.ch, sel.anchor.ch));
|
||
height = Math.abs(sel.head.line - sel.anchor.line) + 1;
|
||
}
|
||
} else if (insertAt == 'endOfSelectedArea') {
|
||
if (!vim.visualMode)
|
||
return;
|
||
if (!vim.visualBlock) {
|
||
if (sel.head.line >= sel.anchor.line) {
|
||
head = offsetCursor(sel.head, 0, 1);
|
||
} else {
|
||
head = Pos(sel.anchor.line, 0);
|
||
}
|
||
} else {
|
||
head = Pos(
|
||
Math.min(sel.head.line, sel.anchor.line),
|
||
Math.max(sel.head.ch + 1, sel.anchor.ch));
|
||
height = Math.abs(sel.head.line - sel.anchor.line) + 1;
|
||
}
|
||
} else if (insertAt == 'inplace') {
|
||
if (vim.visualMode){
|
||
return;
|
||
}
|
||
} else if (insertAt == 'lastEdit') {
|
||
head = getLastEditPos(cm) || head;
|
||
}
|
||
cm.setOption('disableInput', false);
|
||
if (actionArgs && actionArgs.replace) {
|
||
// Handle Replace-mode as a special case of insert mode.
|
||
cm.toggleOverwrite(true);
|
||
cm.setOption('keyMap', 'vim-replace');
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"});
|
||
} else {
|
||
cm.toggleOverwrite(false);
|
||
cm.setOption('keyMap', 'vim-insert');
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"});
|
||
}
|
||
if (!vimGlobalState.macroModeState.isPlaying) {
|
||
// Only record if not replaying.
|
||
cm.on('change', onChange);
|
||
CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
|
||
}
|
||
if (vim.visualMode) {
|
||
exitVisualMode(cm);
|
||
}
|
||
selectForInsert(cm, head, height);
|
||
},
|
||
toggleVisualMode: function(cm, actionArgs, vim) {
|
||
var repeat = actionArgs.repeat;
|
||
var anchor = cm.getCursor();
|
||
var head;
|
||
// TODO: The repeat should actually select number of characters/lines
|
||
// equal to the repeat times the size of the previous visual
|
||
// operation.
|
||
if (!vim.visualMode) {
|
||
// Entering visual mode
|
||
vim.visualMode = true;
|
||
vim.visualLine = !!actionArgs.linewise;
|
||
vim.visualBlock = !!actionArgs.blockwise;
|
||
head = clipCursorToContent(
|
||
cm, Pos(anchor.line, anchor.ch + repeat - 1));
|
||
vim.sel = {
|
||
anchor: anchor,
|
||
head: head
|
||
};
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""});
|
||
updateCmSelection(cm);
|
||
updateMark(cm, vim, '<', cursorMin(anchor, head));
|
||
updateMark(cm, vim, '>', cursorMax(anchor, head));
|
||
} else if (vim.visualLine ^ actionArgs.linewise ||
|
||
vim.visualBlock ^ actionArgs.blockwise) {
|
||
// Toggling between modes
|
||
vim.visualLine = !!actionArgs.linewise;
|
||
vim.visualBlock = !!actionArgs.blockwise;
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""});
|
||
updateCmSelection(cm);
|
||
} else {
|
||
exitVisualMode(cm);
|
||
}
|
||
},
|
||
reselectLastSelection: function(cm, _actionArgs, vim) {
|
||
var lastSelection = vim.lastSelection;
|
||
if (vim.visualMode) {
|
||
updateLastSelection(cm, vim);
|
||
}
|
||
if (lastSelection) {
|
||
var anchor = lastSelection.anchorMark.find();
|
||
var head = lastSelection.headMark.find();
|
||
if (!anchor || !head) {
|
||
// If the marks have been destroyed due to edits, do nothing.
|
||
return;
|
||
}
|
||
vim.sel = {
|
||
anchor: anchor,
|
||
head: head
|
||
};
|
||
vim.visualMode = true;
|
||
vim.visualLine = lastSelection.visualLine;
|
||
vim.visualBlock = lastSelection.visualBlock;
|
||
updateCmSelection(cm);
|
||
updateMark(cm, vim, '<', cursorMin(anchor, head));
|
||
updateMark(cm, vim, '>', cursorMax(anchor, head));
|
||
CodeMirror.signal(cm, 'vim-mode-change', {
|
||
mode: 'visual',
|
||
subMode: vim.visualLine ? 'linewise' :
|
||
vim.visualBlock ? 'blockwise' : ''});
|
||
}
|
||
},
|
||
joinLines: function(cm, actionArgs, vim) {
|
||
var curStart, curEnd;
|
||
if (vim.visualMode) {
|
||
curStart = cm.getCursor('anchor');
|
||
curEnd = cm.getCursor('head');
|
||
if (cursorIsBefore(curEnd, curStart)) {
|
||
var tmp = curEnd;
|
||
curEnd = curStart;
|
||
curStart = tmp;
|
||
}
|
||
curEnd.ch = lineLength(cm, curEnd.line) - 1;
|
||
} else {
|
||
// Repeat is the number of lines to join. Minimum 2 lines.
|
||
var repeat = Math.max(actionArgs.repeat, 2);
|
||
curStart = cm.getCursor();
|
||
curEnd = clipCursorToContent(cm, Pos(curStart.line + repeat - 1,
|
||
Infinity));
|
||
}
|
||
var finalCh = 0;
|
||
for (var i = curStart.line; i < curEnd.line; i++) {
|
||
finalCh = lineLength(cm, curStart.line);
|
||
var tmp = Pos(curStart.line + 1,
|
||
lineLength(cm, curStart.line + 1));
|
||
var text = cm.getRange(curStart, tmp);
|
||
text = actionArgs.keepSpaces
|
||
? text.replace(/\n\r?/g, '')
|
||
: text.replace(/\n\s*/g, ' ');
|
||
cm.replaceRange(text, curStart, tmp);
|
||
}
|
||
var curFinalPos = Pos(curStart.line, finalCh);
|
||
if (vim.visualMode) {
|
||
exitVisualMode(cm, false);
|
||
}
|
||
cm.setCursor(curFinalPos);
|
||
},
|
||
newLineAndEnterInsertMode: function(cm, actionArgs, vim) {
|
||
vim.insertMode = true;
|
||
var insertAt = copyCursor(cm.getCursor());
|
||
if (insertAt.line === cm.firstLine() && !actionArgs.after) {
|
||
// Special case for inserting newline before start of document.
|
||
cm.replaceRange('\n', Pos(cm.firstLine(), 0));
|
||
cm.setCursor(cm.firstLine(), 0);
|
||
} else {
|
||
insertAt.line = (actionArgs.after) ? insertAt.line :
|
||
insertAt.line - 1;
|
||
insertAt.ch = lineLength(cm, insertAt.line);
|
||
cm.setCursor(insertAt);
|
||
var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment ||
|
||
CodeMirror.commands.newlineAndIndent;
|
||
newlineFn(cm);
|
||
}
|
||
this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim);
|
||
},
|
||
paste: function(cm, actionArgs, vim) {
|
||
var cur = copyCursor(cm.getCursor());
|
||
var register = vimGlobalState.registerController.getRegister(
|
||
actionArgs.registerName);
|
||
var text = register.toString();
|
||
if (!text) {
|
||
return;
|
||
}
|
||
if (actionArgs.matchIndent) {
|
||
var tabSize = cm.getOption("tabSize");
|
||
// length that considers tabs and tabSize
|
||
var whitespaceLength = function(str) {
|
||
var tabs = (str.split("\t").length - 1);
|
||
var spaces = (str.split(" ").length - 1);
|
||
return tabs * tabSize + spaces * 1;
|
||
};
|
||
var currentLine = cm.getLine(cm.getCursor().line);
|
||
var indent = whitespaceLength(currentLine.match(/^\s*/)[0]);
|
||
// chomp last newline b/c don't want it to match /^\s*/gm
|
||
var chompedText = text.replace(/\n$/, '');
|
||
var wasChomped = text !== chompedText;
|
||
var firstIndent = whitespaceLength(text.match(/^\s*/)[0]);
|
||
var text = chompedText.replace(/^\s*/gm, function(wspace) {
|
||
var newIndent = indent + (whitespaceLength(wspace) - firstIndent);
|
||
if (newIndent < 0) {
|
||
return "";
|
||
}
|
||
else if (cm.getOption("indentWithTabs")) {
|
||
var quotient = Math.floor(newIndent / tabSize);
|
||
return Array(quotient + 1).join('\t');
|
||
}
|
||
else {
|
||
return Array(newIndent + 1).join(' ');
|
||
}
|
||
});
|
||
text += wasChomped ? "\n" : "";
|
||
}
|
||
if (actionArgs.repeat > 1) {
|
||
var text = Array(actionArgs.repeat + 1).join(text);
|
||
}
|
||
var linewise = register.linewise;
|
||
var blockwise = register.blockwise;
|
||
if (blockwise) {
|
||
text = text.split('\n');
|
||
if (linewise) {
|
||
text.pop();
|
||
}
|
||
for (var i = 0; i < text.length; i++) {
|
||
text[i] = (text[i] == '') ? ' ' : text[i];
|
||
}
|
||
cur.ch += actionArgs.after ? 1 : 0;
|
||
cur.ch = Math.min(lineLength(cm, cur.line), cur.ch);
|
||
} else if (linewise) {
|
||
if(vim.visualMode) {
|
||
text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n';
|
||
} else if (actionArgs.after) {
|
||
// Move the newline at the end to the start instead, and paste just
|
||
// before the newline character of the line we are on right now.
|
||
text = '\n' + text.slice(0, text.length - 1);
|
||
cur.ch = lineLength(cm, cur.line);
|
||
} else {
|
||
cur.ch = 0;
|
||
}
|
||
} else {
|
||
cur.ch += actionArgs.after ? 1 : 0;
|
||
}
|
||
var curPosFinal;
|
||
var idx;
|
||
if (vim.visualMode) {
|
||
// save the pasted text for reselection if the need arises
|
||
vim.lastPastedText = text;
|
||
var lastSelectionCurEnd;
|
||
var selectedArea = getSelectedAreaRange(cm, vim);
|
||
var selectionStart = selectedArea[0];
|
||
var selectionEnd = selectedArea[1];
|
||
var selectedText = cm.getSelection();
|
||
var selections = cm.listSelections();
|
||
var emptyStrings = new Array(selections.length).join('1').split('1');
|
||
// save the curEnd marker before it get cleared due to cm.replaceRange.
|
||
if (vim.lastSelection) {
|
||
lastSelectionCurEnd = vim.lastSelection.headMark.find();
|
||
}
|
||
// push the previously selected text to unnamed register
|
||
vimGlobalState.registerController.unnamedRegister.setText(selectedText);
|
||
if (blockwise) {
|
||
// first delete the selected text
|
||
cm.replaceSelections(emptyStrings);
|
||
// Set new selections as per the block length of the yanked text
|
||
selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch);
|
||
cm.setCursor(selectionStart);
|
||
selectBlock(cm, selectionEnd);
|
||
cm.replaceSelections(text);
|
||
curPosFinal = selectionStart;
|
||
} else if (vim.visualBlock) {
|
||
cm.replaceSelections(emptyStrings);
|
||
cm.setCursor(selectionStart);
|
||
cm.replaceRange(text, selectionStart, selectionStart);
|
||
curPosFinal = selectionStart;
|
||
} else {
|
||
cm.replaceRange(text, selectionStart, selectionEnd);
|
||
curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1);
|
||
}
|
||
// restore the the curEnd marker
|
||
if(lastSelectionCurEnd) {
|
||
vim.lastSelection.headMark = cm.setBookmark(lastSelectionCurEnd);
|
||
}
|
||
if (linewise) {
|
||
curPosFinal.ch=0;
|
||
}
|
||
} else {
|
||
if (blockwise) {
|
||
cm.setCursor(cur);
|
||
for (var i = 0; i < text.length; i++) {
|
||
var line = cur.line+i;
|
||
if (line > cm.lastLine()) {
|
||
cm.replaceRange('\n', Pos(line, 0));
|
||
}
|
||
var lastCh = lineLength(cm, line);
|
||
if (lastCh < cur.ch) {
|
||
extendLineToColumn(cm, line, cur.ch);
|
||
}
|
||
}
|
||
cm.setCursor(cur);
|
||
selectBlock(cm, Pos(cur.line + text.length-1, cur.ch));
|
||
cm.replaceSelections(text);
|
||
curPosFinal = cur;
|
||
} else {
|
||
cm.replaceRange(text, cur);
|
||
// Now fine tune the cursor to where we want it.
|
||
if (linewise && actionArgs.after) {
|
||
curPosFinal = Pos(
|
||
cur.line + 1,
|
||
findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1)));
|
||
} else if (linewise && !actionArgs.after) {
|
||
curPosFinal = Pos(
|
||
cur.line,
|
||
findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line)));
|
||
} else if (!linewise && actionArgs.after) {
|
||
idx = cm.indexFromPos(cur);
|
||
curPosFinal = cm.posFromIndex(idx + text.length - 1);
|
||
} else {
|
||
idx = cm.indexFromPos(cur);
|
||
curPosFinal = cm.posFromIndex(idx + text.length);
|
||
}
|
||
}
|
||
}
|
||
if (vim.visualMode) {
|
||
exitVisualMode(cm, false);
|
||
}
|
||
cm.setCursor(curPosFinal);
|
||
},
|
||
undo: function(cm, actionArgs) {
|
||
cm.operation(function() {
|
||
repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)();
|
||
cm.setCursor(cm.getCursor('anchor'));
|
||
});
|
||
},
|
||
redo: function(cm, actionArgs) {
|
||
repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)();
|
||
},
|
||
setRegister: function(_cm, actionArgs, vim) {
|
||
vim.inputState.registerName = actionArgs.selectedCharacter;
|
||
},
|
||
setMark: function(cm, actionArgs, vim) {
|
||
var markName = actionArgs.selectedCharacter;
|
||
updateMark(cm, vim, markName, cm.getCursor());
|
||
},
|
||
replace: function(cm, actionArgs, vim) {
|
||
var replaceWith = actionArgs.selectedCharacter;
|
||
var curStart = cm.getCursor();
|
||
var replaceTo;
|
||
var curEnd;
|
||
var selections = cm.listSelections();
|
||
if (vim.visualMode) {
|
||
curStart = cm.getCursor('start');
|
||
curEnd = cm.getCursor('end');
|
||
} else {
|
||
var line = cm.getLine(curStart.line);
|
||
replaceTo = curStart.ch + actionArgs.repeat;
|
||
if (replaceTo > line.length) {
|
||
replaceTo=line.length;
|
||
}
|
||
curEnd = Pos(curStart.line, replaceTo);
|
||
}
|
||
if (replaceWith=='\n') {
|
||
if (!vim.visualMode) cm.replaceRange('', curStart, curEnd);
|
||
// special case, where vim help says to replace by just one line-break
|
||
(CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm);
|
||
} else {
|
||
var replaceWithStr = cm.getRange(curStart, curEnd);
|
||
//replace all characters in range by selected, but keep linebreaks
|
||
replaceWithStr = replaceWithStr.replace(/[^\n]/g, replaceWith);
|
||
if (vim.visualBlock) {
|
||
// Tabs are split in visua block before replacing
|
||
var spaces = new Array(cm.getOption("tabSize")+1).join(' ');
|
||
replaceWithStr = cm.getSelection();
|
||
replaceWithStr = replaceWithStr.replace(/\t/g, spaces).replace(/[^\n]/g, replaceWith).split('\n');
|
||
cm.replaceSelections(replaceWithStr);
|
||
} else {
|
||
cm.replaceRange(replaceWithStr, curStart, curEnd);
|
||
}
|
||
if (vim.visualMode) {
|
||
curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ?
|
||
selections[0].anchor : selections[0].head;
|
||
cm.setCursor(curStart);
|
||
exitVisualMode(cm, false);
|
||
} else {
|
||
cm.setCursor(offsetCursor(curEnd, 0, -1));
|
||
}
|
||
}
|
||
},
|
||
incrementNumberToken: function(cm, actionArgs) {
|
||
var cur = cm.getCursor();
|
||
var lineStr = cm.getLine(cur.line);
|
||
var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi;
|
||
var match;
|
||
var start;
|
||
var end;
|
||
var numberStr;
|
||
while ((match = re.exec(lineStr)) !== null) {
|
||
start = match.index;
|
||
end = start + match[0].length;
|
||
if (cur.ch < end)break;
|
||
}
|
||
if (!actionArgs.backtrack && (end <= cur.ch))return;
|
||
if (match) {
|
||
var baseStr = match[2] || match[4]
|
||
var digits = match[3] || match[5]
|
||
var increment = actionArgs.increase ? 1 : -1;
|
||
var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()];
|
||
var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat);
|
||
numberStr = number.toString(base);
|
||
var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : ''
|
||
if (numberStr.charAt(0) === '-') {
|
||
numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1);
|
||
} else {
|
||
numberStr = baseStr + zeroPadding + numberStr;
|
||
}
|
||
var from = Pos(cur.line, start);
|
||
var to = Pos(cur.line, end);
|
||
cm.replaceRange(numberStr, from, to);
|
||
} else {
|
||
return;
|
||
}
|
||
cm.setCursor(Pos(cur.line, start + numberStr.length - 1));
|
||
},
|
||
repeatLastEdit: function(cm, actionArgs, vim) {
|
||
var lastEditInputState = vim.lastEditInputState;
|
||
if (!lastEditInputState) { return; }
|
||
var repeat = actionArgs.repeat;
|
||
if (repeat && actionArgs.repeatIsExplicit) {
|
||
vim.lastEditInputState.repeatOverride = repeat;
|
||
} else {
|
||
repeat = vim.lastEditInputState.repeatOverride || repeat;
|
||
}
|
||
repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */);
|
||
},
|
||
indent: function(cm, actionArgs) {
|
||
cm.indentLine(cm.getCursor().line, actionArgs.indentRight);
|
||
},
|
||
exitInsertMode: exitInsertMode
|
||
};
|
||
|
||
function defineAction(name, fn) {
|
||
actions[name] = fn;
|
||
}
|
||
|
||
/*
|
||
* Below are miscellaneous utility functions used by vim.js
|
||
*/
|
||
|
||
/**
|
||
* Clips cursor to ensure that line is within the buffer's range
|
||
* If includeLineBreak is true, then allow cur.ch == lineLength.
|
||
*/
|
||
function clipCursorToContent(cm, cur) {
|
||
var vim = cm.state.vim;
|
||
var includeLineBreak = vim.insertMode || vim.visualMode;
|
||
var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() );
|
||
var maxCh = lineLength(cm, line) - 1 + !!includeLineBreak;
|
||
var ch = Math.min(Math.max(0, cur.ch), maxCh);
|
||
return Pos(line, ch);
|
||
}
|
||
function copyArgs(args) {
|
||
var ret = {};
|
||
for (var prop in args) {
|
||
if (args.hasOwnProperty(prop)) {
|
||
ret[prop] = args[prop];
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
function offsetCursor(cur, offsetLine, offsetCh) {
|
||
if (typeof offsetLine === 'object') {
|
||
offsetCh = offsetLine.ch;
|
||
offsetLine = offsetLine.line;
|
||
}
|
||
return Pos(cur.line + offsetLine, cur.ch + offsetCh);
|
||
}
|
||
function commandMatches(keys, keyMap, context, inputState) {
|
||
// Partial matches are not applied. They inform the key handler
|
||
// that the current key sequence is a subsequence of a valid key
|
||
// sequence, so that the key buffer is not cleared.
|
||
var match, partial = [], full = [];
|
||
for (var i = 0; i < keyMap.length; i++) {
|
||
var command = keyMap[i];
|
||
if (context == 'insert' && command.context != 'insert' ||
|
||
command.context && command.context != context ||
|
||
inputState.operator && command.type == 'action' ||
|
||
!(match = commandMatch(keys, command.keys))) { continue; }
|
||
if (match == 'partial') { partial.push(command); }
|
||
if (match == 'full') { full.push(command); }
|
||
}
|
||
return {
|
||
partial: partial.length && partial,
|
||
full: full.length && full
|
||
};
|
||
}
|
||
function commandMatch(pressed, mapped) {
|
||
if (mapped.slice(-11) == '<character>') {
|
||
// Last character matches anything.
|
||
var prefixLen = mapped.length - 11;
|
||
var pressedPrefix = pressed.slice(0, prefixLen);
|
||
var mappedPrefix = mapped.slice(0, prefixLen);
|
||
return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? 'full' :
|
||
mappedPrefix.indexOf(pressedPrefix) == 0 ? 'partial' : false;
|
||
} else {
|
||
return pressed == mapped ? 'full' :
|
||
mapped.indexOf(pressed) == 0 ? 'partial' : false;
|
||
}
|
||
}
|
||
function lastChar(keys) {
|
||
var match = /^.*(<[^>]+>)$/.exec(keys);
|
||
var selectedCharacter = match ? match[1] : keys.slice(-1);
|
||
if (selectedCharacter.length > 1){
|
||
switch(selectedCharacter){
|
||
case '<CR>':
|
||
selectedCharacter='\n';
|
||
break;
|
||
case '<Space>':
|
||
selectedCharacter=' ';
|
||
break;
|
||
default:
|
||
selectedCharacter='';
|
||
break;
|
||
}
|
||
}
|
||
return selectedCharacter;
|
||
}
|
||
function repeatFn(cm, fn, repeat) {
|
||
return function() {
|
||
for (var i = 0; i < repeat; i++) {
|
||
fn(cm);
|
||
}
|
||
};
|
||
}
|
||
function copyCursor(cur) {
|
||
return Pos(cur.line, cur.ch);
|
||
}
|
||
function cursorEqual(cur1, cur2) {
|
||
return cur1.ch == cur2.ch && cur1.line == cur2.line;
|
||
}
|
||
function cursorIsBefore(cur1, cur2) {
|
||
if (cur1.line < cur2.line) {
|
||
return true;
|
||
}
|
||
if (cur1.line == cur2.line && cur1.ch < cur2.ch) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
function cursorMin(cur1, cur2) {
|
||
if (arguments.length > 2) {
|
||
cur2 = cursorMin.apply(undefined, Array.prototype.slice.call(arguments, 1));
|
||
}
|
||
return cursorIsBefore(cur1, cur2) ? cur1 : cur2;
|
||
}
|
||
function cursorMax(cur1, cur2) {
|
||
if (arguments.length > 2) {
|
||
cur2 = cursorMax.apply(undefined, Array.prototype.slice.call(arguments, 1));
|
||
}
|
||
return cursorIsBefore(cur1, cur2) ? cur2 : cur1;
|
||
}
|
||
function cursorIsBetween(cur1, cur2, cur3) {
|
||
// returns true if cur2 is between cur1 and cur3.
|
||
var cur1before2 = cursorIsBefore(cur1, cur2);
|
||
var cur2before3 = cursorIsBefore(cur2, cur3);
|
||
return cur1before2 && cur2before3;
|
||
}
|
||
function lineLength(cm, lineNum) {
|
||
return cm.getLine(lineNum).length;
|
||
}
|
||
function trim(s) {
|
||
if (s.trim) {
|
||
return s.trim();
|
||
}
|
||
return s.replace(/^\s+|\s+$/g, '');
|
||
}
|
||
function escapeRegex(s) {
|
||
return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1');
|
||
}
|
||
function extendLineToColumn(cm, lineNum, column) {
|
||
var endCh = lineLength(cm, lineNum);
|
||
var spaces = new Array(column-endCh+1).join(' ');
|
||
cm.setCursor(Pos(lineNum, endCh));
|
||
cm.replaceRange(spaces, cm.getCursor());
|
||
}
|
||
// This functions selects a rectangular block
|
||
// of text with selectionEnd as any of its corner
|
||
// Height of block:
|
||
// Difference in selectionEnd.line and first/last selection.line
|
||
// Width of the block:
|
||
// Distance between selectionEnd.ch and any(first considered here) selection.ch
|
||
function selectBlock(cm, selectionEnd) {
|
||
var selections = [], ranges = cm.listSelections();
|
||
var head = copyCursor(cm.clipPos(selectionEnd));
|
||
var isClipped = !cursorEqual(selectionEnd, head);
|
||
var curHead = cm.getCursor('head');
|
||
var primIndex = getIndex(ranges, curHead);
|
||
var wasClipped = cursorEqual(ranges[primIndex].head, ranges[primIndex].anchor);
|
||
var max = ranges.length - 1;
|
||
var index = max - primIndex > primIndex ? max : 0;
|
||
var base = ranges[index].anchor;
|
||
|
||
var firstLine = Math.min(base.line, head.line);
|
||
var lastLine = Math.max(base.line, head.line);
|
||
var baseCh = base.ch, headCh = head.ch;
|
||
|
||
var dir = ranges[index].head.ch - baseCh;
|
||
var newDir = headCh - baseCh;
|
||
if (dir > 0 && newDir <= 0) {
|
||
baseCh++;
|
||
if (!isClipped) { headCh--; }
|
||
} else if (dir < 0 && newDir >= 0) {
|
||
baseCh--;
|
||
if (!wasClipped) { headCh++; }
|
||
} else if (dir < 0 && newDir == -1) {
|
||
baseCh--;
|
||
headCh++;
|
||
}
|
||
for (var line = firstLine; line <= lastLine; line++) {
|
||
var range = {anchor: new Pos(line, baseCh), head: new Pos(line, headCh)};
|
||
selections.push(range);
|
||
}
|
||
cm.setSelections(selections);
|
||
selectionEnd.ch = headCh;
|
||
base.ch = baseCh;
|
||
return base;
|
||
}
|
||
function selectForInsert(cm, head, height) {
|
||
var sel = [];
|
||
for (var i = 0; i < height; i++) {
|
||
var lineHead = offsetCursor(head, i, 0);
|
||
sel.push({anchor: lineHead, head: lineHead});
|
||
}
|
||
cm.setSelections(sel, 0);
|
||
}
|
||
// getIndex returns the index of the cursor in the selections.
|
||
function getIndex(ranges, cursor, end) {
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
var atAnchor = end != 'head' && cursorEqual(ranges[i].anchor, cursor);
|
||
var atHead = end != 'anchor' && cursorEqual(ranges[i].head, cursor);
|
||
if (atAnchor || atHead) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
function getSelectedAreaRange(cm, vim) {
|
||
var lastSelection = vim.lastSelection;
|
||
var getCurrentSelectedAreaRange = function() {
|
||
var selections = cm.listSelections();
|
||
var start = selections[0];
|
||
var end = selections[selections.length-1];
|
||
var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head;
|
||
var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;
|
||
return [selectionStart, selectionEnd];
|
||
};
|
||
var getLastSelectedAreaRange = function() {
|
||
var selectionStart = cm.getCursor();
|
||
var selectionEnd = cm.getCursor();
|
||
var block = lastSelection.visualBlock;
|
||
if (block) {
|
||
var width = block.width;
|
||
var height = block.height;
|
||
selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width);
|
||
var selections = [];
|
||
// selectBlock creates a 'proper' rectangular block.
|
||
// We do not want that in all cases, so we manually set selections.
|
||
for (var i = selectionStart.line; i < selectionEnd.line; i++) {
|
||
var anchor = Pos(i, selectionStart.ch);
|
||
var head = Pos(i, selectionEnd.ch);
|
||
var range = {anchor: anchor, head: head};
|
||
selections.push(range);
|
||
}
|
||
cm.setSelections(selections);
|
||
} else {
|
||
var start = lastSelection.anchorMark.find();
|
||
var end = lastSelection.headMark.find();
|
||
var line = end.line - start.line;
|
||
var ch = end.ch - start.ch;
|
||
selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch};
|
||
if (lastSelection.visualLine) {
|
||
selectionStart = Pos(selectionStart.line, 0);
|
||
selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line));
|
||
}
|
||
cm.setSelection(selectionStart, selectionEnd);
|
||
}
|
||
return [selectionStart, selectionEnd];
|
||
};
|
||
if (!vim.visualMode) {
|
||
// In case of replaying the action.
|
||
return getLastSelectedAreaRange();
|
||
} else {
|
||
return getCurrentSelectedAreaRange();
|
||
}
|
||
}
|
||
// Updates the previous selection with the current selection's values. This
|
||
// should only be called in visual mode.
|
||
function updateLastSelection(cm, vim) {
|
||
var anchor = vim.sel.anchor;
|
||
var head = vim.sel.head;
|
||
// To accommodate the effect of lastPastedText in the last selection
|
||
if (vim.lastPastedText) {
|
||
head = cm.posFromIndex(cm.indexFromPos(anchor) + vim.lastPastedText.length);
|
||
vim.lastPastedText = null;
|
||
}
|
||
vim.lastSelection = {'anchorMark': cm.setBookmark(anchor),
|
||
'headMark': cm.setBookmark(head),
|
||
'anchor': copyCursor(anchor),
|
||
'head': copyCursor(head),
|
||
'visualMode': vim.visualMode,
|
||
'visualLine': vim.visualLine,
|
||
'visualBlock': vim.visualBlock};
|
||
}
|
||
function expandSelection(cm, start, end) {
|
||
var sel = cm.state.vim.sel;
|
||
var head = sel.head;
|
||
var anchor = sel.anchor;
|
||
var tmp;
|
||
if (cursorIsBefore(end, start)) {
|
||
tmp = end;
|
||
end = start;
|
||
start = tmp;
|
||
}
|
||
if (cursorIsBefore(head, anchor)) {
|
||
head = cursorMin(start, head);
|
||
anchor = cursorMax(anchor, end);
|
||
} else {
|
||
anchor = cursorMin(start, anchor);
|
||
head = cursorMax(head, end);
|
||
head = offsetCursor(head, 0, -1);
|
||
if (head.ch == -1 && head.line != cm.firstLine()) {
|
||
head = Pos(head.line - 1, lineLength(cm, head.line - 1));
|
||
}
|
||
}
|
||
return [anchor, head];
|
||
}
|
||
/**
|
||
* Updates the CodeMirror selection to match the provided vim selection.
|
||
* If no arguments are given, it uses the current vim selection state.
|
||
*/
|
||
function updateCmSelection(cm, sel, mode) {
|
||
var vim = cm.state.vim;
|
||
sel = sel || vim.sel;
|
||
var mode = mode ||
|
||
vim.visualLine ? 'line' : vim.visualBlock ? 'block' : 'char';
|
||
var cmSel = makeCmSelection(cm, sel, mode);
|
||
cm.setSelections(cmSel.ranges, cmSel.primary);
|
||
updateFakeCursor(cm);
|
||
}
|
||
function makeCmSelection(cm, sel, mode, exclusive) {
|
||
var head = copyCursor(sel.head);
|
||
var anchor = copyCursor(sel.anchor);
|
||
if (mode == 'char') {
|
||
var headOffset = !exclusive && !cursorIsBefore(sel.head, sel.anchor) ? 1 : 0;
|
||
var anchorOffset = cursorIsBefore(sel.head, sel.anchor) ? 1 : 0;
|
||
head = offsetCursor(sel.head, 0, headOffset);
|
||
anchor = offsetCursor(sel.anchor, 0, anchorOffset);
|
||
return {
|
||
ranges: [{anchor: anchor, head: head}],
|
||
primary: 0
|
||
};
|
||
} else if (mode == 'line') {
|
||
if (!cursorIsBefore(sel.head, sel.anchor)) {
|
||
anchor.ch = 0;
|
||
|
||
var lastLine = cm.lastLine();
|
||
if (head.line > lastLine) {
|
||
head.line = lastLine;
|
||
}
|
||
head.ch = lineLength(cm, head.line);
|
||
} else {
|
||
head.ch = 0;
|
||
anchor.ch = lineLength(cm, anchor.line);
|
||
}
|
||
return {
|
||
ranges: [{anchor: anchor, head: head}],
|
||
primary: 0
|
||
};
|
||
} else if (mode == 'block') {
|
||
var top = Math.min(anchor.line, head.line),
|
||
left = Math.min(anchor.ch, head.ch),
|
||
bottom = Math.max(anchor.line, head.line),
|
||
right = Math.max(anchor.ch, head.ch) + 1;
|
||
var height = bottom - top + 1;
|
||
var primary = head.line == top ? 0 : height - 1;
|
||
var ranges = [];
|
||
for (var i = 0; i < height; i++) {
|
||
ranges.push({
|
||
anchor: Pos(top + i, left),
|
||
head: Pos(top + i, right)
|
||
});
|
||
}
|
||
return {
|
||
ranges: ranges,
|
||
primary: primary
|
||
};
|
||
}
|
||
}
|
||
function getHead(cm) {
|
||
var cur = cm.getCursor('head');
|
||
if (cm.getSelection().length == 1) {
|
||
// Small corner case when only 1 character is selected. The "real"
|
||
// head is the left of head and anchor.
|
||
cur = cursorMin(cur, cm.getCursor('anchor'));
|
||
}
|
||
return cur;
|
||
}
|
||
|
||
/**
|
||
* If moveHead is set to false, the CodeMirror selection will not be
|
||
* touched. The caller assumes the responsibility of putting the cursor
|
||
* in the right place.
|
||
*/
|
||
function exitVisualMode(cm, moveHead) {
|
||
var vim = cm.state.vim;
|
||
if (moveHead !== false) {
|
||
cm.setCursor(clipCursorToContent(cm, vim.sel.head));
|
||
}
|
||
updateLastSelection(cm, vim);
|
||
vim.visualMode = false;
|
||
vim.visualLine = false;
|
||
vim.visualBlock = false;
|
||
if (!vim.insertMode) CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||
clearFakeCursor(vim);
|
||
}
|
||
|
||
// Remove any trailing newlines from the selection. For
|
||
// example, with the caret at the start of the last word on the line,
|
||
// 'dw' should word, but not the newline, while 'w' should advance the
|
||
// caret to the first character of the next line.
|
||
function clipToLine(cm, curStart, curEnd) {
|
||
var selection = cm.getRange(curStart, curEnd);
|
||
// Only clip if the selection ends with trailing newline + whitespace
|
||
if (/\n\s*$/.test(selection)) {
|
||
var lines = selection.split('\n');
|
||
// We know this is all whitespace.
|
||
lines.pop();
|
||
|
||
// Cases:
|
||
// 1. Last word is an empty line - do not clip the trailing '\n'
|
||
// 2. Last word is not an empty line - clip the trailing '\n'
|
||
var line;
|
||
// Find the line containing the last word, and clip all whitespace up
|
||
// to it.
|
||
for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) {
|
||
curEnd.line--;
|
||
curEnd.ch = 0;
|
||
}
|
||
// If the last word is not an empty line, clip an additional newline
|
||
if (line) {
|
||
curEnd.line--;
|
||
curEnd.ch = lineLength(cm, curEnd.line);
|
||
} else {
|
||
curEnd.ch = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Expand the selection to line ends.
|
||
function expandSelectionToLine(_cm, curStart, curEnd) {
|
||
curStart.ch = 0;
|
||
curEnd.ch = 0;
|
||
curEnd.line++;
|
||
}
|
||
|
||
function findFirstNonWhiteSpaceCharacter(text) {
|
||
if (!text) {
|
||
return 0;
|
||
}
|
||
var firstNonWS = text.search(/\S/);
|
||
return firstNonWS == -1 ? text.length : firstNonWS;
|
||
}
|
||
|
||
function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) {
|
||
var cur = getHead(cm);
|
||
var line = cm.getLine(cur.line);
|
||
var idx = cur.ch;
|
||
|
||
// Seek to first word or non-whitespace character, depending on if
|
||
// noSymbol is true.
|
||
var test = noSymbol ? wordCharTest[0] : bigWordCharTest [0];
|
||
while (!test(line.charAt(idx))) {
|
||
idx++;
|
||
if (idx >= line.length) { return null; }
|
||
}
|
||
|
||
if (bigWord) {
|
||
test = bigWordCharTest[0];
|
||
} else {
|
||
test = wordCharTest[0];
|
||
if (!test(line.charAt(idx))) {
|
||
test = wordCharTest[1];
|
||
}
|
||
}
|
||
|
||
var end = idx, start = idx;
|
||
while (test(line.charAt(end)) && end < line.length) { end++; }
|
||
while (test(line.charAt(start)) && start >= 0) { start--; }
|
||
start++;
|
||
|
||
if (inclusive) {
|
||
// If present, include all whitespace after word.
|
||
// Otherwise, include all whitespace before word, except indentation.
|
||
var wordEnd = end;
|
||
while (/\s/.test(line.charAt(end)) && end < line.length) { end++; }
|
||
if (wordEnd == end) {
|
||
var wordStart = start;
|
||
while (/\s/.test(line.charAt(start - 1)) && start > 0) { start--; }
|
||
if (!start) { start = wordStart; }
|
||
}
|
||
}
|
||
return { start: Pos(cur.line, start), end: Pos(cur.line, end) };
|
||
}
|
||
|
||
function recordJumpPosition(cm, oldCur, newCur) {
|
||
if (!cursorEqual(oldCur, newCur)) {
|
||
vimGlobalState.jumpList.add(cm, oldCur, newCur);
|
||
}
|
||
}
|
||
|
||
function recordLastCharacterSearch(increment, args) {
|
||
vimGlobalState.lastCharacterSearch.increment = increment;
|
||
vimGlobalState.lastCharacterSearch.forward = args.forward;
|
||
vimGlobalState.lastCharacterSearch.selectedCharacter = args.selectedCharacter;
|
||
}
|
||
|
||
var symbolToMode = {
|
||
'(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket',
|
||
'[': 'section', ']': 'section',
|
||
'*': 'comment', '/': 'comment',
|
||
'm': 'method', 'M': 'method',
|
||
'#': 'preprocess'
|
||
};
|
||
var findSymbolModes = {
|
||
bracket: {
|
||
isComplete: function(state) {
|
||
if (state.nextCh === state.symb) {
|
||
state.depth++;
|
||
if (state.depth >= 1)return true;
|
||
} else if (state.nextCh === state.reverseSymb) {
|
||
state.depth--;
|
||
}
|
||
return false;
|
||
}
|
||
},
|
||
section: {
|
||
init: function(state) {
|
||
state.curMoveThrough = true;
|
||
state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}';
|
||
},
|
||
isComplete: function(state) {
|
||
return state.index === 0 && state.nextCh === state.symb;
|
||
}
|
||
},
|
||
comment: {
|
||
isComplete: function(state) {
|
||
var found = state.lastCh === '*' && state.nextCh === '/';
|
||
state.lastCh = state.nextCh;
|
||
return found;
|
||
}
|
||
},
|
||
// TODO: The original Vim implementation only operates on level 1 and 2.
|
||
// The current implementation doesn't check for code block level and
|
||
// therefore it operates on any levels.
|
||
method: {
|
||
init: function(state) {
|
||
state.symb = (state.symb === 'm' ? '{' : '}');
|
||
state.reverseSymb = state.symb === '{' ? '}' : '{';
|
||
},
|
||
isComplete: function(state) {
|
||
if (state.nextCh === state.symb)return true;
|
||
return false;
|
||
}
|
||
},
|
||
preprocess: {
|
||
init: function(state) {
|
||
state.index = 0;
|
||
},
|
||
isComplete: function(state) {
|
||
if (state.nextCh === '#') {
|
||
var token = state.lineText.match(/#(\w+)/)[1];
|
||
if (token === 'endif') {
|
||
if (state.forward && state.depth === 0) {
|
||
return true;
|
||
}
|
||
state.depth++;
|
||
} else if (token === 'if') {
|
||
if (!state.forward && state.depth === 0) {
|
||
return true;
|
||
}
|
||
state.depth--;
|
||
}
|
||
if (token === 'else' && state.depth === 0)return true;
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
};
|
||
function findSymbol(cm, repeat, forward, symb) {
|
||
var cur = copyCursor(cm.getCursor());
|
||
var increment = forward ? 1 : -1;
|
||
var endLine = forward ? cm.lineCount() : -1;
|
||
var curCh = cur.ch;
|
||
var line = cur.line;
|
||
var lineText = cm.getLine(line);
|
||
var state = {
|
||
lineText: lineText,
|
||
nextCh: lineText.charAt(curCh),
|
||
lastCh: null,
|
||
index: curCh,
|
||
symb: symb,
|
||
reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb],
|
||
forward: forward,
|
||
depth: 0,
|
||
curMoveThrough: false
|
||
};
|
||
var mode = symbolToMode[symb];
|
||
if (!mode)return cur;
|
||
var init = findSymbolModes[mode].init;
|
||
var isComplete = findSymbolModes[mode].isComplete;
|
||
if (init) { init(state); }
|
||
while (line !== endLine && repeat) {
|
||
state.index += increment;
|
||
state.nextCh = state.lineText.charAt(state.index);
|
||
if (!state.nextCh) {
|
||
line += increment;
|
||
state.lineText = cm.getLine(line) || '';
|
||
if (increment > 0) {
|
||
state.index = 0;
|
||
} else {
|
||
var lineLen = state.lineText.length;
|
||
state.index = (lineLen > 0) ? (lineLen-1) : 0;
|
||
}
|
||
state.nextCh = state.lineText.charAt(state.index);
|
||
}
|
||
if (isComplete(state)) {
|
||
cur.line = line;
|
||
cur.ch = state.index;
|
||
repeat--;
|
||
}
|
||
}
|
||
if (state.nextCh || state.curMoveThrough) {
|
||
return Pos(line, state.index);
|
||
}
|
||
return cur;
|
||
}
|
||
|
||
/*
|
||
* Returns the boundaries of the next word. If the cursor in the middle of
|
||
* the word, then returns the boundaries of the current word, starting at
|
||
* the cursor. If the cursor is at the start/end of a word, and we are going
|
||
* forward/backward, respectively, find the boundaries of the next word.
|
||
*
|
||
* @param {CodeMirror} cm CodeMirror object.
|
||
* @param {Cursor} cur The cursor position.
|
||
* @param {boolean} forward True to search forward. False to search
|
||
* backward.
|
||
* @param {boolean} bigWord True if punctuation count as part of the word.
|
||
* False if only [a-zA-Z0-9] characters count as part of the word.
|
||
* @param {boolean} emptyLineIsWord True if empty lines should be treated
|
||
* as words.
|
||
* @return {Object{from:number, to:number, line: number}} The boundaries of
|
||
* the word, or null if there are no more words.
|
||
*/
|
||
function findWord(cm, cur, forward, bigWord, emptyLineIsWord) {
|
||
var lineNum = cur.line;
|
||
var pos = cur.ch;
|
||
var line = cm.getLine(lineNum);
|
||
var dir = forward ? 1 : -1;
|
||
var charTests = bigWord ? bigWordCharTest: wordCharTest;
|
||
|
||
if (emptyLineIsWord && line == '') {
|
||
lineNum += dir;
|
||
line = cm.getLine(lineNum);
|
||
if (!isLine(cm, lineNum)) {
|
||
return null;
|
||
}
|
||
pos = (forward) ? 0 : line.length;
|
||
}
|
||
|
||
while (true) {
|
||
if (emptyLineIsWord && line == '') {
|
||
return { from: 0, to: 0, line: lineNum };
|
||
}
|
||
var stop = (dir > 0) ? line.length : -1;
|
||
var wordStart = stop, wordEnd = stop;
|
||
// Find bounds of next word.
|
||
while (pos != stop) {
|
||
var foundWord = false;
|
||
for (var i = 0; i < charTests.length && !foundWord; ++i) {
|
||
if (charTests[i](line.charAt(pos))) {
|
||
wordStart = pos;
|
||
// Advance to end of word.
|
||
while (pos != stop && charTests[i](line.charAt(pos))) {
|
||
pos += dir;
|
||
}
|
||
wordEnd = pos;
|
||
foundWord = wordStart != wordEnd;
|
||
if (wordStart == cur.ch && lineNum == cur.line &&
|
||
wordEnd == wordStart + dir) {
|
||
// We started at the end of a word. Find the next one.
|
||
continue;
|
||
} else {
|
||
return {
|
||
from: Math.min(wordStart, wordEnd + 1),
|
||
to: Math.max(wordStart, wordEnd),
|
||
line: lineNum };
|
||
}
|
||
}
|
||
}
|
||
if (!foundWord) {
|
||
pos += dir;
|
||
}
|
||
}
|
||
// Advance to next/prev line.
|
||
lineNum += dir;
|
||
if (!isLine(cm, lineNum)) {
|
||
return null;
|
||
}
|
||
line = cm.getLine(lineNum);
|
||
pos = (dir > 0) ? 0 : line.length;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @param {CodeMirror} cm CodeMirror object.
|
||
* @param {Pos} cur The position to start from.
|
||
* @param {int} repeat Number of words to move past.
|
||
* @param {boolean} forward True to search forward. False to search
|
||
* backward.
|
||
* @param {boolean} wordEnd True to move to end of word. False to move to
|
||
* beginning of word.
|
||
* @param {boolean} bigWord True if punctuation count as part of the word.
|
||
* False if only alphabet characters count as part of the word.
|
||
* @return {Cursor} The position the cursor should move to.
|
||
*/
|
||
function moveToWord(cm, cur, repeat, forward, wordEnd, bigWord) {
|
||
var curStart = copyCursor(cur);
|
||
var words = [];
|
||
if (forward && !wordEnd || !forward && wordEnd) {
|
||
repeat++;
|
||
}
|
||
// For 'e', empty lines are not considered words, go figure.
|
||
var emptyLineIsWord = !(forward && wordEnd);
|
||
for (var i = 0; i < repeat; i++) {
|
||
var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord);
|
||
if (!word) {
|
||
var eodCh = lineLength(cm, cm.lastLine());
|
||
words.push(forward
|
||
? {line: cm.lastLine(), from: eodCh, to: eodCh}
|
||
: {line: 0, from: 0, to: 0});
|
||
break;
|
||
}
|
||
words.push(word);
|
||
cur = Pos(word.line, forward ? (word.to - 1) : word.from);
|
||
}
|
||
var shortCircuit = words.length != repeat;
|
||
var firstWord = words[0];
|
||
var lastWord = words.pop();
|
||
if (forward && !wordEnd) {
|
||
// w
|
||
if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) {
|
||
// We did not start in the middle of a word. Discard the extra word at the end.
|
||
lastWord = words.pop();
|
||
}
|
||
return Pos(lastWord.line, lastWord.from);
|
||
} else if (forward && wordEnd) {
|
||
return Pos(lastWord.line, lastWord.to - 1);
|
||
} else if (!forward && wordEnd) {
|
||
// ge
|
||
if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) {
|
||
// We did not start in the middle of a word. Discard the extra word at the end.
|
||
lastWord = words.pop();
|
||
}
|
||
return Pos(lastWord.line, lastWord.to);
|
||
} else {
|
||
// b
|
||
return Pos(lastWord.line, lastWord.from);
|
||
}
|
||
}
|
||
|
||
function moveToCharacter(cm, repeat, forward, character) {
|
||
var cur = cm.getCursor();
|
||
var start = cur.ch;
|
||
var idx;
|
||
for (var i = 0; i < repeat; i ++) {
|
||
var line = cm.getLine(cur.line);
|
||
idx = charIdxInLine(start, line, character, forward, true);
|
||
if (idx == -1) {
|
||
return null;
|
||
}
|
||
start = idx;
|
||
}
|
||
return Pos(cm.getCursor().line, idx);
|
||
}
|
||
|
||
function moveToColumn(cm, repeat) {
|
||
// repeat is always >= 1, so repeat - 1 always corresponds
|
||
// to the column we want to go to.
|
||
var line = cm.getCursor().line;
|
||
return clipCursorToContent(cm, Pos(line, repeat - 1));
|
||
}
|
||
|
||
function updateMark(cm, vim, markName, pos) {
|
||
if (!inArray(markName, validMarks)) {
|
||
return;
|
||
}
|
||
if (vim.marks[markName]) {
|
||
vim.marks[markName].clear();
|
||
}
|
||
vim.marks[markName] = cm.setBookmark(pos);
|
||
}
|
||
|
||
function charIdxInLine(start, line, character, forward, includeChar) {
|
||
// Search for char in line.
|
||
// motion_options: {forward, includeChar}
|
||
// If includeChar = true, include it too.
|
||
// If forward = true, search forward, else search backwards.
|
||
// If char is not found on this line, do nothing
|
||
var idx;
|
||
if (forward) {
|
||
idx = line.indexOf(character, start + 1);
|
||
if (idx != -1 && !includeChar) {
|
||
idx -= 1;
|
||
}
|
||
} else {
|
||
idx = line.lastIndexOf(character, start - 1);
|
||
if (idx != -1 && !includeChar) {
|
||
idx += 1;
|
||
}
|
||
}
|
||
return idx;
|
||
}
|
||
|
||
function findParagraph(cm, head, repeat, dir, inclusive) {
|
||
var line = head.line;
|
||
var min = cm.firstLine();
|
||
var max = cm.lastLine();
|
||
var start, end, i = line;
|
||
function isEmpty(i) { return !cm.getLine(i); }
|
||
function isBoundary(i, dir, any) {
|
||
if (any) { return isEmpty(i) != isEmpty(i + dir); }
|
||
return !isEmpty(i) && isEmpty(i + dir);
|
||
}
|
||
if (dir) {
|
||
while (min <= i && i <= max && repeat > 0) {
|
||
if (isBoundary(i, dir)) { repeat--; }
|
||
i += dir;
|
||
}
|
||
return new Pos(i, 0);
|
||
}
|
||
|
||
var vim = cm.state.vim;
|
||
if (vim.visualLine && isBoundary(line, 1, true)) {
|
||
var anchor = vim.sel.anchor;
|
||
if (isBoundary(anchor.line, -1, true)) {
|
||
if (!inclusive || anchor.line != line) {
|
||
line += 1;
|
||
}
|
||
}
|
||
}
|
||
var startState = isEmpty(line);
|
||
for (i = line; i <= max && repeat; i++) {
|
||
if (isBoundary(i, 1, true)) {
|
||
if (!inclusive || isEmpty(i) != startState) {
|
||
repeat--;
|
||
}
|
||
}
|
||
}
|
||
end = new Pos(i, 0);
|
||
// select boundary before paragraph for the last one
|
||
if (i > max && !startState) { startState = true; }
|
||
else { inclusive = false; }
|
||
for (i = line; i > min; i--) {
|
||
if (!inclusive || isEmpty(i) == startState || i == line) {
|
||
if (isBoundary(i, -1, true)) { break; }
|
||
}
|
||
}
|
||
start = new Pos(i, 0);
|
||
return { start: start, end: end };
|
||
}
|
||
|
||
function findSentence(cm, cur, repeat, dir) {
|
||
|
||
/*
|
||
Takes an index object
|
||
{
|
||
line: the line string,
|
||
ln: line number,
|
||
pos: index in line,
|
||
dir: direction of traversal (-1 or 1)
|
||
}
|
||
and modifies the line, ln, and pos members to represent the
|
||
next valid position or sets them to null if there are
|
||
no more valid positions.
|
||
*/
|
||
function nextChar(cm, idx) {
|
||
if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) {
|
||
idx.ln += idx.dir;
|
||
if (!isLine(cm, idx.ln)) {
|
||
idx.line = null;
|
||
idx.ln = null;
|
||
idx.pos = null;
|
||
return;
|
||
}
|
||
idx.line = cm.getLine(idx.ln);
|
||
idx.pos = (idx.dir > 0) ? 0 : idx.line.length - 1;
|
||
}
|
||
else {
|
||
idx.pos += idx.dir;
|
||
}
|
||
}
|
||
|
||
/*
|
||
Performs one iteration of traversal in forward direction
|
||
Returns an index object of the new location
|
||
*/
|
||
function forward(cm, ln, pos, dir) {
|
||
var line = cm.getLine(ln);
|
||
var stop = (line === "");
|
||
|
||
var curr = {
|
||
line: line,
|
||
ln: ln,
|
||
pos: pos,
|
||
dir: dir,
|
||
}
|
||
|
||
var last_valid = {
|
||
ln: curr.ln,
|
||
pos: curr.pos,
|
||
}
|
||
|
||
var skip_empty_lines = (curr.line === "");
|
||
|
||
// Move one step to skip character we start on
|
||
nextChar(cm, curr);
|
||
|
||
while (curr.line !== null) {
|
||
last_valid.ln = curr.ln;
|
||
last_valid.pos = curr.pos;
|
||
|
||
if (curr.line === "" && !skip_empty_lines) {
|
||
return { ln: curr.ln, pos: curr.pos, };
|
||
}
|
||
else if (stop && curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) {
|
||
return { ln: curr.ln, pos: curr.pos, };
|
||
}
|
||
else if (isEndOfSentenceSymbol(curr.line[curr.pos])
|
||
&& !stop
|
||
&& (curr.pos === curr.line.length - 1
|
||
|| isWhiteSpaceString(curr.line[curr.pos + 1]))) {
|
||
stop = true;
|
||
}
|
||
|
||
nextChar(cm, curr);
|
||
}
|
||
|
||
/*
|
||
Set the position to the last non whitespace character on the last
|
||
valid line in the case that we reach the end of the document.
|
||
*/
|
||
var line = cm.getLine(last_valid.ln);
|
||
last_valid.pos = 0;
|
||
for(var i = line.length - 1; i >= 0; --i) {
|
||
if (!isWhiteSpaceString(line[i])) {
|
||
last_valid.pos = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return last_valid;
|
||
|
||
}
|
||
|
||
/*
|
||
Performs one iteration of traversal in reverse direction
|
||
Returns an index object of the new location
|
||
*/
|
||
function reverse(cm, ln, pos, dir) {
|
||
var line = cm.getLine(ln);
|
||
|
||
var curr = {
|
||
line: line,
|
||
ln: ln,
|
||
pos: pos,
|
||
dir: dir,
|
||
}
|
||
|
||
var last_valid = {
|
||
ln: curr.ln,
|
||
pos: null,
|
||
};
|
||
|
||
var skip_empty_lines = (curr.line === "");
|
||
|
||
// Move one step to skip character we start on
|
||
nextChar(cm, curr);
|
||
|
||
while (curr.line !== null) {
|
||
|
||
if (curr.line === "" && !skip_empty_lines) {
|
||
if (last_valid.pos !== null) {
|
||
return last_valid;
|
||
}
|
||
else {
|
||
return { ln: curr.ln, pos: curr.pos };
|
||
}
|
||
}
|
||
else if (isEndOfSentenceSymbol(curr.line[curr.pos])
|
||
&& last_valid.pos !== null
|
||
&& !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) {
|
||
return last_valid;
|
||
}
|
||
else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) {
|
||
skip_empty_lines = false;
|
||
last_valid = { ln: curr.ln, pos: curr.pos }
|
||
}
|
||
|
||
nextChar(cm, curr);
|
||
}
|
||
|
||
/*
|
||
Set the position to the first non whitespace character on the last
|
||
valid line in the case that we reach the beginning of the document.
|
||
*/
|
||
var line = cm.getLine(last_valid.ln);
|
||
last_valid.pos = 0;
|
||
for(var i = 0; i < line.length; ++i) {
|
||
if (!isWhiteSpaceString(line[i])) {
|
||
last_valid.pos = i;
|
||
break;
|
||
}
|
||
}
|
||
return last_valid;
|
||
}
|
||
|
||
var curr_index = {
|
||
ln: cur.line,
|
||
pos: cur.ch,
|
||
};
|
||
|
||
while (repeat > 0) {
|
||
if (dir < 0) {
|
||
curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir);
|
||
}
|
||
else {
|
||
curr_index = forward(cm, curr_index.ln, curr_index.pos, dir);
|
||
}
|
||
repeat--;
|
||
}
|
||
|
||
return Pos(curr_index.ln, curr_index.pos);
|
||
}
|
||
|
||
// TODO: perhaps this finagling of start and end positions belonds
|
||
// in codemirror/replaceRange?
|
||
function selectCompanionObject(cm, head, symb, inclusive) {
|
||
var cur = head, start, end;
|
||
|
||
var bracketRegexp = ({
|
||
'(': /[()]/, ')': /[()]/,
|
||
'[': /[[\]]/, ']': /[[\]]/,
|
||
'{': /[{}]/, '}': /[{}]/,
|
||
'<': /[<>]/, '>': /[<>]/})[symb];
|
||
var openSym = ({
|
||
'(': '(', ')': '(',
|
||
'[': '[', ']': '[',
|
||
'{': '{', '}': '{',
|
||
'<': '<', '>': '<'})[symb];
|
||
var curChar = cm.getLine(cur.line).charAt(cur.ch);
|
||
// Due to the behavior of scanForBracket, we need to add an offset if the
|
||
// cursor is on a matching open bracket.
|
||
var offset = curChar === openSym ? 1 : 0;
|
||
|
||
start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, undefined, {'bracketRegex': bracketRegexp});
|
||
end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, undefined, {'bracketRegex': bracketRegexp});
|
||
|
||
if (!start || !end) {
|
||
return { start: cur, end: cur };
|
||
}
|
||
|
||
start = start.pos;
|
||
end = end.pos;
|
||
|
||
if ((start.line == end.line && start.ch > end.ch)
|
||
|| (start.line > end.line)) {
|
||
var tmp = start;
|
||
start = end;
|
||
end = tmp;
|
||
}
|
||
|
||
if (inclusive) {
|
||
end.ch += 1;
|
||
} else {
|
||
start.ch += 1;
|
||
}
|
||
|
||
return { start: start, end: end };
|
||
}
|
||
|
||
// Takes in a symbol and a cursor and tries to simulate text objects that
|
||
// have identical opening and closing symbols
|
||
// TODO support across multiple lines
|
||
function findBeginningAndEnd(cm, head, symb, inclusive) {
|
||
var cur = copyCursor(head);
|
||
var line = cm.getLine(cur.line);
|
||
var chars = line.split('');
|
||
var start, end, i, len;
|
||
var firstIndex = chars.indexOf(symb);
|
||
|
||
// the decision tree is to always look backwards for the beginning first,
|
||
// but if the cursor is in front of the first instance of the symb,
|
||
// then move the cursor forward
|
||
if (cur.ch < firstIndex) {
|
||
cur.ch = firstIndex;
|
||
// Why is this line even here???
|
||
// cm.setCursor(cur.line, firstIndex+1);
|
||
}
|
||
// otherwise if the cursor is currently on the closing symbol
|
||
else if (firstIndex < cur.ch && chars[cur.ch] == symb) {
|
||
end = cur.ch; // assign end to the current cursor
|
||
--cur.ch; // make sure to look backwards
|
||
}
|
||
|
||
// if we're currently on the symbol, we've got a start
|
||
if (chars[cur.ch] == symb && !end) {
|
||
start = cur.ch + 1; // assign start to ahead of the cursor
|
||
} else {
|
||
// go backwards to find the start
|
||
for (i = cur.ch; i > -1 && !start; i--) {
|
||
if (chars[i] == symb) {
|
||
start = i + 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// look forwards for the end symbol
|
||
if (start && !end) {
|
||
for (i = start, len = chars.length; i < len && !end; i++) {
|
||
if (chars[i] == symb) {
|
||
end = i;
|
||
}
|
||
}
|
||
}
|
||
|
||
// nothing found
|
||
if (!start || !end) {
|
||
return { start: cur, end: cur };
|
||
}
|
||
|
||
// include the symbols
|
||
if (inclusive) {
|
||
--start; ++end;
|
||
}
|
||
|
||
return {
|
||
start: Pos(cur.line, start),
|
||
end: Pos(cur.line, end)
|
||
};
|
||
}
|
||
|
||
// Search functions
|
||
defineOption('pcre', true, 'boolean');
|
||
function SearchState() {}
|
||
SearchState.prototype = {
|
||
getQuery: function() {
|
||
return vimGlobalState.query;
|
||
},
|
||
setQuery: function(query) {
|
||
vimGlobalState.query = query;
|
||
},
|
||
getOverlay: function() {
|
||
return this.searchOverlay;
|
||
},
|
||
setOverlay: function(overlay) {
|
||
this.searchOverlay = overlay;
|
||
},
|
||
isReversed: function() {
|
||
return vimGlobalState.isReversed;
|
||
},
|
||
setReversed: function(reversed) {
|
||
vimGlobalState.isReversed = reversed;
|
||
},
|
||
getScrollbarAnnotate: function() {
|
||
return this.annotate;
|
||
},
|
||
setScrollbarAnnotate: function(annotate) {
|
||
this.annotate = annotate;
|
||
}
|
||
};
|
||
function getSearchState(cm) {
|
||
var vim = cm.state.vim;
|
||
return vim.searchState_ || (vim.searchState_ = new SearchState());
|
||
}
|
||
function dialog(cm, template, shortText, onClose, options) {
|
||
if (cm.openDialog) {
|
||
cm.openDialog(template, onClose, { bottom: true, value: options.value,
|
||
onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp,
|
||
selectValueOnOpen: false});
|
||
}
|
||
else {
|
||
onClose(prompt(shortText, ''));
|
||
}
|
||
}
|
||
function splitBySlash(argString) {
|
||
return splitBySeparator(argString, '/');
|
||
}
|
||
|
||
function findUnescapedSlashes(argString) {
|
||
return findUnescapedSeparators(argString, '/');
|
||
}
|
||
|
||
function splitBySeparator(argString, separator) {
|
||
var slashes = findUnescapedSeparators(argString, separator) || [];
|
||
if (!slashes.length) return [];
|
||
var tokens = [];
|
||
// in case of strings like foo/bar
|
||
if (slashes[0] !== 0) return;
|
||
for (var i = 0; i < slashes.length; i++) {
|
||
if (typeof slashes[i] == 'number')
|
||
tokens.push(argString.substring(slashes[i] + 1, slashes[i+1]));
|
||
}
|
||
return tokens;
|
||
}
|
||
|
||
function findUnescapedSeparators(str, separator) {
|
||
if (!separator)
|
||
separator = '/';
|
||
|
||
var escapeNextChar = false;
|
||
var slashes = [];
|
||
for (var i = 0; i < str.length; i++) {
|
||
var c = str.charAt(i);
|
||
if (!escapeNextChar && c == separator) {
|
||
slashes.push(i);
|
||
}
|
||
escapeNextChar = !escapeNextChar && (c == '\\');
|
||
}
|
||
return slashes;
|
||
}
|
||
|
||
// Translates a search string from ex (vim) syntax into javascript form.
|
||
function translateRegex(str) {
|
||
// When these match, add a '\' if unescaped or remove one if escaped.
|
||
var specials = '|(){';
|
||
// Remove, but never add, a '\' for these.
|
||
var unescape = '}';
|
||
var escapeNextChar = false;
|
||
var out = [];
|
||
for (var i = -1; i < str.length; i++) {
|
||
var c = str.charAt(i) || '';
|
||
var n = str.charAt(i+1) || '';
|
||
var specialComesNext = (n && specials.indexOf(n) != -1);
|
||
if (escapeNextChar) {
|
||
if (c !== '\\' || !specialComesNext) {
|
||
out.push(c);
|
||
}
|
||
escapeNextChar = false;
|
||
} else {
|
||
if (c === '\\') {
|
||
escapeNextChar = true;
|
||
// Treat the unescape list as special for removing, but not adding '\'.
|
||
if (n && unescape.indexOf(n) != -1) {
|
||
specialComesNext = true;
|
||
}
|
||
// Not passing this test means removing a '\'.
|
||
if (!specialComesNext || n === '\\') {
|
||
out.push(c);
|
||
}
|
||
} else {
|
||
out.push(c);
|
||
if (specialComesNext && n !== '\\') {
|
||
out.push('\\');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return out.join('');
|
||
}
|
||
|
||
// Translates the replace part of a search and replace from ex (vim) syntax into
|
||
// javascript form. Similar to translateRegex, but additionally fixes back references
|
||
// (translates '\[0..9]' to '$[0..9]') and follows different rules for escaping '$'.
|
||
var charUnescapes = {'\\n': '\n', '\\r': '\r', '\\t': '\t'};
|
||
function translateRegexReplace(str) {
|
||
var escapeNextChar = false;
|
||
var out = [];
|
||
for (var i = -1; i < str.length; i++) {
|
||
var c = str.charAt(i) || '';
|
||
var n = str.charAt(i+1) || '';
|
||
if (charUnescapes[c + n]) {
|
||
out.push(charUnescapes[c+n]);
|
||
i++;
|
||
} else if (escapeNextChar) {
|
||
// At any point in the loop, escapeNextChar is true if the previous
|
||
// character was a '\' and was not escaped.
|
||
out.push(c);
|
||
escapeNextChar = false;
|
||
} else {
|
||
if (c === '\\') {
|
||
escapeNextChar = true;
|
||
if ((isNumber(n) || n === '$')) {
|
||
out.push('$');
|
||
} else if (n !== '/' && n !== '\\') {
|
||
out.push('\\');
|
||
}
|
||
} else {
|
||
if (c === '$') {
|
||
out.push('$');
|
||
}
|
||
out.push(c);
|
||
if (n === '/') {
|
||
out.push('\\');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return out.join('');
|
||
}
|
||
|
||
// Unescape \ and / in the replace part, for PCRE mode.
|
||
var unescapes = {'\\/': '/', '\\\\': '\\', '\\n': '\n', '\\r': '\r', '\\t': '\t', '\\&':'&'};
|
||
function unescapeRegexReplace(str) {
|
||
var stream = new CodeMirror.StringStream(str);
|
||
var output = [];
|
||
while (!stream.eol()) {
|
||
// Search for \.
|
||
while (stream.peek() && stream.peek() != '\\') {
|
||
output.push(stream.next());
|
||
}
|
||
var matched = false;
|
||
for (var matcher in unescapes) {
|
||
if (stream.match(matcher, true)) {
|
||
matched = true;
|
||
output.push(unescapes[matcher]);
|
||
break;
|
||
}
|
||
}
|
||
if (!matched) {
|
||
// Don't change anything
|
||
output.push(stream.next());
|
||
}
|
||
}
|
||
return output.join('');
|
||
}
|
||
|
||
/**
|
||
* Extract the regular expression from the query and return a Regexp object.
|
||
* Returns null if the query is blank.
|
||
* If ignoreCase is passed in, the Regexp object will have the 'i' flag set.
|
||
* If smartCase is passed in, and the query contains upper case letters,
|
||
* then ignoreCase is overridden, and the 'i' flag will not be set.
|
||
* If the query contains the /i in the flag part of the regular expression,
|
||
* then both ignoreCase and smartCase are ignored, and 'i' will be passed
|
||
* through to the Regex object.
|
||
*/
|
||
function parseQuery(query, ignoreCase, smartCase) {
|
||
// First update the last search register
|
||
var lastSearchRegister = vimGlobalState.registerController.getRegister('/');
|
||
lastSearchRegister.setText(query);
|
||
// Check if the query is already a regex.
|
||
if (query instanceof RegExp) { return query; }
|
||
// First try to extract regex + flags from the input. If no flags found,
|
||
// extract just the regex. IE does not accept flags directly defined in
|
||
// the regex string in the form /regex/flags
|
||
var slashes = findUnescapedSlashes(query);
|
||
var regexPart;
|
||
var forceIgnoreCase;
|
||
if (!slashes.length) {
|
||
// Query looks like 'regexp'
|
||
regexPart = query;
|
||
} else {
|
||
// Query looks like 'regexp/...'
|
||
regexPart = query.substring(0, slashes[0]);
|
||
var flagsPart = query.substring(slashes[0]);
|
||
forceIgnoreCase = (flagsPart.indexOf('i') != -1);
|
||
}
|
||
if (!regexPart) {
|
||
return null;
|
||
}
|
||
if (!getOption('pcre')) {
|
||
regexPart = translateRegex(regexPart);
|
||
}
|
||
if (smartCase) {
|
||
ignoreCase = (/^[^A-Z]*$/).test(regexPart);
|
||
}
|
||
var regexp = new RegExp(regexPart,
|
||
(ignoreCase || forceIgnoreCase) ? 'i' : undefined);
|
||
return regexp;
|
||
}
|
||
function showConfirm(cm, text) {
|
||
if (cm.openNotification) {
|
||
cm.openNotification('<span style="color: red">' + text + '</span>',
|
||
{bottom: true, duration: 5000});
|
||
} else {
|
||
alert(text);
|
||
}
|
||
}
|
||
function makePrompt(prefix, desc) {
|
||
var raw = '<span style="font-family: monospace; white-space: pre">' +
|
||
(prefix || "") + '<input type="text" autocorrect="off" ' +
|
||
'autocapitalize="off" spellcheck="false"></span>';
|
||
if (desc)
|
||
raw += ' <span style="color: #888">' + desc + '</span>';
|
||
return raw;
|
||
}
|
||
var searchPromptDesc = '(Javascript regexp)';
|
||
function showPrompt(cm, options) {
|
||
var shortText = (options.prefix || '') + ' ' + (options.desc || '');
|
||
var prompt = makePrompt(options.prefix, options.desc);
|
||
dialog(cm, prompt, shortText, options.onClose, options);
|
||
}
|
||
function regexEqual(r1, r2) {
|
||
if (r1 instanceof RegExp && r2 instanceof RegExp) {
|
||
var props = ['global', 'multiline', 'ignoreCase', 'source'];
|
||
for (var i = 0; i < props.length; i++) {
|
||
var prop = props[i];
|
||
if (r1[prop] !== r2[prop]) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
// Returns true if the query is valid.
|
||
function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) {
|
||
if (!rawQuery) {
|
||
return;
|
||
}
|
||
var state = getSearchState(cm);
|
||
var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase);
|
||
if (!query) {
|
||
return;
|
||
}
|
||
highlightSearchMatches(cm, query);
|
||
if (regexEqual(query, state.getQuery())) {
|
||
return query;
|
||
}
|
||
state.setQuery(query);
|
||
return query;
|
||
}
|
||
function searchOverlay(query) {
|
||
if (query.source.charAt(0) == '^') {
|
||
var matchSol = true;
|
||
}
|
||
return {
|
||
token: function(stream) {
|
||
if (matchSol && !stream.sol()) {
|
||
stream.skipToEnd();
|
||
return;
|
||
}
|
||
var match = stream.match(query, false);
|
||
if (match) {
|
||
if (match[0].length == 0) {
|
||
// Matched empty string, skip to next.
|
||
stream.next();
|
||
return 'searching';
|
||
}
|
||
if (!stream.sol()) {
|
||
// Backtrack 1 to match \b
|
||
stream.backUp(1);
|
||
if (!query.exec(stream.next() + match[0])) {
|
||
stream.next();
|
||
return null;
|
||
}
|
||
}
|
||
stream.match(query);
|
||
return 'searching';
|
||
}
|
||
while (!stream.eol()) {
|
||
stream.next();
|
||
if (stream.match(query, false)) break;
|
||
}
|
||
},
|
||
query: query
|
||
};
|
||
}
|
||
var highlightTimeout = 0;
|
||
function highlightSearchMatches(cm, query) {
|
||
clearTimeout(highlightTimeout);
|
||
highlightTimeout = setTimeout(function() {
|
||
var searchState = getSearchState(cm);
|
||
var overlay = searchState.getOverlay();
|
||
if (!overlay || query != overlay.query) {
|
||
if (overlay) {
|
||
cm.removeOverlay(overlay);
|
||
}
|
||
overlay = searchOverlay(query);
|
||
cm.addOverlay(overlay);
|
||
if (cm.showMatchesOnScrollbar) {
|
||
if (searchState.getScrollbarAnnotate()) {
|
||
searchState.getScrollbarAnnotate().clear();
|
||
}
|
||
searchState.setScrollbarAnnotate(cm.showMatchesOnScrollbar(query));
|
||
}
|
||
searchState.setOverlay(overlay);
|
||
}
|
||
}, 50);
|
||
}
|
||
function findNext(cm, prev, query, repeat) {
|
||
if (repeat === undefined) { repeat = 1; }
|
||
return cm.operation(function() {
|
||
var pos = cm.getCursor();
|
||
var cursor = cm.getSearchCursor(query, pos);
|
||
for (var i = 0; i < repeat; i++) {
|
||
var found = cursor.find(prev);
|
||
if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); }
|
||
if (!found) {
|
||
// SearchCursor may have returned null because it hit EOF, wrap
|
||
// around and try again.
|
||
cursor = cm.getSearchCursor(query,
|
||
(prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) );
|
||
if (!cursor.find(prev)) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
return cursor.from();
|
||
});
|
||
}
|
||
function clearSearchHighlight(cm) {
|
||
var state = getSearchState(cm);
|
||
cm.removeOverlay(getSearchState(cm).getOverlay());
|
||
state.setOverlay(null);
|
||
if (state.getScrollbarAnnotate()) {
|
||
state.getScrollbarAnnotate().clear();
|
||
state.setScrollbarAnnotate(null);
|
||
}
|
||
}
|
||
/**
|
||
* Check if pos is in the specified range, INCLUSIVE.
|
||
* Range can be specified with 1 or 2 arguments.
|
||
* If the first range argument is an array, treat it as an array of line
|
||
* numbers. Match pos against any of the lines.
|
||
* If the first range argument is a number,
|
||
* if there is only 1 range argument, check if pos has the same line
|
||
* number
|
||
* if there are 2 range arguments, then check if pos is in between the two
|
||
* range arguments.
|
||
*/
|
||
function isInRange(pos, start, end) {
|
||
if (typeof pos != 'number') {
|
||
// Assume it is a cursor position. Get the line number.
|
||
pos = pos.line;
|
||
}
|
||
if (start instanceof Array) {
|
||
return inArray(pos, start);
|
||
} else {
|
||
if (end) {
|
||
return (pos >= start && pos <= end);
|
||
} else {
|
||
return pos == start;
|
||
}
|
||
}
|
||
}
|
||
function getUserVisibleLines(cm) {
|
||
var scrollInfo = cm.getScrollInfo();
|
||
var occludeToleranceTop = 6;
|
||
var occludeToleranceBottom = 10;
|
||
var from = cm.coordsChar({left:0, top: occludeToleranceTop + scrollInfo.top}, 'local');
|
||
var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top;
|
||
var to = cm.coordsChar({left:0, top: bottomY}, 'local');
|
||
return {top: from.line, bottom: to.line};
|
||
}
|
||
|
||
function getMarkPos(cm, vim, markName) {
|
||
if (markName == '\'' || markName == '`') {
|
||
return vimGlobalState.jumpList.find(cm, -1) || Pos(0, 0);
|
||
} else if (markName == '.') {
|
||
return getLastEditPos(cm);
|
||
}
|
||
|
||
var mark = vim.marks[markName];
|
||
return mark && mark.find();
|
||
}
|
||
|
||
function getLastEditPos(cm) {
|
||
var done = cm.doc.history.done;
|
||
for (var i = done.length; i--;) {
|
||
if (done[i].changes) {
|
||
return copyCursor(done[i].changes[0].to);
|
||
}
|
||
}
|
||
}
|
||
|
||
var ExCommandDispatcher = function() {
|
||
this.buildCommandMap_();
|
||
};
|
||
ExCommandDispatcher.prototype = {
|
||
processCommand: function(cm, input, opt_params) {
|
||
var that = this;
|
||
cm.operation(function () {
|
||
cm.curOp.isVimOp = true;
|
||
that._processCommand(cm, input, opt_params);
|
||
});
|
||
},
|
||
_processCommand: function(cm, input, opt_params) {
|
||
var vim = cm.state.vim;
|
||
var commandHistoryRegister = vimGlobalState.registerController.getRegister(':');
|
||
var previousCommand = commandHistoryRegister.toString();
|
||
if (vim.visualMode) {
|
||
exitVisualMode(cm);
|
||
}
|
||
var inputStream = new CodeMirror.StringStream(input);
|
||
// update ": with the latest command whether valid or invalid
|
||
commandHistoryRegister.setText(input);
|
||
var params = opt_params || {};
|
||
params.input = input;
|
||
try {
|
||
this.parseInput_(cm, inputStream, params);
|
||
} catch(e) {
|
||
showConfirm(cm, e);
|
||
throw e;
|
||
}
|
||
var command;
|
||
var commandName;
|
||
if (!params.commandName) {
|
||
// If only a line range is defined, move to the line.
|
||
if (params.line !== undefined) {
|
||
commandName = 'move';
|
||
}
|
||
} else {
|
||
command = this.matchCommand_(params.commandName);
|
||
if (command) {
|
||
commandName = command.name;
|
||
if (command.excludeFromCommandHistory) {
|
||
commandHistoryRegister.setText(previousCommand);
|
||
}
|
||
this.parseCommandArgs_(inputStream, params, command);
|
||
if (command.type == 'exToKey') {
|
||
// Handle Ex to Key mapping.
|
||
for (var i = 0; i < command.toKeys.length; i++) {
|
||
CodeMirror.Vim.handleKey(cm, command.toKeys[i], 'mapping');
|
||
}
|
||
return;
|
||
} else if (command.type == 'exToEx') {
|
||
// Handle Ex to Ex mapping.
|
||
this.processCommand(cm, command.toInput);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
if (!commandName) {
|
||
showConfirm(cm, 'Not an editor command ":' + input + '"');
|
||
return;
|
||
}
|
||
try {
|
||
exCommands[commandName](cm, params);
|
||
// Possibly asynchronous commands (e.g. substitute, which might have a
|
||
// user confirmation), are responsible for calling the callback when
|
||
// done. All others have it taken care of for them here.
|
||
if ((!command || !command.possiblyAsync) && params.callback) {
|
||
params.callback();
|
||
}
|
||
} catch(e) {
|
||
showConfirm(cm, e);
|
||
throw e;
|
||
}
|
||
},
|
||
parseInput_: function(cm, inputStream, result) {
|
||
inputStream.eatWhile(':');
|
||
// Parse range.
|
||
if (inputStream.eat('%')) {
|
||
result.line = cm.firstLine();
|
||
result.lineEnd = cm.lastLine();
|
||
} else {
|
||
result.line = this.parseLineSpec_(cm, inputStream);
|
||
if (result.line !== undefined && inputStream.eat(',')) {
|
||
result.lineEnd = this.parseLineSpec_(cm, inputStream);
|
||
}
|
||
}
|
||
|
||
// Parse command name.
|
||
var commandMatch = inputStream.match(/^(\w+|!!|@@|[!#&*<=>@~])/);
|
||
if (commandMatch) {
|
||
result.commandName = commandMatch[1];
|
||
} else {
|
||
result.commandName = inputStream.match(/.*/)[0];
|
||
}
|
||
|
||
return result;
|
||
},
|
||
parseLineSpec_: function(cm, inputStream) {
|
||
var numberMatch = inputStream.match(/^(\d+)/);
|
||
if (numberMatch) {
|
||
// Absolute line number plus offset (N+M or N-M) is probably a typo,
|
||
// not something the user actually wanted. (NB: vim does allow this.)
|
||
return parseInt(numberMatch[1], 10) - 1;
|
||
}
|
||
switch (inputStream.next()) {
|
||
case '.':
|
||
return this.parseLineSpecOffset_(inputStream, cm.getCursor().line);
|
||
case '$':
|
||
return this.parseLineSpecOffset_(inputStream, cm.lastLine());
|
||
case '\'':
|
||
var markName = inputStream.next();
|
||
var markPos = getMarkPos(cm, cm.state.vim, markName);
|
||
if (!markPos) throw new Error('Mark not set');
|
||
return this.parseLineSpecOffset_(inputStream, markPos.line);
|
||
case '-':
|
||
case '+':
|
||
inputStream.backUp(1);
|
||
// Offset is relative to current line if not otherwise specified.
|
||
return this.parseLineSpecOffset_(inputStream, cm.getCursor().line);
|
||
default:
|
||
inputStream.backUp(1);
|
||
return undefined;
|
||
}
|
||
},
|
||
parseLineSpecOffset_: function(inputStream, line) {
|
||
var offsetMatch = inputStream.match(/^([+-])?(\d+)/);
|
||
if (offsetMatch) {
|
||
var offset = parseInt(offsetMatch[2], 10);
|
||
if (offsetMatch[1] == "-") {
|
||
line -= offset;
|
||
} else {
|
||
line += offset;
|
||
}
|
||
}
|
||
return line;
|
||
},
|
||
parseCommandArgs_: function(inputStream, params, command) {
|
||
if (inputStream.eol()) {
|
||
return;
|
||
}
|
||
params.argString = inputStream.match(/.*/)[0];
|
||
// Parse command-line arguments
|
||
var delim = command.argDelimiter || /\s+/;
|
||
var args = trim(params.argString).split(delim);
|
||
if (args.length && args[0]) {
|
||
params.args = args;
|
||
}
|
||
},
|
||
matchCommand_: function(commandName) {
|
||
// Return the command in the command map that matches the shortest
|
||
// prefix of the passed in command name. The match is guaranteed to be
|
||
// unambiguous if the defaultExCommandMap's shortNames are set up
|
||
// correctly. (see @code{defaultExCommandMap}).
|
||
for (var i = commandName.length; i > 0; i--) {
|
||
var prefix = commandName.substring(0, i);
|
||
if (this.commandMap_[prefix]) {
|
||
var command = this.commandMap_[prefix];
|
||
if (command.name.indexOf(commandName) === 0) {
|
||
return command;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
},
|
||
buildCommandMap_: function() {
|
||
this.commandMap_ = {};
|
||
for (var i = 0; i < defaultExCommandMap.length; i++) {
|
||
var command = defaultExCommandMap[i];
|
||
var key = command.shortName || command.name;
|
||
this.commandMap_[key] = command;
|
||
}
|
||
},
|
||
map: function(lhs, rhs, ctx) {
|
||
if (lhs != ':' && lhs.charAt(0) == ':') {
|
||
if (ctx) { throw Error('Mode not supported for ex mappings'); }
|
||
var commandName = lhs.substring(1);
|
||
if (rhs != ':' && rhs.charAt(0) == ':') {
|
||
// Ex to Ex mapping
|
||
this.commandMap_[commandName] = {
|
||
name: commandName,
|
||
type: 'exToEx',
|
||
toInput: rhs.substring(1),
|
||
user: true
|
||
};
|
||
} else {
|
||
// Ex to key mapping
|
||
this.commandMap_[commandName] = {
|
||
name: commandName,
|
||
type: 'exToKey',
|
||
toKeys: rhs,
|
||
user: true
|
||
};
|
||
}
|
||
} else {
|
||
if (rhs != ':' && rhs.charAt(0) == ':') {
|
||
// Key to Ex mapping.
|
||
var mapping = {
|
||
keys: lhs,
|
||
type: 'keyToEx',
|
||
exArgs: { input: rhs.substring(1) }
|
||
};
|
||
if (ctx) { mapping.context = ctx; }
|
||
defaultKeymap.unshift(mapping);
|
||
} else {
|
||
// Key to key mapping
|
||
var mapping = {
|
||
keys: lhs,
|
||
type: 'keyToKey',
|
||
toKeys: rhs
|
||
};
|
||
if (ctx) { mapping.context = ctx; }
|
||
defaultKeymap.unshift(mapping);
|
||
}
|
||
}
|
||
},
|
||
unmap: function(lhs, ctx) {
|
||
if (lhs != ':' && lhs.charAt(0) == ':') {
|
||
// Ex to Ex or Ex to key mapping
|
||
if (ctx) { throw Error('Mode not supported for ex mappings'); }
|
||
var commandName = lhs.substring(1);
|
||
if (this.commandMap_[commandName] && this.commandMap_[commandName].user) {
|
||
delete this.commandMap_[commandName];
|
||
return;
|
||
}
|
||
} else {
|
||
// Key to Ex or key to key mapping
|
||
var keys = lhs;
|
||
for (var i = 0; i < defaultKeymap.length; i++) {
|
||
if (keys == defaultKeymap[i].keys
|
||
&& defaultKeymap[i].context === ctx) {
|
||
defaultKeymap.splice(i, 1);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
throw Error('No such mapping.');
|
||
}
|
||
};
|
||
|
||
var exCommands = {
|
||
colorscheme: function(cm, params) {
|
||
if (!params.args || params.args.length < 1) {
|
||
showConfirm(cm, cm.getOption('theme'));
|
||
return;
|
||
}
|
||
cm.setOption('theme', params.args[0]);
|
||
},
|
||
map: function(cm, params, ctx) {
|
||
var mapArgs = params.args;
|
||
if (!mapArgs || mapArgs.length < 2) {
|
||
if (cm) {
|
||
showConfirm(cm, 'Invalid mapping: ' + params.input);
|
||
}
|
||
return;
|
||
}
|
||
exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx);
|
||
},
|
||
imap: function(cm, params) { this.map(cm, params, 'insert'); },
|
||
nmap: function(cm, params) { this.map(cm, params, 'normal'); },
|
||
vmap: function(cm, params) { this.map(cm, params, 'visual'); },
|
||
unmap: function(cm, params, ctx) {
|
||
var mapArgs = params.args;
|
||
if (!mapArgs || mapArgs.length < 1) {
|
||
if (cm) {
|
||
showConfirm(cm, 'No such mapping: ' + params.input);
|
||
}
|
||
return;
|
||
}
|
||
exCommandDispatcher.unmap(mapArgs[0], ctx);
|
||
},
|
||
move: function(cm, params) {
|
||
commandDispatcher.processCommand(cm, cm.state.vim, {
|
||
type: 'motion',
|
||
motion: 'moveToLineOrEdgeOfDocument',
|
||
motionArgs: { forward: false, explicitRepeat: true,
|
||
linewise: true },
|
||
repeatOverride: params.line+1});
|
||
},
|
||
set: function(cm, params) {
|
||
var setArgs = params.args;
|
||
// Options passed through to the setOption/getOption calls. May be passed in by the
|
||
// local/global versions of the set command
|
||
var setCfg = params.setCfg || {};
|
||
if (!setArgs || setArgs.length < 1) {
|
||
if (cm) {
|
||
showConfirm(cm, 'Invalid mapping: ' + params.input);
|
||
}
|
||
return;
|
||
}
|
||
var expr = setArgs[0].split('=');
|
||
var optionName = expr[0];
|
||
var value = expr[1];
|
||
var forceGet = false;
|
||
|
||
if (optionName.charAt(optionName.length - 1) == '?') {
|
||
// If post-fixed with ?, then the set is actually a get.
|
||
if (value) { throw Error('Trailing characters: ' + params.argString); }
|
||
optionName = optionName.substring(0, optionName.length - 1);
|
||
forceGet = true;
|
||
}
|
||
if (value === undefined && optionName.substring(0, 2) == 'no') {
|
||
// To set boolean options to false, the option name is prefixed with
|
||
// 'no'.
|
||
optionName = optionName.substring(2);
|
||
value = false;
|
||
}
|
||
|
||
var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean';
|
||
if (optionIsBoolean && value == undefined) {
|
||
// Calling set with a boolean option sets it to true.
|
||
value = true;
|
||
}
|
||
// If no value is provided, then we assume this is a get.
|
||
if (!optionIsBoolean && value === undefined || forceGet) {
|
||
var oldValue = getOption(optionName, cm, setCfg);
|
||
if (oldValue instanceof Error) {
|
||
showConfirm(cm, oldValue.message);
|
||
} else if (oldValue === true || oldValue === false) {
|
||
showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName);
|
||
} else {
|
||
showConfirm(cm, ' ' + optionName + '=' + oldValue);
|
||
}
|
||
} else {
|
||
var setOptionReturn = setOption(optionName, value, cm, setCfg);
|
||
if (setOptionReturn instanceof Error) {
|
||
showConfirm(cm, setOptionReturn.message);
|
||
}
|
||
}
|
||
},
|
||
setlocal: function (cm, params) {
|
||
// setCfg is passed through to setOption
|
||
params.setCfg = {scope: 'local'};
|
||
this.set(cm, params);
|
||
},
|
||
setglobal: function (cm, params) {
|
||
// setCfg is passed through to setOption
|
||
params.setCfg = {scope: 'global'};
|
||
this.set(cm, params);
|
||
},
|
||
registers: function(cm, params) {
|
||
var regArgs = params.args;
|
||
var registers = vimGlobalState.registerController.registers;
|
||
var regInfo = '----------Registers----------<br><br>';
|
||
if (!regArgs) {
|
||
for (var registerName in registers) {
|
||
var text = registers[registerName].toString();
|
||
if (text.length) {
|
||
regInfo += '"' + registerName + ' ' + text + '<br>';
|
||
}
|
||
}
|
||
} else {
|
||
var registerName;
|
||
regArgs = regArgs.join('');
|
||
for (var i = 0; i < regArgs.length; i++) {
|
||
registerName = regArgs.charAt(i);
|
||
if (!vimGlobalState.registerController.isValidRegister(registerName)) {
|
||
continue;
|
||
}
|
||
var register = registers[registerName] || new Register();
|
||
regInfo += '"' + registerName + ' ' + register.toString() + '<br>';
|
||
}
|
||
}
|
||
showConfirm(cm, regInfo);
|
||
},
|
||
sort: function(cm, params) {
|
||
var reverse, ignoreCase, unique, number, pattern;
|
||
function parseArgs() {
|
||
if (params.argString) {
|
||
var args = new CodeMirror.StringStream(params.argString);
|
||
if (args.eat('!')) { reverse = true; }
|
||
if (args.eol()) { return; }
|
||
if (!args.eatSpace()) { return 'Invalid arguments'; }
|
||
var opts = args.match(/([dinuox]+)?\s*(\/.+\/)?\s*/);
|
||
if (!opts && !args.eol()) { return 'Invalid arguments'; }
|
||
if (opts[1]) {
|
||
ignoreCase = opts[1].indexOf('i') != -1;
|
||
unique = opts[1].indexOf('u') != -1;
|
||
var decimal = opts[1].indexOf('d') != -1 || opts[1].indexOf('n') != -1 && 1;
|
||
var hex = opts[1].indexOf('x') != -1 && 1;
|
||
var octal = opts[1].indexOf('o') != -1 && 1;
|
||
if (decimal + hex + octal > 1) { return 'Invalid arguments'; }
|
||
number = decimal && 'decimal' || hex && 'hex' || octal && 'octal';
|
||
}
|
||
if (opts[2]) {
|
||
pattern = new RegExp(opts[2].substr(1, opts[2].length - 2), ignoreCase ? 'i' : '');
|
||
}
|
||
}
|
||
}
|
||
var err = parseArgs();
|
||
if (err) {
|
||
showConfirm(cm, err + ': ' + params.argString);
|
||
return;
|
||
}
|
||
var lineStart = params.line || cm.firstLine();
|
||
var lineEnd = params.lineEnd || params.line || cm.lastLine();
|
||
if (lineStart == lineEnd) { return; }
|
||
var curStart = Pos(lineStart, 0);
|
||
var curEnd = Pos(lineEnd, lineLength(cm, lineEnd));
|
||
var text = cm.getRange(curStart, curEnd).split('\n');
|
||
var numberRegex = pattern ? pattern :
|
||
(number == 'decimal') ? /(-?)([\d]+)/ :
|
||
(number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i :
|
||
(number == 'octal') ? /([0-7]+)/ : null;
|
||
var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null;
|
||
var numPart = [], textPart = [];
|
||
if (number || pattern) {
|
||
for (var i = 0; i < text.length; i++) {
|
||
var matchPart = pattern ? text[i].match(pattern) : null;
|
||
if (matchPart && matchPart[0] != '') {
|
||
numPart.push(matchPart);
|
||
} else if (!pattern && numberRegex.exec(text[i])) {
|
||
numPart.push(text[i]);
|
||
} else {
|
||
textPart.push(text[i]);
|
||
}
|
||
}
|
||
} else {
|
||
textPart = text;
|
||
}
|
||
function compareFn(a, b) {
|
||
if (reverse) { var tmp; tmp = a; a = b; b = tmp; }
|
||
if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); }
|
||
var anum = number && numberRegex.exec(a);
|
||
var bnum = number && numberRegex.exec(b);
|
||
if (!anum) { return a < b ? -1 : 1; }
|
||
anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix);
|
||
bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix);
|
||
return anum - bnum;
|
||
}
|
||
function comparePatternFn(a, b) {
|
||
if (reverse) { var tmp; tmp = a; a = b; b = tmp; }
|
||
if (ignoreCase) { a[0] = a[0].toLowerCase(); b[0] = b[0].toLowerCase(); }
|
||
return (a[0] < b[0]) ? -1 : 1;
|
||
}
|
||
numPart.sort(pattern ? comparePatternFn : compareFn);
|
||
if (pattern) {
|
||
for (var i = 0; i < numPart.length; i++) {
|
||
numPart[i] = numPart[i].input;
|
||
}
|
||
} else if (!number) { textPart.sort(compareFn); }
|
||
text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart);
|
||
if (unique) { // Remove duplicate lines
|
||
var textOld = text;
|
||
var lastLine;
|
||
text = [];
|
||
for (var i = 0; i < textOld.length; i++) {
|
||
if (textOld[i] != lastLine) {
|
||
text.push(textOld[i]);
|
||
}
|
||
lastLine = textOld[i];
|
||
}
|
||
}
|
||
cm.replaceRange(text.join('\n'), curStart, curEnd);
|
||
},
|
||
global: function(cm, params) {
|
||
// a global command is of the form
|
||
// :[range]g/pattern/[cmd]
|
||
// argString holds the string /pattern/[cmd]
|
||
var argString = params.argString;
|
||
if (!argString) {
|
||
showConfirm(cm, 'Regular Expression missing from global');
|
||
return;
|
||
}
|
||
// range is specified here
|
||
var lineStart = (params.line !== undefined) ? params.line : cm.firstLine();
|
||
var lineEnd = params.lineEnd || params.line || cm.lastLine();
|
||
// get the tokens from argString
|
||
var tokens = splitBySlash(argString);
|
||
var regexPart = argString, cmd;
|
||
if (tokens.length) {
|
||
regexPart = tokens[0];
|
||
cmd = tokens.slice(1, tokens.length).join('/');
|
||
}
|
||
if (regexPart) {
|
||
// If regex part is empty, then use the previous query. Otherwise
|
||
// use the regex part as the new query.
|
||
try {
|
||
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
|
||
true /** smartCase */);
|
||
} catch (e) {
|
||
showConfirm(cm, 'Invalid regex: ' + regexPart);
|
||
return;
|
||
}
|
||
}
|
||
// now that we have the regexPart, search for regex matches in the
|
||
// specified range of lines
|
||
var query = getSearchState(cm).getQuery();
|
||
var matchedLines = [], content = '';
|
||
for (var i = lineStart; i <= lineEnd; i++) {
|
||
var matched = query.test(cm.getLine(i));
|
||
if (matched) {
|
||
matchedLines.push(i+1);
|
||
content+= cm.getLine(i) + '<br>';
|
||
}
|
||
}
|
||
// if there is no [cmd], just display the list of matched lines
|
||
if (!cmd) {
|
||
showConfirm(cm, content);
|
||
return;
|
||
}
|
||
var index = 0;
|
||
var nextCommand = function() {
|
||
if (index < matchedLines.length) {
|
||
var command = matchedLines[index] + cmd;
|
||
exCommandDispatcher.processCommand(cm, command, {
|
||
callback: nextCommand
|
||
});
|
||
}
|
||
index++;
|
||
};
|
||
nextCommand();
|
||
},
|
||
substitute: function(cm, params) {
|
||
if (!cm.getSearchCursor) {
|
||
throw new Error('Search feature not available. Requires searchcursor.js or ' +
|
||
'any other getSearchCursor implementation.');
|
||
}
|
||
var argString = params.argString;
|
||
var tokens = argString ? splitBySeparator(argString, argString[0]) : [];
|
||
var regexPart, replacePart = '', trailing, flagsPart, count;
|
||
var confirm = false; // Whether to confirm each replace.
|
||
var global = false; // True to replace all instances on a line, false to replace only 1.
|
||
if (tokens.length) {
|
||
regexPart = tokens[0];
|
||
if (getOption('pcre') && regexPart !== '') {
|
||
regexPart = new RegExp(regexPart).source; //normalize not escaped characters
|
||
}
|
||
replacePart = tokens[1];
|
||
if (regexPart && regexPart[regexPart.length - 1] === '$') {
|
||
regexPart = regexPart.slice(0, regexPart.length - 1) + '\\n';
|
||
replacePart = replacePart ? replacePart + '\n' : '\n';
|
||
}
|
||
if (replacePart !== undefined) {
|
||
if (getOption('pcre')) {
|
||
replacePart = unescapeRegexReplace(replacePart.replace(/([^\\])&/g,"$1$$&"));
|
||
} else {
|
||
replacePart = translateRegexReplace(replacePart);
|
||
}
|
||
vimGlobalState.lastSubstituteReplacePart = replacePart;
|
||
}
|
||
trailing = tokens[2] ? tokens[2].split(' ') : [];
|
||
} else {
|
||
// either the argString is empty or its of the form ' hello/world'
|
||
// actually splitBySlash returns a list of tokens
|
||
// only if the string starts with a '/'
|
||
if (argString && argString.length) {
|
||
showConfirm(cm, 'Substitutions should be of the form ' +
|
||
':s/pattern/replace/');
|
||
return;
|
||
}
|
||
}
|
||
// After the 3rd slash, we can have flags followed by a space followed
|
||
// by count.
|
||
if (trailing) {
|
||
flagsPart = trailing[0];
|
||
count = parseInt(trailing[1]);
|
||
if (flagsPart) {
|
||
if (flagsPart.indexOf('c') != -1) {
|
||
confirm = true;
|
||
flagsPart.replace('c', '');
|
||
}
|
||
if (flagsPart.indexOf('g') != -1) {
|
||
global = true;
|
||
flagsPart.replace('g', '');
|
||
}
|
||
if (getOption('pcre')) {
|
||
regexPart = regexPart + '/' + flagsPart;
|
||
} else {
|
||
regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart;
|
||
}
|
||
}
|
||
}
|
||
if (regexPart) {
|
||
// If regex part is empty, then use the previous query. Otherwise use
|
||
// the regex part as the new query.
|
||
try {
|
||
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
|
||
true /** smartCase */);
|
||
} catch (e) {
|
||
showConfirm(cm, 'Invalid regex: ' + regexPart);
|
||
return;
|
||
}
|
||
}
|
||
replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart;
|
||
if (replacePart === undefined) {
|
||
showConfirm(cm, 'No previous substitute regular expression');
|
||
return;
|
||
}
|
||
var state = getSearchState(cm);
|
||
var query = state.getQuery();
|
||
var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line;
|
||
var lineEnd = params.lineEnd || lineStart;
|
||
if (lineStart == cm.firstLine() && lineEnd == cm.lastLine()) {
|
||
lineEnd = Infinity;
|
||
}
|
||
if (count) {
|
||
lineStart = lineEnd;
|
||
lineEnd = lineStart + count - 1;
|
||
}
|
||
var startPos = clipCursorToContent(cm, Pos(lineStart, 0));
|
||
var cursor = cm.getSearchCursor(query, startPos);
|
||
doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback);
|
||
},
|
||
redo: CodeMirror.commands.redo,
|
||
undo: CodeMirror.commands.undo,
|
||
write: function(cm) {
|
||
if (CodeMirror.commands.save) {
|
||
// If a save command is defined, call it.
|
||
CodeMirror.commands.save(cm);
|
||
} else if (cm.save) {
|
||
// Saves to text area if no save command is defined and cm.save() is available.
|
||
cm.save();
|
||
}
|
||
},
|
||
nohlsearch: function(cm) {
|
||
clearSearchHighlight(cm);
|
||
},
|
||
yank: function (cm) {
|
||
var cur = copyCursor(cm.getCursor());
|
||
var line = cur.line;
|
||
var lineText = cm.getLine(line);
|
||
vimGlobalState.registerController.pushText(
|
||
'0', 'yank', lineText, true, true);
|
||
},
|
||
delmarks: function(cm, params) {
|
||
if (!params.argString || !trim(params.argString)) {
|
||
showConfirm(cm, 'Argument required');
|
||
return;
|
||
}
|
||
|
||
var state = cm.state.vim;
|
||
var stream = new CodeMirror.StringStream(trim(params.argString));
|
||
while (!stream.eol()) {
|
||
stream.eatSpace();
|
||
|
||
// Record the streams position at the beginning of the loop for use
|
||
// in error messages.
|
||
var count = stream.pos;
|
||
|
||
if (!stream.match(/[a-zA-Z]/, false)) {
|
||
showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
|
||
return;
|
||
}
|
||
|
||
var sym = stream.next();
|
||
// Check if this symbol is part of a range
|
||
if (stream.match('-', true)) {
|
||
// This symbol is part of a range.
|
||
|
||
// The range must terminate at an alphabetic character.
|
||
if (!stream.match(/[a-zA-Z]/, false)) {
|
||
showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
|
||
return;
|
||
}
|
||
|
||
var startMark = sym;
|
||
var finishMark = stream.next();
|
||
// The range must terminate at an alphabetic character which
|
||
// shares the same case as the start of the range.
|
||
if (isLowerCase(startMark) && isLowerCase(finishMark) ||
|
||
isUpperCase(startMark) && isUpperCase(finishMark)) {
|
||
var start = startMark.charCodeAt(0);
|
||
var finish = finishMark.charCodeAt(0);
|
||
if (start >= finish) {
|
||
showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
|
||
return;
|
||
}
|
||
|
||
// Because marks are always ASCII values, and we have
|
||
// determined that they are the same case, we can use
|
||
// their char codes to iterate through the defined range.
|
||
for (var j = 0; j <= finish - start; j++) {
|
||
var mark = String.fromCharCode(start + j);
|
||
delete state.marks[mark];
|
||
}
|
||
} else {
|
||
showConfirm(cm, 'Invalid argument: ' + startMark + '-');
|
||
return;
|
||
}
|
||
} else {
|
||
// This symbol is a valid mark, and is not part of a range.
|
||
delete state.marks[sym];
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
var exCommandDispatcher = new ExCommandDispatcher();
|
||
|
||
/**
|
||
* @param {CodeMirror} cm CodeMirror instance we are in.
|
||
* @param {boolean} confirm Whether to confirm each replace.
|
||
* @param {Cursor} lineStart Line to start replacing from.
|
||
* @param {Cursor} lineEnd Line to stop replacing at.
|
||
* @param {RegExp} query Query for performing matches with.
|
||
* @param {string} replaceWith Text to replace matches with. May contain $1,
|
||
* $2, etc for replacing captured groups using Javascript replace.
|
||
* @param {function()} callback A callback for when the replace is done.
|
||
*/
|
||
function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query,
|
||
replaceWith, callback) {
|
||
// Set up all the functions.
|
||
cm.state.vim.exMode = true;
|
||
var done = false;
|
||
var lastPos = searchCursor.from();
|
||
function replaceAll() {
|
||
cm.operation(function() {
|
||
while (!done) {
|
||
replace();
|
||
next();
|
||
}
|
||
stop();
|
||
});
|
||
}
|
||
function replace() {
|
||
var text = cm.getRange(searchCursor.from(), searchCursor.to());
|
||
var newText = text.replace(query, replaceWith);
|
||
searchCursor.replace(newText);
|
||
}
|
||
function next() {
|
||
// The below only loops to skip over multiple occurrences on the same
|
||
// line when 'global' is not true.
|
||
while(searchCursor.findNext() &&
|
||
isInRange(searchCursor.from(), lineStart, lineEnd)) {
|
||
if (!global && lastPos && searchCursor.from().line == lastPos.line) {
|
||
continue;
|
||
}
|
||
cm.scrollIntoView(searchCursor.from(), 30);
|
||
cm.setSelection(searchCursor.from(), searchCursor.to());
|
||
lastPos = searchCursor.from();
|
||
done = false;
|
||
return;
|
||
}
|
||
done = true;
|
||
}
|
||
function stop(close) {
|
||
if (close) { close(); }
|
||
cm.focus();
|
||
if (lastPos) {
|
||
cm.setCursor(lastPos);
|
||
var vim = cm.state.vim;
|
||
vim.exMode = false;
|
||
vim.lastHPos = vim.lastHSPos = lastPos.ch;
|
||
}
|
||
if (callback) { callback(); }
|
||
}
|
||
function onPromptKeyDown(e, _value, close) {
|
||
// Swallow all keys.
|
||
CodeMirror.e_stop(e);
|
||
var keyName = CodeMirror.keyName(e);
|
||
switch (keyName) {
|
||
case 'Y':
|
||
replace(); next(); break;
|
||
case 'N':
|
||
next(); break;
|
||
case 'A':
|
||
// replaceAll contains a call to close of its own. We don't want it
|
||
// to fire too early or multiple times.
|
||
var savedCallback = callback;
|
||
callback = undefined;
|
||
cm.operation(replaceAll);
|
||
callback = savedCallback;
|
||
break;
|
||
case 'L':
|
||
replace();
|
||
// fall through and exit.
|
||
case 'Q':
|
||
case 'Esc':
|
||
case 'Ctrl-C':
|
||
case 'Ctrl-[':
|
||
stop(close);
|
||
break;
|
||
}
|
||
if (done) { stop(close); }
|
||
return true;
|
||
}
|
||
|
||
// Actually do replace.
|
||
next();
|
||
if (done) {
|
||
showConfirm(cm, 'No matches for ' + query.source);
|
||
return;
|
||
}
|
||
if (!confirm) {
|
||
replaceAll();
|
||
if (callback) { callback(); }
|
||
return;
|
||
}
|
||
showPrompt(cm, {
|
||
prefix: 'replace with <strong>' + replaceWith + '</strong> (y/n/a/q/l)',
|
||
onKeyDown: onPromptKeyDown
|
||
});
|
||
}
|
||
|
||
CodeMirror.keyMap.vim = {
|
||
attach: attachVimMap,
|
||
detach: detachVimMap,
|
||
call: cmKey
|
||
};
|
||
|
||
function exitInsertMode(cm) {
|
||
var vim = cm.state.vim;
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.');
|
||
var isPlaying = macroModeState.isPlaying;
|
||
var lastChange = macroModeState.lastInsertModeChanges;
|
||
if (!isPlaying) {
|
||
cm.off('change', onChange);
|
||
CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
|
||
}
|
||
if (!isPlaying && vim.insertModeRepeat > 1) {
|
||
// Perform insert mode repeat for commands like 3,a and 3,o.
|
||
repeatLastEdit(cm, vim, vim.insertModeRepeat - 1,
|
||
true /** repeatForInsert */);
|
||
vim.lastEditInputState.repeatOverride = vim.insertModeRepeat;
|
||
}
|
||
delete vim.insertModeRepeat;
|
||
vim.insertMode = false;
|
||
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1);
|
||
cm.setOption('keyMap', 'vim');
|
||
cm.setOption('disableInput', true);
|
||
cm.toggleOverwrite(false); // exit replace mode if we were in it.
|
||
// update the ". register before exiting insert mode
|
||
insertModeChangeRegister.setText(lastChange.changes.join(''));
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||
if (macroModeState.isRecording) {
|
||
logInsertModeChange(macroModeState);
|
||
}
|
||
}
|
||
|
||
function _mapCommand(command) {
|
||
defaultKeymap.unshift(command);
|
||
}
|
||
|
||
function mapCommand(keys, type, name, args, extra) {
|
||
var command = {keys: keys, type: type};
|
||
command[type] = name;
|
||
command[type + "Args"] = args;
|
||
for (var key in extra)
|
||
command[key] = extra[key];
|
||
_mapCommand(command);
|
||
}
|
||
|
||
// The timeout in milliseconds for the two-character ESC keymap should be
|
||
// adjusted according to your typing speed to prevent false positives.
|
||
defineOption('insertModeEscKeysTimeout', 200, 'number');
|
||
|
||
CodeMirror.keyMap['vim-insert'] = {
|
||
// TODO: override navigation keys so that Esc will cancel automatic
|
||
// indentation from o, O, i_<CR>
|
||
fallthrough: ['default'],
|
||
attach: attachVimMap,
|
||
detach: detachVimMap,
|
||
call: cmKey
|
||
};
|
||
|
||
CodeMirror.keyMap['vim-replace'] = {
|
||
'Backspace': 'goCharLeft',
|
||
fallthrough: ['vim-insert'],
|
||
attach: attachVimMap,
|
||
detach: detachVimMap,
|
||
call: cmKey
|
||
};
|
||
|
||
function executeMacroRegister(cm, vim, macroModeState, registerName) {
|
||
var register = vimGlobalState.registerController.getRegister(registerName);
|
||
if (registerName == ':') {
|
||
// Read-only register containing last Ex command.
|
||
if (register.keyBuffer[0]) {
|
||
exCommandDispatcher.processCommand(cm, register.keyBuffer[0]);
|
||
}
|
||
macroModeState.isPlaying = false;
|
||
return;
|
||
}
|
||
var keyBuffer = register.keyBuffer;
|
||
var imc = 0;
|
||
macroModeState.isPlaying = true;
|
||
macroModeState.replaySearchQueries = register.searchQueries.slice(0);
|
||
for (var i = 0; i < keyBuffer.length; i++) {
|
||
var text = keyBuffer[i];
|
||
var match, key;
|
||
while (text) {
|
||
// Pull off one command key, which is either a single character
|
||
// or a special sequence wrapped in '<' and '>', e.g. '<Space>'.
|
||
match = (/<\w+-.+?>|<\w+>|./).exec(text);
|
||
key = match[0];
|
||
text = text.substring(match.index + key.length);
|
||
CodeMirror.Vim.handleKey(cm, key, 'macro');
|
||
if (vim.insertMode) {
|
||
var changes = register.insertModeChanges[imc++].changes;
|
||
vimGlobalState.macroModeState.lastInsertModeChanges.changes =
|
||
changes;
|
||
repeatInsertModeChanges(cm, changes, 1);
|
||
exitInsertMode(cm);
|
||
}
|
||
}
|
||
}
|
||
macroModeState.isPlaying = false;
|
||
}
|
||
|
||
function logKey(macroModeState, key) {
|
||
if (macroModeState.isPlaying) { return; }
|
||
var registerName = macroModeState.latestRegister;
|
||
var register = vimGlobalState.registerController.getRegister(registerName);
|
||
if (register) {
|
||
register.pushText(key);
|
||
}
|
||
}
|
||
|
||
function logInsertModeChange(macroModeState) {
|
||
if (macroModeState.isPlaying) { return; }
|
||
var registerName = macroModeState.latestRegister;
|
||
var register = vimGlobalState.registerController.getRegister(registerName);
|
||
if (register && register.pushInsertModeChanges) {
|
||
register.pushInsertModeChanges(macroModeState.lastInsertModeChanges);
|
||
}
|
||
}
|
||
|
||
function logSearchQuery(macroModeState, query) {
|
||
if (macroModeState.isPlaying) { return; }
|
||
var registerName = macroModeState.latestRegister;
|
||
var register = vimGlobalState.registerController.getRegister(registerName);
|
||
if (register && register.pushSearchQuery) {
|
||
register.pushSearchQuery(query);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Listens for changes made in insert mode.
|
||
* Should only be active in insert mode.
|
||
*/
|
||
function onChange(cm, changeObj) {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
var lastChange = macroModeState.lastInsertModeChanges;
|
||
if (!macroModeState.isPlaying) {
|
||
while(changeObj) {
|
||
lastChange.expectCursorActivityForChange = true;
|
||
if (lastChange.ignoreCount > 1) {
|
||
lastChange.ignoreCount--;
|
||
} else if (changeObj.origin == '+input' || changeObj.origin == 'paste'
|
||
|| changeObj.origin === undefined /* only in testing */) {
|
||
var selectionCount = cm.listSelections().length;
|
||
if (selectionCount > 1)
|
||
lastChange.ignoreCount = selectionCount;
|
||
var text = changeObj.text.join('\n');
|
||
if (lastChange.maybeReset) {
|
||
lastChange.changes = [];
|
||
lastChange.maybeReset = false;
|
||
}
|
||
if (text) {
|
||
if (cm.state.overwrite && !/\n/.test(text)) {
|
||
lastChange.changes.push([text]);
|
||
} else {
|
||
lastChange.changes.push(text);
|
||
}
|
||
}
|
||
}
|
||
// Change objects may be chained with next.
|
||
changeObj = changeObj.next;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Listens for any kind of cursor activity on CodeMirror.
|
||
*/
|
||
function onCursorActivity(cm) {
|
||
var vim = cm.state.vim;
|
||
if (vim.insertMode) {
|
||
// Tracking cursor activity in insert mode (for macro support).
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
if (macroModeState.isPlaying) { return; }
|
||
var lastChange = macroModeState.lastInsertModeChanges;
|
||
if (lastChange.expectCursorActivityForChange) {
|
||
lastChange.expectCursorActivityForChange = false;
|
||
} else {
|
||
// Cursor moved outside the context of an edit. Reset the change.
|
||
lastChange.maybeReset = true;
|
||
}
|
||
} else if (!cm.curOp.isVimOp) {
|
||
handleExternalSelection(cm, vim);
|
||
}
|
||
if (vim.visualMode) {
|
||
updateFakeCursor(cm);
|
||
}
|
||
}
|
||
/**
|
||
* Keeps track of a fake cursor to support visual mode cursor behavior.
|
||
*/
|
||
function updateFakeCursor(cm) {
|
||
var className = 'cm-animate-fat-cursor';
|
||
var vim = cm.state.vim;
|
||
var from = clipCursorToContent(cm, copyCursor(vim.sel.head));
|
||
var to = offsetCursor(from, 0, 1);
|
||
clearFakeCursor(vim);
|
||
// In visual mode, the cursor may be positioned over EOL.
|
||
if (from.ch == cm.getLine(from.line).length) {
|
||
var widget = document.createElement("span");
|
||
widget.textContent = "\u00a0";
|
||
widget.className = className;
|
||
vim.fakeCursorBookmark = cm.setBookmark(from, {widget: widget});
|
||
} else {
|
||
vim.fakeCursor = cm.markText(from, to, {className: className});
|
||
}
|
||
}
|
||
function clearFakeCursor(vim) {
|
||
if (vim.fakeCursor) {
|
||
vim.fakeCursor.clear();
|
||
vim.fakeCursor = null;
|
||
}
|
||
if (vim.fakeCursorBookmark) {
|
||
vim.fakeCursorBookmark.clear();
|
||
vim.fakeCursorBookmark = null;
|
||
}
|
||
}
|
||
function handleExternalSelection(cm, vim) {
|
||
var anchor = cm.getCursor('anchor');
|
||
var head = cm.getCursor('head');
|
||
// Enter or exit visual mode to match mouse selection.
|
||
if (vim.visualMode && !cm.somethingSelected()) {
|
||
exitVisualMode(cm, false);
|
||
} else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) {
|
||
vim.visualMode = true;
|
||
vim.visualLine = false;
|
||
CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"});
|
||
}
|
||
if (vim.visualMode) {
|
||
// Bind CodeMirror selection model to vim selection model.
|
||
// Mouse selections are considered visual characterwise.
|
||
var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0;
|
||
var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0;
|
||
head = offsetCursor(head, 0, headOffset);
|
||
anchor = offsetCursor(anchor, 0, anchorOffset);
|
||
vim.sel = {
|
||
anchor: anchor,
|
||
head: head
|
||
};
|
||
updateMark(cm, vim, '<', cursorMin(head, anchor));
|
||
updateMark(cm, vim, '>', cursorMax(head, anchor));
|
||
} else if (!vim.insertMode) {
|
||
// Reset lastHPos if selection was modified by something outside of vim mode e.g. by mouse.
|
||
vim.lastHPos = cm.getCursor().ch;
|
||
}
|
||
}
|
||
|
||
/** Wrapper for special keys pressed in insert mode */
|
||
function InsertModeKey(keyName) {
|
||
this.keyName = keyName;
|
||
}
|
||
|
||
/**
|
||
* Handles raw key down events from the text area.
|
||
* - Should only be active in insert mode.
|
||
* - For recording deletes in insert mode.
|
||
*/
|
||
function onKeyEventTargetKeyDown(e) {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
var lastChange = macroModeState.lastInsertModeChanges;
|
||
var keyName = CodeMirror.keyName(e);
|
||
if (!keyName) { return; }
|
||
function onKeyFound() {
|
||
if (lastChange.maybeReset) {
|
||
lastChange.changes = [];
|
||
lastChange.maybeReset = false;
|
||
}
|
||
lastChange.changes.push(new InsertModeKey(keyName));
|
||
return true;
|
||
}
|
||
if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) {
|
||
CodeMirror.lookupKey(keyName, 'vim-insert', onKeyFound);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Repeats the last edit, which includes exactly 1 command and at most 1
|
||
* insert. Operator and motion commands are read from lastEditInputState,
|
||
* while action commands are read from lastEditActionCommand.
|
||
*
|
||
* If repeatForInsert is true, then the function was called by
|
||
* exitInsertMode to repeat the insert mode changes the user just made. The
|
||
* corresponding enterInsertMode call was made with a count.
|
||
*/
|
||
function repeatLastEdit(cm, vim, repeat, repeatForInsert) {
|
||
var macroModeState = vimGlobalState.macroModeState;
|
||
macroModeState.isPlaying = true;
|
||
var isAction = !!vim.lastEditActionCommand;
|
||
var cachedInputState = vim.inputState;
|
||
function repeatCommand() {
|
||
if (isAction) {
|
||
commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand);
|
||
} else {
|
||
commandDispatcher.evalInput(cm, vim);
|
||
}
|
||
}
|
||
function repeatInsert(repeat) {
|
||
if (macroModeState.lastInsertModeChanges.changes.length > 0) {
|
||
// For some reason, repeat cw in desktop VIM does not repeat
|
||
// insert mode changes. Will conform to that behavior.
|
||
repeat = !vim.lastEditActionCommand ? 1 : repeat;
|
||
var changeObject = macroModeState.lastInsertModeChanges;
|
||
repeatInsertModeChanges(cm, changeObject.changes, repeat);
|
||
}
|
||
}
|
||
vim.inputState = vim.lastEditInputState;
|
||
if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) {
|
||
// o and O repeat have to be interlaced with insert repeats so that the
|
||
// insertions appear on separate lines instead of the last line.
|
||
for (var i = 0; i < repeat; i++) {
|
||
repeatCommand();
|
||
repeatInsert(1);
|
||
}
|
||
} else {
|
||
if (!repeatForInsert) {
|
||
// Hack to get the cursor to end up at the right place. If I is
|
||
// repeated in insert mode repeat, cursor will be 1 insert
|
||
// change set left of where it should be.
|
||
repeatCommand();
|
||
}
|
||
repeatInsert(repeat);
|
||
}
|
||
vim.inputState = cachedInputState;
|
||
if (vim.insertMode && !repeatForInsert) {
|
||
// Don't exit insert mode twice. If repeatForInsert is set, then we
|
||
// were called by an exitInsertMode call lower on the stack.
|
||
exitInsertMode(cm);
|
||
}
|
||
macroModeState.isPlaying = false;
|
||
}
|
||
|
||
function repeatInsertModeChanges(cm, changes, repeat) {
|
||
function keyHandler(binding) {
|
||
if (typeof binding == 'string') {
|
||
CodeMirror.commands[binding](cm);
|
||
} else {
|
||
binding(cm);
|
||
}
|
||
return true;
|
||
}
|
||
var head = cm.getCursor('head');
|
||
var visualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.visualBlock;
|
||
if (visualBlock) {
|
||
// Set up block selection again for repeating the changes.
|
||
selectForInsert(cm, head, visualBlock + 1);
|
||
repeat = cm.listSelections().length;
|
||
cm.setCursor(head);
|
||
}
|
||
for (var i = 0; i < repeat; i++) {
|
||
if (visualBlock) {
|
||
cm.setCursor(offsetCursor(head, i, 0));
|
||
}
|
||
for (var j = 0; j < changes.length; j++) {
|
||
var change = changes[j];
|
||
if (change instanceof InsertModeKey) {
|
||
CodeMirror.lookupKey(change.keyName, 'vim-insert', keyHandler);
|
||
} else if (typeof change == "string") {
|
||
var cur = cm.getCursor();
|
||
cm.replaceRange(change, cur, cur);
|
||
} else {
|
||
var start = cm.getCursor();
|
||
var end = offsetCursor(start, 0, change[0].length);
|
||
cm.replaceRange(change[0], start, end);
|
||
}
|
||
}
|
||
}
|
||
if (visualBlock) {
|
||
cm.setCursor(offsetCursor(head, 0, 1));
|
||
}
|
||
}
|
||
|
||
resetVimGlobalState();
|
||
return vimApi;
|
||
};
|
||
// Initialize Vim and make it available as an API.
|
||
CodeMirror.Vim = Vim();
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('edit/js/editor',[
|
||
'jquery',
|
||
'base/js/utils',
|
||
'base/js/i18n',
|
||
'base/js/dialog',
|
||
'codemirror/lib/codemirror',
|
||
'codemirror/mode/meta',
|
||
'codemirror/addon/comment/comment',
|
||
'codemirror/addon/dialog/dialog',
|
||
'codemirror/addon/edit/closebrackets',
|
||
'codemirror/addon/edit/matchbrackets',
|
||
'codemirror/addon/search/searchcursor',
|
||
'codemirror/addon/search/search',
|
||
'codemirror/keymap/emacs',
|
||
'codemirror/keymap/sublime',
|
||
'codemirror/keymap/vim',
|
||
],
|
||
function(
|
||
$,
|
||
utils,
|
||
i18n,
|
||
dialog,
|
||
CodeMirror
|
||
) {
|
||
"use strict";
|
||
|
||
var Editor = function(selector, options) {
|
||
var that = this;
|
||
this.selector = selector;
|
||
this.clean = false;
|
||
this.contents = options.contents;
|
||
this.events = options.events;
|
||
this.base_url = options.base_url;
|
||
this.file_path = options.file_path;
|
||
this.config = options.config;
|
||
this.file_extension_modes = options.file_extension_modes || {};
|
||
this.last_modified = null;
|
||
this._changed_on_disk_dialog = null;
|
||
|
||
this.codemirror = new CodeMirror($(this.selector)[0]);
|
||
this.codemirror.on('changes', function(cm, changes){
|
||
that._clean_state();
|
||
});
|
||
this.generation = -1;
|
||
|
||
// It appears we have to set commands on the CodeMirror class, not the
|
||
// instance. I'd like to be wrong, but since there should only be one CM
|
||
// instance on the page, this is good enough for now.
|
||
CodeMirror.commands.save = $.proxy(this.save, this);
|
||
|
||
this.save_enabled = false;
|
||
|
||
this.config.loaded.then(function () {
|
||
// load codemirror config
|
||
var cfg = that.config.data.Editor || {};
|
||
var cmopts = $.extend(true, {}, // true = recursive copy
|
||
Editor.default_codemirror_options,
|
||
cfg.codemirror_options || {}
|
||
);
|
||
that._set_codemirror_options(cmopts);
|
||
that.events.trigger('config_changed.Editor', {config: that.config});
|
||
if (cfg.file_extension_modes) {
|
||
// check for file extension in user preferences
|
||
var modename = cfg.file_extension_modes[that._get_file_extension()];
|
||
if (modename) {
|
||
var modeinfo = CodeMirror.findModeByName(modename);
|
||
if (modeinfo) {
|
||
that.set_codemirror_mode(modeinfo);
|
||
}
|
||
}
|
||
}
|
||
that._clean_state();
|
||
});
|
||
this.clean_sel = $('<div/>');
|
||
$('.last_modified').before(this.clean_sel);
|
||
this.clean_sel.addClass('dirty-indicator-dirty');
|
||
};
|
||
|
||
// default CodeMirror options
|
||
Editor.default_codemirror_options = {
|
||
extraKeys: {
|
||
"Cmd-Right": "goLineRight",
|
||
"End": "goLineRight",
|
||
"Cmd-Left": "goLineLeft",
|
||
"Tab": "indentMore",
|
||
"Shift-Tab" : "indentLess",
|
||
"Cmd-/" : "toggleComment",
|
||
"Ctrl-/" : "toggleComment",
|
||
},
|
||
indentUnit: 4,
|
||
theme: "ipython",
|
||
lineNumbers: true,
|
||
lineWrapping: true
|
||
};
|
||
|
||
Editor.prototype.load = function() {
|
||
/** load the file */
|
||
var that = this;
|
||
var cm = this.codemirror;
|
||
return this.contents.get(this.file_path, {type: 'file', format: 'text'})
|
||
.then(function(model) {
|
||
cm.setValue(model.content);
|
||
|
||
// Setting the file's initial value creates a history entry,
|
||
// which we don't want.
|
||
cm.clearHistory();
|
||
that._set_mode_for_model(model);
|
||
that.save_enabled = true;
|
||
that.generation = cm.changeGeneration();
|
||
that.events.trigger("file_loaded.Editor", model);
|
||
that._clean_state();
|
||
that.last_modified = new Date(model.last_modified);
|
||
}).catch(
|
||
function(error) {
|
||
that.events.trigger("file_load_failed.Editor", error);
|
||
console.warn('Error loading: ', error);
|
||
cm.setValue("Error! " + error.message +
|
||
"\nSaving disabled.\nSee Console for more details.");
|
||
cm.setOption('readOnly','nocursor');
|
||
that.save_enabled = false;
|
||
}
|
||
);
|
||
};
|
||
|
||
Editor.prototype._set_mode_for_model = function (model) {
|
||
/** Set the CodeMirror mode based on the file model */
|
||
|
||
// Find and load the highlighting mode,
|
||
// first by mime-type, then by file extension
|
||
|
||
var modeinfo;
|
||
var ext = this._get_file_extension();
|
||
if (ext) {
|
||
// check if a mode has been remembered for this extension
|
||
var modename = this.file_extension_modes[ext];
|
||
if (modename) {
|
||
modeinfo = CodeMirror.findModeByName(modename);
|
||
}
|
||
}
|
||
// prioritize CodeMirror's filename identification
|
||
if (!modeinfo || modeinfo.mode === "null") {
|
||
modeinfo = CodeMirror.findModeByFileName(model.name);
|
||
// codemirror's filename identification is case-sensitive.
|
||
// try once more with lowercase extension
|
||
if (!modeinfo && ext) {
|
||
// CodeMirror wants lowercase ext without leading '.'
|
||
modeinfo = CodeMirror.findModeByExtension(ext.slice(1).toLowerCase());
|
||
}
|
||
}
|
||
if (model.mimetype && (!modeinfo || modeinfo.mode === "null")) {
|
||
// mimetype is not set on file rename
|
||
modeinfo = CodeMirror.findModeByMIME(model.mimetype);
|
||
}
|
||
if (modeinfo) {
|
||
this.set_codemirror_mode(modeinfo);
|
||
}
|
||
};
|
||
|
||
Editor.prototype.set_codemirror_mode = function (modeinfo) {
|
||
/** set the codemirror mode from a modeinfo struct */
|
||
var that = this;
|
||
utils.requireCodeMirrorMode(modeinfo, function () {
|
||
that.codemirror.setOption('mode', modeinfo.mime);
|
||
that.events.trigger("mode_changed.Editor", modeinfo);
|
||
}, function(err) {
|
||
console.log('Error getting CodeMirror mode: ' + err);
|
||
});
|
||
};
|
||
|
||
Editor.prototype.save_codemirror_mode = function (modeinfo) {
|
||
/** save the selected codemirror mode for the current extension in config */
|
||
var update_mode_map = {};
|
||
var ext = this._get_file_extension();
|
||
// no extension, nothing to save
|
||
// TODO: allow remembering no-extension things like Makefile?
|
||
if (!ext) return;
|
||
|
||
update_mode_map[ext] = modeinfo.name;
|
||
return this.config.update({
|
||
Editor: {
|
||
file_extension_modes: update_mode_map,
|
||
}
|
||
});
|
||
};
|
||
|
||
Editor.prototype.get_filename = function () {
|
||
return utils.url_path_split(this.file_path)[1];
|
||
};
|
||
|
||
Editor.prototype._get_file_extension = function () {
|
||
/** return file extension *including* .
|
||
|
||
Returns undefined if no extension is found.
|
||
*/
|
||
var filename = this.get_filename();
|
||
var ext_idx = filename.lastIndexOf('.');
|
||
if (ext_idx < 0) {
|
||
return;
|
||
} else {
|
||
return filename.slice(ext_idx);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Rename the file.
|
||
* @param {string} new_name
|
||
* @return {Promise} promise that resolves when the file is renamed.
|
||
*/
|
||
Editor.prototype.rename = function (new_name) {
|
||
/** rename the file */
|
||
var that = this;
|
||
var parent = utils.url_path_split(this.file_path)[0];
|
||
var new_path = utils.url_path_join(parent, new_name);
|
||
return this.contents.rename(this.file_path, new_path).then(
|
||
function (model) {
|
||
that.file_path = model.path;
|
||
that.events.trigger('file_renamed.Editor', model);
|
||
that.last_modified = new Date(model.last_modified);
|
||
that._set_mode_for_model(model);
|
||
that._clean_state();
|
||
}
|
||
);
|
||
};
|
||
|
||
|
||
/**
|
||
* Save this file on the server.
|
||
*
|
||
* @param {boolean} check_last_modified - checks if file has been modified on disk
|
||
* @return {Promise} - promise that resolves when the notebook is saved.
|
||
*/
|
||
Editor.prototype.save = function (check_last_modified) {
|
||
/** save the file */
|
||
if (!this.save_enabled) {
|
||
console.log("Not saving, save disabled");
|
||
return;
|
||
}
|
||
|
||
// used to check for last modified saves
|
||
if (check_last_modified === undefined) {
|
||
check_last_modified = true;
|
||
}
|
||
|
||
var model = {
|
||
path: this.file_path,
|
||
type: 'file',
|
||
format: 'text',
|
||
content: this.codemirror.getValue(),
|
||
};
|
||
var that = this;
|
||
|
||
var _save = function () {
|
||
that.events.trigger("file_saving.Editor");
|
||
return that.contents.save(that.file_path, model).then(function(data) {
|
||
// record change generation for isClean
|
||
that.generation = that.codemirror.changeGeneration();
|
||
that.events.trigger("file_saved.Editor", data);
|
||
that.last_modified = new Date(data.last_modified);
|
||
that._clean_state();
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Gets the current working file, and checks if the file has been modified on disk. If so, it
|
||
* creates & opens a modal that issues the user a warning and prompts them to overwrite the file.
|
||
*
|
||
* If it can't get the working file, it builds a new file and saves.
|
||
*/
|
||
if (check_last_modified) {
|
||
return this.contents.get(that.file_path, {content: false}).then(
|
||
function check_if_modified(data) {
|
||
var last_modified = new Date(data.last_modified);
|
||
// We want to check last_modified (disk) > that.last_modified (our last save)
|
||
// In some cases the filesystem reports an inconsistent time,
|
||
// so we allow 0.5 seconds difference before complaining.
|
||
if ((last_modified.getTime() - that.last_modified.getTime()) > 500) { // 500 ms
|
||
console.warn("Last saving was done on `"+that.last_modified+"`("+that._last_modified+"), "+
|
||
"while the current file seem to have been saved on `"+data.last_modified+"`");
|
||
if (that._changed_on_disk_dialog !== null) {
|
||
// since the modal's event bindings are removed when destroyed, we reinstate
|
||
// save & reload callbacks on the confirmation & reload buttons
|
||
that._changed_on_disk_dialog.find('.save-confirm-btn').click(_save);
|
||
that._changed_on_disk_dialog.find('.btn-warning').click(function () {window.location.reload()});
|
||
|
||
// redisplay existing dialog
|
||
that._changed_on_disk_dialog.modal('show');
|
||
} else {
|
||
// create new dialog
|
||
that._changed_on_disk_dialog = dialog.modal({
|
||
keyboard_manager: that.keyboard_manager,
|
||
title: i18n.msg._("File changed"),
|
||
body: i18n.msg._("The file has changed on disk since the last time we opened or saved it. "
|
||
+ "Do you want to overwrite the file on disk with the version open here, or load "
|
||
+ "the version on disk (reload the page)?"),
|
||
buttons: {
|
||
Reload: {
|
||
class: 'btn-warning',
|
||
click: function () {
|
||
window.location.reload();
|
||
}
|
||
},
|
||
Cancel: {},
|
||
Overwrite: {
|
||
class: 'btn-danger save-confirm-btn',
|
||
click: function () {
|
||
_save();
|
||
}
|
||
},
|
||
}
|
||
});
|
||
}
|
||
} else {
|
||
return _save();
|
||
}
|
||
}, function (error) {
|
||
console.log(error);
|
||
// maybe it has been deleted or renamed? Go ahead and save.
|
||
return _save();
|
||
})
|
||
} else {
|
||
return _save();
|
||
}
|
||
};
|
||
|
||
Editor.prototype._clean_state = function(){
|
||
var clean = this.codemirror.isClean(this.generation);
|
||
if (clean === this.clean){
|
||
return;
|
||
} else {
|
||
this.clean = clean;
|
||
}
|
||
if(clean){
|
||
this.events.trigger("save_status_clean.Editor");
|
||
this.clean_sel.attr('class','dirty-indicator-clean').attr('title','No changes to save');
|
||
} else {
|
||
this.events.trigger("save_status_dirty.Editor");
|
||
this.clean_sel.attr('class','dirty-indicator-dirty').attr('title','Unsaved changes');
|
||
}
|
||
};
|
||
|
||
Editor.prototype._set_codemirror_options = function (options) {
|
||
// update codemirror options from a dict
|
||
var codemirror = this.codemirror;
|
||
$.map(options, function (value, opt) {
|
||
if (value === null) {
|
||
value = CodeMirror.defaults[opt];
|
||
}
|
||
codemirror.setOption(opt, value);
|
||
});
|
||
var that = this;
|
||
};
|
||
|
||
Editor.prototype.update_codemirror_options = function (options) {
|
||
/** update codemirror options locally and save changes in config */
|
||
var that = this;
|
||
this._set_codemirror_options(options);
|
||
return this.config.update({
|
||
Editor: {
|
||
codemirror_options: options
|
||
}
|
||
}).then(
|
||
that.events.trigger('config_changed.Editor', {config: that.config})
|
||
);
|
||
};
|
||
|
||
return {Editor: Editor};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('edit/js/menubar',[
|
||
'jquery',
|
||
'base/js/namespace',
|
||
'base/js/utils',
|
||
'base/js/dialog',
|
||
'codemirror/lib/codemirror',
|
||
'codemirror/mode/meta',
|
||
], function($, IPython, utils, dialog, CodeMirror) {
|
||
"use strict";
|
||
|
||
var MenuBar = function (selector, options) {
|
||
/**
|
||
* Constructor
|
||
*
|
||
* A MenuBar Class to generate the menubar of IPython notebook
|
||
*
|
||
* Parameters:
|
||
* selector: string
|
||
* options: dictionary
|
||
* Dictionary of keyword arguments.
|
||
* codemirror: CodeMirror instance
|
||
* contents: ContentManager instance
|
||
* events: $(Events) instance
|
||
* base_url : string
|
||
* file_path : string
|
||
*/
|
||
options = options || {};
|
||
this.base_url = options.base_url || utils.get_body_data("baseUrl");
|
||
this.selector = selector;
|
||
this.editor = options.editor;
|
||
this.events = options.events;
|
||
this.save_widget = options.save_widget;
|
||
|
||
if (this.selector !== undefined) {
|
||
this.element = $(selector);
|
||
this.bind_events();
|
||
}
|
||
this._load_mode_menu();
|
||
Object.seal(this);
|
||
};
|
||
|
||
MenuBar.prototype.bind_events = function () {
|
||
var that = this;
|
||
var editor = that.editor;
|
||
|
||
// File
|
||
this.element.find('#new-file').click(function () {
|
||
var w = window.open(undefined, IPython._target);
|
||
// Create a new file in the current directory
|
||
var parent = utils.url_path_split(editor.file_path)[0];
|
||
editor.contents.new_untitled(parent, {type: "file"}).then(
|
||
function (data) {
|
||
w.location = utils.url_path_join(
|
||
that.base_url, 'edit', utils.encode_uri_components(data.path)
|
||
);
|
||
},
|
||
function(error) {
|
||
w.close();
|
||
dialog.modal({
|
||
title : 'Creating New File Failed',
|
||
body : "The error was: " + error.message,
|
||
buttons : {'OK' : {'class' : 'btn-primary'}}
|
||
});
|
||
}
|
||
);
|
||
});
|
||
this.element.find('#save-file').click(function () {
|
||
editor.save();
|
||
});
|
||
this.element.find('#rename-file').click(function () {
|
||
that.save_widget.rename();
|
||
});
|
||
this.element.find('#download-file').click(function () {
|
||
window.open(utils.url_path_join(
|
||
that.base_url, 'files',
|
||
utils.encode_uri_components(that.editor.file_path)
|
||
) + '?download=1');
|
||
});
|
||
|
||
// Edit
|
||
this.element.find('#menu-find').click(function () {
|
||
editor.codemirror.execCommand("find");
|
||
});
|
||
this.element.find('#menu-replace').click(function () {
|
||
editor.codemirror.execCommand("replace");
|
||
});
|
||
this.element.find('#menu-keymap-default').click(function () {
|
||
editor.update_codemirror_options({
|
||
vimMode: false,
|
||
keyMap: 'default'
|
||
});
|
||
});
|
||
this.element.find('#menu-keymap-sublime').click(function () {
|
||
editor.update_codemirror_options({
|
||
vimMode: false,
|
||
keyMap: 'sublime'
|
||
});
|
||
});
|
||
this.element.find('#menu-keymap-emacs').click(function () {
|
||
editor.update_codemirror_options({
|
||
vimMode: false,
|
||
keyMap: 'emacs'
|
||
});
|
||
});
|
||
this.element.find('#menu-keymap-vim').click(function () {
|
||
editor.update_codemirror_options({
|
||
vimMode: true,
|
||
keyMap: 'vim'
|
||
});
|
||
});
|
||
|
||
// View
|
||
|
||
this.element.find('#toggle_header').click(function (){
|
||
$("#header-container").toggle();
|
||
});
|
||
|
||
this.element.find('#menu-line-numbers').click(function () {
|
||
var current = editor.codemirror.getOption('lineNumbers');
|
||
var value = Boolean(1-current);
|
||
editor.update_codemirror_options({lineNumbers: value});
|
||
});
|
||
|
||
this.events.on("config_changed.Editor", function () {
|
||
var keyMap = editor.codemirror.getOption('keyMap') || 'default';
|
||
that.element.find(".selected-keymap").removeClass("selected-keymap");
|
||
that.element.find("#menu-keymap-" + keyMap).addClass("selected-keymap");
|
||
});
|
||
|
||
this.events.on("mode_changed.Editor", function (evt, modeinfo) {
|
||
that.element.find("#current-mode")
|
||
.text(modeinfo.name)
|
||
.attr(
|
||
'title',
|
||
"The current language is " + modeinfo.name
|
||
);
|
||
});
|
||
};
|
||
|
||
MenuBar.prototype._load_mode_menu = function () {
|
||
var list = this.element.find("#mode-menu");
|
||
var editor = this.editor;
|
||
function make_set_mode(info) {
|
||
return function () {
|
||
editor.set_codemirror_mode(info);
|
||
// save codemirror mode for extension when explicitly selected
|
||
editor.save_codemirror_mode(info);
|
||
};
|
||
}
|
||
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
|
||
var info = CodeMirror.modeInfo[i];
|
||
list.append($("<li>").append(
|
||
$("<a>").attr("href", "#")
|
||
.text(info.name)
|
||
.click(make_set_mode(info))
|
||
.attr('title',
|
||
"Set language to " + info.name
|
||
)
|
||
));
|
||
}
|
||
};
|
||
|
||
return {'MenuBar': MenuBar};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
/**
|
||
*
|
||
*
|
||
* @module keyboard
|
||
* @namespace keyboard
|
||
* @class ShortcutManager
|
||
*/
|
||
|
||
define('base/js/keyboard',[
|
||
'jquery',
|
||
'base/js/utils',
|
||
'underscore',
|
||
], function($, utils, _) {
|
||
"use strict";
|
||
|
||
|
||
/**
|
||
* Setup global keycodes and inverse keycodes.
|
||
*
|
||
* See http://unixpapa.com/js/key.html for a complete description. The short of
|
||
* it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
|
||
* and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
|
||
* but have minor differences.
|
||
**/
|
||
|
||
// These apply to Firefox, (Webkit and IE)
|
||
// This does work **only** on US keyboard.
|
||
var _keycodes = {
|
||
'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
|
||
'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
|
||
's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
|
||
'1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
|
||
'7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
|
||
'[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
|
||
'\\ |': 220, '\' "': 222,
|
||
'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
|
||
'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
|
||
'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
|
||
'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
|
||
'f8': 119, 'f9': 120, 'f10': 121, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
|
||
'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
|
||
'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
|
||
'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
|
||
'insert': 45, 'delete': 46, 'numlock': 144,
|
||
};
|
||
|
||
// These apply to Firefox and Opera
|
||
var _mozilla_keycodes = {
|
||
'; :': 59, '= +': 61, '- _': 173, 'meta': 224, 'minus':173
|
||
};
|
||
|
||
// This apply to Webkit and IE
|
||
var _ie_keycodes = {
|
||
'; :': 186, '= +': 187, '- _': 189, 'minus':189
|
||
};
|
||
|
||
var browser = utils.browser[0];
|
||
var platform = utils.platform;
|
||
|
||
if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
|
||
$.extend(_keycodes, _mozilla_keycodes);
|
||
} else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
|
||
$.extend(_keycodes, _ie_keycodes);
|
||
}
|
||
|
||
var keycodes = {};
|
||
var inv_keycodes = {};
|
||
for (var name in _keycodes) {
|
||
var names = name.split(' ');
|
||
if (names.length === 1) {
|
||
var n = names[0];
|
||
keycodes[n] = _keycodes[n];
|
||
inv_keycodes[_keycodes[n]] = n;
|
||
} else {
|
||
var primary = names[0];
|
||
var secondary = names[1];
|
||
keycodes[primary] = _keycodes[name];
|
||
keycodes[secondary] = _keycodes[name];
|
||
inv_keycodes[_keycodes[name]] = primary;
|
||
}
|
||
}
|
||
|
||
var normalize_key = function (key) {
|
||
return inv_keycodes[keycodes[key]];
|
||
};
|
||
|
||
var normalize_shortcut = function (shortcut) {
|
||
/**
|
||
* @function _normalize_shortcut
|
||
* @private
|
||
* return a dict containing the normalized shortcut and the number of time it should be pressed:
|
||
*
|
||
* Put a shortcut into normalized form:
|
||
* 1. Make lowercase
|
||
* 2. Replace cmd by meta
|
||
* 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
|
||
* 4. Normalize keys
|
||
**/
|
||
if (platform === 'MacOS') {
|
||
shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'cmd-');
|
||
} else {
|
||
shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'ctrl-');
|
||
}
|
||
|
||
shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
|
||
shortcut = shortcut.replace(/-$/, 'minus'); // catch shortcuts using '-' key
|
||
shortcut = shortcut.replace(/,$/, 'comma'); // catch shortcuts using '-' key
|
||
if(shortcut.indexOf(',') !== -1){
|
||
var sht = shortcut.split(',');
|
||
sht = _.map(sht, normalize_shortcut);
|
||
return shortcut;
|
||
}
|
||
shortcut = shortcut.replace(/comma/g, ','); // catch shortcuts using '-' key
|
||
var values = shortcut.split("-");
|
||
if (values.length === 1) {
|
||
return normalize_key(values[0]);
|
||
} else {
|
||
var modifiers = values.slice(0,-1);
|
||
var key = normalize_key(values[values.length-1]);
|
||
modifiers.sort();
|
||
return modifiers.join('-') + '-' + key;
|
||
}
|
||
};
|
||
|
||
var shortcut_to_event = function (shortcut, type) {
|
||
/**
|
||
* Convert a shortcut (shift-r) to a jQuery Event object
|
||
**/
|
||
type = type || 'keydown';
|
||
shortcut = normalize_shortcut(shortcut);
|
||
shortcut = shortcut.replace(/-$/, 'minus'); // catch shortcuts using '-' key
|
||
var values = shortcut.split("-");
|
||
var modifiers = values.slice(0,-1);
|
||
var key = values[values.length-1];
|
||
var opts = {which: keycodes[key]};
|
||
if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
|
||
if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
|
||
if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
|
||
if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
|
||
return $.Event(type, opts);
|
||
};
|
||
|
||
var only_modifier_event = function(event){
|
||
/**
|
||
* Return `true` if the event only contains modifiers keys.
|
||
* false otherwise
|
||
**/
|
||
var key = inv_keycodes[event.which];
|
||
return ((event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) &&
|
||
(key === 'alt'|| key === 'ctrl'|| key === 'meta'|| key === 'shift'));
|
||
|
||
};
|
||
|
||
var event_to_shortcut = function (event) {
|
||
/**
|
||
* Convert a jQuery Event object to a normalized shortcut string (shift-r)
|
||
**/
|
||
var shortcut = '';
|
||
var key = inv_keycodes[event.which];
|
||
if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
|
||
if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
|
||
if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
|
||
if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
|
||
shortcut += key;
|
||
return shortcut;
|
||
};
|
||
|
||
// Shortcut manager class
|
||
|
||
var ShortcutManager = function (delay, events, actions, env, config, mode) {
|
||
/**
|
||
* A class to deal with keyboard event and shortcut
|
||
*
|
||
* @class ShortcutManager
|
||
* @constructor
|
||
*
|
||
* :config: configobjet on which to call `update(....)` to persist the config.
|
||
* :mode: mode of this shortcut manager where to persist config.
|
||
*/
|
||
mode = mode || 'command';
|
||
this._shortcuts = {};
|
||
this._defaults_bindings = [];
|
||
this.delay = delay || 800; // delay in milliseconds
|
||
this.events = events;
|
||
this.actions = actions;
|
||
this.actions.extend_env(env);
|
||
this._queue = [];
|
||
this._cleartimeout = null;
|
||
this._config = config;
|
||
this._mode = mode;
|
||
Object.seal(this);
|
||
};
|
||
|
||
ShortcutManager.prototype.clearsoon = function(){
|
||
/**
|
||
* Clear the pending shortcut soon, and cancel previous clearing
|
||
* that might be registered.
|
||
**/
|
||
var that = this;
|
||
clearTimeout(this._cleartimeout);
|
||
this._cleartimeout = setTimeout(function(){that.clearqueue();}, this.delay);
|
||
};
|
||
|
||
|
||
ShortcutManager.prototype.clearqueue = function(){
|
||
/**
|
||
* clear the pending shortcut sequence now.
|
||
**/
|
||
this._queue = [];
|
||
clearTimeout(this._cleartimeout);
|
||
};
|
||
|
||
|
||
var flatten_shorttree = function(tree){
|
||
/**
|
||
* Flatten a tree of shortcut sequences.
|
||
* use full to iterate over all the key/values of available shortcuts.
|
||
**/
|
||
var dct = {};
|
||
_.forEach(tree, function(value, key) {
|
||
if(typeof(value) === 'string'){
|
||
dct[key] = value;
|
||
} else {
|
||
var ftree=flatten_shorttree(value);
|
||
_.forEach(ftree, function(v2, subkey) {
|
||
dct[key+','+subkey] = ftree[subkey];
|
||
});
|
||
}
|
||
});
|
||
return dct;
|
||
};
|
||
|
||
|
||
ShortcutManager.prototype.get_action_shortcuts = function(name){
|
||
var ftree = flatten_shorttree(this._shortcuts);
|
||
var res = [];
|
||
_.forEach(ftree, function(value, key) {
|
||
if(value === name){
|
||
res.push(key);
|
||
}
|
||
});
|
||
return res;
|
||
};
|
||
|
||
ShortcutManager.prototype.get_action_shortcut = function(name){
|
||
var matches = this.get_action_shortcuts(name);
|
||
if (matches.length > 0) {
|
||
return matches[0];
|
||
}
|
||
return undefined;
|
||
};
|
||
|
||
ShortcutManager.prototype.help = function () {
|
||
var that = this;
|
||
var help = [];
|
||
var ftree = flatten_shorttree(this._shortcuts);
|
||
_.forEach(ftree, function(value, key) {
|
||
var action = that.actions.get(value);
|
||
var help_string = action.help||'== no help ==';
|
||
var help_index = action.help_index;
|
||
if (help_string) {
|
||
var shortstring = (action.shortstring||key);
|
||
help.push({
|
||
shortcut: shortstring,
|
||
help: help_string,
|
||
help_index: help_index}
|
||
);
|
||
}
|
||
});
|
||
help.sort(function (a, b) {
|
||
if (a.help_index === b.help_index) {
|
||
if (a.shortcut === b.shortcut) {
|
||
return 0;
|
||
}
|
||
if (a.shortcut > b.shortcut) {
|
||
return 1;
|
||
}
|
||
return -1;
|
||
}
|
||
if (a.help_index === undefined || a.help_index > b.help_index){
|
||
return 1;
|
||
}
|
||
return -1;
|
||
});
|
||
return help;
|
||
};
|
||
|
||
ShortcutManager.prototype.clear_shortcuts = function () {
|
||
this._shortcuts = {};
|
||
};
|
||
|
||
ShortcutManager.prototype.get_shortcut = function (shortcut){
|
||
/**
|
||
* return a node of the shortcut tree which an action name (string) if leaf,
|
||
* and an object with `object.subtree===true`
|
||
**/
|
||
if(typeof(shortcut) === 'string'){
|
||
shortcut = shortcut.split(',');
|
||
}
|
||
|
||
return this._get_leaf(shortcut, this._shortcuts);
|
||
};
|
||
|
||
|
||
ShortcutManager.prototype._get_leaf = function(shortcut_array, tree){
|
||
/**
|
||
* @private
|
||
* find a leaf/node in a subtree of the keyboard shortcut
|
||
*
|
||
**/
|
||
if(shortcut_array.length === 1){
|
||
return tree[shortcut_array[0]];
|
||
} else if( typeof(tree[shortcut_array[0]]) !== 'string'){
|
||
return this._get_leaf(shortcut_array.slice(1), tree[shortcut_array[0]]);
|
||
}
|
||
return null;
|
||
};
|
||
|
||
ShortcutManager.prototype.set_shortcut = function( shortcut, action_name){
|
||
if( typeof(action_name) !== 'string'){throw new Error('action is not a string', action_name);}
|
||
if( typeof(shortcut) === 'string'){
|
||
shortcut = shortcut.split(',');
|
||
}
|
||
return this._set_leaf(shortcut, action_name, this._shortcuts);
|
||
};
|
||
|
||
ShortcutManager.prototype._is_leaf = function(shortcut_array, tree){
|
||
if(shortcut_array.length === 1){
|
||
return(typeof(tree[shortcut_array[0]]) === 'string');
|
||
} else {
|
||
var subtree = tree[shortcut_array[0]];
|
||
return this._is_leaf(shortcut_array.slice(1), subtree );
|
||
}
|
||
};
|
||
|
||
ShortcutManager.prototype._remove_leaf = function(shortcut_array, tree, allow_node){
|
||
if(shortcut_array.length === 1){
|
||
var current_node = tree[shortcut_array[0]];
|
||
if(typeof(current_node) === 'string'){
|
||
delete tree[shortcut_array[0]];
|
||
} else {
|
||
throw new Error('try to delete non-leaf');
|
||
}
|
||
} else {
|
||
this._remove_leaf(shortcut_array.slice(1), tree[shortcut_array[0]], allow_node);
|
||
if(_.keys(tree[shortcut_array[0]]).length === 0){
|
||
delete tree[shortcut_array[0]];
|
||
}
|
||
}
|
||
};
|
||
|
||
ShortcutManager.prototype.is_available_shortcut = function(shortcut){
|
||
var shortcut_array = shortcut.split(',');
|
||
return this._is_available_shortcut(shortcut_array, this._shortcuts);
|
||
};
|
||
|
||
ShortcutManager.prototype._is_available_shortcut = function(shortcut_array, tree){
|
||
var current_node = tree[shortcut_array[0]];
|
||
if(!shortcut_array[0]){
|
||
return false;
|
||
}
|
||
if(current_node === undefined){
|
||
return true;
|
||
} else {
|
||
if (typeof(current_node) === 'string'){
|
||
return false;
|
||
} else { // assume is a sub-shortcut tree
|
||
return this._is_available_shortcut(shortcut_array.slice(1), current_node);
|
||
}
|
||
}
|
||
};
|
||
|
||
ShortcutManager.prototype._set_leaf = function(shortcut_array, action_name, tree){
|
||
var current_node = tree[shortcut_array[0]];
|
||
|
||
if(shortcut_array.length === 1){
|
||
if(current_node !== undefined && typeof(current_node) !== 'string'){
|
||
console.warn('[warning], you are overriting a long shortcut with a shorter one');
|
||
}
|
||
tree[shortcut_array[0]] = action_name;
|
||
return true;
|
||
} else {
|
||
if(typeof(current_node) === 'string'){
|
||
console.warn('you are trying to set a shortcut that will be shadowed'+
|
||
'by a more specific one. Aborting for :', action_name, 'the following '+
|
||
'will take precedence', current_node);
|
||
return false;
|
||
} else {
|
||
tree[shortcut_array[0]] = tree[shortcut_array[0]]||{};
|
||
}
|
||
this._set_leaf(shortcut_array.slice(1), action_name, tree[shortcut_array[0]]);
|
||
return true;
|
||
}
|
||
};
|
||
|
||
ShortcutManager.prototype._persist_shortcut = function(shortcut, data) {
|
||
/**
|
||
* add a shortcut to this manager and persist it to the config file.
|
||
**/
|
||
shortcut = shortcut.toLowerCase();
|
||
this.add_shortcut(shortcut, data);
|
||
var patch = {keys:{}};
|
||
patch.keys[this._mode] = {bind:{}};
|
||
patch.keys[this._mode].bind[shortcut] = data;
|
||
this._config.update(patch);
|
||
};
|
||
|
||
ShortcutManager.prototype._persist_remove_shortcut = function(shortcut){
|
||
/**
|
||
* Remove a shortcut from this manager and persist its removal.
|
||
*/
|
||
|
||
shortcut = shortcut.toLowerCase();
|
||
this.remove_shortcut(shortcut);
|
||
var patch = {keys: {}};
|
||
patch.keys[this._mode] = {bind:{}};
|
||
patch.keys[this._mode].bind[shortcut] = null;
|
||
this._config.update(patch);
|
||
|
||
// if the shortcut we unbind is a default one, we add it to the list of
|
||
// things to unbind at startup
|
||
if( this._defaults_bindings.indexOf(shortcut) !== -1 ){
|
||
var cnf = (this._config.data.keys || {})[this._mode];
|
||
var unbind_array = cnf.unbind || [];
|
||
|
||
|
||
// unless it's already there (like if we have remapped a default
|
||
// shortcut to another command): unbind it)
|
||
if(unbind_array.indexOf(shortcut) === -1){
|
||
var _parray = unbind_array.concat(shortcut);
|
||
var unbind_patch = {keys:{}};
|
||
unbind_patch.keys[this._mode] = {unbind:_parray};
|
||
console.warn('up:', unbind_patch);
|
||
this._config.update(unbind_patch);
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
|
||
/**
|
||
* Add an action to be handled by shortcut manager.
|
||
*
|
||
* - `shortcut` should be a `Shortcut Sequence` of the for `Ctrl-Alt-C,Meta-X`...
|
||
* - `data` could be an `action name`, an `action` or a `function`.
|
||
* if a `function` is passed it will be converted to an anonymous `action`.
|
||
*
|
||
**/
|
||
var action_name = this.actions.get_name(data);
|
||
if (! action_name){
|
||
if (typeof data === 'string') {
|
||
// If we have an action name, allow it to be bound anyway.
|
||
console.log("Unknown action '" + data + "' for shortcut " + shortcut
|
||
+ "; it may be defined by an extension which is not yet loaded.");
|
||
action_name = data;
|
||
} else {
|
||
throw new Error('does not know how to deal with : ' + data);
|
||
}
|
||
}
|
||
var _shortcut = normalize_shortcut(shortcut);
|
||
this.set_shortcut(_shortcut, action_name);
|
||
|
||
if (!suppress_help_update) {
|
||
// update the keyboard shortcuts notebook help
|
||
this.events.trigger('rebuild.QuickHelp');
|
||
}
|
||
};
|
||
|
||
ShortcutManager.prototype.add_shortcuts = function (data) {
|
||
/**
|
||
* Convenient methods to call `add_shortcut(key, value)` on several items
|
||
*
|
||
* data : Dict of the form {key:value, ...}
|
||
**/
|
||
var that = this;
|
||
_.forEach(data, function(value, key) {
|
||
that.add_shortcut(key, value, true);
|
||
});
|
||
// update the keyboard shortcuts notebook help
|
||
this.events.trigger('rebuild.QuickHelp');
|
||
};
|
||
|
||
ShortcutManager.prototype._add_default_shortcuts = function (data) {
|
||
/**
|
||
* same as add_shortcuts, but register them as "default" that if persistently unbound, with
|
||
* persist_remove_shortcut, need to be on the "unbind" list.
|
||
**/
|
||
this._defaults_bindings = this._defaults_bindings.concat(Object.keys(data));
|
||
this.add_shortcuts(data);
|
||
|
||
};
|
||
|
||
ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
|
||
/**
|
||
* Remove the binding of shortcut `shortcut` with its action.
|
||
* throw an error if trying to remove a non-exiting shortcut
|
||
**/
|
||
if(!shortcut){
|
||
console.warn('trying to remove empty shortcut');
|
||
return;
|
||
}
|
||
shortcut = normalize_shortcut(shortcut);
|
||
if( typeof(shortcut) === 'string'){
|
||
shortcut = shortcut.split(',');
|
||
}
|
||
/*
|
||
* The shortcut error should be explicit here, because it will be
|
||
* seen by users.
|
||
*/
|
||
try {
|
||
this._remove_leaf(shortcut, this._shortcuts);
|
||
if (!suppress_help_update) {
|
||
// update the keyboard shortcuts notebook help
|
||
this.events.trigger('rebuild.QuickHelp');
|
||
}
|
||
} catch (ex) {
|
||
throw new Error('trying to remove a non-existent shortcut', shortcut, typeof shortcut);
|
||
}
|
||
};
|
||
|
||
|
||
|
||
ShortcutManager.prototype.call_handler = function (event) {
|
||
/**
|
||
* Call the corresponding shortcut handler for a keyboard event
|
||
* @method call_handler
|
||
* @return {Boolean} `true|false`, `false` if no handler was found, otherwise the value return by the handler.
|
||
* @param event {event}
|
||
*
|
||
* given an event, call the corresponding shortcut.
|
||
* return false is event wan handled, true otherwise
|
||
* in any case returning false stop event propagation
|
||
**/
|
||
|
||
|
||
this.clearsoon();
|
||
if(only_modifier_event(event)){
|
||
return true;
|
||
}
|
||
var shortcut = event_to_shortcut(event);
|
||
this._queue.push(shortcut);
|
||
var action_name = this.get_shortcut(this._queue);
|
||
|
||
if (typeof(action_name) === 'undefined'|| action_name === null){
|
||
this.clearqueue();
|
||
return true;
|
||
}
|
||
|
||
if (this.actions.exists(action_name)) {
|
||
event.preventDefault();
|
||
this.clearqueue();
|
||
return this.actions.call(action_name, event);
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
|
||
ShortcutManager.prototype.handles = function (event) {
|
||
var shortcut = event_to_shortcut(event);
|
||
var action_name = this.get_shortcut(this._queue.concat(shortcut));
|
||
return (typeof(action_name) !== 'undefined');
|
||
};
|
||
|
||
return {
|
||
keycodes : keycodes,
|
||
inv_keycodes : inv_keycodes,
|
||
ShortcutManager : ShortcutManager,
|
||
normalize_key : normalize_key,
|
||
normalize_shortcut : normalize_shortcut,
|
||
shortcut_to_event : shortcut_to_event,
|
||
event_to_shortcut : event_to_shortcut,
|
||
};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('bidi/numericshaping',[],
|
||
function(bidi) {
|
||
"use strict";
|
||
|
||
var regex = /([0-9])|([\u0660-\u0669])|([\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FF\u0750-\u077F\u08A0-\u08E3\u200F\u202B\u202E\u2067\uFB50-\uFD3D\uFD40-\uFDCF\uFDF0-\uFDFC\uFDFE-\uFDFF\uFE70-\uFEFE]+)|([^0-9\u0660-\u0669\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FF\u0750-\u077F\u08A0-\u08E3\u200F\u202B\u202E\u2067\uFB50-\uFD3D\uFD40-\uFDCF\uFDF0-\uFDFC\uFDFE-\uFDFF\uFE70-\uFEFE\u0600-\u0607\u0609-\u060A\u060C\u060E-\u061A\u064B-\u066C\u0670\u06D6-\u06E4\u06E7-\u06ED\u06F0-\u06F9\u08E4-\u08FF\uFD3E-\uFD3F\uFDD0-\uFDEF\uFDFD\uFEFF\u0000-\u0040\u005B-\u0060\u007B-\u007F\u0080-\u00A9\u00AB-\u00B4\u00B6-\u00B9\u00BB-\u00BF\u00D7\u00F7\u02B9-\u02BA\u02C2-\u02CF\u02D2-\u02DF\u02E5-\u02ED\u02EF-\u02FF\u2070\u2074-\u207E\u2080-\u208E\u2100-\u2101\u2103-\u2106\u2108-\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A-\u213B\u2140-\u2144\u214A-\u214D\u2150-\u215F\u2189\uA720-\uA721\uA788\uFF01-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\uFFE0-\uFFE6\uFFE8-\uFFEE]+)/g;
|
||
|
||
var shape = function(text, shaperType) {
|
||
text = text.toString();
|
||
if (!text) {
|
||
return text;
|
||
}
|
||
switch (shaperType) {
|
||
case "defaultNumeral":
|
||
return _shapeEuropean(text);
|
||
case "national":
|
||
return _shapeArabic(text);
|
||
default:
|
||
return text;
|
||
}
|
||
};
|
||
|
||
var _shapeEuropean = function(text) {
|
||
return text.replace(/[\u0660-\u0669]/g, function(c) {
|
||
return c.charCodeAt(0) - 1632;
|
||
});
|
||
};
|
||
|
||
var _shapeArabic = function(text) {
|
||
return text.replace(/[0-9]/g, function(c) {
|
||
return String.fromCharCode(parseInt(c) + 1632);
|
||
});
|
||
};
|
||
|
||
var numericshaping = {
|
||
shapeNumerals : shape
|
||
};
|
||
|
||
return numericshaping;
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('bidi/bidi',['bidi/numericshaping'], function(numericshaping) {
|
||
'use strict';
|
||
|
||
var shaperType = '';
|
||
|
||
var _uiLang = function() {
|
||
return navigator.language.toLowerCase();
|
||
};
|
||
|
||
var _loadLocale = function() {
|
||
if (_isMirroringEnabled()) {
|
||
document.body.dir = 'rtl';
|
||
}
|
||
|
||
requirejs(['moment'], function (moment) {
|
||
console.log('Loaded moment locale', moment.locale(_uiLang()));
|
||
});
|
||
|
||
shaperType = _uiLang().split('-')[0] == 'ar' ? 'national' : 'defaultNumeral';
|
||
};
|
||
|
||
var _isMirroringEnabled = function() {
|
||
return new RegExp('^(ar|ara|arc|ae|ave|egy|he|heb|nqo|pal|phn|sam|syc|syr|fa|per|fas|ckb|ur|urd)').test(_uiLang());
|
||
};
|
||
|
||
/**
|
||
* @param value : the string to apply the bidi-support on it.
|
||
* @param flag :indicates the type of bidi-support (Numeric-shaping ,Base-text-dir ).
|
||
*/
|
||
var _applyBidi = function(value /*, flag*/) {
|
||
value = numericshaping.shapeNumerals(value, shaperType);
|
||
return value;
|
||
};
|
||
|
||
var bidi = {
|
||
applyBidi: _applyBidi,
|
||
isMirroringEnabled: _isMirroringEnabled,
|
||
loadLocale: _loadLocale,
|
||
};
|
||
|
||
return bidi;
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('edit/js/savewidget',[
|
||
'jquery',
|
||
'base/js/utils',
|
||
'base/js/dialog',
|
||
'base/js/keyboard',
|
||
'moment',
|
||
'bidi/bidi',
|
||
], function($, utils, dialog, keyboard, moment, bidi) {
|
||
"use strict";
|
||
|
||
var SaveWidget = function (selector, options) {
|
||
this.editor = undefined;
|
||
this.selector = selector;
|
||
this.events = options.events;
|
||
this.editor = options.editor;
|
||
this._last_modified = undefined;
|
||
this._filename = undefined;
|
||
this.keyboard_manager = options.keyboard_manager;
|
||
if (this.selector !== undefined) {
|
||
this.element = $(selector);
|
||
this.bind_events();
|
||
}
|
||
};
|
||
|
||
|
||
SaveWidget.prototype.bind_events = function () {
|
||
var that = this;
|
||
this.element.find('span.filename').click(function () {
|
||
that.rename();
|
||
});
|
||
this.events.on('save_status_clean.Editor', function (evt) {
|
||
that.update_document_title();
|
||
});
|
||
this.events.on('save_status_dirty.Editor', function (evt) {
|
||
that.update_document_title(undefined, true);
|
||
});
|
||
this.events.on('file_loaded.Editor', function (evt, model) {
|
||
that.update_filename(model.name);
|
||
that.update_document_title(model.name);
|
||
that.update_last_modified(model.last_modified);
|
||
});
|
||
this.events.on('file_saved.Editor', function (evt, model) {
|
||
that.update_filename(model.name);
|
||
that.update_document_title(model.name);
|
||
that.update_last_modified(model.last_modified);
|
||
});
|
||
this.events.on('file_renamed.Editor', function (evt, model) {
|
||
that.update_filename(model.name);
|
||
that.update_document_title(model.name);
|
||
that.update_address_bar(model.path);
|
||
});
|
||
this.events.on('file_save_failed.Editor', function () {
|
||
that.set_save_status('Save Failed!');
|
||
});
|
||
};
|
||
|
||
|
||
SaveWidget.prototype.rename = function (options) {
|
||
options = options || {};
|
||
var that = this;
|
||
var dialog_body = $('<div/>').append(
|
||
$("<p/>").addClass("rename-message")
|
||
.text('Enter a new filename:')
|
||
).append(
|
||
$("<br/>")
|
||
).append(
|
||
$('<input/>').attr('type','text').attr('size','25').addClass('form-control')
|
||
.val(that.editor.get_filename())
|
||
);
|
||
var d = dialog.modal({
|
||
title: "Rename File",
|
||
body: dialog_body,
|
||
default_button: "Cancel",
|
||
buttons : {
|
||
"Cancel": {},
|
||
"OK": {
|
||
class: "btn-primary",
|
||
click: function () {
|
||
var new_name = d.find('input').val();
|
||
if (!new_name) {
|
||
// Reset the message
|
||
d.find('.rename-message').text("Enter a new filename:");
|
||
return false;
|
||
}
|
||
d.find('.rename-message').text("Renaming...");
|
||
d.find('input[type="text"]').prop('disabled', true);
|
||
that.editor.rename(new_name).then(
|
||
function () {
|
||
d.modal('hide');
|
||
}, function (error) {
|
||
d.find('.rename-message').text(error.message || 'Unknown error');
|
||
d.find('input[type="text"]').prop('disabled', false).focus().select();
|
||
}
|
||
);
|
||
return false;
|
||
}
|
||
}
|
||
},
|
||
open : function () {
|
||
// Upon ENTER, click the OK button.
|
||
d.find('input[type="text"]').keydown(function (event) {
|
||
if (event.which === keyboard.keycodes.enter) {
|
||
d.find('.btn-primary').first().click();
|
||
return false;
|
||
}
|
||
});
|
||
d.find('input[type="text"]').focus().select();
|
||
}
|
||
});
|
||
};
|
||
|
||
|
||
SaveWidget.prototype.update_filename = function (filename) {
|
||
filename = bidi.applyBidi(filename);
|
||
this.element.find('span.filename').text(filename);
|
||
};
|
||
|
||
SaveWidget.prototype.update_document_title = function (filename, dirty) {
|
||
if(filename){
|
||
this._filename = filename;
|
||
}
|
||
document.title = (dirty ? '*' : '') + this._filename + ' - Jupyter Text Editor';
|
||
};
|
||
|
||
SaveWidget.prototype.update_address_bar = function (path) {
|
||
var state = {path : path};
|
||
window.history.replaceState(state, "", utils.url_path_join(
|
||
this.editor.base_url,
|
||
"edit",
|
||
utils.encode_uri_components(path)
|
||
));
|
||
};
|
||
|
||
SaveWidget.prototype.update_last_modified = function (last_modified) {
|
||
if (last_modified) {
|
||
this._last_modified = new Date(last_modified);
|
||
} else {
|
||
this._last_modified = null;
|
||
}
|
||
this._render_last_modified();
|
||
};
|
||
|
||
SaveWidget.prototype._render_last_modified = function () {
|
||
/** actually set the text in the element, from our _last_modified value
|
||
|
||
called directly, and periodically in timeouts.
|
||
*/
|
||
this._schedule_render_last_modified();
|
||
var el = this.element.find('span.last_modified');
|
||
if (!this._last_modified) {
|
||
el.text('').attr('title', 'never saved');
|
||
return;
|
||
}
|
||
var chkd = moment(this._last_modified);
|
||
var long_date = chkd.format('llll');
|
||
var human_date;
|
||
var tdelta = Math.ceil(new Date() - this._last_modified);
|
||
if (tdelta < utils.time.milliseconds.d){
|
||
// less than 24 hours old, use relative date
|
||
human_date = chkd.fromNow();
|
||
} else {
|
||
// otherwise show calendar
|
||
// <Today | yesterday|...> at hh,mm,ss
|
||
human_date = chkd.calendar();
|
||
}
|
||
el.text(human_date).attr('title', long_date);
|
||
};
|
||
|
||
SaveWidget.prototype._schedule_render_last_modified = function () {
|
||
/** schedule the next update to relative date
|
||
|
||
periodically updated, so short values like 'a few seconds ago' don't get stale.
|
||
*/
|
||
if (!this._last_modified) {
|
||
return;
|
||
}
|
||
if ((this._last_modified_timeout)) {
|
||
clearTimeout(this._last_modified_timeout);
|
||
}
|
||
var dt = Math.ceil(new Date() - this._last_modified);
|
||
this._last_modified_timeout = setTimeout(
|
||
$.proxy(this._render_last_modified, this),
|
||
utils.time.timeout_from_dt(dt)
|
||
);
|
||
};
|
||
|
||
return {'SaveWidget': SaveWidget};
|
||
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('base/js/notificationwidget',['jquery'], function($) {
|
||
"use strict";
|
||
|
||
/**
|
||
* Construct a NotificationWidget object.
|
||
*
|
||
* @constructor
|
||
* @param {string} selector - a jQuery selector string for the
|
||
* notification widget element
|
||
*/
|
||
var NotificationWidget = function (selector) {
|
||
this.selector = selector;
|
||
this.timeout = null;
|
||
this.busy = false;
|
||
if (this.selector !== undefined) {
|
||
this.element = $(selector);
|
||
this.style();
|
||
}
|
||
this.element.hide();
|
||
this.inner = $('<span/>');
|
||
this.element.append(this.inner);
|
||
};
|
||
|
||
/**
|
||
* Add the 'notification_widget' CSS class to the widget element.
|
||
*
|
||
* @method style
|
||
*/
|
||
NotificationWidget.prototype.style = function () {
|
||
// use explicit bootstrap classes here,
|
||
// because multiple inheritance in LESS doesn't work
|
||
// for this particular combination
|
||
this.element.addClass('notification_widget btn btn-xs navbar-btn');
|
||
};
|
||
|
||
/**
|
||
* hide the widget and empty the text
|
||
**/
|
||
NotificationWidget.prototype.hide = function () {
|
||
var that = this;
|
||
this.element.fadeOut(100, function(){that.inner.text('');});
|
||
};
|
||
|
||
/**
|
||
* Set the notification widget message to display for a certain
|
||
* amount of time (timeout). The widget will be shown forever if
|
||
* timeout is <= 0 or undefined. If the widget is clicked while it
|
||
* is still displayed, execute an optional callback
|
||
* (click_callback). If the callback returns false, it will
|
||
* prevent the notification from being dismissed.
|
||
*
|
||
* Options:
|
||
* class - CSS class name for styling
|
||
* icon - CSS class name for the widget icon
|
||
* title - HTML title attribute for the widget
|
||
*
|
||
* @method set_message
|
||
* @param {string} msg - The notification to display
|
||
* @param {integer} [timeout] - The amount of time in milliseconds to display the widget
|
||
* @param {function} [click_callback] - The function to run when the widget is clicked
|
||
* @param {Object} [options] - Additional options
|
||
*/
|
||
NotificationWidget.prototype.set_message = function (msg, timeout, click_callback, options) {
|
||
options = options || {};
|
||
|
||
// unbind potential previous callback
|
||
this.element.unbind('click');
|
||
this.inner.attr('class', options.icon);
|
||
this.inner.attr('title', options.title);
|
||
this.inner.text(msg);
|
||
this.element.fadeIn(100);
|
||
|
||
// reset previous set style
|
||
this.element.removeClass();
|
||
this.style();
|
||
if (options.class) {
|
||
this.element.addClass(options.class);
|
||
}
|
||
|
||
// clear previous timer
|
||
if (this.timeout !== null) {
|
||
clearTimeout(this.timeout);
|
||
this.timeout = null;
|
||
}
|
||
|
||
// set the timer if a timeout is given
|
||
var that = this;
|
||
if (timeout !== undefined && timeout >= 0) {
|
||
this.timeout = setTimeout(function () {
|
||
that.element.fadeOut(100, function () {that.inner.text('');});
|
||
that.element.unbind('click');
|
||
that.timeout = null;
|
||
}, timeout);
|
||
}
|
||
|
||
// if no click callback assume we will just dismiss the notification
|
||
if (click_callback === undefined) {
|
||
click_callback = function(){return true};
|
||
}
|
||
// on click, remove widget if click callback say so
|
||
// and unbind click event.
|
||
this.element.click(function () {
|
||
if (click_callback() !== false) {
|
||
that.element.fadeOut(100, function () {that.inner.text('');});
|
||
that.element.unbind('click');
|
||
}
|
||
if (that.timeout !== null) {
|
||
clearTimeout(that.timeout);
|
||
that.timeout = null;
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Display an information message (styled with the 'info'
|
||
* class). Arguments are the same as in set_message. Default
|
||
* timeout is 3500 milliseconds.
|
||
*
|
||
* @method info
|
||
*/
|
||
NotificationWidget.prototype.info = function (msg, timeout, click_callback, options) {
|
||
options = options || {};
|
||
options.class = options.class + ' info';
|
||
timeout = timeout || 3500;
|
||
this.set_message(msg, timeout, click_callback, options);
|
||
};
|
||
|
||
/**
|
||
* Display a warning message (styled with the 'warning'
|
||
* class). Arguments are the same as in set_message. Messages are
|
||
* sticky by default.
|
||
*
|
||
* @method warning
|
||
*/
|
||
NotificationWidget.prototype.warning = function (msg, timeout, click_callback, options) {
|
||
options = options || {};
|
||
options.class = options.class + ' warning';
|
||
this.set_message(msg, timeout, click_callback, options);
|
||
};
|
||
|
||
/**
|
||
* Display a danger message (styled with the 'danger'
|
||
* class). Arguments are the same as in set_message. Messages are
|
||
* sticky by default.
|
||
*
|
||
* @method danger
|
||
*/
|
||
NotificationWidget.prototype.danger = function (msg, timeout, click_callback, options) {
|
||
options = options || {};
|
||
options.class = options.class + ' danger';
|
||
this.set_message(msg, timeout, click_callback, options);
|
||
};
|
||
|
||
/**
|
||
* Get the text of the widget message.
|
||
*
|
||
* @method get_message
|
||
* @return {string} - the message text
|
||
*/
|
||
NotificationWidget.prototype.get_message = function () {
|
||
return this.inner.html();
|
||
};
|
||
|
||
return {'NotificationWidget': NotificationWidget};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('base/js/notificationarea',[
|
||
'jquery',
|
||
'base/js/notificationwidget',
|
||
], function($, notificationwidget) {
|
||
"use strict";
|
||
|
||
// store reference to the NotificationWidget class
|
||
var NotificationWidget = notificationwidget.NotificationWidget;
|
||
|
||
/**
|
||
* Construct the NotificationArea object. Options are:
|
||
* events: $(Events) instance
|
||
* save_widget: SaveWidget instance
|
||
* notebook: Notebook instance
|
||
* keyboard_manager: KeyboardManager instance
|
||
*
|
||
* @constructor
|
||
* @param {string} selector - a jQuery selector string for the
|
||
* notification area element
|
||
* @param {Object} [options] - a dictionary of keyword arguments.
|
||
*/
|
||
var NotificationArea = function (selector, options) {
|
||
this.selector = selector;
|
||
this.events = options.events;
|
||
if (this.selector !== undefined) {
|
||
this.element = $(selector);
|
||
}
|
||
this.widget_dict = {};
|
||
};
|
||
|
||
/**
|
||
* Get a widget by name, creating it if it doesn't exist.
|
||
*
|
||
* @method widget
|
||
* @param {string} name - the widget name
|
||
*/
|
||
NotificationArea.prototype.widget = function (name) {
|
||
if (this.widget_dict[name] === undefined) {
|
||
return this.new_notification_widget(name);
|
||
}
|
||
return this.get_widget(name);
|
||
};
|
||
|
||
/**
|
||
* Get a widget by name, throwing an error if it doesn't exist.
|
||
*
|
||
* @method get_widget
|
||
* @param {string} name - the widget name
|
||
*/
|
||
NotificationArea.prototype.get_widget = function (name) {
|
||
if(this.widget_dict[name] === undefined) {
|
||
throw new Error('no widgets with this name');
|
||
}
|
||
return this.widget_dict[name];
|
||
};
|
||
|
||
/**
|
||
* Create a new notification widget with the given name. The
|
||
* widget must not already exist.
|
||
*
|
||
* @method new_notification_widget
|
||
* @param {string} name - the widget name
|
||
*/
|
||
NotificationArea.prototype.new_notification_widget = function (name) {
|
||
if (this.widget_dict[name] !== undefined) {
|
||
throw new Error('widget with that name already exists!');
|
||
}
|
||
|
||
// create the element for the notification widget and add it
|
||
// to the notification aread element
|
||
var div = $('<div/>').attr('id', 'notification_' + name);
|
||
$(this.selector).append(div);
|
||
|
||
// create the widget object and return it
|
||
this.widget_dict[name] = new NotificationWidget('#notification_' + name);
|
||
return this.widget_dict[name];
|
||
};
|
||
|
||
return {'NotificationArea': NotificationArea};
|
||
});
|
||
|
||
define('edit/js/notificationarea',[
|
||
'base/js/notificationarea'
|
||
], function(notificationarea) {
|
||
"use strict";
|
||
var NotificationArea = notificationarea.NotificationArea;
|
||
|
||
var EditorNotificationArea = function(selector, options) {
|
||
NotificationArea.apply(this, [selector, options]);
|
||
}
|
||
|
||
EditorNotificationArea.prototype = Object.create(NotificationArea.prototype);
|
||
|
||
/**
|
||
* Initialize the default set of notification widgets.
|
||
*
|
||
* @method init_notification_widgets
|
||
*/
|
||
EditorNotificationArea.prototype.init_notification_widgets = function () {
|
||
var that = this;
|
||
var savew = this.new_notification_widget('save');
|
||
|
||
this.events.on("file_saved.Editor", function() {
|
||
savew.set_message("File saved", 2000);
|
||
});
|
||
};
|
||
|
||
|
||
return {EditorNotificationArea: EditorNotificationArea};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
define('auth/js/loginwidget',[
|
||
'jquery',
|
||
'base/js/utils',
|
||
], function($, utils){
|
||
"use strict";
|
||
|
||
var LoginWidget = function (selector, options) {
|
||
options = options || {};
|
||
this.base_url = options.base_url || utils.get_body_data("baseUrl");
|
||
this.selector = selector;
|
||
if (this.selector !== undefined) {
|
||
this.element = $(selector);
|
||
this.bind_events();
|
||
}
|
||
};
|
||
|
||
|
||
LoginWidget.prototype.bind_events = function () {
|
||
var that = this;
|
||
this.element.find("button#logout").click(function () {
|
||
window.location = utils.url_path_join(
|
||
that.base_url,
|
||
"logout"
|
||
);
|
||
});
|
||
this.element.find("button#login").click(function () {
|
||
window.location = utils.url_path_join(
|
||
that.base_url,
|
||
"login"
|
||
);
|
||
});
|
||
};
|
||
|
||
return {'LoginWidget': LoginWidget};
|
||
});
|
||
|
||
// Copyright (c) Jupyter Development Team.
|
||
// Distributed under the terms of the Modified BSD License.
|
||
|
||
requirejs([
|
||
'jquery',
|
||
'contents',
|
||
'base/js/namespace',
|
||
'base/js/utils',
|
||
'base/js/page',
|
||
'base/js/events',
|
||
'services/config',
|
||
'edit/js/editor',
|
||
'edit/js/menubar',
|
||
'edit/js/savewidget',
|
||
'edit/js/notificationarea',
|
||
'bidi/bidi',
|
||
'auth/js/loginwidget',
|
||
], function(
|
||
$,
|
||
contents_service,
|
||
IPython,
|
||
utils,
|
||
page,
|
||
events,
|
||
configmod,
|
||
editmod,
|
||
menubar,
|
||
savewidget,
|
||
notificationarea,
|
||
bidi,
|
||
loginwidget,
|
||
){
|
||
"use strict";
|
||
|
||
try {
|
||
requirejs(['custom/custom'], function() {});
|
||
bidi.loadLocale();
|
||
} catch(err) {
|
||
console.log("Error loading custom.js from edition service. Continuing and logging");
|
||
console.warn(err);
|
||
}
|
||
|
||
page = new page.Page('div#header', 'div#site');
|
||
|
||
var base_url = utils.get_body_data('baseUrl');
|
||
var file_path = utils.get_body_data('filePath');
|
||
// This enables logout
|
||
var login_widget = new loginwidget.LoginWidget('#login_widget', {
|
||
base_url: base_url
|
||
});
|
||
var config = new configmod.ConfigSection('edit', {base_url: base_url});
|
||
config.load();
|
||
var common_config = new configmod.ConfigSection('common', {base_url: base_url});
|
||
common_config.load();
|
||
var contents = new contents_service.Contents({
|
||
base_url: base_url,
|
||
common_config: common_config
|
||
});
|
||
|
||
var editor = new editmod.Editor('#texteditor-container', {
|
||
base_url: base_url,
|
||
events: events,
|
||
contents: contents,
|
||
file_path: file_path,
|
||
config: config,
|
||
});
|
||
|
||
// Make it available for debugging
|
||
IPython.editor = editor;
|
||
|
||
var save_widget = new savewidget.SaveWidget('span#save_widget', {
|
||
editor: editor,
|
||
events: events,
|
||
});
|
||
|
||
var menus = new menubar.MenuBar('#menubar', {
|
||
base_url: base_url,
|
||
editor: editor,
|
||
events: events,
|
||
save_widget: save_widget,
|
||
});
|
||
|
||
var notification_area = new notificationarea.EditorNotificationArea(
|
||
'#notification_area', {
|
||
events: events,
|
||
});
|
||
editor.notification_area = notification_area;
|
||
notification_area.init_notification_widgets();
|
||
|
||
utils.load_extensions_from_config(config);
|
||
utils.load_extensions_from_config(common_config);
|
||
editor.load();
|
||
page.show();
|
||
|
||
window.onbeforeunload = function () {
|
||
if (editor.save_enabled && !editor.codemirror.isClean(editor.generation)) {
|
||
return "Unsaved changes will be lost. Close anyway?";
|
||
}
|
||
};
|
||
|
||
// Make sure the codemirror editor is sized appropriately.
|
||
var _handle_resize = function() {
|
||
var backdrop = $("#texteditor-backdrop");
|
||
|
||
// account for padding on the backdrop wrapper
|
||
var padding = backdrop.outerHeight(true) - backdrop.height();
|
||
$('div.CodeMirror').height($("#site").height() - padding);
|
||
};
|
||
$(window).resize(_handle_resize);
|
||
|
||
// On document ready, resize codemirror.
|
||
$(document).ready(_handle_resize);
|
||
});
|
||
|
||
define("edit/js/main", function(){});
|
||
|
||
|
||
//# sourceMappingURL=main.min.js.map |