diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1812a2660..90b5a0d8c 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -797,6 +797,12 @@ _pages:
text: "タイトル"
default: "デフォルト値"
+ canvas: "キャンバス"
+ _canvas:
+ id: "キャンバスID"
+ width: "幅"
+ height: "高さ"
+
switch: "スイッチ"
_switch:
name: "変数名"
diff --git a/package.json b/package.json
index f34a0d3aa..491f937fc 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"@koa/cors": "3.0.0",
"@koa/multer": "2.0.2",
"@koa/router": "8.0.8",
- "@syuilo/aiscript": "0.2.0",
+ "@syuilo/aiscript": "0.3.0",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.12.1",
"@types/cbor": "5.0.0",
diff --git a/src/client/components/page/page.block.vue b/src/client/components/page/page.block.vue
index c1d046fa2..04bbb0b85 100644
--- a/src/client/components/page/page.block.vue
+++ b/src/client/components/page/page.block.vue
@@ -17,10 +17,11 @@ import XTextarea from './page.textarea.vue';
import XPost from './page.post.vue';
import XCounter from './page.counter.vue';
import XRadioButton from './page.radio-button.vue';
+import XCanvas from './page.canvas.vue';
export default Vue.extend({
components: {
- XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton
+ XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas
},
props: {
value: {
diff --git a/src/client/components/page/page.canvas.vue b/src/client/components/page/page.canvas.vue
new file mode 100644
index 000000000..edcb9cba3
--- /dev/null
+++ b/src/client/components/page/page.canvas.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/client/components/page/page.vue b/src/client/components/page/page.vue
index 3723fcd3c..99cc6e67e 100644
--- a/src/client/components/page/page.vue
+++ b/src/client/components/page/page.vue
@@ -21,39 +21,11 @@ class Script {
public vars: Record;
public page: Record;
- constructor(page, aoiScript, onError, cb) {
+ constructor(page, aoiScript, onError) {
this.page = page;
this.aoiScript = aoiScript;
this.onError = onError;
-
- if (this.page.script && this.aoiScript.aiscript) {
- let ast;
- try {
- ast = parse(this.page.script);
- } catch (e) {
- console.error(e);
- /*this.$root.dialog({
- type: 'error',
- text: 'Syntax error :('
- });*/
- return;
- }
- this.aoiScript.aiscript.exec(ast).then(() => {
- this.eval();
- cb();
- }).catch(e => {
- console.error(e);
- /*this.$root.dialog({
- type: 'error',
- text: e
- });*/
- });
- } else {
- setTimeout(() => {
- this.eval();
- cb();
- }, 1);
- }
+ this.eval();
}
public eval() {
@@ -67,13 +39,15 @@ class Script {
public interpolate(str: string) {
if (str == null) return null;
return str.replace(/{(.+?)}/g, match => {
- const v = this.vars[match.slice(1, -1).trim()];
+ const v = this.vars ? this.vars[match.slice(1, -1).trim()] : null;
return v == null ? 'NULL' : v.toString();
});
}
public callAiScript(fn: string) {
- if (this.aoiScript.aiscript) this.aoiScript.aiscript.execFn(this.aoiScript.aiscript.scope.get(fn), []);
+ try {
+ if (this.aoiScript.aiscript) this.aoiScript.aiscript.execFn(this.aoiScript.aiscript.scope.get(fn), []);
+ } catch (e) {}
}
}
@@ -101,7 +75,7 @@ export default Vue.extend({
created() {
const pageVars = this.getPageVars();
- const s = new Script(this.page, new ASEvaluator(this, this.page.variables, pageVars, {
+ this.script = new Script(this.page, new ASEvaluator(this, this.page.variables, pageVars, {
randomSeed: Math.random(),
visitor: this.$store.state.i,
page: this.page,
@@ -109,15 +83,42 @@ export default Vue.extend({
enableAiScript: !this.$store.state.device.disablePagesScript
}), e => {
console.dir(e);
- }, () => {
- this.script = s;
});
- if (s.aoiScript.aiscript) s.aoiScript.aiscript.scope.opts.onUpdated = (name, value) => {
- s.eval();
+ if (this.script.aoiScript.aiscript) this.script.aoiScript.aiscript.scope.opts.onUpdated = (name, value) => {
+ this.script.eval();
};
},
+ mounted() {
+ this.$nextTick(() => {
+ if (this.script.page.script && this.script.aoiScript.aiscript) {
+ let ast;
+ try {
+ ast = parse(this.script.page.script);
+ } catch (e) {
+ console.error(e);
+ /*this.$root.dialog({
+ type: 'error',
+ text: 'Syntax error :('
+ });*/
+ return;
+ }
+ this.script.aoiScript.aiscript.exec(ast).then(() => {
+ this.script.eval();
+ }).catch(e => {
+ console.error(e);
+ /*this.$root.dialog({
+ type: 'error',
+ text: e
+ });*/
+ });
+ } else {
+ this.script.eval();
+ }
+ });
+ },
+
beforeDestroy() {
if (this.script.aoiScript.aiscript) this.script.aoiScript.aiscript.abort();
},
diff --git a/src/client/pages/page-editor/els/page-editor.el.canvas.vue b/src/client/pages/page-editor/els/page-editor.el.canvas.vue
new file mode 100644
index 000000000..497731891
--- /dev/null
+++ b/src/client/pages/page-editor/els/page-editor.el.canvas.vue
@@ -0,0 +1,45 @@
+
+ $emit('remove')" :draggable="true">
+ {{ $t('_pages.blocks.canvas') }}
+
+
+ {{ $t('_pages.blocks._canvas.id') }}
+ {{ $t('_pages.blocks._canvas.width') }}px
+ {{ $t('_pages.blocks._canvas.height') }}px
+
+
+
+
+
diff --git a/src/client/pages/page-editor/page-editor.blocks.vue b/src/client/pages/page-editor/page-editor.blocks.vue
index bfc75cada..c6ec42b8d 100644
--- a/src/client/pages/page-editor/page-editor.blocks.vue
+++ b/src/client/pages/page-editor/page-editor.blocks.vue
@@ -20,10 +20,11 @@ import XIf from './els/page-editor.el.if.vue';
import XPost from './els/page-editor.el.post.vue';
import XCounter from './els/page-editor.el.counter.vue';
import XRadioButton from './els/page-editor.el.radio-button.vue';
+import XCanvas from './els/page-editor.el.canvas.vue';
export default Vue.extend({
components: {
- XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton
+ XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas
},
props: {
diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue
index 6177663b7..1af8689de 100644
--- a/src/client/pages/page-editor/page-editor.vue
+++ b/src/client/pages/page-editor/page-editor.vue
@@ -351,6 +351,7 @@ export default Vue.extend({
{ value: 'text', text: this.$t('_pages.blocks.text') },
{ value: 'image', text: this.$t('_pages.blocks.image') },
{ value: 'textarea', text: this.$t('_pages.blocks.textarea') },
+ { value: 'canvas', text: this.$t('_pages.blocks.canvas') },
]
}, {
label: this.$t('_pages.inputBlocks'),
@@ -428,8 +429,6 @@ export default Vue.extend({
margin-bottom: var(--margin);
> header {
- background: var(--faceHeader);
-
> .title {
z-index: 1;
margin: 0;
@@ -437,8 +436,7 @@ export default Vue.extend({
line-height: 42px;
font-size: 0.9em;
font-weight: bold;
- color: var(--faceHeaderText);
- box-shadow: 0 var(--lineWidth) rgba(#000, 0.07);
+ box-shadow: 0 1px rgba(#000, 0.07);
> [data-icon] {
margin-right: 6px;
diff --git a/src/client/scripts/aoiscript/evaluator.ts b/src/client/scripts/aoiscript/evaluator.ts
index cd488aeda..e911be2ca 100644
--- a/src/client/scripts/aoiscript/evaluator.ts
+++ b/src/client/scripts/aoiscript/evaluator.ts
@@ -19,6 +19,7 @@ export class ASEvaluator {
private envVars: Record;
public aiscript?: AiScript;
private pageVarUpdatedCallback;
+ private canvases: Record = {};
private opts: {
randomSeed: string; visitor?: any; page?: any; url?: string;
@@ -36,6 +37,28 @@ export class ASEvaluator {
}), ...{
'MkPages:updated': values.FN_NATIVE(([callback]) => {
this.pageVarUpdatedCallback = callback;
+ }),
+ 'MkPages:get_canvas': values.FN_NATIVE(([id]) => {
+ utils.assertString(id);
+ const canvas = this.canvases[id.value];
+ const ctx = canvas.getContext('2d');
+ return values.OBJ(new Map([
+ ['clear_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.clearRect(x.value, y.value, width.value, height.value) })],
+ ['fill_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.fillRect(x.value, y.value, width.value, height.value) })],
+ ['stroke_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.strokeRect(x.value, y.value, width.value, height.value) })],
+ ['fill_text', values.FN_NATIVE(([text, x, y, width]) => { ctx.fillText(text.value, x.value, y.value, width ? width.value : undefined) })],
+ ['stroke_text', values.FN_NATIVE(([text, x, y, width]) => { ctx.strokeText(text.value, x.value, y.value, width ? width.value : undefined) })],
+ ['set_line_width', values.FN_NATIVE(([width]) => { ctx.lineWidth = width.value })],
+ ['set_font', values.FN_NATIVE(([font]) => { ctx.font = font.value })],
+ ['set_fill_style', values.FN_NATIVE(([style]) => { ctx.fillStyle = style.value })],
+ ['set_stroke_style', values.FN_NATIVE(([style]) => { ctx.strokeStyle = style.value })],
+ ['begin_path', values.FN_NATIVE(() => { ctx.beginPath() })],
+ ['close_path', values.FN_NATIVE(() => { ctx.closePath() })],
+ ['move_to', values.FN_NATIVE(([x, y]) => { ctx.moveTo(x.value, y.value) })],
+ ['line_to', values.FN_NATIVE(([x, y]) => { ctx.lineTo(x.value, y.value) })],
+ ['fill', values.FN_NATIVE(() => { ctx.fill() })],
+ ['stroke', values.FN_NATIVE(() => { ctx.stroke() })],
+ ]));
})
}}, {
in: (q) => {
@@ -73,10 +96,15 @@ export class ASEvaluator {
IS_CAT: opts.visitor ? opts.visitor.isCat : false,
SEED: opts.randomSeed ? opts.randomSeed : '',
YMD: `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`,
+ AISCRIPT_DISABLED: !this.opts.enableAiScript,
NULL: null
};
}
+ public registerCanvas(id: string, canvas: any) {
+ this.canvases[id] = canvas;
+ }
+
@autobind
public updatePageVar(name: string, value: any) {
const pageVar = this.pageVars.find(v => v.name === name);
@@ -147,7 +175,11 @@ export class ASEvaluator {
if (block.type === 'aiScriptVar') {
if (this.aiscript) {
- return utils.valToJs(this.aiscript.scope.get(block.value));
+ try {
+ return utils.valToJs(this.aiscript.scope.get(block.value));
+ } catch (e) {
+ return null;
+ }
} else {
return null;
}
diff --git a/src/client/scripts/aoiscript/index.ts b/src/client/scripts/aoiscript/index.ts
index e6de5faaa..7f3496406 100644
--- a/src/client/scripts/aoiscript/index.ts
+++ b/src/client/scripts/aoiscript/index.ts
@@ -128,6 +128,7 @@ export const envVarsDef: Record = {
IS_CAT: 'boolean',
SEED: null,
YMD: 'string',
+ AISCRIPT_DISABLED: 'boolean',
NULL: null,
};
diff --git a/yarn.lock b/yarn.lock
index 724488a69..027894030 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -144,10 +144,10 @@
dependencies:
type-detect "4.0.8"
-"@syuilo/aiscript@0.2.0":
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/@syuilo/aiscript/-/aiscript-0.2.0.tgz#dcb489bca13f6d965ac86034a45fd46514b1487a"
- integrity sha512-N9fYchn3zjtniG9fNmZ81PwYZFdulk+RSBcjDZWBgHsFJQc1wxOCr9hZux/vSXrZ/ZWEzK0loNz1dorl2jJLeA==
+"@syuilo/aiscript@0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@syuilo/aiscript/-/aiscript-0.3.0.tgz#cb0645df40ae97a54eb7e318abef2ccb8045aa14"
+ integrity sha512-jjtcFqnp5ryzAU3mxP25YJEJH/FmIrMycnFwSer/q1BVsAIqHOIhnRTWjxjVI3n1YHIO5DSD4yG/Em6I3bxJow==
dependencies:
"@types/seedrandom" "2.4.28"
autobind-decorator "2.4.0"