@jscad/web 2.5.4 → 2.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.3.2](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/examples@2.3.1...@jscad/examples@2.3.2) (2022-02-19)
7
+
8
+ **Note:** Version bump only for package @jscad/examples
9
+
10
+
11
+
12
+
13
+
6
14
  ## [2.3.1](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/examples@2.3.0...@jscad/examples@2.3.1) (2021-09-27)
7
15
 
8
16
  **Note:** Version bump only for package @jscad/examples
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jscad/examples",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Example Files for JSCAD",
5
5
  "repository": "https://github.com/jscad/OpenJSCAD.org",
6
6
  "scripts": {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jscad/web",
3
- "version": "2.5.4",
3
+ "version": "2.5.8",
4
4
  "description": "Web Application for JSCAD",
5
5
  "repository": "https://github.com/jscad/OpenJSCAD.org",
6
6
  "main": "src/index.js",
@@ -34,18 +34,18 @@
34
34
  ],
35
35
  "license": "MIT",
36
36
  "dependencies": {
37
- "@jscad/array-utils": "2.1.1",
38
- "@jscad/core": "2.5.4",
39
- "@jscad/examples": "2.3.2",
40
- "@jscad/io": "2.2.4",
41
- "@jscad/modeling": "2.7.2",
42
- "@jscad/regl-renderer": "2.5.4",
37
+ "@jscad/array-utils": "2.1.3",
38
+ "@jscad/core": "2.5.8",
39
+ "@jscad/examples": "2.3.3",
40
+ "@jscad/io": "2.3.1",
41
+ "@jscad/modeling": "2.9.2",
42
+ "@jscad/regl-renderer": "2.5.8",
43
43
  "@most/create": "2.0.1",
44
44
  "brace": "0.11.1",
45
- "codemirror": "5.57.0",
45
+ "codemirror": "5.65.2",
46
46
  "es2015-i18n-tag": "1.6.1",
47
- "file-saver": "2.0.2",
48
- "is-electron": "2.2.0",
47
+ "file-saver": "2.0.5",
48
+ "is-electron": "2.2.1",
49
49
  "morphdom": "2.6.1",
50
50
  "most": "1.8.0",
51
51
  "most-proxy": "3.3.0",
@@ -58,7 +58,7 @@
58
58
  "browserify": "16.5.1",
59
59
  "budo": "11.6.4",
60
60
  "copy-dir": "1.3.0",
61
- "docblock": "0.4.4",
61
+ "docblock": "0.4.5",
62
62
  "uglifyify": "5.0.2"
63
63
  },
64
64
  "collective": {
@@ -66,5 +66,5 @@
66
66
  "url": "https://opencollective.com/openjscad",
67
67
  "logo": "https://opencollective.com/openjscad/logo.txt"
68
68
  },
69
- "gitHead": "b6c5675d2d9a292e0ba24896bf22d0e9dc5d4270"
69
+ "gitHead": "0cebde0166c104e3c08cc05d2c03d9defc7eca26"
70
70
  }
