mirror of
https://github.com/seigler/janus
synced 2025-07-27 09:46:10 +00:00
feat: integrate Behave.js for live editor 🏆 so good
This commit is contained in:
parent
3333e8e6ea
commit
ead85b1f05
3 changed files with 780 additions and 73 deletions
|
@ -81,7 +81,7 @@ body {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
font-size: calc(1vw + 1em);
|
font-size: calc(1vw + 1em);
|
||||||
height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
nav {
|
nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -139,6 +139,7 @@ section + section {
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
<script type="text/javascript" src="libs/openjs-shortcut/shortcut.js"></script>
|
<script type="text/javascript" src="libs/openjs-shortcut/shortcut.js"></script>
|
||||||
|
<script type="text/javascript" src="libs/behave/behave.js"></script>
|
||||||
<script type="text/javascript" src="scripts/app.js"></script>
|
<script type="text/javascript" src="scripts/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
675
libs/behave/behave.js
Normal file
675
libs/behave/behave.js
Normal file
|
@ -0,0 +1,675 @@
|
||||||
|
/*
|
||||||
|
* Behave.js
|
||||||
|
*
|
||||||
|
* Copyright 2013, Jacob Kelley - http://jakiestfu.com/
|
||||||
|
* Released under the MIT Licence
|
||||||
|
* http://opensource.org/licenses/MIT
|
||||||
|
*
|
||||||
|
* Github: http://github.com/jakiestfu/Behave.js/
|
||||||
|
* Version: 1.5
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (undefined) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var BehaveHooks = BehaveHooks || (function () {
|
||||||
|
var hooks = {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
add: function (hookName, fn) {
|
||||||
|
if (typeof hookName == "object") {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < hookName.length; i++) {
|
||||||
|
var theHook = hookName[i];
|
||||||
|
if (!hooks[theHook]) {
|
||||||
|
hooks[theHook] = [];
|
||||||
|
}
|
||||||
|
hooks[theHook].push(fn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!hooks[hookName]) {
|
||||||
|
hooks[hookName] = [];
|
||||||
|
}
|
||||||
|
hooks[hookName].push(fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get: function (hookName) {
|
||||||
|
if (hooks[hookName]) {
|
||||||
|
return hooks[hookName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})(),
|
||||||
|
Behave = Behave || function (userOpts) {
|
||||||
|
|
||||||
|
if (typeof String.prototype.repeat !== 'function') {
|
||||||
|
String.prototype.repeat = function (times) {
|
||||||
|
if (times < 1) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (times % 2) {
|
||||||
|
return this.repeat(times - 1) + this;
|
||||||
|
}
|
||||||
|
var half = this.repeat(times / 2);
|
||||||
|
return half + half;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Array.prototype.filter !== 'function') {
|
||||||
|
Array.prototype.filter = function (func /*, thisp */ ) {
|
||||||
|
if (this === null) {
|
||||||
|
throw new TypeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = Object(this),
|
||||||
|
len = t.length >>> 0;
|
||||||
|
if (typeof func != "function") {
|
||||||
|
throw new TypeError();
|
||||||
|
}
|
||||||
|
var res = [],
|
||||||
|
thisp = arguments[1];
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
if (i in t) {
|
||||||
|
var val = t[i];
|
||||||
|
if (func.call(thisp, val, i, t)) {
|
||||||
|
res.push(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
textarea: null,
|
||||||
|
replaceTab: true,
|
||||||
|
softTabs: true,
|
||||||
|
tabSize: 4,
|
||||||
|
autoOpen: true,
|
||||||
|
overwrite: true,
|
||||||
|
autoStrip: true,
|
||||||
|
autoIndent: true,
|
||||||
|
fence: false
|
||||||
|
},
|
||||||
|
tab,
|
||||||
|
newLine,
|
||||||
|
charSettings = {
|
||||||
|
|
||||||
|
keyMap: [
|
||||||
|
{
|
||||||
|
open: "\"",
|
||||||
|
close: "\"",
|
||||||
|
canBreak: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: "'",
|
||||||
|
close: "'",
|
||||||
|
canBreak: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: "(",
|
||||||
|
close: ")",
|
||||||
|
canBreak: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: "[",
|
||||||
|
close: "]",
|
||||||
|
canBreak: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: "{",
|
||||||
|
close: "}",
|
||||||
|
canBreak: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
utils = {
|
||||||
|
|
||||||
|
_callHook: function (hookName, passData) {
|
||||||
|
var hooks = BehaveHooks.get(hookName);
|
||||||
|
passData = typeof passData == "boolean" && passData === false ? false : true;
|
||||||
|
|
||||||
|
if (hooks) {
|
||||||
|
if (passData) {
|
||||||
|
var theEditor = defaults.textarea,
|
||||||
|
textVal = theEditor.value,
|
||||||
|
caretPos = utils.cursor.get(),
|
||||||
|
i;
|
||||||
|
|
||||||
|
for (i = 0; i < hooks.length; i++) {
|
||||||
|
hooks[i].call(undefined, {
|
||||||
|
editor: {
|
||||||
|
element: theEditor,
|
||||||
|
text: textVal,
|
||||||
|
levelsDeep: utils.levelsDeep()
|
||||||
|
},
|
||||||
|
caret: {
|
||||||
|
pos: caretPos
|
||||||
|
},
|
||||||
|
lines: {
|
||||||
|
current: utils.cursor.getLine(textVal, caretPos),
|
||||||
|
total: utils.editor.getLines(textVal)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < hooks.length; i++) {
|
||||||
|
hooks[i].call(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
defineNewLine: function () {
|
||||||
|
var ta = document.createElement('textarea');
|
||||||
|
ta.value = "\n";
|
||||||
|
|
||||||
|
if (ta.value.length == 2) {
|
||||||
|
newLine = "\r\n";
|
||||||
|
} else {
|
||||||
|
newLine = "\n";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defineTabSize: function (tabSize) {
|
||||||
|
if (typeof defaults.textarea.style.OTabSize != "undefined") {
|
||||||
|
defaults.textarea.style.OTabSize = tabSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof defaults.textarea.style.MozTabSize != "undefined") {
|
||||||
|
defaults.textarea.style.MozTabSize = tabSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof defaults.textarea.style.tabSize != "undefined") {
|
||||||
|
defaults.textarea.style.tabSize = tabSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cursor: {
|
||||||
|
getLine: function (textVal, pos) {
|
||||||
|
return ((textVal.substring(0, pos)).split("\n")).length;
|
||||||
|
},
|
||||||
|
get: function () {
|
||||||
|
|
||||||
|
if (typeof document.createElement('textarea').selectionStart === "number") {
|
||||||
|
return defaults.textarea.selectionStart;
|
||||||
|
} else if (document.selection) {
|
||||||
|
var caretPos = 0,
|
||||||
|
range = defaults.textarea.createTextRange(),
|
||||||
|
rangeDupe = document.selection.createRange().duplicate(),
|
||||||
|
rangeDupeBookmark = rangeDupe.getBookmark();
|
||||||
|
range.moveToBookmark(rangeDupeBookmark);
|
||||||
|
|
||||||
|
while (range.moveStart('character', -1) !== 0) {
|
||||||
|
caretPos++;
|
||||||
|
}
|
||||||
|
return caretPos;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set: function (start, end) {
|
||||||
|
if (!end) {
|
||||||
|
end = start;
|
||||||
|
}
|
||||||
|
if (defaults.textarea.setSelectionRange) {
|
||||||
|
defaults.textarea.focus();
|
||||||
|
defaults.textarea.setSelectionRange(start, end);
|
||||||
|
} else if (defaults.textarea.createTextRange) {
|
||||||
|
var range = defaults.textarea.createTextRange();
|
||||||
|
range.collapse(true);
|
||||||
|
range.moveEnd('character', end);
|
||||||
|
range.moveStart('character', start);
|
||||||
|
range.select();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selection: function () {
|
||||||
|
var textAreaElement = defaults.textarea,
|
||||||
|
start = 0,
|
||||||
|
end = 0,
|
||||||
|
normalizedValue,
|
||||||
|
range,
|
||||||
|
textInputRange,
|
||||||
|
len,
|
||||||
|
endRange;
|
||||||
|
|
||||||
|
if (typeof textAreaElement.selectionStart == "number" && typeof textAreaElement.selectionEnd == "number") {
|
||||||
|
start = textAreaElement.selectionStart;
|
||||||
|
end = textAreaElement.selectionEnd;
|
||||||
|
} else {
|
||||||
|
range = document.selection.createRange();
|
||||||
|
|
||||||
|
if (range && range.parentElement() == textAreaElement) {
|
||||||
|
|
||||||
|
normalizedValue = utils.editor.get();
|
||||||
|
len = normalizedValue.length;
|
||||||
|
|
||||||
|
textInputRange = textAreaElement.createTextRange();
|
||||||
|
textInputRange.moveToBookmark(range.getBookmark());
|
||||||
|
|
||||||
|
endRange = textAreaElement.createTextRange();
|
||||||
|
endRange.collapse(false);
|
||||||
|
|
||||||
|
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
|
||||||
|
start = end = len;
|
||||||
|
} else {
|
||||||
|
start = -textInputRange.moveStart("character", -len);
|
||||||
|
start += normalizedValue.slice(0, start).split(newLine).length - 1;
|
||||||
|
|
||||||
|
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
|
||||||
|
end = len;
|
||||||
|
} else {
|
||||||
|
end = -textInputRange.moveEnd("character", -len);
|
||||||
|
end += normalizedValue.slice(0, end).split(newLine).length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return start == end ? false : {
|
||||||
|
start: start,
|
||||||
|
end: end
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
getLines: function (textVal) {
|
||||||
|
return (textVal).split("\n").length;
|
||||||
|
},
|
||||||
|
get: function () {
|
||||||
|
return defaults.textarea.value.replace(/\r/g, '');
|
||||||
|
},
|
||||||
|
set: function (data) {
|
||||||
|
defaults.textarea.value = data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fenceRange: function () {
|
||||||
|
if (typeof defaults.fence == "string") {
|
||||||
|
|
||||||
|
var data = utils.editor.get(),
|
||||||
|
pos = utils.cursor.get(),
|
||||||
|
hacked = 0,
|
||||||
|
matchedFence = data.indexOf(defaults.fence),
|
||||||
|
matchCase = 0;
|
||||||
|
|
||||||
|
while (matchedFence >= 0) {
|
||||||
|
matchCase++;
|
||||||
|
if (pos < (matchedFence + hacked)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hacked += matchedFence + defaults.fence.length;
|
||||||
|
data = data.substring(matchedFence + defaults.fence.length);
|
||||||
|
matchedFence = data.indexOf(defaults.fence);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hacked) < pos && ((matchedFence + hacked) > pos) && matchCase % 2 === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isEven: function (_this, i) {
|
||||||
|
return i % 2;
|
||||||
|
},
|
||||||
|
levelsDeep: function () {
|
||||||
|
var pos = utils.cursor.get(),
|
||||||
|
val = utils.editor.get();
|
||||||
|
|
||||||
|
var left = val.substring(0, pos),
|
||||||
|
levels = 0,
|
||||||
|
i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < left.length; i++) {
|
||||||
|
for (j = 0; j < charSettings.keyMap.length; j++) {
|
||||||
|
if (charSettings.keyMap[j].canBreak) {
|
||||||
|
if (charSettings.keyMap[j].open == left.charAt(i)) {
|
||||||
|
levels++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charSettings.keyMap[j].close == left.charAt(i)) {
|
||||||
|
levels--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var toDecrement = 0,
|
||||||
|
quoteMap = ["'", "\""];
|
||||||
|
for (i = 0; i < charSettings.keyMap.length; i++) {
|
||||||
|
if (charSettings.keyMap[i].canBreak) {
|
||||||
|
for (j in quoteMap) {
|
||||||
|
toDecrement += left.split(quoteMap[j]).filter(utils.isEven).join('').split(charSettings.keyMap[i].open).length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalLevels = levels - toDecrement;
|
||||||
|
|
||||||
|
return finalLevels >= 0 ? finalLevels : 0;
|
||||||
|
},
|
||||||
|
deepExtend: function (destination, source) {
|
||||||
|
for (var property in source) {
|
||||||
|
if (source[property] && source[property].constructor &&
|
||||||
|
source[property].constructor === Object) {
|
||||||
|
destination[property] = destination[property] || {};
|
||||||
|
utils.deepExtend(destination[property], source[property]);
|
||||||
|
} else {
|
||||||
|
destination[property] = source[property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
},
|
||||||
|
addEvent: function addEvent(element, eventName, func) {
|
||||||
|
if (element.addEventListener) {
|
||||||
|
element.addEventListener(eventName, func, false);
|
||||||
|
} else if (element.attachEvent) {
|
||||||
|
element.attachEvent("on" + eventName, func);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeEvent: function addEvent(element, eventName, func) {
|
||||||
|
if (element.addEventListener) {
|
||||||
|
element.removeEventListener(eventName, func, false);
|
||||||
|
} else if (element.attachEvent) {
|
||||||
|
element.detachEvent("on" + eventName, func);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
preventDefaultEvent: function (e) {
|
||||||
|
if (e.preventDefault) {
|
||||||
|
e.preventDefault();
|
||||||
|
} else {
|
||||||
|
e.returnValue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
intercept = {
|
||||||
|
tabKey: function (e) {
|
||||||
|
|
||||||
|
if (!utils.fenceRange()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.keyCode == 9) {
|
||||||
|
utils.preventDefaultEvent(e);
|
||||||
|
|
||||||
|
var toReturn = true;
|
||||||
|
utils._callHook('tab:before');
|
||||||
|
|
||||||
|
var selection = utils.cursor.selection(),
|
||||||
|
pos = utils.cursor.get(),
|
||||||
|
val = utils.editor.get();
|
||||||
|
|
||||||
|
if (selection) {
|
||||||
|
|
||||||
|
var tempStart = selection.start;
|
||||||
|
while (tempStart--) {
|
||||||
|
if (val.charAt(tempStart) == "\n") {
|
||||||
|
selection.start = tempStart + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var toIndent = val.substring(selection.start, selection.end),
|
||||||
|
lines = toIndent.split("\n"),
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (e.shiftKey) {
|
||||||
|
for (i = 0; i < lines.length; i++) {
|
||||||
|
if (lines[i].substring(0, tab.length) == tab) {
|
||||||
|
lines[i] = lines[i].substring(tab.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toIndent = lines.join("\n");
|
||||||
|
|
||||||
|
utils.editor.set(val.substring(0, selection.start) + toIndent + val.substring(selection.end));
|
||||||
|
utils.cursor.set(selection.start, selection.start + toIndent.length);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (i in lines) {
|
||||||
|
lines[i] = tab + lines[i];
|
||||||
|
}
|
||||||
|
toIndent = lines.join("\n");
|
||||||
|
|
||||||
|
utils.editor.set(val.substring(0, selection.start) + toIndent + val.substring(selection.end));
|
||||||
|
utils.cursor.set(selection.start, selection.start + toIndent.length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var left = val.substring(0, pos),
|
||||||
|
right = val.substring(pos),
|
||||||
|
edited = left + tab + right;
|
||||||
|
|
||||||
|
if (e.shiftKey) {
|
||||||
|
if (val.substring(pos - tab.length, pos) == tab) {
|
||||||
|
edited = val.substring(0, pos - tab.length) + right;
|
||||||
|
utils.editor.set(edited);
|
||||||
|
utils.cursor.set(pos - tab.length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
utils.editor.set(edited);
|
||||||
|
utils.cursor.set(pos + tab.length);
|
||||||
|
toReturn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utils._callHook('tab:after');
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
},
|
||||||
|
enterKey: function (e) {
|
||||||
|
|
||||||
|
if (!utils.fenceRange()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
|
||||||
|
utils.preventDefaultEvent(e);
|
||||||
|
utils._callHook('enter:before');
|
||||||
|
|
||||||
|
var pos = utils.cursor.get(),
|
||||||
|
val = utils.editor.get(),
|
||||||
|
left = val.substring(0, pos),
|
||||||
|
right = val.substring(pos),
|
||||||
|
leftChar = left.charAt(left.length - 1),
|
||||||
|
rightChar = right.charAt(0),
|
||||||
|
numTabs = utils.levelsDeep(),
|
||||||
|
ourIndent = "",
|
||||||
|
closingBreak = "",
|
||||||
|
finalCursorPos,
|
||||||
|
i;
|
||||||
|
if (!numTabs) {
|
||||||
|
finalCursorPos = 1;
|
||||||
|
} else {
|
||||||
|
while (numTabs--) {
|
||||||
|
ourIndent += tab;
|
||||||
|
}
|
||||||
|
ourIndent = ourIndent;
|
||||||
|
finalCursorPos = ourIndent.length + 1;
|
||||||
|
|
||||||
|
for (i = 0; i < charSettings.keyMap.length; i++) {
|
||||||
|
if (charSettings.keyMap[i].open == leftChar && charSettings.keyMap[i].close == rightChar) {
|
||||||
|
closingBreak = newLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var edited = left + newLine + ourIndent + closingBreak + (ourIndent.substring(0, ourIndent.length - tab.length)) + right;
|
||||||
|
utils.editor.set(edited);
|
||||||
|
utils.cursor.set(pos + finalCursorPos);
|
||||||
|
utils._callHook('enter:after');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteKey: function (e) {
|
||||||
|
|
||||||
|
if (!utils.fenceRange()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.keyCode == 8) {
|
||||||
|
utils.preventDefaultEvent(e);
|
||||||
|
|
||||||
|
utils._callHook('delete:before');
|
||||||
|
|
||||||
|
var pos = utils.cursor.get(),
|
||||||
|
val = utils.editor.get(),
|
||||||
|
left = val.substring(0, pos),
|
||||||
|
right = val.substring(pos),
|
||||||
|
leftChar = left.charAt(left.length - 1),
|
||||||
|
rightChar = right.charAt(0),
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (utils.cursor.selection() === false) {
|
||||||
|
for (i = 0; i < charSettings.keyMap.length; i++) {
|
||||||
|
if (charSettings.keyMap[i].open == leftChar && charSettings.keyMap[i].close == rightChar) {
|
||||||
|
var edited = val.substring(0, pos - 1) + val.substring(pos + 1);
|
||||||
|
utils.editor.set(edited);
|
||||||
|
utils.cursor.set(pos - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var edited = val.substring(0, pos - 1) + val.substring(pos);
|
||||||
|
utils.editor.set(edited);
|
||||||
|
utils.cursor.set(pos - 1);
|
||||||
|
} else {
|
||||||
|
var sel = utils.cursor.selection(),
|
||||||
|
edited = val.substring(0, sel.start) + val.substring(sel.end);
|
||||||
|
utils.editor.set(edited);
|
||||||
|
utils.cursor.set(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils._callHook('delete:after');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
charFuncs = {
|
||||||
|
openedChar: function (_char, e) {
|
||||||
|
utils.preventDefaultEvent(e);
|
||||||
|
utils._callHook('openChar:before');
|
||||||
|
var pos = utils.cursor.get(),
|
||||||
|
val = utils.editor.get(),
|
||||||
|
left = val.substring(0, pos),
|
||||||
|
right = val.substring(pos),
|
||||||
|
edited = left + _char.open + _char.close + right;
|
||||||
|
|
||||||
|
defaults.textarea.value = edited;
|
||||||
|
utils.cursor.set(pos + 1);
|
||||||
|
utils._callHook('openChar:after');
|
||||||
|
},
|
||||||
|
closedChar: function (_char, e) {
|
||||||
|
var pos = utils.cursor.get(),
|
||||||
|
val = utils.editor.get(),
|
||||||
|
toOverwrite = val.substring(pos, pos + 1);
|
||||||
|
if (toOverwrite == _char.close) {
|
||||||
|
utils.preventDefaultEvent(e);
|
||||||
|
utils._callHook('closeChar:before');
|
||||||
|
utils.cursor.set(utils.cursor.get() + 1);
|
||||||
|
utils._callHook('closeChar:after');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
action = {
|
||||||
|
filter: function (e) {
|
||||||
|
|
||||||
|
if (!utils.fenceRange()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var theCode = e.which || e.keyCode;
|
||||||
|
|
||||||
|
if (theCode == 39 || theCode == 40 && e.which === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _char = String.fromCharCode(theCode),
|
||||||
|
i;
|
||||||
|
|
||||||
|
for (i = 0; i < charSettings.keyMap.length; i++) {
|
||||||
|
|
||||||
|
if (charSettings.keyMap[i].close == _char) {
|
||||||
|
var didClose = defaults.overwrite && charFuncs.closedChar(charSettings.keyMap[i], e);
|
||||||
|
|
||||||
|
if (!didClose && charSettings.keyMap[i].open == _char && defaults.autoOpen) {
|
||||||
|
charFuncs.openedChar(charSettings.keyMap[i], e);
|
||||||
|
}
|
||||||
|
} else if (charSettings.keyMap[i].open == _char && defaults.autoOpen) {
|
||||||
|
charFuncs.openedChar(charSettings.keyMap[i], e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
listen: function () {
|
||||||
|
|
||||||
|
if (defaults.replaceTab) {
|
||||||
|
utils.addEvent(defaults.textarea, 'keydown', intercept.tabKey);
|
||||||
|
}
|
||||||
|
if (defaults.autoIndent) {
|
||||||
|
utils.addEvent(defaults.textarea, 'keydown', intercept.enterKey);
|
||||||
|
}
|
||||||
|
if (defaults.autoStrip) {
|
||||||
|
utils.addEvent(defaults.textarea, 'keydown', intercept.deleteKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.addEvent(defaults.textarea, 'keypress', action.filter);
|
||||||
|
|
||||||
|
utils.addEvent(defaults.textarea, 'keydown', function () {
|
||||||
|
utils._callHook('keydown');
|
||||||
|
});
|
||||||
|
utils.addEvent(defaults.textarea, 'keyup', function () {
|
||||||
|
utils._callHook('keyup');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init = function (opts) {
|
||||||
|
|
||||||
|
if (opts.textarea) {
|
||||||
|
utils._callHook('init:before', false);
|
||||||
|
utils.deepExtend(defaults, opts);
|
||||||
|
utils.defineNewLine();
|
||||||
|
|
||||||
|
if (defaults.softTabs) {
|
||||||
|
tab = " ".repeat(defaults.tabSize);
|
||||||
|
} else {
|
||||||
|
tab = "\t";
|
||||||
|
|
||||||
|
utils.defineTabSize(defaults.tabSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
action.listen();
|
||||||
|
utils._callHook('init:after', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
utils.removeEvent(defaults.textarea, 'keydown', intercept.tabKey);
|
||||||
|
utils.removeEvent(defaults.textarea, 'keydown', intercept.enterKey);
|
||||||
|
utils.removeEvent(defaults.textarea, 'keydown', intercept.deleteKey);
|
||||||
|
utils.removeEvent(defaults.textarea, 'keypress', action.filter);
|
||||||
|
};
|
||||||
|
|
||||||
|
init(userOpts);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
module.exports = Behave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof ender === 'undefined') {
|
||||||
|
this.Behave = Behave;
|
||||||
|
this.BehaveHooks = BehaveHooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
define("behave", [], function () {
|
||||||
|
return Behave;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).call(this);
|
175
scripts/app.js
175
scripts/app.js
|
@ -1,8 +1,8 @@
|
||||||
/*jslint browser: true*/
|
/*jslint browser: true*/
|
||||||
/*global shortcut*/
|
/*global shortcut, Behave*/
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
var slides = [],
|
var slides = [],
|
||||||
syncFormElements = [],
|
syncFormElements = [],
|
||||||
|
@ -27,20 +27,20 @@
|
||||||
if (newSlideNumber !== currentSlideNumber) {
|
if (newSlideNumber !== currentSlideNumber) {
|
||||||
currentSlideNumber = newSlideNumber;
|
currentSlideNumber = newSlideNumber;
|
||||||
if (storeChange) {
|
if (storeChange) {
|
||||||
localStorage.setItem('janus-currentSlideNumber', currentSlideNumber);
|
localStorage.setItem("janus-currentSlideNumber", currentSlideNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slides.forEach(function (item, index, array) {
|
slides.forEach(function (item, index, array) {
|
||||||
if (index < currentSlideNumber) {
|
if (index < currentSlideNumber) {
|
||||||
if (slides[index].contains(slides[currentSlideNumber])) {
|
if (slides[index].contains(slides[currentSlideNumber])) {
|
||||||
item.setAttribute('janus-timeline', 'present');
|
item.setAttribute("janus-timeline", "present");
|
||||||
} else {
|
} else {
|
||||||
item.setAttribute('janus-timeline', 'past');
|
item.setAttribute("janus-timeline", "past");
|
||||||
}
|
}
|
||||||
} else if (index === currentSlideNumber) {
|
} else if (index === currentSlideNumber) {
|
||||||
item.setAttribute('janus-timeline', 'present');
|
item.setAttribute("janus-timeline", "present");
|
||||||
} else {
|
} else {
|
||||||
item.setAttribute('janus-timeline', 'future');
|
item.setAttribute("janus-timeline", "future");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,20 +53,20 @@
|
||||||
|
|
||||||
function toggleCommandBar(visible) {
|
function toggleCommandBar(visible) {
|
||||||
if (visible === false) {
|
if (visible === false) {
|
||||||
commandBar.style.display = 'none';
|
commandBar.style.display = "none";
|
||||||
commandBarVisible = false;
|
commandBarVisible = false;
|
||||||
} else if (visible === true) {
|
} else if (visible === true) {
|
||||||
commandBar.style.display = 'flex';
|
commandBar.style.display = "flex";
|
||||||
commandField.value = '';
|
commandField.value = "";
|
||||||
commandField.focus();
|
commandField.focus();
|
||||||
commandBarVisible = true;
|
commandBarVisible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMouseX(value, storeChange) {
|
function setMouseX(value, storeChange) {
|
||||||
$('section[janus-timeline="present"]').style.setProperty("--mouse-x", value);
|
$("section[janus-timeline=\"present\"]").style.setProperty("--mouse-x", value);
|
||||||
if (storeChange) {
|
if (storeChange) {
|
||||||
localStorage.setItem('mouse-x', value);
|
localStorage.setItem("mouse-x", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,16 +80,16 @@
|
||||||
function runCommand(command) {
|
function runCommand(command) {
|
||||||
var commands, s;
|
var commands, s;
|
||||||
commands = {
|
commands = {
|
||||||
's': function () {
|
"s": function () {
|
||||||
document.body.classList.toggle('simulate-projection');
|
document.body.classList.toggle("simulate-projection");
|
||||||
},
|
},
|
||||||
'p': function () {
|
"p": function () {
|
||||||
document.body.classList.toggle('show-notes');
|
document.body.classList.toggle("show-notes");
|
||||||
},
|
},
|
||||||
'c': function () {
|
"c": function () {
|
||||||
window.open(window.location.href, '_blank');
|
window.open(window.location.href, "_blank");
|
||||||
},
|
},
|
||||||
'r': function () {
|
"r": function () {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
setCurrentSlide(0, true);
|
setCurrentSlide(0, true);
|
||||||
}
|
}
|
||||||
|
@ -117,10 +117,10 @@
|
||||||
|
|
||||||
function editorListenerGenerator(editor) {
|
function editorListenerGenerator(editor) {
|
||||||
var markupEl, styleEl, scriptEl, frameEl, frameWindow, listener;
|
var markupEl, styleEl, scriptEl, frameEl, frameWindow, listener;
|
||||||
markupEl = editor.querySelector('[name="html"]');
|
markupEl = editor.querySelector("[name=\"html\"]");
|
||||||
styleEl = editor.querySelector('[name="css"]');
|
styleEl = editor.querySelector("[name=\"css\"]");
|
||||||
scriptEl = editor.querySelector('[name="js"]');
|
scriptEl = editor.querySelector("[name=\"js\"]");
|
||||||
frameEl = editor.querySelector('iframe');
|
frameEl = editor.querySelector("iframe");
|
||||||
if (frameEl.contentWindow) {
|
if (frameEl.contentWindow) {
|
||||||
frameWindow = frameEl.contentWindow;
|
frameWindow = frameEl.contentWindow;
|
||||||
} else {
|
} else {
|
||||||
|
@ -131,27 +131,58 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function editorAction() {
|
function editorAction() {
|
||||||
var compiled = '<!DOCTYPE html><html><head><style>' + styleEl.value + '</style></head><body>' + markupEl.value + '<scr' + 'ipt>' + scriptEl.value + '</scr' + 'ipt></body></html>';
|
var compiled = "<!DOCTYPE html><html><head><style>" + styleEl.value + "</style></head><body>" + markupEl.value + "<scr" + "ipt>" + scriptEl.value + "</scr" + "ipt></body></html>";
|
||||||
frameWindow.document.open();
|
frameWindow.document.open();
|
||||||
frameWindow.document.write(compiled);
|
frameWindow.document.write(compiled);
|
||||||
frameWindow.document.close();
|
frameWindow.document.close();
|
||||||
// frameEl.src = 'data:text/html;charset=utf-8,' + encodeURI(compiled);
|
|
||||||
}
|
}
|
||||||
// listener = function () {
|
|
||||||
// if (this.timeoutId) {
|
|
||||||
// window.clearTimeout(this.timeoutId);
|
|
||||||
// }
|
|
||||||
// this.timeoutId = window.setTimeout(editorAction, 100);
|
|
||||||
// };
|
|
||||||
[markupEl, styleEl, scriptEl].forEach(function (current, index, array) {
|
[markupEl, styleEl, scriptEl].forEach(function (current, index, array) {
|
||||||
var syncFormElementsIndex = syncFormElements.indexOf(current);
|
var syncFormElementsIndex = syncFormElements.indexOf(current), editor;
|
||||||
current.addEventListener('keyup', editorAction);
|
// // add a listener to do indenting
|
||||||
|
// current.addEventListener('keydown', function(event) {
|
||||||
|
// var initialScroll, beforeCursor, inSelection, afterCursor, selectionMin, selectionMax, replacedText;
|
||||||
|
// beforeCursor = current.value.slice(0, selectionMin);
|
||||||
|
// inSelection = current.value.slice(selectionMin, selectionMax);
|
||||||
|
// afterCursor = current.value.slice(selectionMax);
|
||||||
|
// initialScroll = current.scrollTop;
|
||||||
|
// if (event.keyCode === 13) {
|
||||||
|
// // NEWLINE
|
||||||
|
// event.preventDefault();
|
||||||
|
// replacedText = "\n";
|
||||||
|
// document.execCommand("insertText", false, replacedText);
|
||||||
|
// selectionMin += replacedText.length;
|
||||||
|
// selectionMax = selectionMin;
|
||||||
|
// current.scrollTop = initialScroll;
|
||||||
|
// } else if (event.keyCode === 9) {
|
||||||
|
// // TAB
|
||||||
|
// event.preventDefault();
|
||||||
|
// event.stopPropagation();
|
||||||
|
// replacedText = "\t";
|
||||||
|
// document.execCommand("insertText", false, replacedText);
|
||||||
|
// selectionMin += replacedText.length;
|
||||||
|
// selectionMax = selectionMin;
|
||||||
|
// current.scrollTop = initialScroll;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
editor = new Behave({
|
||||||
|
textarea: current,
|
||||||
|
replaceTab: true,
|
||||||
|
softTabs: true,
|
||||||
|
tabSize: 2,
|
||||||
|
autoOpen: true,
|
||||||
|
overwrite: true,
|
||||||
|
autoStrip: true,
|
||||||
|
autoIndent: true,
|
||||||
|
fence: false
|
||||||
|
});
|
||||||
|
// add a listener to build the source when the fields are changed
|
||||||
|
current.addEventListener('input', editorAction);
|
||||||
if (syncFormElementsIndex >= 0) {
|
if (syncFormElementsIndex >= 0) {
|
||||||
// add a listener to receive changes from localStorage
|
// add a listener to receive changes from localStorage
|
||||||
localStorageActions['janus-input-' + syncFormElementsIndex] = function (event) {
|
localStorageActions["janus-input-" + syncFormElementsIndex] = function (event) {
|
||||||
var storedValue = event.newValue,
|
var storedValue = event.newValue,
|
||||||
decodedValue = storedValue.split('/', 2);
|
decodedValue = storedValue.split("/", 2);
|
||||||
decodedValue.push(storedValue.slice(decodedValue.join(' ').length + 1));
|
decodedValue.push(storedValue.slice(decodedValue.join(" ").length + 1));
|
||||||
current.value = decodedValue[2];
|
current.value = decodedValue[2];
|
||||||
current.setSelectionRange(+decodedValue[0], +decodedValue[1]);
|
current.setSelectionRange(+decodedValue[0], +decodedValue[1]);
|
||||||
editorAction();
|
editorAction();
|
||||||
|
@ -164,93 +195,93 @@
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
var storedSlideNumber;
|
var storedSlideNumber;
|
||||||
commandField = $('#commandField');
|
commandField = $("#commandField");
|
||||||
commandField.addEventListener('keydown', commandListener);
|
commandField.addEventListener("keydown", commandListener);
|
||||||
commandField.addEventListener('blur', function (event) {
|
commandField.addEventListener("blur", function (event) {
|
||||||
toggleCommandBar(false);
|
toggleCommandBar(false);
|
||||||
});
|
});
|
||||||
commandBar = $('body > nav');
|
commandBar = $("body > nav");
|
||||||
toggleCommandBar(false);
|
toggleCommandBar(false);
|
||||||
|
|
||||||
slides = $$('main>section, [janus-timeline]');
|
slides = $$("main>section, [janus-timeline]");
|
||||||
shortcut.add('Page_down', function () {
|
shortcut.add("Page_down", function () {
|
||||||
setCurrentSlide(currentSlideNumber + 1, true);
|
setCurrentSlide(currentSlideNumber + 1, true);
|
||||||
});
|
});
|
||||||
shortcut.add('Page_up', function () {
|
shortcut.add("Page_up", function () {
|
||||||
setCurrentSlide(currentSlideNumber - 1, true);
|
setCurrentSlide(currentSlideNumber - 1, true);
|
||||||
});
|
});
|
||||||
shortcut.add('Escape', function () {
|
shortcut.add("Escape", function () {
|
||||||
toggleCommandBar(!commandBarVisible);
|
toggleCommandBar(!commandBarVisible);
|
||||||
});
|
});
|
||||||
|
|
||||||
storedSlideNumber = localStorage.getItem('janus-currentSlideNumber');
|
storedSlideNumber = localStorage.getItem("janus-currentSlideNumber");
|
||||||
if (storedSlideNumber) {
|
if (storedSlideNumber) {
|
||||||
setCurrentSlide(storedSlideNumber, false);
|
setCurrentSlide(storedSlideNumber, false);
|
||||||
} else {
|
} else {
|
||||||
setCurrentSlide(0);
|
setCurrentSlide(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('mousemove', mouseListener);
|
document.addEventListener("mousemove", mouseListener);
|
||||||
|
|
||||||
localStorageActions = {
|
localStorageActions = {
|
||||||
'janus-currentSlideNumber': function (event) {
|
"janus-currentSlideNumber": function (event) {
|
||||||
setCurrentSlide(+event.newValue, false);
|
setCurrentSlide(+event.newValue, false);
|
||||||
},
|
},
|
||||||
'mouse-x' : function (event) {
|
"mouse-x" : function (event) {
|
||||||
setMouseX(event.newValue, false);
|
setMouseX(event.newValue, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$$('[janus-sync]').forEach(function (current, index, array) {
|
$$("[janus-sync]").forEach(function (current, index, array) {
|
||||||
var currentKey, storedValue, decodedValue, group;
|
var currentKey, storedValue, decodedValue, group, replacedText;
|
||||||
syncFormElements.push(current);
|
syncFormElements.push(current);
|
||||||
if (current.type === 'textarea' || current.type === 'text') {
|
if (current.type === "textarea" || current.type === "text") {
|
||||||
currentKey = 'janus-input-' + index;
|
currentKey = "janus-input-" + index;
|
||||||
storedValue = localStorage.getItem(currentKey);
|
storedValue = localStorage.getItem(currentKey);
|
||||||
if (storedValue) {
|
if (storedValue) {
|
||||||
decodedValue = storedValue.split('/', 2);
|
decodedValue = storedValue.split("/", 2);
|
||||||
decodedValue.push(storedValue.slice(decodedValue.join(' ').length + 1));
|
decodedValue.push(storedValue.slice(decodedValue.join(" ").length + 1));
|
||||||
current.value = decodedValue[2];
|
current.value = decodedValue[2];
|
||||||
current.setSelectionRange(+decodedValue[0], +decodedValue[1]);
|
current.setSelectionRange(+decodedValue[0], +decodedValue[1]);
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem(currentKey, '0/0/' + current.value);
|
localStorage.setItem(currentKey, "0/0/" + current.value);
|
||||||
}
|
}
|
||||||
// add a listener to store changes
|
// add a listener to store changes
|
||||||
current.addEventListener('keyup', function () {
|
current.addEventListener("keyup", function (event) {
|
||||||
localStorage.setItem(currentKey, current.selectionStart + '/' + current.selectionEnd + '/' + current.value);
|
localStorage.setItem(currentKey, current.selectionStart + "/" + current.selectionEnd + "/" + current.value);
|
||||||
});
|
});
|
||||||
// add a listener to respond to localStorage updates
|
// add a listener to respond to localStorage updates
|
||||||
if (!localStorageActions[currentKey]) {
|
if (!localStorageActions[currentKey]) {
|
||||||
localStorageActions[currentKey] = function (event) {
|
localStorageActions[currentKey] = function (event) {
|
||||||
var storedValue = event.newValue,
|
var storedValue = event.newValue,
|
||||||
decodedValue = storedValue.split('/', 2);
|
decodedValue = storedValue.split("/", 2);
|
||||||
decodedValue.push(storedValue.slice(decodedValue.join(' ').length + 1));
|
decodedValue.push(storedValue.slice(decodedValue.join(" ").length + 1));
|
||||||
current.value = decodedValue[2];
|
current.value = decodedValue[2];
|
||||||
current.focus();
|
current.focus();
|
||||||
current.setSelectionRange(+decodedValue[0], +decodedValue[1]);
|
current.setSelectionRange(+decodedValue[0], +decodedValue[1]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (current.type === 'checkbox') {
|
} else if (current.type === "checkbox") {
|
||||||
currentKey = 'janus-input-' + index;
|
currentKey = "janus-input-" + index;
|
||||||
storedValue = localStorage.getItem(currentKey);
|
storedValue = localStorage.getItem(currentKey);
|
||||||
if (storedValue !== null) {
|
if (storedValue !== null) {
|
||||||
current.checked = (storedValue === 'true');
|
current.checked = (storedValue === "true");
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem(currentKey, current.checked);
|
localStorage.setItem(currentKey, current.checked);
|
||||||
}
|
}
|
||||||
// add a listener to store changes
|
// add a listener to store changes
|
||||||
current.addEventListener('change', function () {
|
current.addEventListener("change", function (event) {
|
||||||
localStorage.setItem(currentKey, current.checked);
|
localStorage.setItem(currentKey, current.checked);
|
||||||
});
|
});
|
||||||
// add a listener to respond to localStorage updates
|
// add a listener to respond to localStorage updates
|
||||||
if (!localStorageActions[currentKey]) {
|
if (!localStorageActions[currentKey]) {
|
||||||
localStorageActions[currentKey] = function (event) {
|
localStorageActions[currentKey] = function (event) {
|
||||||
current.checked = (event.newValue === 'true');
|
current.checked = (event.newValue === "true");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (current.type === 'radio') {
|
} else if (current.type === "radio") {
|
||||||
group = current.getAttribute('name');
|
group = current.getAttribute("name");
|
||||||
currentKey = 'janus-input-' + group;
|
currentKey = "janus-input-" + group;
|
||||||
storedValue = localStorage.getItem(currentKey);
|
storedValue = localStorage.getItem(currentKey);
|
||||||
if (storedValue !== null && +storedValue === index) {
|
if (storedValue !== null && +storedValue === index) {
|
||||||
current.checked = true;
|
current.checked = true;
|
||||||
|
@ -258,7 +289,7 @@
|
||||||
localStorage.setItem(currentKey, index);
|
localStorage.setItem(currentKey, index);
|
||||||
}
|
}
|
||||||
// add a listener to store changes
|
// add a listener to store changes
|
||||||
current.addEventListener('change', function () {
|
current.addEventListener("change", function () {
|
||||||
localStorage.setItem(currentKey, index);
|
localStorage.setItem(currentKey, index);
|
||||||
});
|
});
|
||||||
// add a listener to respond to localStorage updates
|
// add a listener to respond to localStorage updates
|
||||||
|
@ -270,13 +301,13 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$$('.live-coding').forEach(function (current, index, array) {
|
$$(".live-coding").forEach(function (current, index, array) {
|
||||||
editorListenerGenerator(current);
|
editorListenerGenerator(current);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.classList.remove('is-loading');
|
document.body.classList.remove("is-loading");
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', init);
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
window.addEventListener('storage', sessionListener);
|
window.addEventListener("storage", sessionListener);
|
||||||
}());
|
}());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue