Compare commits

...

16 Commits

Author SHA1 Message Date
syuilo
84a1ec01bc 12.33.0 2020-04-16 23:23:07 +09:00
syuilo
36e59c5b5f chore: update deps 2020-04-16 23:20:34 +09:00
syuilo
5389b16c59 chore(client): 🎨 2020-04-16 23:13:33 +09:00
syuilo
da3008af1c fix(pages): AiScript変数があると型チェックができない問題を修正 2020-04-16 23:04:49 +09:00
syuilo
6637766554 feat(pages): Add arc method 2020-04-16 18:11:13 +09:00
syuilo
2bc63631a4 12.32.0 2020-04-16 01:09:28 +09:00
syuilo
5215721942 New Crowdin translations (#6255)
* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)
2020-04-16 01:05:32 +09:00
tamaina
d02e14cb94 Fix Media List in CW Content (#6099) 2020-04-16 01:04:21 +09:00
MeiMei
fa75b40dfd リアクションの修正 (#6260) 2020-04-16 00:47:17 +09:00
MeiMei
f32d8b7069 0以下のリアクションは送らないように Resolve #6263 (#6264) 2020-04-16 00:45:43 +09:00
syuilo
90e8527556 Resolve #6256 2020-04-16 00:39:21 +09:00
MeiMei
66377d3f27 Update CHANGELOG.md 2020-04-14 01:49:52 +09:00
MeiMei
c6ae93df80 Update CHANGELOG.md 2020-04-14 01:45:55 +09:00
MeiMei
55e9099091 Update CHANGELOG.md 2020-04-14 01:37:24 +09:00
MeiMei
c6ace29446 Update CHANGELOG.md 2020-04-14 01:35:33 +09:00
mei23
b0b885aacd lint 2020-04-14 01:13:01 +09:00
27 changed files with 335 additions and 90 deletions

View File

@@ -1,6 +1,69 @@
ChangeLog
=========
12.33.0 (2020/4/16)
-------------------
### ✨Improvements
* Pagesで円を書くメソッドを追加
* AiScriptのバージョンアップ
### 🐛Fixes
* PagesでAiScript変数があると編集が機能しなくなる問題を修正
12.32.0 (2020/4/16)
-------------------
### ✨Improvements
* Pagesで画像を描画できるように
* AiScriptのバージョンアップ
* 0以下のリアクションは送らないように
### 🐛Fixes
* リアクションの修正
* Fix Media List in CW Content
12.31.0 (2020/4/14)
-------------------
### ✨Improvements
* プロキシの除外ホスト指定とオブジェクトストレージへの適用を除外するオプション
* AiScript
* モデレーション関連機能
* sensitiveではないメディアも非表示にできるように
* 投稿のURLプレビューポップアップを改良
* リモートのカスタム絵文字リアクションを表示できるように
### 🐛Fixes
* リアクションカウントがおかしくなることがあるのを修正
12.30.0 (2020/4/11)
-------------------
### ✨Improvements
* リクエストライブラリをrequestからnode-fetchに変更
* オブジェクトストレージのhttpスキーマリクエストでもProxyが適用されるように
* DNSキャッシュとKeep-Alive適用箇所を増やす
* ドイツ語と中国語(繁体)を有効に
* NSFWを再度隠せるように
* Implement AiScript scratchpad (/scratchpad)
### 🐛Fixes
* APのurl処理の修正
12.29.0 (2020/4/5)
-------------------
### ✨Improvements
* トークン系の乱数ソースではcryptoを使うように
* broadcast stream が追加され emojiAdded イベントをサポート
* APIリファレンスの高速化等
* Ability to set header image for a Page
* ログの改善
### 🐛Fixes
* アプリ一覧に1回も使用していないアプリが表示されないのを修正
* admin/accounts/createで一般ユーザーがアカウントを作成し放題なのを修正
* 翻訳の未適用箇所を修正
* APIの権限設定漏れを修正
* インストール直後にアクティビティが飛んで来たりするともう初期管理者セットアップがができなくなるのを修正
* リモート投稿でurlがあればそちらをリンクするように修正
12.28.0 (2020/3/29)
-------------------
### ✨Improvements

View File

@@ -41,8 +41,8 @@ addToList: "Zur Liste hinzufügen"
sendMessage: "Nachricht senden"
copyUsername: "Benutzernamen kopieren"
reply: "Antworten"
loadMore: "Zeige mehr"
youGotNewFollower: "Sie haben einen neuen Follower"
loadMore: "Mehr anzeigen"
youGotNewFollower: "Du hast einen neuen Follower"
receiveFollowRequest: "Follow-Anfrage erhalten."
followRequestAccepted: "Follow-Anfrage akzeptiert"
mentions: "Erwähnungen"
@@ -265,6 +265,7 @@ watch: "Beobachten"
unwatch: "Nicht mehr beobachten"
accept: "Akzeptieren"
reject: "Ablehnen"
normal: "Normal"
instanceName: "Name der Instanz"
instanceDescription: "Beschreibung der Instanz"
maintainerName: "Betreiber"
@@ -319,6 +320,7 @@ notesAndReplies: "Notizen und Antworten"
withFiles: "Dateien beinhalten"
silence: "Instanzweit stummschalten"
silenceConfirm: "Möchtest du diesen Benutzer wirklich instanzweit stummschalten?"
unsilence: "Instanzweite Stummschaltung aufheben"
unsilenceConfirm: "Möchtest du die instanzweite Stummschaltung dieses Benutzers wirklich aufheben?"
popularUsers: "Beliebte Benutzer"
recentlyUpdatedUsers: "Vor kurzem aktive Benutzer"
@@ -331,7 +333,7 @@ userList: "Listen"
about: "Über"
aboutMisskey: "Über Misskey"
aboutMisskeyText: "Misskey ist Open-Source-Software die von syuilo seit 2014 entwickelt wird."
misskeyMembers: "Sie wird momentan von den unten aufgelisteten Mitgliedern weiterentwickelt und instand gehalten:"
misskeyMembers: "Misskey wird momentan von den unten aufgelisteten Mitgliedern weiterentwickelt und instand gehalten:"
misskeySource: "Der Quelltext ist hier verfügbar:"
misskeyTranslation: "Hilf dabei, Misskey zu übersetzen:"
misskeyDonate: "Spende an Misskey, um die Weiterentwicklung zu unterstützen:"
@@ -353,7 +355,7 @@ newPasswordIs: "Das neue Passwort ist \"{password}\""
post: "Beitrag"
posted: "Gesendet"
autoReloadWhenDisconnected: "Automatisch aktualisieren wenn die Serververbindung getrennt wird"
autoNoteWatch: "Notiz automatisch beobachten"
autoNoteWatch: "Notizen automatisch beobachten"
autoNoteWatchDescription: "Werde über Notizen, auf die du reagiert oder geantwortet hast, informiert"
reduceUiAnimation: "Animationen der Benutzeroberfläche reduzieren"
share: "Teilen"
@@ -454,6 +456,8 @@ objectStorageRegion: "Region"
objectStorageRegionDesc: "Gib eine Region (wie z.B. \"xx-east-1\") an. Falls dein Anbieter nicht zwischen Regionen unterscheidet, lass dieses Feld leer oder gib \"us-east-1\" an."
objectStorageUseSSL: "SSL verwenden"
objectStorageUseSSLDesc: "Deaktiviere dies falls du für die API-Verbindungen kein HTTPS verwenden wirst"
objectStorageUseProxy: "Über Proxy verbinden"
objectStorageUseProxyDesc: "Deaktiviere dies falls du keinen Proxy für den Objektspeicher verwenden wirst"
serverLogs: "Serverprotokolle"
deleteAll: "Alle löschen"
showFixedPostForm: "Bereich zum Schreiben neuer Notizen am Anfang der Chronik anzeigen"
@@ -476,7 +480,18 @@ state: "Status"
sort: "Sortieren"
ascendingOrder: "Aufsteigende Reihenfolge"
descendingOrder: "Absteigende Reihenfolge"
scratchpad: "Testumgebung"
scratchpadDescription: "Die Testumgebung bietet eine experimentale Umgebung für AiScript. Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Misskey überprüfen."
output: "Ausgabe"
script: "Skript"
disablePagesScript: "AiScript auf Seiten deaktivieren"
updateRemoteUser: "Informationen über den Benutzer der fremder Instanz aktualisieren"
deleteAllFiles: "Alle Dateien löschen"
deleteAllFilesConfirm: "Möchtest du wirklich alle Dateien löschen?"
removeAllFollowing: "Allen gefolgten Benutzern entfolgen"
removeAllFollowingDescription: "Allen Benutzerkonten von {host} entfolgen. Bitte führe dies durch, falls diese Instanz nicht mehr existiert."
userSuspended: "Dieser Benutzer wurde gesperrt."
userSilenced: "Dieser Benutzer wurde instanzweit stummgeschaltet."
_theme:
explore: "Themen erforschen"
install: "Thema installieren"
@@ -600,7 +615,7 @@ _widgets:
photos: "Fotos"
_cw:
hide: "Ausblenden"
show: "Zeige mehr"
show: "Mehr anzeigen"
chars: "{count} Zeichen"
files: "{count} Dateien"
poll: "Umfrage"
@@ -656,9 +671,9 @@ _profile:
metadataContent: "Inhalt"
_exportOrImport:
allNotes: "Alle Notizen"
followingList: "Folgen"
muteList: "Stummschalten"
blockingList: "Blockieren"
followingList: "Gefolgte Benutzer"
muteList: "Stummschaltungen"
blockingList: "Blockierungen"
userLists: "Listen"
_charts:
federationInstancesIncDec: "Unterschied in der Anzahl von förderierenden Instanzen"
@@ -780,6 +795,9 @@ _pages:
message: "Nachricht, die bei Aktivierung gezeigt werden soll"
variable: "Variable, die gesendet werden soll"
no-variable: "Keine"
callAiScript: "AiScript ausführen"
_callAiScript:
functionName: "Funktionsname"
radioButton: "Optionsfeld"
_radioButton:
name: "Variablenname"
@@ -940,6 +958,7 @@ _pages:
_splitStrByLine:
arg1: "Text"
ref: "Variablen"
aiScriptVar: "AiScript Variablen"
fn: "Funktionen"
_fn:
slots: "Slots"

View File

@@ -770,6 +770,11 @@ _pages:
name: "Variable name"
text: "Title"
default: "Default value"
canvas: "Canvas"
_canvas:
id: "Canvas ID"
width: "Width"
height: "Height"
switch: "Switch"
_switch:
name: "Variable name"

View File

@@ -60,7 +60,7 @@ lists: "Listas"
noLists: "No tiene listas"
note: "Notas"
notes: "Notas"
following: "Sigue"
following: "Siguiendo"
followers: "Seguidores"
followsYou: "Te sigue"
createList: "Crear lista"
@@ -488,6 +488,10 @@ disablePagesScript: "Deshabilitar AiScript en Páginas"
updateRemoteUser: "Actualizar información de usuario remoto"
deleteAllFiles: "Borrar todos los archivos"
deleteAllFilesConfirm: "¿Desea borrar todos los archivos?"
removeAllFollowing: "Retener todos los siguientes"
removeAllFollowingDescription: "Cancelar todos los siguientes del servidor {host}. Ejecutar en caso de que esta instancia haya dejado de existir"
userSuspended: "Este usuario ha sido suspendido."
userSilenced: "Este usuario ha sido silenciado."
_theme:
explore: "Explorar temas"
install: "Instalar tema"
@@ -766,6 +770,11 @@ _pages:
name: "Nombre de variable"
text: "Título"
default: "Valor predeterminado"
canvas: "Lienzo"
_canvas:
id: "Lienzo ID"
width: "Ancho"
height: "Altura"
switch: "Interruptor"
_switch:
name: "Nombre de variable"

View File

@@ -491,7 +491,7 @@ deleteAllFilesConfirm: "Êtes vous surs de vouloir supprimer tous les fichiers ?
removeAllFollowing: "Retenir tous les abonnements"
removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Exécutez cette commande si l'instance n'existe plus."
userSuspended: "Cette utilisateur·trice a été suspendue."
userSilenced: "Cette utilisateur·trice a été masquer.\n"
userSilenced: "Cette utilisateur·trice a été masquer."
_theme:
explore: "Explorer les thèmes"
install: "Installer un thème"
@@ -770,6 +770,11 @@ _pages:
name: "Nom de la variable"
text: "Titre"
default: "Valeur par défaut"
canvas: "Toile"
_canvas:
id: "Toile ID"
width: "Largeur"
height: "Hauteur"
switch: "Basculer"
_switch:
name: "Nom de la variable"

View File

@@ -797,6 +797,12 @@ _pages:
text: "タイトル"
default: "デフォルト値"
canvas: "キャンバス"
_canvas:
id: "キャンバスID"
width: "幅"
height: "高さ"
switch: "スイッチ"
_switch:
name: "変数名"

View File

@@ -481,7 +481,7 @@ sort: "정렬"
ascendingOrder: "오름차순"
descendingOrder: "내림차순"
scratchpad: "스크래치 패드"
scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을 제공합니다.\nMisskey 와 상호 작용하는 코드를 작성, 실행 및 결과를 확인할 수 있습니다."
scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을 제공합니다. Misskey 와 상호 작용하는 코드를 작성, 실행 및 결과를 확인할 수 있습니다."
output: "출력"
script: "스크립트"
disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음"
@@ -770,6 +770,11 @@ _pages:
name: "변수명"
text: "제목"
default: "기본값"
canvas: "캔버스"
_canvas:
id: "캔버스 ID"
width: "폭"
height: "높이"
switch: "스위치"
_switch:
name: "변수명"

View File

@@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.31.0",
"version": "12.33.0",
"codename": "indigo",
"repository": {
"type": "git",
@@ -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.1",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.12.1",
"@types/cbor": "5.0.0",

View File

@@ -34,9 +34,7 @@ export default Vue.extend({
default: false
},
// specify the parent element
parentElement: {
type: Object
}
parentElement: {}
},
data() {
return {
@@ -69,7 +67,7 @@ export default Vue.extend({
if (this.$refs.gridOuter) {
let height = 287;
const parent = this.$props.parentElement || this.$parent.$el;
const parent = this.parentElement || this.$parent.$el;
if (this.$refs.gridOuter.clientHeight) {
height = this.$refs.gridOuter.clientHeight;
@@ -83,6 +81,11 @@ export default Vue.extend({
}
});
}
},
watch: {
parentElement() {
this.size();
}
}
});
</script>

View File

@@ -33,7 +33,7 @@
<mk-avatar class="avatar" :user="appearNote.user"/>
<div class="main">
<x-note-header class="header" :note="appearNote" :mini="true"/>
<div class="body" v-if="appearNote.deletedAt == null">
<div class="body" v-if="appearNote.deletedAt == null" ref="noteBody">
<p v-if="appearNote.cw != null" class="cw">
<mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" />
<x-cw-button v-model="showContent" :note="appearNote"/>
@@ -46,7 +46,7 @@
<a class="rp" v-if="appearNote.renote != null">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">
<x-media-list :media-list="appearNote.files"/>
<x-media-list :media-list="appearNote.files" :parent-element="noteBody"/>
</div>
<x-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :compact="true" class="url-preview"/>
@@ -142,6 +142,7 @@ export default Vue.extend({
replies: [],
showContent: false,
hideThisNote: false,
noteBody: this.$refs.noteBody,
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan
};
},
@@ -254,6 +255,8 @@ export default Vue.extend({
if (this.$store.getters.isSignedIn) {
this.connection.on('_connected_', this.onStreamConnected);
}
this.noteBody = this.$refs.noteBody
},
beforeDestroy() {

View File

@@ -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: {

View File

@@ -0,0 +1,29 @@
<template>
<div>
<canvas ref="canvas" class="ysrxegms" :width="value.width" :height="value.height"/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
value: {
required: true
},
script: {
required: true
}
},
mounted() {
this.script.aoiScript.registerCanvas(this.value.name, this.$refs.canvas);
}
});
</script>
<style lang="scss" scoped>
.ysrxegms {
display: block;
}
</style>

View File

@@ -21,39 +21,11 @@ class Script {
public vars: Record<string, any>;
public page: Record<string, any>;
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();
},

View File

@@ -1,7 +1,7 @@
<template>
<button
class="hkzvhatu _button"
:class="{ reacted: note.myReaction == reaction }"
:class="{ reacted: note.myReaction == reaction, canToggle }"
@click="toggleReaction(reaction)"
v-if="count > 0"
@mouseover="onMouseover"
@@ -40,11 +40,6 @@ export default Vue.extend({
type: Object,
required: true,
},
canToggle: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
@@ -57,6 +52,9 @@ export default Vue.extend({
isMe(): boolean {
return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId;
},
canToggle(): boolean {
return !this.reaction.match(/@\w/);
},
},
mounted() {
if (!this.isInitial) this.anime();
@@ -144,6 +142,18 @@ export default Vue.extend({
padding: 0 6px;
border-radius: 4px;
&.canToggle {
background: rgba(0, 0, 0, 0.05);
&:hover {
background: rgba(0, 0, 0, 0.1);
}
}
&:not(.canToggle) {
cursor: default;
}
&.reacted {
background: var(--accent);
@@ -152,14 +162,6 @@ export default Vue.extend({
}
}
&:not(.reacted) {
background: rgba(0, 0, 0, 0.05);
&:hover {
background: rgba(0, 0, 0, 0.1);
}
}
> span {
font-size: 0.9em;
line-height: 32px;

View File

@@ -0,0 +1,45 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faPaintBrush"/> {{ $t('_pages.blocks.canvas') }}</template>
<section style="padding: 0 16px 0 16px;">
<mk-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('_pages.blocks._canvas.id') }}</span></mk-input>
<mk-input v-model="value.width" type="number"><span>{{ $t('_pages.blocks._canvas.width') }}</span><template #suffix>px</template></mk-input>
<mk-input v-model="value.height" type="number"><span>{{ $t('_pages.blocks._canvas.height') }}</span><template #suffix>px</template></mk-input>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faPaintBrush, faMagic } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../i18n';
import XContainer from '../page-editor.container.vue';
import MkInput from '../../../components/ui/input.vue';
export default Vue.extend({
i18n,
components: {
XContainer, MkInput
},
props: {
value: {
required: true
},
},
data() {
return {
faPaintBrush, faMagic
};
},
created() {
if (this.value.name == null) Vue.set(this.value, 'name', '');
if (this.value.width == null) Vue.set(this.value, 'width', 300);
if (this.value.height == null) Vue.set(this.value, 'height', 200);
},
});
</script>

View File

@@ -2,7 +2,7 @@
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faQuestion"/> {{ $t('_pages.blocks.if') }}</template>
<template #func>
<button @click="add()">
<button @click="add()" class="_button">
<fa :icon="faPlus"/>
</button>
</template>

View File

@@ -2,10 +2,10 @@
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faStickyNote"/> {{ value.title }}</template>
<template #func>
<button @click="rename()">
<button @click="rename()" class="_button">
<fa :icon="faPencilAlt"/>
</button>
<button @click="add()">
<button @click="add()" class="_button">
<fa :icon="faPlus"/>
</button>
</template>

View File

@@ -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: {

View File

@@ -18,7 +18,7 @@
</header>
<p v-show="showBody" class="error" v-if="error != null">{{ $t('_pages.script.typeError', { slot: error.arg + 1, expect: $t(`script.types.${error.expect}`), actual: $t(`script.types.${error.actual}`) }) }}</p>
<p v-show="showBody" class="warn" v-if="warn != null">{{ $t('_pages.script.thereIsEmptySlot', { slot: warn.slot + 1 }) }}</p>
<div v-show="showBody">
<div v-show="showBody" class="body">
<slot></slot>
</div>
</div>
@@ -148,5 +148,17 @@ export default Vue.extend({
padding: 16px 16px 0 16px;
font-size: 14px;
}
> .body {
::v-deep .juejbjww, ::v-deep .eiipwacr {
&:not(.inline):first-child {
margin-top: 28px;
}
&:not(.inline):last-child {
margin-bottom: 20px;
}
}
}
}
</style>

View File

@@ -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;

View File

@@ -17,8 +17,9 @@ export class ASEvaluator {
private variables: Variable[];
private pageVars: PageVar[];
private envVars: Record<keyof typeof envVarsDef, any>;
public aiscript: AiScript | undefined;
public aiscript?: AiScript;
private pageVarUpdatedCallback;
private canvases: Record<string, HTMLCanvasElement> = {};
private opts: {
randomSeed: string; visitor?: any; page?: any; url?: string;
@@ -36,6 +37,29 @@ 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) })],
['arc', values.FN_NATIVE(([x, y, radius, startAngle, endAngle]) => { ctx.arc(x.value, y.value, radius.value, startAngle.value, endAngle.value) })],
['fill', values.FN_NATIVE(() => { ctx.fill() })],
['stroke', values.FN_NATIVE(() => { ctx.stroke() })],
]));
})
}}, {
in: (q) => {
@@ -73,10 +97,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 +176,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;
}

View File

@@ -128,6 +128,7 @@ export const envVarsDef: Record<string, Type> = {
IS_CAT: 'boolean',
SEED: null,
YMD: 'string',
AISCRIPT_DISABLED: 'boolean',
NULL: null,
};

View File

@@ -110,6 +110,7 @@ export class ASTypeChecker {
return null;
}
if (v.type === 'aiScriptVar') return null;
if (v.type === 'fn') return null; // todo
if (v.type.startsWith('fn:')) return null; // todo

View File

@@ -26,6 +26,8 @@ export function convertLegacyReactions(reactions: Record<string, number>) {
const _reactions = {} as Record<string, number>;
for (const reaction of Object.keys(reactions)) {
if (reactions[reaction] <= 0) continue;
if (Object.keys(legacies).includes(reaction)) {
if (_reactions[legacies[reaction]]) {
_reactions[legacies[reaction]] += reactions[reaction];
@@ -68,7 +70,7 @@ export async function toDbReaction(reaction?: string | null, reacterHost?: strin
return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, '');
}
const custom = reaction.match(/^:([\w+-]+):$/);
const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
if (custom) {
const name = custom[1];
const emoji = await Emojis.findOne({

View File

@@ -72,13 +72,13 @@ export default async (user: User, note: Note, reaction?: string) => {
if (emoji) {
emoji = {
name: emoji.host ? `${emoji.name}@${emoji.host}` : `${emoji.name}`,
name: emoji.host ? `${emoji.name}@${emoji.host}` : `${emoji.name}@.`,
url: emoji.url
} as any;
}
publishNoteStream(note.id, 'reacted', {
reaction: reaction,
reaction: decodedReaction.reaction,
emoji: emoji,
userId: user.id
});

View File

@@ -7,6 +7,7 @@ import { IdentifiableError } from '../../../misc/identifiable-error';
import { User, IRemoteUser } from '../../../models/entities/user';
import { Note } from '../../../models/entities/note';
import { NoteReactions, Users, Notes } from '../../../models';
import { decodeReaction } from '../../../misc/reaction-lib';
export default async (user: User, note: Note) => {
// if already unreacted
@@ -38,7 +39,7 @@ export default async (user: User, note: Note) => {
Notes.decrement({ id: note.id }, 'score', 1);
publishNoteStream(note.id, 'unreacted', {
reaction: exist.reaction,
reaction: decodeReaction(exist.reaction).reaction,
userId: user.id
});

View File

@@ -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.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@syuilo/aiscript/-/aiscript-0.3.1.tgz#40176c4a4f7803e62c8cbdf571c52c227b2e7444"
integrity sha512-xqdkVBFEjHZlKG9gQMdbCGVPTrWDA39mdpSN8nl6PlETkcjMRlnZ9HKEZrbP4HsSnyPWwTUzs/m7lsvuqt/zaw==
dependencies:
"@types/seedrandom" "2.4.28"
autobind-decorator "2.4.0"