From 10216af48a90293b5471ff771509bcdc18bdda08 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 1 May 2019 10:05:33 +0900 Subject: [PATCH] Improve MisskeyPages --- locales/ja-JP.yml | 8 +++- src/client/app/common/scripts/aiscript.ts | 43 +++++++++++++++---- .../page-editor/page-editor.script-block.vue | 18 +++++--- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index cd29135bdb..adc3d18913 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2036,12 +2036,18 @@ pages: _numberToString: arg1: "数値" ref: "変数" - in: "引数" + in: "スロット入力" _in: arg1: "スロット番号" fn: "関数" _fn: + slots: "スロット" + slots-info: "スロットひとつひとつを改行で区切ってください" arg1: "出力" + for: "繰り返し" + _for: + arg1: "回数" + arg2: "処理" typeError: "スロット{slot}は\"{expect}\"を受け付けますが、\"{actual}\"が入れられています!" thereIsEmptySlot: "スロット{slot}が空です!" types: diff --git a/src/client/app/common/scripts/aiscript.ts b/src/client/app/common/scripts/aiscript.ts index 765d740e23..975531dfa4 100644 --- a/src/client/app/common/scripts/aiscript.ts +++ b/src/client/app/common/scripts/aiscript.ts @@ -27,18 +27,27 @@ import { faDice, faSortNumericUp, faExchangeAlt, + faRecycle, } from '@fortawesome/free-solid-svg-icons'; import { faFlag } from '@fortawesome/free-regular-svg-icons'; import { version } from '../../config'; -export type Block = { +export type Block = { id: string; type: string; args: Block[]; - value: any; + value: V; }; +type FnBlock = Block<{ + slots: { + name: string; + type: Type; + }[]; + expression: Block; +}>; + export type Variable = Block & { name: string; }; @@ -53,6 +62,7 @@ type TypeError = { const funcDefs = { if: { in: ['boolean', 0, 0], out: 0, category: 'flow', icon: faShareAlt, }, + for: { in: ['number', 'function'], out: 0, category: 'flow', icon: faRecycle, }, not: { in: ['boolean'], out: 'boolean', category: 'logical', icon: faFlag, }, or: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: faFlag, }, and: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: faFlag, }, @@ -99,6 +109,10 @@ const blockDefs = [ })) ]; +function isFnBlock(block: Block): block is FnBlock { + return block.type === 'fn'; +} + type PageVar = { name: string; value: any; type: Type; }; const envVarsDef = { @@ -326,7 +340,7 @@ export class AiScript { @autobind private interpolate(str: string, values: { name: string, value: any }[]) { return str.replace(/\{(.+?)\}/g, match => { - const v = this.getVariableValue(match.slice(1, -1).trim(), values); + const v = this.getVarVal(match.slice(1, -1).trim(), values); return v == null ? 'NULL' : v.toString(); }); } @@ -378,23 +392,23 @@ export class AiScript { } if (block.type === 'ref') { - return this.getVariableValue(block.value, values); + return this.getVarVal(block.value, values); } if (block.type === 'in') { return slotArg[block.value]; } - if (block.type === 'fn') { // ユーザー関数定義 + if (isFnBlock(block)) { // ユーザー関数定義 return { - slots: block.value.slots, + slots: block.value.slots.map(x => x.name), exec: slotArg => this.evaluate(block.value.expression, values, slotArg) }; } if (block.type.startsWith('fn:')) { // ユーザー関数呼び出し const fnName = block.type.split(':')[1]; - const fn = this.getVariableValue(fnName, values); + const fn = this.getVarVal(fnName, values); for (let i = 0; i < fn.slots.length; i++) { const name = fn.slots[i]; slotArg[name] = this.evaluate(block.args[i], values); @@ -418,6 +432,14 @@ export class AiScript { or: (a, b) => a || b, and: (a, b) => a && b, if: (bool, a, b) => bool ? a : b, + for: (times, fn) => { + const result = []; + for (let i = 0; i < times; i++) { + slotArg[fn.slots[0]] = i + 1; + result.push(fn.exec(slotArg)); + } + return result; + }, add: (a, b) => a + b, subtract: (a, b) => a - b, multiply: (a, b) => a * b, @@ -449,8 +471,13 @@ export class AiScript { return fn(...args); } + /** + * 指定した名前の変数の値を取得します + * @param name 変数名 + * @param values ユーザー定義変数のリスト + */ @autobind - private getVariableValue(name: string, values: { name: string, value: any }[]): any { + private getVarVal(name: string, values: { name: string, value: any }[]): any { const v = values.find(v => v.name === name); if (v) { return v.value; diff --git a/src/client/app/common/views/components/page-editor/page-editor.script-block.vue b/src/client/app/common/views/components/page-editor/page-editor.script-block.vue index 9554c75d04..2f78f7de3a 100644 --- a/src/client/app/common/views/components/page-editor/page-editor.script-block.vue +++ b/src/client/app/common/views/components/page-editor/page-editor.script-block.vue @@ -35,15 +35,18 @@
-
- +
+ + {{ $t('script.blocks._fn.slots') }} + +
- +
@@ -118,7 +121,10 @@ export default Vue.extend({ watch: { slots() { - this.value.value.slots = this.slots.split('\n'); + this.value.value.slots = this.slots.split('\n').map(x => ({ + name: x, + type: null + })); } }, @@ -129,7 +135,7 @@ export default Vue.extend({ created() { if (this.value.value == null) Vue.set(this.value, 'value', null); - if (this.value.value && this.value.value.slots) this.slots = this.value.value.slots.join('\n'); + if (this.value.value && this.value.value.slots) this.slots = this.value.value.slots.map(x => x.name).join('\n'); this.$watch('value.type', (t) => { this.warn = null;