Improve MisskeyPages

* ifブロック を追加
* ボタンやスイッチなどのテキストに変数使えるようにした
This commit is contained in:
syuilo 2019-04-30 06:40:02 +09:00
parent a60d83b101
commit 2e8e5c2751
No known key found for this signature in database
GPG key ID: BDC4C49D06AB9D69
16 changed files with 227 additions and 65 deletions

View file

@ -1842,6 +1842,7 @@ dev/views/new-app.vue:
pages: pages:
new-page: "ページの作成" new-page: "ページの作成"
edit-page: "ページの編集" edit-page: "ページの編集"
read-page: "ソースを表示中"
page-created: "ページを作成しました" page-created: "ページを作成しました"
page-updated: "ページを更新しました" page-updated: "ページを更新しました"
are-you-sure-delete: "このページを削除しますか?" are-you-sure-delete: "このページを削除しますか?"
@ -1871,6 +1872,9 @@ pages:
section: "セクション" section: "セクション"
image: "画像" image: "画像"
button: "ボタン" button: "ボタン"
if: "もし"
_if:
variable: "変数"
input: "ユーザー入力" input: "ユーザー入力"
_input: _input:
name: "変数名" name: "変数名"

View file

@ -16,9 +16,9 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n';
import { faBolt } from '@fortawesome/free-solid-svg-icons'; import { faBolt } from '@fortawesome/free-solid-svg-icons';
import XContainer from './page-editor.container.vue'; import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('pages'), i18n: i18n('pages'),

View file

@ -0,0 +1,113 @@
<template>
<x-container @remove="() => $emit('remove')">
<template #header><fa :icon="faQuestion"/> {{ $t('blocks.if') }}</template>
<template #func>
<button @click="add()">
<fa :icon="faPlus"/>
</button>
</template>
<section class="romcojzs">
<ui-select v-model="value.var">
<template #label>{{ $t('blocks._if.variable') }}</template>
<option v-for="v in aiScript.getVarsByType('boolean')" :value="v.name">{{ v.name }}</option>
<optgroup :label="$t('script.pageVariables')">
<option v-for="v in aiScript.getPageVarsByType('boolean')" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$t('script.enviromentVariables')">
<option v-for="v in aiScript.getEnvVarsByType('boolean')" :value="v">{{ v }}</option>
</optgroup>
</ui-select>
<div class="children">
<x-block v-for="child in value.children" :value="child" @input="v => updateItem(v)" @remove="() => remove(child)" :key="child.id" :ai-script="aiScript"/>
</div>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import * as uuid from 'uuid';
import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
inject: ['getPageBlockList'],
props: {
value: {
required: true
},
aiScript: {
required: true,
},
},
data() {
return {
faPlus, faQuestion
};
},
beforeCreate() {
this.$options.components.XBlock = require('../page-editor.block.vue').default
},
created() {
if (this.value.children == null) Vue.set(this.value, 'children', []);
if (this.value.var === undefined) Vue.set(this.value, 'var', null);
},
methods: {
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
title: this.$t('choose-block'),
select: {
items: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid.v4();
this.value.children.push({ id, type });
},
updateItem(v) {
const i = this.value.children.findIndex(x => x.id === v.id);
const newValue = [
...this.value.children.slice(0, i),
v,
...this.value.children.slice(i + 1)
];
this.value.children = newValue;
this.$emit('input', this.value);
},
remove(el) {
const i = this.value.children.findIndex(x => x.id === el.id);
const newValue = [
...this.value.children.slice(0, i),
...this.value.children.slice(i + 1)
];
this.value.children = newValue;
this.$emit('input', this.value);
}
}
});
</script>
<style lang="stylus" scoped>
.romcojzs
padding 0 16px 16px 16px
</style>

View file

@ -15,11 +15,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n';
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { faImage, faFolderOpen } from '@fortawesome/free-regular-svg-icons'; import { faImage, faFolderOpen } from '@fortawesome/free-regular-svg-icons';
import XContainer from './page-editor.container.vue'; import i18n from '../../../../../i18n';
import XFileThumbnail from '../drive-file-thumbnail.vue'; import XContainer from '../page-editor.container.vue';
import XFileThumbnail from '../../drive-file-thumbnail.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('pages'), i18n: i18n('pages'),

