Init commit

This commit is contained in:
Asraelite 2023-10-30 16:41:48 +01:00
commit c45ad79440
48 changed files with 6786 additions and 0 deletions

View file

@ -0,0 +1,85 @@
/* Keybinder.js
* written by Colin Kuebler 2012
* Part of LDT, dual licensed under GPLv3 and MIT
* Simplifies the creation of keybindings on any element
*/
var Keybinder = {
bind: function( element, keymap ){
element.keymap = keymap;
var keyNames = {
8: "Backspace",
9: "Tab",
13: "Enter",
16: "Shift",
17: "Ctrl",
18: "Alt",
19: "Pause",
20: "CapsLk",
27: "Esc",
33: "PgUp",
34: "PgDn",
35: "End",
36: "Home",
37: "Left",
38: "Up",
39: "Right",
40: "Down",
45: "Insert",
46: "Delete",
112: "F1",
113: "F2",
114: "F3",
115: "F4",
116: "F5",
117: "F6",
118: "F7",
119: "F8",
120: "F9",
121: "F10",
122: "F11",
123: "F12",
145: "ScrLk" };
var keyEventNormalizer = function(e){
// get the event object and start constructing a query
var e = e || window.event;
var query = "";
// add in prefixes for each key modifier
e.shiftKey && (query += "Shift-");
e.ctrlKey && (query += "Ctrl-");
e.altKey && (query += "Alt-");
e.metaKey && (query += "Meta-");
// determine the key code
var key = e.which || e.keyCode || e.charCode;
// if we have a name for it, use it
if( keyNames[key] )
query += keyNames[key];
// otherwise turn it into a string
else
query += String.fromCharCode(key).toUpperCase();
/* DEBUG */
//console.log("keyEvent: "+query);
// try to run the keybinding, cancel the event if it returns true
if( element.keymap[query] && element.keymap[query]() ){
e.preventDefault && e.preventDefault();
e.stopPropagation && e.stopPropagation();
return false;
}
return true;
};
// capture onkeydown and onkeypress events to capture repeating key events
// maintain a boolean so we only fire once per character
var fireOnKeyPress = true;
element.onkeydown = function(e){
fireOnKeyPress = false;
return keyEventNormalizer(e);
};
element.onkeypress = function(e){
if( fireOnKeyPress )
return keyEventNormalizer(e);
fireOnKeyPress = true;
return true;
};
}
}

View file

@ -0,0 +1,55 @@
/* Parser.js
* written by Colin Kuebler 2012
* Part of LDT, dual licensed under GPLv3 and MIT
* Generates a tokenizer from regular expressions for TextareaDecorator
*/
function Parser(rules, useI) {
/* INIT */
const api = this;
// variables used internally
const i = useI ? 'i' : '';
let parseRegex = null;
let ruleSrc = [];
let ruleNames = [];
let ruleMap = {};
api.add = function (rules) {
for (const [name, rule] of Object.entries(rules)) {
let s = rule.source;
s = '(?<' + name + '>' + s + ')';
ruleSrc.push(s);
// ruleMap[rule] = new RegExp('^(' + s + ')$', i);
ruleNames.push(name);
}
parseRegex = new RegExp(ruleSrc.join('|'), 'gm' + i);
};
api.tokenize = function (input) {
const tokens = [];
const lines = input.match(/.*\n?/gm);
for (const [lineNumber, line] of lines.entries()) {
for (const match of line.matchAll(parseRegex)) {
for (const ruleName of ruleNames) {
if (match.groups[ruleName] !== undefined) {
tokens.push({
tag: ruleName,
text: match[0],
lineNumber,
});
break;
}
}
}
}
return tokens;
};
api.identify = function (token) {
return token.tag;
};
api.add(rules);
return api;
};

View file

@ -0,0 +1,25 @@
/* SelectHelper.js
* written by Colin Kuebler 2012
* Part of LDT, dual licensed under GPLv3 and MIT
* Convenient utilities for cross browser textarea selection manipulation
*/
var SelectHelper = {
add: function( element ){
element.insertAtCursor = element.createTextRange ?
// IE version
function(x){
document.selection.createRange().text = x;
} :
// standards version
function(x){
var s = element.selectionStart,
e = element.selectionEnd,
v = element.value;
element.value = v.substring(0, s) + x + v.substring(e);
s += x.length;
element.setSelectionRange(s, s);
};
}
};

