@@ -4,7 +4,8 @@ | |||
"**/*.min.css", | |||
"**/*.min.js", | |||
"interface/css/d3evolution.css", | |||
"interface/css/nprogress.css" | |||
"interface/css/nprogress.css", | |||
"interface/css/prism.css" | |||
], | |||
"rules": { | |||
"at-rule-empty-line-before": null, |
@@ -0,0 +1,161 @@ | |||
/* PrismJS 1.20.0 | |||
https://prismjs.com/download.html#themes=prism-okaidia&languages=clike&plugins=show-invisibles */ | |||
/** | |||
* okaidia theme for JavaScript, CSS and HTML | |||
* Loosely based on Monokai textmate theme by http://www.monokai.nl/ | |||
* @author ocodia | |||
*/ | |||
code[class*="language-"], | |||
pre[class*="language-"] { | |||
color: #f8f8f2; | |||
background: none; | |||
text-shadow: 0 1px rgba(0, 0, 0, 0.3); | |||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; | |||
font-size: 1em; | |||
text-align: left; | |||
white-space: pre; | |||
word-spacing: normal; | |||
word-break: normal; | |||
word-wrap: normal; | |||
line-height: 1.5; | |||
-moz-tab-size: 4; | |||
-o-tab-size: 4; | |||
tab-size: 4; | |||
-webkit-hyphens: none; | |||
-moz-hyphens: none; | |||
-ms-hyphens: none; | |||
hyphens: none; | |||
} | |||
/* Code blocks */ | |||
pre[class*="language-"] { | |||
padding: 1em; | |||
margin: .5em 0; | |||
overflow: auto; | |||
border-radius: 0.3em; | |||
} | |||
:not(pre) > code[class*="language-"], | |||
pre[class*="language-"] { | |||
background: #272822; | |||
} | |||
/* Inline code */ | |||
:not(pre) > code[class*="language-"] { | |||
padding: .1em; | |||
border-radius: .3em; | |||
white-space: normal; | |||
} | |||
.token.comment, | |||
.token.prolog, | |||
.token.doctype, | |||
.token.cdata { | |||
color: #8292a2; | |||
} | |||
.token.punctuation { | |||
color: #f8f8f2; | |||
} | |||
.token.namespace { | |||
opacity: .7; | |||
} | |||
.token.property, | |||
.token.tag, | |||
.token.constant, | |||
.token.symbol, | |||
.token.deleted { | |||
color: #f92672; | |||
} | |||
.token.boolean, | |||
.token.number { | |||
color: #ae81ff; | |||
} | |||
.token.selector, | |||
.token.attr-name, | |||
.token.string, | |||
.token.char, | |||
.token.builtin, | |||
.token.inserted { | |||
color: #a6e22e; | |||
} | |||
.token.operator, | |||
.token.entity, | |||
.token.url, | |||
.language-css .token.string, | |||
.style .token.string, | |||
.token.variable { | |||
color: #f8f8f2; | |||
} | |||
.token.atrule, | |||
.token.attr-value, | |||
.token.function, | |||
.token.class-name { | |||
color: #e6db74; | |||
} | |||
.token.keyword { | |||
color: #66d9ef; | |||
} | |||
.token.regex, | |||
.token.important { | |||
color: #fd971f; | |||
} | |||
.token.important, | |||
.token.bold { | |||
font-weight: bold; | |||
} | |||
.token.italic { | |||
font-style: italic; | |||
} | |||
.token.entity { | |||
cursor: help; | |||
} | |||
.token.tab:not(:empty), | |||
.token.cr, | |||
.token.lf, | |||
.token.space { | |||
position: relative; | |||
} | |||
.token.tab:not(:empty):before, | |||
.token.cr:before, | |||
.token.lf:before, | |||
.token.space:before { | |||
color: #808080; | |||
opacity: 0.6; | |||
position: absolute; | |||
} | |||
.token.tab:not(:empty):before { | |||
content: '\21E5'; | |||
} | |||
.token.cr:before { | |||
content: '\240D'; | |||
} | |||
.token.crlf:before { | |||
content: '\240D\240A'; | |||
} | |||
.token.lf:before { | |||
content: '\240A'; | |||
} | |||
.token.space:before { | |||
content: '\00B7'; | |||
} | |||
@@ -285,9 +285,6 @@ table#symbolsTable input[type="number"] { | |||
background-color: #cddbff; | |||
} | |||
#map-textarea { | |||
height: 360px; | |||
} | |||
td.maps-cell { | |||
vertical-align: middle; | |||
} | |||
@@ -536,3 +533,32 @@ td.maps-cell { | |||
#clusterTable tr:last-child td:last-child { | |||
border-radius: 0 0 calc(.25rem - 1px) 0; | |||
} | |||
textarea#editor { | |||
height: calc(100vh - 178px); | |||
} | |||
.codejar-wrap { | |||
background: rgb(0, 47, 79); | |||
border-radius: 6px; | |||
max-height: calc(100vh - 178px); | |||
overflow-y: auto; | |||
} | |||
.codejar-linenumbers { | |||
background: rgba(255, 255, 255, 0.07) !important; | |||
bottom: unset !important; | |||
color: rgba(120, 120, 120, 1) !important; | |||
mix-blend-mode: unset !important; | |||
text-align: right; | |||
overflow: unset !important; | |||
} | |||
.editor { | |||
color: #fff; | |||
font-family: monospace; | |||
font-size: 14px; | |||
font-weight: 400; | |||
letter-spacing: normal; | |||
min-height: 1.5em; | |||
resize: unset !important; | |||
tab-size: 4; | |||
overflow-y: visible !important; | |||
} |
@@ -21,6 +21,7 @@ | |||
<link rel="stylesheet" type="text/css" href="./css/svg-with-js.min.css"> | |||
<link rel="stylesheet" type="text/css" href="./css/d3evolution.css"> | |||
<link rel="stylesheet" type="text/css" href="./css/nprogress.css"/> | |||
<link rel="stylesheet" type="text/css" href="./css/prism.css"/> | |||
<link href="./css/rspamd.css" rel="stylesheet"> | |||
</head> | |||
@@ -22,8 +22,8 @@ | |||
THE SOFTWARE. | |||
*/ | |||
define(["jquery"], | |||
function ($) { | |||
define(["jquery", "codejar", "linenumbers", "prism"], | |||
function ($, CodeJar, withLineNumbers, Prism) { | |||
"use strict"; | |||
var ui = {}; | |||
@@ -155,6 +155,22 @@ define(["jquery"], | |||
}; | |||
ui.setup = function (rspamd) { | |||
var jar = {}; | |||
// CodeJar requires ES6 | |||
var editor = window.CodeJar && | |||
// Required to restore cursor position | |||
(typeof window.getSelection().setBaseAndExtent === "function") | |||
? { | |||
codejar: true, | |||
elt: "div", | |||
class: "editor language-clike", | |||
} | |||
// Fallback to textarea if the browser does not support ES6 | |||
: { | |||
elt: "textarea", | |||
class: "form-control map-textarea", | |||
}; | |||
// Modal form for maps | |||
$(document).on("click", "[data-toggle=\"modal\"]", function () { | |||
var checked_server = rspamd.getSelector("selSrv"); | |||
@@ -176,10 +192,19 @@ define(["jquery"], | |||
} | |||
$("#modalDialog .modal-header").find("[data-fa-i2svg]").addClass(icon); | |||
$("#modalTitle").html(item.uri); | |||
$('<textarea id="map-textarea" class="form-control"' + readonly + | |||
$("<" + editor.elt + ' id="editor" class="' + editor.class + '"' + readonly + | |||
' data-id="' + item.map + '">' + | |||
text + | |||
"</textarea>").appendTo("#modalBody"); | |||
"</" + editor.elt + ">").appendTo("#modalBody"); | |||
if (editor.codejar) { | |||
jar = new CodeJar( | |||
document.querySelector("#editor"), | |||
withLineNumbers(Prism.highlightElement) | |||
); | |||
} | |||
$("#modalDialog").modal("show"); | |||
}, | |||
errorMessage: "Cannot receive maps data", | |||
@@ -188,7 +213,12 @@ define(["jquery"], | |||
return false; | |||
}); | |||
$("#modalDialog").on("hidden.bs.modal", function () { | |||
$("#map-textarea").remove(); | |||
if (editor.codejar) { | |||
jar.destroy(); | |||
$(".codejar-wrap").remove(); | |||
} else { | |||
$("#editor").remove(); | |||
} | |||
}); | |||
$("#saveActionsBtn").on("click", function () { | |||
@@ -207,10 +237,10 @@ define(["jquery"], | |||
errorMessage: "Save map error", | |||
method: "POST", | |||
headers: { | |||
Map: $("#map-textarea").data("id"), | |||
Map: $("#editor").data("id"), | |||
}, | |||
params: { | |||
data: $("#map-textarea").val(), | |||
data: editor.codejar ? jar.toString() : $("#editor").val(), | |||
dataType: "text", | |||
}, | |||
server: server |
@@ -0,0 +1,5 @@ | |||
/*! | |||
* CodeJar 3.1.0 (https://github.com/antonmedv/codejar) | |||
* Copyright (c) 2020, Anton Medvedev, MIT | |||
*/ | |||
function CodeJar(t,e,n={}){const o=Object.assign({tab:"\t",indentOn:/{$/},n);let r,s,i=[],c=[],d=-1,a=!1,f=navigator.userAgent.toLowerCase().indexOf("firefox")>-1;t.setAttribute("contentEditable",f?"true":"plaintext-only"),t.setAttribute("spellcheck","false"),t.style.outline="none",t.style.overflowWrap="break-word",t.style.overflowY="auto",t.style.resize="vertical",t.style.whiteSpace="pre-wrap",e(t);const l=E(()=>{const n=y();e(t),m(n)},30);let u=!1;const p=t=>!T(t)&&!v(t)&&"Meta"!==t.key&&"Control"!==t.key&&"Alt"!==t.key&&!t.key.startsWith("Arrow"),g=E(t=>{p(t)&&(O(),u=!1)},300),h=(e,n)=>{i.push([e,n]),t.addEventListener(e,n)};function y(){const e=window.getSelection(),n={start:0,end:0,dir:void 0};return C(t,t=>{if(t===e.anchorNode&&t===e.focusNode)return n.start+=e.anchorOffset,n.end+=e.focusOffset,n.dir=e.anchorOffset<=e.focusOffset?"->":"<-","stop";if(t===e.anchorNode){if(n.start+=e.anchorOffset,n.dir)return"stop";n.dir="->"}else if(t===e.focusNode){if(n.end+=e.focusOffset,n.dir)return"stop";n.dir="<-"}t.nodeType===Node.TEXT_NODE&&("->"!=n.dir&&(n.start+=t.nodeValue.length),"<-"!=n.dir&&(n.end+=t.nodeValue.length))}),n}function m(e){const n=window.getSelection();let o,r,s=0,i=0;if(e.dir||(e.dir="->"),e.start<0&&(e.start=0),e.end<0&&(e.end=0),"<-"==e.dir){const{start:t,end:n}=e;e.start=n,e.end=t}let c=0;C(t,t=>{if(t.nodeType!==Node.TEXT_NODE)return;const n=(t.nodeValue||"").length;if(c+n>=e.start&&(o||(o=t,s=e.start-c),c+n>=e.end))return r=t,i=e.end-c,"stop";c+=n}),o||(o=t),r||(r=t),"<-"==e.dir&&([o,s,r,i]=[r,i,o,s]),n.setBaseAndExtent(o,s,r,i)}function b(){const e=window.getSelection().getRangeAt(0),n=document.createRange();return n.selectNodeContents(t),n.setEnd(e.startContainer,e.startOffset),n.toString()}function w(){const e=window.getSelection().getRangeAt(0),n=document.createRange();return n.selectNodeContents(t),n.setStart(e.endContainer,e.endOffset),n.toString()}function O(){if(!a)return;const e=t.innerHTML,n=y(),o=c[d];if(o&&o.html===e&&o.pos.start===n.start&&o.pos.end===n.end)return;c[++d]={html:e,pos:n},c.splice(d+1);d>300&&(d=300,c.splice(0,1))}function C(t,e){const n=[];t.firstChild&&n.push(t.firstChild);let o=n.pop();for(;o&&"stop"!==e(o);)o.nextSibling&&n.push(o.nextSibling),o.firstChild&&n.push(o.firstChild),o=n.pop()}function k(t){return t.metaKey||t.ctrlKey}function T(t){return k(t)&&!t.shiftKey&&"KeyZ"===t.code}function v(t){return k(t)&&t.shiftKey&&"KeyZ"===t.code}function x(t){t=t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),document.execCommand("insertHTML",!1,t)}function E(t,e){let n=0;return(...o)=>{clearTimeout(n),n=window.setTimeout(()=>t(...o),e)}}function S(t){let e=t.length-1;for(;e>=0&&"\n"!==t[e];)e--;let n=++e;for(;n<t.length&&/[ \t]/.test(t[n]);)n++;return[t.substring(e,n)||"",e,n]}function N(){return t.textContent||""}function A(t){t.preventDefault()}return h("keydown",e=>{e.defaultPrevented||(s=N(),function(t){if("Enter"===t.key){const e=b(),n=w();let[r]=S(e),s=r;if(o.indentOn.test(e)&&(s+=o.tab),f?(A(t),x("\n"+s)):s.length>0&&(A(t),x("\n"+s)),s!==r&&"}"===n[0]){const t=y();x("\n"+r),m(t)}}}(e),function(t){if("Tab"===t.key)if(A(t),t.shiftKey){const t=b();let[e,n]=S(t);if(e.length>0){const t=y(),r=Math.min(o.tab.length,e.length);m({start:n,end:n+r}),document.execCommand("delete"),t.start-=r,t.end-=r,m(t)}}else x(o.tab)}(e),function(t){const e="([{'\"",n=")]}'\"",o=w();if(n.includes(t.key)&&o.substr(0,1)===t.key){const e=y();A(t),e.start=++e.end,m(e)}else if(e.includes(t.key)){const o=y();A(t);const r=t.key+n[e.indexOf(t.key)];x(r),o.start=++o.end,m(o)}}(e),function(e){if(T(e)){A(e);const n=c[--d];n&&(t.innerHTML=n.html,m(n.pos)),d<0&&(d=0)}if(v(e)){A(e);const n=c[++d];n&&(t.innerHTML=n.html,m(n.pos)),d>=c.length&&d--}}(e),p(e)&&!u&&(O(),u=!0))}),h("keyup",t=>{t.defaultPrevented||t.isComposing||(s!==N()&&l(),g(t),r&&r(N()))}),h("focus",t=>{a=!0}),h("blur",t=>{a=!1}),h("paste",n=>{O(),function(n){A(n);const o=(n.originalEvent||n).clipboardData.getData("text/plain"),r=y();x(o),e(t),m({start:r.end+o.length,end:r.end+o.length})}(n),O(),r&&r(N())}),{updateOptions(t){t=Object.assign(Object.assign({},t),t)},updateCode(n){t.textContent=n,e(t)},onUpdate(t){r=t},toString:N,destroy(){for(let[e,n]of i)t.removeEventListener(e,n)}}} |
@@ -0,0 +1,5 @@ | |||
/*! | |||
* CodeJar 3.1.0 helper: lineNumbers (https://github.com/antonmedv/codejar) | |||
* Copyright (c) 2020, Anton Medvedev, MIT | |||
*/ | |||
function withLineNumbers(e,t={}){const o=Object.assign({class:"codejar-linenumbers",wrapClass:"codejar-wrap",width:"35px",backgroundColor:"rgba(128, 128, 128, 0.15)",color:""},t);let l;return function(t){e(t),l||(l=init(t,o));const n=(t.textContent||"").replace(/\n+$/,"\n").split("\n").length+1;let s="";for(let e=1;e<n;e++)s+=`${e}\n`;l.innerText=s}}function init(e,t){const o=getComputedStyle(e),l=document.createElement("div");l.className=t.wrapClass,l.style.position="relative";const n=document.createElement("div");return n.className=t.class,l.appendChild(n),n.style.position="absolute",n.style.top="0px",n.style.left="0px",n.style.bottom="0px",n.style.width=t.width,n.style.overflow="hidden",n.style.backgroundColor=t.backgroundColor,n.style.color=t.color||o.color,n.style.setProperty("mix-blend-mode","difference"),n.style.fontFamily=o.fontFamily,n.style.fontSize=o.fontSize,n.style.lineHeight=o.lineHeight,n.style.paddingTop=o.paddingTop,n.style.paddingLeft=o.paddingLeft,n.style.borderTopLeftRadius=o.borderTopLeftRadius,n.style.borderBottomLeftRadius=o.borderBottomLeftRadius,e.style.paddingLeft=`calc(${t.width} + ${n.style.paddingLeft})`,e.style.whiteSpace="pre",e.parentNode.insertBefore(l,e),l.appendChild(e),n} |
@@ -7,21 +7,27 @@ requirejs.config({ | |||
jquery: "jquery-3.5.1.min", | |||
visibility: "visibility.min", | |||
bootstrap: "bootstrap.bundle.min", | |||
codejar: "codejar.min", | |||
d3: "d3.min", | |||
d3evolution: "d3evolution.min", | |||
d3pie: "d3pie.min", | |||
fontawesome: "fontawesome.min", | |||
fontawesome_solid: "solid.min", | |||
footable: "footable.min", | |||
linenumbers: "linenumbers.min", | |||
nprogress: "nprogress.min", | |||
prism: "prism", | |||
stickytabs: "jquery.stickytabs.min" | |||
}, | |||
shim: { | |||
codejar: {exports: "CodeJar", deps:["linenumbers"]}, | |||
bootstrap: {exports:"bootstrap", deps:["jquery"]}, | |||
d3pie: {exports:"d3pie", deps:["d3.global", "jquery"]}, | |||
d3evolution: {exports:"D3Evolution", deps:["d3", "jquery"]}, | |||
d3pie: {exports:"d3pie", deps:["d3.global", "jquery"]}, | |||
fontawesome: {exports: "FontAwesome", deps:["fontawesome_solid"]}, | |||
footable: {deps:["bootstrap", "jquery"]}, | |||
linenumbers: {exports: "withLineNumbers", deps:["prism"]}, | |||
prism: {exports: "Prism"}, | |||
stickytabs: {deps:["jquery"]} | |||
}, | |||
waitSeconds: 30, |
@@ -5,6 +5,7 @@ | |||
"stylelint-config-standard": "*" | |||
}, | |||
"eslintIgnore": [ | |||
"*.min.js" | |||
"*.min.js", | |||
"prism.js" | |||
] | |||
} |