├── .gitignore ├── .nojekyll ├── .vscode └── tasks.json ├── LICENSE ├── README.md ├── codemirror ├── active-line.js ├── annotatescrollbar.js ├── codemirror.min.css ├── codemirror.min.js ├── dialog.css ├── dialog.js ├── matchesonscrollbar.css ├── matchesonscrollbar.js ├── qb-lang.js ├── search.js ├── searchcursor.js ├── themes │ ├── mdn-like.css │ ├── qb45.css │ ├── qb64-vscode.css │ ├── qbjs.css │ ├── vscode-dark.css │ └── win-classic.css └── vim.js ├── dosvga.ttf ├── export ├── auto.html ├── fullscreen-hover.svg ├── fullscreen.svg ├── logo.png ├── play.html └── qbjs.css ├── favicon.ico ├── githelp.js ├── gx ├── __gx_font_default.png ├── __gx_font_default_black.png └── gx.js ├── img ├── about-hover.svg ├── about.svg ├── console-hide-hover.svg ├── console-hide.svg ├── console-show-hover.svg ├── console-show.svg ├── delete-hover.svg ├── delete.svg ├── file.png ├── file.svg ├── folder.png ├── folder.svg ├── fullscreen.png ├── gx-logo.png ├── methods-hover.svg ├── methods.svg ├── new-folder-hover.svg ├── new-folder.svg ├── open-hover.svg ├── open.svg ├── play.png ├── refresh-hover.svg ├── refresh.png ├── refresh.svg ├── run-hover.svg ├── run.svg ├── save-hover.svg ├── save.svg ├── settings-hover.svg ├── settings.svg ├── share-hover.svg ├── share.svg ├── slide-left-hover.svg ├── slide-left.svg ├── slide-right-hover.svg ├── slide-right.svg ├── stop-hover.svg ├── stop.svg ├── upload-hover.svg └── upload.svg ├── index.html ├── lib ├── graphics │ └── 2d.bas ├── io │ └── fs.bas └── web │ ├── console.bas │ ├── dom.bas │ └── storage.bas ├── logo-256.png ├── logo.png ├── manifest.json ├── play.png ├── qb-console.js ├── qb.js ├── qb2js.js ├── qbc.js ├── qbjs-ide.css ├── qbjs-ide.js ├── qbjs.woff2 ├── samples ├── apps │ ├── new-message.ogg │ └── paint.bas ├── games │ ├── banner-for-bplus.zip │ ├── banner.zip │ ├── banner2.zip │ ├── banner3.zip │ ├── fall-runner.zip │ └── trfbird.bas ├── include │ ├── caman.bas │ ├── gif │ │ ├── GIFEncoder.js │ │ ├── LZWEncoder.js │ │ ├── NeuQuant.js │ │ └── animated.bas │ ├── maths.bas │ └── test.bas └── project │ ├── animated-gif.zip │ ├── bplus-banner-builder.zip │ ├── cayman.zip │ ├── custom-font.zip │ ├── overworld.zip │ ├── simple.zip │ └── sleighless.zip ├── service-worker.js ├── tools ├── qb2js.bas ├── qb2js.bi └── webserver.bas ├── util ├── jszip.min.js ├── lzutf8.js ├── pako.2.1.0.min.js ├── shorty.min.js ├── showdown.min.js └── showdown.min.js.map └── vfs.js /.gitignore: -------------------------------------------------------------------------------- 1 | tools/webserver.exe 2 | tools/webserver 3 | tools/qb2js.exe 4 | tools/qb2js 5 | qbjs.zip 6 | .vscode/launch.json 7 | .vscode/settings.json 8 | .vscode/tasks.json 9 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- 1 | gx/__gx_font_default_black.png 2 | gx/__gx_font_default.png -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "type": "shell", 7 | "command": "${config:qb64.installPath}/qb64.exe", 8 | "args": [ 9 | "-c", 10 | "'${fileDirname}/${fileBasename}'", 11 | "-x", 12 | "-o", 13 | "'${fileDirname}/${fileBasenameNoExtension}.exe'" 14 | ], 15 | "linux": { 16 | "command": "${config:qb64.installPath}/qb64", 17 | "args": [ 18 | "-c", 19 | "'${fileDirname}/${fileBasename}'", 20 | "-x", 21 | "-o", 22 | "'${fileDirname}/${fileBasenameNoExtension}'" 23 | ] 24 | }, 25 | "osx": { 26 | "command": "${config:qb64.installPath}/qb64", 27 | "args": [ 28 | "-c", 29 | "'{fileDirname}/${fileBasename}'", 30 | "-x", 31 | "-o", 32 | "'${fileDirname}/${fileBasenameNoExtension}'" 33 | ] 34 | }, 35 | "group": { 36 | "kind": "build", 37 | "isDefault": true 38 | }, 39 | "presentation": { 40 | "reveal": "always", 41 | "panel": "new" 42 | } 43 | }, 44 | { 45 | "label": "Clean QB64", 46 | "type": "shell", 47 | "options": { 48 | "cwd": "${config:qb64.installPath}/internal", 49 | }, 50 | "command": "${config:qb64.installPath}/internal/clean.bat", 51 | "linux": { 52 | "command":"${config:qb64.installPath}/internal/clean.sh", 53 | }, 54 | "osx": { 55 | "command":"${config:qb64.installPath}/internal/clean.sh", 56 | }, 57 | "group": { 58 | "kind": "build", 59 | "isDefault": false 60 | }, 61 | "presentation": { 62 | "reveal": "always", 63 | "panel": "new" 64 | } 65 | }, 66 | { 67 | "label": "Exe Compact", 68 | "type": "shell", 69 | "windows": { 70 | "command": "compact", 71 | "args": [ 72 | "/c", 73 | "/exe:lzx", 74 | "\"${fileDirname}\\${fileBasenameNoExtension}.exe\"" 75 | ] 76 | }, 77 | "linux": { 78 | "command": "upx", 79 | "args": [ 80 | "${fileDirname}/${fileBasenameNoExtension}.exe" 81 | ] 82 | }, 83 | "osx": { 84 | "command": "upx", 85 | "args": [ 86 | "${fileDirname}/${fileBasenameNoExtension}.exe" 87 | ] 88 | }, 89 | "group": { 90 | "kind": "build", 91 | "isDefault": false 92 | }, 93 | "presentation": { 94 | "reveal": "always", 95 | "panel": "new" 96 | } 97 | } 98 | ] 99 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 boxgaming 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About QBJS 2 | 3 | QBJS is an implementation of the Basic programming language for the web, with multimedia support and easy sharing of programs. It aims to be compatible with QB64, which in turn implements the same dialect as the classic QBasic. 4 | 5 | The project is in active development as of 30 March 2022. It can be tried online on itch.io; documentation and releases are hosted on GitHub. 6 | 7 | Support for browser APIs is built-in as of version 0.3.0-beta; a game engine is included separately. 8 | -------------------------------------------------------------------------------- /codemirror/active-line.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function(CodeMirror) { 12 | "use strict"; 13 | var WRAP_CLASS = "CodeMirror-activeline"; 14 | var BACK_CLASS = "CodeMirror-activeline-background"; 15 | var GUTT_CLASS = "CodeMirror-activeline-gutter"; 16 | 17 | CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { 18 | var prev = old == CodeMirror.Init ? false : old; 19 | if (val == prev) return 20 | if (prev) { 21 | cm.off("beforeSelectionChange", selectionChange); 22 | clearActiveLines(cm); 23 | delete cm.state.activeLines; 24 | } 25 | if (val) { 26 | cm.state.activeLines = []; 27 | updateActiveLines(cm, cm.listSelections()); 28 | cm.on("beforeSelectionChange", selectionChange); 29 | } 30 | }); 31 | 32 | function clearActiveLines(cm) { 33 | for (var i = 0; i < cm.state.activeLines.length; i++) { 34 | cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); 35 | cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); 36 | cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); 37 | } 38 | } 39 | 40 | function sameArray(a, b) { 41 | if (a.length != b.length) return false; 42 | for (var i = 0; i < a.length; i++) 43 | if (a[i] != b[i]) return false; 44 | return true; 45 | } 46 | 47 | function updateActiveLines(cm, ranges) { 48 | var active = []; 49 | for (var i = 0; i < ranges.length; i++) { 50 | var range = ranges[i]; 51 | var option = cm.getOption("styleActiveLine"); 52 | if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) 53 | continue 54 | var line = cm.getLineHandleVisualStart(range.head.line); 55 | if (active[active.length - 1] != line) active.push(line); 56 | } 57 | if (sameArray(cm.state.activeLines, active)) return; 58 | cm.operation(function() { 59 | clearActiveLines(cm); 60 | for (var i = 0; i < active.length; i++) { 61 | cm.addLineClass(active[i], "wrap", WRAP_CLASS); 62 | cm.addLineClass(active[i], "background", BACK_CLASS); 63 | cm.addLineClass(active[i], "gutter", GUTT_CLASS); 64 | } 65 | cm.state.activeLines = active; 66 | }); 67 | } 68 | 69 | function selectionChange(cm, sel) { 70 | updateActiveLines(cm, sel.ranges); 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /codemirror/annotatescrollbar.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function(CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.defineExtension("annotateScrollbar", function(options) { 15 | if (typeof options == "string") options = {className: options}; 16 | return new Annotation(this, options); 17 | }); 18 | 19 | CodeMirror.defineOption("scrollButtonHeight", 0); 20 | 21 | function Annotation(cm, options) { 22 | this.cm = cm; 23 | this.options = options; 24 | this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight"); 25 | this.annotations = []; 26 | this.doRedraw = this.doUpdate = null; 27 | this.div = cm.getWrapperElement().appendChild(document.createElement("div")); 28 | this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none"; 29 | this.computeScale(); 30 | 31 | function scheduleRedraw(delay) { 32 | clearTimeout(self.doRedraw); 33 | self.doRedraw = setTimeout(function() { self.redraw(); }, delay); 34 | } 35 | 36 | var self = this; 37 | cm.on("refresh", this.resizeHandler = function() { 38 | clearTimeout(self.doUpdate); 39 | self.doUpdate = setTimeout(function() { 40 | if (self.computeScale()) scheduleRedraw(20); 41 | }, 100); 42 | }); 43 | cm.on("markerAdded", this.resizeHandler); 44 | cm.on("markerCleared", this.resizeHandler); 45 | if (options.listenForChanges !== false) 46 | cm.on("changes", this.changeHandler = function() { 47 | scheduleRedraw(250); 48 | }); 49 | } 50 | 51 | Annotation.prototype.computeScale = function() { 52 | var cm = this.cm; 53 | var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) / 54 | cm.getScrollerElement().scrollHeight 55 | if (hScale != this.hScale) { 56 | this.hScale = hScale; 57 | return true; 58 | } 59 | }; 60 | 61 | Annotation.prototype.update = function(annotations) { 62 | this.annotations = annotations; 63 | this.redraw(); 64 | }; 65 | 66 | Annotation.prototype.redraw = function(compute) { 67 | if (compute !== false) this.computeScale(); 68 | var cm = this.cm, hScale = this.hScale; 69 | 70 | var frag = document.createDocumentFragment(), anns = this.annotations; 71 | 72 | var wrapping = cm.getOption("lineWrapping"); 73 | var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; 74 | var curLine = null, curLineObj = null; 75 | 76 | function getY(pos, top) { 77 | if (curLine != pos.line) { 78 | curLine = pos.line 79 | curLineObj = cm.getLineHandle(pos.line) 80 | var visual = cm.getLineHandleVisualStart(curLineObj) 81 | if (visual != curLineObj) { 82 | curLine = cm.getLineNumber(visual) 83 | curLineObj = visual 84 | } 85 | } 86 | if ((curLineObj.widgets && curLineObj.widgets.length) || 87 | (wrapping && curLineObj.height > singleLineH)) 88 | return cm.charCoords(pos, "local")[top ? "top" : "bottom"]; 89 | var topY = cm.heightAtLine(curLineObj, "local"); 90 | return topY + (top ? 0 : curLineObj.height); 91 | } 92 | 93 | var lastLine = cm.lastLine() 94 | if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { 95 | var ann = anns[i]; 96 | if (ann.to.line > lastLine) continue; 97 | var top = nextTop || getY(ann.from, true) * hScale; 98 | var bottom = getY(ann.to, false) * hScale; 99 | while (i < anns.length - 1) { 100 | if (anns[i + 1].to.line > lastLine) break; 101 | nextTop = getY(anns[i + 1].from, true) * hScale; 102 | if (nextTop > bottom + .9) break; 103 | ann = anns[++i]; 104 | bottom = getY(ann.to, false) * hScale; 105 | } 106 | if (bottom == top) continue; 107 | var height = Math.max(bottom - top, 3); 108 | 109 | var elt = frag.appendChild(document.createElement("div")); 110 | elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " 111 | + (top + this.buttonHeight) + "px; height: " + height + "px"; 112 | elt.className = this.options.className; 113 | if (ann.id) { 114 | elt.setAttribute("annotation-id", ann.id); 115 | } 116 | } 117 | this.div.textContent = ""; 118 | this.div.appendChild(frag); 119 | }; 120 | 121 | Annotation.prototype.clear = function() { 122 | this.cm.off("refresh", this.resizeHandler); 123 | this.cm.off("markerAdded", this.resizeHandler); 124 | this.cm.off("markerCleared", this.resizeHandler); 125 | if (this.changeHandler) this.cm.off("changes", this.changeHandler); 126 | this.div.parentNode.removeChild(this.div); 127 | }; 128 | }); 129 | -------------------------------------------------------------------------------- /codemirror/codemirror.min.css: -------------------------------------------------------------------------------- 1 | .CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.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}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.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-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{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:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}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}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{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}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;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.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{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}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{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}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0} 2 | /*# sourceMappingURL=codemirror.min.css.map */ -------------------------------------------------------------------------------- /codemirror/dialog.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-dialog { 2 | position: absolute; 3 | left: 0; right: 0; 4 | background: inherit; 5 | z-index: 15; 6 | padding: .1em .8em; 7 | overflow: hidden; 8 | color: inherit; 9 | } 10 | 11 | .CodeMirror-dialog-top { 12 | border-bottom: 1px solid #eee; 13 | top: 0; 14 | } 15 | 16 | .CodeMirror-dialog-bottom { 17 | border-top: 1px solid #eee; 18 | bottom: 0; 19 | } 20 | 21 | .CodeMirror-dialog input { 22 | border: none; 23 | outline: none; 24 | background: transparent; 25 | width: 20em; 26 | color: inherit; 27 | font-family: monospace; 28 | } 29 | 30 | .CodeMirror-dialog button { 31 | font-size: 70%; 32 | } 33 | -------------------------------------------------------------------------------- /codemirror/dialog.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | // Open simple dialogs on top of an editor. Relies on dialog.css. 5 | 6 | (function(mod) { 7 | if (typeof exports == "object" && typeof module == "object") // CommonJS 8 | mod(require("../../lib/codemirror")); 9 | else if (typeof define == "function" && define.amd) // AMD 10 | define(["../../lib/codemirror"], mod); 11 | else // Plain browser env 12 | mod(CodeMirror); 13 | })(function(CodeMirror) { 14 | function dialogDiv(cm, template, bottom) { 15 | var wrap = cm.getWrapperElement(); 16 | var dialog; 17 | dialog = wrap.appendChild(document.createElement("div")); 18 | if (bottom) 19 | dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; 20 | else 21 | dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; 22 | 23 | if (typeof template == "string") { 24 | dialog.innerHTML = template; 25 | } else { // Assuming it's a detached DOM element. 26 | dialog.appendChild(template); 27 | } 28 | CodeMirror.addClass(wrap, 'dialog-opened'); 29 | return dialog; 30 | } 31 | 32 | function closeNotification(cm, newVal) { 33 | if (cm.state.currentNotificationClose) 34 | cm.state.currentNotificationClose(); 35 | cm.state.currentNotificationClose = newVal; 36 | } 37 | 38 | CodeMirror.defineExtension("openDialog", function(template, callback, options) { 39 | if (!options) options = {}; 40 | 41 | closeNotification(this, null); 42 | 43 | var dialog = dialogDiv(this, template, options.bottom); 44 | var closed = false, me = this; 45 | function close(newVal) { 46 | if (typeof newVal == 'string') { 47 | inp.value = newVal; 48 | } else { 49 | if (closed) return; 50 | closed = true; 51 | CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); 52 | dialog.parentNode.removeChild(dialog); 53 | me.focus(); 54 | 55 | if (options.onClose) options.onClose(dialog); 56 | } 57 | } 58 | 59 | var inp = dialog.getElementsByTagName("input")[0], button; 60 | if (inp) { 61 | inp.focus(); 62 | 63 | if (options.value) { 64 | inp.value = options.value; 65 | if (options.selectValueOnOpen !== false) { 66 | inp.select(); 67 | } 68 | } 69 | 70 | if (options.onInput) 71 | CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); 72 | if (options.onKeyUp) 73 | CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); 74 | 75 | CodeMirror.on(inp, "keydown", function(e) { 76 | if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } 77 | if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { 78 | inp.blur(); 79 | CodeMirror.e_stop(e); 80 | close(); 81 | } 82 | if (e.keyCode == 13) callback(inp.value, e); 83 | }); 84 | 85 | if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) { 86 | if (evt.relatedTarget !== null) close(); 87 | }); 88 | } else if (button = dialog.getElementsByTagName("button")[0]) { 89 | CodeMirror.on(button, "click", function() { 90 | close(); 91 | me.focus(); 92 | }); 93 | 94 | if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); 95 | 96 | button.focus(); 97 | } 98 | return close; 99 | }); 100 | 101 | CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { 102 | closeNotification(this, null); 103 | var dialog = dialogDiv(this, template, options && options.bottom); 104 | var buttons = dialog.getElementsByTagName("button"); 105 | var closed = false, me = this, blurring = 1; 106 | function close() { 107 | if (closed) return; 108 | closed = true; 109 | CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); 110 | dialog.parentNode.removeChild(dialog); 111 | me.focus(); 112 | } 113 | buttons[0].focus(); 114 | for (var i = 0; i < buttons.length; ++i) { 115 | var b = buttons[i]; 116 | (function(callback) { 117 | CodeMirror.on(b, "click", function(e) { 118 | CodeMirror.e_preventDefault(e); 119 | close(); 120 | if (callback) callback(me); 121 | }); 122 | })(callbacks[i]); 123 | CodeMirror.on(b, "blur", function() { 124 | --blurring; 125 | setTimeout(function() { if (blurring <= 0) close(); }, 200); 126 | }); 127 | CodeMirror.on(b, "focus", function() { ++blurring; }); 128 | } 129 | }); 130 | 131 | /* 132 | * openNotification 133 | * Opens a notification, that can be closed with an optional timer 134 | * (default 5000ms timer) and always closes on click. 135 | * 136 | * If a notification is opened while another is opened, it will close the 137 | * currently opened one and open the new one immediately. 138 | */ 139 | CodeMirror.defineExtension("openNotification", function(template, options) { 140 | closeNotification(this, close); 141 | var dialog = dialogDiv(this, template, options && options.bottom); 142 | var closed = false, doneTimer; 143 | var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; 144 | 145 | function close() { 146 | if (closed) return; 147 | closed = true; 148 | clearTimeout(doneTimer); 149 | CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); 150 | dialog.parentNode.removeChild(dialog); 151 | } 152 | 153 | CodeMirror.on(dialog, 'click', function(e) { 154 | CodeMirror.e_preventDefault(e); 155 | close(); 156 | }); 157 | 158 | if (duration) 159 | doneTimer = setTimeout(close, duration); 160 | 161 | return close; 162 | }); 163 | }); 164 | -------------------------------------------------------------------------------- /codemirror/matchesonscrollbar.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-search-match { 2 | background: gold; 3 | border-top: 1px solid orange; 4 | border-bottom: 1px solid orange; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | opacity: .5; 8 | } 9 | -------------------------------------------------------------------------------- /codemirror/matchesonscrollbar.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function(CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { 15 | if (typeof options == "string") options = {className: options}; 16 | if (!options) options = {}; 17 | return new SearchAnnotation(this, query, caseFold, options); 18 | }); 19 | 20 | function SearchAnnotation(cm, query, caseFold, options) { 21 | this.cm = cm; 22 | this.options = options; 23 | var annotateOptions = {listenForChanges: false}; 24 | for (var prop in options) annotateOptions[prop] = options[prop]; 25 | if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; 26 | this.annotation = cm.annotateScrollbar(annotateOptions); 27 | this.query = query; 28 | this.caseFold = caseFold; 29 | this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; 30 | this.matches = []; 31 | this.update = null; 32 | 33 | this.findMatches(); 34 | this.annotation.update(this.matches); 35 | 36 | var self = this; 37 | cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); 38 | } 39 | 40 | var MAX_MATCHES = 1000; 41 | 42 | SearchAnnotation.prototype.findMatches = function() { 43 | if (!this.gap) return; 44 | for (var i = 0; i < this.matches.length; i++) { 45 | var match = this.matches[i]; 46 | if (match.from.line >= this.gap.to) break; 47 | if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); 48 | } 49 | var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline}); 50 | var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES; 51 | while (cursor.findNext()) { 52 | var match = {from: cursor.from(), to: cursor.to()}; 53 | if (match.from.line >= this.gap.to) break; 54 | this.matches.splice(i++, 0, match); 55 | if (this.matches.length > maxMatches) break; 56 | } 57 | this.gap = null; 58 | }; 59 | 60 | function offsetLine(line, changeStart, sizeChange) { 61 | if (line <= changeStart) return line; 62 | return Math.max(changeStart, line + sizeChange); 63 | } 64 | 65 | SearchAnnotation.prototype.onChange = function(change) { 66 | var startLine = change.from.line; 67 | var endLine = CodeMirror.changeEnd(change).line; 68 | var sizeChange = endLine - change.to.line; 69 | if (this.gap) { 70 | this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); 71 | this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); 72 | } else { 73 | this.gap = {from: change.from.line, to: endLine + 1}; 74 | } 75 | 76 | if (sizeChange) for (var i = 0; i < this.matches.length; i++) { 77 | var match = this.matches[i]; 78 | var newFrom = offsetLine(match.from.line, startLine, sizeChange); 79 | if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); 80 | var newTo = offsetLine(match.to.line, startLine, sizeChange); 81 | if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); 82 | } 83 | clearTimeout(this.update); 84 | var self = this; 85 | this.update = setTimeout(function() { self.updateAfterChange(); }, 250); 86 | }; 87 | 88 | SearchAnnotation.prototype.updateAfterChange = function() { 89 | this.findMatches(); 90 | this.annotation.update(this.matches); 91 | }; 92 | 93 | SearchAnnotation.prototype.clear = function() { 94 | this.cm.off("change", this.changeHandler); 95 | this.annotation.clear(); 96 | }; 97 | }); 98 | -------------------------------------------------------------------------------- /codemirror/search.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | // Define search commands. Depends on dialog.js or another 5 | // implementation of the openDialog method. 6 | 7 | // Replace works a little oddly -- it will do the replace on the next 8 | // Ctrl-G (or whatever is bound to findNext) press. You prevent a 9 | // replace by making sure the match is no longer selected when hitting 10 | // Ctrl-G. 11 | 12 | (function(mod) { 13 | if (typeof exports == "object" && typeof module == "object") // CommonJS 14 | mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); 15 | else if (typeof define == "function" && define.amd) // AMD 16 | define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); 17 | else // Plain browser env 18 | mod(CodeMirror); 19 | })(function(CodeMirror) { 20 | "use strict"; 21 | 22 | // default search panel location 23 | CodeMirror.defineOption("search", {bottom: false}); 24 | 25 | function searchOverlay(query, caseInsensitive) { 26 | if (typeof query == "string") 27 | query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); 28 | else if (!query.global) 29 | query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); 30 | 31 | return {token: function(stream) { 32 | query.lastIndex = stream.pos; 33 | var match = query.exec(stream.string); 34 | if (match && match.index == stream.pos) { 35 | stream.pos += match[0].length || 1; 36 | return "searching"; 37 | } else if (match) { 38 | stream.pos = match.index; 39 | } else { 40 | stream.skipToEnd(); 41 | } 42 | }}; 43 | } 44 | 45 | function SearchState() { 46 | this.posFrom = this.posTo = this.lastQuery = this.query = null; 47 | this.overlay = null; 48 | } 49 | 50 | function getSearchState(cm) { 51 | return cm.state.search || (cm.state.search = new SearchState()); 52 | } 53 | 54 | function queryCaseInsensitive(query) { 55 | return typeof query == "string" && query == query.toLowerCase(); 56 | } 57 | 58 | function getSearchCursor(cm, query, pos) { 59 | // Heuristic: if the query string is all lowercase, do a case insensitive search. 60 | return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true}); 61 | } 62 | 63 | function persistentDialog(cm, text, deflt, onEnter, onKeyDown) { 64 | cm.openDialog(text, onEnter, { 65 | value: deflt, 66 | selectValueOnOpen: true, 67 | closeOnEnter: false, 68 | onClose: function() { clearSearch(cm); }, 69 | onKeyDown: onKeyDown, 70 | bottom: cm.options.search.bottom 71 | }); 72 | } 73 | 74 | function dialog(cm, text, shortText, deflt, f) { 75 | if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom}); 76 | else f(prompt(shortText, deflt)); 77 | } 78 | 79 | function confirmDialog(cm, text, shortText, fs) { 80 | if (cm.openConfirm) cm.openConfirm(text, fs); 81 | else if (confirm(shortText)) fs[0](); 82 | } 83 | 84 | function parseString(string) { 85 | return string.replace(/\\([nrt\\])/g, function(match, ch) { 86 | if (ch == "n") return "\n" 87 | if (ch == "r") return "\r" 88 | if (ch == "t") return "\t" 89 | if (ch == "\\") return "\\" 90 | return match 91 | }) 92 | } 93 | 94 | function parseQuery(query) { 95 | var isRE = query.match(/^\/(.*)\/([a-z]*)$/); 96 | if (isRE) { 97 | try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } 98 | catch(e) {} // Not a regular expression after all, do a string search 99 | } else { 100 | query = parseString(query) 101 | } 102 | if (typeof query == "string" ? query == "" : query.test("")) 103 | query = /x^/; 104 | return query; 105 | } 106 | 107 | function startSearch(cm, state, query) { 108 | state.queryText = query; 109 | state.query = parseQuery(query); 110 | cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); 111 | state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); 112 | cm.addOverlay(state.overlay); 113 | if (cm.showMatchesOnScrollbar) { 114 | if (state.annotate) { state.annotate.clear(); state.annotate = null; } 115 | state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); 116 | } 117 | } 118 | 119 | function doSearch(cm, rev, persistent, immediate) { 120 | var state = getSearchState(cm); 121 | if (state.query) return findNext(cm, rev); 122 | var q = cm.getSelection() || state.lastQuery; 123 | if (q instanceof RegExp && q.source == "x^") q = null 124 | if (persistent && cm.openDialog) { 125 | var hiding = null 126 | var searchNext = function(query, event) { 127 | CodeMirror.e_stop(event); 128 | if (!query) return; 129 | if (query != state.queryText) { 130 | startSearch(cm, state, query); 131 | state.posFrom = state.posTo = cm.getCursor(); 132 | } 133 | if (hiding) hiding.style.opacity = 1 134 | findNext(cm, event.shiftKey, function(_, to) { 135 | var dialog 136 | if (to.line < 3 && document.querySelector && 137 | (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && 138 | dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) 139 | (hiding = dialog).style.opacity = .4 140 | }) 141 | }; 142 | persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) { 143 | var keyName = CodeMirror.keyName(event) 144 | var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName] 145 | if (cmd == "findNext" || cmd == "findPrev" || 146 | cmd == "findPersistentNext" || cmd == "findPersistentPrev") { 147 | CodeMirror.e_stop(event); 148 | startSearch(cm, getSearchState(cm), query); 149 | cm.execCommand(cmd); 150 | } else if (cmd == "find" || cmd == "findPersistent") { 151 | CodeMirror.e_stop(event); 152 | searchNext(query, event); 153 | } 154 | }); 155 | if (immediate && q) { 156 | startSearch(cm, state, q); 157 | findNext(cm, rev); 158 | } 159 | } else { 160 | dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) { 161 | if (query && !state.query) cm.operation(function() { 162 | startSearch(cm, state, query); 163 | state.posFrom = state.posTo = cm.getCursor(); 164 | findNext(cm, rev); 165 | }); 166 | }); 167 | } 168 | } 169 | 170 | function findNext(cm, rev, callback) {cm.operation(function() { 171 | var state = getSearchState(cm); 172 | var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); 173 | if (!cursor.find(rev)) { 174 | cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); 175 | if (!cursor.find(rev)) return; 176 | } 177 | cm.setSelection(cursor.from(), cursor.to()); 178 | cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); 179 | state.posFrom = cursor.from(); state.posTo = cursor.to(); 180 | if (callback) callback(cursor.from(), cursor.to()) 181 | });} 182 | 183 | function clearSearch(cm) {cm.operation(function() { 184 | var state = getSearchState(cm); 185 | state.lastQuery = state.query; 186 | if (!state.query) return; 187 | state.query = state.queryText = null; 188 | cm.removeOverlay(state.overlay); 189 | if (state.annotate) { state.annotate.clear(); state.annotate = null; } 190 | });} 191 | 192 | function el(tag, attrs) { 193 | var element = tag ? document.createElement(tag) : document.createDocumentFragment(); 194 | for (var key in attrs) { 195 | element[key] = attrs[key]; 196 | } 197 | for (var i = 2; i < arguments.length; i++) { 198 | var child = arguments[i] 199 | element.appendChild(typeof child == "string" ? document.createTextNode(child) : child); 200 | } 201 | return element; 202 | } 203 | 204 | function getQueryDialog(cm) { 205 | return el("", null, 206 | el("span", {className: "CodeMirror-search-label"}, cm.phrase("Search:")), " ", 207 | el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ", 208 | el("span", {style: "color: #888", className: "CodeMirror-search-hint"}, 209 | cm.phrase("(Use /re/ syntax for regexp search)"))); 210 | } 211 | function getReplaceQueryDialog(cm) { 212 | return el("", null, " ", 213 | el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ", 214 | el("span", {style: "color: #888", className: "CodeMirror-search-hint"}, 215 | cm.phrase("(Use /re/ syntax for regexp search)"))); 216 | } 217 | function getReplacementQueryDialog(cm) { 218 | return el("", null, 219 | el("span", {className: "CodeMirror-search-label"}, cm.phrase("With:")), " ", 220 | el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"})); 221 | } 222 | function getDoReplaceConfirm(cm) { 223 | return el("", null, 224 | el("span", {className: "CodeMirror-search-label"}, cm.phrase("Replace?")), " ", 225 | el("button", {}, cm.phrase("Yes")), " ", 226 | el("button", {}, cm.phrase("No")), " ", 227 | el("button", {}, cm.phrase("All")), " ", 228 | el("button", {}, cm.phrase("Stop"))); 229 | } 230 | 231 | function replaceAll(cm, query, text) { 232 | cm.operation(function() { 233 | for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { 234 | if (typeof query != "string") { 235 | var match = cm.getRange(cursor.from(), cursor.to()).match(query); 236 | cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); 237 | } else cursor.replace(text); 238 | } 239 | }); 240 | } 241 | 242 | function replace(cm, all) { 243 | if (cm.getOption("readOnly")) return; 244 | var query = cm.getSelection() || getSearchState(cm).lastQuery; 245 | var dialogText = all ? cm.phrase("Replace all:") : cm.phrase("Replace:") 246 | var fragment = el("", null, 247 | el("span", {className: "CodeMirror-search-label"}, dialogText), 248 | getReplaceQueryDialog(cm)) 249 | dialog(cm, fragment, dialogText, query, function(query) { 250 | if (!query) return; 251 | query = parseQuery(query); 252 | dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) { 253 | text = parseString(text) 254 | if (all) { 255 | replaceAll(cm, query, text) 256 | } else { 257 | clearSearch(cm); 258 | var cursor = getSearchCursor(cm, query, cm.getCursor("from")); 259 | var advance = function() { 260 | var start = cursor.from(), match; 261 | if (!(match = cursor.findNext())) { 262 | cursor = getSearchCursor(cm, query); 263 | if (!(match = cursor.findNext()) || 264 | (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; 265 | } 266 | cm.setSelection(cursor.from(), cursor.to()); 267 | cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); 268 | confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"), 269 | [function() {doReplace(match);}, advance, 270 | function() {replaceAll(cm, query, text)}]); 271 | }; 272 | var doReplace = function(match) { 273 | cursor.replace(typeof query == "string" ? text : 274 | text.replace(/\$(\d)/g, function(_, i) {return match[i];})); 275 | advance(); 276 | }; 277 | advance(); 278 | } 279 | }); 280 | }); 281 | } 282 | 283 | CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; 284 | CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; 285 | CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);}; 286 | CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);}; 287 | CodeMirror.commands.findNext = doSearch; 288 | CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; 289 | CodeMirror.commands.clearSearch = clearSearch; 290 | CodeMirror.commands.replace = replace; 291 | CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; 292 | }); 293 | -------------------------------------------------------------------------------- /codemirror/themes/mdn-like.css: -------------------------------------------------------------------------------- 1 | /* 2 | MDN-LIKE Theme - Mozilla 3 | Ported to CodeMirror by Peter Kroon 4 | Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues 5 | GitHub: @peterkroon 6 | 7 | The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation 8 | 9 | */ 10 | .cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } 11 | .cm-s-mdn-like div.CodeMirror-selected { background: #cfc; } 12 | .cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; } 13 | .cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; } 14 | 15 | .cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } 16 | .cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; } 17 | .cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } 18 | 19 | .cm-s-mdn-like .cm-keyword { color: #6262FF; } 20 | .cm-s-mdn-like .cm-atom { color: #F90; } 21 | .cm-s-mdn-like .cm-number { color: #ca7841; } 22 | .cm-s-mdn-like .cm-def { color: #8DA6CE; } 23 | .cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } 24 | .cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; } 25 | 26 | .cm-s-mdn-like .cm-variable { color: #07a; } 27 | .cm-s-mdn-like .cm-property { color: #905; } 28 | .cm-s-mdn-like .cm-qualifier { color: #690; } 29 | 30 | .cm-s-mdn-like .cm-operator { color: #cda869; } 31 | .cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } 32 | .cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } 33 | .cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ 34 | .cm-s-mdn-like .cm-meta { color: #000; } /*?*/ 35 | .cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ 36 | .cm-s-mdn-like .cm-tag { color: #997643; } 37 | .cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ 38 | .cm-s-mdn-like .cm-header { color: #FF6400; } 39 | .cm-s-mdn-like .cm-hr { color: #AEAEAE; } 40 | .cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } 41 | .cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } 42 | 43 | div.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; } 44 | div.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; } 45 | 46 | .cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); } 47 | 48 | body { 49 | background-color: #ddd; 50 | font-family: Verdana, Geneva, Tahoma, sans-serif; 51 | font-size: 12px; 52 | } 53 | #gx-container { background-color: #666; border: 2px inset; } 54 | 55 | #toolbar { background-color: #ddd; border: 2px outset; font-size: 16px; } 56 | #toolbar a { filter: invert(1); border: none; padding: 0; } 57 | 58 | a, a:link, a:visited { color: #666; border: 2px outset; padding: 2px 5px; } 59 | a:active { border: 2px inset;} 60 | a:hover { color: #999; } 61 | a:before { content: ""; } 62 | a:after { content: ""; } 63 | 64 | #share-dialog textarea { 65 | font-family: 'Courier New', monospace; 66 | font-size: 14px; 67 | } 68 | 69 | #share-dialog { 70 | border: 2px outset; 71 | } 72 | 73 | #code { 74 | border: 2px inset; 75 | border-top: 0; 76 | } 77 | 78 | #logo { right: 2px; top: 2px; } 79 | 80 | #output-content, #warning-container { 81 | font-family: 'Courier New', monospace; 82 | /*font-size: 14px;*/ 83 | } 84 | 85 | #output-content { border: 2px outset; } 86 | 87 | .tab { 88 | position: relative; 89 | top: 1px; 90 | border: 2px outset; 91 | border-bottom: 0; 92 | border-radius: 5px 5px 0px 0px; 93 | } 94 | 95 | #tabs .active { 96 | color: #333; 97 | border-bottom: 2px solid #ddd; 98 | } 99 | 100 | .tab:hover, #tabs .active:hover { 101 | color: #333; 102 | background-color: transparent; 103 | } 104 | -------------------------------------------------------------------------------- /codemirror/themes/qb45.css: -------------------------------------------------------------------------------- 1 | .cm-s-qb45 { line-height: 1em; } 2 | .cm-s-qb45.CodeMirror { background: rgb(0, 0, 170); color: rgb(216, 216, 216); /*text-shadow: 0 -1px 1px #262626;*/ font-family: dosvga; } 3 | .cm-s-qb45 div.CodeMirror-selected { background: rgb(216, 216, 216, .5); } /* 33322B*/ 4 | /*.cm-s-qb45 .CodeMirror-line::selection, .cm-s-qb45 .CodeMirror-line > span::selection, .cm-s-qb45 .CodeMirror-line > span > span::selection { background: rgb(216, 216, 216); color: rgb(0, 0, 170); } 5 | .cm-s-qb45 .CodeMirror-line::-moz-selection, .cm-s-qb45 .CodeMirror-line > span::-moz-selection, .cm-s-qb45 .CodeMirror-line > span > span::-moz-selection { background: rgb(216, 216, 216); color: rgb(0, 0, 170); }*/ 6 | .cm-s-qb45 .CodeMirror-cursor { border-left: 1px solid #fff; overflow: hidden; width: 0px;} 7 | .cm-s-qb45 pre { padding: 0 8px; }/*editable code holder*/ 8 | 9 | .cm-s-qb45.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ 10 | 11 | .cm-s-qb45 .CodeMirror-gutters { background: rgb(0, 0, 170); border-right:1px solid rgb(177, 177, 177); } 12 | .cm-s-qb45 .CodeMirror-guttermarker { color: #599eff; } 13 | .cm-s-qb45 .CodeMirror-guttermarker-subtle { color: #777; } 14 | .cm-s-qb45 .CodeMirror-linenumber { color: rgb(177, 177, 177); } 15 | 16 | .cm-s-qb45 span.cm-header { color: #a0a; } 17 | .cm-s-qb45 span.cm-quote { color: #090; } 18 | .cm-s-qb45 span.cm-keyword { color: rgb(177, 177, 177); } 19 | .cm-s-qb45 span.cm-atom { color: #C2B470; } 20 | .cm-s-qb45 span.cm-number { color: rgb(177, 177, 177); } 21 | .cm-s-qb45 span.cm-def { color: white; } 22 | .cm-s-qb45 span.cm-variable { color:rgb(177, 177, 177); } 23 | .cm-s-qb45 span.cm-variable-2 { color: rgb(177, 177, 177); } 24 | .cm-s-qb45 span.cm-variable-3, .cm-s-qb45 span.cm-type { color: white; } 25 | .cm-s-qb45 span.cm-property { color: #92A75C; } 26 | .cm-s-qb45 span.cm-operator { color: #92A75C; } 27 | .cm-s-qb45 span.cm-comment { color: rgb(177, 177, 177); } 28 | .cm-s-qb45 span.cm-string { color: rgb(177, 177, 177); } 29 | .cm-s-qb45 span.cm-string-2 { color: rgb(177, 177, 177); } 30 | .cm-s-qb45 span.cm-meta { color: #738C73; } 31 | .cm-s-qb45 span.cm-qualifier { color: #555; } 32 | .cm-s-qb45 span.cm-builtin { color: rgb(177, 177, 177); } 33 | .cm-s-qb45 span.cm-bracket { color: #EBEFE7; } 34 | .cm-s-qb45 span.cm-tag { color: #669199; } 35 | .cm-s-qb45 span.cm-attribute { color: #81a4d5; } 36 | .cm-s-qb45 span.cm-hr { color: #999; } 37 | .cm-s-qb45 span.cm-link { color: #7070E6; } 38 | .cm-s-qb45 span.cm-error { color: #999; } 39 | 40 | .cm-s-qb45 .CodeMirror-activeline-background { background: rgb(0, 0, 170); } 41 | .cm-s-qb45 .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } 42 | 43 | .cm-s-qb45 .CodeMirror-search-field { font-family: dosvga; font-size: 1em; } 44 | .cm-s-qb45 .cm-searching { color: #333 !important; background-color: #ccc; } 45 | 46 | body { 47 | background-color: rgb(0, 0, 170); 48 | } 49 | 50 | #gx-container { 51 | letter-spacing: normal; 52 | } 53 | 54 | #code, #gx-container, #toolbar, #toolbar .spacer, .tab, #output-content { 55 | border-color: rgb(177, 177, 177); 56 | } 57 | 58 | #slider { 59 | color: rgb(177, 177, 177); 60 | } 61 | 62 | #tabs .active { 63 | border-bottom: 1px solid rgb(0, 0, 170); 64 | } 65 | 66 | .tab:hover, #tabs .active:hover { 67 | background-color: rgb(0, 0, 170); 68 | } 69 | 70 | #warning-container .selected { 71 | color: rgb(0, 0, 170); 72 | background-color: rgb(216, 216, 216); 73 | } 74 | 75 | #fs-path { border-color: rgb(177, 177, 177); } 76 | 77 | #fs-contents a, #fs-contents a:visited, #fs-contents a:active { color: rgb(177, 177, 177); } 78 | #fs-contents a:hover { color: #efefef; } 79 | 80 | #help-nav a:hover { color: #fff; } 81 | #help-nav a:before { content: "< "; } 82 | #help-nav a:after { content: " >"; } 83 | #help-nav a { margin-right: 0px; } 84 | -------------------------------------------------------------------------------- /codemirror/themes/qb64-vscode.css: -------------------------------------------------------------------------------- 1 | .cm-s-qb64-vscode { line-height: 1em; } 2 | .cm-s-qb64-vscode.CodeMirror { background: rgb(0, 0, 170); color: rgb(216, 216, 216); /*text-shadow: 0 -1px 1px #262626;*/ font-family: dosvga; } 3 | .cm-s-qb64-vscode div.CodeMirror-selected { background: rgb(216, 216, 216, .5); } /* 33322B*/ 4 | /*.cm-s-qb64-vscode .CodeMirror-line::selection, .cm-s-qb64-vscode .CodeMirror-line > span::selection, .cm-s-qb64-vscode .CodeMirror-line > span > span::selection { background: rgb(216, 216, 216); color: rgb(0, 0, 170); } 5 | .cm-s-qb64-vscode .CodeMirror-line::-moz-selection, .cm-s-qb64-vscode .CodeMirror-line > span::-moz-selection, .cm-s-qb64-vscode .CodeMirror-line > span > span::-moz-selection { background: rgb(216, 216, 216); color: rgb(0, 0, 170); }*/ 6 | .cm-s-qb64-vscode .CodeMirror-cursor { border-left: 2px solid #f7ff00; overflow: hidden; width: 0px;} 7 | .cm-s-qb64-vscode pre { padding: 0 8px; }/*editable code holder*/ 8 | 9 | .cm-s-qb64-vscode.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ 10 | 11 | .cm-s-qb64-vscode .CodeMirror-gutters { background: rgba(0, 0, 0, 0.5); border-right:1px solid rgba(177, 177, 177, 0.5); } 12 | .cm-s-qb64-vscode .CodeMirror-guttermarker { color: #599eff; } 13 | .cm-s-qb64-vscode .CodeMirror-guttermarker-subtle { color: #777; } 14 | .cm-s-qb64-vscode .CodeMirror-linenumber { color: rgba(177, 177, 177, 0.6); } 15 | 16 | .cm-s-qb64-vscode span.cm-header { color: #a0a; } 17 | .cm-s-qb64-vscode span.cm-quote { color: #090; } 18 | .cm-s-qb64-vscode span.cm-keyword { color: #FFF; } 19 | .cm-s-qb64-vscode span.cm-atom { color: #59DDF5; } 20 | .cm-s-qb64-vscode span.cm-number { color: #FF85A7; } 21 | .cm-s-qb64-vscode span.cm-def { color: white; } 22 | .cm-s-qb64-vscode span.cm-variable { color:#93C4EB; } 23 | .cm-s-qb64-vscode span.cm-variable-2 { color: #93C4EB; } 24 | .cm-s-qb64-vscode span.cm-variable-3, .cm-s-qb64-vscode span.cm-type { color: white; } 25 | .cm-s-qb64-vscode span.cm-property { color: #92A75C; } 26 | .cm-s-qb64-vscode span.cm-operator { color: #93C4EB; } 27 | .cm-s-qb64-vscode span.cm-comment { color: #8681C9; } 28 | .cm-s-qb64-vscode span.cm-string { color: #FF5; } 29 | .cm-s-qb64-vscode span.cm-string-2 { color: #FF5; } 30 | .cm-s-qb64-vscode span.cm-meta { color: #738C73; } 31 | .cm-s-qb64-vscode span.cm-qualifier { color: #555; } 32 | .cm-s-qb64-vscode span.cm-builtin { color: #FFF; } 33 | .cm-s-qb64-vscode span.cm-bracket { color: #EBC093; } 34 | .cm-s-qb64-vscode span.cm-tag { color: #669199; } 35 | .cm-s-qb64-vscode span.cm-attribute { color: #81a4d5; } 36 | .cm-s-qb64-vscode span.cm-hr { color: #999; } 37 | .cm-s-qb64-vscode span.cm-link { color: #7070E6; } 38 | .cm-s-qb64-vscode span.cm-error { color: #93C4EB; } 39 | 40 | .cm-s-qb64-vscode .CodeMirror-activeline-background { background: #007; } 41 | .cm-s-qb64-vscode .CodeMirror-matchingbracket { outline:1px solid #009; color:white !important; } 42 | 43 | .cm-s-qb64-vscode .CodeMirror-search-field { font-family: dosvga; font-size: 1em; } 44 | .cm-s-qb64-vscode .cm-searching { color: #333 !important; background-color: #ccc; } 45 | 46 | body { 47 | background-color: #0000AA; 48 | } 49 | 50 | #code, #gx-container, #toolbar, #toolbar .spacer, .tab, #output-content { 51 | border-color: rgb(177, 177, 177); 52 | } 53 | 54 | #slider { 55 | color: rgb(177, 177, 177); 56 | } 57 | 58 | #tabs .active { 59 | border-bottom: 1px solid rgb(0, 0, 170); 60 | } 61 | 62 | .tab:hover, #tabs .active:hover { 63 | background-color: rgb(0, 0, 170); 64 | } 65 | 66 | #warning-container .selected { 67 | color: rgb(0, 0, 170); 68 | background-color: rgb(216, 216, 216); 69 | } 70 | 71 | #fs-path { border-color: rgb(177, 177, 177); } 72 | 73 | #fs-contents a, #fs-contents a:visited, #fs-contents a:active { color: rgb(177, 177, 177); } 74 | #fs-contents a:hover { color: #efefef; } 75 | 76 | #help-nav a:hover { color: #fff; } 77 | #help-nav a:before { content: "< "; } 78 | #help-nav a:after { content: " >"; } 79 | #help-nav a { margin-right: 0px; } -------------------------------------------------------------------------------- /codemirror/themes/qbjs.css: -------------------------------------------------------------------------------- 1 | .cm-s-qbjs { 2 | line-height: 1em; 3 | } 4 | .cm-s-qbjs.CodeMirror { background: rgb(0, 0, 39); color: rgb(216, 216, 216); text-shadow: 0 -1px 1px #262626; font-family: dosvga; } 5 | .cm-s-qbjs div.CodeMirror-selected { background: #45443B; } /* 33322B*/ 6 | .cm-s-qbjs .CodeMirror-line::selection, .cm-s-qbjs .CodeMirror-line > span::selection, .cm-s-qbjs .CodeMirror-line > span > span::selection { background: rgba(0, 49, 78, .99); } 7 | .cm-s-qbjs .CodeMirror-line::-moz-selection, .cm-s-qbjs .CodeMirror-line > span::-moz-selection, .cm-s-qbjs .CodeMirror-line > span > span::-moz-selection { background: rgba(69, 68, 59, .99); } 8 | .cm-s-qbjs .CodeMirror-cursor { border-left: 1px solid #fff; } /* overflow: hidden; width: 0px;} */ 9 | .cm-s-qbjs pre { padding: 0 8px; }/*editable code holder*/ 10 | 11 | .cm-s-qbjs.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ 12 | 13 | .cm-s-qbjs .CodeMirror-gutters { background: rgb(0, 49, 78); border-right:1px solid #aaa; } 14 | .cm-s-qbjs .CodeMirror-guttermarker { color: #599eff; } 15 | .cm-s-qbjs .CodeMirror-guttermarker-subtle { color: #777; } 16 | .cm-s-qbjs .CodeMirror-linenumber { color: rgb(175, 175, 175); } 17 | 18 | .cm-s-qbjs span.cm-header { color: #a0a; } 19 | .cm-s-qbjs span.cm-quote { color: #090; } 20 | .cm-s-qbjs span.cm-keyword { color: rgb(69, 118, 147); } 21 | .cm-s-qbjs span.cm-atom { color: #C2B470; } 22 | .cm-s-qbjs span.cm-number { color: rgb(216, 98, 78); } 23 | .cm-s-qbjs span.cm-def { color: white; } 24 | .cm-s-qbjs span.cm-variable { color:rgb(216, 216, 216); } 25 | .cm-s-qbjs span.cm-variable-2 { color: #669199; } 26 | .cm-s-qbjs span.cm-variable-3, .cm-s-qbjs span.cm-type { color: white; } 27 | .cm-s-qbjs span.cm-property { color: #92A75C; } 28 | .cm-s-qbjs span.cm-operator { color: #92A75C; } 29 | .cm-s-qbjs span.cm-comment { color: rgb(98, 98, 98); } 30 | .cm-s-qbjs span.cm-string { color: rgb(255, 167, 0); } 31 | .cm-s-qbjs span.cm-string-2 { color: #f50; } 32 | .cm-s-qbjs span.cm-meta { color: #738C73; } 33 | .cm-s-qbjs span.cm-qualifier { color: #555; } 34 | .cm-s-qbjs span.cm-builtin { color: rgb(69, 118, 147); } 35 | .cm-s-qbjs span.cm-bracket { color: #EBEFE7; } 36 | .cm-s-qbjs span.cm-tag { color: #669199; } 37 | .cm-s-qbjs span.cm-attribute { color: #81a4d5; } 38 | .cm-s-qbjs span.cm-hr { color: #999; } 39 | .cm-s-qbjs span.cm-link { color: #7070E6; } 40 | /*.cm-s-qbjs span.cm-error { color: #9d1e15; }*/ 41 | .cm-s-qbjs span.cm-error { color: #999; } 42 | 43 | .cm-s-qbjs .CodeMirror-activeline-background { background: rgb(0, 49, 78); } 44 | .cm-s-qbjs .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } 45 | 46 | .cm-s-qbjs .CodeMirror-search-field { font-family: dosvga; font-size: 1em; } 47 | .cm-s-qbjs .cm-searching { color: #333 !important; background-color: #ccc; } 48 | 49 | #help-nav a:hover { color: #fff; } 50 | #help-nav a:before { content: "< "; } 51 | #help-nav a:after { content: " >"; } 52 | #help-nav a { margin-right: 0px; } 53 | -------------------------------------------------------------------------------- /codemirror/themes/vscode-dark.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @package vscode-dark theme 3 | * @version 1.0.0 4 | * @author Inter-Net PRO 5 | * @link https://inter-net.pro 6 | * @github https://github.com/Inter-Net-Pro/Theme-VSCode-Dark 7 | */ 8 | .cm-s-vscode-dark span.cm-meta {color: #569cd6} 9 | .cm-s-vscode-dark span.cm-number {color: #b5cea8} 10 | .cm-s-vscode-dark span.cm-keyword {line-height: 1em; color: #569cd6;} 11 | .cm-s-vscode-dark span.cm-def {color:#9cdcfe} 12 | .cm-s-vscode-dark span.cm-variable {color: #ddd6a3} 13 | .cm-s-vscode-dark span.cm-variable-2 {color: #9cdcfe} 14 | .cm-s-vscode-dark span.cm-variable-3, 15 | .cm-s-vscode-dark span.cm-type {color: #A9B7C6} 16 | .cm-s-vscode-dark span.cm-property {color: #9cdcfe} 17 | .cm-s-vscode-dark span.cm-operator {color: #d4d4d4} 18 | .cm-s-vscode-dark span.cm-string {color: #ce9178} 19 | .cm-s-vscode-dark span.cm-string-2 {color: #6A8759} 20 | .cm-s-vscode-dark span.cm-comment {color: #6A9955} 21 | .cm-s-vscode-dark span.cm-link {color: #287BDE} 22 | .cm-s-vscode-dark span.cm-atom {color: #569cd6} 23 | /*.cm-s-vscode-dark span.cm-error {color: #BC3F3C}*/ 24 | .cm-s-vscode-dark span.cm-tag {color: #569cd6} 25 | .cm-s-vscode-dark span.cm-attribute {color: #9cdcfe} 26 | .cm-s-vscode-dark span.cm-qualifier {color: #d7ba7d} 27 | .cm-s-vscode-dark span.cm-bracket {color: #808080} 28 | 29 | .cm-s-vscode-dark.CodeMirror {background: #1e1e1e; color: #e9e9e9;} 30 | .cm-s-vscode-dark .CodeMirror-cursor {border-left: 1px solid #bebebe;} 31 | .CodeMirror-activeline-background {background: #3A3A3A;} 32 | .cm-s-vscode-dark div.CodeMirror-selected {background: #1e496c} 33 | .cm-s-vscode-dark .CodeMirror-gutters {background: #252526; border-right: 1px solid grey; color: #606366} 34 | .cm-s-vscode-dark span.cm-builtin {color: #A9B7C6;} 35 | .cm-s-vscode-dark {font-family: Consolas, 'Courier New', monospace, serif;} 36 | .cm-s-vscode-dark .CodeMirror-matchingbracket {background-color: #3b514d; color: yellow !important;} 37 | 38 | .CodeMirror * { 39 | font-size: 14px; 40 | } 41 | .CodeMirror-hints.vscode-dark { 42 | font-family: Consolas, 'Courier New', monospace; 43 | color: #9c9e9e; 44 | background-color: #3b3e3f !important; 45 | } 46 | 47 | .CodeMirror-hints.vscode-dark .CodeMirror-hint-active { 48 | background-color: #494d4e !important; 49 | color: #9c9e9e !important; 50 | } 51 | 52 | /* QBJS IDE styles */ 53 | body { 54 | background-color: #3A3A3A; 55 | font-family: Arial, helvetica, sans-serif; 56 | font-size: 14px; 57 | } 58 | #gx-container { background-color: #1e1e1e; /*border-top: 0px;*/ } 59 | 60 | #slider { 61 | font-family: dosvga; 62 | } 63 | 64 | a, #tabs, #method-tabs { 65 | font-family: arial, helvetica, sans-serif; 66 | font-variant: all-small-caps; 67 | font-size: 14px; 68 | } 69 | 70 | #output-content, #warning-container { 71 | font-family: Consolas, 'Courier New', monospace; 72 | font-size: 14px; 73 | } 74 | 75 | #output-content { background-color: #1e1e1e; } 76 | 77 | #tabs .active, #method-tabs .active { 78 | border-bottom: 1px solid #1e1e1e; 79 | background-color: #1e1e1e; 80 | } 81 | 82 | .tab:hover, #tabs .active:hover, #method-tabs .active:hover { 83 | background-color: #1e1e1e; 84 | color: #ccc; 85 | } 86 | 87 | #toolbar a { font-size: 17px; } 88 | 89 | dialog textarea { 90 | font-family: Consolas, 'Courier New', monospace; 91 | background-color: #1e1e1e; 92 | color: #ccc; 93 | } 94 | 95 | dialog { 96 | background-color: #3A3A3A; 97 | border: 1px solid #666; 98 | color: #ccc; 99 | } 100 | 101 | dialog a { color: #ccc !important; } 102 | dialog a:hover { color: #fff !important; } 103 | a:before { content: ""; } 104 | a:after { content: ""; } 105 | a:hover { text-decoration: underline; } 106 | dialog a.disabled, dialog a.disabled:hover { color: #999 !important; } 107 | dialog a.disabled:hover { text-decoration: none; } 108 | 109 | #fs-contents a { font-variant: normal; font-family: Verdana, Geneva, Tahoma, sans-serif; font-size: 13px; } 110 | #fs-contents a:hover { text-decoration: none; } 111 | 112 | .help a { font-variant: normal; font-size: 15px } 113 | 114 | 115 | /*.methods thead { 116 | border: 1px solid #666; 117 | }*/ 118 | 119 | .methods thead tr { 120 | background-color: #1e1e1e; 121 | box-shadow: 0px 1px 1px #666; 122 | } 123 | 124 | .methods tbody { 125 | background-color: #1e1e1e; 126 | } 127 | 128 | .methods { 129 | border: 1px solid #666; 130 | } 131 | 132 | #method-tabs .tab { 133 | color: #999; 134 | } 135 | 136 | #method-tabs .tab { 137 | border-color: #666; 138 | border-bottom-color: transparent; 139 | } 140 | 141 | #method-tabs .tab:hover { 142 | color: #ccc; 143 | background-color: #1e1e1e; 144 | } 145 | #method-tabs .active { 146 | color: #ccc; 147 | /*border-bottom-color: #1e1e1e;*/ 148 | } -------------------------------------------------------------------------------- /codemirror/themes/win-classic.css: -------------------------------------------------------------------------------- 1 | .cm-s-win-classic .cm-keyword { color: #6262FF; } 2 | .cm-s-win-classic .cm-atom { color: #F90; } 3 | .cm-s-win-classic .cm-number { color: #ca7841; } 4 | .cm-s-win-classic .cm-def { color: #8DA6CE; } 5 | .cm-s-win-classic span.cm-variable-2, .cm-s-win-classic span.cm-tag { color: #690; } 6 | .cm-s-win-classic span.cm-variable-3, .cm-s-win-classic span.cm-def, .cm-s-win-classic span.cm-type { color: #07a; } 7 | 8 | .cm-s-win-classic .cm-variable { color: #07a; } 9 | .cm-s-win-classic .cm-property { color: #905; } 10 | .cm-s-win-classic .cm-qualifier { color: #690; } 11 | 12 | .cm-s-win-classic .cm-operator { color: #cda869; } 13 | .cm-s-win-classic .cm-comment { color:#777; font-weight:normal; } 14 | .cm-s-win-classic .cm-string { color:#07a; /*font-style:italic;*/ } 15 | .cm-s-win-classic .cm-string-2 { color:#bd6b18; } /*?*/ 16 | .cm-s-win-classic .cm-meta { color: #000; } /*?*/ 17 | .cm-s-win-classic .cm-builtin { color: #9B7536; } /*?*/ 18 | .cm-s-win-classic .cm-tag { color: #997643; } 19 | .cm-s-win-classic .cm-attribute { color: #d6bb6d; } /*?*/ 20 | .cm-s-win-classic .cm-header { color: #FF6400; } 21 | .cm-s-win-classic .cm-hr { color: #AEAEAE; } 22 | .cm-s-win-classic .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } 23 | 24 | div.cm-s-win-classic .CodeMirror-activeline-background { background: #efefff; } 25 | div.cm-s-win-classic span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; } 26 | 27 | 28 | .cm-s-win-classic.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); } 29 | 30 | body { 31 | background-color: #ddd; 32 | font-family: Verdana, Geneva, Tahoma, sans-serif; 33 | font-size: 12px; 34 | } 35 | #gx-container { background-color: #666; border: 2px inset; } 36 | 37 | #toolbar { background-color: #ddd; border: 2px outset; font-size: 16px; } 38 | #toolbar a { filter: invert(1); border: none; padding: 0; } 39 | 40 | a, a:link, a:visited { color: #333; border: 2px outset; padding: 2px 5px; user-select: none; } 41 | a:active { border: 2px inset;} 42 | a:hover { color: #000; } 43 | a:before { content: ""; } 44 | a:after { content: ""; } 45 | dialog a.disabled:active { border: 2px outset; } 46 | 47 | li a, li a:link, li a:visited { border: 0; text-decoration: underline; } 48 | li a:active { border: 0; } 49 | 50 | dialog textarea { 51 | font-family: 'Courier New', monospace; 52 | font-size: 14px; 53 | border: 2px inset; 54 | } 55 | dialog textarea:focus { 56 | outline: none; 57 | } 58 | 59 | dialog { 60 | border: 2px outset; 61 | background-color: #ddd; 62 | } 63 | 64 | #code { 65 | border: 2px inset; 66 | font-size: 14px; 67 | } 68 | 69 | #logo { right: 10px; top: 10px; } 70 | 71 | #output-content, #warning-container { 72 | font-family: 'Courier New', monospace; 73 | } 74 | 75 | #output-content { 76 | border: 2px outset; 77 | overflow: hidden; 78 | } 79 | 80 | .tab { 81 | position: relative; 82 | top: 1px; 83 | border: 2px outset; 84 | border-bottom: 0; 85 | border-radius: 5px 5px 0px 0px; 86 | color: #666; 87 | } 88 | 89 | #tabs .active { 90 | color: #333; 91 | border-bottom: 2px solid #ddd; 92 | } 93 | 94 | .tab:hover, #tabs .active:hover { 95 | color: #333; 96 | background-color: transparent; 97 | } 98 | 99 | #warning-container, #js-code, #fs-contents { 100 | position: absolute; 101 | top: 40px; 102 | left: 10px; 103 | bottom: 10px; 104 | right: 10px; 105 | border: 2px inset; 106 | overflow: auto; 107 | background-color: #efefef; 108 | color: #333; 109 | } 110 | #warning-container .selected { background-color: #ccc; } 111 | 112 | #run-button, #edit-button, #stop-button, #share-button, #toggle-console { display: inline-block; } 113 | 114 | #fs-browser { font-family: Verdana, Geneva, Tahoma, sans-serif; } 115 | #fs-path { border: 2px inset; color: #333; } 116 | #fs-path div { filter: invert(1); } 117 | #fs-contents a { border: 0; user-select: auto; color: #333; } 118 | #fs-contents a:hover { background-color: #ddd; } 119 | #fs-contents { top: 70px; color: #333; grid-auto-rows: 25px; padding-top: 5px; padding-right: 5px; } 120 | .fs-delete:hover { background-color: transparent; } 121 | 122 | .help { background-color: #f6f6f6; color: #333; } 123 | .help a, .help a:link, .help a:visited { border: 0; padding: 0; user-select: auto; } 124 | .help a:active { border: 0;} 125 | .help a:hover { color: #000; text-decoration: underline; } 126 | .help a:before { content: ""; } 127 | .help a:after { content: ""; } 128 | 129 | .help tr:nth-child(even) { background: rgba(175, 175, 175, .5) } 130 | .help code { background-color: rgba(175, 175, 175, .5); } 131 | .help-nav { padding-left: 5px; } 132 | .help-nav a { color: #333 !important; font-family: Verdana, Geneva, Tahoma, sans-serif; margin-right: 0px; } 133 | 134 | 135 | #method-tabs .tab { 136 | border-color: inherit; 137 | } 138 | 139 | .methods { 140 | border: 2px inset; 141 | border-top: 2px outset; 142 | } 143 | 144 | .methods thead { 145 | border: 2px outset; 146 | border-top: 0; 147 | border-left: 0; 148 | } 149 | .methods thead tr { 150 | box-shadow: 0px 1px 0px #999; 151 | } 152 | 153 | .methods th { 154 | border: 0; 155 | } 156 | 157 | .methods tbody { 158 | background-color: #f6f6f6; 159 | } 160 | #method-tabs { 161 | margin-left: 10px; 162 | } 163 | #method-tabs .active { 164 | border-bottom: 2px solid #ddd; 165 | } -------------------------------------------------------------------------------- /dosvga.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/dosvga.ttf -------------------------------------------------------------------------------- /export/auto.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 14 |   15 | 16 | 17 | 18 | 19 | 20 | 42 | -------------------------------------------------------------------------------- /export/fullscreen-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 47 | -------------------------------------------------------------------------------- /export/fullscreen.svg: -------------------------------------------------------------------------------- 1 | 2 | 47 | -------------------------------------------------------------------------------- /export/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/export/logo.png -------------------------------------------------------------------------------- /export/play.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
_
10 | 14 | 15 | 16 | 17 | 18 | 19 | 44 | -------------------------------------------------------------------------------- /export/qbjs.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: dosvga; 3 | src: url(qbjs.woff2); 4 | } 5 | body { 6 | background-color: #000; 7 | font-family: dosvga, Arial, Helvetica, sans-serif; 8 | color: #999; 9 | } 10 | #gx-container { 11 | text-align: center; 12 | position: absolute; 13 | left: 0px; 14 | top: 0px; 15 | overflow: hidden; 16 | } 17 | #gx-footer { 18 | margin: 0 auto; 19 | background-color: #333; 20 | display: flex; 21 | justify-content: space-between; 22 | width: 600px; 23 | } 24 | #gx-link, #gx-fullscreen { 25 | margin: 1px; 26 | } 27 | #gx-fullscreen { 28 | cursor: pointer; 29 | background-image: url('fullscreen.svg'); 30 | width: 26px; 31 | height: 26px; 32 | margin: 4px; 33 | background-size: 26px 26px; 34 | } 35 | #gx-fullscreen:hover { 36 | background-image: url('fullscreen-hover.svg'); 37 | } 38 | #gx-canvas { 39 | border: 1px solid #222; 40 | background-color: #000; 41 | } 42 | #gx-load-screen { 43 | display: block; 44 | text-align: center; 45 | margin: auto; 46 | width: 100%; 47 | height: 100%; 48 | font-size: 24px; 49 | color: #ccc; 50 | border: 1px solid #000; 51 | text-decoration: none; 52 | background-position: center center; 53 | background-image: url('play.png'); 54 | background-repeat: no-repeat; 55 | background-color: #000; 56 | } 57 | #gx-load-screen:hover { 58 | background-color: #333; 59 | } 60 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/favicon.ico -------------------------------------------------------------------------------- /githelp.js: -------------------------------------------------------------------------------- 1 | var GitHelp = new function() { 2 | var navhist = []; 3 | var page = document.getElementById("help-page"); 4 | var sidebar = document.getElementById("help-sidebar"); 5 | var sconverter = new showdown.Converter(); 6 | sconverter.setFlavor("github"); 7 | 8 | baseUrl = location.protocol + "//" + location.host + location.pathname; 9 | if (baseUrl.endsWith("/index.html")) { 10 | baseUrl = baseUrl.replace("/index.html", ""); 11 | } 12 | if (baseUrl.endsWith("/")) { 13 | baseUrl = baseUrl.slice(0, -1); 14 | } 15 | 16 | function fixlinks(div, project) { 17 | var a = div.getElementsByTagName("a"); 18 | for (var i=0; i < a.length; i++) { 19 | if (a[i].href) { 20 | var href = a[i].href; 21 | if (href.startsWith("https://github.com") && href.includes("/wiki/")) { 22 | href = href.replace("/wiki/", "/"); 23 | href = href.replace("github.com", "raw.githubusercontent.com/wiki") + ".md"; 24 | a[i].href = "javascript:GitHelp.wikinav('" + href + "')"; 25 | } 26 | else if (href.startsWith("#") || href.startsWith(baseUrl + "/index.html#")) { 27 | // do nothing 28 | } 29 | else if (href.startsWith(baseUrl + "#") || href.startsWith(baseUrl + "/#")) { 30 | a[i].href = href.substring(href.indexOf("#")); 31 | } 32 | else if (href.startsWith(baseUrl + "?") || 33 | href.startsWith(baseUrl + "/?") || 34 | href.startsWith(baseUrl + "/index.html?")) { 35 | a[i].target = "_blank"; 36 | } 37 | else if (href.startsWith(baseUrl + "/")) { 38 | href = href.replace(baseUrl + "/", ""); 39 | href = "https://raw.githubusercontent.com/wiki/" + project + "/" + href + ".md"; 40 | a[i].href = "javascript:GitHelp.wikinav('" + href + "')"; 41 | } 42 | else { 43 | a[i].target = "_blank"; 44 | } 45 | } 46 | } 47 | } 48 | 49 | this.navhome = function() { 50 | navhist = []; 51 | this.wikinav("https://raw.githubusercontent.com/wiki/boxgaming/qbjs/QBasic-Language-Support.md"); 52 | return false; 53 | }; 54 | 55 | this.navback = function() { 56 | if (navhist.length > 1) { 57 | navhist.pop(); 58 | var prev = navhist.pop(); 59 | this.wikinav(prev); 60 | } 61 | return false; 62 | }; 63 | 64 | this.navto = function(id) { 65 | document.getElementById(id).scrollIntoView(); 66 | }; 67 | 68 | this.wikinav = async function(url) { 69 | var project; 70 | var pageName; 71 | var res = await QB.func_Fetch(url); 72 | 73 | navhist.push(url); 74 | page.scrollTop = 0; 75 | 76 | project = url.replace("https://raw.githubusercontent.com/wiki/", ""); 77 | project = project.substring(0, project.lastIndexOf("/")); 78 | pageName = url.substring(url.lastIndexOf("/")+1); 79 | pageName = pageName.replaceAll("-", " "); 80 | pageName = pageName.replace(".md", ""); 81 | 82 | page.innerHTML = "

" + pageName + "

" + sconverter.makeHtml(res.text); 83 | fixlinks(page, project); 84 | 85 | res = await QB.func_Fetch("https://raw.githubusercontent.com/wiki/" + project + "/_Sidebar.md"); 86 | sidebar.innerHTML = sconverter.makeHtml(res.text); 87 | fixlinks(sidebar, project); 88 | } 89 | }; -------------------------------------------------------------------------------- /gx/__gx_font_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/gx/__gx_font_default.png -------------------------------------------------------------------------------- /gx/__gx_font_default_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/gx/__gx_font_default_black.png -------------------------------------------------------------------------------- /img/about-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 16 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /img/about.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 16 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /img/console-hide-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 20 | 34 | 42 | 49 | 50 | -------------------------------------------------------------------------------- /img/console-hide.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 20 | 34 | 42 | 49 | 50 | -------------------------------------------------------------------------------- /img/console-show-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 33 | 35 | 43 | 57 | 65 | 66 | -------------------------------------------------------------------------------- /img/console-show.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 33 | 35 | 43 | 57 | 65 | 66 | -------------------------------------------------------------------------------- /img/delete-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 31 | 33 | 35 | 36 | 38 | 46 | 54 | 55 | -------------------------------------------------------------------------------- /img/delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 31 | 33 | 35 | 36 | 38 | 46 | 54 | 55 | -------------------------------------------------------------------------------- /img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/img/file.png -------------------------------------------------------------------------------- /img/file.svg: -------------------------------------------------------------------------------- 1 | 2 | 55 | -------------------------------------------------------------------------------- /img/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/img/folder.png -------------------------------------------------------------------------------- /img/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 33 | -------------------------------------------------------------------------------- /img/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/img/fullscreen.png -------------------------------------------------------------------------------- /img/gx-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/img/gx-logo.png -------------------------------------------------------------------------------- /img/methods-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 32 | 34 | 38 | 42 | 46 | 47 | -------------------------------------------------------------------------------- /img/methods.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 32 | 34 | 38 | 42 | 46 | 47 | -------------------------------------------------------------------------------- /img/new-folder-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 36 | 42 | 48 | 55 | 62 | 63 | -------------------------------------------------------------------------------- /img/new-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 36 | 42 | 48 | 55 | 62 | 63 | -------------------------------------------------------------------------------- /img/open-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 31 | 33 | 35 | 36 | 38 | 43 | 48 | 49 | -------------------------------------------------------------------------------- /img/open.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 31 | 33 | 35 | 36 | 38 | 43 | 48 | 49 | -------------------------------------------------------------------------------- /img/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/img/play.png -------------------------------------------------------------------------------- /img/refresh-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 38 | -------------------------------------------------------------------------------- /img/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/img/refresh.png -------------------------------------------------------------------------------- /img/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 38 | -------------------------------------------------------------------------------- /img/run-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 37 | 41 | 42 | -------------------------------------------------------------------------------- /img/run.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 37 | 41 | 42 | -------------------------------------------------------------------------------- /img/settings-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 37 | 41 | 42 | -------------------------------------------------------------------------------- /img/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /img/share-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 37 | 41 | 45 | 52 | 53 | -------------------------------------------------------------------------------- /img/share.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 37 | 41 | 45 | 52 | 53 | -------------------------------------------------------------------------------- /img/slide-left-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 20 | 34 | 38 | 46 | 47 | -------------------------------------------------------------------------------- /img/slide-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 15 | 22 | 35 | 39 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /img/slide-right-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 35 | 38 | 46 | 60 | 64 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /img/slide-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 19 | 32 | 36 | 43 | 44 | -------------------------------------------------------------------------------- /img/stop-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 33 | 38 | 51 | 52 | -------------------------------------------------------------------------------- /img/stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 33 | 38 | 51 | 52 | -------------------------------------------------------------------------------- /img/upload-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 30 | 32 | 37 | 46 | 58 | 67 | 73 | 74 | -------------------------------------------------------------------------------- /img/upload.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 30 | 32 | 37 | 46 | 58 | 67 | 73 | 74 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QBJS 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 |
41 | 42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |   59 |
60 |
61 |
62 |
63 |
Console
Javascript
Files
Help
64 |
65 |
66 |
67 |
68 |
69 |
70 | / 71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | Home 81 | Back 82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | 92 | 93 |
94 | 95 |
96 | 97 | 98 |
Copy the link below to share your code:
99 |
100 |
Launch Mode: 101 | 106 |
107 | Export 108 | Close 109 | Test 110 |
111 | 112 | 113 |
114 | No main.bas file found.
115 | Select main program source file: 116 |
117 | 118 |
119 | Ok 120 | Cancel 121 |
122 |
123 | 124 | 125 |
Select a theme:
126 | 133 |

134 |
Key Bindings:
135 | 139 |

140 |
Convert Source Encoding:
141 |
Code Page 437 to UTF
142 |
143 | Close 144 |
145 |
146 | 147 | 148 |
149 |
Methods
Imports
150 |
151 |
152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 |
MethodTypeArguments
160 |
161 | 171 | Close 172 |
173 | 174 | 175 |
176 | 177 |

QBJS - QBasic for the Web!

178 |

Version: 0.9.1

179 |

180 |

181 | QBJS brings the fun and accessibility of QBasic to the browser.
182 | Learn more:
183 |

188 |

189 |

Copyright (c) 2022-2024 boxgaming

190 |
191 | Close 192 |
193 |
194 |
195 | 196 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /lib/graphics/2d.bas: -------------------------------------------------------------------------------- 1 | Const DEFAULT = "butt" 2 | Const ROUND = "round" 3 | Const SQUARE = "square" 4 | 5 | Export DEFAULT, ROUND, SQUARE 6 | Export RotoZoom, SaveImage 7 | Export Triangle, FillTriangle, RoundRect, FillRoundRect, InvertRect 8 | Export Shadow, ShadowOff, LineWidth, LineCap, LineDash, LineDashOff 9 | Export FillCircle, Ellipse, FillEllipse, Curve, Bezier 10 | 11 | Sub RotoZoom (centerX As Long, centerY As Long, img As Long, xScale As Single, yScale As Single, rotation As Single) 12 | Dim newImage As Long 13 | Dim imgWidth, imgHeight 14 | imgWidth = _Width(img) 15 | imgHeight = _Height(img) 16 | Dim destImg As Long 17 | destImage = _Dest 18 | 19 | $If Javascript Then 20 | var origImg = QB.getImage(img); 21 | var cx = imgWidth / 2.0; 22 | var cy = imgHeight / 2.0; 23 | 24 | var destImg = QB.getImage(destImg); 25 | var ctx = destImg.getContext("2d"); 26 | ctx.save(); 27 | 28 | ctx.translate(centerX, centerY); 29 | ctx.rotate((Math.PI / 180) * rotation); 30 | ctx.scale(xScale, yScale); 31 | ctx.drawImage(origImg, -cx, -cy); 32 | 33 | ctx.restore(); 34 | $End If 35 | End Sub 36 | 37 | Sub SaveImage (imageId As Long, filepath As String) 38 | $If Javascript Then 39 | var vfs = QB.vfs(); 40 | var filename = vfs.getFileName(filepath); 41 | var ppath = vfs.getParentPath(filepath); 42 | var pnode = null; 43 | if (ppath == "") { pnode = QB.vfsCwd(); } 44 | else { pnode = vfs.getNode(ppath, QB.vfsCwd()); } 45 | if (!pnode) { 46 | throw Object.assign(new Error("Path not found: [" + ppath + "]"), { _stackDepth: 1 }); 47 | } 48 | var img = QB.getImage(imageId); 49 | var f = vfs.createFile(filename, pnode); 50 | var complete = false; 51 | await img.toBlob(async function(b) { 52 | var ab = await b.arrayBuffer(); 53 | vfs.writeData(f, ab); 54 | complete = true; 55 | }); 56 | while (!complete) { 57 | await GX.sleep(10); 58 | } 59 | $End If 60 | 61 | End Sub 62 | 63 | Sub FillCircle (x As Long, y As Long, radius As Long, clr As _Unsigned Long) 64 | Dim destImg As Long 65 | destImg = _Dest 66 | 67 | If clr = undefined Then 68 | clr = _DefaultColor 69 | End If 70 | 71 | $If Javascript Then 72 | var c = QB.colorToRGB(clr); 73 | var ctx = QB.getImage(destImg).getContext("2d"); 74 | ctx.fillStyle = c.rgba(); 75 | ctx.beginPath(); 76 | ctx.arc(x, y, radius, 0, 2 * Math.PI); 77 | ctx.fill(); 78 | $End If 79 | End Sub 80 | 81 | Sub Ellipse(x As Long, y As Long, radiusX As Long, radiusY As Long, rotation As Integer, clr As _Unsigned Long) 82 | _Ellipse x, y, radiusX, radiusY, rotation, clr, false 83 | End Sub 84 | 85 | Sub FillEllipse (x As Long, y As Long, radiusX As Long, radiusY As Long, rotation As Integer, clr As _Unsigned Long) 86 | _Ellipse x, y, radiusX, radiusY, rotation, clr, true 87 | End Sub 88 | 89 | Sub _Ellipse (x As Long, y As Long, radiusX As Long, radiusY As Long, rotation As Integer, clr As _Unsigned Long, fill) 90 | Dim destImg As Long 91 | destImg = _Dest 92 | If rotation = undefined Then 93 | rotation = 0 94 | End If 95 | If clr = undefined Then 96 | clr = _DefaultColor 97 | End If 98 | 99 | $If Javascript Then 100 | var c = QB.colorToRGB(clr); 101 | var ctx = QB.getImage(destImg).getContext("2d"); 102 | if (fill) { 103 | ctx.fillStyle = c.rgba(); 104 | } else { 105 | ctx.strokeStyle = c.rgba(); 106 | ctx.lineWidth = QB.defaultLineWidth(); 107 | } 108 | ctx.beginPath(); 109 | ctx.ellipse(x, y, radiusX, radiusY, rotation * (Math.PI / 180), 0, 2 * Math.PI); 110 | if (fill) { 111 | ctx.fill(); 112 | } else { 113 | ctx.stroke(); 114 | } 115 | $End If 116 | End Sub 117 | 118 | Sub Triangle (x1 As Long, y1 As Long, x2 As Long, y2 As Long, x3 As Long, y3 As Long, clr As _Unsigned Long) 119 | _Triangle x1, y1, x2, y2, x3, y3, clr, false 120 | End Sub 121 | 122 | Sub FillTriangle (x1 As Long, y1 As Long, x2 As Long, y2 As Long, x3 As Long, y3 As Long, clr As _Unsigned Long) 123 | _Triangle x1, y1, x2, y2, x3, y3, clr, true 124 | End Sub 125 | 126 | Sub _Triangle (x1 As Long, y1 As Long, x2 As Long, y2 As Long, x3 As Long, y3 As Long, clr As _Unsigned Long, fill) 127 | Dim destImg As Long 128 | destImg = _Dest 129 | 130 | If clr = undefined Then 131 | clr = _DefaultColor 132 | End If 133 | 134 | $If Javascript Then 135 | var c = QB.colorToRGB(clr); 136 | var ctx = QB.getImage(destImg).getContext("2d"); 137 | if (fill) { 138 | ctx.fillStyle = c.rgba(); 139 | } else { 140 | ctx.strokeStyle = c.rgba(); 141 | ctx.lineWidth = QB.defaultLineWidth(); 142 | } 143 | ctx.beginPath(); 144 | ctx.moveTo(x1, y1); 145 | ctx.lineTo(x2, y2); 146 | ctx.lineTo(x3, y3); 147 | ctx.lineTo(x1, y1); 148 | if (fill) { 149 | ctx.fill(); 150 | } else { 151 | ctx.stroke(); 152 | } 153 | $End If 154 | End Sub 155 | 156 | Sub RoundRect (x As Long, y As Long, w As Long, h As Long, radius As Integer, clr As _Unsigned Long) 157 | _RoundRect x, y, w, h, radius, clr, false 158 | End Sub 159 | 160 | Sub FillRoundRect (x As Long, y As Long, w As Long, h As Long, radius As Integer, clr As _Unsigned Long) 161 | _RoundRect x, y, w, h, radius, clr, true 162 | End Sub 163 | 164 | Sub _RoundRect (x As Long, y As Long, w As Long, h As Long, radius As Integer, clr As _Unsigned Long, fill) 165 | Dim destImg As Long 166 | destImg = _Dest 167 | 168 | If clr = undefined Then 169 | clr = _DefaultColor 170 | End If 171 | 172 | $If Javascript Then 173 | var c = QB.colorToRGB(clr); 174 | var ctx = QB.getImage(destImg).getContext("2d"); 175 | if (fill) { 176 | ctx.fillStyle = c.rgba(); 177 | } else { 178 | ctx.strokeStyle = c.rgba(); 179 | ctx.lineWidth = QB.defaultLineWidth(); 180 | } 181 | ctx.beginPath(); 182 | ctx.roundRect(x, y, w, h, radius); 183 | if (fill) { 184 | ctx.fill(); 185 | } else { 186 | ctx.stroke(); 187 | } 188 | $End If 189 | End Sub 190 | 191 | Sub InvertRect (x As Long, y As Long, width As Long, height As Long, fill As Integer) 192 | Dim destImg As Long 193 | destImg = _Dest 194 | 195 | $If Javascript Then 196 | var ctx = QB.getImage(destImg).getContext("2d"); 197 | ctx.beginPath(); 198 | ctx.globalCompositeOperation="difference"; 199 | if (fill) { 200 | ctx.fillStyle = "white"; 201 | ctx.rect(x, y, width, height); 202 | ctx.fill(); 203 | } 204 | else { 205 | ctx.lineWidth = QB.defaultLineWidth(); 206 | ctx.strokeStyle = "white"; 207 | ctx.rect(x, y, width, height); 208 | ctx.stroke(); 209 | } 210 | ctx.globalCompositeOperation = "source-over"; 211 | $End If 212 | End Sub 213 | 214 | Sub Shadow (clr As Long, offsetX As Long, offsetY As Long, blur As Long) 215 | Dim destImg As Long 216 | destImg = _Dest 217 | 218 | If offsetX = undefined Then 219 | offsetX = 0 220 | End If 221 | If offsetY = undefined Then 222 | offsetY = 0 223 | End If 224 | If blur = undefined Then 225 | blur = 0 226 | End If 227 | If clr = undefined Then 228 | clr = _DefaultColor 229 | End If 230 | 231 | $If Javascript Then 232 | var c = QB.colorToRGB(clr); 233 | var ctx = QB.getImage(destImg).getContext("2d"); 234 | ctx.shadowBlur = blur; 235 | ctx.shadowColor = c.rgba(); 236 | ctx.shadowOffsetX = offsetX; 237 | ctx.shadowOffsetY = offsetY; 238 | $End If 239 | End Sub 240 | 241 | Sub ShadowOff 242 | Dim destImg As Long 243 | destImg = _Dest 244 | 245 | $If Javascript Then 246 | var ctx = QB.getImage(destImg).getContext("2d"); 247 | ctx.shadowBlur = 0; 248 | ctx.shadowColor = "#000"; 249 | ctx.shadowOffsetX = 0; 250 | ctx.shadowOffsetY = 0; 251 | $End If 252 | End Sub 253 | 254 | Sub LineWidth (w As Long) 255 | $If Javascript Then 256 | QB.defaultLineWidth(w); 257 | $End If 258 | End Sub 259 | 260 | Function LineWidth 261 | $If Javascript Then 262 | LineWidth = QB.defaultLineWidth(); 263 | $End If 264 | End Function 265 | 266 | Sub LineCap (cap As String) 267 | $If Javascript Then 268 | var ctx = QB.getImage(QB.func__Dest()).getContext("2d"); 269 | ctx.lineCap = cap; 270 | $End If 271 | End Sub 272 | 273 | Function LineCap 274 | $If Javascript Then 275 | var ctx = QB.getImage(QB.func__Dest()).getContext("2d"); 276 | LineCap = ctx.lineCap; 277 | $End If 278 | End Function 279 | 280 | Sub LineDash (dashLen As Integer, dashSpace As Integer) 281 | $If Javascript Then 282 | var ctx = QB.getImage(QB.func__Dest()).getContext("2d"); 283 | if (dashLen > 0) { 284 | var dl = dashLen; 285 | var ds = dashLen; 286 | if (dashSpace > 0) { 287 | ds = dashSpace; 288 | } 289 | ctx.setLineDash([dl, ds]) 290 | } 291 | else { 292 | ctx.setLineDash([]) 293 | } 294 | $End If 295 | End Sub 296 | 297 | Sub LineDashOff 298 | $If Javascript Then 299 | var ctx = QB.getImage(QB.func__Dest()).getContext("2d"); 300 | ctx.setLineDash([]) 301 | $End If 302 | End Sub 303 | 304 | Sub Curve (sx As Long, sy As Long, cx As Long, cy As Long, ex As Long, ey as Long, clr As _Unsigned Long) 305 | If clr = undefined Then 306 | clr = _DefaultColor 307 | End If 308 | 309 | $If Javascript Then 310 | var c = QB.colorToRGB(clr); 311 | var ctx = QB.getImage(QB.func__Dest()).getContext("2d"); 312 | ctx.strokeStyle = c.rgba(); 313 | ctx.lineWidth = QB.defaultLineWidth(); 314 | ctx.beginPath(); 315 | ctx.moveTo(sx, sy); 316 | ctx.quadraticCurveTo(cx, cy, ex, ey); 317 | ctx.stroke(); 318 | $End If 319 | End Sub 320 | 321 | Sub Bezier (sx As Long, sy As Long, cx1 As Long, cy1 As Long, cx2 As Long, cy2 As Long, ex As Long, ey as Long, clr As _Unsigned Long) 322 | If clr = undefined Then 323 | clr = _DefaultColor 324 | End If 325 | 326 | $If Javascript Then 327 | var c = QB.colorToRGB(clr); 328 | var ctx = QB.getImage(QB.func__Dest()).getContext("2d"); 329 | ctx.strokeStyle = c.rgba(); 330 | ctx.lineWidth = QB.defaultLineWidth(); 331 | ctx.beginPath(); 332 | ctx.moveTo(sx, sy); 333 | ctx.bezierCurveTo(cx1, cy1, cx2, cy2, ex, ey); 334 | ctx.stroke(); 335 | $End If 336 | End Sub -------------------------------------------------------------------------------- /lib/io/fs.bas: -------------------------------------------------------------------------------- 1 | Const ALL = 0 2 | Const FILE = 1 3 | Const DIRECTORY = 2 4 | 5 | Export ALL, FILE, DIRECTORY 6 | Export ListDirectory, DownloadFile, UploadFile 7 | 8 | Function ListDirectory(dirpath As String, listMode As Integer) 9 | If dirpath = undefined Then dirpath = "" 10 | If listMode = undefined Then listMode = ALL 11 | 12 | Dim children As Object 13 | 14 | $If Javascript Then 15 | var vfs = QB.vfs(); 16 | var pnode = null; 17 | if (dirpath == "") { 18 | pnode = QB.vfsCwd(); 19 | } 20 | else { 21 | pnode = vfs.getNode(dirpath, QB.vfsCwd()); 22 | } 23 | if (!pnode) { 24 | throw Object.assign(new Error("Path not found: [" + dirpath + "]"), { _stackDepth: 1 }); 25 | } 26 | var mode = null; 27 | if (listMode == DIRECTORY) { 28 | mode = vfs.DIRECTORY; 29 | } 30 | else if (listMode == FILE) { 31 | mode = vfs.FILE; 32 | } 33 | children = vfs.getChildren(pnode, mode); 34 | $End If 35 | 36 | Dim type, i As Integer 37 | Dim results(children.length) As Object 38 | For i = 0 To children.length - 1 39 | results(i+1).name = children[i].name 40 | $If Javascript Then 41 | if (children[i].type == vfs.FILE) { 42 | type = FILE; 43 | } 44 | else { 45 | type = DIRECTORY; 46 | } 47 | $End If 48 | results(i+1).type = type 49 | Next i 50 | 51 | ListDirectory = results 52 | End Function 53 | 54 | Sub DownloadFile(filepath As String) 55 | $If Javascript Then 56 | var vfs = QB.vfs(); 57 | var file = vfs.getNode(filepath, QB.vfsCwd()); 58 | if (!file || file.type != vfs.FILE) { 59 | throw Object.assign(new Error("File not found: [" + filepath + "]"), { _stackDepth: 1 }); 60 | } 61 | await QB.downloadFile(new Blob([file.data]), file.name); 62 | $End If 63 | End Sub 64 | 65 | Sub UploadFile(destpath As String, filter As String, fnCallback As Object) 66 | $If Javascript Then 67 | var vfs = QB.vfs(); 68 | var parentDir = null; 69 | if (destpath == "/") { 70 | parentDir = QB.vfs().rootDirectory(); 71 | destpath = ""; 72 | } 73 | else if (destpath == undefined || destpath == "") { 74 | parentDir = QB.vfsCwd(); 75 | } 76 | else { 77 | parentDir = vfs.getNode(destpath, QB.vfsCwd()); 78 | if (!parentDir) { 79 | throw Object.assign(new Error("Path not found: [" + destpath + "]"), { _stackDepth: 1 }); 80 | } 81 | else if (parentDir && parentDir.type != vfs.DIRECTORY) { 82 | throw Object.assign(new Error("Path is not a directory: [" + destpath + "]"), { _stackDepth: 1 }); 83 | } 84 | } 85 | var fileInput = document.getElementById("upload-file-input"); 86 | if (fileInput == null) { 87 | fileInput = document.createElement("input"); 88 | fileInput.id = "upload-file-input"; 89 | fileInput.type = "file"; 90 | } 91 | fileInput.value = null; 92 | if (filter != undefined) { 93 | fileInput.accept = filter; 94 | } 95 | fileInput.onchange = function(event) { 96 | if (event.target.files.length > 0) { 97 | var f = event.target.files[0]; 98 | var fr = new FileReader(); 99 | fr.onload = function() { 100 | var file = vfs.createFile(f.name, parentDir); 101 | vfs.writeData(file, fr.result); 102 | 103 | if (fnCallback) { 104 | fnCallback(vfs.fullPath(file)); 105 | } 106 | } 107 | fr.readAsArrayBuffer(f); 108 | } 109 | }; 110 | fileInput.click(); 111 | $End If 112 | End Sub 113 | -------------------------------------------------------------------------------- /lib/web/console.bas: -------------------------------------------------------------------------------- 1 | Const NONE = "NONE" 2 | Const FATAL = "FATAL" 3 | Const ERROR = "ERROR" 4 | Const WARN = "WARN" 5 | Const INFO = "INFO" 6 | Const DEBUG = "DEBUG" 7 | Const TRACE = "TRACE" 8 | Const ALL = "ALL" 9 | 10 | Export NONE, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL 11 | Export Log, LogLevel, Echo 12 | 13 | Dim Shared levelMap(0) 14 | levelMap(NONE) = 0 15 | levelMap(FATAL) = 1 16 | levelMap(ERROR) = 2 17 | levelMap(WARN) = 3 18 | levelMap(INFO) = 4 19 | levelMap(DEBUG) = 5 20 | levelMap(TRACE) = 6 21 | levelMap(ALL) = 7 22 | Dim Shared level As Integer 23 | level = 4 24 | 25 | Sub LogLevel (newLevel) 26 | level = levelMap(newLevel) 27 | End Sub 28 | 29 | Function LogLevel 30 | LogLevel = level 31 | End Function 32 | 33 | Sub Log (msg As String, msgType As String) 34 | If msgType = undefined Then msgType = INFO 35 | Dim ll As Integer 36 | ll = levelMap(msgType) 37 | If ll > level Then Exit Sub 38 | 39 | $If Javascript Then 40 | var t = document.querySelector("#warning-container table"); 41 | if (!t || IDE.mode() != "ide") { 42 | console.log(msgType + ":" + msg); 43 | return; 44 | } 45 | var errorLine = await IDE.getErrorLine(new Error(), 1); 46 | var tr = document.createElement("tr"); 47 | IDE.addWarningCell(tr, msgType); 48 | IDE.addWarningCell(tr, ":"); 49 | IDE.addWarningCell(tr, errorLine); 50 | IDE.addWarningCell(tr, ":"); 51 | IDE.addWarningCell(tr, await func_EscapeHtml(msg), "99%"); 52 | tr.codeLine = errorLine - 1; 53 | tr.onclick = IDE.gotoWarning; 54 | t.append(tr); 55 | var container = document.getElementById("output-content"); 56 | container.scrollTop = container.scrollHeight; 57 | IDE.changeTab("console"); 58 | IDE.showConsole(true); 59 | $End If 60 | End Sub 61 | 62 | Sub Echo (msg As String) 63 | $If Javascript Then 64 | var t = document.querySelector("#warning-container table"); 65 | if (!t || IDE.mode() != "ide") { 66 | console.log(msg); 67 | return; 68 | } 69 | var tr = document.createElement("tr"); 70 | IDE.addWarningCell(tr, await func_EscapeHtml(msg)); 71 | tr.firstChild.colSpan = "5"; 72 | t.append(tr); 73 | var container = document.getElementById("output-content"); 74 | container.scrollTop = container.scrollHeight; 75 | IDE.changeTab("console"); 76 | IDE.showConsole(true); 77 | $End If 78 | End Sub 79 | 80 | Function EscapeHtml (text As String) 81 | text = GXSTR_Replace(text, "&", "&") 82 | text = GXSTR_Replace(text, "<", "<") 83 | text = GXSTR_Replace(text, ">", ">") 84 | text = GXSTR_Replace(text, Chr$(34), """) 85 | text = GXSTR_Replace(text, "'", "'") 86 | EscapeHtml = text 87 | End Function -------------------------------------------------------------------------------- /lib/web/dom.bas: -------------------------------------------------------------------------------- 1 | Export Add, Alert, Confirm, Create, Event, Container, Get, GetImage, Remove, Prompt 2 | 3 | $If Javascript Then 4 | if (QB._domElements) { 5 | var e = null; 6 | while (e = QB._domElements.pop()) { 7 | e.remove(); 8 | } 9 | } 10 | else { 11 | QB._domElements = []; 12 | } 13 | 14 | if (QB._domEvents) { 15 | while (e = QB._domEvents.pop()) { 16 | e.target.removeEventListener(e.eventType, e.callbackFn); 17 | } 18 | } 19 | else { 20 | QB._domEvents = []; 21 | } 22 | $End If 23 | 24 | Sub Alert (text As String) 25 | $If Javascript Then 26 | alert(text); 27 | $End If 28 | End Sub 29 | 30 | Function Confirm (text As String) 31 | $If Javascript Then 32 | Confirm = confirm(text) ? -1 : 0; 33 | $End If 34 | End Function 35 | 36 | Sub Add (e As Object, parent As Object, beforeElement As Object) 37 | $If Javascript Then 38 | if (typeof e == "string") { 39 | e = document.getElementById(e); 40 | } 41 | 42 | if (parent == undefined || parent == "") { 43 | parent = await func_Container(); 44 | } 45 | else if (typeof parent == "string") { 46 | parent = document.getElementById(parent); 47 | } 48 | 49 | if (beforeElement == undefined || beforeElement == "") { 50 | beforeElement = null; 51 | } 52 | else if (typeof beforeElement == "string") { 53 | beforeElement = document.getElementById(beforeElement); 54 | } 55 | 56 | parent.insertBefore(e, beforeElement); 57 | $End If 58 | End Sub 59 | 60 | Function Create (etype As String, parent As Object, content As String, eid As String, beforeElement As Object) 61 | $If Javascript Then 62 | var e = document.createElement(etype); 63 | if (eid != undefined && eid != "") { 64 | e.id = eid; 65 | } 66 | e.className = "qbjs"; 67 | 68 | if (content != undefined) { 69 | if (e.value != undefined) { 70 | e.value = content; 71 | } 72 | if (e.innerHTML != undefined) { 73 | e.innerHTML = content; 74 | } 75 | } 76 | 77 | QB._domElements.push(e); 78 | await sub_Add(e, parent, beforeElement); 79 | Create = e; 80 | $End If 81 | End Function 82 | 83 | Sub Create (etype As String, parent As Object, content As String, eid As String, beforeElement As Object) 84 | Dim e 85 | e = Create(etype, parent, content, eid, beforeElement) 86 | End Sub 87 | 88 | Sub Event (target As Object, eventType As String, callbackFn As Object) 89 | $If Javascript Then 90 | if (typeof target == "string") { 91 | target = document.getElementById(target); 92 | } 93 | var callbackWrapper = async function(event) { 94 | var result = await callbackFn(event); 95 | if (result == false) { 96 | event.preventDefault(); 97 | } 98 | return result; 99 | } 100 | target.addEventListener(eventType, callbackWrapper); 101 | QB._domEvents.push({ target: target, eventType: eventType, callbackFn: callbackWrapper}); 102 | $End If 103 | End Sub 104 | 105 | Function Container 106 | $If Javascript Then 107 | Container = document.getElementById("gx-container"); 108 | $End If 109 | End Function 110 | 111 | Function Get (eid As String) 112 | $If Javascript Then 113 | Get = document.getElementById(eid); 114 | $End If 115 | End Function 116 | 117 | Function GetImage (imageId As Integer) 118 | $If Javascript Then 119 | GetImage = QB.getImage(imageId); 120 | $End If 121 | End Function 122 | 123 | Sub Remove (e As Object) 124 | $If Javascript Then 125 | if (typeof e == "string") { 126 | e = document.getElementById(e); 127 | } 128 | if (e != undefined && e != null) { 129 | e.remove(); 130 | } 131 | $End If 132 | End Sub 133 | 134 | Function Prompt (text As String, defaultValue As String) 135 | Dim result As String 136 | $If Javascript Then 137 | result = prompt(text, defaultValue); 138 | if (!result) { result = ""; } 139 | $End If 140 | Prompt = result; 141 | End Function -------------------------------------------------------------------------------- /lib/web/storage.bas: -------------------------------------------------------------------------------- 1 | Const LOCAL = "LOCAL" 2 | Const SESSION = "SESSION" 3 | 4 | Export LOCAL, SESSION 5 | Export Clear, Get, Key, Length, Set, Remove 6 | 7 | $If Javascript Then 8 | function _storage(stype) { 9 | return (stype == SESSION) ? sessionStorage : localStorage; 10 | } 11 | $End If 12 | 13 | Sub Clear (stype As String) 14 | $If Javascript Then 15 | _storage(stype).clear(); 16 | $End If 17 | End Sub 18 | 19 | Function Get (key As String, stype As String) 20 | $If Javascript Then 21 | var result = _storage(stype).getItem(key); 22 | if (result == null) { result = ""; } 23 | Get = result 24 | $End If 25 | End Function 26 | 27 | Function Key (idx As Integer, stype As String) 28 | $If Javascript Then 29 | Key = _storage(stype).key(idx); 30 | $End If 31 | End Function 32 | 33 | Function Length (stype As String) 34 | $If Javascript Then 35 | Length = _storage(stype).length; 36 | $End If 37 | End Function 38 | 39 | Sub Set (key As String, value As String, stype As String) 40 | $If Javascript Then 41 | _storage(stype).setItem(key, value); 42 | $End If 43 | End Sub 44 | 45 | Sub Remove (key As String, stype As String) 46 | $If Javascript Then 47 | _storage(stype).removeItem(key); 48 | $End If 49 | End Sub -------------------------------------------------------------------------------- /logo-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/logo-256.png -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/logo.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "start_url": "https://boxgaming.github.io/qbjs/", 3 | "name": "QBJS", 4 | "icons": [ 5 | { 6 | "src": "logo-256.png", 7 | "type": "image/png", 8 | "sizes": "256x256" 9 | } 10 | ], 11 | "display": "standalone" 12 | } -------------------------------------------------------------------------------- /play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/play.png -------------------------------------------------------------------------------- /qb-console.js: -------------------------------------------------------------------------------- 1 | function _QB() { 2 | // mininimal console-only implementation of the qb.js runtime library 3 | // initially used only for the qbc.js command line compiler 4 | var _rndSeed; 5 | 6 | // Runtime Assertions 7 | function _assertParam(param, arg) { 8 | if (arg == undefined) { arg = 1; } 9 | if (param == undefined) { throw new Error("Method argument " + arg + " is required"); } 10 | } 11 | 12 | function _assertNumber(param, arg) { 13 | if (arg == undefined) { arg = 1; } 14 | if (isNaN(param)) { throw new Error("Number required for method argument " + arg); } 15 | } 16 | 17 | // Array handling methods 18 | // ---------------------------------------------------- 19 | function initArray(dimensions, obj) { 20 | var a = {}; 21 | if (dimensions && dimensions.length > 0) { 22 | a._dimensions = dimensions; 23 | } 24 | else { 25 | // default to single dimension to support Dim myArray() syntax 26 | // for convenient hashtable declaration 27 | a._dimensions = [{l:0,u:1}]; 28 | } 29 | a._newObj = { value: obj }; 30 | return a; 31 | }; 32 | 33 | function resizeArray (a, dimensions, obj, preserve) { 34 | if (!preserve) { 35 | var props = Object.getOwnPropertyNames(a); 36 | for (var i = 0; i < props.length; i++) { 37 | if (props[i] != "_newObj") { 38 | delete a[props[i]]; 39 | } 40 | } 41 | } 42 | if (dimensions && dimensions.length > 0) { 43 | a._dimensions = dimensions; 44 | } 45 | else { 46 | // default to single dimension to support Dim myArray() syntax 47 | // for convenient hashtable declaration 48 | a._dimensions = [{l:0,u:1}]; 49 | } 50 | } 51 | 52 | function arrayValue(a, indexes) { 53 | var value = a; 54 | for (var i=0; i < indexes.length; i++) { 55 | if (value[indexes[i]] == undefined) { 56 | if (i == indexes.length-1) { 57 | value[indexes[i]] = JSON.parse(JSON.stringify(a._newObj)); 58 | } 59 | else { 60 | value[indexes[i]] = {}; 61 | } 62 | } 63 | value = value[indexes[i]]; 64 | } 65 | 66 | return value; 67 | } 68 | 69 | function halt() { 70 | /*_haltedFlag = true; 71 | _runningFlag = false; 72 | _inputMode = false; 73 | GX.soundStopAll(); 74 | toggleCursor(true);*/ 75 | } 76 | 77 | function halted() { 78 | return false; 79 | //return _haltedFlag; 80 | }; 81 | 82 | function autoLimit() { 83 | /*var timeElapsed = new Date() - _lastLimitTime; 84 | if (timeElapsed > 1000) { 85 | _flushAllScreenCache(); 86 | await GX.sleep(1); 87 | _lastLimitTime = new Date(); 88 | }*/ 89 | } 90 | 91 | function func_Asc(value, pos) { 92 | _assertParam(value); 93 | if (pos == undefined) { 94 | pos = 0; 95 | } 96 | else { 97 | _assertNumber(pos, 2); 98 | pos--; 99 | } 100 | 101 | var c = String(value).charCodeAt(pos); 102 | //var uc = _ccharMap[c]; 103 | //if (uc) { c = uc; } 104 | return c; 105 | } 106 | 107 | function func_Chr(charCode) { 108 | _assertNumber(charCode); 109 | //var uc = _ucharMap[charCode]; 110 | //if (uc) { charCode = uc; } 111 | return String.fromCharCode(charCode); 112 | } 113 | 114 | function func_Command() { 115 | return ""; 116 | } 117 | 118 | async function sub_Fetch (url, fetchRes) { 119 | const fs = require("fs"); 120 | const data = fs.readFileSync(url, 'utf8'); 121 | fetchRes.ok = true; 122 | fetchRes.text = data; 123 | } 124 | 125 | async function func_Fetch(url) { 126 | var fetchRes = {}; 127 | await QB.sub_Fetch(url, fetchRes); 128 | return fetchRes; 129 | } 130 | 131 | function func_Left(value, n) { 132 | _assertParam(value, 1); 133 | _assertNumber(n, 2); 134 | return String(value).substring(0, n); 135 | } 136 | 137 | function func_InStr(arg1, arg2, arg3) { 138 | _assertParam(arg1, 1); 139 | _assertParam(arg2, 2); 140 | var startIndex = 0; 141 | var strSource = ""; 142 | var strSearch = ""; 143 | if (arg3 != undefined) { 144 | startIndex = arg1-1; 145 | strSource = String(arg2); 146 | strSearch = String(arg3); 147 | } 148 | else { 149 | strSource = String(arg1); 150 | strSearch = String(arg2); 151 | } 152 | return strSource.indexOf(strSearch, startIndex)+1; 153 | } 154 | 155 | function func__InStrRev(arg1, arg2, arg3) { 156 | _assertParam(arg1, 1); 157 | _assertParam(arg2, 2); 158 | var startIndex = +Infinity; 159 | var strSource = ""; 160 | var strSearch = ""; 161 | if (arg3 != undefined) { 162 | startIndex = arg1-1; 163 | strSource = String(arg2); 164 | strSearch = String(arg3); 165 | } 166 | else { 167 | strSource = String(arg1); 168 | strSearch = String(arg2); 169 | } 170 | return strSource.lastIndexOf(strSearch, startIndex)+1; 171 | } 172 | 173 | function func_LCase(value) { 174 | _assertParam(value); 175 | return String(value).toLowerCase(); 176 | }; 177 | 178 | function func_Left(value, n) { 179 | _assertParam(value, 1); 180 | _assertNumber(n, 2); 181 | return String(value).substring(0, n); 182 | } 183 | 184 | function func_Len(value) { 185 | _assertParam(value); 186 | return String(value).length; 187 | } 188 | 189 | function func_LTrim(value) { 190 | _assertParam(value); 191 | return String(value).trimStart(); 192 | } 193 | 194 | function func_Mid(value, n, len) { 195 | _assertParam(value, 1); 196 | _assertNumber(n, 2); 197 | if (len == undefined) { 198 | return String(value).substring(n-1); 199 | } 200 | else { 201 | return String(value).substring(n-1, n+len-1); 202 | } 203 | } 204 | 205 | function func_Right(value, n) { 206 | _assertParam(value, 1); 207 | _assertNumber(n, 2); 208 | if (value == undefined) { 209 | return ""; 210 | } 211 | var s = String(value); 212 | return s.substring(s.length-n, s.length); 213 | } 214 | 215 | function func__Round(value) { 216 | _assertNumber(value); 217 | if (value < 0) { 218 | return -Math.round(-value); 219 | } else { 220 | return Math.round(value); 221 | } 222 | } 223 | 224 | function func_Rnd(n) { 225 | if (n == undefined) {n = 1;} 226 | if (n != 0) { 227 | if (n < 0) { 228 | const buffer = new ArrayBuffer(8); 229 | const view = new DataView(buffer); 230 | view.setFloat32(0, n, false); 231 | var m = view.getUint32(0); 232 | _rndSeed = (m & 0xFFFFFF) + ((m & 0xFF000000) >>> 24); 233 | } 234 | _rndSeed = (_rndSeed * 16598013 + 12820163) & 0xFFFFFF; 235 | } 236 | return _rndSeed / 0x1000000; 237 | } 238 | 239 | function func_RTrim(value) { 240 | _assertParam(value); 241 | return String(value).trimEnd(); 242 | } 243 | 244 | function func_Str(value) { 245 | return String(value); 246 | } 247 | 248 | function func_String(ccount, s) { 249 | _assertNumber(ccount, 1); 250 | _assertParam(s, 2); 251 | if (typeof s === "string") { 252 | s = s.substring(0, 1); 253 | } 254 | else { 255 | s = String.fromCharCode(s); 256 | } 257 | return "".padStart(ccount, s); 258 | } 259 | 260 | function func__Trim(value) { 261 | _assertParam(value); 262 | return value.trim(); 263 | } 264 | 265 | function func_UBound(a, dimension) { 266 | _assertParam(a); 267 | if (dimension == undefined) { 268 | dimension = 1; 269 | } 270 | else { 271 | _assertNumber(dimension, 2); 272 | } 273 | return a._dimensions[dimension-1].u; 274 | } 275 | 276 | function func_UCase(value) { 277 | _assertParam(value); 278 | return String(value).toUpperCase(); 279 | } 280 | 281 | return { 282 | initArray: initArray, 283 | resizeArray: resizeArray, 284 | arrayValue: arrayValue, 285 | autoLimit: autoLimit, 286 | halt: halt, 287 | halted: halted, 288 | func_Asc: func_Asc, 289 | func_Chr: func_Chr, 290 | func_Command: func_Command, 291 | func_Fetch: func_Fetch, 292 | sub_Fetch: sub_Fetch, 293 | func_InStr: func_InStr, 294 | func__InStrRev: func__InStrRev, 295 | func_LCase: func_LCase, 296 | func_Left: func_Left, 297 | func_Len: func_Len, 298 | func_LTrim: func_LTrim, 299 | func_Mid: func_Mid, 300 | func_Right: func_Right, 301 | func__Round: func__Round, 302 | func_Rnd: func_Rnd, 303 | func_RTrim: func_RTrim, 304 | func_Str: func_Str, 305 | func_String: func_String, 306 | func__Trim: func__Trim, 307 | func_UBound: func_UBound, 308 | func_UCase: func_UCase 309 | }; 310 | } 311 | 312 | module.exports.QB = _QB; -------------------------------------------------------------------------------- /qbc.js: -------------------------------------------------------------------------------- 1 | compile(); 2 | 3 | async function compile(src) { 4 | const qbc = await require("./qb2js.js").QBCompiler(); 5 | const fs = require("fs"); 6 | 7 | const sourceFile = process.argv[2]; 8 | const data = fs.readFileSync(sourceFile, "utf8"); 9 | 10 | var result = ""; 11 | if (sourceFile.endsWith("qb2js.bas")) { 12 | qbc.setSelfConvert(); 13 | result = await qbc.compile(data); 14 | } 15 | else { 16 | result = "async function __qbjs_run() {\n" + await qbc.compile(data) + "\n}"; 17 | } 18 | fs.writeFileSync(process.argv[3], result, "utf8"); 19 | 20 | var warnings = qbc.getWarnings(); 21 | for (var i=0; i < warnings.length; i++) { 22 | var mtype = warnings[i].mtype ? "ERROR" : "WARN"; 23 | console.log(mtype + ":" + warnings[i].line + ":" + warnings[i].text); 24 | } 25 | } -------------------------------------------------------------------------------- /qbjs.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/qbjs.woff2 -------------------------------------------------------------------------------- /samples/apps/new-message.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/apps/new-message.ogg -------------------------------------------------------------------------------- /samples/apps/paint.bas: -------------------------------------------------------------------------------- 1 | $TouchMouse 2 | Dim Shared tool, cp, btnUndo 3 | CreateToolbar 4 | 5 | Dim fimage, cimage 6 | fimage = _NewImage(_Width, _Height) 7 | cimage = _NewImage(_Width, _Height) 8 | 9 | Dim drawing, lastX, lastY, startX, startY, radius 10 | Do 11 | If _Resize Then 12 | Dim tmp 13 | tmp = fimage 14 | Screen _NewImage(_ResizeWidth - 2, _ResizeHeight - 42) 15 | fimage = _NewImage(_ResizeWidth - 2, _ResizeHeight - 42) 16 | _PutImage (0, 0), tmp, fimage 17 | End If 18 | 19 | If _MouseButton(1) Then 20 | If Not drawing Then 21 | _PutImage (0, 0), cimage, fimage 22 | _FreeImage cimage 23 | cimage = _NewImage(_Width, _Height) 24 | lastX = _MouseX 25 | lastY = _MouseY 26 | startX = lastX 27 | startY = lastY 28 | drawing = -1 29 | btnUndo.disabled = false 30 | Else 31 | If tool.value = "Freehand" Then 32 | _Dest cimage 33 | Line (lastX, lastY)-(_MouseX, _MouseY), SelectedColor 34 | lastX = _MouseX 35 | lastY = _MouseY 36 | _Dest 0 37 | 38 | ElseIf tool.value = "Line" Then 39 | PrepDrawDest 40 | Line (startX, startY)-(_MouseX, _MouseY), SelectedColor 41 | _Dest 0 42 | 43 | ElseIf tool.value = "Rectangle" Then 44 | PrepDrawDest 45 | Line (startX, startY)-(_MouseX, _MouseY), SelectedColor, B 46 | _Dest 0 47 | 48 | ElseIf tool.value = "Filled Rectangle" Then 49 | PrepDrawDest 50 | Line (startX, startY)-(_MouseX, _MouseY), SelectedColor, BF 51 | _Dest 0 52 | 53 | ElseIf tool.value = "Circle" Then 54 | PrepDrawDest 55 | If Abs(_MouseX - startX) > Abs(_MouseY - startY) Then 56 | radius = Abs(_MouseX - startX) 57 | Else 58 | radius = Abs(_MouseY - startY) 59 | End If 60 | Circle (startX, startY), radius, SelectedColor 61 | _Dest 0 62 | 63 | ElseIf tool.value = "Filled Circle" Then 64 | PrepDrawDest 65 | If Abs(_MouseX - startX) > Abs(_MouseY - startY) Then 66 | radius = Abs(_MouseX - startX) 67 | Else 68 | radius = Abs(_MouseY - startY) 69 | End If 70 | Dim r 71 | For r = 0 To radius Step .3 72 | Circle (startX, startY), r, SelectedColor 73 | Next r 74 | _Dest 0 75 | End If 76 | End If 77 | Else 78 | drawing = 0 79 | End If 80 | Cls 81 | _PutImage (0, 0), fimage 82 | _PutImage (0, 0), cimage 83 | _Limit 30 84 | Loop 85 | 86 | Sub PrepDrawDest 87 | _FreeImage cimage 88 | cimage = _NewImage(_Width, _Height) 89 | _Dest cimage 90 | End Sub 91 | 92 | Sub OnBtnUndo 93 | _FreeImage cimage 94 | cimage = _NewImage(640, 400) 95 | btnUndo.disabled = true 96 | End Sub 97 | 98 | Sub CreateToolbar 99 | DomGetImage(0).style.cursor = "crosshair" 100 | DomGetImage(0).style.position = "absolute" 101 | DomGetImage(0).style.border = "0" 102 | DomGetImage(0).style.margin = "0" 103 | DomGetImage(0).style.top = "1px" 104 | DomGetImage(0).style.left = "1px" 105 | 106 | Dim panel 107 | panel = DomCreate("div") 108 | DomCreate "span", panel, "Tool: " 109 | tool = DomCreate("select", panel) 110 | DomCreate "span", panel, "Color: " 111 | cp = DomCreate("input", panel) 112 | cp.type = "color" 113 | cp.value = "#ffffff" 114 | 115 | btnUndo = DomCreate("button", panel, "Undo") 116 | btnUndo.style.float = "right" 117 | btnUndo.style.padding = "5px 10px" 118 | btnUndo.disabled = true 119 | DomEvent btnUndo, "click", sub_OnBtnUndo 120 | 121 | panel.style.textAlign = "left" 122 | panel.style.position = "absolute" 123 | panel.style.bottom = "2px" 124 | panel.style.left = "2px" 125 | panel.style.right = "2px" 126 | panel.style.padding = "5px" 127 | panel.style.fontFamily = "Arial, helvetica, sans-serif" 128 | panel.style.fontSize = ".85em" 129 | panel.style.border = "1px solid #666" 130 | panel.style.backgroundColor = "#333" 131 | panel.style.verticalAlign = "middle" 132 | 133 | InitToolList 134 | End Sub 135 | 136 | Sub InitToolList 137 | tool.style.marginRight = "15px" 138 | tool.style.padding = "5px" 139 | tool.style.verticalAlign = "top" 140 | DomCreate "option", tool, "Freehand" 141 | DomCreate "option", tool, "Line" 142 | DomCreate "option", tool, "Rectangle" 143 | DomCreate "option", tool, "Filled Rectangle" 144 | DomCreate "option", tool, "Circle" 145 | DomCreate "option", tool, "Filled Circle" 146 | End Sub 147 | 148 | Function SelectedColor 149 | Dim r, g, b, c 150 | c = cp.value 151 | 152 | $If Javascript 153 | r = parseInt(c.substr(1,2), 16) 154 | g = parseInt(c.substr(3,2), 16) 155 | b = parseInt(c.substr(5,2), 16) 156 | $End If 157 | 158 | SelectedColor = _RGB(r, g, b) 159 | End Function -------------------------------------------------------------------------------- /samples/games/banner-for-bplus.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/games/banner-for-bplus.zip -------------------------------------------------------------------------------- /samples/games/banner.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/games/banner.zip -------------------------------------------------------------------------------- /samples/games/banner2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/games/banner2.zip -------------------------------------------------------------------------------- /samples/games/banner3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/games/banner3.zip -------------------------------------------------------------------------------- /samples/games/fall-runner.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/games/fall-runner.zip -------------------------------------------------------------------------------- /samples/include/caman.bas: -------------------------------------------------------------------------------- 1 | Export Render 2 | 3 | IncludeJS "https://cdnjs.cloudflare.com/ajax/libs/camanjs/4.0.0/caman.full.min.js" 4 | 5 | Dim lastOpts As Object 6 | 7 | Sub Render(opts, imageId) 8 | $If Javascript Then 9 | var complete = false; 10 | if (imageId == undefined) { imageId = 0; } 11 | Caman(QB.getImage(imageId), function() { 12 | if (opts.brightness) { this.brightness(opts.brightness); } 13 | if (opts.contrast) { this.contrast(opts.contrast); } 14 | if (opts.saturation) { this.saturation(opts.saturation); } 15 | if (opts.vibrance) { this.vibrance(opts.vibrance); } 16 | if (opts.exposure) { this.exposure(opts.exposure); } 17 | if (opts.hue) { this.hue(opts.hue); } 18 | if (opts.sepia) { this.sepia(opts.sepia); } 19 | if (opts.gamma) { this.gamma(opts.gamma); } 20 | if (opts.noise) { this.noise(opts.noise); } 21 | if (opts.clip) { this.clip(opts.clip); } 22 | if (opts.sharpen) { this.sharpen(opts.sharpen); } 23 | if (opts.blur) { this.stackBlur(opts.blur); } 24 | this.render(); 25 | lastOpts = opts; 26 | complete = true; 27 | }); 28 | while (!complete) { await GX.sleep(10); } 29 | $End If 30 | End Sub -------------------------------------------------------------------------------- /samples/include/gif/LZWEncoder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class handles LZW encoding 3 | * Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott. 4 | * @author Kevin Weiner (original Java version - kweiner@fmsware.com) 5 | * @author Thibault Imbert (AS3 version - bytearray.org) 6 | * @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif) 7 | * @version 0.1 AS3 implementation 8 | */ 9 | 10 | LZWEncoder = function() { 11 | 12 | var exports = {}; 13 | var EOF = -1; 14 | var imgW; 15 | var imgH; 16 | var pixAry; 17 | var initCodeSize; 18 | var remaining; 19 | var curPixel; 20 | 21 | // GIFCOMPR.C - GIF Image compression routines 22 | // Lempel-Ziv compression based on 'compress'. GIF modifications by 23 | // David Rowley (mgardi@watdcsu.waterloo.edu) 24 | // General DEFINEs 25 | 26 | var BITS = 12; 27 | var HSIZE = 5003; // 80% occupancy 28 | 29 | // GIF Image compression - modified 'compress' 30 | // Based on: compress.c - File compression ala IEEE Computer, June 1984. 31 | // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) 32 | // Jim McKie (decvax!mcvax!jim) 33 | // Steve Davies (decvax!vax135!petsd!peora!srd) 34 | // Ken Turkowski (decvax!decwrl!turtlevax!ken) 35 | // James A. Woods (decvax!ihnp4!ames!jaw) 36 | // Joe Orost (decvax!vax135!petsd!joe) 37 | 38 | var n_bits; // number of bits/code 39 | var maxbits = BITS; // user settable max # bits/code 40 | var maxcode; // maximum code, given n_bits 41 | var maxmaxcode = 1 << BITS; // should NEVER generate this code 42 | var htab = []; 43 | var codetab = []; 44 | var hsize = HSIZE; // for dynamic table sizing 45 | var free_ent = 0; // first unused entry 46 | 47 | // block compression parameters -- after all codes are used up, 48 | // and compression rate changes, start over. 49 | 50 | var clear_flg = false; 51 | 52 | // Algorithm: use open addressing double hashing (no chaining) on the 53 | // prefix code / next character combination. We do a variant of Knuth's 54 | // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime 55 | // secondary probe. Here, the modular division first probe is gives way 56 | // to a faster exclusive-or manipulation. Also do block compression with 57 | // an adaptive reset, whereby the code table is cleared when the compression 58 | // ratio decreases, but after the table fills. The variable-length output 59 | // codes are re-sized at this point, and a special CLEAR code is generated 60 | // for the decompressor. Late addition: construct the table according to 61 | // file size for noticeable speed improvement on small files. Please direct 62 | // questions about this implementation to ames!jaw. 63 | 64 | var g_init_bits; 65 | var ClearCode; 66 | var EOFCode; 67 | 68 | // output 69 | // Output the given code. 70 | // Inputs: 71 | // code: A n_bits-bit integer. If == -1, then EOF. This assumes 72 | // that n_bits =< wordsize - 1. 73 | // Outputs: 74 | // Outputs code to the file. 75 | // Assumptions: 76 | // Chars are 8 bits long. 77 | // Algorithm: 78 | // Maintain a BITS character long buffer (so that 8 codes will 79 | // fit in it exactly). Use the VAX insv instruction to insert each 80 | // code in turn. When the buffer fills up empty it and start over. 81 | 82 | var cur_accum = 0; 83 | var cur_bits = 0; 84 | var masks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF]; 85 | 86 | // Number of characters so far in this 'packet' 87 | var a_count; 88 | 89 | // Define the storage for the packet accumulator 90 | var accum = []; 91 | 92 | var LZWEncoder = exports.LZWEncoder = function LZWEncoder(width, height, pixels, color_depth) { 93 | imgW = width; 94 | imgH = height; 95 | pixAry = pixels; 96 | initCodeSize = Math.max(2, color_depth); 97 | }; 98 | 99 | // Add a character to the end of the current packet, and if it is 254 100 | // characters, flush the packet to disk. 101 | var char_out = function char_out(c, outs) { 102 | accum[a_count++] = c; 103 | if (a_count >= 254) flush_char(outs); 104 | }; 105 | 106 | // Clear out the hash table 107 | // table clear for block compress 108 | 109 | var cl_block = function cl_block(outs) { 110 | cl_hash(hsize); 111 | free_ent = ClearCode + 2; 112 | clear_flg = true; 113 | output(ClearCode, outs); 114 | }; 115 | 116 | // reset code table 117 | var cl_hash = function cl_hash(hsize) { 118 | for (var i = 0; i < hsize; ++i) htab[i] = -1; 119 | }; 120 | 121 | var compress = exports.compress = function compress(init_bits, outs) { 122 | 123 | var fcode; 124 | var i; /* = 0 */ 125 | var c; 126 | var ent; 127 | var disp; 128 | var hsize_reg; 129 | var hshift; 130 | 131 | // Set up the globals: g_init_bits - initial number of bits 132 | g_init_bits = init_bits; 133 | 134 | // Set up the necessary values 135 | clear_flg = false; 136 | n_bits = g_init_bits; 137 | maxcode = MAXCODE(n_bits); 138 | 139 | ClearCode = 1 << (init_bits - 1); 140 | EOFCode = ClearCode + 1; 141 | free_ent = ClearCode + 2; 142 | 143 | a_count = 0; // clear packet 144 | 145 | ent = nextPixel(); 146 | 147 | hshift = 0; 148 | for (fcode = hsize; fcode < 65536; fcode *= 2) 149 | ++hshift; 150 | hshift = 8 - hshift; // set hash code range bound 151 | 152 | hsize_reg = hsize; 153 | cl_hash(hsize_reg); // clear hash table 154 | 155 | output(ClearCode, outs); 156 | 157 | outer_loop: while ((c = nextPixel()) != EOF) { 158 | fcode = (c << maxbits) + ent; 159 | i = (c << hshift) ^ ent; // xor hashing 160 | 161 | if (htab[i] == fcode) { 162 | ent = codetab[i]; 163 | continue; 164 | } 165 | 166 | else if (htab[i] >= 0) { // non-empty slot 167 | 168 | disp = hsize_reg - i; // secondary hash (after G. Knott) 169 | if (i === 0) disp = 1; 170 | 171 | do { 172 | if ((i -= disp) < 0) 173 | i += hsize_reg; 174 | 175 | if (htab[i] == fcode) { 176 | ent = codetab[i]; 177 | continue outer_loop; 178 | } 179 | } while (htab[i] >= 0); 180 | } 181 | 182 | output(ent, outs); 183 | ent = c; 184 | if (free_ent < maxmaxcode) { 185 | codetab[i] = free_ent++; // code -> hashtable 186 | htab[i] = fcode; 187 | } 188 | else cl_block(outs); 189 | } 190 | 191 | // Put out the final code. 192 | output(ent, outs); 193 | output(EOFCode, outs); 194 | }; 195 | 196 | // ---------------------------------------------------------------------------- 197 | var encode = exports.encode = function encode(os) { 198 | os.writeByte(initCodeSize); // write "initial code size" byte 199 | remaining = imgW * imgH; // reset navigation variables 200 | curPixel = 0; 201 | compress(initCodeSize + 1, os); // compress and write the pixel data 202 | os.writeByte(0); // write block terminator 203 | }; 204 | 205 | // Flush the packet to disk, and reset the accumulator 206 | var flush_char = function flush_char(outs) { 207 | if (a_count > 0) { 208 | outs.writeByte(a_count); 209 | outs.writeBytes(accum, 0, a_count); 210 | a_count = 0; 211 | } 212 | }; 213 | 214 | var MAXCODE = function MAXCODE(n_bits) { 215 | return (1 << n_bits) - 1; 216 | }; 217 | 218 | // ---------------------------------------------------------------------------- 219 | // Return the next pixel from the image 220 | // ---------------------------------------------------------------------------- 221 | 222 | var nextPixel = function nextPixel() { 223 | if (remaining === 0) return EOF; 224 | --remaining; 225 | var pix = pixAry[curPixel++]; 226 | return pix & 0xff; 227 | }; 228 | 229 | var output = function output(code, outs) { 230 | 231 | cur_accum &= masks[cur_bits]; 232 | 233 | if (cur_bits > 0) cur_accum |= (code << cur_bits); 234 | else cur_accum = code; 235 | 236 | cur_bits += n_bits; 237 | 238 | while (cur_bits >= 8) { 239 | char_out((cur_accum & 0xff), outs); 240 | cur_accum >>= 8; 241 | cur_bits -= 8; 242 | } 243 | 244 | // If the next entry is going to be too big for the code size, 245 | // then increase it, if possible. 246 | 247 | if (free_ent > maxcode || clear_flg) { 248 | 249 | if (clear_flg) { 250 | 251 | maxcode = MAXCODE(n_bits = g_init_bits); 252 | clear_flg = false; 253 | 254 | } else { 255 | 256 | ++n_bits; 257 | if (n_bits == maxbits) maxcode = maxmaxcode; 258 | else maxcode = MAXCODE(n_bits); 259 | } 260 | } 261 | 262 | if (code == EOFCode) { 263 | 264 | // At EOF, write the rest of the buffer. 265 | while (cur_bits > 0) { 266 | char_out((cur_accum & 0xff), outs); 267 | cur_accum >>= 8; 268 | cur_bits -= 8; 269 | } 270 | 271 | flush_char(outs); 272 | } 273 | }; 274 | 275 | LZWEncoder.apply(this, arguments); 276 | return exports; 277 | }; 278 | -------------------------------------------------------------------------------- /samples/include/gif/animated.bas: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /samples/include/maths.bas: -------------------------------------------------------------------------------- 1 | Export increment As Plus1 2 | Export factorial AS Factorial 3 | 4 | Function increment (num) 5 | increment = num + 1 6 | End Function 7 | 8 | Function factorial (num) 9 | Dim res 10 | $If Javascript Then 11 | if (num === 0 || num === 1) { 12 | num = 1; 13 | } 14 | else { 15 | for (var i = num - 1; i >= 1; i--) { 16 | num *= i; 17 | } 18 | } 19 | $End If 20 | factorial = num 21 | End Function -------------------------------------------------------------------------------- /samples/include/test.bas: -------------------------------------------------------------------------------- 1 | Export GetStuff As GetThings 2 | Export DoStuff 3 | 4 | Dim foo 5 | foo = "somthing" 6 | 7 | Function GetStuff 8 | GetStuff = "got the stuff" 9 | End Function 10 | 11 | Sub DoStuff 12 | Print "do the stuff" 13 | End Sub 14 | 15 | 16 | -------------------------------------------------------------------------------- /samples/project/animated-gif.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/animated-gif.zip -------------------------------------------------------------------------------- /samples/project/bplus-banner-builder.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/bplus-banner-builder.zip -------------------------------------------------------------------------------- /samples/project/cayman.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/cayman.zip -------------------------------------------------------------------------------- /samples/project/custom-font.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/custom-font.zip -------------------------------------------------------------------------------- /samples/project/overworld.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/overworld.zip -------------------------------------------------------------------------------- /samples/project/simple.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/simple.zip -------------------------------------------------------------------------------- /samples/project/sleighless.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgaming/qbjs/7315b6ffd0f274f25aeec20d7c3f346737f2a006/samples/project/sleighless.zip -------------------------------------------------------------------------------- /service-worker.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Google Inc. All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | // Names of the two caches used in this version of the service worker. 15 | // Change to v2, etc. when you update any of the local resources, which will 16 | // in turn trigger the install event again. 17 | const PRECACHE = 'precache-v28'; 18 | const RUNTIME = 'runtime'; 19 | const PREFIX = (self.location.origin.indexOf("github.io") == -1) ? "/" : "/qbjs/"; 20 | 21 | // A list of local resources we always want to be cached. 22 | const PRECACHE_URLS = [ 23 | PREFIX + 'codemirror/themes/qb45.css', 24 | PREFIX + 'codemirror/themes/qb64-vscode.css', 25 | PREFIX + 'codemirror/themes/qbjs.css', 26 | PREFIX + 'codemirror/themes/vscode-dark.css', 27 | PREFIX + 'codemirror/themes/win-classic.css', 28 | PREFIX + 'codemirror/active-line.js', 29 | PREFIX + 'codemirror/annotatescrollbar.js', 30 | PREFIX + 'codemirror/codemirror.min.css', 31 | PREFIX + 'codemirror/codemirror.min.js', 32 | PREFIX + 'codemirror/dialog.css', 33 | PREFIX + 'codemirror/dialog.js', 34 | PREFIX + 'codemirror/matchesonscrollbar.css', 35 | PREFIX + 'codemirror/matchesonscrollbar.js', 36 | PREFIX + 'codemirror/qb-lang.js', 37 | PREFIX + 'codemirror/search.js', 38 | PREFIX + 'codemirror/searchcursor.js', 39 | PREFIX + 'codemirror/vim.js', 40 | PREFIX + 'export/auto.html', 41 | PREFIX + 'export/fullscreen-hover.svg', 42 | PREFIX + 'export/fullscreen.svg', 43 | PREFIX + 'export/logo.png', 44 | PREFIX + 'export/play.html', 45 | PREFIX + 'export/qbjs.css', 46 | PREFIX + 'gx/__gx_font_default_black.png', 47 | PREFIX + 'gx/__gx_font_default.png', 48 | PREFIX + 'gx/gx.js', 49 | PREFIX + 'img/about-hover.svg', 50 | PREFIX + 'img/about.svg', 51 | PREFIX + 'img/console-hide-hover.svg', 52 | PREFIX + 'img/console-hide.svg', 53 | PREFIX + 'img/console-show-hover.svg', 54 | PREFIX + 'img/console-show.svg', 55 | PREFIX + 'img/delete-hover.svg', 56 | PREFIX + 'img/delete.svg', 57 | PREFIX + 'img/file.svg', 58 | PREFIX + 'img/folder.svg', 59 | PREFIX + 'img/fullscreen.png', 60 | PREFIX + 'img/methods-hover.svg', 61 | PREFIX + 'img/methods.svg', 62 | PREFIX + 'img/new-folder-hover.svg', 63 | PREFIX + 'img/new-folder.svg', 64 | PREFIX + 'img/open-hover.svg', 65 | PREFIX + 'img/open.svg', 66 | PREFIX + 'img/play.png', 67 | PREFIX + 'img/refresh.svg', 68 | PREFIX + 'img/run-hover.svg', 69 | PREFIX + 'img/run.svg', 70 | PREFIX + 'img/save-hover.svg', 71 | PREFIX + 'img/save.svg', 72 | PREFIX + 'img/settings-hover.svg', 73 | PREFIX + 'img/settings.svg', 74 | PREFIX + 'img/share-hover.svg', 75 | PREFIX + 'img/share.svg', 76 | PREFIX + 'img/slide-left-hover.svg', 77 | PREFIX + 'img/slide-left.svg', 78 | PREFIX + 'img/slide-right-hover.svg', 79 | PREFIX + 'img/slide-right.svg', 80 | PREFIX + 'img/stop-hover.svg', 81 | PREFIX + 'img/stop.svg', 82 | PREFIX + 'img/upload-hover.svg', 83 | PREFIX + 'img/upload.svg', 84 | PREFIX + 'lib/graphics/2d.bas', 85 | PREFIX + 'lib/io/fs.bas', 86 | PREFIX + 'lib/web/console.bas', 87 | PREFIX + 'lib/web/dom.bas', 88 | PREFIX + 'lib/web/storage.bas', 89 | PREFIX + 'util/jszip.min.js', 90 | PREFIX + 'util/lzutf8.js', 91 | PREFIX + 'util/pako.2.1.0.min.js', 92 | PREFIX + 'util/shorty.min.js', 93 | PREFIX + 'util/showdown.min.js', 94 | PREFIX + 'util/showdown.min.js.map', 95 | PREFIX + 'favicon.ico', 96 | PREFIX + 'githelp.js', 97 | PREFIX + 'index.html', 98 | PREFIX, // '/', // Alias for index.html 99 | PREFIX + 'logo-256.png', 100 | PREFIX + 'logo.png', 101 | PREFIX + 'manifest.json', 102 | PREFIX + 'play.png', 103 | PREFIX + 'qb.js', 104 | PREFIX + 'qb2js.js', 105 | PREFIX + 'qbjs-ide.css', 106 | PREFIX + 'qbjs-ide.js', 107 | PREFIX + 'qbjs.woff2', 108 | PREFIX + 'vfs.js' 109 | ]; 110 | 111 | // The install handler takes care of precaching the resources we always need. 112 | self.addEventListener('install', event => { 113 | event.waitUntil( 114 | caches.open(PRECACHE) 115 | .then(cache => cache.addAll(PRECACHE_URLS)) 116 | .then(self.skipWaiting()) 117 | ); 118 | }); 119 | 120 | // The activate handler takes care of cleaning up old caches. 121 | self.addEventListener('activate', event => { 122 | const currentCaches = [PRECACHE, RUNTIME]; 123 | event.waitUntil( 124 | caches.keys().then(cacheNames => { 125 | return cacheNames.filter(cacheName => !currentCaches.includes(cacheName)); 126 | }).then(cachesToDelete => { 127 | return Promise.all(cachesToDelete.map(cacheToDelete => { 128 | return caches.delete(cacheToDelete); 129 | })); 130 | }).then(() => self.clients.claim()) 131 | ); 132 | }); 133 | 134 | // The fetch handler serves responses for same-origin resources from a cache. 135 | // If no response is found, it populates the runtime cache with the response 136 | // from the network before returning it to the page. 137 | self.addEventListener('fetch', event => { 138 | // Skip cross-origin requests, like those for Google Analytics. 139 | if (event.request.url.startsWith(self.location.origin)) { 140 | event.respondWith( 141 | caches.match(event.request).then(cachedResponse => { 142 | if (cachedResponse) { 143 | return cachedResponse; 144 | } 145 | 146 | return caches.open(RUNTIME).then(cache => { 147 | return fetch(event.request).then(response => { 148 | // Put a copy of the response in the runtime cache. 149 | return cache.put(event.request, response.clone()).then(() => { 150 | return response; 151 | }); 152 | }); 153 | }); 154 | }) 155 | ); 156 | } 157 | }); -------------------------------------------------------------------------------- /tools/qb2js.bi: -------------------------------------------------------------------------------- 1 | ' Define web-only types and methods needed for compilation 2 | Type FetchResponse 3 | ok As Integer 4 | status As Integer 5 | statusText As String 6 | text As String 7 | End Type 8 | 9 | Sub Fetch (url As String, response As FetchResponse): End Sub 10 | -------------------------------------------------------------------------------- /util/shorty.min.js: -------------------------------------------------------------------------------- 1 | /* shorty.js - by enki - https://enkimute.github.io */ 2 | !function(t,i,e){"undefined"!=typeof module&&module.exports?module.exports=e():"function"==typeof define&&define.amd?define(t,e):i[t]=e()}("Shorty",this,function(){function t(t){this.tokensize=t||10,this.reset(!0)}return t.prototype.reset=function(t){t===!0&&(this.nodes=[{up:0,weight:0}],this.nyt=0,this.nodecount=0),this.data="",this.curpos=0,this.bitCount=7,this.bitChar=0},t.prototype.findNode=function(t){for(var i=this.nodes.length-1;i>0;i--)if("undefined"!=typeof this.nodes[i].symbol&&this.nodes[i].symbol==t)return i;return 0},t.prototype.addNode=function(t){return this.nodecount>=2046?0:(this.nodes[++this.nodecount]={up:this.nyt,symbol:t,weight:1},this.nodes[++this.nodecount]={up:this.nyt,weight:0},this.nodes[this.nyt].weight+=1,this.nyt=this.nodecount,this.nodes[this.nodecount-2].up!=this.nodecount-2&&this.balanceNode(this.nodes[this.nodecount-2].up),this.nodecount-2)},t.prototype.swapNode=function(t,i){var e=this.nodes[t].symbol,s=this.nodes[i].symbol,o=this.nodes[t].weight;this.nodes[t].symbol=s,this.nodes[i].symbol=e,this.nodes[t].weight=this.nodes[i].weight,this.nodes[i].weight=o;for(var h=this.nodes.length-1;h>0;h--)this.nodes[h].up==t?this.nodes[h].up=i:this.nodes[h].up==i&&(this.nodes[h].up=t)},t.prototype.balanceNode=function(t){for(;;){for(var i=t,e=this.nodes[t].weight;i>1&&this.nodes[i-1].weight==e;)i--;if(i!=t&&i!=this.nodes[t].up&&(this.swapNode(i,t),t=i),this.nodes[t].weight++,this.nodes[t].up==t)return;t=this.nodes[t].up}},t.prototype.emitNode=function(t){for(var i=[];0!=t;)i.unshift(t%2),t=this.nodes[t].up;for(var e=0;e8&&this.emitBit(8&i),this.tokensize>4&&this.emitBit(4&i),this.tokensize>2&&this.emitBit(2&i),this.tokensize>1&&this.emitBit(1&i);for(var e=0;e8?8*this.readBit():0)+(this.tokensize>4?4*this.readBit():0)+(this.tokensize>2?2*this.readBit():0)+(this.tokensize>1?this.readBit():0)+1,i="";t--;)i+=this.readByte();return i}for(var e=0;;){var s=this.readBit();if(void 0==this.nodes[e].symbol)for(var o=0;;o++)if(this.nodes[o].up==e&&o!=e&&o%2==s){e=o;break}if(void 0!=this.nodes[e].symbol||0==this.nodes[e].weight){if(this.nodes[e].weight)return this.nodes[e].symbol;for(var t=(this.tokensize>8?8*this.readBit():0)+(this.tokensize>4?4*this.readBit():0)+(this.tokensize>2?2*this.readBit():0)+(this.tokensize>1?this.readBit():0)+1,i="";t--;)i+=this.readByte();return i}}},t.prototype.emitBit=function(t){t&&(this.bitChar+=1<=0;i--)this.emitBit(t>>i&1)},t.prototype.readBit=function(){if(this.curpos==8*this.data.length)throw"done";var t=this.data.charCodeAt(this.curpos>>3)>>(7-this.curpos&7)&1;return this.curpos++,t},t.prototype.readByte=function(){res=0;for(var t=0;8>t;t++)res+=(128>>t)*this.readBit();return String.fromCharCode(res)},t.prototype.deflate=function(t){var i,e,s,o=t.length;for(this.reset(),e=0;o>e;e++){if(i=t[e],this.tokensize>1)if(/[a-zA-Z]/.test(i))for(;o>e+1&&i.lengthe+1&&i.length=0;e++){var s=this.readNode();i+=s;var o=this.findNode(s);o?this.balanceNode(o):this.addNode(s)}}catch(h){}return i},t}); --------------------------------------------------------------------------------