diff --git a/src/client/components/page/page.block.vue b/src/client/components/page/page.block.vue index 04bbb0b858..0a4b068b63 100644 --- a/src/client/components/page/page.block.vue +++ b/src/client/components/page/page.block.vue @@ -1,5 +1,5 @@ <template> -<component :is="'x-' + value.type" :value="value" :page="page" :script="script" :key="value.id" :h="h"/> +<component :is="'x-' + value.type" :value="value" :page="page" :hpml="hpml" :key="value.id" :h="h"/> </template> <script lang="ts"> @@ -27,7 +27,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true }, page: { diff --git a/src/client/components/page/page.button.vue b/src/client/components/page/page.button.vue index 148fdc8e9c..83753b4e80 100644 --- a/src/client/components/page/page.button.vue +++ b/src/client/components/page/page.button.vue @@ -1,6 +1,6 @@ <template> <div> - <mk-button class="kudkigyw" @click="click()" :primary="value.primary">{{ script.interpolate(value.text) }}</mk-button> + <mk-button class="kudkigyw" @click="click()" :primary="value.primary">{{ hpml.interpolate(value.text) }}</mk-button> </div> </template> @@ -16,35 +16,35 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, methods: { click() { if (this.value.action === 'dialog') { - this.script.eval(); + this.hpml.eval(); this.$root.dialog({ - text: this.script.interpolate(this.value.content) + text: this.hpml.interpolate(this.value.content) }); } else if (this.value.action === 'resetRandom') { - this.script.aoiScript.updateRandomSeed(Math.random()); - this.script.eval(); + this.hpml.updateRandomSeed(Math.random()); + this.hpml.eval(); } else if (this.value.action === 'pushEvent') { this.$root.api('page-push', { - pageId: this.script.page.id, + pageId: this.hpml.page.id, event: this.value.event, ...(this.value.var ? { - var: this.script.vars[this.value.var] + var: this.hpml.vars[this.value.var] } : {}) }); this.$root.dialog({ type: 'success', - text: this.script.interpolate(this.value.message) + text: this.hpml.interpolate(this.value.message) }); } else if (this.value.action === 'callAiScript') { - this.script.callAiScript(this.value.fn); + this.hpml.callAiScript(this.value.fn); } } } diff --git a/src/client/components/page/page.canvas.vue b/src/client/components/page/page.canvas.vue index a0f424bf60..2d7cc1f8f9 100644 --- a/src/client/components/page/page.canvas.vue +++ b/src/client/components/page/page.canvas.vue @@ -12,12 +12,12 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, mounted() { - this.script.aoiScript.registerCanvas(this.value.name, this.$refs.canvas); + this.hpml.registerCanvas(this.value.name, this.$refs.canvas); } }); </script> diff --git a/src/client/components/page/page.counter.vue b/src/client/components/page/page.counter.vue index f7557c003a..a3674b87a2 100644 --- a/src/client/components/page/page.counter.vue +++ b/src/client/components/page/page.counter.vue @@ -1,6 +1,6 @@ <template> <div> - <mk-button class="llumlmnx" @click="click()">{{ script.interpolate(value.text) }}</mk-button> + <mk-button class="llumlmnx" @click="click()">{{ hpml.interpolate(value.text) }}</mk-button> </div> </template> @@ -16,7 +16,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, @@ -27,8 +27,8 @@ export default Vue.extend({ }, watch: { v() { - this.script.aoiScript.updatePageVar(this.value.name, this.v); - this.script.eval(); + this.hpml.updatePageVar(this.value.name, this.v); + this.hpml.eval(); } }, methods: { diff --git a/src/client/components/page/page.if.vue b/src/client/components/page/page.if.vue index a714a522e8..d73153bcd1 100644 --- a/src/client/components/page/page.if.vue +++ b/src/client/components/page/page.if.vue @@ -1,6 +1,6 @@ <template> <div v-show="script.vars[value.var]"> - <x-block v-for="child in value.children" :value="child" :page="page" :script="script" :key="child.id" :h="h"/> + <x-block v-for="child in value.children" :value="child" :page="page" :hpml="hpml" :key="child.id" :h="h"/> </div> </template> @@ -12,7 +12,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true }, page: { diff --git a/src/client/components/page/page.number-input.vue b/src/client/components/page/page.number-input.vue index 9ea1ebb642..56899b1b20 100644 --- a/src/client/components/page/page.number-input.vue +++ b/src/client/components/page/page.number-input.vue @@ -1,6 +1,6 @@ <template> <div> - <mk-input class="kudkigyw" v-model="v" type="number">{{ script.interpolate(value.text) }}</mk-input> + <mk-input class="kudkigyw" v-model="v" type="number">{{ hpml.interpolate(value.text) }}</mk-input> </div> </template> @@ -16,7 +16,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, @@ -27,8 +27,8 @@ export default Vue.extend({ }, watch: { v() { - this.script.aoiScript.updatePageVar(this.value.name, this.v); - this.script.eval(); + this.hpml.updatePageVar(this.value.name, this.v); + this.hpml.eval(); } } }); diff --git a/src/client/components/page/page.post.vue b/src/client/components/page/page.post.vue index 80e0f70cb2..9942a68d55 100644 --- a/src/client/components/page/page.post.vue +++ b/src/client/components/page/page.post.vue @@ -23,22 +23,22 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, data() { return { - text: this.script.interpolate(this.value.text), + text: this.hpml.interpolate(this.value.text), posted: false, posting: false, faCheck, faPaperPlane }; }, watch: { - 'script.vars': { + 'hpml.vars': { handler() { - this.text = this.script.interpolate(this.value.text); + this.text = this.hpml.interpolate(this.value.text); }, deep: true } @@ -53,7 +53,7 @@ export default Vue.extend({ showCancelButton: false, cancelableByBgClick: false }); - const canvas = this.script.aoiScript.canvases[this.value.canvasId]; + const canvas = this.hpml.canvases[this.value.canvasId]; canvas.toBlob(blob => { const data = new FormData(); data.append('file', blob); diff --git a/src/client/components/page/page.radio-button.vue b/src/client/components/page/page.radio-button.vue index dd5cbcbded..99d9ead385 100644 --- a/src/client/components/page/page.radio-button.vue +++ b/src/client/components/page/page.radio-button.vue @@ -1,6 +1,6 @@ <template> <div> - <div>{{ script.interpolate(value.title) }}</div> + <div>{{ hpml.interpolate(value.title) }}</div> <mk-radio v-for="x in value.values" v-model="v" :value="x" :key="x">{{ x }}</mk-radio> </div> </template> @@ -17,7 +17,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, @@ -28,8 +28,8 @@ export default Vue.extend({ }, watch: { v() { - this.script.aoiScript.updatePageVar(this.value.name, this.v); - this.script.eval(); + this.hpml.updatePageVar(this.value.name, this.v); + this.hpml.eval(); } } }); diff --git a/src/client/components/page/page.section.vue b/src/client/components/page/page.section.vue index b83c773f71..c9758a0dbe 100644 --- a/src/client/components/page/page.section.vue +++ b/src/client/components/page/page.section.vue @@ -3,7 +3,7 @@ <component :is="'h' + h">{{ value.title }}</component> <div class="children"> - <x-block v-for="child in value.children" :value="child" :page="page" :script="script" :key="child.id" :h="h + 1"/> + <x-block v-for="child in value.children" :value="child" :page="page" :hpml="hpml" :key="child.id" :h="h + 1"/> </div> </section> </template> @@ -16,7 +16,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true }, page: { diff --git a/src/client/components/page/page.switch.vue b/src/client/components/page/page.switch.vue index 79d871df8f..9f04ad19c4 100644 --- a/src/client/components/page/page.switch.vue +++ b/src/client/components/page/page.switch.vue @@ -1,6 +1,6 @@ <template> <div class="hkcxmtwj"> - <mk-switch v-model="v">{{ script.interpolate(value.text) }}</mk-switch> + <mk-switch v-model="v">{{ hpml.interpolate(value.text) }}</mk-switch> </div> </template> @@ -16,7 +16,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, @@ -27,8 +27,8 @@ export default Vue.extend({ }, watch: { v() { - this.script.aoiScript.updatePageVar(this.value.name, this.v); - this.script.eval(); + this.hpml.updatePageVar(this.value.name, this.v); + this.hpml.eval(); } } }); diff --git a/src/client/components/page/page.text-input.vue b/src/client/components/page/page.text-input.vue index 843d541de6..0d09f9fb5e 100644 --- a/src/client/components/page/page.text-input.vue +++ b/src/client/components/page/page.text-input.vue @@ -1,6 +1,6 @@ <template> <div> - <mk-input class="kudkigyw" v-model="v" type="text">{{ script.interpolate(value.text) }}</mk-input> + <mk-input class="kudkigyw" v-model="v" type="text">{{ hpml.interpolate(value.text) }}</mk-input> </div> </template> @@ -16,7 +16,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, @@ -27,8 +27,8 @@ export default Vue.extend({ }, watch: { v() { - this.script.aoiScript.updatePageVar(this.value.name, this.v); - this.script.eval(); + this.hpml.updatePageVar(this.value.name, this.v); + this.hpml.eval(); } } }); diff --git a/src/client/components/page/page.text.vue b/src/client/components/page/page.text.vue index aeab31225e..66e2acb90a 100644 --- a/src/client/components/page/page.text.vue +++ b/src/client/components/page/page.text.vue @@ -15,13 +15,13 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, data() { return { - text: this.script.interpolate(this.value.text), + text: this.hpml.interpolate(this.value.text), }; }, computed: { @@ -38,9 +38,9 @@ export default Vue.extend({ } }, watch: { - 'script.vars': { + 'hpml.vars': { handler() { - this.text = this.script.interpolate(this.value.text); + this.text = this.hpml.interpolate(this.value.text); }, deep: true } diff --git a/src/client/components/page/page.textarea-input.vue b/src/client/components/page/page.textarea-input.vue index 5ba22e7c58..5e0cc43779 100644 --- a/src/client/components/page/page.textarea-input.vue +++ b/src/client/components/page/page.textarea-input.vue @@ -1,6 +1,6 @@ <template> <div> - <mk-textarea v-model="v">{{ script.interpolate(value.text) }}</mk-textarea> + <mk-textarea v-model="v">{{ hpml.interpolate(value.text) }}</mk-textarea> </div> </template> @@ -16,7 +16,7 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, @@ -27,8 +27,8 @@ export default Vue.extend({ }, watch: { v() { - this.script.aoiScript.updatePageVar(this.value.name, this.v); - this.script.eval(); + this.hpml.updatePageVar(this.value.name, this.v); + this.hpml.eval(); } } }); diff --git a/src/client/components/page/page.textarea.vue b/src/client/components/page/page.textarea.vue index 78b74dd64c..abb30d78ee 100644 --- a/src/client/components/page/page.textarea.vue +++ b/src/client/components/page/page.textarea.vue @@ -14,19 +14,19 @@ export default Vue.extend({ value: { required: true }, - script: { + hpml: { required: true } }, data() { return { - text: this.script.interpolate(this.value.text), + text: this.hpml.interpolate(this.value.text), }; }, watch: { - 'script.vars': { + 'hpml.vars': { handler() { - this.text = this.script.interpolate(this.value.text); + this.text = this.hpml.interpolate(this.value.text); }, deep: true } diff --git a/src/client/components/page/page.vue b/src/client/components/page/page.vue index 99cc6e67e5..e3b04d7fd6 100644 --- a/src/client/components/page/page.vue +++ b/src/client/components/page/page.vue @@ -1,56 +1,19 @@ <template> -<div class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }" v-if="script"> - <x-block v-for="child in page.content" :value="child" @input="v => updateBlock(v)" :page="page" :script="script" :key="child.id" :h="2"/> +<div class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }" v-if="hpml"> + <x-block v-for="child in page.content" :value="child" @input="v => updateBlock(v)" :page="page" :hpml="hpml" :key="child.id" :h="2"/> </div> </template> <script lang="ts"> import Vue from 'vue'; -import { AiScript, parse, values } from '@syuilo/aiscript'; +import { parse } from '@syuilo/aiscript'; import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons'; import { faHeart } from '@fortawesome/free-regular-svg-icons'; import i18n from '../../i18n'; import XBlock from './page.block.vue'; -import { ASEvaluator } from '../../scripts/aoiscript/evaluator'; -import { collectPageVars } from '../../scripts/collect-page-vars'; +import { Hpml } from '../../scripts/hpml/evaluator'; import { url } from '../../config'; -class Script { - public aoiScript: ASEvaluator; - private onError: any; - public vars: Record<string, any>; - public page: Record<string, any>; - - constructor(page, aoiScript, onError) { - this.page = page; - this.aoiScript = aoiScript; - this.onError = onError; - this.eval(); - } - - public eval() { - try { - this.vars = this.aoiScript.evaluateVars(); - } catch (e) { - this.onError(e); - } - } - - public interpolate(str: string) { - if (str == null) return null; - return str.replace(/{(.+?)}/g, match => { - const v = this.vars ? this.vars[match.slice(1, -1).trim()] : null; - return v == null ? 'NULL' : v.toString(); - }); - } - - public callAiScript(fn: string) { - try { - if (this.aoiScript.aiscript) this.aoiScript.aiscript.execFn(this.aoiScript.aiscript.scope.get(fn), []); - } catch (e) {} - } -} - export default Vue.extend({ i18n, @@ -67,35 +30,26 @@ export default Vue.extend({ data() { return { - script: null, + hpml: null, faHeartS, faHeart }; }, created() { - const pageVars = this.getPageVars(); - - this.script = new Script(this.page, new ASEvaluator(this, this.page.variables, pageVars, { + this.hpml = new Hpml(this, this.page, { randomSeed: Math.random(), visitor: this.$store.state.i, - page: this.page, url: url, enableAiScript: !this.$store.state.device.disablePagesScript - }), e => { - console.dir(e); }); - - 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) { + if (this.page.script && this.hpml.aiscript) { let ast; try { - ast = parse(this.script.page.script); + ast = parse(this.page.script); } catch (e) { console.error(e); /*this.$root.dialog({ @@ -104,8 +58,8 @@ export default Vue.extend({ });*/ return; } - this.script.aoiScript.aiscript.exec(ast).then(() => { - this.script.eval(); + this.hpml.aiscript.exec(ast).then(() => { + this.hpml.eval(); }).catch(e => { console.error(e); /*this.$root.dialog({ @@ -114,20 +68,14 @@ export default Vue.extend({ });*/ }); } else { - this.script.eval(); + this.hpml.eval(); } }); }, beforeDestroy() { - if (this.script.aoiScript.aiscript) this.script.aoiScript.aiscript.abort(); + if (this.hpml.aiscript) this.hpml.aiscript.abort(); }, - - methods: { - getPageVars() { - return collectPageVars(this.page.content); - }, - } }); </script> diff --git a/src/client/pages/page-editor/els/page-editor.el.button.vue b/src/client/pages/page-editor/els/page-editor.el.button.vue index 508d77a7a0..9ca9fe06f3 100644 --- a/src/client/pages/page-editor/els/page-editor.el.button.vue +++ b/src/client/pages/page-editor/els/page-editor.el.button.vue @@ -21,12 +21,12 @@ <mk-select v-model="value.var"> <template #label>{{ $t('_pages.blocks._button._action._pushEvent.variable') }}</template> <option :value="null">{{ $t('_pages.blocks._button._action._pushEvent.no-variable') }}</option> - <option v-for="v in aoiScript.getVarsByType()" :value="v.name">{{ v.name }}</option> + <option v-for="v in hpml.getVarsByType()" :value="v.name">{{ v.name }}</option> <optgroup :label="$t('_pages.script.pageVariables')"> - <option v-for="v in aoiScript.getPageVarsByType()" :value="v">{{ v }}</option> + <option v-for="v in hpml.getPageVarsByType()" :value="v">{{ v }}</option> </optgroup> <optgroup :label="$t('_pages.script.enviromentVariables')"> - <option v-for="v in aoiScript.getEnvVarsByType()" :value="v">{{ v }}</option> + <option v-for="v in hpml.getEnvVarsByType()" :value="v">{{ v }}</option> </optgroup> </mk-select> </template> @@ -57,7 +57,7 @@ export default Vue.extend({ value: { required: true }, - aoiScript: { + hpml: { required: true, }, }, diff --git a/src/client/pages/page-editor/els/page-editor.el.if.vue b/src/client/pages/page-editor/els/page-editor.el.if.vue index 1c6a33e1b3..0449b9cf2b 100644 --- a/src/client/pages/page-editor/els/page-editor.el.if.vue +++ b/src/client/pages/page-editor/els/page-editor.el.if.vue @@ -10,16 +10,16 @@ <section class="romcojzs"> <mk-select v-model="value.var"> <template #label>{{ $t('_pages.blocks._if.variable') }}</template> - <option v-for="v in aoiScript.getVarsByType('boolean')" :value="v.name">{{ v.name }}</option> + <option v-for="v in hpml.getVarsByType('boolean')" :value="v.name">{{ v.name }}</option> <optgroup :label="$t('_pages.script.pageVariables')"> - <option v-for="v in aoiScript.getPageVarsByType('boolean')" :value="v">{{ v }}</option> + <option v-for="v in hpml.getPageVarsByType('boolean')" :value="v">{{ v }}</option> </optgroup> <optgroup :label="$t('_pages.script.enviromentVariables')"> - <option v-for="v in aoiScript.getEnvVarsByType('boolean')" :value="v">{{ v }}</option> + <option v-for="v in hpml.getEnvVarsByType('boolean')" :value="v">{{ v }}</option> </optgroup> </mk-select> - <x-blocks class="children" v-model="value.children" :aoi-script="aoiScript"/> + <x-blocks class="children" v-model="value.children" :hpml="hpml"/> </section> </x-container> </template> @@ -45,7 +45,7 @@ export default Vue.extend({ value: { required: true }, - aoiScript: { + hpml: { required: true, }, }, diff --git a/src/client/pages/page-editor/els/page-editor.el.section.vue b/src/client/pages/page-editor/els/page-editor.el.section.vue index c1d5497f4c..a32cf9c753 100644 --- a/src/client/pages/page-editor/els/page-editor.el.section.vue +++ b/src/client/pages/page-editor/els/page-editor.el.section.vue @@ -11,7 +11,7 @@ </template> <section class="ilrvjyvi"> - <x-blocks class="children" v-model="value.children" :aoi-script="aoiScript"/> + <x-blocks class="children" v-model="value.children" :hpml="hpml"/> </section> </x-container> </template> @@ -37,7 +37,7 @@ export default Vue.extend({ value: { required: true }, - aoiScript: { + hpml: { required: true, }, }, diff --git a/src/client/pages/page-editor/page-editor.blocks.vue b/src/client/pages/page-editor/page-editor.blocks.vue index c6ec42b8da..6e9408e0b7 100644 --- a/src/client/pages/page-editor/page-editor.blocks.vue +++ b/src/client/pages/page-editor/page-editor.blocks.vue @@ -1,6 +1,6 @@ <template> <x-draggable tag="div" :list="blocks" handle=".drag-handle" :group="{ name: 'blocks' }" animation="150" swap-threshold="0.5"> - <component v-for="block in blocks" :is="'x-' + block.type" :value="block" @input="updateItem" @remove="() => removeItem(block)" :key="block.id" :aoi-script="aoiScript"/> + <component v-for="block in blocks" :is="'x-' + block.type" :value="block" @input="updateItem" @remove="() => removeItem(block)" :key="block.id" :hpml="hpml"/> </x-draggable> </template> @@ -32,7 +32,7 @@ export default Vue.extend({ type: Array, required: true }, - aoiScript: { + hpml: { required: true, }, }, diff --git a/src/client/pages/page-editor/page-editor.script-block.vue b/src/client/pages/page-editor/page-editor.script-block.vue index 7e3bbf0c88..9eafd5daa0 100644 --- a/src/client/pages/page-editor/page-editor.script-block.vue +++ b/src/client/pages/page-editor/page-editor.script-block.vue @@ -24,15 +24,15 @@ </section> <section v-else-if="value.type === 'ref'" class="hpdwcrvs"> <select v-model="value.value"> - <option v-for="v in aoiScript.getVarsByType(getExpectedType ? getExpectedType() : null).filter(x => x.name !== name)" :value="v.name">{{ v.name }}</option> + <option v-for="v in hpml.getVarsByType(getExpectedType ? getExpectedType() : null).filter(x => x.name !== name)" :value="v.name">{{ v.name }}</option> <optgroup :label="$t('_pages.script.argVariables')"> <option v-for="v in fnSlots" :value="v.name">{{ v.name }}</option> </optgroup> <optgroup :label="$t('_pages.script.pageVariables')"> - <option v-for="v in aoiScript.getPageVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option> + <option v-for="v in hpml.getPageVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option> </optgroup> <optgroup :label="$t('_pages.script.enviromentVariables')"> - <option v-for="v in aoiScript.getEnvVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option> + <option v-for="v in hpml.getEnvVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option> </optgroup> </select> </section> @@ -44,13 +44,13 @@ <span>{{ $t('_pages.script.blocks._fn.slots') }}</span> <template #desc>{{ $t('_pages.script.blocks._fn.slots-info') }}</template> </mk-textarea> - <x-v v-if="value.value.expression" v-model="value.value.expression" :title="$t(`_pages.script.blocks._fn.arg1`)" :get-expected-type="() => null" :aoi-script="aoiScript" :fn-slots="value.value.slots" :name="name"/> + <x-v v-if="value.value.expression" v-model="value.value.expression" :title="$t(`_pages.script.blocks._fn.arg1`)" :get-expected-type="() => null" :hpml="hpml" :fn-slots="value.value.slots" :name="name"/> </section> <section v-else-if="value.type.startsWith('fn:')" class="" style="padding:16px;"> - <x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="aoiScript.getVarByName(value.type.split(':')[1]).value.slots[i].name" :get-expected-type="() => null" :aoi-script="aoiScript" :name="name" :key="i"/> + <x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="hpml.getVarByName(value.type.split(':')[1]).value.slots[i].name" :get-expected-type="() => null" :hpml="hpml" :name="name" :key="i"/> </section> <section v-else class="" style="padding:16px;"> - <x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="$t(`_pages.script.blocks._${value.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :aoi-script="aoiScript" :name="name" :fn-slots="fnSlots" :key="i"/> + <x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="$t(`_pages.script.blocks._${value.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :hpml="hpml" :name="name" :fn-slots="fnSlots" :key="i"/> </section> </x-container> </template> @@ -62,7 +62,7 @@ import { v4 as uuid } from 'uuid'; import i18n from '../../i18n'; import XContainer from './page-editor.container.vue'; import MkTextarea from '../../components/ui/textarea.vue'; -import { isLiteralBlock, funcDefs, blockDefs } from '../../scripts/aoiscript/index'; +import { isLiteralBlock, funcDefs, blockDefs } from '../../scripts/hpml/index'; export default Vue.extend({ i18n, @@ -88,7 +88,7 @@ export default Vue.extend({ required: false, default: false }, - aoiScript: { + hpml: { required: true, }, name: { @@ -156,7 +156,7 @@ export default Vue.extend({ if (this.value.type && this.value.type.startsWith('fn:')) { const fnName = this.value.type.split(':')[1]; - const fn = this.aoiScript.getVarByName(fnName); + const fn = this.hpml.getVarByName(fnName); const empties = []; for (let i = 0; i < fn.value.slots.length; i++) { @@ -202,9 +202,9 @@ export default Vue.extend({ deep: true }); - this.$watch('aoiScript.variables', () => { + this.$watch('hpml.variables', () => { if (this.type != null && this.value) { - this.error = this.aoiScript.typeCheck(this.value); + this.error = this.hpml.typeCheck(this.value); } }, { deep: true @@ -226,7 +226,7 @@ export default Vue.extend({ }, _getExpectedType(slot: number) { - return this.aoiScript.getExpectedType(this.value, slot); + return this.hpml.getExpectedType(this.value, slot); } } }); diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue index 21d7af9a34..4437c7716d 100644 --- a/src/client/pages/page-editor/page-editor.vue +++ b/src/client/pages/page-editor/page-editor.vue @@ -46,7 +46,7 @@ </div> </template> - <x-blocks class="content" v-model="content" :aoi-script="aoiScript"/> + <x-blocks class="content" v-model="content" :hpml="hpml"/> <mk-button @click="add()" v-if="!readonly"><fa :icon="faPlus"/></mk-button> </section> @@ -62,7 +62,7 @@ @input="v => updateVariable(v)" @remove="() => removeVariable(variable)" :key="variable.name" - :aoi-script="aoiScript" + :hpml="hpml" :name="variable.name" :title="variable.name" :draggable="true" @@ -100,8 +100,8 @@ import MkButton from '../../components/ui/button.vue'; import MkSelect from '../../components/ui/select.vue'; import MkSwitch from '../../components/ui/switch.vue'; import MkInput from '../../components/ui/input.vue'; -import { blockDefs } from '../../scripts/aoiscript/index'; -import { ASTypeChecker } from '../../scripts/aoiscript/type-checker'; +import { blockDefs } from '../../scripts/hpml/index'; +import { HpmlTypeChecker } from '../../scripts/hpml/type-checker'; import { url } from '../../config'; import { collectPageVars } from '../../scripts/collect-page-vars'; import { selectDriveFile } from '../../scripts/select-drive-file'; @@ -145,7 +145,7 @@ export default Vue.extend({ alignCenter: false, hideTitleWhenPinned: false, variables: [], - aoiScript: null, + hpml: null, script: '', showOptions: false, url, @@ -166,14 +166,14 @@ export default Vue.extend({ }, async created() { - this.aoiScript = new ASTypeChecker(); + this.hpml = new HpmlTypeChecker(); this.$watch('variables', () => { - this.aoiScript.variables = this.variables; + this.hpml.variables = this.variables; }, { deep: true }); this.$watch('content', () => { - this.aoiScript.pageVars = collectPageVars(this.content); + this.hpml.pageVars = collectPageVars(this.content); }, { deep: true }); if (this.initPageId) { @@ -322,7 +322,7 @@ export default Vue.extend({ name = name.trim(); - if (this.aoiScript.isUsedName(name)) { + if (this.hpml.isUsedName(name)) { this.$root.dialog({ type: 'error', text: this.$t('_pages.variableNameIsAlreadyUsed') diff --git a/src/client/scripts/aoiscript/evaluator.ts b/src/client/scripts/hpml/evaluator.ts similarity index 58% rename from src/client/scripts/aoiscript/evaluator.ts rename to src/client/scripts/hpml/evaluator.ts index dbd4735fde..f1fcdde0e5 100644 --- a/src/client/scripts/aoiscript/evaluator.ts +++ b/src/client/scripts/hpml/evaluator.ts @@ -1,157 +1,45 @@ import autobind from 'autobind-decorator'; import * as seedrandom from 'seedrandom'; -import Chart from 'chart.js'; -import * as tinycolor from 'tinycolor2'; import { Variable, PageVar, envVarsDef, funcDefs, Block, isFnBlock } from '.'; import { version } from '../../config'; -import { AiScript, utils, parse, values } from '@syuilo/aiscript'; +import { AiScript, utils, values } from '@syuilo/aiscript'; import { createAiScriptEnv } from '../create-aiscript-env'; - -// https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs -Chart.pluginService.register({ - beforeDraw: function (chart, easing) { - if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) { - var ctx = chart.chart.ctx; - ctx.save(); - ctx.fillStyle = chart.config.options.chartArea.backgroundColor; - ctx.fillRect(0, 0, chart.chart.width, chart.chart.height); - ctx.restore(); - } - } -}); +import { collectPageVars } from '../collect-page-vars'; +import { initLib } from './lib'; type Fn = { slots: string[]; - exec: (args: Record<string, any>) => ReturnType<ASEvaluator['evaluate']>; + exec: (args: Record<string, any>) => ReturnType<Hpml['evaluate']>; }; /** - * AoiScript evaluator + * Hpml evaluator */ -export class ASEvaluator { +export class Hpml { private variables: Variable[]; private pageVars: PageVar[]; private envVars: Record<keyof typeof envVarsDef, any>; public aiscript?: AiScript; private pageVarUpdatedCallback; public canvases: Record<string, HTMLCanvasElement> = {}; + public vars: Record<string, any>; + public page: Record<string, any>; private opts: { - randomSeed: string; visitor?: any; page?: any; url?: string; + randomSeed: string; visitor?: any; url?: string; enableAiScript: boolean; }; - constructor(vm: any, variables: Variable[], pageVars: PageVar[], opts: ASEvaluator['opts']) { - this.variables = variables; - this.pageVars = pageVars; + constructor(vm: any, page: Hpml['page'], opts: Hpml['opts']) { + this.page = page; + this.variables = this.page.variables; + this.pageVars = collectPageVars(this.page.content); this.opts = opts; if (this.opts.enableAiScript) { this.aiscript = new AiScript({ ...createAiScriptEnv(vm, { - storageKey: 'pages:' + opts.page.id - }), ...{ - '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) })], - ['arc', values.FN_NATIVE(([x, y, radius, startAngle, endAngle]) => { ctx.arc(x.value, y.value, radius.value, startAngle.value, endAngle.value) })], - ['rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.rect(x.value, y.value, width.value, height.value) })], - ['fill', values.FN_NATIVE(() => { ctx.fill() })], - ['stroke', values.FN_NATIVE(() => { ctx.stroke() })], - ])); - }), - 'MkPages:chart': values.FN_NATIVE(([id, opts]) => { - utils.assertString(id); - utils.assertObject(opts); - const canvas = this.canvases[id.value]; - const color = getComputedStyle(document.documentElement).getPropertyValue('--accent'); - const chart = new Chart(canvas, { - type: opts.value.get('type').value, - data: { - labels: opts.value.get('labels').value.map(x => x.value), - datasets: opts.value.get('datasets').value.map(x => ({ - label: x.value.has('label') ? x.value.get('label').value : '', - data: x.value.get('data').value.map(x => x.value), - pointRadius: 0, - lineTension: 0, - borderWidth: 2, - borderColor: x.value.has('color') ? x.value.get('color') : color, - backgroundColor: tinycolor(x.value.has('color') ? x.value.get('color') : color).setAlpha(0.1).toRgbString(), - })) - }, - options: { - responsive: false, - devicePixelRatio: 1.5, - title: { - display: opts.value.has('title'), - text: opts.value.has('title') ? opts.value.get('title').value : '', - fontSize: 14, - }, - layout: { - padding: { - left: 32, - right: 32, - top: opts.value.has('title') ? 16 : 32, - bottom: 16 - } - }, - legend: { - display: opts.value.get('datasets').value.filter(x => x.value.has('label') && x.value.get('label').value).length === 0 ? false : true, - position: 'bottom', - labels: { - boxWidth: 16, - } - }, - tooltips: { - enabled: false, - }, - chartArea: { - backgroundColor: '#fff' - }, - ...(opts.value.get('type').value === 'radar' ? { - scale: { - ticks: { - display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : false, - min: opts.value.has('min') ? opts.value.get('min').value : undefined, - max: opts.value.has('max') ? opts.value.get('max').value : undefined, - maxTicksLimit: 8, - }, - pointLabels: { - fontSize: 12 - } - } - } : { - scales: { - yAxes: [{ - ticks: { - display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : true, - min: opts.value.has('min') ? opts.value.get('min').value : undefined, - max: opts.value.has('max') ? opts.value.get('max').value : undefined, - } - }] - } - }) - } - }); - }), - }}, { + storageKey: 'pages:' + this.page.id + }), ...initLib(this)}, { in: (q) => { return new Promise(ok => { vm.$root.dialog({ @@ -168,6 +56,10 @@ export class ASEvaluator { log: (type, params) => { }, }); + + this.aiscript.scope.opts.onUpdated = (name, value) => { + this.eval(); + }; } const date = new Date(); @@ -175,7 +67,7 @@ export class ASEvaluator { this.envVars = { AI: 'kawaii', VERSION: version, - URL: opts.page ? `${opts.url}/@${opts.page.user.username}/pages/${opts.page.name}` : '', + URL: this.page ? `${opts.url}/@${this.page.user.username}/pages/${this.page.name}` : '', LOGIN: opts.visitor != null, NAME: opts.visitor ? opts.visitor.name || opts.visitor.username : '', USERNAME: opts.visitor ? opts.visitor.username : '', @@ -189,8 +81,36 @@ export class ASEvaluator { AISCRIPT_DISABLED: !this.opts.enableAiScript, NULL: null }; + + this.eval(); } + @autobind + public eval() { + try { + this.vars = this.evaluateVars(); + } catch (e) { + //this.onError(e); + } + } + + @autobind + public interpolate(str: string) { + if (str == null) return null; + return str.replace(/{(.+?)}/g, match => { + const v = this.vars ? this.vars[match.slice(1, -1).trim()] : null; + return v == null ? 'NULL' : v.toString(); + }); + } + + @autobind + public callAiScript(fn: string) { + try { + if (this.aiscript) this.aiscript.execFn(this.aiscript.scope.get(fn), []); + } catch (e) {} + } + + @autobind public registerCanvas(id: string, canvas: any) { this.canvases[id] = canvas; } @@ -204,7 +124,7 @@ export class ASEvaluator { if (this.aiscript) this.aiscript.execFn(this.pageVarUpdatedCallback, [values.STR(name), utils.jsToVal(value)]); } } else { - throw new AoiScriptError(`No such page var '${name}'`); + throw new HpmlError(`No such page var '${name}'`); } } @@ -215,7 +135,7 @@ export class ASEvaluator { } @autobind - private interpolate(str: string, scope: Scope) { + private _interpolate(str: string, scope: Scope) { return str.replace(/{(.+?)}/g, match => { const v = scope.getState(match.slice(1, -1).trim()); return v == null ? 'NULL' : v.toString(); @@ -252,11 +172,11 @@ export class ASEvaluator { } if (block.type === 'text' || block.type === 'multiLineText') { - return this.interpolate(block.value || '', scope); + return this._interpolate(block.value || '', scope); } if (block.type === 'textList') { - return this.interpolate(block.value || '', scope).trim().split('\n'); + return this._interpolate(block.value || '', scope).trim().split('\n'); } if (block.type === 'ref') { @@ -371,14 +291,14 @@ export class ASEvaluator { const fnName = block.type; const fn = (funcs as any)[fnName]; if (fn == null) { - throw new AoiScriptError(`No such function '${fnName}'`); + throw new HpmlError(`No such function '${fnName}'`); } else { return fn(...block.args.map(x => this.evaluate(x, scope))); } } } -class AoiScriptError extends Error { +class HpmlError extends Error { public info?: any; constructor(message: string, info?: any) { @@ -388,7 +308,7 @@ class AoiScriptError extends Error { // Maintains proper stack trace for where our error was thrown (only available on V8) if (Error.captureStackTrace) { - Error.captureStackTrace(this, AoiScriptError); + Error.captureStackTrace(this, HpmlError); } } } @@ -421,7 +341,7 @@ class Scope { } } - throw new AoiScriptError( + throw new HpmlError( `No such variable '${name}' in scope '${this.name}'`, { scope: this.layerdStates }); diff --git a/src/client/scripts/aoiscript/index.ts b/src/client/scripts/hpml/index.ts similarity index 99% rename from src/client/scripts/aoiscript/index.ts rename to src/client/scripts/hpml/index.ts index 7f34964064..c87d5b9985 100644 --- a/src/client/scripts/aoiscript/index.ts +++ b/src/client/scripts/hpml/index.ts @@ -1,5 +1,5 @@ /** - * AoiScript + * Hpml */ import { diff --git a/src/client/scripts/hpml/lib.ts b/src/client/scripts/hpml/lib.ts new file mode 100644 index 0000000000..9c71cfaba5 --- /dev/null +++ b/src/client/scripts/hpml/lib.ts @@ -0,0 +1,124 @@ +import * as tinycolor from 'tinycolor2'; +import Chart from 'chart.js'; +import { Hpml } from './evaluator'; +import { values, utils } from '@syuilo/aiscript'; + +// https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs +Chart.pluginService.register({ + beforeDraw: function (chart, easing) { + if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) { + var ctx = chart.chart.ctx; + ctx.save(); + ctx.fillStyle = chart.config.options.chartArea.backgroundColor; + ctx.fillRect(0, 0, chart.chart.width, chart.chart.height); + ctx.restore(); + } + } +}); + +export function initLib(hpml: Hpml) { + return { + 'MkPages:updated': values.FN_NATIVE(([callback]) => { + hpml.pageVarUpdatedCallback = callback; + }), + 'MkPages:get_canvas': values.FN_NATIVE(([id]) => { + utils.assertString(id); + const canvas = hpml.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) })], + ['arc', values.FN_NATIVE(([x, y, radius, startAngle, endAngle]) => { ctx.arc(x.value, y.value, radius.value, startAngle.value, endAngle.value) })], + ['rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.rect(x.value, y.value, width.value, height.value) })], + ['fill', values.FN_NATIVE(() => { ctx.fill() })], + ['stroke', values.FN_NATIVE(() => { ctx.stroke() })], + ])); + }), + 'MkPages:chart': values.FN_NATIVE(([id, opts]) => { + utils.assertString(id); + utils.assertObject(opts); + const canvas = hpml.canvases[id.value]; + const color = getComputedStyle(document.documentElement).getPropertyValue('--accent'); + Chart.defaults.global.defaultFontColor = '#555'; + const chart = new Chart(canvas, { + type: opts.value.get('type').value, + data: { + labels: opts.value.get('labels').value.map(x => x.value), + datasets: opts.value.get('datasets').value.map(x => ({ + label: x.value.has('label') ? x.value.get('label').value : '', + data: x.value.get('data').value.map(x => x.value), + pointRadius: 0, + lineTension: 0, + borderWidth: 2, + borderColor: x.value.has('color') ? x.value.get('color') : color, + backgroundColor: tinycolor(x.value.has('color') ? x.value.get('color') : color).setAlpha(0.1).toRgbString(), + })) + }, + options: { + responsive: false, + devicePixelRatio: 1.5, + title: { + display: opts.value.has('title'), + text: opts.value.has('title') ? opts.value.get('title').value : '', + fontSize: 14, + }, + layout: { + padding: { + left: 32, + right: 32, + top: opts.value.has('title') ? 16 : 32, + bottom: 16 + } + }, + legend: { + display: opts.value.get('datasets').value.filter(x => x.value.has('label') && x.value.get('label').value).length === 0 ? false : true, + position: 'bottom', + labels: { + boxWidth: 16, + } + }, + tooltips: { + enabled: false, + }, + chartArea: { + backgroundColor: '#fff' + }, + ...(opts.value.get('type').value === 'radar' ? { + scale: { + ticks: { + display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : false, + min: opts.value.has('min') ? opts.value.get('min').value : undefined, + max: opts.value.has('max') ? opts.value.get('max').value : undefined, + maxTicksLimit: 8, + }, + pointLabels: { + fontSize: 12 + } + } + } : { + scales: { + yAxes: [{ + ticks: { + display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : true, + min: opts.value.has('min') ? opts.value.get('min').value : undefined, + max: opts.value.has('max') ? opts.value.get('max').value : undefined, + } + }] + } + }) + } + }); + }) + }; +} diff --git a/src/client/scripts/aoiscript/type-checker.ts b/src/client/scripts/hpml/type-checker.ts similarity index 96% rename from src/client/scripts/aoiscript/type-checker.ts rename to src/client/scripts/hpml/type-checker.ts index c10198e119..14950e0195 100644 --- a/src/client/scripts/aoiscript/type-checker.ts +++ b/src/client/scripts/hpml/type-checker.ts @@ -8,13 +8,13 @@ type TypeError = { }; /** - * AoiScript type checker + * Hpml type checker */ -export class ASTypeChecker { +export class HpmlTypeChecker { public variables: Variable[]; public pageVars: PageVar[]; - constructor(variables: ASTypeChecker['variables'] = [], pageVars: ASTypeChecker['pageVars'] = []) { + constructor(variables: HpmlTypeChecker['variables'] = [], pageVars: HpmlTypeChecker['pageVars'] = []) { this.variables = variables; this.pageVars = pageVars; }