|
@@ -2,63 +2,82 @@ import { LanguageService } from "./../services/languageService";
|
|
|
import { LocalizedStrings } from "./../services/localizedStringsService";
|
|
|
import { Operators } from "./../ast/operators";
|
|
|
|
|
|
-/**
|
|
|
- * source: https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
|
|
|
- *
|
|
|
-*/
|
|
|
-export function scrollIt (destination, duration = 200, easing = 'linear', callback = null) {
|
|
|
-
|
|
|
+/**
|
|
|
+ * source: https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
|
|
|
+ *
|
|
|
+ */
|
|
|
+export function scrollIt (
|
|
|
+ destination,
|
|
|
+ duration = 200,
|
|
|
+ easing = "linear",
|
|
|
+ callback = null
|
|
|
+) {
|
|
|
const easings = {
|
|
|
- linear(t) {
|
|
|
+ linear (t) {
|
|
|
return t;
|
|
|
},
|
|
|
- easeInQuad(t) {
|
|
|
+ easeInQuad (t) {
|
|
|
return t * t;
|
|
|
},
|
|
|
- easeOutQuad(t) {
|
|
|
+ easeOutQuad (t) {
|
|
|
return t * (2 - t);
|
|
|
},
|
|
|
- easeInOutQuad(t) {
|
|
|
+ easeInOutQuad (t) {
|
|
|
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
|
},
|
|
|
- easeInCubic(t) {
|
|
|
+ easeInCubic (t) {
|
|
|
return t * t * t;
|
|
|
},
|
|
|
- easeOutCubic(t) {
|
|
|
- return (--t) * t * t + 1;
|
|
|
+ easeOutCubic (t) {
|
|
|
+ return --t * t * t + 1;
|
|
|
},
|
|
|
- easeInOutCubic(t) {
|
|
|
+ easeInOutCubic (t) {
|
|
|
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
|
|
},
|
|
|
- easeInQuart(t) {
|
|
|
+ easeInQuart (t) {
|
|
|
return t * t * t * t;
|
|
|
},
|
|
|
- easeOutQuart(t) {
|
|
|
- return 1 - (--t) * t * t * t;
|
|
|
+ easeOutQuart (t) {
|
|
|
+ return 1 - --t * t * t * t;
|
|
|
},
|
|
|
- easeInOutQuart(t) {
|
|
|
- return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
|
|
|
+ easeInOutQuart (t) {
|
|
|
+ return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
|
|
|
},
|
|
|
- easeInQuint(t) {
|
|
|
+ easeInQuint (t) {
|
|
|
return t * t * t * t * t;
|
|
|
},
|
|
|
- easeOutQuint(t) {
|
|
|
- return 1 + (--t) * t * t * t * t;
|
|
|
+ easeOutQuint (t) {
|
|
|
+ return 1 + --t * t * t * t * t;
|
|
|
+ },
|
|
|
+ easeInOutQuint (t) {
|
|
|
+ return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
|
|
|
},
|
|
|
- easeInOutQuint(t) {
|
|
|
- return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
|
|
|
- }
|
|
|
};
|
|
|
|
|
|
const start = window.pageYOffset;
|
|
|
- const startTime = 'now' in window.performance ? performance.now() : new Date().getTime();
|
|
|
+ const startTime =
|
|
|
+ "now" in window.performance ? performance.now() : new Date().getTime();
|
|
|
|
|
|
- const documentHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
|
|
|
- const windowHeight = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight;
|
|
|
- const destinationOffset = typeof destination === 'number' ? destination : destination.offsetTop;
|
|
|
- const destinationOffsetToScroll = Math.round(documentHeight - destinationOffset < windowHeight ? documentHeight - windowHeight : destinationOffset);
|
|
|
+ const documentHeight = Math.max(
|
|
|
+ document.body.scrollHeight,
|
|
|
+ document.body.offsetHeight,
|
|
|
+ document.documentElement.clientHeight,
|
|
|
+ document.documentElement.scrollHeight,
|
|
|
+ document.documentElement.offsetHeight
|
|
|
+ );
|
|
|
+ const windowHeight =
|
|
|
+ window.innerHeight ||
|
|
|
+ document.documentElement.clientHeight ||
|
|
|
+ document.getElementsByTagName("body")[0].clientHeight;
|
|
|
+ const destinationOffset =
|
|
|
+ typeof destination === "number" ? destination : destination.offsetTop;
|
|
|
+ const destinationOffsetToScroll = Math.round(
|
|
|
+ documentHeight - destinationOffset < windowHeight
|
|
|
+ ? documentHeight - windowHeight
|
|
|
+ : destinationOffset
|
|
|
+ );
|
|
|
|
|
|
- if ('requestAnimationFrame' in window === false) {
|
|
|
+ if ("requestAnimationFrame" in window === false) {
|
|
|
window.scroll(0, destinationOffsetToScroll);
|
|
|
if (callback) {
|
|
|
callback();
|
|
@@ -66,11 +85,15 @@ export function scrollIt (destination, duration = 200, easing = 'linear', callba
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- function scroll() {
|
|
|
- const now = 'now' in window.performance ? performance.now() : new Date().getTime();
|
|
|
- const time = Math.min(1, ((now - startTime) / duration));
|
|
|
+ function scroll () {
|
|
|
+ const now =
|
|
|
+ "now" in window.performance ? performance.now() : new Date().getTime();
|
|
|
+ const time = Math.min(1, (now - startTime) / duration);
|
|
|
const timeFunction = easings[easing](time);
|
|
|
- window.scroll(0, Math.ceil((timeFunction * (destinationOffsetToScroll - start)) + start));
|
|
|
+ window.scroll(
|
|
|
+ 0,
|
|
|
+ Math.ceil(timeFunction * (destinationOffsetToScroll - start) + start)
|
|
|
+ );
|
|
|
|
|
|
if (window.pageYOffset === destinationOffsetToScroll) {
|
|
|
if (callback) {
|
|
@@ -86,42 +109,67 @@ export function scrollIt (destination, duration = 200, easing = 'linear', callba
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* source: https://stackoverflow.com/a/16270434
|
|
|
*/
|
|
|
export function isElementInViewport (el) {
|
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
|
|
- return rect.bottom > 0 &&
|
|
|
+ return (
|
|
|
+ rect.bottom > 0 &&
|
|
|
rect.right > 0 &&
|
|
|
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
|
|
|
- rect.top < (window.innerHeight || document.documentElement.clientHeight);
|
|
|
+ rect.top < (window.innerHeight || document.documentElement.clientHeight)
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
let cacheMainList = null;
|
|
|
let cacheOp = null;
|
|
|
|
|
|
function fillCache () {
|
|
|
- if(cacheMainList == null) {
|
|
|
+ if (cacheMainList == null) {
|
|
|
cacheMainList = [];
|
|
|
- const mainList = ["RK_PROGRAM","RK_REAL","RK_VOID","RK_BOOLEAN","RK_STRING",
|
|
|
- "RK_INTEGER","RK_CHARACTER","RK_SWITCH","RK_CASE","RK_DEFAULT","RK_CONST",
|
|
|
- "RK_FUNCTION","RK_RETURN","RK_FOR","RK_BREAK","RK_DO","RK_WHILE","RK_IF",
|
|
|
- "RK_ELSE","RK_FALSE","RK_TRUE"];
|
|
|
- const lexerClass = LanguageService.getCurrentLexer();
|
|
|
- const nullLexer = new lexerClass();
|
|
|
+ const mainList = [
|
|
|
+ "RK_PROGRAM",
|
|
|
+ "RK_REAL",
|
|
|
+ "RK_VOID",
|
|
|
+ "RK_BOOLEAN",
|
|
|
+ "RK_STRING",
|
|
|
+ "RK_INTEGER",
|
|
|
+ "RK_CHARACTER",
|
|
|
+ "RK_SWITCH",
|
|
|
+ "RK_CASE",
|
|
|
+ "RK_DEFAULT",
|
|
|
+ "RK_CONST",
|
|
|
+ "RK_FUNCTION",
|
|
|
+ "RK_RETURN",
|
|
|
+ "RK_FOR",
|
|
|
+ "RK_BREAK",
|
|
|
+ "RK_DO",
|
|
|
+ "RK_WHILE",
|
|
|
+ "RK_IF",
|
|
|
+ "RK_ELSE",
|
|
|
+ "RK_FALSE",
|
|
|
+ "RK_TRUE",
|
|
|
+ ];
|
|
|
+ const lexer = LanguageService.getCurrentLexer();
|
|
|
+ const names = lexer.getReservedKeys();
|
|
|
for (let key = 0; key < mainList.length; ++key) {
|
|
|
const word = mainList[key];
|
|
|
- const keyword = nullLexer.literalNames[lexerClass[word]];
|
|
|
- cacheMainList.push(keyword.substring(1, keyword.length-1));
|
|
|
+ const keyword = names[word];
|
|
|
+ cacheMainList.push(keyword);
|
|
|
}
|
|
|
}
|
|
|
- if(cacheOp == null) {
|
|
|
- cacheOp = []
|
|
|
- const logicOpList = [Operators.AND.value, Operators.OR.value, Operators.NOT.value];
|
|
|
+ if (cacheOp == null) {
|
|
|
+ cacheOp = [];
|
|
|
+ const logicOpList = [
|
|
|
+ Operators.AND.value,
|
|
|
+ Operators.OR.value,
|
|
|
+ Operators.NOT.value,
|
|
|
+ ];
|
|
|
for (let op = 0; op < logicOpList.length; ++op) {
|
|
|
const lOp = `logic_operator_${logicOpList[op]}`;
|
|
|
- cacheOp.push(LocalizedStrings.getUI(lOp))
|
|
|
+ cacheOp.push(LocalizedStrings.getUI(lOp));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -130,14 +178,14 @@ export function isKeyword (text) {
|
|
|
fillCache();
|
|
|
for (let key = 0; key < cacheMainList.length; ++key) {
|
|
|
const keyword = cacheMainList[key];
|
|
|
- if(keyword == text) {
|
|
|
+ if (keyword == text) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
// not in main list, check op
|
|
|
for (let op = 0; op < cacheOp.length; op++) {
|
|
|
const lOp = cacheOp[op];
|
|
|
- if(lOp == text) {
|
|
|
+ if (lOp == text) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -146,122 +194,153 @@ export function isKeyword (text) {
|
|
|
|
|
|
export function isValidIdentifier (identifier_str) {
|
|
|
const validRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier_str);
|
|
|
- if(!validRegex) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- return !isKeyword(identifier_str);
|
|
|
+ return validRegex && !isKeyword(identifier_str)
|
|
|
}
|
|
|
|
|
|
export function getCodeEditorModeConfig () {
|
|
|
- const blockList = ["RK_SWITCH", "RK_PROGRAM","RK_CASE","RK_DEFAULT","RK_FOR","RK_FOR_ALT",
|
|
|
- "RK_FUNCTION","RK_DO","RK_WHILE","RK_WHILE_ALT","RK_IF","RK_ELSE"]
|
|
|
- const keywordsList = ["RK_CONST","RK_RETURN","RK_BREAK","RK_FOR_FROM","RK_FOR_TO","RK_FOR_PASS","RK_DO_UNTIL"];
|
|
|
- const typeList = ["RK_REAL","RK_VOID","RK_BOOLEAN","RK_STRING","RK_INTEGER","RK_CHARACTER"];
|
|
|
+ const blockList = [
|
|
|
+ "RK_SWITCH",
|
|
|
+ "RK_PROGRAM",
|
|
|
+ "RK_CASE",
|
|
|
+ "RK_DEFAULT",
|
|
|
+ "RK_FOR",
|
|
|
+ "RK_FOR_ALT",
|
|
|
+ "RK_FUNCTION",
|
|
|
+ "RK_DO",
|
|
|
+ "RK_WHILE",
|
|
|
+ "RK_WHILE_ALT",
|
|
|
+ "RK_IF",
|
|
|
+ "RK_ELSE",
|
|
|
+ ];
|
|
|
+ const keywordsList = [
|
|
|
+ "RK_CONST",
|
|
|
+ "RK_RETURN",
|
|
|
+ "RK_BREAK",
|
|
|
+ "RK_FOR_FROM",
|
|
|
+ "RK_FOR_TO",
|
|
|
+ "RK_FOR_PASS",
|
|
|
+ "RK_DO_UNTIL",
|
|
|
+ ];
|
|
|
+ const typeList = [
|
|
|
+ "RK_REAL",
|
|
|
+ "RK_VOID",
|
|
|
+ "RK_BOOLEAN",
|
|
|
+ "RK_STRING",
|
|
|
+ "RK_INTEGER",
|
|
|
+ "RK_CHARACTER",
|
|
|
+ ];
|
|
|
const atomList = ["RK_FALSE", "RK_TRUE"];
|
|
|
|
|
|
const case_default = [];
|
|
|
const blocks = [];
|
|
|
const keywords = [];
|
|
|
const types = [];
|
|
|
- const atoms = []
|
|
|
+ const atoms = [];
|
|
|
let switchString = "";
|
|
|
|
|
|
cacheMainList = [];
|
|
|
- const lexerClass = LanguageService.getCurrentLexer();
|
|
|
- const nullLexer = new lexerClass();
|
|
|
- blockList.forEach( v => {
|
|
|
- const keyword = nullLexer.literalNames[lexerClass[v]];
|
|
|
- const value = keyword.substring(1, keyword.length-1);
|
|
|
+ const lexer = LanguageService.getCurrentLexer();
|
|
|
+ const names = lexer.getReservedKeys();
|
|
|
+ //console.debug(names);
|
|
|
+ blockList.forEach((v) => {
|
|
|
+ const keyword = names[v];
|
|
|
+ const value = keyword;
|
|
|
cacheMainList.push(value);
|
|
|
keywords.push(value);
|
|
|
blocks.push(value);
|
|
|
- if(v == "RK_SWITCH") {
|
|
|
+ if (v == "RK_SWITCH") {
|
|
|
switchString = value;
|
|
|
} else if (v == "RK_CASE" || v == "RK_DEFAULT") {
|
|
|
case_default.push(value);
|
|
|
}
|
|
|
});
|
|
|
- keywordsList.forEach( v => {
|
|
|
- const keyword = nullLexer.literalNames[lexerClass[v]];
|
|
|
- const value = keyword.substring(1, keyword.length-1);
|
|
|
+ keywordsList.forEach((v) => {
|
|
|
+ const keyword = names[v];
|
|
|
+ const value = keyword;
|
|
|
cacheMainList.push(value);
|
|
|
keywords.push(value);
|
|
|
});
|
|
|
- typeList.forEach(v => {
|
|
|
- const keyword = nullLexer.literalNames[lexerClass[v]];
|
|
|
- const value = keyword.substring(1, keyword.length-1);
|
|
|
+ typeList.forEach((v) => {
|
|
|
+ const keyword = names[v];
|
|
|
+ const value = keyword;
|
|
|
cacheMainList.push(value);
|
|
|
types.push(value);
|
|
|
- })
|
|
|
- atomList.forEach( v => {
|
|
|
- const keyword = nullLexer.literalNames[lexerClass[v]];
|
|
|
- const value = keyword.substring(1, keyword.length-1);
|
|
|
+ });
|
|
|
+ atomList.forEach((v) => {
|
|
|
+ const keyword = names[v];
|
|
|
+ const value = keyword;
|
|
|
cacheMainList.push(value);
|
|
|
atoms.push(value);
|
|
|
- })
|
|
|
-
|
|
|
- cacheOp = []
|
|
|
- const logicOpList = [Operators.AND.value, Operators.OR.value, Operators.NOT.value];
|
|
|
- for (let op = 0; op < logicOpList.length; ++op) {
|
|
|
- const lOp = `logic_operator_${logicOpList[op]}`;
|
|
|
- const value = LocalizedStrings.getUI(lOp);
|
|
|
- cacheOp.push(value)
|
|
|
+ });
|
|
|
+
|
|
|
+ cacheOp = [];
|
|
|
+ const logicOpList = ["NOT_OPERATOR", "OR_OPERATOR", "AND_OPERATOR"];
|
|
|
+
|
|
|
+ logicOpList.forEach((v) => {
|
|
|
+ const keyword = names[v];
|
|
|
+ const value = keyword;
|
|
|
+ cacheOp.push(value);
|
|
|
keywords.push(value);
|
|
|
- }
|
|
|
+ });
|
|
|
+ cacheMainList.push(lexer.getLangFuncs().main_function);
|
|
|
return {
|
|
|
case_default: case_default,
|
|
|
atoms: atoms,
|
|
|
keywords: keywords,
|
|
|
switchString: switchString,
|
|
|
types: types,
|
|
|
- blocks: blocks
|
|
|
- }
|
|
|
+ blocks: blocks,
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Source: https://gist.github.com/andrei-m/982927
|
|
|
- * @param {string} a
|
|
|
- * @param {string} b
|
|
|
+ * @param {string} a
|
|
|
+ * @param {string} b
|
|
|
*/
|
|
|
export function levenshteinDistance (a, b) {
|
|
|
- if(a.length == 0) return b.length;
|
|
|
- if(b.length == 0) return a.length;
|
|
|
+ if (a.length == 0) return b.length;
|
|
|
+ if (b.length == 0) return a.length;
|
|
|
|
|
|
const matrix = [];
|
|
|
|
|
|
// increment along the first column of each row
|
|
|
let i;
|
|
|
- for(i = 0; i <= b.length; i++){
|
|
|
+ for (i = 0; i <= b.length; i++) {
|
|
|
matrix[i] = [i];
|
|
|
}
|
|
|
|
|
|
// increment each column in the first row
|
|
|
let j;
|
|
|
- for(j = 0; j <= a.length; j++){
|
|
|
+ for (j = 0; j <= a.length; j++) {
|
|
|
matrix[0][j] = j;
|
|
|
}
|
|
|
|
|
|
// Fill in the rest of the matrix
|
|
|
- for(i = 1; i <= b.length; i++){
|
|
|
- for(j = 1; j <= a.length; j++){
|
|
|
- if(b.charCodeAt(i-1) == a.charCodeAt(j-1)){
|
|
|
- matrix[i][j] = matrix[i-1][j-1];
|
|
|
+ for (i = 1; i <= b.length; i++) {
|
|
|
+ for (j = 1; j <= a.length; j++) {
|
|
|
+ if (b.charCodeAt(i - 1) == a.charCodeAt(j - 1)) {
|
|
|
+ matrix[i][j] = matrix[i - 1][j - 1];
|
|
|
} else {
|
|
|
- matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
|
|
|
- Math.min(matrix[i][j-1] + 1, // insertion
|
|
|
- matrix[i-1][j] + 1)); // deletion
|
|
|
+ matrix[i][j] = Math.min(
|
|
|
+ matrix[i - 1][j - 1] + 1, // substitution
|
|
|
+ Math.min(
|
|
|
+ matrix[i][j - 1] + 1, // insertion
|
|
|
+ matrix[i - 1][j] + 1
|
|
|
+ )
|
|
|
+ ); // deletion
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return matrix[b.length][a.length];
|
|
|
}
|
|
|
|
|
|
-let win = null
|
|
|
+let win = null;
|
|
|
export function openAssessmentDetail (event) {
|
|
|
event.preventDefault();
|
|
|
const page_code = event.currentTarget.dataset.page;
|
|
|
- if(win != null) {
|
|
|
- win.close()
|
|
|
+ if (win != null) {
|
|
|
+ win.close();
|
|
|
}
|
|
|
win = window.open("", "DetailWindow", "width=550,height=600");
|
|
|
win.document.open();
|
|
@@ -270,13 +349,13 @@ export function openAssessmentDetail (event) {
|
|
|
}
|
|
|
|
|
|
export function range (size, startAt = 0) {
|
|
|
- return [...Array(size).keys()].map(i => i + startAt);
|
|
|
+ return [...Array(size).keys()].map((i) => i + startAt);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
- * @param {number} ms
|
|
|
+ *
|
|
|
+ * @param {number} ms
|
|
|
*/
|
|
|
export async function sleep (ms) {
|
|
|
- return new Promise( (res, _) => setTimeout(res, ms));
|
|
|
- }
|
|
|
+ return new Promise((res, _) => setTimeout(res, ms));
|
|
|
+}
|