diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..79a710fd --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..28a804d8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/_server/CodeMirror/codemirror.css b/_server/CodeMirror/codemirror.css index c7a8ae70..07ccdf75 100644 --- a/_server/CodeMirror/codemirror.css +++ b/_server/CodeMirror/codemirror.css @@ -1,154 +1,285 @@ /* BASICS */ .CodeMirror { - /* Set height, width, borders, and global font properties here */ - font-family: monospace; - height: 300px; - color: black; - direction: ltr; + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + direction: ltr; } /* PADDING */ .CodeMirror-lines { - padding: 4px 0; /* Vertical padding around content */ + padding: 4px 0; /* Vertical padding around content */ } + .CodeMirror pre { - padding: 0 4px; /* Horizontal padding of content */ + padding: 0 4px; /* Horizontal padding of content */ } .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - background-color: white; /* The little square between H and V scrollbars */ + background-color: white; /* The little square between H and V scrollbars */ } /* GUTTER */ .CodeMirror-gutters { - border-right: 1px solid #ddd; - background-color: #f7f7f7; - white-space: nowrap; -} -.CodeMirror-linenumbers {} -.CodeMirror-linenumber { - padding: 0 3px 0 5px; - min-width: 20px; - text-align: right; - color: #999; - white-space: nowrap; + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; } -.CodeMirror-guttermarker { color: black; } -.CodeMirror-guttermarker-subtle { color: #999; } +.CodeMirror-linenumbers { +} + +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { + color: black; +} + +.CodeMirror-guttermarker-subtle { + color: #999; +} /* CURSOR */ .CodeMirror-cursor { - border-left: 1px solid black; - border-right: none; - width: 0; + border-left: 1px solid black; + border-right: none; + width: 0; } + /* Shown when moving in bi-directional text */ .CodeMirror div.CodeMirror-secondarycursor { - border-left: 1px solid silver; + border-left: 1px solid silver; } + .cm-fat-cursor .CodeMirror-cursor { - width: auto; - border: 0 !important; - background: #7e7; + width: auto; + border: 0 !important; + background: #7e7; } + .cm-fat-cursor div.CodeMirror-cursors { - z-index: 1; + z-index: 1; } + .cm-fat-cursor-mark { - background-color: rgba(20, 255, 20, 0.5); - -webkit-animation: blink 1.06s steps(1) infinite; - -moz-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; } + .cm-animate-fat-cursor { - width: auto; - border: 0; - -webkit-animation: blink 1.06s steps(1) infinite; - -moz-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; - background-color: #7e7; + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; } + @-moz-keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} + 0% { + } + 50% { + background-color: transparent; + } + 100% { + } } + @-webkit-keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} + 0% { + } + 50% { + background-color: transparent; + } + 100% { + } } + @keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} + 0% { + } + 50% { + background-color: transparent; + } + 100% { + } } /* Can style cursor different in overwrite (non-insert) mode */ -.CodeMirror-overwrite .CodeMirror-cursor {} +.CodeMirror-overwrite .CodeMirror-cursor { +} -.cm-tab { display: inline-block; text-decoration: inherit; } +.cm-tab { + display: inline-block; + text-decoration: inherit; +} .CodeMirror-rulers { - position: absolute; - left: 0; right: 0; top: -50px; bottom: -20px; - overflow: hidden; + position: absolute; + left: 0; + right: 0; + top: -50px; + bottom: -20px; + overflow: hidden; } + .CodeMirror-ruler { - border-left: 1px solid #ccc; - top: 0; bottom: 0; - position: absolute; + border-left: 1px solid #ccc; + top: 0; + bottom: 0; + position: absolute; } /* DEFAULT THEME */ -.cm-s-default .cm-header {color: blue;} -.cm-s-default .cm-quote {color: #090;} -.cm-negative {color: #d44;} -.cm-positive {color: #292;} -.cm-header, .cm-strong {font-weight: bold;} -.cm-em {font-style: italic;} -.cm-link {text-decoration: underline;} -.cm-strikethrough {text-decoration: line-through;} +.cm-s-default .cm-header { + color: blue; +} + +.cm-s-default .cm-quote { + color: #090; +} + +.cm-negative { + color: #d44; +} + +.cm-positive { + color: #292; +} + +.cm-header, .cm-strong { + font-weight: bold; +} + +.cm-em { + font-style: italic; +} + +.cm-link { + text-decoration: underline; +} + +.cm-strikethrough { + text-decoration: line-through; +} + +.cm-s-default .cm-keyword { + color: #708; +} + +.cm-s-default .cm-atom { + color: #219; +} + +.cm-s-default .cm-number { + color: #164; +} + +.cm-s-default .cm-def { + color: #00f; +} -.cm-s-default .cm-keyword {color: #708;} -.cm-s-default .cm-atom {color: #219;} -.cm-s-default .cm-number {color: #164;} -.cm-s-default .cm-def {color: #00f;} .cm-s-default .cm-variable, .cm-s-default .cm-punctuation, .cm-s-default .cm-property, -.cm-s-default .cm-operator {} -.cm-s-default .cm-variable-2 {color: #05a;} -.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} -.cm-s-default .cm-comment {color: #a50;} -.cm-s-default .cm-string {color: #a11;} -.cm-s-default .cm-string-2 {color: #f50;} -.cm-s-default .cm-meta {color: #555;} -.cm-s-default .cm-qualifier {color: #555;} -.cm-s-default .cm-builtin {color: #30a;} -.cm-s-default .cm-bracket {color: #997;} -.cm-s-default .cm-tag {color: #170;} -.cm-s-default .cm-attribute {color: #00c;} -.cm-s-default .cm-hr {color: #999;} -.cm-s-default .cm-link {color: #00c;} +.cm-s-default .cm-operator { +} -.cm-s-default .cm-error {color: #f00;} -.cm-invalidchar {color: #f00;} +.cm-s-default .cm-variable-2 { + color: #05a; +} -.CodeMirror-composing { border-bottom: 2px solid; } +.cm-s-default .cm-variable-3, .cm-s-default .cm-type { + color: #085; +} + +.cm-s-default .cm-comment { + color: #a50; +} + +.cm-s-default .cm-string { + color: #a11; +} + +.cm-s-default .cm-string-2 { + color: #f50; +} + +.cm-s-default .cm-meta { + color: #555; +} + +.cm-s-default .cm-qualifier { + color: #555; +} + +.cm-s-default .cm-builtin { + color: #30a; +} + +.cm-s-default .cm-bracket { + color: #997; +} + +.cm-s-default .cm-tag { + color: #170; +} + +.cm-s-default .cm-attribute { + color: #00c; +} + +.cm-s-default .cm-hr { + color: #999; +} + +.cm-s-default .cm-link { + color: #00c; +} + +.cm-s-default .cm-error { + color: #f00; +} + +.cm-invalidchar { + color: #f00; +} + +.CodeMirror-composing { + border-bottom: 2px solid; +} /* Default styles for common addons */ -div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} -div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} -.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } -.CodeMirror-activeline-background {background: #e8f2ff;} +div.CodeMirror span.CodeMirror-matchingbracket { + color: #0b0; +} + +div.CodeMirror span.CodeMirror-nonmatchingbracket { + color: #a22; +} + +.CodeMirror-matchingtag { + background: rgba(255, 150, 0, .3); +} + +.CodeMirror-activeline-background { + background: #e8f2ff; +} /* STOP */ @@ -156,129 +287,162 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} the editor. You probably shouldn't touch them. */ .CodeMirror { - position: relative; - overflow: hidden; - background: white; + position: relative; + overflow: hidden; + background: white; } .CodeMirror-scroll { - overflow: scroll !important; /* Things will break if this is overridden */ - /* 30px is the magic margin used to hide the element's real scrollbars */ - /* See overflow: hidden in .CodeMirror */ - margin-bottom: -30px; margin-right: -30px; - padding-bottom: 30px; - height: 100%; - outline: none; /* Prevent dragging from highlighting the element */ - position: relative; + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; + margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; } + .CodeMirror-sizer { - position: relative; - border-right: 30px solid transparent; + position: relative; + border-right: 30px solid transparent; } /* The fake, visible scrollbars. Used to force redraw during scrolling before actual scrolling happens, thus preventing shaking and flickering artifacts. */ .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - position: absolute; - z-index: 6; - display: none; + position: absolute; + z-index: 6; + display: none; } + .CodeMirror-vscrollbar { - right: 0; top: 0; - overflow-x: hidden; - overflow-y: scroll; + right: 0; + top: 0; + overflow-x: hidden; + overflow-y: scroll; } + .CodeMirror-hscrollbar { - bottom: 0; left: 0; - overflow-y: hidden; - overflow-x: scroll; + bottom: 0; + left: 0; + overflow-y: hidden; + overflow-x: scroll; } + .CodeMirror-scrollbar-filler { - right: 0; bottom: 0; + right: 0; + bottom: 0; } + .CodeMirror-gutter-filler { - left: 0; bottom: 0; + left: 0; + bottom: 0; } .CodeMirror-gutters { - position: absolute; left: 0; top: 0; - min-height: 100%; - z-index: 3; + position: absolute; + left: 0; + top: 0; + min-height: 100%; + z-index: 3; } + .CodeMirror-gutter { - white-space: normal; - height: 100%; - display: inline-block; - vertical-align: top; - margin-bottom: -30px; + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; } + .CodeMirror-gutter-wrapper { - position: absolute; - z-index: 4; - background: none !important; - border: none !important; + position: absolute; + z-index: 4; + background: none !important; + border: none !important; } + .CodeMirror-gutter-background { - position: absolute; - top: 0; bottom: 0; - z-index: 4; + position: absolute; + top: 0; + bottom: 0; + z-index: 4; } + .CodeMirror-gutter-elt { - position: absolute; - cursor: default; - z-index: 4; + position: absolute; + cursor: default; + z-index: 4; +} + +.CodeMirror-gutter-wrapper ::selection { + background-color: transparent +} + +.CodeMirror-gutter-wrapper ::-moz-selection { + background-color: transparent } -.CodeMirror-gutter-wrapper ::selection { background-color: transparent } -.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } .CodeMirror-lines { - cursor: text; - min-height: 1px; /* prevents collapsing before first draw */ + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ } + .CodeMirror pre { - /* Reset some styles that the rest of the page might have set */ - -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; - border-width: 0; - background: transparent; - font-family: inherit; - font-size: inherit; - margin: 0; - white-space: pre; - word-wrap: normal; - line-height: inherit; - color: inherit; - z-index: 2; - position: relative; - overflow: visible; - -webkit-tap-highlight-color: transparent; - -webkit-font-variant-ligatures: contextual; - font-variant-ligatures: contextual; + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; } + .CodeMirror-wrap pre { - word-wrap: break-word; - white-space: pre-wrap; - word-break: normal; + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; } .CodeMirror-linebackground { - position: absolute; - left: 0; right: 0; top: 0; bottom: 0; - z-index: 0; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 0; } .CodeMirror-linewidget { - position: relative; - z-index: 2; - padding: 0.1px; /* Force widget margins to stay inside of the container */ + position: relative; + z-index: 2; + padding: 0.1px; /* Force widget margins to stay inside of the container */ } -.CodeMirror-widget {} +.CodeMirror-widget { +} -.CodeMirror-rtl pre { direction: rtl; } +.CodeMirror-rtl pre { + direction: rtl; +} .CodeMirror-code { - outline: none; + outline: none; } /* Force content-box sizing for the elements where we expect it */ @@ -287,60 +451,84 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} .CodeMirror-gutter, .CodeMirror-gutters, .CodeMirror-linenumber { - -moz-box-sizing: content-box; - box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; } .CodeMirror-measure { - position: absolute; - width: 100%; - height: 0; - overflow: hidden; - visibility: hidden; + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; } .CodeMirror-cursor { - position: absolute; - pointer-events: none; + position: absolute; + pointer-events: none; +} + +.CodeMirror-measure pre { + position: static; } -.CodeMirror-measure pre { position: static; } div.CodeMirror-cursors { - visibility: hidden; - position: relative; - z-index: 3; + visibility: hidden; + position: relative; + z-index: 3; } + div.CodeMirror-dragcursors { - visibility: visible; + visibility: visible; } .CodeMirror-focused div.CodeMirror-cursors { - visibility: visible; + visibility: visible; } -.CodeMirror-selected { background: #d9d9d9; } -.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } -.CodeMirror-crosshair { cursor: crosshair; } -.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } -.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } +.CodeMirror-selected { + background: #d9d9d9; +} + +.CodeMirror-focused .CodeMirror-selected { + background: #d7d4f0; +} + +.CodeMirror-crosshair { + cursor: crosshair; +} + +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { + background: #d7d4f0; +} + +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { + background: #d7d4f0; +} .cm-searching { - background-color: #ffa; - background-color: rgba(255, 255, 0, .4); + background-color: #ffa; + background-color: rgba(255, 255, 0, .4); } /* Used to force a border model for a node */ -.cm-force-border { padding-right: .1px; } +.cm-force-border { + padding-right: .1px; +} @media print { - /* Hide the cursor when printing */ - .CodeMirror div.CodeMirror-cursors { - visibility: hidden; - } + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } } /* See issue #2901 */ -.cm-tab-wrap-hack:after { content: ''; } +.cm-tab-wrap-hack:after { + content: ''; +} /* Help users use markselection to safely style text background */ -span.CodeMirror-selectedtext { background: none; } +span.CodeMirror-selectedtext { + background: none; +} diff --git a/_server/CodeMirror/javascript-hint.js b/_server/CodeMirror/javascript-hint.js index 21d1fe9a..e84049f1 100644 --- a/_server/CodeMirror/javascript-hint.js +++ b/_server/CodeMirror/javascript-hint.js @@ -1,156 +1,165 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE -(function(mod) { +(function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror"], mod); else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { + mod(CodeMirror); +})(function (CodeMirror) { var Pos = CodeMirror.Pos; - + function forEach(arr, f) { - for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } - + function arrayContains(arr, item) { - if (!Array.prototype.indexOf) { - var i = arr.length; - while (i--) { - if (arr[i] === item) { - return true; - } + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; } - return false; - } - return arr.indexOf(item) != -1; + return arr.indexOf(item) != -1; } - + function scriptHint(editor, keywords, getToken, options) { - // Find the token at the cursor - var cur = editor.getCursor(), token = getToken(editor, cur); - if (/\b(?:string|comment)\b/.test(token.type)) return; - token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; - - // If it's not a 'word-style' token, ignore the token. - if (!/^[\w$_]*$/.test(token.string)) { - token = {start: cur.ch, end: cur.ch, string: "", state: token.state, - type: token.string == "." ? "property" : null}; - } else if (token.end > cur.ch) { - token.end = cur.ch; - token.string = token.string.slice(0, cur.ch - token.start); - } - - var tprop = token; - // If it is a property, find out what it is a property of. - while (tprop.type == "property") { - tprop = getToken(editor, Pos(cur.line, tprop.start)); - if (tprop.string != ".") return; - tprop = getToken(editor, Pos(cur.line, tprop.start)); - if (!context) var context = []; - context.push(tprop); - } - return {list: getCompletions(token, context, keywords, options), - from: Pos(cur.line, token.start), - to: Pos(cur.line, token.end)}; + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = { + start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null + }; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + return { + list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end) + }; } - + function javascriptHint(editor, options) { - return scriptHint(editor, javascriptKeywords, - function (e, cur) {return e.getTokenAt(cur);}, - options); + return scriptHint(editor, javascriptKeywords, + function (e, cur) { + return e.getTokenAt(cur); + }, + options); }; CodeMirror.registerHelper("hint", "javascript", javascriptHint); - + function getCoffeeScriptToken(editor, cur) { - // This getToken, it is for coffeescript, imitates the behavior of - // getTokenAt method in javascript.js, that is, returning "property" - // type and treat "." as indepenent token. - var token = editor.getTokenAt(cur); - if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { - token.end = token.start; - token.string = '.'; - token.type = "property"; - } - else if (/^\.[\w$_]*$/.test(token.string)) { - token.type = "property"; - token.start++; - token.string = token.string.replace(/\./, ''); - } - return token; + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; } - + function coffeescriptHint(editor, options) { - return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); - + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + - "toUpperCase toLowerCase split concat match replace search").split(" "); + "toUpperCase toLowerCase split concat match replace search").split(" "); var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + - "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); var funcProps = "prototype apply call bind".split(" "); var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " + - "if in import instanceof new null return super switch this throw true try typeof var void while with yield").split(" "); + "if in import instanceof new null return super switch this throw true try typeof var void while with yield").split(" "); var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + - "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); - + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + function forAllProps(obj, callback) { - if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { - for (var name in obj) callback(name) - } else { - for (var o = obj; o; o = Object.getPrototypeOf(o)) - Object.getOwnPropertyNames(o).forEach(callback) - } - } - - function getCompletions(token, context, keywords, options) { - var found = [], start = token.string, global = options && options.globalScope || window; - function maybeAdd(str) { - if (str==null || str==undefined) return; - if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); - } - function gatherCompletions(obj) { - if (typeof obj == "string") forEach(stringProps, maybeAdd); - else if (obj instanceof Array) forEach(arrayProps, maybeAdd); - else if (obj instanceof Function) forEach(funcProps, maybeAdd); - forAllProps(obj, maybeAdd) - } - - if (context && context.length) { - // If this is a property, see if it belongs to some object we can - // find in the current environment. - var obj = context.pop(), base; - if (obj.type && obj.type.indexOf("variable") === 0) { - if (options && options.additionalContext) - base = options.additionalContext[obj.string]; - if (!options || options.useGlobalScope !== false) - base = base || global[obj.string]; - } else if (obj.type == "string") { - base = ""; - } else if (obj.type == "atom") { - base = 1; - } else if (obj.type == "function") { - if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && - (typeof global.jQuery == 'function')) - base = global.jQuery(); - else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) - base = global._(); + if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { + for (var name in obj) callback(name) + } else { + for (var o = obj; o; o = Object.getPrototypeOf(o)) + Object.getOwnPropertyNames(o).forEach(callback) } - while (base != null && context.length) - base = base[context.pop().string]; - if (base != null) gatherCompletions(base); - } else { - // If not, just look in the global object and any local scope - // (reading into JS mode internals to get at the local and global variables) - for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); - for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); - if (!options || options.useGlobalScope !== false) - gatherCompletions(global); - forEach(keywords, maybeAdd); - } - return found; } - }); \ No newline at end of file + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + + function maybeAdd(str) { + if (str == null || str == undefined) return; + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + forAllProps(obj, maybeAdd) + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return found; + } +}); \ No newline at end of file diff --git a/_server/CodeMirror/javascript-lint.js b/_server/CodeMirror/javascript-lint.js index fc3dfdc2..a350ce66 100644 --- a/_server/CodeMirror/javascript-lint.js +++ b/_server/CodeMirror/javascript-lint.js @@ -1,63 +1,64 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE -(function(mod) { +(function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror"], mod); else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { + mod(CodeMirror); +})(function (CodeMirror) { "use strict"; + // declare global: JSHINT - + function validator(text, options) { - if (!window.JSHINT) { - if (window.console) { - window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run."); - } - return []; - } - if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation - options.indent = 1; // JSHint default value is 4 - JSHINT(text, options, options.globals); - var errors = JSHINT.data().errors, result = []; - if (errors) parseErrors(errors, result); - return result; - } - - CodeMirror.registerHelper("lint", "javascript", validator); - - function parseErrors(errors, output) { - for ( var i = 0; i < errors.length; i++) { - var error = errors[i]; - if (error) { - if (error.line <= 0) { + if (!window.JSHINT) { if (window.console) { - window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error); + window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run."); } - continue; - } - - var start = error.character - 1, end = start + 1; - if (error.evidence) { - var index = error.evidence.substring(start).search(/.\b/); - if (index > -1) { - end += index; - } - } - - // Convert to format expected by validation service - var hint = { - message: error.reason, - severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error", - from: CodeMirror.Pos(error.line - 1, start), - to: CodeMirror.Pos(error.line - 1, end) - }; - - output.push(hint); + return []; } - } + if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation + options.indent = 1; // JSHint default value is 4 + JSHINT(text, options, options.globals); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; } - }); \ No newline at end of file + + CodeMirror.registerHelper("lint", "javascript", validator); + + function parseErrors(errors, output) { + for (var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + if (error.line <= 0) { + if (window.console) { + window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error); + } + continue; + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + var index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + var hint = { + message: error.reason, + severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error", + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end) + }; + + output.push(hint); + } + } + } +}); \ No newline at end of file diff --git a/_server/CodeMirror/lint.css b/_server/CodeMirror/lint.css index 037a451d..a9a0e65b 100644 --- a/_server/CodeMirror/lint.css +++ b/_server/CodeMirror/lint.css @@ -1,9 +1,9 @@ /* The lint marker gutter */ .CodeMirror-lint-markers { width: 16px; - } - - .CodeMirror-lint-tooltip { +} + +.CodeMirror-lint-tooltip { background-color: #ffd; border: 1px solid black; border-radius: 4px 4px 4px 4px; @@ -23,24 +23,22 @@ -webkit-transition: opacity .4s; -o-transition: opacity .4s; -ms-transition: opacity .4s; - } - - .CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat-x; - } - - .CodeMirror-lint-mark-error { - background-image: - url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") - ; - } - - .CodeMirror-lint-mark-warning { +} + +.CodeMirror-lint-mark-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); +} + +.CodeMirror-lint-mark-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); - } - - .CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { background-position: center center; background-repeat: no-repeat; cursor: pointer; @@ -49,25 +47,26 @@ width: 16px; vertical-align: middle; position: relative; - } - - .CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { padding-left: 18px; background-position: top left; background-repeat: no-repeat; - } - - .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); - } - - .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); - } - - .CodeMirror-lint-marker-multiple { +} + +.CodeMirror-lint-marker-multiple { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: right bottom; - width: 100%; height: 100%; - } \ No newline at end of file + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/_server/CodeMirror/lint.js b/_server/CodeMirror/lint.js index df8a60b2..53b1e07d 100644 --- a/_server/CodeMirror/lint.js +++ b/_server/CodeMirror/lint.js @@ -1,252 +1,277 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE -(function(mod) { +(function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror"], mod); else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { + mod(CodeMirror); +})(function (CodeMirror) { "use strict"; var GUTTER_ID = "CodeMirror-lint-markers"; - + function showTooltip(e, content) { - var tt = document.createElement("div"); - tt.className = "CodeMirror-lint-tooltip"; - tt.appendChild(content.cloneNode(true)); - document.body.appendChild(tt); - - function position(e) { - if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); - tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; - tt.style.left = (e.clientX + 5) + "px"; - } - CodeMirror.on(document, "mousemove", position); - position(e); - if (tt.style.opacity != null) tt.style.opacity = 1; - return tt; + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; + tt.appendChild(content.cloneNode(true)); + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + + CodeMirror.on(document, "mousemove", position); + position(e); + if (tt.style.opacity != null) tt.style.opacity = 1; + return tt; } + function rm(elt) { - if (elt.parentNode) elt.parentNode.removeChild(elt); + if (elt.parentNode) elt.parentNode.removeChild(elt); } + function hideTooltip(tt) { - if (!tt.parentNode) return; - if (tt.style.opacity == null) rm(tt); - tt.style.opacity = 0; - setTimeout(function() { rm(tt); }, 600); + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function () { + rm(tt); + }, 600); } - + function showTooltipFor(e, content, node) { - var tooltip = showTooltip(e, content); - function hide() { - CodeMirror.off(node, "mouseout", hide); - if (tooltip) { hideTooltip(tooltip); tooltip = null; } - } - var poll = setInterval(function() { - if (tooltip) for (var n = node;; n = n.parentNode) { - if (n && n.nodeType == 11) n = n.host; - if (n == document.body) return; - if (!n) { hide(); break; } + var tooltip = showTooltip(e, content); + + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { + hideTooltip(tooltip); + tooltip = null; + } } - if (!tooltip) return clearInterval(poll); - }, 400); - CodeMirror.on(node, "mouseout", hide); + + var poll = setInterval(function () { + if (tooltip) for (var n = node; ; n = n.parentNode) { + if (n && n.nodeType == 11) n = n.host; + if (n == document.body) return; + if (!n) { + hide(); + break; + } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); } - + function LintState(cm, options, hasGutter) { - this.marked = []; - this.options = options; - this.timeout = null; - this.hasGutter = hasGutter; - this.onMouseOver = function(e) { onMouseOver(cm, e); }; - this.waitingFor = 0 + this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function (e) { + onMouseOver(cm, e); + }; + this.waitingFor = 0 } - + function parseOptions(_cm, options) { - if (options instanceof Function) return {getAnnotations: options}; - if (!options || options === true) options = {}; - return options; + if (options instanceof Function) return {getAnnotations: options}; + if (!options || options === true) options = {}; + return options; } - + function clearMarks(cm) { - var state = cm.state.lint; - if (state.hasGutter) cm.clearGutter(GUTTER_ID); - for (var i = 0; i < state.marked.length; ++i) - state.marked[i].clear(); - state.marked.length = 0; + var state = cm.state.lint; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked.length = 0; } - + function makeMarker(labels, severity, multiple, tooltips) { - var marker = document.createElement("div"), inner = marker; - marker.className = "CodeMirror-lint-marker-" + severity; - if (multiple) { - inner = marker.appendChild(document.createElement("div")); - inner.className = "CodeMirror-lint-marker-multiple"; - } - - if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { - showTooltipFor(e, labels, inner); - }); - - return marker; - } - - function getMaxSeverity(a, b) { - if (a == "error") return a; - else return b; - } - - function groupByLine(annotations) { - var lines = []; - for (var i = 0; i < annotations.length; ++i) { - var ann = annotations[i], line = ann.from.line; - (lines[line] || (lines[line] = [])).push(ann); - } - return lines; - } - - function annotationTooltip(ann) { - var severity = ann.severity; - if (!severity) severity = "error"; - var tip = document.createElement("div"); - tip.className = "CodeMirror-lint-message-" + severity; - if (typeof ann.messageHTML != 'undefined') { - tip.innerHTML = ann.messageHTML; - } else { - tip.appendChild(document.createTextNode(ann.message)); - } - return tip; - } - - function lintAsync(cm, getAnnotations, passOptions) { - var state = cm.state.lint - var id = ++state.waitingFor - function abort() { - id = -1 - cm.off("change", abort) - } - cm.on("change", abort) - getAnnotations(cm.getValue(), function(annotations, arg2) { - cm.off("change", abort) - if (state.waitingFor != id) return - if (arg2 && annotations instanceof CodeMirror) annotations = arg2 - cm.operation(function() {updateLinting(cm, annotations)}) - }, passOptions, cm); - } - - function startLinting(cm) { - var state = cm.state.lint, options = state.options; - /* - * Passing rules in `options` property prevents JSHint (and other linters) from complaining - * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. - */ - var passOptions = options.options || options; - var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); - if (!getAnnotations) return; - if (options.async || getAnnotations.async) { - lintAsync(cm, getAnnotations, passOptions) - } else { - var annotations = getAnnotations(cm.getValue(), passOptions, cm); - if (!annotations) return; - if (annotations.then) annotations.then(function(issues) { - cm.operation(function() {updateLinting(cm, issues)}) - }); - else cm.operation(function() {updateLinting(cm, annotations)}) - } - } - - function updateLinting(cm, annotationsNotSorted) { - clearMarks(cm); - var state = cm.state.lint, options = state.options; - - var annotations = groupByLine(annotationsNotSorted); - - for (var line = 0; line < annotations.length; ++line) { - var anns = annotations[line]; - if (!anns) continue; - - var maxSeverity = null; - var tipLabel = state.hasGutter && document.createDocumentFragment(); - - for (var i = 0; i < anns.length; ++i) { - var ann = anns[i]; - var severity = ann.severity; - if (!severity) severity = "error"; - maxSeverity = getMaxSeverity(maxSeverity, severity); - - if (options.formatAnnotation) ann = options.formatAnnotation(ann); - if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); - - if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { - className: "CodeMirror-lint-mark-" + severity, - __annotation: ann - })); + var marker = document.createElement("div"), inner = marker; + marker.className = "CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker-multiple"; } - - if (state.hasGutter) - cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, - state.options.tooltips)); - } - if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + + if (tooltips != false) CodeMirror.on(inner, "mouseover", function (e) { + showTooltipFor(e, labels, inner); + }); + + return marker; } - - function onChange(cm) { - var state = cm.state.lint; - if (!state) return; - clearTimeout(state.timeout); - state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); + + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; } - - function popupTooltips(annotations, e) { - var target = e.target || e.srcElement; - var tooltip = document.createDocumentFragment(); - for (var i = 0; i < annotations.length; i++) { - var ann = annotations[i]; - tooltip.appendChild(annotationTooltip(ann)); - } - showTooltipFor(e, tooltip, target); + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); + } + return lines; } - - function onMouseOver(cm, e) { - var target = e.target || e.srcElement; - if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; - var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; - var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); - - var annotations = []; - for (var i = 0; i < spans.length; ++i) { - var ann = spans[i].__annotation; - if (ann) annotations.push(ann); - } - if (annotations.length) popupTooltips(annotations, e); + + function annotationTooltip(ann) { + var severity = ann.severity; + if (!severity) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message-" + severity; + if (typeof ann.messageHTML != 'undefined') { + tip.innerHTML = ann.messageHTML; + } else { + tip.appendChild(document.createTextNode(ann.message)); + } + return tip; } - - CodeMirror.defineOption("lint", false, function(cm, val, old) { - if (old && old != CodeMirror.Init) { + + function lintAsync(cm, getAnnotations, passOptions) { + var state = cm.state.lint + var id = ++state.waitingFor + + function abort() { + id = -1 + cm.off("change", abort) + } + + cm.on("change", abort) + getAnnotations(cm.getValue(), function (annotations, arg2) { + cm.off("change", abort) + if (state.waitingFor != id) return + if (arg2 && annotations instanceof CodeMirror) annotations = arg2 + cm.operation(function () { + updateLinting(cm, annotations) + }) + }, passOptions, cm); + } + + function startLinting(cm) { + var state = cm.state.lint, options = state.options; + /* + * Passing rules in `options` property prevents JSHint (and other linters) from complaining + * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. + */ + var passOptions = options.options || options; + var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!getAnnotations) return; + if (options.async || getAnnotations.async) { + lintAsync(cm, getAnnotations, passOptions) + } else { + var annotations = getAnnotations(cm.getValue(), passOptions, cm); + if (!annotations) return; + if (annotations.then) annotations.then(function (issues) { + cm.operation(function () { + updateLinting(cm, issues) + }) + }); + else cm.operation(function () { + updateLinting(cm, annotations) + }) + } + } + + function updateLinting(cm, annotationsNotSorted) { clearMarks(cm); - if (cm.state.lint.options.lintOnChange !== false) - cm.off("change", onChange); - CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); - clearTimeout(cm.state.lint.timeout); - delete cm.state.lint; - } - - if (val) { - var gutters = cm.getOption("gutters"), hasLintGutter = false; - for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; - var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); - if (state.options.lintOnChange !== false) - cm.on("change", onChange); - if (state.options.tooltips != false && state.options.tooltips != "gutter") - CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); - - startLinting(cm); - } + var state = cm.state.lint, options = state.options; + + var annotations = groupByLine(annotationsNotSorted); + + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; + + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); + + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!severity) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); + + if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); + + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint-mark-" + severity, + __annotation: ann + })); + } + + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, + state.options.tooltips)); + } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + } + + function onChange(cm) { + var state = cm.state.lint; + if (!state) return; + clearTimeout(state.timeout); + state.timeout = setTimeout(function () { + startLinting(cm); + }, state.options.delay || 500); + } + + function popupTooltips(annotations, e) { + var target = e.target || e.srcElement; + var tooltip = document.createDocumentFragment(); + for (var i = 0; i < annotations.length; i++) { + var ann = annotations[i]; + tooltip.appendChild(annotationTooltip(ann)); + } + showTooltipFor(e, tooltip, target); + } + + function onMouseOver(cm, e) { + var target = e.target || e.srcElement; + if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; + var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; + var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); + + var annotations = []; + for (var i = 0; i < spans.length; ++i) { + var ann = spans[i].__annotation; + if (ann) annotations.push(ann); + } + if (annotations.length) popupTooltips(annotations, e); + } + + CodeMirror.defineOption("lint", false, function (cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + if (cm.state.lint.options.lintOnChange !== false) + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + clearTimeout(cm.state.lint.timeout); + delete cm.state.lint; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); + if (state.options.lintOnChange !== false) + cm.on("change", onChange); + if (state.options.tooltips != false && state.options.tooltips != "gutter") + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + + startLinting(cm); + } }); - - CodeMirror.defineExtension("performLint", function() { - if (this.state.lint) startLinting(this); + + CodeMirror.defineExtension("performLint", function () { + if (this.state.lint) startLinting(this); }); - }); \ No newline at end of file +}); \ No newline at end of file diff --git a/_server/CodeMirror/show-hint.css b/_server/CodeMirror/show-hint.css index 88c93df1..1d26fbeb 100644 --- a/_server/CodeMirror/show-hint.css +++ b/_server/CodeMirror/show-hint.css @@ -3,34 +3,34 @@ z-index: 301; overflow: hidden; list-style: none; - + margin: 0; padding: 2px; - - -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); - -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); - box-shadow: 2px 3px 5px rgba(0,0,0,.2); + + -webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); + -moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); + box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); border-radius: 3px; border: 1px solid silver; - + background: white; font-size: 90%; font-family: monospace; - + max-height: 20em; overflow-y: auto; - } - - .CodeMirror-hint { +} + +.CodeMirror-hint { margin: 0; padding: 0 4px; border-radius: 2px; white-space: pre; color: black; cursor: pointer; - } - - li.CodeMirror-hint-active { +} + +li.CodeMirror-hint-active { background: #08f; color: white; - } \ No newline at end of file +} \ No newline at end of file diff --git a/_server/CodeMirror/show-hint.js b/_server/CodeMirror/show-hint.js index d7cd9427..ddf0cfa7 100644 --- a/_server/CodeMirror/show-hint.js +++ b/_server/CodeMirror/show-hint.js @@ -1,432 +1,484 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE -(function(mod) { +(function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror"], mod); else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { + mod(CodeMirror); +})(function (CodeMirror) { "use strict"; - - var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; - + // This is the old interface, kept around for now to stay // backwards-compatible. - CodeMirror.showHint = function(cm, getHints, options) { - if (!getHints) return cm.showHint(options); - if (options && options.async) getHints.async = true; - var newOpts = {hint: getHints}; - if (options) for (var prop in options) newOpts[prop] = options[prop]; - return cm.showHint(newOpts); + CodeMirror.showHint = function (cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); }; - - CodeMirror.defineExtension("showHint", function(options) { - options = parseOptions(this, this.getCursor("start"), options); - var selections = this.listSelections() - if (selections.length > 1) return; - // By default, don't allow completion when something is selected. - // A hint function can have a `supportsSelection` property to - // indicate that it can handle selections. - if (this.somethingSelected()) { - if (!options.hint.supportsSelection) return; - // Don't try with cross-line selections - for (var i = 0; i < selections.length; i++) - if (selections[i].head.line != selections[i].anchor.line) return; - } - - if (this.state.completionActive) this.state.completionActive.close(); - var completion = this.state.completionActive = new Completion(this, options); - if (!completion.options.hint) return; - - CodeMirror.signal(this, "startCompletion", this); - completion.update(true); + + CodeMirror.defineExtension("showHint", function (options) { + options = parseOptions(this, this.getCursor("start"), options); + var selections = this.listSelections() + if (selections.length > 1) return; + // By default, don't allow completion when something is selected. + // A hint function can have a `supportsSelection` property to + // indicate that it can handle selections. + if (this.somethingSelected()) { + if (!options.hint.supportsSelection) return; + // Don't try with cross-line selections + for (var i = 0; i < selections.length; i++) + if (selections[i].head.line != selections[i].anchor.line) return; + } + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + if (!completion.options.hint) return; + + CodeMirror.signal(this, "startCompletion", this); + completion.update(true); }); - + function Completion(cm, options) { - this.cm = cm; - this.options = options; - this.widget = null; - this.debounce = 0; - this.tick = 0; - this.startPos = this.cm.getCursor("start"); - this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; - - var self = this; - cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + this.cm = cm; + this.options = options; + this.widget = null; + this.debounce = 0; + this.tick = 0; + this.startPos = this.cm.getCursor("start"); + this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; + + var self = this; + cm.on("cursorActivity", this.activityFunc = function () { + self.cursorActivity(); + }); } - - var requestAnimationFrame = window.requestAnimationFrame || function(fn) { - return setTimeout(fn, 1000/60); + + var requestAnimationFrame = window.requestAnimationFrame || function (fn) { + return setTimeout(fn, 1000 / 60); }; var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; - + Completion.prototype = { - close: function() { - if (!this.active()) return; - this.cm.state.completionActive = null; - this.tick = null; - this.cm.off("cursorActivity", this.activityFunc); - - if (this.widget && this.data) CodeMirror.signal(this.data, "close"); - if (this.widget) this.widget.close(); - CodeMirror.signal(this.cm, "endCompletion", this.cm); - }, - - active: function() { - return this.cm.state.completionActive == this; - }, - - pick: function(data, i) { - var completion = data.list[i]; - if (completion.hint) completion.hint(this.cm, data, completion); - else this.cm.replaceRange(getText(completion), completion.from || data.from, - completion.to || data.to, "complete"); - CodeMirror.signal(data, "pick", completion); - this.close(); - }, - - cursorActivity: function() { - if (this.debounce) { - cancelAnimationFrame(this.debounce); - this.debounce = 0; - } - - var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); - if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || - pos.ch < this.startPos.ch || this.cm.somethingSelected() || - (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { - this.close(); - } else { - var self = this; - this.debounce = requestAnimationFrame(function() {self.update();}); - if (this.widget) this.widget.disable(); - } - }, - - update: function(first) { - if (this.tick == null) return - var self = this, myTick = ++this.tick - fetchHints(this.options.hint, this.cm, this.options, function(data) { - if (self.tick == myTick) self.finishUpdate(data, first) - }) - }, - - finishUpdate: function(data, first) { - if (this.data) CodeMirror.signal(this.data, "update"); - - var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); - if (this.widget) this.widget.close(); - - this.data = data; - - if (data && data.list.length) { - if (picked && data.list.length == 1) { - this.pick(data, 0); - } else { - this.widget = new Widget(this, data); - CodeMirror.signal(data, "shown"); - } - } - } - }; - - function parseOptions(cm, pos, options) { - var editor = cm.options.hintOptions; - var out = {}; - for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; - if (editor) for (var prop in editor) - if (editor[prop] !== undefined) out[prop] = editor[prop]; - if (options) for (var prop in options) - if (options[prop] !== undefined) out[prop] = options[prop]; - if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) - return out; - } - - function getText(completion) { - if (typeof completion == "string") return completion; - else return completion.text; - } - - function buildKeyMap(completion, handle) { - var baseMap = { - Up: function() {handle.moveFocus(-1);}, - Down: function() {handle.moveFocus(1);}, - PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, - PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, - Home: function() {handle.setFocus(0);}, - End: function() {handle.setFocus(handle.length - 1);}, - Enter: handle.pick, - Tab: handle.pick, - Esc: handle.close - }; - var custom = completion.options.customKeys; - var ourMap = custom ? {} : baseMap; - function addBinding(key, val) { - var bound; - if (typeof val != "string") - bound = function(cm) { return val(cm, handle); }; - // This mechanism is deprecated - else if (baseMap.hasOwnProperty(val)) - bound = baseMap[val]; - else - bound = val; - ourMap[key] = bound; - } - if (custom) - for (var key in custom) if (custom.hasOwnProperty(key)) - addBinding(key, custom[key]); - var extra = completion.options.extraKeys; - if (extra) - for (var key in extra) if (extra.hasOwnProperty(key)) - addBinding(key, extra[key]); - return ourMap; - } - - function getHintElement(hintsElement, el) { - while (el && el != hintsElement) { - if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; - el = el.parentNode; - } - } - - function Widget(completion, data) { - this.completion = completion; - this.data = data; - this.picked = false; - var widget = this, cm = completion.cm; - - var hints = this.hints = document.createElement("ul"); - hints.className = "CodeMirror-hints"; - this.selectedHint = data.selectedHint || 0; - - var completions = data.list; - for (var i = 0; i < completions.length; ++i) { - var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; - var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); - if (cur.className != null) className = cur.className + " " + className; - elt.className = className; - if (cur.render) cur.render(elt, data, cur); - else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); - elt.hintId = i; - } - - var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); - var left = pos.left, top = pos.bottom, below = true; - hints.style.left = left + "px"; - hints.style.top = top + "px"; - // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. - var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); - var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); - (completion.options.container || document.body).appendChild(hints); - var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; - var scrolls = hints.scrollHeight > hints.clientHeight + 1 - var startScroll = cm.getScrollInfo(); - - if (overlapY > 0) { - var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); - if (curTop - height > 0) { // Fits above cursor - hints.style.top = (top = pos.top - height) + "px"; - below = false; - } else if (height > winH) { - hints.style.height = (winH - 5) + "px"; - hints.style.top = (top = pos.bottom - box.top) + "px"; - var cursor = cm.getCursor(); - if (data.from.ch != cursor.ch) { - pos = cm.cursorCoords(cursor); - hints.style.left = (left = pos.left) + "px"; - box = hints.getBoundingClientRect(); - } - } - } - var overlapX = box.right - winW; - if (overlapX > 0) { - if (box.right - box.left > winW) { - hints.style.width = (winW - 5) + "px"; - overlapX -= (box.right - box.left) - winW; - } - hints.style.left = (left = pos.left - overlapX) + "px"; - } - if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) - node.style.paddingRight = cm.display.nativeBarWidth + "px" - - cm.addKeyMap(this.keyMap = buildKeyMap(completion, { - moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, - setFocus: function(n) { widget.changeActive(n); }, - menuSize: function() { return widget.screenAmount(); }, - length: completions.length, - close: function() { completion.close(); }, - pick: function() { widget.pick(); }, - data: data - })); - - if (completion.options.closeOnUnfocus) { - var closingOnBlur; - cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); - cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); - } - - cm.on("scroll", this.onScroll = function() { - var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); - var newTop = top + startScroll.top - curScroll.top; - var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); - if (!below) point += hints.offsetHeight; - if (point <= editor.top || point >= editor.bottom) return completion.close(); - hints.style.top = newTop + "px"; - hints.style.left = (left + startScroll.left - curScroll.left) + "px"; - }); - - CodeMirror.on(hints, "dblclick", function(e) { - var t = getHintElement(hints, e.target || e.srcElement); - if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} - }); - - CodeMirror.on(hints, "click", function(e) { - var t = getHintElement(hints, e.target || e.srcElement); - if (t && t.hintId != null) { - widget.changeActive(t.hintId); - if (completion.options.completeOnSingleClick) widget.pick(); - } - }); - - CodeMirror.on(hints, "mousedown", function() { - setTimeout(function(){cm.focus();}, 20); - }); - - CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); - return true; - } - - Widget.prototype = { - close: function() { - if (this.completion.widget != this) return; - this.completion.widget = null; - this.hints.parentNode.removeChild(this.hints); - this.completion.cm.removeKeyMap(this.keyMap); - - var cm = this.completion.cm; - if (this.completion.options.closeOnUnfocus) { - cm.off("blur", this.onBlur); - cm.off("focus", this.onFocus); - } - cm.off("scroll", this.onScroll); - }, - - disable: function() { - this.completion.cm.removeKeyMap(this.keyMap); - var widget = this; - this.keyMap = {Enter: function() { widget.picked = true; }}; - this.completion.cm.addKeyMap(this.keyMap); - }, - - pick: function() { - this.completion.pick(this.data, this.selectedHint); - }, - - changeActive: function(i, avoidWrap) { - if (i >= this.data.list.length) - i = avoidWrap ? this.data.list.length - 1 : 0; - else if (i < 0) - i = avoidWrap ? 0 : this.data.list.length - 1; - if (this.selectedHint == i) return; - var node = this.hints.childNodes[this.selectedHint]; - node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); - node = this.hints.childNodes[this.selectedHint = i]; - node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; - if (node.offsetTop < this.hints.scrollTop) - this.hints.scrollTop = node.offsetTop - 3; - else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) - this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; - CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); - }, - - screenAmount: function() { - return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; - } - }; - - function applicableHelpers(cm, helpers) { - if (!cm.somethingSelected()) return helpers - var result = [] - for (var i = 0; i < helpers.length; i++) - if (helpers[i].supportsSelection) result.push(helpers[i]) - return result - } - - function fetchHints(hint, cm, options, callback) { - if (hint.async) { - hint(cm, callback, options) - } else { - var result = hint(cm, options) - if (result && result.then) result.then(callback) - else callback(result) - } - } - - function resolveAutoHints(cm, pos) { - var helpers = cm.getHelpers(pos, "hint"), words - if (helpers.length) { - var resolved = function(cm, callback, options) { - var app = applicableHelpers(cm, helpers); - function run(i) { - if (i == app.length) return callback(null) - fetchHints(app[i], cm, options, function(result) { - if (result && result.list.length > 0) callback(result) - else run(i + 1) + close: function () { + if (!this.active()) return; + this.cm.state.completionActive = null; + this.tick = null; + this.cm.off("cursorActivity", this.activityFunc); + + if (this.widget && this.data) CodeMirror.signal(this.data, "close"); + if (this.widget) this.widget.close(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function () { + return this.cm.state.completionActive == this; + }, + + pick: function (data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + cursorActivity: function () { + if (this.debounce) { + cancelAnimationFrame(this.debounce); + this.debounce = 0; + } + + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); + if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || + pos.ch < this.startPos.ch || this.cm.somethingSelected() || + (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { + this.close(); + } else { + var self = this; + this.debounce = requestAnimationFrame(function () { + self.update(); + }); + if (this.widget) this.widget.disable(); + } + }, + + update: function (first) { + if (this.tick == null) return + var self = this, myTick = ++this.tick + fetchHints(this.options.hint, this.cm, this.options, function (data) { + if (self.tick == myTick) self.finishUpdate(data, first) }) - } - run(0) + }, + + finishUpdate: function (data, first) { + if (this.data) CodeMirror.signal(this.data, "update"); + + var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); + if (this.widget) this.widget.close(); + + this.data = data; + + if (data && data.list.length) { + if (picked && data.list.length == 1) { + this.pick(data, 0); + } else { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + } + } } - resolved.async = true - resolved.supportsSelection = true - return resolved - } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { - return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } - } else if (CodeMirror.hint.anyword) { - return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } - } else { - return function() {} - } - } - - CodeMirror.registerHelper("hint", "auto", { - resolve: resolveAutoHints - }); - - CodeMirror.registerHelper("hint", "fromList", function(cm, options) { - var cur = cm.getCursor(), token = cm.getTokenAt(cur); - var to = CodeMirror.Pos(cur.line, token.end); - if (token.string && /\w/.test(token.string[token.string.length - 1])) { - var term = token.string, from = CodeMirror.Pos(cur.line, token.start); - } else { - var term = "", from = to; - } - var found = []; - for (var i = 0; i < options.words.length; i++) { - var word = options.words[i]; - if (word.slice(0, term.length) == term) - found.push(word); - } - - if (found.length) return {list: found, from: from, to: to}; - }); - - CodeMirror.commands.autocomplete = CodeMirror.showHint; - - var defaultOptions = { - hint: CodeMirror.hint.auto, - completeSingle: true, - alignWithWord: true, - closeCharacters: /[\s()\[\]{};:>,]/, - closeOnUnfocus: true, - completeOnSingleClick: true, - container: null, - customKeys: null, - extraKeys: null }; - + + function parseOptions(cm, pos, options) { + var editor = cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) + return out; + } + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function () { + handle.moveFocus(-1); + }, + Down: function () { + handle.moveFocus(1); + }, + PageUp: function () { + handle.moveFocus(-handle.menuSize() + 1, true); + }, + PageDown: function () { + handle.moveFocus(handle.menuSize() - 1, true); + }, + Home: function () { + handle.setFocus(0); + }, + End: function () { + handle.setFocus(handle.length - 1); + }, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function (cm) { + return val(cm, handle); + }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + this.picked = false; + var widget = this, cm = completion.cm; + + var hints = this.hints = document.createElement("ul"); + hints.className = "CodeMirror-hints"; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + hints.style.left = left + "px"; + hints.style.top = top + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (completion.options.container || document.body).appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + var scrolls = hints.scrollHeight > hints.clientHeight + 1 + var startScroll = cm.getScrollInfo(); + + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX) + "px"; + } + if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) + node.style.paddingRight = cm.display.nativeBarWidth + "px" + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function (n, avoidWrap) { + widget.changeActive(widget.selectedHint + n, avoidWrap); + }, + setFocus: function (n) { + widget.changeActive(n); + }, + menuSize: function () { + return widget.screenAmount(); + }, + length: completions.length, + close: function () { + completion.close(); + }, + pick: function () { + widget.pick(); + }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function () { + closingOnBlur = setTimeout(function () { + completion.close(); + }, 100); + }); + cm.on("focus", this.onFocus = function () { + clearTimeout(closingOnBlur); + }); + } + + cm.on("scroll", this.onScroll = function () { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function (e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + widget.pick(); + } + }); + + CodeMirror.on(hints, "click", function (e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function () { + setTimeout(function () { + cm.focus(); + }, 20); + }); + + CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); + return true; + } + + Widget.prototype = { + close: function () { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + disable: function () { + this.completion.cm.removeKeyMap(this.keyMap); + var widget = this; + this.keyMap = { + Enter: function () { + widget.picked = true; + } + }; + this.completion.cm.addKeyMap(this.keyMap); + }, + + pick: function () { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function (i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function () { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + function applicableHelpers(cm, helpers) { + if (!cm.somethingSelected()) return helpers + var result = [] + for (var i = 0; i < helpers.length; i++) + if (helpers[i].supportsSelection) result.push(helpers[i]) + return result + } + + function fetchHints(hint, cm, options, callback) { + if (hint.async) { + hint(cm, callback, options) + } else { + var result = hint(cm, options) + if (result && result.then) result.then(callback) + else callback(result) + } + } + + function resolveAutoHints(cm, pos) { + var helpers = cm.getHelpers(pos, "hint"), words + if (helpers.length) { + var resolved = function (cm, callback, options) { + var app = applicableHelpers(cm, helpers); + + function run(i) { + if (i == app.length) return callback(null) + fetchHints(app[i], cm, options, function (result) { + if (result && result.list.length > 0) callback(result) + else run(i + 1) + }) + } + + run(0) + } + resolved.async = true + resolved.supportsSelection = true + return resolved + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + return function (cm) { + return CodeMirror.hint.fromList(cm, {words: words}) + } + } else if (CodeMirror.hint.anyword) { + return function (cm, options) { + return CodeMirror.hint.anyword(cm, options) + } + } else { + return function () { + } + } + } + + CodeMirror.registerHelper("hint", "auto", { + resolve: resolveAutoHints + }); + + CodeMirror.registerHelper("hint", "fromList", function (cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var to = CodeMirror.Pos(cur.line, token.end); + if (token.string && /\w/.test(token.string[token.string.length - 1])) { + var term = token.string, from = CodeMirror.Pos(cur.line, token.start); + } else { + var term = "", from = to; + } + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, term.length) == term) + found.push(word); + } + + if (found.length) return {list: found, from: from, to: to}; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: true, + container: null, + customKeys: null, + extraKeys: null + }; + CodeMirror.defineOption("hintOptions", null); - }); \ No newline at end of file +}); \ No newline at end of file diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 027fe661..033ed685 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -177,6 +177,10 @@ action | animate_s | showImage_0_s | showImage_1_s + | animateImage_0_s + | animateImage_1_s + | showGif_0_s + | showGif_1_s | setFg_0_s | setFg_1_s | setWeather_s @@ -488,7 +492,7 @@ helpUrl : https://ckcz123.github.io/mota-js/#/event?id=changepos-%e5%bd%93%e5%89 default : [0,0,[['不变',''],['上','up'],['下','down'],['左','left'],['右','right']]] colour : this.dataColor DirectionEx_List_0 = DirectionEx_List_0 && (', "direction": "'+DirectionEx_List_0+'"'); -var code = '{"type": "changePos", "loc": ['+Int_0+','+Int_1+']'+DirectionEx_List_0+'},\n'; +var code = '{"type": "changePos", "loc": ['+Number_0+','+Number_1+']'+DirectionEx_List_0+'},\n'; return code; */ @@ -553,7 +557,7 @@ return code; */ showImage_0_s - : '显示图片' EvalString '起点像素位置' 'x' Int 'y' Int Newline + : '显示图片' EvalString '起点像素位置' 'x' Number 'y' Number Newline ; /* showImage_0_s @@ -561,7 +565,7 @@ tooltip : showImage:显示图片 helpUrl : https://ckcz123.github.io/mota-js/#/event?id=showimage%ef%bc%9a%e6%98%be%e7%a4%ba%e5%9b%be%e7%89%87 default : ["bg.jpg",0,0] colour : this.printColor -var code = '{"type": "showImage", "name": "'+EvalString_0+'", "loc": ['+Int_0+','+Int_1+']},\n'; +var code = '{"type": "showImage", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+']},\n'; return code; */ @@ -577,6 +581,57 @@ var code = '{"type": "showImage"},\n'; return code; */ +animateImage_0_s + : '图片淡入' EvalString '起点像素位置' 'x' Number 'y' Number '动画时间' Int Newline + ; + +/* animateImage_0_s +tooltip : animageImage:图片淡入 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=animateimage%ef%bc%9a%e5%9b%be%e7%89%87%e6%b7%a1%e5%85%a5%e6%b7%a1%e5%87%b +default : ["bg.jpg",0,0,500] +colour : this.printColor +var code = '{"type": "animateImage", "action": "show", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+'], "time": '+Int_0+'},\n'; +return code; +*/ + +animateImage_1_s + : '图片淡出' EvalString '起点像素位置' 'x' Number 'y' Number '动画时间' Int Newline + ; + +/* animateImage_1_s +tooltip : animageImage:图片淡出 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=animateimage%ef%bc%9a%e5%9b%be%e7%89%87%e6%b7%a1%e5%85%a5%e6%b7%a1%e5%87%b +default : ["bg.jpg",0,0,500] +colour : this.printColor +var code = '{"type": "animateImage", "action": "hide", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+'], "time": '+Int_0+'},\n'; +return code; +*/ + +showGif_0_s + : '显示动图' EvalString '起点像素位置' 'x' Number 'y' Number Newline + ; + +/* showGif_0_s +tooltip : showGif:显示动图 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=showgif%ef%bc%9a%e6%98%be%e7%a4%ba%e5%8a%a8%e5%9b%be +default : ["bg.gif",0,0] +colour : this.printColor +var code = '{"type": "showGif", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+']},\n'; +return code; +*/ + +showGif_1_s + : '清除所有动图' Newline + ; + +/* showGif_1_s +tooltip : showGif:清除所有显示的动图 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=showgif%ef%bc%9a%e6%98%be%e7%a4%ba%e5%8a%a8%e5%9b%be +colour : this.printColor +var code = '{"type": "showGif"},\n'; +return code; +*/ + setFg_0_s : '更改画面色调' Number ',' Number ',' Number ',' Number '动画时间' Int? Newline ; @@ -712,7 +767,7 @@ return code; */ win_s - : '游戏胜利,原因' ':' EvalString? Newline + : '游戏胜利,结局' ':' EvalString? Newline ; /* win_s @@ -724,7 +779,7 @@ return code; */ lose_s - : '游戏失败,原因' ':' EvalString? Newline + : '游戏失败,结局' ':' EvalString? Newline ; /* lose_s @@ -1244,6 +1299,24 @@ ActionParser.prototype.parseAction = function() { this.next]); } break; + case "animateImage": // 显示图片 + if(data.action == 'show'){ + this.next = MotaActionBlocks['animateImage_0_s'].xmlText([ + data.name,data.loc[0],data.loc[1],data.time,this.next]); + } else if (data.action == 'hide') { + this.next = MotaActionBlocks['animateImage_1_s'].xmlText([ + data.name,data.loc[0],data.loc[1],data.time,this.next]); + } + break; + case "showGif": // 显示动图 + if(this.isset(data.name)){ + this.next = MotaActionBlocks['showGif_0_s'].xmlText([ + data.name,data.loc[0],data.loc[1],this.next]); + } else { + this.next = MotaActionBlocks['showGif_1_s'].xmlText([ + this.next]); + } + break; case "setFg": // 颜色渐变 if(this.isset(data.color)){ this.next = MotaActionBlocks['setFg_0_s'].xmlText([ diff --git a/_server/blockly/blockly_compressed.js b/_server/blockly/blockly_compressed.js index 75586e3d..6478672d 100644 --- a/_server/blockly/blockly_compressed.js +++ b/_server/blockly/blockly_compressed.js @@ -1,1604 +1,18850 @@ // Do not edit this file; automatically generated by build.py. 'use strict'; -var $jscomp=$jscomp||{};$jscomp.scope={};var COMPILED=!0,goog=goog||{};goog.global=this;goog.isDef=function(a){return void 0!==a};goog.isString=function(a){return"string"==typeof a};goog.isBoolean=function(a){return"boolean"==typeof a};goog.isNumber=function(a){return"number"==typeof a}; -goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&goog.isDef(b)?c[d]=b:c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}}; -goog.define=function(a,b){var c=b;COMPILED||(goog.global.CLOSURE_UNCOMPILED_DEFINES&&void 0===goog.global.CLOSURE_UNCOMPILED_DEFINES.nodeType&&Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_UNCOMPILED_DEFINES,a)?c=goog.global.CLOSURE_UNCOMPILED_DEFINES[a]:goog.global.CLOSURE_DEFINES&&void 0===goog.global.CLOSURE_DEFINES.nodeType&&Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_DEFINES,a)&&(c=goog.global.CLOSURE_DEFINES[a]));goog.exportPath_(a,c)};goog.DEBUG=!1;goog.LOCALE="en"; -goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG;goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1;goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide can not be used within a goog.module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)}; -goog.constructNamespace_=function(a,b){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var c=a;(c=c.substring(0,c.lastIndexOf(".")))&&!goog.getObjectByName(c);)goog.implicitNamespaces_[c]=!0}goog.exportPath_(a,b)};goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/; -goog.module=function(a){if(!goog.isString(a)||!a||-1==a.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInModuleLoader_())throw Error("Module "+a+" has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide.");if(goog.moduleLoaderState_.moduleName)throw Error("goog.module may only be called once per module."); -goog.moduleLoaderState_.moduleName=a;if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a]}};goog.module.get=function(a){return goog.module.getInternal_(a)};goog.module.getInternal_=function(a){if(!COMPILED){if(a in goog.loadedModules_)return goog.loadedModules_[a];if(!goog.implicitNamespaces_[a])return a=goog.getObjectByName(a),null!=a?a:null}return null};goog.moduleLoaderState_=null; -goog.isInModuleLoader_=function(){return null!=goog.moduleLoaderState_};goog.module.declareLegacyNamespace=function(){if(!COMPILED&&!goog.isInModuleLoader_())throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module");if(!COMPILED&&!goog.moduleLoaderState_.moduleName)throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace.");goog.moduleLoaderState_.declareLegacyNamespace=!0}; -goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){};COMPILED||(goog.isProvided_=function(a){return a in goog.loadedModules_||!goog.implicitNamespaces_[a]&&goog.isDefAndNotNull(goog.getObjectByName(a))},goog.implicitNamespaces_={"goog.module":!0}); -goog.getObjectByName=function(a,b){for(var c=a.split("."),d=b||goog.global,e=0;e>>0);goog.uidCounter_=0;goog.getHashCode=goog.getUid; -goog.removeHashCode=goog.removeUid;goog.cloneObject=function(a){var b=goog.typeOf(a);if("object"==b||"array"==b){if(a.clone)return a.clone();b="array"==b?[]:{};for(var c in a)b[c]=goog.cloneObject(a[c]);return b}return a};goog.bindNative_=function(a,b,c){return a.call.apply(a.bind,arguments)}; -goog.bindJs_=function(a,b,c){if(!a)throw Error();if(2Number(a[1])?!1:b('(()=>{"use strict";class X{constructor(){if(new.target!=String)throw 1;this.x=42}}let q=Reflect.construct(X,[],String);if(q.x!=42||!(q instanceof String))throw 1;for(const a of[2,3]){if(a==2)continue;function f(z={a}){let a=0;return z.a}{function f(){return 0;}}return f()==3}})()')});a("es6-impl",function(){return!0});a("es7",function(){return b("2 ** 2 == 4")});a("es8",function(){return b("async () => 1, true")});return c},goog.Transpiler.prototype.needsTranspile= -function(a){if("always"==goog.TRANSPILE)return!0;if("never"==goog.TRANSPILE)return!1;this.requiresTranspilation_||(this.requiresTranspilation_=this.createRequiresTranspilation_());if(a in this.requiresTranspilation_)return this.requiresTranspilation_[a];throw Error("Unknown language mode: "+a);},goog.Transpiler.prototype.transpile=function(a,b){return goog.transpile_(a,b)},goog.transpiler_=new goog.Transpiler,goog.DebugLoader=function(){this.dependencies_={loadFlags:{},nameToPath:{},requires:{},visited:{}, -written:{},deferred:{}};this.oldIeWaiting_=!1;this.queuedModules_=[];this.lastNonModuleScriptIndex_=0},goog.DebugLoader.IS_OLD_IE_=!(goog.global.atob||!goog.global.document||!goog.global.document.all),goog.DebugLoader.prototype.earlyProcessLoad=function(a){goog.DebugLoader.IS_OLD_IE_&&this.maybeProcessDeferredDep_(a)},goog.DebugLoader.prototype.load=function(a){var b=this.getPathFromDeps_(a);if(b){var c=function(a){if(!(a in f.written||a in f.visited)){f.visited[a]=!0;if(a in f.requires)for(var b in f.requires[a])if(!g.isProvided(b))if(b in -f.nameToPath)c(f.nameToPath[b]);else throw Error("Undefined nameToPath for "+b);a in e||(e[a]=!0,d.push(a))}},d=[],e={},f=this.dependencies_,g=this;c(b);for(a=0;a\x3c/script>')},goog.DebugLoader.prototype.appendScriptSrcNode_=function(a){var b=goog.global.document,c=b.createElement("script");c.type="text/javascript";c.src=a;c.defer=!1;c.async=!1;b.head.appendChild(c)},goog.DebugLoader.prototype.writeScriptTag_=function(a,b){if(this.inHtmlDocument()){var c=goog.global.document;if(!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING&& -"complete"==c.readyState){if(/\bdeps.js$/.test(a))return!1;throw Error('Cannot write "'+a+'" after document load');}if(void 0===b)if(goog.DebugLoader.IS_OLD_IE_){this.oldIeWaiting_=!0;var d=" onreadystatechange='goog.debugLoader_.onScriptLoad_(this, "+ ++this.lastNonModuleScriptIndex_+")' ";c.write(' - - + + + + + + + \ No newline at end of file diff --git a/_server/vm.js b/_server/vm.js index 0f2aaecd..64471533 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -1,333 +1,375 @@ // vue 相关处理 -document.body.onmousedown = function(e){ - //console.log(e); - var eid=[]; - e.path.forEach(function(node){ - if(!node.getAttribute)return; - var id_ = node.getAttribute('id'); - if (id_){ - if(['left','left1','left2','left3','left4','left5','left8'].indexOf(id_)!==-1)eid.push('edit'); - eid.push(id_); - } - }); - //console.log(eid); - if(eid.indexOf('edit')===-1){ - if(eid.indexOf('tip')===-1)selectBox.isSelected = false; - } - //editor.mode.onmode(''); - editor.info = {}; -} -iconLib.onmousedown = function(e){ - e.stopPropagation(); -} -var exportM = new Vue({ - el: '#exportM', - data: { - isExport: false, - }, - methods: { - exportMap: function(){ - editor.updateMap(); - - var filestr=''; - for (var yy = 0; yy < 13; yy++){ - filestr+='[' - for (var xx = 0; xx < 13; xx++) { - var mapxy=editor.map[yy][xx]; - if(typeof(mapxy)==typeof({})){ - if ('idnum' in mapxy)mapxy=mapxy.idnum; - else { - // mapxy='!!?'; - tip.whichShow = 3; - return; - } - }else if(typeof(mapxy)=='undefined'){ - tip.whichShow = 3; - return; - } - mapxy=String(mapxy); - mapxy=Array(Math.max(4-mapxy.length,0)).join(' ')+mapxy; - filestr+=mapxy+(xx==12?'':',') +document.body.onmousedown = function (e) { + //console.log(e); + var eid = []; + e.path.forEach(function (node) { + if (!node.getAttribute) return; + var id_ = node.getAttribute('id'); + if (id_) { + if (['left', 'left1', 'left2', 'left3', 'left4', 'left5', 'left8'].indexOf(id_) !== -1) eid.push('edit'); + eid.push(id_); + } + }); + //console.log(eid); + if (eid.indexOf('edit') === -1) { + if (eid.indexOf('tip') === -1) { + if (selectBox.isSelected) { + editor_mode.onmode(''); + editor.file.saveFloorFile(function (err) { + if (err) { + printe(err); + throw(err) + } + ;printf('地图保存成功'); + }); + } + selectBox.isSelected = false; + } + } + //editor.mode.onmode(''); + editor.info = {}; +} +iconLib.onmousedown = function (e) { + e.stopPropagation(); +} +var exportMap = new Vue({ + el: '#exportMap', + data: { + isExport: false, + }, + methods: { + exportMap: function () { + editor.updateMap(); + + var filestr = ''; + for (var yy = 0; yy < 13; yy++) { + filestr += '[' + for (var xx = 0; xx < 13; xx++) { + var mapxy = editor.map[yy][xx]; + if (typeof(mapxy) == typeof({})) { + if ('idnum' in mapxy) mapxy = mapxy.idnum; + else { + // mapxy='!!?'; + tip.whichShow = 3; + return; + } + } else if (typeof(mapxy) == 'undefined') { + tip.whichShow = 3; + return; + } + mapxy = String(mapxy); + mapxy = Array(Math.max(4 - mapxy.length, 0)).join(' ') + mapxy; + filestr += mapxy + (xx == 12 ? '' : ',') + } + + filestr += ']' + (yy == 12 ? '' : ',\n'); + } + pout.value = filestr; + editArea.mapArr = filestr; + this.isExport = true; + editArea.error = 0; + tip.whichShow = 2; } - - filestr += ']'+(yy==12?'':',\n'); - } - pout.value = filestr; - editArea.mapArr = filestr; - this.isExport = true; - editArea.error = 0; - tip.whichShow = 2; } - } }) var editArea = new Vue({ - el: '#editArea', - data: { - mapArr: '', - errors: [ // 编号1,2,3,4 - "格式错误!请使用正确格式(13*13数组,如不清楚,可先点击生成地图查看正确格式)", - "当前有未定义ID(在地图区域显示红块),请修改ID或者到icons.js和maps.js中进行定义!", - "ID越界(在地图区域显示红块),当前编辑器暂时支持编号小于400,请修改编号!", - // "发生错误!", - ], - error: 0, - formatTimer: null, - }, - watch: { - mapArr: function (val, oldval) { - var that = this; - if(val=='') return; - if(exportM.isExport){ - exportM.isExport = false; - return; - } - if(that.formatArr()){ - that.error = 0; - - setTimeout(function(){ - that.mapArr = that.formatArr(); - that.drawMap(); - tip.whichShow = 8 - }, 1000); - that.formatTimer = setTimeout(function(){ - pout.value = that.formatArr(); - }, 5000); //5s后再格式化,不然光标跳到最后很烦 - }else{ - that.error = 1; - } + el: '#editArea', + data: { + mapArr: '', + errors: [ // 编号1,2,3,4 + "格式错误!请使用正确格式(13*13数组,如不清楚,可先点击生成地图查看正确格式)", + "当前有未定义ID(在地图区域显示红块),请修改ID或者到icons.js和maps.js中进行定义!", + "ID越界(在地图区域显示红块),当前编辑器暂时支持编号小于400,请修改编号!", + // "发生错误!", + ], + error: 0, + formatTimer: null, }, - error: function(){ - // console.log(editArea.mapArr); - } - }, - methods: { - drawMap: function(){ - var that = this; + watch: { + mapArr: function (val, oldval) { + var that = this; + if (val == '') return; + if (exportMap.isExport) { + exportMap.isExport = false; + return; + } + if (that.formatArr()) { + that.error = 0; - // var mapArray = that.mapArr.split(/\D+/).join(' ').trim().split(' '); - var mapArray = JSON.parse('['+that.mapArr+']'); - for(var y=0; y<13; y++) - for(var x=0; x<13; x++){ - var num = mapArray[y][x]; - if(num == 0 ) - editor.map[y][x] = 0; - else if(num >= 1000){ - that.error = 3; - editor.map[y][x] = undefined; - }else if(typeof(editor.indexs[num][0]) == 'undefined'){ - that.error = 2; - editor.map[y][x] = undefined; - }else editor.map[y][x] = editor.ids[[editor.indexs[num][0]]]; + setTimeout(function () { + that.mapArr = that.formatArr(); + that.drawMap(); + tip.whichShow = 8 + }, 1000); + that.formatTimer = setTimeout(function () { + pout.value = that.formatArr(); + }, 5000); //5s后再格式化,不然光标跳到最后很烦 + } else { + that.error = 1; + } + }, + error: function () { + // console.log(editArea.mapArr); } - - editor.updateMap(); - }, - formatArr: function(){ - var formatArrStr = ''; - var that = this; - clearTimeout(that.formatTimer); - if(this.mapArr.split(/\D+/).join(' ').trim().split(' ').length != 169) return false; - var arr = this.mapArr.replace(/\s+/g, '').split('],['); - - if(arr.length != 13) return ; - for(var i =0; i<13; i++){ - var a = []; - formatArrStr +='['; - if(i==0||i==12) a = arr[i].split(/\D+/).join(' ').trim().split(' '); - else a = arr[i].split(/\D+/); - if(a.length != 13){ - formatArrStr = ''; - return ; - } + methods: { + drawMap: function () { + var that = this; - for(var k=0; k<13; k++){ - var num = parseInt(a[k]); - formatArrStr += Array(Math.max(4-String(num).length,0)).join(' ')+num+(k==12?'':','); + // var mapArray = that.mapArr.split(/\D+/).join(' ').trim().split(' '); + var mapArray = JSON.parse('[' + that.mapArr + ']'); + for (var y = 0; y < 13; y++) + for (var x = 0; x < 13; x++) { + var num = mapArray[y][x]; + if (num == 0) + editor.map[y][x] = 0; + else if (num >= 1000) { + that.error = 3; + editor.map[y][x] = undefined; + } else if (typeof(editor.indexs[num][0]) == 'undefined') { + that.error = 2; + editor.map[y][x] = undefined; + } else editor.map[y][x] = editor.ids[[editor.indexs[num][0]]]; + } + + editor.updateMap(); + + }, + formatArr: function () { + var formatArrStr = ''; + var that = this; + clearTimeout(that.formatTimer); + if (this.mapArr.split(/\D+/).join(' ').trim().split(' ').length != 169) return false; + var arr = this.mapArr.replace(/\s+/g, '').split('],['); + + if (arr.length != 13) return; + for (var i = 0; i < 13; i++) { + var a = []; + formatArrStr += '['; + if (i == 0 || i == 12) a = arr[i].split(/\D+/).join(' ').trim().split(' '); + else a = arr[i].split(/\D+/); + if (a.length != 13) { + formatArrStr = ''; + return; + } + + for (var k = 0; k < 13; k++) { + var num = parseInt(a[k]); + formatArrStr += Array(Math.max(4 - String(num).length, 0)).join(' ') + num + (k == 12 ? '' : ','); + } + formatArrStr += ']' + (i == 12 ? '' : ',\n'); + } + return formatArrStr; } - formatArrStr += ']'+(i==12?'':',\n'); - } - return formatArrStr; } - } }); -var editTip = new Vue({ - el: '#editTip', - data: { - err: '' - }, - methods: { - copyMap: function(){ +var copyMap = new Vue({ + el: '#copyMap', + data: { + err: '' + }, + methods: { + copyMap: function () { - tip.whichShow = 0; - if(pout.value.trim() != ''){ - if(editArea.error) { - this.err = editArea.errors[editArea.error-1]; - tip.whichShow = 5 - return; + tip.whichShow = 0; + if (pout.value.trim() != '') { + if (editArea.error) { + this.err = editArea.errors[editArea.error - 1]; + tip.whichShow = 5 + return; + } + try { + pout.select(); + document.execCommand("Copy"); + tip.whichShow = 6; + } catch (e) { + this.err = e; + tip.whichShow = 5; + } + } else { + tip.whichShow = 7; + } } - try{ - pout.select(); - document.execCommand("Copy"); - tip.whichShow = 6; - }catch(e){ - this.err= e; - tip.whichShow = 5; - } - }else{ - tip.whichShow = 7; - } - } - }, + }, }) -var clear = new Vue({ - el: '#clear', +var clearMap = new Vue({ + el: '#clearMap', - methods: { - clearMap: function(){ - editor.mapInit(); - editor.updateMap(); - clearTimeout(editArea.formatTimer); - clearTimeout(tip.timer); - pout.value = ''; - editArea.mapArr = ''; - tip.whichShow = 4; - editArea.error = 0; + methods: { + clearMap: function () { + editor.mapInit(); + editor_mode.onmode(''); + editor.file.saveFloorFile(function (err) { + if (err) { + printe(err); + throw(err) + } + ;printf('地图清除成功'); + }); + editor.updateMap(); + clearTimeout(editArea.formatTimer); + clearTimeout(tip.timer); + pout.value = ''; + editArea.mapArr = ''; + tip.whichShow = 4; + editArea.error = 0; + } } - } }) -printf = function(str_,type) { - selectBox.isSelected = false; - if(!type){ - tip.whichShow=11; - } else { - tip.whichShow=12; - } - setTimeout(function(){ - if(!type){ - tip.msgs[11]=String(str_); - tip.whichShow=12; +var deleteMap = new Vue({ + el: '#deleteMap', + methods: { + deleteMap: function () { + editor_mode.onmode(''); + var index = core.floorIds.indexOf(editor.currentFloorId); + if (index>=0) { + core.floorIds.splice(index,1); + editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {/*console.log(objs_);*/ + if (objs_.slice(-1)[0] != null) { + printe(objs_.slice(-1)[0]); + throw(objs_.slice(-1)[0]) + } + ;printe('删除成功,请F5刷新编辑器生效'); + }); + } + else printe('删除成功,请F5刷新编辑器生效'); + } + } +}) +printf = function (str_, type) { + selectBox.isSelected = false; + if (!type) { + tip.whichShow = 11; } else { - tip.msgs[10]=String(str_); - tip.whichShow=11; + tip.whichShow = 12; } - },1); + setTimeout(function () { + if (!type) { + tip.msgs[11] = String(str_); + tip.whichShow = 12; + } else { + tip.msgs[10] = String(str_); + tip.whichShow = 11; + } + }, 1); +} +printe = function (str_) { + printf(str_, 'error') } -printe = function(str_){printf(str_,'error')} tip_in_showMode = [ - '涉及图片的更改需要F5刷新浏览器来生效', - '文本域可以通过双击,在文本编辑器或事件编辑器中编辑', - '事件编辑器中的显示文本和自定义脚本的方块也可以双击', - "画出的地图要点击\"保存地图\"才会写入到文件中", + '涉及图片的更改需要F5刷新浏览器来生效', + '文本域可以通过双击,在文本编辑器或事件编辑器中编辑', + '事件编辑器中的显示文本和自定义脚本的方块也可以双击', + "画出的地图要点击\"保存地图\"才会写入到文件中", ]; var tip = new Vue({ - el: '#tip', - data: { - infos: {}, - hasId: true, - isAutotile: false, - isSelectedBlock: false, - isClearBlock: false, - geneMapSuccess: false, - timer: null, - msgs: [ //分别编号1,2,3,4,5,6,7,8,9,10;奇数警告,偶数成功 - "当前未选择任何图块,请先在右边选择要画的图块!", - "生成地图成功!可点击复制按钮复制地图数组到剪切板", - "生成失败! 地图中有未定义的图块,建议先用其他有效图块覆盖或点击清除地图!", - "地图清除成功!", - "复制失败!", - "复制成功!可直接粘贴到楼层文件的地图数组中。", - "复制失败!当前还没有数据", - "修改成功!可点击复制按钮复制地图数组到剪切板", - "选择背景图片失败!文件名格式错误或图片不存在!", - "更新背景图片成功!", - "11:警告", - "12:成功" - ], - mapMsg: '', - whichShow: 0, - }, - watch: { - infos: { - handler: function(val, oldval){ - this.isClearBlock = false; - if(typeof(val) != 'undefined'){ - if(val==0) { - this.isClearBlock = true; - return; - } - if('id' in val){ - this.hasId = true; - }else{ - this.hasId = false; - } - this.isAutotile = false; - if(val.images == "autotile" && this.hasId) this.isAutotile = true; - } - }, - deep: true + el: '#tip', + data: { + infos: {}, + hasId: true, + isAutotile: false, + isSelectedBlock: false, + isClearBlock: false, + geneMapSuccess: false, + timer: null, + msgs: [ //分别编号1,2,3,4,5,6,7,8,9,10;奇数警告,偶数成功 + "当前未选择任何图块,请先在右边选择要画的图块!", + "生成地图成功!可点击复制按钮复制地图数组到剪切板", + "生成失败! 地图中有未定义的图块,建议先用其他有效图块覆盖或点击清除地图!", + "地图清除成功!", + "复制失败!", + "复制成功!可直接粘贴到楼层文件的地图数组中。", + "复制失败!当前还没有数据", + "修改成功!可点击复制按钮复制地图数组到剪切板", + "选择背景图片失败!文件名格式错误或图片不存在!", + "更新背景图片成功!", + "11:警告", + "12:成功" + ], + mapMsg: '', + whichShow: 0, }, + watch: { + infos: { + handler: function (val, oldval) { + this.isClearBlock = false; + if (typeof(val) != 'undefined') { + if (val == 0) { + this.isClearBlock = true; + return; + } + if ('id' in val) { + this.hasId = true; + } else { + this.hasId = false; + } + this.isAutotile = false; + if (val.images == "autotile" && this.hasId) this.isAutotile = true; + } + }, + deep: true + }, - whichShow: function(){ - var that = this; - that.mapMsg = ''; - that.msgs[4] = "复制失败!"+editTip.err; - clearTimeout(that.timer); - if(that.whichShow){ - that.mapMsg = that.msgs[that.whichShow-1]; - that.timer = setTimeout(function() { - if(!(that.whichShow%2)) - that.whichShow = 0; - }, 5000); //5秒后自动清除success,warn不清除 - } + whichShow: function () { + var that = this; + that.mapMsg = ''; + that.msgs[4] = "复制失败!" + editTip.err; + clearTimeout(that.timer); + if (that.whichShow) { + that.mapMsg = that.msgs[that.whichShow - 1]; + that.timer = setTimeout(function () { + if (!(that.whichShow % 2)) + that.whichShow = 0; + }, 5000); //5秒后自动清除success,warn不清除 + } + } } - } }) var selectBox = new Vue({ - el: '#selectBox', - data: { - isSelected: false - }, - watch: { - isSelected: function(){ - tip.isSelectedBlock = this.isSelected; - tip.whichShow = 0; - clearTimeout(tip.timer); + el: '#selectBox', + data: { + isSelected: false + }, + watch: { + isSelected: function () { + tip.isSelectedBlock = this.isSelected; + tip.whichShow = 0; + clearTimeout(tip.timer); + } } - } }) var bgSelect = new Vue({ - el: '#bgSelect', - data: { - bgs: {}, - selectedBg: 'ground', - imgname: '' - }, - watch:{ - selectedBg: function(){ - editor.bgY = this.bgs.indexOf(this.selectedBg); - editor.drawMapBg(); + el: '#bgSelect', + data: { + bgs: {}, + selectedBg: 'ground', + imgname: '' + }, + watch: { + selectedBg: function () { + editor.bgY = this.bgs.indexOf(this.selectedBg); + editor.drawMapBg(); + } + }, + methods: { + updatebg: function () { + tip.whichShow = 0; + var regx = /\S+\.(png|bmp|jpg|jpeg|gif)$/i; + if (regx.test(this.imgname)) { + var url = 'images/' + this.imgname; + editor.loadImg(url).then(function (img) { + editor.drawMapBg(img); + tip.whichShow = 10; + }).catch(function (err) { + console.log(err); + tip.whichShow = 9; + }); + } else { + tip.whichShow = 9; + } + } } - }, - methods: { - updatebg: function(){ - tip.whichShow = 0; - var regx = /\S+\.(png|bmp|jpg|jpeg|gif)$/i; - if(regx.test(this.imgname)){ - var url = 'images/'+this.imgname; - editor.loadImg(url).then(function(img){ - editor.drawMapBg(img); - tip.whichShow = 10; - }).catch(function(err){ - console.log(err); - tip.whichShow = 9; - }); - }else{ - tip.whichShow = 9; - } - } - } }) \ No newline at end of file diff --git a/docs/element.md b/docs/element.md index 299c00a6..0b1f5827 100644 --- a/docs/element.md +++ b/docs/element.md @@ -14,14 +14,26 @@ 大多数宝物都有默认的效果,屠龙匕首暂未定义,如有自己的需求可参见[自定义道具效果](personalization#自定义道具效果)。 -如需让剑盾变成装备,可以直接在`data.js`中设置`'equipment': true`即可。 - 拿到道具后将触发`afterGetItem`事件,有关事件的详细介绍请参见[事件](event)。 如需修改某个道具的效果,在不同区域宝石数据发生变化等问题,请参见[自定义道具效果](personalization#自定义道具效果)的说明。 **有关轻按,在data.js的系统变量中有定义。如果`enableGentleClick`为true,则鼠标(触摸屏)通过双击勇士,键盘通过空格可达到轻按效果,即不向前移动而获得前方物品。** +## 装备 + +如果需要让剑盾等变成装备,可以直接在`data.js`中设置`'equipment': true`即可。 + +值得注意的是,有时候会有一个装备加多种属性的需求,此时需要把剑盾的效果从数值改成一个对象: + +``` js +"sword1": {"atk": 10, "def": 0, "mdef": 5}, // 铁剑加10攻和5魔防 +"shield1": {"atk": 0, "def": 10, "mdef": 10}, // 铁盾加10防和10魔防 +``` + +将需要的项目按照如上方式修改即可。 + + ## 门 本塔支持6种门,黄蓝红绿铁花。前五种门需要有对应的钥匙打开,花门只能通过调用`openDoor`事件进行打开。 diff --git a/docs/event.md b/docs/event.md index f661e1d3..b7ff20fd 100644 --- a/docs/event.md +++ b/docs/event.md @@ -636,6 +636,50 @@ loc为图片左上角坐标,以像素为单位进行计算。 调用show/hide/move/animate等几个事件同样会清除所有显示的图片。 +### animateImage:图片淡入淡出 + +我们还可以使用 `{"type": "animateImage"}` 来造成显示图片的淡入淡出效果。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "animateImage", "action": "show", "name": "bg.jpg", "loc": [231,297], "time": 500}, // 在(231,297)淡入bg.jpg,动画时间500ms + {"type": "animateImage", "action": "hide", "name": "1.png", "loc": [109,167], "time": 300}, // 在(109,167)淡出1.png,动画时间300ms +] +``` + +action为淡入还是淡出,`show`为淡入,`hide`会淡出。 + +name为图片名。**请确保图片在data.js中的images中被定义过。** + +loc为图片左上角坐标,以像素为单位进行计算。 + +time为淡入淡出的时间,如果是0则忽略此项。 + +!> 淡入淡出图片只是会在顶层绘制“淡入”和“淡出”效果,动画结束即消失,并不会实际对图片的显示造成影响。请与showImage事件合用。 + +如果多张图片的淡入淡出可以采用以下方式(仅供参考): + +假设我现在已经有了`1.jpg`显示在屏幕上: +- 淡入显示`2.png`:调用`animateImage`淡入图片,然后立刻调用`showImage`显示图片。 +- 淡出`1.png`:清除所有图片,`showImage`显示`2.png`,然后调用`animateImage`淡出`1.jpg` + +### showGif:显示动图 + +我们可以使用 `{"type": "showGif"}` 来显示一张图片。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "showGif", "name": "timg.gif", "loc": [231,297]}, // 在(231,297)显示一张动图 + {"type": "showGif"} // 如果不指定name则清除所有动图。 +] +``` + +name为图片名。**请确保图片在data.js中的images中被定义过。** + +loc为动图左上角坐标,以像素为单位进行计算。 + +如果不指定name则清除所有显示的动图。 + ### setFg: 更改画面色调 我们可以使用 `{"type": "setFg"}` 来更改画面色调。 diff --git a/docs/personalization.md b/docs/personalization.md index 6d8b0880..64550140 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -249,7 +249,7 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her // 如果有神圣盾免疫吸血等可以在这里写 if (core.hasFlag("shield5")) vampireDamage = 0; // 存在神圣盾,吸血伤害为0 - vampireDamage = parseInt(vampireDamage); + vampireDamage = Math.floor(vampireDamage) || 0; // 加到自身 if (monster.add) // 如果加到自身 mon_hp += vampireDamage; @@ -286,7 +286,7 @@ control.prototype.checkBlock = function () { 你需自己指定一个special数字,修改getSpecialText函数(属性名)和getSpecialHint函数(属性提示文字)。 -如果要修改伤害计算公式,请修改下面的calDamage函数。请注意,如果无法战斗,该函数必须返回`999999999`。 +如果要修改伤害计算公式,请修改下面的calDamage函数。请注意,如果无法战斗,该函数必须返回`null`。 对于毒衰弱怪物的战斗后结算在`functions.js`中的afterBattle函数中。 diff --git a/editor.html b/editor.html index cf24e470..e3a2d9fa 100644 --- a/editor.html +++ b/editor.html @@ -1,229 +1,269 @@ - + - + -
+
-
-
-
-
- -

{{ errors[error-1] }}

+
+
+
+
+ +

{{ errors[error-1] }}

+
+
+ + +
+
+ + + + +
-
-
- - - -
-
- - -
-
-
+
-
-
+
+
+ +
-
-
-

追加素材

-
-

- - - -

-
- - - - -
-
1
-
2
-
3
-
4
+

追加素材

+
+

+ + + + +

+
+ + + + +
+
1
+
2
+
3
+
4
+
+
-
-
+
-

地图选点  

-
-

0,0

-
- - - - -
条目注释
-
-
-
-

图块属性  

-
-
- - - -
-
-
- - - - -
条目注释
+

地图选点   +

+
+

0,0

+
+ + + + + + + + +
条目注释
+
-
-
+
+
+

图块属性   +

+
+
+ + + +
+
+
+ + + + + + + + +
条目注释
+
+
+
+
-

楼层属性  

-
-
- - - - -
条目注释
-
-
+

楼层属性   +

+
+
+ + + + + + + + +
条目注释
+
+
+
-

全塔属性  

-
-
- - - - -
条目注释
-
-
-
-

事件编辑器    - - - - - - - -

-
-
- -
-
+

全塔属性   +

+
+
+ + + + + + + + +
条目注释
+
+
+
+
+
+

事件编辑器    + + + + + + +

+
+
+
+
+ +
+
+
- - - - Lint - + + + + Lint +
-

脚本编辑  

-
-
- - - - -
条目注释
-
-
-
-
-
-
- - - - -
-
-
-
-

当前选择为清除块,可擦除地图上块

-
-

图块编号:{{ infos['idnum'] }}

-

图块ID:{{ infos['id'] }}

-

该图块无对应的数字或ID存在,请先前往icons.js和maps.js中进行定义!

-

图块所在素材:{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}

-

图块索引:{{ infos['y'] }}

+

脚本编辑   +

+
+
+ + + + + + + + +
条目注释
-
-
-

{{ mapMsg }}

-
- +
+
+
+
+
+ + + + +
+
+
+
+

当前选择为清除块,可擦除地图上块

+
+

图块编号:{{ infos['idnum'] }}

+

图块ID:{{ infos['id'] }}

+

该图块无对应的数字或ID存在,请先前往icons.js和maps.js中进行定义!

+

图块所在素材:{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }} +