@@ -1,212 +1,133 @@
1
- // ui-editor.js
2
- //
3
- // == OpenJSCAD.org, Copyright (c) 2013-2016, Licensed under MIT License
4
- //
5
- // Editor Functionality
6
- //
7
- // History:
8
- // 2016/06/27: 0.5.1: added local storage by Robert Starkey
9
- // 2016/02/02: 0.4.0: GUI refactored, functionality split up into more files, mostly done by Z3 Dev
10
-
11
- // --- Dependencies
12
- // gProcessor var
13
- // #editor element
14
-
15
- // --- Global Variables
16
- const ace = require('brace')
17
- require('brace/ext/language_tools.js')
18
- ace.acequire('ace/ext/language_tools')
19
- require('brace/mode/javascript')
20
- require('brace/mode/scad')
21
- require('brace/theme/chrome')
22
- require('brace/theme/monokai')
23
- const openscadOpenJscadParser = require('@jscad/openscad-openjscad-translator')
24
-
25
- // See http://ace.ajax.org/#nav=howto
26
- const setUpEditor = (element, gProcessor) => {
27
- const langTools = ace.acequire('ace/ext/language_tools')
28
-
29
- const flowCompleter = {
30
- getCompletions: (editor, session, pos, prefix, callback) => {
31
- // your code
32
- }
33
- }
34
- langTools.addCompleter(flowCompleter)
35
-
36
- let gEditor = null
37
- gEditor = ace.edit(element)
38
- gEditor.$blockScrolling = Infinity
39
- gEditor.getSession().setMode('ace/mode/javascript')
40
- gEditor.setTheme('ace/theme/monokai')
41
- // gEditor.getSession().setMode("ace/mode/javascript");
42
- // gEditor.setTheme("ace/theme/ambiance")
43
- // gEditor.setTheme("ace/theme/chaos")
44
- // gEditor.setTheme('ace/theme/chrome')
45
- // gEditor.setTheme("ace/theme/clouds")
46
- // gEditor.setTheme("ace/theme/cobalt")
47
- // gEditor.setTheme("ace/theme/dawn") // nice
48
- // gEditor.setTheme("ace/theme/dreamweaver")
49
- // gEditor.setTheme("ace/theme/eclipse")
50
- // gEditor.setTheme("ace/theme/github")
51
- // gEditor.setTheme("ace/theme/idle_fingers")
52
- // gEditor.setTheme("ace/theme/katzenmilch")
53
- // gEditor.setTheme("ace/theme/kr_theme")
54
- // gEditor.setTheme("ace/theme/kuroir")
55
- // gEditor.setTheme("ace/theme/merbivore")
56
- // gEditor.setTheme("ace/theme/mono_industrial")
57
- // gEditor.setTheme("ace/theme/monokai")
58
- // gEditor.setTheme("ace/theme/pastel_on_dark")
59
- // gEditor.setTheme("ace/theme/solarized_dark")
60
- // gEditor.setTheme("ace/theme/solarized_light")
61
- // gEditor.setTheme("ace/theme/terminal")
62
- // gEditor.setTheme("ace/theme/textmate")
63
- // gEditor.setTheme("ace/theme/tomorrow")
64
- // gEditor.setTheme("ace/theme/tomorrow_night")
65
- // gEditor.setTheme("ace/theme/tomorrow_night_blue")
66
- // gEditor.setTheme("ace/theme/tomorrow_night_bright")
67
- // gEditor.setTheme("ace/theme/tomorrow_night_eighties")
68
- // gEditor.setTheme("ace/theme/twilight")
69
- // gEditor.setTheme("ace/theme/vibrant_ink")
70
- // gEditor.setTheme("ace/theme/xcode")
71
-
72
- const runExec = (editor) => {
73
- let src = editor.getValue()
74
- if (src.match(/^\/\/!OpenSCAD/i)) {
75
- editor.getSession().setMode('ace/mode/scad')
76
- // FIXME test for the global function first
77
- src = openscadOpenJscadParser.parse(src)
78
- } else {
79
- editor.getSession().setMode('ace/mode/javascript')
80
- }
81
- if (gProcessor !== null) {
82
- // gProcessor.setJsCad(src)
83
- }
84
- }
85
- // enable special keystrokes
86
- gEditor.commands.addCommand({
87
- name: 'setJSCAD',
88
- bindKey: { win: 'F5|Shift-Return', mac: 'F5|Shift-Return' },
89
- exec: runExec
90
- })
91
- document.body.addEventListener('keydown', (evt) => {
92
- if (evt.key === 'F5') {
93
- evt.preventDefault()
94
- runExec(gEditor)
95
- }
96
- })
97
- gEditor.commands.addCommand({
98
- name: 'viewerReset',
99
- bindKey: { win: 'Ctrl-Return', mac: 'Command-Return' },
100
- exec: function (editor) {
101
- if (gProcessor !== null) {
102
- gProcessor.viewer.resetCamera()
103
- }
104
- }
105
- })
106
- gEditor.commands.addCommand({
107
- name: 'saveSource',
108
- bindKey: { win: 'Ctrl-S', mac: 'Command-S' },
109
- exec: function (editor) {
110
- const src = editor.getValue()
111
- localStorage.editorContent = src
112
- gProcessor.setStatus('saved', 'Saved source to browser storage')
113
- }
114
- })
115
- gEditor.commands.addCommand({
116
- name: 'loadSource',
117
- bindKey: { win: 'Ctrl-L', mac: 'Command-L' },
118
- exec: function (editor) {
119
- const src = localStorage.editorContent
120
- if (src && src.length) editor.setValue(src, 1)
121
- gEditor.commands.exec('setJSCAD', editor)
122
- gProcessor.setStatus('loaded', 'Loaded source from browser storage')
123
- }
124
- })
125
- gEditor.commands.addCommand({
126
- name: 'downloadSource',
127
- bindKey: { win: 'Ctrl-Shift-S', mac: 'Command-Shift-S' },
128
- exec: function (editor) {
129
- const src = editor.getValue()
130
- setTimeout(() => {
131
- const blob = new Blob([src], { type: 'text/plain' })
132
- const objectUrl = URL.createObjectURL(blob)
133
- const saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
134
- saveLink.href = objectUrl
135
- saveLink.download = 'MyDesign.jscad'
136
-
137
- const event = new MouseEvent('click')
138
- saveLink.dispatchEvent(event)
139
- }, 0)
140
- }
141
- })
142
- gEditor.commands.addCommand({
143
- name: 'clearStorage',
144
- bindKey: { win: 'Ctrl-Shift-\\', mac: 'Command-Shift-\\' },
145
- exec: function (editor) {
146
- localStorage.clear()
147
- gProcessor.setStatus('cleared', 'Cleared browser storage')
148
- }
149
- })
150
-
151
- return gEditor
1
+ const html = require('nanohtml')
2
+
3
+ const CodeMirror = require('codemirror')
4
+ require('codemirror/mode/javascript/javascript')
5
+ require('codemirror/addon/hint/javascript-hint')
6
+
7
+ const editorOptions = {
8
+ mode: 'javascript',
9
+ indentUnit: 2,
10
+ smartIndent: false,
11
+ indentWithTabs: false,
12
+ lineNumbers: true,
13
+ autofocus: true
152
14
  }
153
15
 
154
- const putSourceInEditor = (gEditor, src, fn) => {
155
- if (gEditor) {
156
- gEditor.setValue(src, -1)
157
- if (src.match(/^\/\/!OpenSCAD/i)) {
158
- gEditor.getSession().setMode('ace/mode/scad')
159
- } else {
160
- gEditor.getSession().setMode('ace/mode/javascript')
161
- }
16
+ let editor
17
+ let wrapper
18
+
19
+ /*
20
+ * Create a file tree from the contents of the editor
21
+ */
22
+ const createFileTree = (editor) => {
23
+ const source = editor.getValue()
24
+ if (source && source.length > 0) {
25
+ return [{ ext: 'js', fullPath: '/changes.js', mimetype: 'javascript', name: 'changes.js', source }]
162
26
  }
27
+ return null
163
28
  }
164
29
 
165
- const getSourceFromEditor = (gEditor) => {
166
- if (gEditor !== null) {
167
- return gEditor.getValue()
30
+ /*
31
+ * Create a HTML wrapper for the editor (single instance)
32
+ */
33
+ const createWrapper = (state, callbackToStream) => {
34
+ if (!wrapper) {
35
+ wrapper = html`
36
+ <section class='popup-menu' id='editor' key='editor' style='visibility:${state.activeTool === 'editor' ? 'visible' : 'hidden'}'>
37
+ <textarea></textarea>
38
+ </section>
39
+ `
40
+ wrapper.onkeydown = (e) => e.stopPropagation()
41
+ wrapper.onkeyup = (e) => e.stopPropagation()
42
+
43
+ // and add the editor
44
+ editor = CodeMirror.fromTextArea(wrapper.firstChild, editorOptions)
45
+
46
+ editor.setOption('extraKeys', {
47
+ Tab: (cm) => {
48
+ const spaces = Array(cm.getOption('indentUnit') + 1).join(' ')
49
+ cm.replaceSelection(spaces)
50
+ }
51
+ })
52
+
53
+ // inject style sheet for the editor
54
+ const head = document.getElementsByTagName('HEAD')[0]
55
+ const link = document.createElement('LINK')
56
+ link.rel = 'stylesheet'
57
+ link.href = './css/codemirror.css'
58
+ head.appendChild(link)
168
59
  }
169
- return ''
60
+ return wrapper
170
61
  }
171
- const html = require('bel')
172
62
 
63
+ /*
64
+ * Create the editor wrapper for handling changes to file contents.
65
+ *
66
+ * Note: Only the contents of a single file are loaded into the editor. No projects.
67
+ * Note: Only the contents of javascript files are loaded into the editor. No external formats.
68
+ */
173
69
  const editorWrapper = (state, editorCallbackToStream) => {
174
- const el = html`
175
- <div id='editor' key='editor' style='visibility:${state.activeTool === 'editor' ? 'visible' : 'hidden'}' >
176
- </div>`
177
-
178
- const editor = setUpEditor(el)
179
- // const snippets = '# Prototype\nsnippet proto\n ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n ${4:// body...}\n };\n# Function\nsnippet fun\n function ${1?:function_name}(${2:argument}) {\n ${3:// body...}\n }\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n function${M1?: ${1:functionName}}($2) {\n ${0:$TM_SELECTED_TEXT}\n }${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n (function(${1}) {\n ${0:${TM_SELECTED_TEXT:/* code */}}\n }(${1}));\n# if\nsnippet if\n if (${1:true}) {\n ${0}\n }\n# if ... else\nsnippet ife\n if (${1:true}) {\n ${2}\n } else {\n ${0}\n }\n# tertiary conditional\nsnippet ter\n ${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n switch (${1:expression}) {\n case \'${3:case}\':\n ${4:// code}\n break;\n ${5}\n default:\n ${2:// code}\n }\n# case\nsnippet case\n case \'${1:case}\':\n ${2:// code}\n break;\n ${3}\n\n# while (...) {...}\nsnippet wh\n while (${1:/* condition */}) {\n ${0:/* code */}\n }\n# try\nsnippet try\n try {\n ${0:/* code */}\n } catch (e) {}\n# do...while\nsnippet do\n do {\n ${2:/* code */}\n } while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n ${1:method_name}: function(${2:attribute}) {\n ${0}\n }${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# Get Elements\nsnippet gett\n getElementsBy${1:TagName}(\'${2}\')${3}\n# Get Element\nsnippet get\n getElementBy${1:Id}(\'${2}\')${3}\n# console.log (Firebug)\nsnippet cl\n console.log(${1});\n# return\nsnippet ret\n return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n for (var ${1:prop} in ${2:Things}) {\n ${0:$2[$1]}\n }\n# hasOwnProperty\nsnippet has\n hasOwnProperty(${1})\n# docstring\nsnippet /**\n /**\n * ${1:description}\n *\n */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n @param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n @return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n var ${1:function_name} = function(${2:argument}) {\n ${3:// initial code ...}\n\n $1 = function($2) {\n ${4:// main code}\n };\n }\n# singleton\nsnippet sing\n function ${1:Singleton} (${2:argument}) {\n // the cached instance\n var instance;\n\n // rewrite the constructor\n $1 = function $1($2) {\n return instance;\n };\n \n // carry over the prototype properties\n $1.prototype = this;\n\n // the instance\n instance = new $1();\n\n // reset the constructor pointer\n instance.constructor = $1;\n\n ${3:// code ...}\n\n return instance;\n }\n# class\nsnippet class\nregex /^\\s*/clas{0,2}/\n var ${1:class} = function(${20}) {\n $40$0\n };\n \n (function() {\n ${60:this.prop = ""}\n }).call(${1:class}.prototype);\n \n exports.${1:class} = ${1:class};\n# \nsnippet for-\n for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n ${0:${2:Things}[${1:i}];}\n }\n# for (...) {...}\nsnippet for\n for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n ${3:$2[$1]}$0\n }\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n ${3:$2[$1]}$0\n }\n\n\n#modules\nsnippet def\n define(function(require, exports, module) {\n "use strict";\n var ${1/.*\\///} = require("${1}");\n \n $TM_SELECTED_TEXT\n });\nsnippet req\nguard ^\\s*\n var ${1/.*\\///} = require("${1}");\n $0\nsnippet requ\nguard ^\\s*\n var ${1/.*\\/(.)/\\u$1/} = require("${1}").${1/.*\\/(.)/\\u$1/};\n $0\n'
180
-
181
- // editor.resize(true)
182
- // editor.renderer.updateFull()
183
- /* ace.config.loadModule('ace/snippets/javascript', function (ba) {
184
- })
185
- ace.config.loadModule('ace/ext/language_tools', function () {
186
- const bla = require('brace/snippets/javascript')
187
- editor.insertSnippet(bli);
188
- }) */
189
- editor.setOptions({
190
- enableBasicAutocompletion: true,
191
- enableSnippets: true,
192
- enableLiveAutocompletion: false
193
- })
194
-
195
- const source = `
196
- const main = (params) => {
70
+ const el = createWrapper(state, editorCallbackToStream)
71
+
72
+ // and adjust the state
73
+ if (state.activeTool === 'editor') {
74
+ el.style.visibility = 'visible'
75
+ el.focus()
76
+
77
+ let compileShortcut = state.shortcuts.find((shortcut) => shortcut.args === 'reevaluate')
78
+ if (!compileShortcut) compileShortcut = { args: 'Shift-Enter' }
79
+ let key = compileShortcut.key.toUpperCase()
80
+ // can you say PAIN? codemirror has very specific control prefixes!
81
+ key = key.replace(/enter/i, 'Enter')
82
+ key = key.replace(/alt[+-]/i, 'Alt-')
83
+ key = key.replace(/cmd[+-]/i, 'Cmd-')
84
+ key = key.replace(/control[+-]/i, 'Ctrl-')
85
+ key = key.replace(/shift[+-]/i, 'Shift-')
86
+
87
+ const extraKeys = {
88
+ Tab: (cm) => {
89
+ const spaces = Array(cm.getOption('indentUnit') + 1).join(' ')
90
+ cm.replaceSelection(spaces)
91
+ }
92
+ }
93
+ extraKeys[key] = (cm) => {
94
+ const fileTree = createFileTree(cm)
95
+ if (fileTree) editorCallbackToStream.callback({ type: 'read', id: 'loadRemote', data: fileTree })
96
+ }
97
+ editor.setOption('extraKeys', extraKeys)
98
+
99
+ editor.focus()
100
+ editor.scrollIntoView({ line: 0, ch: 0 })
101
+ // workaround to make content appear without clicking the editor after loading an example
102
+ // call the refresh in a setTimeout to force js to run it in the next global event loop
103
+ setTimeout(() => editor.refresh(), 0)
104
+ } else {
105
+ el.style.visibility = 'hidden'
106
+ }
197
107
 
108
+ // and adjust the contents if any
109
+ if (state.design && state.design.filesAndFolders) {
110
+ if (state.design.filesAndFolders.length === 1) {
111
+ const file0 = state.design.filesAndFolders[0]
112
+ let source = file0.source ? file0.source : ''
113
+ if (file0.mimetype) {
114
+ if (file0.mimetype.indexOf('javascript') < 0) source = '// imported from external format'
115
+ } else {
116
+ source = '// imported from project'
117
+ }
118
+ const prevsource = editor.getValue()
119
+ if (source !== prevsource) {
120
+ editor.focus()
121
+ editor.setValue(source)
122
+ editor.setCursor(0, 0)
123
+ editor.refresh()
124
+ }
125
+ }
198
126
  }
199
- module.exports = {main}
200
- `
201
- // state.design.source
202
127
 
203
- putSourceInEditor(editor, source)
204
128
  return el
205
129
  }
206
130
 
207
131
  module.exports = {
208
- editorWrapper,
209
- setUpEditor,
210
- putSourceInEditor,
211
- getSourceFromEditor
132
+ editorWrapper
212
133
  }
@@ -11,7 +11,7 @@ const dom = (state, i18n, paramsCallbacktoStream, editorCallbackToStream) => {
11
11
  const help = require('./help')(state, i18n)
12
12
 
13
13
  const io = require('./io')(state, i18n)
14
- const editor = require('./editor2').editorWrapper(state, editorCallbackToStream, i18n)
14
+ const editor = require('./editor').editorWrapper(state, editorCallbackToStream, i18n)
15
15
  const toolBar = require('./toolbar')(state, i18n)
16
16
 
17
17
  const viewer = require('./viewer')(state, i18n)
@@ -143,7 +143,7 @@ const viewer = (state, i18n) => {
143
143
  } else {
144
144
  // only generate entities when the solids change
145
145
  // themes, options, etc also change the viewer state
146
- const solids = state.design.solids
146
+ const solids = state.design.solids.filter((solid) => solid && (solid instanceof Object))
147
147
  if (prevSolids) {
148
148
  const theme = state.themes.themeSettings.viewer
149
149
  const color = theme.rendering.meshColor
@@ -18,7 +18,7 @@ const makeLogger = (params) => {
18
18
 
19
19
  const warning = (...params) => {
20
20
  if (enabled) {
21
- console.warning(...params)
21
+ console.warn(...params)
22
22
  }
23
23
  }
24
24
  const error = (...params) => {