View file

@ -0,0 +1,65 @@
/* TextareaDecorator.css
* written by Colin Kuebler 2012
* Part of LDT, dual licensed under GPLv3 and MIT
* Provides styles for rendering a textarea on top of a pre with scrollbars
*/
/* settings you can play with */
.ldt, .ldt label {
padding: 4px;
}
.ldt, .ldt pre, .ldt textarea {
font-size: 16px !important;
/* resize algorithm depends on a monospaced font */
font-family: monospace !important;
}
.ldt textarea {
/* hide the text but show the text caret */
color: transparent;
/* Firefox caret position is slow to update when color is transparent */
color: rgba(0, 0, 0, 0.004);
caret-color: #000;
}
/* settings you shouldn't play with unless you have a good reason */
.ldt {
overflow: auto;
position: relative;
}
.ldt pre {
margin: 0;
overflow: initial;
}
.ldt label {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: inline;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
cursor: text;
}
.ldt textarea {
margin: 0;
padding: 0;
border: 0;
background: 0;
outline: none;
resize: none;
min-width: 100%;
min-height: 100%;
overflow: hidden;
/* IE doesn't support rgba textarea, so use vendor specific alpha filter */
filter: alpha(opacity = 20);
}

View file

@ -0,0 +1,111 @@
/* TextareaDecorator.js
* written by Colin Kuebler 2012
* Part of LDT, dual licensed under GPLv3 and MIT
* Builds and maintains a styled output layer under a textarea input layer
*/
function TextareaDecorator(textarea, parser) {
/* INIT */
var api = this;
this.parser = parser;
this.errorMap = {};
// construct editor DOM
var parent = document.createElement("div");
var output = document.createElement("pre");
parent.appendChild(output);
var label = document.createElement("label");
parent.appendChild(label);
// replace the textarea with RTA DOM and reattach on label
textarea.parentNode.replaceChild(parent, textarea);
label.appendChild(textarea);
// transfer the CSS styles to our editor
parent.className = 'ldt ' + textarea.className;
textarea.className = '';
// turn off built-in spellchecking in firefox
textarea.spellcheck = false;
// turn off word wrap
textarea.wrap = "off";
var getParser = () => {
return this.parser;
}
var getErrorMap = () => {
return this.errorMap;
}
// coloring algorithm
var color = function (input, output, parser) {
var oldTokens = output.childNodes;
var newTokens = parser.tokenize(input);
var firstDiff, lastDiffNew, lastDiffOld;
output.innerHTML = '';
// add in modified spans
for (const token of newTokens) {
var span = document.createElement("span");
span.className = token.tag;
if (getErrorMap()[token.lineNumber]) {
span.classList.add('error');
}
span.textContent = span.innerText = token.text;
output.appendChild(span);
}
};
api.input = textarea;
api.output = output;
api.update = function () {
var input = textarea.value;
if (input) {
color(input, output, getParser());
// determine the best size for the textarea
var lines = input.split('\n');
// find the number of columns
var maxlen = 0, curlen;
for (var i = 0; i < lines.length; i++) {
// calculate the width of each tab
var tabLength = 0, offset = -1;
while ((offset = lines[i].indexOf('\t', offset + 1)) > -1) {
tabLength += 7 - (tabLength + offset) % 8;
}
var curlen = lines[i].length + tabLength;
// store the greatest line length thus far
maxlen = maxlen > curlen ? maxlen : curlen;
}
textarea.cols = maxlen + 1;
textarea.rows = lines.length + 2;
} else {
// clear the display
output.innerHTML = '';
// reset textarea rows/cols
textarea.cols = textarea.rows = 1;
}
};
// detect all changes to the textarea,
// including keyboard input, cut/copy/paste, drag & drop, etc
if (textarea.addEventListener) {
// standards browsers: oninput event
textarea.addEventListener("input", api.update, false);
} else {
// MSIE: detect changes to the 'value' property
textarea.attachEvent("onpropertychange",
function (e) {
if (e.propertyName.toLowerCase() === 'value') {
api.update();
}
}
);
}
// initial highlighting
api.update();
api.setErrorMap = (errors) => {
this.errorMap = errors;
api.update();
}
return api;
};