+

图块索引:{{ infos['y'] }}

+
+
+
+

{{ mapMsg }}

+
+
- -



- - - - - -
- - + + + @@ -353,38 +395,38 @@ diff --git a/index.html b/index.html index e04a22e4..bf967b87 100644 --- a/index.html +++ b/index.html @@ -103,6 +103,8 @@

+
+
diff --git a/libs/actions.js b/libs/actions.js index 48601e6f..c29d7f1a 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1245,10 +1245,12 @@ actions.prototype.clickSL = function(x,y) { // 上一页 if ((x == 3 || x == 4) && y == 12) { core.ui.drawSLPanel(10*(page-1)+offset); + return; } // 下一页 if ((x == 8 || x == 9) && y == 12) { core.ui.drawSLPanel(10*(page+1)+offset); + return; } // 返回 if (x>=10 && x<=12 && y==12) { @@ -1258,17 +1260,37 @@ actions.prototype.clickSL = function(x,y) { } return; } + // 删除 + if (x>=0 && x<=2 && y==12) { + core.status.event.selection=!core.status.event.selection; + core.ui.drawSLPanel(index); + return; + } - var index=6*page+1; + var id=null; if (y>=1 && y<=4) { - if (x>=1 && x<=3) core.doSL("autoSave", core.status.event.id); - if (x>=5 && x<=7) core.doSL(5*page+1, core.status.event.id); - if (x>=9 && x<=11) core.doSL(5*page+2, core.status.event.id); + if (x>=1 && x<=3) id = "autoSave"; + if (x>=5 && x<=7) id = 5*page+1; + if (x>=9 && x<=11) id = 5*page+2; } if (y>=7 && y<=10) { - if (x>=1 && x<=3) core.doSL(5*page+3, core.status.event.id); - if (x>=5 && x<=7) core.doSL(5*page+4, core.status.event.id); - if (x>=9 && x<=11) core.doSL(5*page+5, core.status.event.id); + if (x>=1 && x<=3) id = 5*page+3; + if (x>=5 && x<=7) id = 5*page+4; + if (x>=9 && x<=11) id = 5*page+5; + } + if (id!=null) { + if (core.status.event.selection) { + if (id == 'autoSave') { + core.drawTip("无法删除自动存档!"); + } + else { + core.removeLocalStorage("save"+id); + core.ui.drawSLPanel(index); + } + } + else { + core.doSL(id, core.status.event.id); + } } } @@ -1346,6 +1368,15 @@ actions.prototype.keyUpSL = function (keycode) { } return; } + if (keycode==46) { + if (offset==0) { + core.drawTip("无法删除自动存档!"); + } + else { + core.removeLocalStorage("save"+(5*page+offset)); + core.ui.drawSLPanel(index); + } + } } ////// 系统设置界面时的点击操作 ////// @@ -1389,15 +1420,21 @@ actions.prototype.clickSwitchs = function (x,y) { core.ui.drawSwitchs(); break; case 4: + core.flags.displayCritical=!core.flags.displayCritical; + core.updateFg(); + core.setLocalStorage('critical', core.flags.displayCritical); + core.ui.drawSwitchs(); + break; + case 5: core.flags.displayExtraDamage=!core.flags.displayExtraDamage; core.updateFg(); core.setLocalStorage('extraDamage', core.flags.displayExtraDamage); core.ui.drawSwitchs(); break; - case 5: + case 6: window.open(core.firstData.name+".zip", "_blank"); break; - case 6: + case 7: core.status.event.selection=0; core.ui.drawSettings(); break; diff --git a/libs/control.js b/libs/control.js index 0bae3a0d..a4db300b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -946,7 +946,7 @@ control.prototype.updateCheckBlock = function() { core.status.checkBlock.betweenAttack[13*x+y]=true; var leftHp = core.status.hero.hp - core.status.checkBlock.damage[13*x+y]; if (leftHp>1) - core.status.checkBlock.damage[13*x+y] += parseInt((leftHp+(core.flags.betweenAttackCeil?0:1))/2); + core.status.checkBlock.damage[13*x+y] += Math.floor((leftHp+(core.flags.betweenAttackCeil?0:1))/2); } } } @@ -1039,21 +1039,28 @@ control.prototype.snipe = function (snipes) { snipe.blockIcon = core.material.icons[cls][block.event.id]; snipe.blockImage = core.material.images[cls]; snipe.height = height; + var damage = core.enemys.getDamage(block.event.id); + var color = '#000000'; - var color = "#000000"; - if (damage <= 0) color = '#00FF00'; - else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; - else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; - else if (damage < core.status.hero.hp) color = '#FF7F00'; - else color = '#FF0000'; + if (damage == null) { + damage = "???"; + color = '#FF0000'; + } + else { + if (damage <= 0) color = '#00FF00'; + else if (damage < hero_hp / 3) color = '#FFFFFF'; + else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; + else if (damage < hero_hp) color = '#FF7F00'; + else color = '#FF0000'; - if (damage >= 999999999) damage = "???"; - else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; + damage = core.formatBigNumber(damage); + } snipe.damage = damage; snipe.color = color; snipe.block = core.clone(block); + }) var finishSnipe = function () { @@ -1245,7 +1252,7 @@ control.prototype.updateFg = function () { if (!core.hasItem('book')) return; core.setFont('fg', "bold 11px Arial"); var hero_hp = core.status.hero.hp; - if (core.flags.displayEnemyDamage) { + if (core.flags.displayEnemyDamage || core.flags.displayCritical) { core.canvas.fg.textAlign = 'left'; for (var b = 0; b < mapBlocks.length; b++) { var x = mapBlocks[b].x, y = mapBlocks[b].y; @@ -1264,25 +1271,46 @@ control.prototype.updateFg = function () { var id = mapBlocks[b].event.id; - var damage = core.enemys.getDamage(id); - var color = "#000000"; - if (damage <= 0) color = '#00FF00'; - else if (damage < hero_hp / 3) color = '#FFFFFF'; - else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; - else if (damage < hero_hp) color = '#FF7F00'; - else color = '#FF0000'; + if (core.flags.displayEnemyDamage) { + var damage = core.enemys.getDamage(id); + var color = '#000000'; - if (damage >= 999999999) damage = "???"; - else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; + if (damage == null) { + damage = "???"; + color = '#FF0000'; + } + else { + if (damage <= 0) color = '#00FF00'; + else if (damage < hero_hp / 3) color = '#FFFFFF'; + else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; + else if (damage < hero_hp) color = '#FF7F00'; + else color = '#FF0000'; - core.setFillStyle('fg', '#000000'); - core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1) - 2); - core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1) - 2); - core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1)); - core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1)); + damage = core.formatBigNumber(damage); + } - core.setFillStyle('fg', color); - core.canvas.fg.fillText(damage, 32 * x + 1, 32 * (y + 1) - 1); + core.setFillStyle('fg', '#000000'); + core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1) - 2); + core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1) - 2); + core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1)); + core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1)); + + core.setFillStyle('fg', color); + core.canvas.fg.fillText(damage, 32 * x + 1, 32 * (y + 1) - 1); + } + + // 临界显伤 + if (core.flags.displayCritical) { + var critical = core.formatBigNumber(core.enemys.getCritical(id)); + if (critical == '???') critical = '?'; + core.setFillStyle('fg', '#000000'); + core.canvas.fg.fillText(critical, 32 * x + 2, 32 * (y + 1) - 2 - 10); + core.canvas.fg.fillText(critical, 32 * x, 32 * (y + 1) - 2 - 10); + core.canvas.fg.fillText(critical, 32 * x + 2, 32 * (y + 1) - 10); + core.canvas.fg.fillText(critical, 32 * x, 32 * (y + 1) - 10); + core.setFillStyle('fg', '#FFFFFF'); + core.canvas.fg.fillText(critical, 32 * x + 1, 32 * (y + 1) - 1 - 10); + } } } @@ -2075,8 +2103,9 @@ control.prototype.updateStatusBar = function () { var statusList = ['hpmax', 'hp', 'atk', 'def', 'mdef', 'money', 'experience']; statusList.forEach(function (item) { - core.statusBar[item].innerHTML = core.getStatus(item); + core.statusBar[item].innerHTML = core.formatBigNumber(core.getStatus(item)); }); + // 进阶 if (core.flags.enableLevelUp && core.status.hero.lv= 999999999) return damage; + if (damage == null) return null; return damage + this.getExtraDamage(monster); } @@ -132,17 +138,43 @@ enemys.prototype.getCritical = function (monsterId) { // 坚固、模仿怪物没有临界! if (this.hasSpecial(monster.special, 3) || this.hasSpecial(monster.special, 10)) return "???"; - var last = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef); + if (monster.def + monster.hp/2 <= 0) { - if (last <= 0) return 0; + var last = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef); + + if (last == null) return '???'; + + if (last <= 0) return 0; + + for (var i = core.status.hero.atk + 1; i <= monster.hp + monster.def; i++) { + var damage = this.calDamage(monster, core.status.hero.hp, i, core.status.hero.def, core.status.hero.mdef); + if (damage == null) return '???'; + if (damage < last) + return core.formatBigNumber(i - core.status.hero.atk); + last = damage; + } + return 0; - for (var i = core.status.hero.atk + 1; i <= monster.hp + monster.def; i++) { - var damage = this.calDamage(monster, core.status.hero.hp, i, core.status.hero.def, core.status.hero.mdef); - if (damage < last) - return i - core.status.hero.atk; - last = damage; } - return 0; + else { + + var info = this.getDamageInfo(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef); + + if (info == null) return '???'; + if (info.damage <= 0) return 0; + + var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = monster.def, turn = info.turn; + + // turn 是勇士攻击次数 + if (turn<=1) return 0; // 攻杀 + + // 每回合最小伤害 = ⎡怪物生命/勇士攻击次数⎤ + var nextAtk = Math.ceil(mon_hp/(turn-1)) + mon_def; + + if (nextAtk <= hero_atk) return 0; + return nextAtk - hero_atk; + } + } ////// 临界减伤计算 ////// @@ -152,9 +184,9 @@ enemys.prototype.getCriticalDamage = function (monsterId) { if (c <= 0) return 0; var monster = core.material.enemys[monsterId]; var last = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef); - if (last >= 999999999) return '???'; - - return last - this.calDamage(monster, core.status.hero.hp, core.status.hero.atk + c, core.status.hero.def, core.status.hero.mdef); + var now = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk+c, core.status.hero.def, core.status.hero.mdef); + if (last == null || now==null) return '???'; + return last - now; } ////// 1防减伤计算 ////// @@ -162,12 +194,12 @@ enemys.prototype.getDefDamage = function (monsterId) { var monster = core.material.enemys[monsterId]; var nowDamage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef); var nextDamage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def + 1, core.status.hero.mdef); - if (nowDamage >= 999999999 || nextDamage >= 999999999) return "???"; + if (nowDamage == null || nextDamage ==null) return "???"; return nowDamage - nextDamage; } -////// 具体的伤害计算公式 ////// -enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) { +////// 获得战斗伤害信息 ////// +enemys.prototype.getDamageInfo = function(monster, hero_hp, hero_atk, hero_def, hero_mdef) { var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_special = monster.special; hero_hp=Math.max(0, hero_hp); @@ -176,7 +208,7 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her hero_mdef=Math.max(0, hero_mdef); if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross")) // 如果是无敌属性,且勇士未持有十字架 - return 999999999; // 返回无限大 + return null; // 返回不可战斗 var initDamage = 0; // 战前伤害 @@ -186,7 +218,7 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her // 如果有神圣盾免疫吸血等可以在这里写 - vampireDamage = parseInt(vampireDamage); + vampireDamage = Math.floor(vampireDamage) || 0; // 加到自身 if (monster.add) // 如果加到自身 mon_hp += vampireDamage; @@ -203,7 +235,7 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her if (this.hasSpecial(mon_special,2)) hero_def = 0; // 坚固 if (this.hasSpecial(mon_special,3) && mon_def < hero_atk - 1) mon_def = hero_atk - 1; - if (hero_atk <= mon_def) return 999999999; // 不可战斗时请直接返回999999999 + if (hero_atk <= mon_def) return null; // 不可战斗时请直接返回null var per_damage = mon_atk - hero_def; if (per_damage < 0) per_damage = 0; @@ -215,7 +247,7 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her var counterDamage = 0; // 反击 - if (this.hasSpecial(mon_special, 8)) counterDamage += parseInt(core.values.counterAttack * hero_atk); + if (this.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk); // 先攻 if (this.hasSpecial(mon_special, 1)) @@ -223,20 +255,41 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her // 破甲 if (this.hasSpecial(mon_special, 7)) - initDamage += parseInt(core.values.breakArmor * hero_def); + initDamage += Math.floor(core.values.breakArmor * hero_def); // 净化 if (this.hasSpecial(mon_special, 9)) - initDamage += parseInt(core.values.purify * hero_mdef); + initDamage += Math.floor(core.values.purify * hero_mdef); - var turn = parseInt((mon_hp - 1) / (hero_atk - mon_def)); - var ans = initDamage + turn * per_damage + (turn + 1) * counterDamage; + // turn: 勇士攻击回合数 + var turn = Math.ceil(mon_hp / (hero_atk - mon_def)); + var ans = initDamage + (turn - 1) * per_damage + turn * counterDamage; ans -= hero_mdef; if (!core.flags.enableNegativeDamage) ans=Math.max(0, ans); - return ans; + return { + "hero_atk": hero_atk, + "hero_def": hero_def, + "hero_mdef": hero_mdef, + "mon_hp": mon_hp, + "mon_atk": mon_atk, + "mon_def": mon_def, + "per_damage": per_damage, + "initDamage": initDamage, + "turn": turn, + "damage": ans + }; +} + +////// 具体的伤害计算公式 ////// +enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) { + + var info = this.getDamageInfo(monster, hero_hp, hero_atk, hero_def, hero_mdef); + if (info == null) return null; + return info.damage; + } ////// 获得当前楼层的怪物列表 ////// diff --git a/libs/events.js b/libs/events.js index bac028d1..de85c843 100644 --- a/libs/events.js +++ b/libs/events.js @@ -123,11 +123,32 @@ events.prototype.lose = function (reason) { ////// 游戏结束 ////// events.prototype.gameOver = function (ending, fromReplay) { + // 下载录像 + var confirmDownload = function () { + core.ui.closePanel(); + setTimeout(function () { + core.ui.drawConfirmBox("你想下载录像吗?", function () { + var obj = { + 'name': core.firstData.name, + 'version': core.firstData.version, + 'hard': core.status.hard, + 'route': core.encodeRoute(core.status.route) + } + core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj)); + core.restart(); + }, function () { + core.restart(); + }) + }, 150); + } + // 上传成绩 var confirmUpload = function () { + core.ui.closePanel(); + if (!core.isset(ending)) { - core.restart(); + confirmDownload(); return; } @@ -154,8 +175,7 @@ events.prototype.gameOver = function (ending, fromReplay) { formData.append('route', core.encodeRoute(core.status.route)); core.http("POST", "/games/upload.php", formData); - - core.restart(); + confirmDownload(); } core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () { @@ -167,30 +187,14 @@ events.prototype.gameOver = function (ending, fromReplay) { return; } - // 下载录像 - var confirmDownload = function () { - core.ui.closePanel(); - core.ui.drawConfirmBox("你想下载录像吗?", function () { - var obj = { - 'name': core.firstData.name, - 'version': core.firstData.version, - 'hard': core.status.hard, - 'route': core.encodeRoute(core.status.route) - } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj)); - confirmUpload(); - }, function () { - confirmUpload(); - }) - } - if (fromReplay) { core.drawText("录像回放完毕!", function () { core.restart(); }); } else { - confirmDownload(); + // confirmDownload(); + confirmUpload(); } } @@ -386,13 +390,15 @@ events.prototype.doAction = function() { }); break; case "changeFloor": // 楼层转换 - var heroLoc = {"x": data.loc[0], "y": data.loc[1]}; - if (core.isset(data.direction)) heroLoc.direction=data.direction; - core.changeFloor(data.floorId||core.status.floorId, null, heroLoc, data.time, function() { - core.lockControl(); - core.events.doAction(); - }); - break; + { + var heroLoc = {"x": data.loc[0], "y": data.loc[1]}; + if (core.isset(data.direction)) heroLoc.direction=data.direction; + core.changeFloor(data.floorId||core.status.floorId, null, heroLoc, data.time, function() { + core.lockControl(); + core.events.doAction(); + }); + break; + } case "changePos": // 直接更换勇士位置,不切换楼层 core.clearMap('hero', 0, 0, 416, 416); if (core.isset(data.loc)) { @@ -410,6 +416,36 @@ events.prototype.doAction = function() { else core.clearMap('animate', 0, 0, 416, 416); this.doAction(); break; + case "animateImage": // 淡入淡出图片 + if (core.status.replay.replaying) { // 正在播放录像 + this.doAction(); + } + else { + if (core.isset(data.loc) && core.isset(core.material.images.images[data.name]) && (data.action=="show" || data.action=="hide")) { + core.events.animateImage(data.action, core.material.images.images[data.name], data.loc, data.time, function() { + core.events.doAction(); + }); + } + else { + this.doAction(); + } + } + break; + case "showGif": // 显示动图 + if (core.isset(data.loc) && core.isset(core.material.images.images[data.name])) { + var gif = new Image(); + gif.src = core.material.images.images[data.name].src; + gif.style.position = 'absolute'; + gif.style.left = (data.loc[0]*core.domStyle.scale)+"px"; + gif.style.top = (data.loc[1]*core.domStyle.scale)+"px"; + core.dom.gif2.appendChild(gif); + } + else { + while (core.dom.gif2.firstChild) + core.dom.gif2.removeChild(core.dom.gif2.firstChild); + } + this.doAction(); + break; case "setFg": // 颜色渐变 core.setFg(data.color, data.time, function() { core.events.doAction(); @@ -420,21 +456,23 @@ events.prototype.doAction = function() { this.doAction(); break; case "openDoor": // 开一个门,包括暗墙 - var floorId=data.floorId || core.status.floorId; - var block=core.getBlock(data.loc[0], data.loc[1], floorId); - if (block!=null) { - if (floorId==core.status.floorId) - core.openDoor(block.block.event.id, block.block.x, block.block.y, false, function() { - core.events.doAction(); - }) - else { - core.removeBlock(block.block.x,block.block.y,floorId); - this.doAction(); + { + var floorId=data.floorId || core.status.floorId; + var block=core.getBlock(data.loc[0], data.loc[1], floorId); + if (block!=null) { + if (floorId==core.status.floorId) + core.openDoor(block.block.event.id, block.block.x, block.block.y, false, function() { + core.events.doAction(); + }) + else { + core.removeBlock(block.block.x,block.block.y,floorId); + this.doAction(); + } + break; } + this.doAction(); break; } - this.doAction(); - break; case "openShop": // 打开一个全局商店 if (core.status.replay.replaying) { // 正在播放录像,简单将visited置为true core.status.shops[data.id].visited=true; @@ -454,21 +492,24 @@ events.prototype.doAction = function() { }) break; case "trigger": // 触发另一个事件;当前事件会被立刻结束。需要另一个地点的事件是有效的 - var toX=data.loc[0], toY=data.loc[1]; - var block=core.getBlock(toX, toY); - if (block!=null) { - block = block.block; - if (core.isset(block.event) && block.event.trigger=='action') { - // 触发 - core.status.event.data.list = core.clone(block.event.data); - core.status.event.data.x=block.x; - core.status.event.data.y=block.y; + { + var toX=data.loc[0], toY=data.loc[1]; + var block=core.getBlock(toX, toY); + if (block!=null) { + block = block.block; + if (core.isset(block.event) && block.event.trigger=='action') { + // 触发 + core.status.event.data.list = core.clone(block.event.data); + core.status.event.data.x=block.x; + core.status.event.data.y=block.y; + } } + this.doAction(); + break; } - this.doAction(); - break; case "playSound": - core.playSound(data.name); + if (!core.status.replay.replaying) + core.playSound(data.name); this.doAction(); break; case "playBgm": @@ -488,7 +529,7 @@ events.prototype.doAction = function() { var value=core.calValue(data.value); // 属性 if (data.name.indexOf("status:")==0) { - value=parseInt(value); + value=parseFloat(value); core.setStatus(data.name.substring(7), value); } // 道具 @@ -581,35 +622,43 @@ events.prototype.doAction = function() { }); break; case "function": - var func = data["function"]; - if (core.isset(func)) { - if ((typeof func == "string") && func.indexOf("function")==0) { - eval('('+func+')()'); + { + var func = data["function"]; + if (core.isset(func)) { + if ((typeof func == "string") && func.indexOf("function")==0) { + eval('('+func+')()'); + } + else if (func instanceof Function) + func(); } - else if (func instanceof Function) - func(); + this.doAction(); + break; } - this.doAction(); - break; case "update": core.updateStatusBar(); this.doAction(); break; case "sleep": // 等待多少毫秒 - setTimeout(function () { + if (core.status.replay.replaying) core.events.doAction(); - }, data.time); + else { + setTimeout(function () { + core.events.doAction(); + }, data.time); + } break; case "revisit": // 立刻重新执行该事件 - var block=core.getBlock(x,y); // 重新获得事件 - if (block!=null) { - block = block.block; - if (core.isset(block.event) && block.event.trigger=='action') { - core.status.event.data.list = core.clone(block.event.data); + { + var block=core.getBlock(x,y); // 重新获得事件 + if (block!=null) { + block = block.block; + if (core.isset(block.event) && block.event.trigger=='action') { + core.status.event.data.list = core.clone(block.event.data); + } } + this.doAction(); + break; } - this.doAction(); - break; case "exit": // 立刻结束事件 core.status.event.data.list = []; core.events.doAction(); @@ -732,9 +781,8 @@ events.prototype.battle = function (id, x, y, force, callback) { core.stopHero(); core.stopAutomaticRoute(); - var damage = core.enemys.getDamage(id); // 非强制战斗 - if (damage >= core.status.hero.hp && !force) { + if (!core.enemys.canBattle(id) && !force) { core.drawTip("你打不过此怪物!"); core.clearContinueAutomaticRoute(); return; @@ -885,6 +933,10 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } else core.setWeather(); + // 清除gif + while (core.dom.gif.firstChild) + core.dom.gif.removeChild(core.dom.gif.firstChild); + // 检查重生 if (!core.isset(fromLoad)) { core.status.maps[floorId].blocks.forEach(function(block) { @@ -894,7 +946,6 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } }) } - core.drawMap(floorId, function () { setTimeout(function() { if (core.isset(heroLoc.direction)) @@ -933,6 +984,37 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback }, 25); } +////// 图片淡入/淡出 ////// +events.prototype.animateImage = function (type, image, loc, time, callback) { + time = time||0; + if ((type!='show' && type!='hide') || time<=0) { + if (core.isset(callback)) callback(); + return; + } + + clearInterval(core.interval.tipAnimate); + core.setAlpha('data', 1); + + var opacityVal = 0; + if (type == 'hide') opacityVal = 1; + + core.setOpacity('data', opacityVal); + core.canvas.data.drawImage(image, loc[0], loc[1]); + core.status.replay.animate=true; + var animate = setInterval(function () { + if (type=='show') opacityVal += 0.1; + else opacityVal -= 0.1; + core.setOpacity('data', opacityVal); + if (opacityVal >=1 || opacityVal<=0) { + clearInterval(animate); + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 1); + core.status.replay.animate=false; + if (core.isset(callback)) callback(); + } + }, time / 10 / core.status.replay.speed); +} + ////// 打开一个全局商店 ////// events.prototype.openShop = function(shopId, needVisited) { var shop = core.status.shops[shopId]; diff --git a/libs/loader.js b/libs/loader.js index 48844bb6..e93571d1 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -171,8 +171,8 @@ loader.prototype.loadMusic = function () { } else { var music = new Audio(); - music.preload = core.musicStatus.startDirectly?'auto':'none'; - if (main.bgmRemote) music.src = 'https://gitee.com/ckcz123/h5music/raw/master/'+core.firstData.name+'/'+t; + music.preload = 'none'; + if (main.bgmRemote) music.src = main.bgmRemoteRoot+core.firstData.name+'/'+t; else music.src = 'project/sounds/'+t; music.loop = 'loop'; core.material.bgms[t] = music; diff --git a/libs/maps.js b/libs/maps.js index 23866b4a..d2575c2c 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -328,8 +328,19 @@ maps.prototype.drawMap = function (mapName, callback) { if (core.isset(dx) && core.isset(dy) && core.isset(core.material.images.images[p])) { dx*=32; dy*=32; var image = core.material.images.images[p]; - if (!t[3]) - core.canvas.bg.drawImage(image, dx*ratio, dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); + if (!t[3]) { + core.canvas.bg.drawImage(image, dx * ratio, dy * ratio, Math.min(size - dx * ratio, ratio * image.width), Math.min(size - dy * ratio, ratio * image.height)); + if (/.*\.gif/i.test(p)) { + while (core.dom.gif.firstChild) + core.dom.gif.removeChild(core.dom.gif.firstChild); + var gif = new Image(); + gif.src = core.material.images.images[p].src; + gif.style.position = 'absolute'; + gif.style.left = (dx*core.domStyle.scale)+"px"; + gif.style.top = (dy*core.domStyle.scale)+"px"; + core.dom.gif.appendChild(gif); + } + } else core.canvas.event2.drawImage(image, dx*ratio, dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); } @@ -669,9 +680,6 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { if (type=='show') opacityVal += 0.1; else opacityVal -= 0.1; core.setOpacity('animate', opacityVal); - core.clearMap('animate',0,0,416,416); - - draw(); if (opacityVal >=1 || opacityVal<=0) { clearInterval(animate); core.clearMap('animate', 0, 0, 416, 416); diff --git a/libs/ui.js b/libs/ui.js index e01d802f..0c9425de 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -734,6 +734,7 @@ ui.prototype.drawSwitchs = function() { "背景音效:"+(core.musicStatus.soundStatus ? "[ON]" : "[OFF]"), "战斗动画: "+(core.flags.battleAnimate ? "[ON]" : "[OFF]"), "怪物显伤: "+(core.flags.displayEnemyDamage ? "[ON]" : "[OFF]"), + "临界显伤: "+(core.flags.displayCritical ? "[ON]" : "[OFF]"), "领域显伤: "+(core.flags.displayExtraDamage ? "[ON]" : "[OFF]"), "下载离线版本", "返回主菜单" @@ -787,7 +788,7 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) { // 如果有神圣盾免疫吸血等可以在这里写 - vampireDamage = parseInt(vampireDamage); + vampireDamage = Math.floor(vampireDamage); // 加到自身 if (monster.add) // 如果加到自身 mon_hp += vampireDamage; @@ -815,8 +816,8 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) { if (core.enemys.hasSpecial(mon_special, 6)) turns=1+(monster.n||4); // 初始伤害 - if (core.enemys.hasSpecial(mon_special, 7)) initDamage+=parseInt(core.values.breakArmor * hero_def); - if (core.enemys.hasSpecial(mon_special, 9)) initDamage+=parseInt(core.values.purify * hero_mdef); + if (core.enemys.hasSpecial(mon_special, 7)) initDamage+=Math.floor(core.values.breakArmor * hero_def); + if (core.enemys.hasSpecial(mon_special, 9)) initDamage+=Math.floor(core.values.purify * hero_mdef); hero_mdef-=initDamage; if (hero_mdef<0) { hero_hp+=hero_mdef; @@ -1001,7 +1002,7 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) { // 反击 if (core.enemys.hasSpecial(mon_special, 8)) { - hero_mdef -= parseInt(core.values.counterAttack * hero_atk); + hero_mdef -= Math.floor(core.values.counterAttack * hero_atk); if (hero_mdef<0) { hero_hp+=hero_mdef; @@ -1247,16 +1248,16 @@ ui.prototype.drawBook = function (index) { } core.canvas.ui.textAlign = "left"; core.fillText('ui', '生命', 165, 62 * i + 32, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.hp, 195, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.hp), 195, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '攻击', 255, 62 * i + 32, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.atk, 285, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.atk), 285, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '防御', 335, 62 * i + 32, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.def, 365, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.def), 365, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); var expOffset = 165, line_cnt=0; if (core.flags.enableMoney) { core.fillText('ui', '金币', 165, 62 * i + 50, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.money, 195, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.money), 195, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); expOffset = 255; line_cnt++; } @@ -1265,7 +1266,7 @@ ui.prototype.drawBook = function (index) { if (core.flags.enableAddPoint) { core.canvas.ui.textAlign = "left"; core.fillText('ui', '加点', expOffset, 62 * i + 50, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.point, expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.point), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); expOffset = 255; line_cnt++; } @@ -1273,7 +1274,7 @@ ui.prototype.drawBook = function (index) { if (core.flags.enableExperience && line_cnt<2) { core.canvas.ui.textAlign = "left"; core.fillText('ui', '经验', expOffset, 62 * i + 50, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.experience, expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.experience), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); line_cnt++; } @@ -1281,31 +1282,30 @@ ui.prototype.drawBook = function (index) { if (line_cnt==1) damageOffset=326; if (line_cnt==2) damageOffset=361; - /* - var damageOffet = 281; - if (core.flags.enableMoney && core.flags.enableExperience) - damageOffet = 361; - else if (core.flags.enableMoney || core.flags.enableExperience) - damageOffet = 326; - */ - - core.canvas.ui.textAlign = "center"; var damage = enemy.damage; + var color = '#FFFF00'; - if (damage >= core.status.hero.hp) color = '#FF0000'; - if (damage <= 0) color = '#00FF00'; - if (damage >= 999999999) damage = '无法战斗'; + if (damage == null) { + damage = '无法战斗'; + color = '#FF0000'; + } + else { + if (damage >= core.status.hero.hp) color = '#FF0000'; + if (damage<=0) color = '#00FF00'; + + damage = core.formatBigNumber(damage); + } core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px Verdana'); core.canvas.ui.textAlign = "left"; core.fillText('ui', '临界', 165, 62 * i + 68, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.critical, 195, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.critical), 195, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '减伤', 255, 62 * i + 68, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.criticalDamage, 285, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.criticalDamage), 285, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '1防', 335, 62 * i + 68, '#DDDDDD', '13px Verdana'); - core.fillText('ui', enemy.defDamage, 365, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.defDamage), 365, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); if (index == start+i) { core.strokeRect('ui', 10, 62 * i + 13, 416-10*2, 62, '#FFD700'); @@ -1327,10 +1327,9 @@ ui.prototype.drawBookDetail = function (index) { var enemyId=enemy.id; var hints=core.enemys.getSpecialHint(core.material.enemys[enemyId]); - if (hints.length==0) { - core.drawTip("该怪物无特殊属性!"); - return; - } + + if (hints.length==0) + hints.push("该怪物无特殊属性。"); var content=hints.join("\n"); core.status.event.id = 'book-detail'; @@ -1573,13 +1572,16 @@ ui.prototype.drawSLPanel = function(index) { var u=416/6, size=118; + var strokeColor = '#FFD700'; + if (core.status.event.selection) strokeColor = '#FF6A6A'; + var name=core.status.event.id=='save'?"存档":"读档"; for (var i=0;i<6;i++) { var id=5*page+i; var data=core.getLocalStorage(i==0?"autoSave":"save"+id, null); if (i<3) { core.fillText('ui', i==0?"自动存档":name+id, (2*i+1)*u, 35, '#FFFFFF', "bold 17px Verdana"); - core.strokeRect('ui', (2*i+1)*u-size/2, 50, size, size, i==offset?'#FFD700':'#FFFFFF', i==offset?6:2); + core.strokeRect('ui', (2*i+1)*u-size/2, 50, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { this.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 50, size, data.hero.loc); core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 65+size, '#FFFFFF', '10px Verdana'); @@ -1591,7 +1593,7 @@ ui.prototype.drawSLPanel = function(index) { } else { core.fillText('ui', name+id, (2*i-5)*u, 230, '#FFFFFF', "bold 17px Verdana"); - core.strokeRect('ui', (2*i-5)*u-size/2, 245, size, size, i==offset?'#FFD700':'#FFFFFF', i==offset?6:2); + core.strokeRect('ui', (2*i-5)*u-size/2, 245, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { this.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 245, size, data.hero.loc); core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 260+size, '#FFFFFF', '10px Verdana'); @@ -1603,6 +1605,11 @@ ui.prototype.drawSLPanel = function(index) { } } this.drawPagination(page+1, 30); + + if (core.status.event.selection) + core.setFillStyle('ui', '#FF6A6A'); + core.fillText('ui', '删除模式', 48, 403); + } ////// 绘制一个缩略图 ////// diff --git a/libs/utils.js b/libs/utils.js index 8c46819e..aaf82da3 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -145,6 +145,29 @@ utils.prototype.setTwoDigits = function (x) { return parseInt(x)<10?"0"+x:x; } +utils.prototype.formatBigNumber = function (x) { + x = parseFloat(x); + if (!core.isset(x)) return '???'; + + var all = [ + {"val": 10e20, "c": "g"}, + {"val": 10e16, "c": "j"}, + {"val": 10e12, "c": "z"}, + {"val": 10e8, "c": "e"}, + {"val": 10e4, "c": "w"}, + ] + + for (var i=0;i=10*one.val) { + var v = x/one.val; + return v.toFixed(Math.max(0, Math.floor(4-Math.log10(v)))) + one.c; + } + } + + return x; +} + ////// 数组转RGB ////// utils.prototype.arrayToRGB = function (color) { var nowR = parseInt(color[0])||0, nowG = parseInt(color[1])||0, nowB = parseInt(color[2])||0; @@ -278,7 +301,7 @@ utils.prototype.readFile = function (success, error, readType) { if (core.platform.fileInput==null) { core.platform.fileInput = document.createElement("input"); - core.platform.fileInput.style.display = 'none'; + core.platform.fileInput.style.opacity = 0; core.platform.fileInput.type = 'file'; core.platform.fileInput.onchange = function () { var files = core.platform.fileInput.files; @@ -301,6 +324,11 @@ utils.prototype.readFile = function (success, error, readType) { ////// 下载文件到本地 ////// utils.prototype.download = function (filename, content) { + if (core.isset(window.jsinterface)) { + window.jsinterface.download(filename, content); + return; + } + // Step 0: 不为http/https,直接不支持 if (!core.platform.isOnline) { alert("离线状态下不支持下载操作!"); diff --git a/main.js b/main.js index ee198da6..f503e097 100644 --- a/main.js +++ b/main.js @@ -10,6 +10,7 @@ function main() { // 如果要进行剧本的修改请务必将其改成false。 this.bgmRemote = false; // 是否采用远程BGM + this.bgmRemoteRoot = "https://gitee.com/ckcz123/h5music/raw/master/"; // 远程BGM的根目录 //------------------------ 用户修改内容 END ------------------------// @@ -35,6 +36,8 @@ function main() { 'toolBar': document.getElementById('toolBar'), 'tools': document.getElementsByClassName('tools'), 'gameCanvas': document.getElementsByClassName('gameCanvas'), + 'gif': document.getElementById('gif'), + 'gif2': document.getElementById('gif2'), 'curtain': document.getElementById('curtain'), 'startButtons': document.getElementById('startButtons'), 'playGame': document.getElementById('playGame'), @@ -174,17 +177,26 @@ main.prototype.init = function (mode, callback) { ////// 动态加载所有核心JS文件 ////// main.prototype.loaderJs = function (dir, loadList, callback) { - var instanceNum = 0; + // 加载js main.setMainTipsText('正在加载核心js文件...') - for (var i = 0; i < loadList.length; i++) { - main.loadMod(dir, loadList[i], function (modName) { - main.setMainTipsText(modName + '.js 加载完毕'); - instanceNum++; - if (instanceNum === loadList.length) { - callback(); - } - }); + + if (this.useCompress) { + main.loadMod(dir, dir, function () { + callback(); + }) + } + else { + var instanceNum = 0; + for (var i = 0; i < loadList.length; i++) { + main.loadMod(dir, loadList[i], function (modName) { + main.setMainTipsText(modName + '.js 加载完毕'); + instanceNum++; + if (instanceNum === loadList.length) { + callback(); + } + }); + } } } diff --git a/project/data.comment.js b/project/data.comment.js index 92601f77..464163fa 100644 --- a/project/data.comment.js +++ b/project/data.comment.js @@ -488,6 +488,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否地图怪物显伤;用户可以手动在菜单栏中开关" }, + "displayCritical": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否地图显示临界;用户可以手动在菜单栏中开关" + }, "displayExtraDamage": { "_leaf": true, "_type": "checkbox", diff --git a/project/data.js b/project/data.js index 1059227c..1bf2802b 100644 --- a/project/data.js +++ b/project/data.js @@ -5,13 +5,13 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "sample0", "sample1", "sample2", "MT0" ], "images" : [ - "bg.jpg", + "bg.jpg" ], "animates" : [ - "hand", "sword", "zone", "yongchang", + "hand", "sword", "zone", ], "bgms" : [ - 'bgm.mp3', 'qianjin.mid', 'star.mid', + 'bgm.mp3' ], "sounds" : [ 'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg', 'zone.ogg' @@ -142,13 +142,13 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableLevelUp": false, "enableDebuff": false, "flyNearStair": true, - "pickaxeFourDirections": true, - "bombFourDirections": true, + "pickaxeFourDirections": false, + "bombFourDirections": false, "bigKeyIsBox": false, - "equipment": true, + "equipment": false, "enableDeleteItem": true, "enableAddPoint": false, - "enableNegativeDamage": true, + "enableNegativeDamage": false, "hatredDecrease": true, "betweenAttackCeil": false, "startDirectly": false, @@ -156,6 +156,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "showBattleAnimateConfirm": true, "battleAnimate": true, "displayEnemyDamage": true, + "displayCritical": true, "displayExtraDamage": true, "enableGentleClick": true, "potionWhileRouting": false, diff --git a/project/floors/sample0.js b/project/floors/sample0.js index 804dee94..7b75facb 100644 --- a/project/floors/sample0.js +++ b/project/floors/sample0.js @@ -15,19 +15,19 @@ main.floors.sample0 = "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 "item_ratio": 2, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 - [0, 0, 220, 0, 0, 20, 87, 3, 65, 64, 44, 43, 42], - [0, 246, 0, 246, 0, 20, 0, 3, 58, 59, 60, 61, 41], - [219, 0, 0, 0, 219, 20, 0, 3, 57, 26, 62, 63, 40], - [20, 20, 125, 20, 20, 20, 0, 3, 53, 54, 55, 56, 39], - [216, 247, 263, 235, 248, 6, 0, 3, 49, 50, 51, 52, 38], - [6, 6, 125, 6, 6, 6, 0, 1, 45, 46, 47, 48, 37], - [224, 254, 212, 262, 204, 5, 0, 1, 31, 32, 34, 33, 36], - [201, 261, 217, 264, 207, 5, 0, 1, 27, 28, 29, 30, 35], - [5, 5, 125, 5, 5, 5, 0, 1, 21, 22, 23, 24, 25], - [0, 0, 237, 0, 0, 0, 45, 1, 1, 1, 121, 1, 1], - [4, 4, 133, 4, 4, 4, 0, 0, 0, 0, 0, 85, 124], - [87, 11, 12, 13, 14, 4, 4, 2, 2, 2, 122, 2, 2], - [88, 89, 90, 91, 92, 93, 94, 2, 81, 82, 83, 84, 86], + [ 0, 0,220, 0, 0, 20, 87, 3, 65, 64, 44, 43, 42], + [ 0,246, 0,246, 0, 20, 0, 3, 58, 59, 60, 61, 41], + [219, 0, 0, 0,219, 20, 0, 3, 57, 26, 62, 63, 40], + [ 20, 20,115, 20, 20, 20, 0, 3, 53, 54, 55, 56, 39], + [216,247,263,235,248, 6, 0, 3, 49, 50, 51, 52, 38], + [ 6, 6,115, 6, 6, 6, 0, 1, 45, 46, 47, 48, 37], + [224,254,212,262,204, 5, 0, 1, 31, 32, 34, 33, 36], + [201,261,217,264,207, 5, 0, 1, 27, 28, 29, 30, 35], + [ 5, 5,115, 5, 5, 5, 0, 1, 21, 22, 23, 24, 25], + [ 0, 0,237, 0, 0, 0, 45, 1, 1, 1,111, 1, 1], + [ 4, 4,139, 4, 4, 4, 0, 0, 0, 0, 0, 85,114], + [ 87, 11, 12, 13, 14, 4, 4, 2, 2, 2,112, 2, 2], + [ 88, 89, 90, 91, 92, 93, 94, 2, 81, 82, 83, 84, 86] ], "firstArrive": [ // 第一次到该楼层触发的事件 "\t[样板提示]首次到达某层可以触发 firstArrive 事件,该事件可类似于RMXP中的“自动执行脚本”。\n\n本事件支持一切的事件类型,常常用来触发对话,例如:", diff --git a/project/floors/sample1.js b/project/floors/sample1.js index 669d67b1..70d17578 100644 --- a/project/floors/sample1.js +++ b/project/floors/sample1.js @@ -15,19 +15,19 @@ main.floors.sample1 = // "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 "item_ratio": 1, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 - [7, 131, 8, 152, 9, 130, 10, 152, 166, 165, 132, 165, 166], - [0, 0, 0, 0, 0, 0, 0, 152, 165, 164, 0, 162, 165], - [152, 152, 152, 152, 121, 152, 152, 152, 0, 0, 229, 0, 0], - [43, 33, 44, 151, 0, 0, 0, 152, 165, 161, 0, 163, 165], - [21, 22, 21, 151, 0, 0, 0, 152, 166, 165, 0, 165, 166], - [151, 245, 151, 151, 0, 87, 0, 152, 152, 152, 85, 153, 153], - [0, 246, 0, 151, 0, 0, 0, 152, 152, 221, 0, 221, 153], - [246, 0, 246, 151, 0, 0, 0, 121, 85, 0, 0, 0, 153], - [151, 246, 151, 151, 0, 153, 153, 153, 153, 153, 153, 153, 153], - [0, 0, 0, 0, 0, 0, 0, 164, 0, 0, 163, 0, 0], - [1, 1, 1, 1, 0, 20, 0, 0, 0, 162, 0, 161, 0], - [1, 0, 123, 1, 0, 20, 124, 0, 121, 0, 122, 0, 126], - [1, 0, 0, 1, 88, 20, 86, 0, 0, 0, 0, 0, 0], + [ 7,121, 8,152, 9,120, 10,352,176,175,122,175,176], + [ 0, 0, 0, 0, 0, 0, 0,352,175,174, 0,172,175], + [352,352,352,352,111,352,352,352, 0, 0,229, 0, 0], + [ 43, 33, 44,151, 0, 0, 0,352,175,171, 0,173,175], + [ 21, 22, 21,151, 0, 0, 0,352,176,175, 0,175,176], + [351,245,351,351, 0, 87, 0,352,352,352, 85,353,353], + [ 0,246, 0,351, 0, 0, 0,352,152,221, 0,221,353], + [246, 0,246,351, 0, 0, 0,111, 85, 0, 0, 0,353], + [351,246,351,351, 0,353,353,353,353,353,353,353,353], + [ 0, 0, 0, 0, 0, 0, 0,174, 0, 0,173, 0, 0], + [ 1, 1, 1, 1, 0, 20, 0, 0, 0,172, 0,171, 0], + [ 1, 0,113, 1, 0, 20,114, 0,111, 0,112, 0,116], + [ 1, 0, 0, 1, 88, 20, 86, 0, 0, 0, 0, 0, 0] ], "firstArrive": [ // 第一次到该楼层触发的事件 diff --git a/project/floors/sample2.js b/project/floors/sample2.js index 6f6e5f7b..8467f162 100644 --- a/project/floors/sample2.js +++ b/project/floors/sample2.js @@ -12,22 +12,22 @@ main.floors.sample2 = "images": [], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 "color": [255,0,0,0.3], // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 "weather": ["rain",10], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 - "bgm": "qianjin.mid", // 到达该层后默认播放的BGM。本项可忽略。 + "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 "item_ratio": 1, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 - [5, 5, 5, 5, 5, 5, 87, 5, 5, 5, 5, 5, 5], - [5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], - [5, 4, 4, 4, 4, 1, 85, 1, 4, 4, 4, 4, 5], - [5, 4, 4, 4, 247, 1, 247, 1, 247, 4, 4, 4, 5], - [5, 4, 4, 4, 1, 247, 247, 247, 1, 4, 4, 4, 5], - [5, 4, 4, 4, 1, 247, 30, 247, 1, 4, 4, 4, 5], - [5, 4, 4, 4, 247, 1, 124, 1, 247, 4, 4, 4, 5], - [5, 4, 4, 4, 4, 1, 123, 1, 4, 4, 4, 4, 5], - [5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], - [5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], - [5, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 5], - [5, 4, 4, 4, 4, 4, 85, 4, 4, 4, 4, 4, 5], - [5, 5, 5, 5, 5, 5, 88, 5, 5, 5, 5, 5, 5], + [ 5, 5, 5, 5, 5, 5, 87, 5, 5, 5, 5, 5, 5], + [ 5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], + [ 5, 4, 4, 4, 4, 1, 85, 1, 4, 4, 4, 4, 5], + [ 5, 4, 4, 4,247, 1,247, 1,247, 4, 4, 4, 5], + [ 5, 4, 4, 4, 1,247,247,247, 1, 4, 4, 4, 5], + [ 5, 4, 4, 4, 1,247, 30,247, 1, 4, 4, 4, 5], + [ 5, 4, 4, 4,247, 1,114, 1,247, 4, 4, 4, 5], + [ 5, 4, 4, 4, 4, 1,113, 1, 4, 4, 4, 4, 5], + [ 5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], + [ 5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], + [ 5, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 5], + [ 5, 4, 4, 4, 4, 4, 85, 4, 4, 4, 4, 4, 5], + [ 5, 5, 5, 5, 5, 5, 88, 5, 5, 5, 5, 5, 5] ], "firstArrive": [ // 第一次到该楼层触发的事件 "\t[实战!]本楼将尝试复刻《宿命的旋律》40F剧情。" diff --git a/project/functions.js b/project/functions.js index 4b1ab6f4..ad3567e3 100644 --- a/project/functions.js +++ b/project/functions.js @@ -59,7 +59,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.removeGlobalAnimate(0,0,true); core.clearMap('all'); // 清空全地图 core.drawText([ - "\t[恭喜通关]你的分数是${status:hp}。" + "\t[" + (reason||"恭喜通关") + "]你的分数是${status:hp}。" ], function () { core.events.gameOver(reason||'', replaying); }) @@ -73,7 +73,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.stopReplay(); core.waitHeroToStop(function() { core.drawText([ - "\t[结局1]你死了。\n如题。" + "\t["+(reason||"结局1")+"]你死了。\n如题。" ], function () { core.events.gameOver(null, replaying); }); @@ -116,8 +116,11 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var enemy = core.material.enemys[enemyId]; + var damage = core.enemys.getDamage(enemyId); + if (damage == null) damage = core.status.hero.hp+1; + // 扣减体力值 - core.status.hero.hp -= core.enemys.getDamage(enemyId); + core.status.hero.hp -= damage; if (core.status.hero.hp<=0) { core.status.hero.hp=0; core.updateStatusBar(); @@ -343,18 +346,52 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = this.useEquipment = function (itemId) { // 使用装备 if (itemId.indexOf("sword")==0) { var now=core.getFlag('sword', 'sword0'); // 当前装备剑的ID - core.status.hero.atk -= core.values[now]; + + if (typeof core.values[now] == 'number') { + core.status.hero.atk -= core.values[now]; + } + else { + core.status.hero.atk -= core.values[now].atk || 0; + core.status.hero.def -= core.values[now].def || 0; + core.status.hero.mdef -= core.values[now].mdef || 0; + } + + if (typeof core.values[itemId] == 'number') { + core.status.hero.atk += core.values[itemId]; + } + else { + core.status.hero.atk -= core.values[itemId].atk || 0; + core.status.hero.def -= core.values[itemId].def || 0; + core.status.hero.mdef -= core.values[itemId].mdef || 0; + } + core.setItem(now, 1); - core.status.hero.atk += core.values[itemId]; core.setItem(itemId, 0); core.setFlag('sword', itemId); core.drawTip("已装备"+core.material.items[itemId].name); } if (itemId.indexOf("shield")==0) { var now=core.getFlag('shield', 'shield0'); - core.status.hero.def -= core.values[now]; + + if (typeof core.values[now] == 'number') { + core.status.hero.def -= core.values[now]; + } + else { + core.status.hero.atk -= core.values[now].atk || 0; + core.status.hero.def -= core.values[now].def || 0; + core.status.hero.mdef -= core.values[now].mdef || 0; + } + + if (typeof core.values[itemId] == 'number') { + core.status.hero.def += core.values[itemId]; + } + else { + core.status.hero.atk -= core.values[itemId].atk || 0; + core.status.hero.def -= core.values[itemId].def || 0; + core.status.hero.mdef -= core.values[itemId].mdef || 0; + } + core.setItem(now, 1); - core.status.hero.def += core.values[itemId]; core.setItem(itemId, 0); core.setFlag('shield', itemId); core.drawTip("已装备"+core.material.items[itemId].name); diff --git a/project/icons.js b/project/icons.js index 21c181d2..cfc26a35 100644 --- a/project/icons.js +++ b/project/icons.js @@ -99,7 +99,23 @@ icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 = 'wood': 8, 'pinkShop': 9, 'blueShop': 10, - 'princess': 11 + 'princess': 11, + 'wlt': 12, + 'wt': 13, + 'wrt': 14, + 'wl': 15, + 'wc': 16, + 'wr': 17, + 'wlb': 18, + 'wrb': 19, + 'dlt': 20, + 'dt': 21, + 'drt': 22, + 'dl': 23, + 'dc': 24, + 'dr': 25, + 'dlb': 26, + 'drb': 27, }, 'npc48': { 'npc0': 0, diff --git a/project/images/enemys.png b/project/images/enemys.png index 6797ae59..01d4396f 100644 Binary files a/project/images/enemys.png and b/project/images/enemys.png differ diff --git a/project/images/npcs.png b/project/images/npcs.png index 3df2b21d..a2830bc9 100644 Binary files a/project/images/npcs.png and b/project/images/npcs.png differ diff --git a/project/maps.js b/project/maps.js index 027b4302..45641367 100644 --- a/project/maps.js +++ b/project/maps.js @@ -23,10 +23,10 @@ maps_90f36752_8815_4be8_b32b_d7fad1d0542e = // Autotile '20':{'cls': 'autotile', 'id': 'autotile', 'noPass': true}, // autotile - // 更多的autotile从151到160等,只要不和现有的数字冲突即可 - '151':{'cls': 'autotile', 'id': 'autotile1', 'noPass': true}, - '152':{'cls': 'autotile', 'id': 'autotile2', 'noPass': true}, - '153':{'cls': 'autotile', 'id': 'autotile3', 'noPass': true}, + // 更多的autotile只要不和现有的数字冲突即可 + '351':{'cls': 'autotile', 'id': 'autotile1', 'noPass': true}, + '352':{'cls': 'autotile', 'id': 'autotile2', 'noPass': true}, + '353':{'cls': 'autotile', 'id': 'autotile3', 'noPass': true}, ////////////////////////// 物品部分 ////////////////////////// @@ -99,40 +99,54 @@ maps_90f36752_8815_4be8_b32b_d7fad1d0542e = ////////////////////////// NPC部分 ////////////////////////// - // 121-150 NPC - '121':{'cls': 'npcs', 'id': 'man'}, - '122':{'cls': 'npcs', 'id': 'woman'}, - '123':{'cls': 'npcs', 'id': 'thief'}, - '124':{'cls': 'npcs', 'id': 'fairy'}, - '125':{'cls': 'npcs', 'id': 'magician'}, - '126':{'cls': 'npcs', 'id': 'womanMagician'}, - '127':{'cls': 'npcs', 'id': 'oldMan'}, - '128':{'cls': 'npcs', 'id': 'child'}, - '129':{'cls': 'npcs', 'id': 'wood'}, - '130':{'cls': 'npcs', 'id': 'pinkShop'}, - '131':{'cls': 'npcs', 'id': 'blueShop'}, - '132':{'cls': 'npcs', 'id': 'princess'}, - '133':{'cls': 'npc48', 'id': 'npc0'}, - '134':{'cls': 'npc48', 'id': 'npc1'}, - '135':{'cls': 'npc48', 'id': 'npc2'}, - '136':{'cls': 'npc48', 'id': 'npc3'}, - '137':{'cls': 'npc48', 'id': 'npc4'}, - + // 111-150 NPC + '111':{'cls': 'npcs', 'id': 'man'}, + '112':{'cls': 'npcs', 'id': 'woman'}, + '113':{'cls': 'npcs', 'id': 'thief'}, + '114':{'cls': 'npcs', 'id': 'fairy'}, + '115':{'cls': 'npcs', 'id': 'magician'}, + '116':{'cls': 'npcs', 'id': 'womanMagician'}, + '117':{'cls': 'npcs', 'id': 'oldMan'}, + '118':{'cls': 'npcs', 'id': 'child'}, + '119':{'cls': 'npcs', 'id': 'wood'}, + '120':{'cls': 'npcs', 'id': 'pinkShop'}, + '121':{'cls': 'npcs', 'id': 'blueShop'}, + '122':{'cls': 'npcs', 'id': 'princess'}, + '123': {'cls': 'npcs', 'id': 'wlt'}, + '124': {'cls': 'npcs', 'id': 'wt'}, + '125': {'cls': 'npcs', 'id': 'wrt'}, + '126': {'cls': 'npcs', 'id': 'wl'}, + '127': {'cls': 'npcs', 'id': 'wc'}, + '128': {'cls': 'npcs', 'id': 'wr'}, + '129': {'cls': 'npcs', 'id': 'wlb'}, + '130': {'cls': 'npcs', 'id': 'wrb'}, + '131': {'cls': 'npcs', 'id': 'dlt'}, + '132': {'cls': 'npcs', 'id': 'dt'}, + '133': {'cls': 'npcs', 'id': 'drt'}, + '134': {'cls': 'npcs', 'id': 'dl'}, + '135': {'cls': 'npcs', 'id': 'dc'}, + '136': {'cls': 'npcs', 'id': 'dr'}, + '137': {'cls': 'npcs', 'id': 'dlb'}, + '138': {'cls': 'npcs', 'id': 'drb'}, + '139': {'cls': 'npc48', 'id': 'npc0'}, + '140': {'cls': 'npc48', 'id': 'npc1'}, + '141': {'cls': 'npc48', 'id': 'npc2'}, + '142': {'cls': 'npc48', 'id': 'npc3'}, + '143': {'cls': 'npc48', 'id': 'npc4'}, ////////////////////////// 其他部分 ////////////////////////// - // 161-200 其他(单向箭头、灯、箱子等等) - '161':{'cls': 'terrains', 'id': 'arrowUp', 'noPass': false}, // 单向上箭头 - '162':{'cls': 'terrains', 'id': 'arrowDown', 'noPass': false}, // 单向下箭头 - '163':{'cls': 'terrains', 'id': 'arrowLeft', 'noPass': false}, // 单向左箭头 - '164':{'cls': 'terrains', 'id': 'arrowRight', 'noPass': false}, // 单向右箭头 - '165':{'cls': 'terrains', 'id': 'light', 'trigger': 'changeLight', 'noPass': false}, // 灯 - '166':{'cls': 'terrains', 'id': 'darkLight', 'noPass': true}, // 暗灯 - '167':{'cls': 'terrains', 'id': 'ski', 'trigger': 'ski', 'noPass': false}, // 滑冰 - '168':{'cls': 'terrains', 'id': 'flower', 'noPass': false}, // 花 - '169':{'cls': 'terrains', 'id': 'box', 'trigger': 'pushBox', 'noPass': true}, // 箱子 - '170':{'cls': 'terrains', 'id': 'boxed', 'trigger': 'pushBox', 'noPass': true}, // 完成的箱子 - + // 171-200 其他(单向箭头、灯、箱子等等) + '171':{'cls': 'terrains', 'id': 'arrowUp', 'noPass': false}, // 单向上箭头 + '172':{'cls': 'terrains', 'id': 'arrowDown', 'noPass': false}, // 单向下箭头 + '173':{'cls': 'terrains', 'id': 'arrowLeft', 'noPass': false}, // 单向左箭头 + '174':{'cls': 'terrains', 'id': 'arrowRight', 'noPass': false}, // 单向右箭头 + '175':{'cls': 'terrains', 'id': 'light', 'trigger': 'changeLight', 'noPass': false}, // 灯 + '176':{'cls': 'terrains', 'id': 'darkLight', 'noPass': true}, // 暗灯 + '177':{'cls': 'terrains', 'id': 'ski', 'trigger': 'ski', 'noPass': false}, // 滑冰 + '178':{'cls': 'terrains', 'id': 'flower', 'noPass': false}, // 花 + '179':{'cls': 'terrains', 'id': 'box', 'trigger': 'pushBox', 'noPass': true}, // 箱子 + '180':{'cls': 'terrains', 'id': 'boxed', 'trigger': 'pushBox', 'noPass': true}, // 完成的箱子 ////////////////////////// 怪物部分 ////////////////////////// diff --git a/project/sounds/058-Slow01.mid b/project/sounds/058-Slow01.mid deleted file mode 100644 index 05ce9228..00000000 Binary files a/project/sounds/058-Slow01.mid and /dev/null differ diff --git a/project/sounds/qianjin.mid b/project/sounds/qianjin.mid deleted file mode 100644 index b4236a96..00000000 Binary files a/project/sounds/qianjin.mid and /dev/null differ diff --git a/project/sounds/star.mid b/project/sounds/star.mid deleted file mode 100644 index cc78e590..00000000 Binary files a/project/sounds/star.mid and /dev/null differ diff --git a/styles.css b/styles.css index 913d64e0..511f28c1 100644 --- a/styles.css +++ b/styles.css @@ -21,7 +21,7 @@ position: fixed; top: 10px; left: 10px; - z-index: 15; + z-index: 320; } #startPanel { @@ -32,7 +32,7 @@ left: 0; background-color: #fff; overflow: hidden; - z-index: 12; + z-index: 250; } #startTop { @@ -42,7 +42,7 @@ top: 0; left: 0; background-color: #000; - z-index: 14; + z-index: 300; } #startTopProgressBar { @@ -77,12 +77,12 @@ height: 100%; width: auto; transform:translate(-50%,-50%); - z-index: 12; + z-index: 210; } #startLogo { position: absolute; - z-index: 12; + z-index: 240; left: 0; right: 0; margin-left: auto; @@ -95,7 +95,7 @@ #startTitle { position: absolute; - z-index: 13; + z-index: 230; } #startButtonGroup { @@ -106,7 +106,7 @@ background-color: #000; opacity: 0.85; display: none; - z-index: 12; + z-index: 220; bottom: 0; margin-bottom: 7%; } @@ -142,7 +142,7 @@ display: none; color: #fff; background-color: #000; - z-index: 11; + z-index: 180; } #logoLabel { @@ -170,7 +170,7 @@ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; background: url(project/images/ground.png) repeat; - z-index: 9; + z-index: 160; display: none; } #statusBar .status{ @@ -199,7 +199,7 @@ #toolBar { position: absolute; background: url(project/images/ground.png) repeat; - z-index: 8; + z-index: 150; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -233,47 +233,59 @@ span#poison, span#weak, span#curse { -webkit-box-sizing: border-box; } +#gif { + z-index: 20; + position: absolute; + overflow: hidden; +} + +#gif2 { + z-index: 90; + position: absolute; + overflow: hidden; +} + #curtain { - z-index: 8; + z-index: 100; position: absolute; opacity: 0; background: #000000; } #bg { - z-index: 1; + z-index: 10; } #event { - z-index: 2; + z-index: 30; } #hero { - z-index: 3; + z-index: 40; } #event2 { - z-index: 4; + z-index: 50; } #fg { - z-index: 5; + z-index: 60; } #animate { - z-index: 6; + z-index: 70; } #weather { - z-index: 7; + z-index: 80; } #ui { - z-index: 9; + z-index: 110; } #data { - z-index: 10; + z-index: 120; } .clearfix:before, diff --git a/常用工具/JS代码压缩工具.exe b/常用工具/JS代码压缩工具.exe index 787fd7ea..318afa28 100644 Binary files a/常用工具/JS代码压缩工具.exe and b/常用工具/JS代码压缩工具.exe differ diff --git a/更新说明.txt b/更新说明.txt index 10d8a0d8..b51b91de 100644 --- a/更新说明.txt +++ b/更新说明.txt @@ -1,4 +1,20 @@ -HTML5魔塔样板V2.0.1 +HTML5魔塔样板V2.0.2 + +编辑器添加新建和删除按钮;地图自动保存 √ +录像支持倒退(录像播放中每50步自动存档,最多存20个) +Gif支持:可以作为楼层背景图或者使用显示动图事件 √ +图片显示增加淡入淡出效果 √ +APP端也能下载录像 +地图临界显伤 √ +单个存档清理 √ +大数据魔塔的支持(临界计算等) √ +进一步对JS文件进行压缩 √ +修复有时候无法输入ID的问题 √ +其他细节优化 + +----------------------------------------------------------------------- + +HTML5魔塔样板V2.0.1 道具使用效果的进一步分离 支持插件编写,用户可以根据需求来写插件了