View file

@ -17,9 +17,9 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n';
import { faBolt, faSquareRootAlt } from '@fortawesome/free-solid-svg-icons'; import { faBolt, faSquareRootAlt } from '@fortawesome/free-solid-svg-icons';
import XContainer from './page-editor.container.vue'; import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('pages'), i18n: i18n('pages'),

View file

@ -12,7 +12,7 @@
<section class="ilrvjyvi"> <section class="ilrvjyvi">
<div class="children"> <div class="children">
<x-block v-for="child in value.children" :value="child" @input="v => updateItem(v)" @remove="() => remove(child)" :key="child.id"/> <x-block v-for="child in value.children" :value="child" @input="v => updateItem(v)" @remove="() => remove(child)" :key="child.id" :ai-script="aiScript"/>
</div> </div>
</section> </section>
</x-container> </x-container>
@ -20,11 +20,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n'; import * as uuid from 'uuid';
import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons'; import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
import XContainer from './page-editor.container.vue'; import i18n from '../../../../../i18n';
import * as uuid from 'uuid'; import XContainer from '../page-editor.container.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('pages'), i18n: i18n('pages'),
@ -33,10 +33,15 @@ export default Vue.extend({
XContainer XContainer
}, },
inject: ['getPageBlockList'],
props: { props: {
value: { value: {
required: true required: true
}, },
aiScript: {
required: true,
},
}, },
data() { data() {
@ -46,7 +51,7 @@ export default Vue.extend({
}, },
beforeCreate() { beforeCreate() {
this.$options.components.XBlock = require('./page-editor.block.vue').default this.$options.components.XBlock = require('../page-editor.block.vue').default
}, },
created() { created() {
@ -79,19 +84,7 @@ export default Vue.extend({
type: null, type: null,
title: this.$t('choose-block'), title: this.$t('choose-block'),
select: { select: {
items: [{ items: this.getPageBlockList()
value: 'section', text: this.$t('blocks.section')
}, {
value: 'text', text: this.$t('blocks.text')
}, {
value: 'image', text: this.$t('blocks.image')
}, {
value: 'button', text: this.$t('blocks.button')
}, {
value: 'input', text: this.$t('blocks.input')
}, {
value: 'switch', text: this.$t('blocks.switch')
}]
}, },
showCancelButton: true showCancelButton: true
}); });

View file

@ -12,9 +12,9 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n';
import { faBolt, faSquareRootAlt } from '@fortawesome/free-solid-svg-icons'; import { faBolt, faSquareRootAlt } from '@fortawesome/free-solid-svg-icons';
import XContainer from './page-editor.container.vue'; import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('pages'), i18n: i18n('pages'),

View file

@ -10,9 +10,9 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n';
import { faAlignLeft } from '@fortawesome/free-solid-svg-icons'; import { faAlignLeft } from '@fortawesome/free-solid-svg-icons';
import XContainer from './page-editor.container.vue'; import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('pages'), i18n: i18n('pages'),

View file

@ -1,25 +1,29 @@
<template> <template>
<component :is="'x-' + value.type" :value="value" @input="v => updateItem(v)" @remove="() => $emit('remove', value)" :key="value.id"/> <component :is="'x-' + value.type" :value="value" @input="v => updateItem(v)" @remove="() => $emit('remove', value)" :key="value.id" :ai-script="aiScript"/>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import XSection from './page-editor.section.vue'; import XSection from './els/page-editor.el.section.vue';
import XText from './page-editor.text.vue'; import XText from './els/page-editor.el.text.vue';
import XImage from './page-editor.image.vue'; import XImage from './els/page-editor.el.image.vue';
import XButton from './page-editor.button.vue'; import XButton from './els/page-editor.el.button.vue';
import XInput from './page-editor.input.vue'; import XInput from './els/page-editor.el.input.vue';
import XSwitch from './page-editor.switch.vue'; import XSwitch from './els/page-editor.el.switch.vue';
import XIf from './els/page-editor.el.if.vue';
export default Vue.extend({ export default Vue.extend({
components: { components: {
XSection, XText, XImage, XButton, XInput, XSwitch XSection, XText, XImage, XButton, XInput, XSwitch, XIf
}, },
props: { props: {
value: { value: {
required: true required: true
} },
aiScript: {
required: true,
},
}, },
}); });
</script> </script>

View file

@ -2,16 +2,16 @@
<div> <div>
<div class="gwbmwxkm" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }"> <div class="gwbmwxkm" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<header> <header>
<div class="title"><fa :icon="faStickyNote"/> {{ pageId ? $t('edit-page') : $t('new-page') }}</div> <div class="title"><fa :icon="faStickyNote"/> {{ readonly ? $t('read-page') : pageId ? $t('edit-page') : $t('new-page') }}</div>
<div class="buttons"> <div class="buttons">
<button @click="del()"><fa :icon="faTrashAlt"/></button> <button @click="del()" v-if="!readonly"><fa :icon="faTrashAlt"/></button>
<button @click="() => showOptions = !showOptions"><fa :icon="faCog"/></button> <button @click="() => showOptions = !showOptions"><fa :icon="faCog"/></button>
<button @click="save()"><fa :icon="faSave"/></button> <button @click="save()" v-if="!readonly"><fa :icon="faSave"/></button>
</div> </div>
</header> </header>
<section> <section>
<a class="view" v-if="pageId" :href="`/@${ $store.state.i.username }/pages/${ currentName }`" target="_blank"><fa :icon="faExternalLinkSquareAlt"/> {{ $t('view-page') }}</a> <a class="view" v-if="pageId" :href="`/@${ author.username }/pages/${ currentName }`" target="_blank"><fa :icon="faExternalLinkSquareAlt"/> {{ $t('view-page') }}</a>
<ui-input v-model="title"> <ui-input v-model="title">
<span>{{ $t('title') }}</span> <span>{{ $t('title') }}</span>
@ -23,7 +23,7 @@
</ui-input> </ui-input>
<ui-input v-model="name"> <ui-input v-model="name">
<template #prefix>{{ url }}/@{{ $store.state.i.username }}/pages/</template> <template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
<span>{{ $t('url') }}</span> <span>{{ $t('url') }}</span>
</ui-input> </ui-input>
@ -45,10 +45,10 @@
</template> </template>
<div class="content" v-for="child in content"> <div class="content" v-for="child in content">
<x-block :value="child" @input="v => updateItem(v)" @remove="() => remove(child)" :key="child.id"/> <x-block :value="child" @input="v => updateItem(v)" @remove="() => remove(child)" :key="child.id" :ai-script="aiScript"/>
</div> </div>
<ui-button @click="add()"><fa :icon="faPlus"/></ui-button> <ui-button @click="add()" v-if="!readonly"><fa :icon="faPlus"/></ui-button>
</section> </section>
</div> </div>
@ -70,7 +70,7 @@
</template> </template>
</div> </div>
<ui-button @click="addVariable()" class="add"><fa :icon="faPlus"/></ui-button> <ui-button @click="addVariable()" class="add" v-if="!readonly"><fa :icon="faPlus"/></ui-button>
<ui-info><span v-html="$t('variables-info')"></span><a @click="() => moreDetails = true" style="display:block;">{{ $t('more-details') }}</a></ui-info> <ui-info><span v-html="$t('variables-info')"></span><a @click="() => moreDetails = true" style="display:block;">{{ $t('more-details') }}</a></ui-info>
@ -106,11 +106,17 @@ export default Vue.extend({
page: { page: {
type: String, type: String,
required: false required: false
} },
readonly: {
type: Boolean,
required: false,
default: false
},
}, },
data() { data() {
return { return {
author: this.$store.state.i,
pageId: null, pageId: null,
currentName: null, currentName: null,
title: '', title: '',
@ -157,6 +163,7 @@ export default Vue.extend({
this.$root.api('pages/show', { this.$root.api('pages/show', {
pageId: this.page, pageId: this.page,
}).then(page => { }).then(page => {
this.author = page.user;
this.pageId = page.id; this.pageId = page.id;
this.title = page.title; this.title = page.title;
this.name = page.name; this.name = page.name;
@ -180,7 +187,9 @@ export default Vue.extend({
provide() { provide() {
return { return {
getScriptBlockList: this.getScriptBlockList readonly: this.readonly,
getScriptBlockList: this.getScriptBlockList,
getPageBlockList: this.getPageBlockList
} }
}, },
@ -250,19 +259,7 @@ export default Vue.extend({
type: null, type: null,
title: this.$t('choose-block'), title: this.$t('choose-block'),
select: { select: {
items: [{ items: this.getPageBlockList()
value: 'section', text: this.$t('blocks.section')
}, {
value: 'text', text: this.$t('blocks.text')
}, {
value: 'image', text: this.$t('blocks.image')
}, {
value: 'button', text: this.$t('blocks.button')
}, {
value: 'input', text: this.$t('blocks.input')
}, {
value: 'switch', text: this.$t('blocks.switch')
}]
}, },
showCancelButton: true showCancelButton: true
}); });
@ -324,6 +321,24 @@ export default Vue.extend({
this.variables = newValue; this.variables = newValue;
}, },
getPageBlockList() {
return [{
value: 'section', text: this.$t('blocks.section')
}, {
value: 'text', text: this.$t('blocks.text')
}, {
value: 'image', text: this.$t('blocks.image')
}, {
value: 'button', text: this.$t('blocks.button')
}, {
value: 'input', text: this.$t('blocks.input')
}, {
value: 'switch', text: this.$t('blocks.switch')
}, {
value: 'if', text: this.$t('blocks.if')
}];
},
getScriptBlockList(type: string = null) { getScriptBlockList(type: string = null) {
const list = []; const list = [];
@ -436,6 +451,7 @@ export default Vue.extend({
> .view > .view
display inline-block display inline-block
margin 16px 0 0 0 margin 16px 0 0 0
font-size 14px
> .content > .content
margin-bottom 16px margin-bottom 16px

View file

@ -10,10 +10,11 @@ import XImage from './page.image.vue';
import XButton from './page.button.vue'; import XButton from './page.button.vue';
import XInput from './page.input.vue'; import XInput from './page.input.vue';
import XSwitch from './page.switch.vue'; import XSwitch from './page.switch.vue';
import XIf from './page.if.vue';
export default Vue.extend({ export default Vue.extend({
components: { components: {
XText, XSection, XImage, XButton, XInput, XSwitch XText, XSection, XImage, XButton, XInput, XSwitch, XIf
}, },
props: { props: {

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<ui-button class="kudkigyw" @click="click()">{{ value.text }}</ui-button> <ui-button class="kudkigyw" @click="click()">{{ script.interpolate(value.text) }}</ui-button>
</div> </div>
</template> </template>

View file

@ -0,0 +1,30 @@
<template>
<div v-show="script.vars.find(x => x.name === value.var).value">
<x-block v-for="child in value.children" :value="child" :page="page" :script="script" :key="child.id" :h="h"/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
value: {
required: true
},
script: {
required: true
},
page: {
required: true
},
h: {
required: true
}
},
beforeCreate() {
this.$options.components.XBlock = require('./page.block.vue').default
},
});
</script>

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<ui-input class="kudkigyw" v-model="v" :type="value.inputType">{{ value.text }}</ui-input> <ui-input class="kudkigyw" v-model="v" :type="value.inputType">{{ script.interpolate(value.text) }}</ui-input>
</div> </div>
</template> </template>

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="hkcxmtwj"> <div class="hkcxmtwj">
<ui-switch v-model="v">{{ value.text }}</ui-switch> <ui-switch v-model="v">{{ script.interpolate(value.text) }}</ui-switch>
</div> </div>
</template> </template>

View file

@ -38,6 +38,7 @@ class Script {
} }
public interpolate(str: string) { public interpolate(str: string) {
if (str == null) return null;
return str.replace(/\{(.+?)\}/g, match => { return str.replace(/\{(.+?)\}/g, match => {
const v = this.vars.find(x => x.name === match.slice(1, -1).trim()).value; const v = this.vars.find(x => x.name === match.slice(1, -1).trim()).value;
return v == null ? 'NULL' : v.toString(); return v == null ? 'NULL' : v.toString();