Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
2314133112 | |||
06a47a7bd3 | |||
05a785ebd0 | |||
2ee5835186 | |||
19e1abe110 | |||
d19441f3ae | |||
6e3ee05cb6 | |||
51476ad06f | |||
1f998168e2 | |||
e72011f1da | |||
0df3e22e51 | |||
5a9530ccd4 | |||
0a4d119d86 | |||
2ee0e07bb6 | |||
533c9a4fe1 | |||
30c000116f | |||
dc649fe420 | |||
4a8ec173ae | |||
26d6fe9a4e | |||
46f5175a0d | |||
f704e7a602 | |||
8cefcaa55f | |||
164c6505f2 | |||
0a1b83c70f |
@ -152,7 +152,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/28779508/3cd4cb7f017f4ee0864341e3464d42f9/1.png?token-time=2145916800&token-hash=eGQtR15be44kgvh8fw2Jx8Db4Bv15YBp2ldxh0EKRxA%3D" alt="S Y" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/16542964" alt="Takumi Sugita" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/26340354/08834cf767b3449e93098ef73a434e2f/2.png?token-time=2145916800&token-hash=nyM8DnKRL8hR47HQ619mUzsqVRpkWZjgtgBU9RY15Uc%3D" alt="totokoro " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5827393/59893c191dda408f9cabd0f20a3a5627/1.jpeg?token-time=2145916800&token-hash=i9N05vOph-eP1LTLb9_npATjYOpntL0ZsHNaZFSsPmE%3D" alt="motcha " width="100"></td>
|
||||
@ -162,7 +162,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/user?u=28779508">S Y</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=16542964">Takumi Sugita</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin </a></td>
|
||||
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI </a></td>
|
||||
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=26340354">totokoro </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=19356899">sheeta.s </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=5827393">motcha </a></td>
|
||||
@ -204,7 +204,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||
</tr></table>
|
||||
|
||||
**Last updated:** Fri, 03 Apr 2020 11:52:08 UTC
|
||||
**Last updated:** Sun, 19 Apr 2020 11:51:06 UTC
|
||||
<!-- PATREON_END -->
|
||||
|
||||
[backer-url]: #backers
|
||||
|
@ -27,7 +27,7 @@ uploading: "Upload läuft"
|
||||
save: "Speichern"
|
||||
users: "Benutzer"
|
||||
addUser: "Benutzer hinzufügen"
|
||||
favorite: "Favorit"
|
||||
favorite: "Zu Favoriten hinzufügen"
|
||||
favorites: "Favoriten"
|
||||
unfavorite: "Aus Favoriten entfernen"
|
||||
pin: "Anheften"
|
||||
@ -239,6 +239,8 @@ drive: "Drive"
|
||||
fileName: "Dateiname"
|
||||
selectFile: "Datei auswählen"
|
||||
selectFiles: "Dateien auswählen"
|
||||
selectFolder: "Wähle einen Ordner"
|
||||
selectFolders: "Wähle Ordner"
|
||||
renameFile: "Datei umbenennen"
|
||||
folderName: "Ordnername"
|
||||
createFolder: "Ordner erstellen"
|
||||
@ -317,7 +319,7 @@ caseSensitive: "Groß-/Kleinschreibung unterscheiden"
|
||||
withReplies: "Antworten beinhalten"
|
||||
connectedTo: "Mit folgenden Benutzerkonten verknüpft"
|
||||
notesAndReplies: "Notizen und Antworten"
|
||||
withFiles: "Dateien beinhalten"
|
||||
withFiles: "Notizen mit Dateien"
|
||||
silence: "Instanzweit stummschalten"
|
||||
silenceConfirm: "Möchtest du diesen Benutzer wirklich instanzweit stummschalten?"
|
||||
unsilence: "Instanzweite Stummschaltung aufheben"
|
||||
@ -352,8 +354,6 @@ unregister: "Deaktivieren"
|
||||
passwordLessLogin: "Passwortloses Anmelden einrichten"
|
||||
resetPassword: "Passwort zurücksetzen"
|
||||
newPasswordIs: "Das neue Passwort ist \"{password}\""
|
||||
post: "Beitrag"
|
||||
posted: "Gesendet"
|
||||
autoReloadWhenDisconnected: "Automatisch aktualisieren wenn die Serververbindung getrennt wird"
|
||||
autoNoteWatch: "Notizen automatisch beobachten"
|
||||
autoNoteWatchDescription: "Werde über Notizen, auf die du reagiert oder geantwortet hast, informiert"
|
||||
@ -755,6 +755,7 @@ _pages:
|
||||
post: "Neue Notiz anfertigen"
|
||||
_post:
|
||||
text: "Inhalt"
|
||||
attachCanvasImage: "Leinwand als Bild anfügen"
|
||||
canvasId: "Leinwand-ID"
|
||||
textInput: "Texteingabe"
|
||||
_textInput:
|
||||
|
@ -239,6 +239,8 @@ drive: "Drive"
|
||||
fileName: "Filename"
|
||||
selectFile: "Select a file"
|
||||
selectFiles: "Select files"
|
||||
selectFolder: "Select a folder"
|
||||
selectFolders: "Select folders"
|
||||
renameFile: "Rename file"
|
||||
folderName: "Folder name"
|
||||
createFolder: "Create a folder"
|
||||
@ -352,8 +354,6 @@ unregister: "Unregister"
|
||||
passwordLessLogin: "Set up password-less login"
|
||||
resetPassword: "Reset password"
|
||||
newPasswordIs: "The new password is \"{password}\""
|
||||
post: "Post"
|
||||
posted: "Posted!"
|
||||
autoReloadWhenDisconnected: "Auto refresh when disconnected from server"
|
||||
autoNoteWatch: "Watch note automatically"
|
||||
autoNoteWatchDescription: "Get notified about the notes which you reactioned or replied."
|
||||
@ -755,6 +755,7 @@ _pages:
|
||||
post: "Compose a note"
|
||||
_post:
|
||||
text: "Content"
|
||||
attachCanvasImage: "Post with Canvas as Image"
|
||||
canvasId: "Canvas ID"
|
||||
textInput: "Text input"
|
||||
_textInput:
|
||||
|
@ -239,6 +239,8 @@ drive: "Drive"
|
||||
fileName: "Nombre de archivo"
|
||||
selectFile: "Elegir archivo"
|
||||
selectFiles: "Elegir archivos"
|
||||
selectFolder: "Seleccione una carpeta"
|
||||
selectFolders: "Seleccione carpetas"
|
||||
renameFile: "Renombrar archivo"
|
||||
folderName: "Nombre de la carpeta"
|
||||
createFolder: "Crear carpeta"
|
||||
@ -352,8 +354,6 @@ unregister: "Cancelar registro"
|
||||
passwordLessLogin: "Iniciar sesión sin contraseña"
|
||||
resetPassword: "Resetear contraseña"
|
||||
newPasswordIs: "La nueva contraseña es \"{password}\""
|
||||
post: "Nota"
|
||||
posted: "Posteado"
|
||||
autoReloadWhenDisconnected: "Recargar automáticamente cuando el servidor está desconectado"
|
||||
autoNoteWatch: "Ver nota automáticamente"
|
||||
autoNoteWatchDescription: "Recibe notificaciones sobre las notas de otros usuarios que a los que respondiste y reaccionaste"
|
||||
@ -755,6 +755,7 @@ _pages:
|
||||
post: "Formulario"
|
||||
_post:
|
||||
text: "Contenido"
|
||||
attachCanvasImage: "Nota con lienzo como imagen"
|
||||
canvasId: "Lienzo ID"
|
||||
textInput: "Entrada de texto"
|
||||
_textInput:
|
||||
|
@ -239,6 +239,8 @@ drive: "Drive"
|
||||
fileName: "Nom du fichier"
|
||||
selectFile: "Choisir le fichier"
|
||||
selectFiles: "Choisir le fichiers"
|
||||
selectFolder: "Sélectionnez un dossier"
|
||||
selectFolders: "Sélectionnez dossiers"
|
||||
renameFile: "Renommer le ficher"
|
||||
folderName: "Nom du dossier"
|
||||
createFolder: "Créer un dossier"
|
||||
@ -352,8 +354,6 @@ unregister: "Se désinscrire"
|
||||
passwordLessLogin: "Connectez-vous sans mot de passe"
|
||||
resetPassword: "Réinitialiser mot de passe"
|
||||
newPasswordIs: "Votre nouveau mot de passe est \"{password}\""
|
||||
post: "Publier"
|
||||
posted: "Publié !"
|
||||
autoReloadWhenDisconnected: "Rechargement automatique lorsque le serveur se déconnecte"
|
||||
autoNoteWatch: "Surveiller automatique pour les notes"
|
||||
autoNoteWatchDescription: "Soyez informé des notes auxquelles vous avez réagi ou répondu."
|
||||
@ -755,6 +755,7 @@ _pages:
|
||||
post: "Formulaire à publier"
|
||||
_post:
|
||||
text: "Contenu"
|
||||
attachCanvasImage: "Publier avec Toile comme image"
|
||||
canvasId: "Toile ID"
|
||||
textInput: "Entrée de textuelle"
|
||||
_textInput:
|
||||
|
@ -239,6 +239,8 @@ drive: "ドライブ"
|
||||
fileName: "ファイル名"
|
||||
selectFile: "ファイルを選択"
|
||||
selectFiles: "ファイルを選択"
|
||||
selectFolder: "フォルダーを選択"
|
||||
selectFolders: "フォルダーを選択"
|
||||
renameFile: "ファイル名を変更"
|
||||
folderName: "フォルダー名"
|
||||
createFolder: "フォルダーを作成"
|
||||
@ -352,8 +354,6 @@ unregister: "登録を解除"
|
||||
passwordLessLogin: "パスワード無しログイン"
|
||||
resetPassword: "パスワードをリセット"
|
||||
newPasswordIs: "新しいパスワードは「{password}」です"
|
||||
post: "投稿"
|
||||
posted: "投稿しました"
|
||||
autoReloadWhenDisconnected: "サーバー切断時に自動リロード"
|
||||
autoNoteWatch: "ノートの自動ウォッチ"
|
||||
autoNoteWatchDescription: "あなたがリアクションしたり返信したりした他のユーザーのノートに関する通知を受け取るようにします。"
|
||||
|
@ -239,6 +239,8 @@ drive: "드라이브"
|
||||
fileName: "파일명"
|
||||
selectFile: "파일 선택"
|
||||
selectFiles: "파일 선택"
|
||||
selectFolder: "폴더 선택"
|
||||
selectFolders: "폴더 선택"
|
||||
renameFile: "파일 이름 변경"
|
||||
folderName: "폴더명"
|
||||
createFolder: "폴더 만들기"
|
||||
@ -352,8 +354,6 @@ unregister: "등록 해제"
|
||||
passwordLessLogin: "비밀번호 없이 로그인"
|
||||
resetPassword: "비밀번호 재설정"
|
||||
newPasswordIs: "새로운 비밀번호는 \"{password}\" 입니다"
|
||||
post: "작성"
|
||||
posted: "게시하였습니다"
|
||||
autoReloadWhenDisconnected: "서버와의 연결이 끊기면 자동 새로고침"
|
||||
autoNoteWatch: "노트를 자동으로 지켜보기"
|
||||
autoNoteWatchDescription: "리액션하거나 답글을 남긴 다른 유저의 노트에 대한 알림을 받습니다."
|
||||
@ -755,6 +755,7 @@ _pages:
|
||||
post: "글 입력란"
|
||||
_post:
|
||||
text: "내용"
|
||||
attachCanvasImage: "캔버스의 이미지와 함께 게시하기"
|
||||
canvasId: "캔버스 ID"
|
||||
textInput: "텍스트 입력"
|
||||
_textInput:
|
||||
|
@ -239,6 +239,8 @@ drive: "网盘"
|
||||
fileName: "文件名称"
|
||||
selectFile: "选择文件"
|
||||
selectFiles: "选择文件"
|
||||
selectFolder: "选择文件夹"
|
||||
selectFolders: "选择多个文件夹"
|
||||
renameFile: "重命名文件"
|
||||
folderName: "文件夹名称"
|
||||
createFolder: "创建文件夹"
|
||||
@ -265,6 +267,7 @@ watch: "关注"
|
||||
unwatch: "取消关注"
|
||||
accept: "允许"
|
||||
reject: "拒绝"
|
||||
normal: "正常"
|
||||
instanceName: "实例名称"
|
||||
instanceDescription: "实例介绍"
|
||||
maintainerName: "管理员名称"
|
||||
@ -319,6 +322,7 @@ notesAndReplies: "帖子与回复"
|
||||
withFiles: "附件"
|
||||
silence: "禁言"
|
||||
silenceConfirm: "确认要禁言吗?"
|
||||
unsilence: "解除禁言"
|
||||
unsilenceConfirm: "要解除禁言吗?"
|
||||
popularUsers: "热门用户"
|
||||
recentlyUpdatedUsers: "最近投稿用户"
|
||||
@ -350,8 +354,6 @@ unregister: "删除账户"
|
||||
passwordLessLogin: "无密码登录"
|
||||
resetPassword: "重置密码"
|
||||
newPasswordIs: "新的密码是「{password}」"
|
||||
post: "投稿"
|
||||
posted: "已投稿"
|
||||
autoReloadWhenDisconnected: "断开连接时自动重新加载"
|
||||
autoNoteWatch: "自动关注帖子"
|
||||
autoNoteWatchDescription: "让您能够收到关于「反应」和回复其他用户的帖子的通知。"
|
||||
@ -454,6 +456,8 @@ objectStorageRegion: "可用区"
|
||||
objectStorageRegionDesc: "指定一个可用区,例如“xx-east-1”。 如果您的对象存储服务没有可用区概念,请将其留空或填写“us-east-1”。"
|
||||
objectStorageUseSSL: "使用SSL"
|
||||
objectStorageUseSSLDesc: "如果不使用https进行API连接,请关闭。"
|
||||
objectStorageUseProxy: "使用代理"
|
||||
objectStorageUseProxyDesc: "如果您不使用代理进行API连接,请将其关闭。"
|
||||
serverLogs: "服务器日志"
|
||||
deleteAll: "删除全部"
|
||||
showFixedPostForm: "在时间线顶部显示帖子表单"
|
||||
@ -476,7 +480,18 @@ state: "状态"
|
||||
sort: "排序"
|
||||
ascendingOrder: "升序"
|
||||
descendingOrder: "降序"
|
||||
scratchpad: "暂存器"
|
||||
scratchpadDescription: "暂存器为AiScript提供了实验环境。您可以编写代码以与Misskey交互,运行它并查看结果。"
|
||||
output: "输出"
|
||||
script: "脚本"
|
||||
disablePagesScript: "禁用页面脚本"
|
||||
updateRemoteUser: "更新远程用户信息"
|
||||
deleteAllFiles: "删除所有文件"
|
||||
deleteAllFilesConfirm: "要删除所有文件吗?"
|
||||
removeAllFollowing: "取消所有关注"
|
||||
removeAllFollowingDescription: "取消{host}的所有关注者。当实例不存在时执行。"
|
||||
userSuspended: "该用户已被冻结。"
|
||||
userSilenced: "该用户已被禁言。"
|
||||
_theme:
|
||||
explore: "寻找主题"
|
||||
install: "安装主题"
|
||||
@ -740,6 +755,8 @@ _pages:
|
||||
post: "投稿窗口"
|
||||
_post:
|
||||
text: "内容"
|
||||
attachCanvasImage: "附加画布图像"
|
||||
canvasId: "画布ID"
|
||||
textInput: "文本输入"
|
||||
_textInput:
|
||||
name: "变量名"
|
||||
@ -755,6 +772,11 @@ _pages:
|
||||
name: "变量名"
|
||||
text: "标题"
|
||||
default: "默认值"
|
||||
canvas: "画布"
|
||||
_canvas:
|
||||
id: "画布ID"
|
||||
width: "宽度"
|
||||
height: "高度"
|
||||
switch: "开关"
|
||||
_switch:
|
||||
name: "变量名"
|
||||
@ -780,6 +802,9 @@ _pages:
|
||||
message: "按下时显示的消息"
|
||||
variable: "发送的变量"
|
||||
no-variable: "空"
|
||||
callAiScript: "调用AiScript"
|
||||
_callAiScript:
|
||||
functionName: "函数名"
|
||||
radioButton: "选择项"
|
||||
_radioButton:
|
||||
name: "变量名"
|
||||
@ -940,6 +965,7 @@ _pages:
|
||||
_splitStrByLine:
|
||||
arg1: "文本"
|
||||
ref: "变量"
|
||||
aiScriptVar: "AiScript变量"
|
||||
fn: "函数"
|
||||
_fn:
|
||||
slots: "槽函数"
|
||||
|
@ -256,8 +256,6 @@ userList: "清單"
|
||||
passwordLessLogin: "設置無密碼登入"
|
||||
resetPassword: "重置密碼"
|
||||
newPasswordIs: "新密碼為「{password}」"
|
||||
post: "投稿"
|
||||
posted: "投稿完成"
|
||||
autoReloadWhenDisconnected: "和伺服器斷線時自動重新載入"
|
||||
autoNoteWatch: "自動關注筆記"
|
||||
autoNoteWatchDescription: "收到反應或回覆過的筆記的通知"
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.35.1",
|
||||
"version": "12.36.1",
|
||||
"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.4.0",
|
||||
"@syuilo/aiscript": "0.6.0",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.12.2",
|
||||
"@types/cbor": "5.0.0",
|
||||
@ -189,7 +189,6 @@
|
||||
"postcss-loader": "3.0.0",
|
||||
"prismjs": "1.20.0",
|
||||
"probe-image-size": "5.0.0",
|
||||
"progress-bar-webpack-plugin": "2.1.0",
|
||||
"promise-limit": "2.7.0",
|
||||
"promise-sequential": "1.1.1",
|
||||
"pug": "2.0.4",
|
||||
@ -223,7 +222,6 @@
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "4.23.3",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"terser-webpack-plugin": "2.3.5",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.115.0",
|
||||
"tinycolor2": "1.4.1",
|
||||
@ -258,7 +256,7 @@
|
||||
"vuex": "3.1.3",
|
||||
"vuex-persistedstate": "3.0.1",
|
||||
"web-push": "3.4.3",
|
||||
"webpack": "4.42.1",
|
||||
"webpack": "5.0.0-beta.15",
|
||||
"webpack-cli": "3.3.11",
|
||||
"websocket": "1.0.31",
|
||||
"ws": "7.2.3",
|
||||
|
@ -163,7 +163,6 @@ import { v4 as uuid } from 'uuid';
|
||||
import i18n from './i18n';
|
||||
import { host, instanceName } from './config';
|
||||
import { search } from './scripts/search';
|
||||
import MkToast from './components/toast.vue';
|
||||
|
||||
const DESKTOP_THRESHOLD = 1100;
|
||||
|
||||
@ -535,14 +534,14 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
|
||||
onNotification(notification) {
|
||||
async onNotification(notification) {
|
||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||
if (true) {
|
||||
this.$root.stream.send('readNotification', {
|
||||
id: notification.id
|
||||
});
|
||||
|
||||
this.$root.new(MkToast, {
|
||||
this.$root.new(await import('./components/toast.vue').then(m => m.default), {
|
||||
notification
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
<template>
|
||||
<x-window ref="window" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="selected.length === 0" @ok="ok()">
|
||||
<template #header>{{ multiple ? $t('selectFiles') : $t('selectFile') }}<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ selected.length | number }})</span></template>
|
||||
<x-window ref="window" :width="800" :height="500" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="(type === 'file') && (selected.length === 0)" @ok="ok()">
|
||||
<template #header>
|
||||
{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
|
||||
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ selected.length | number }})</span>
|
||||
</template>
|
||||
<div>
|
||||
<x-drive :multiple="multiple" @change-selection="onChangeSelection" :select-mode="true"/>
|
||||
<x-drive :multiple="multiple" @change-selection="onChangeSelection" :select="type"/>
|
||||
</div>
|
||||
</x-window>
|
||||
</template>
|
||||
@ -25,7 +28,7 @@ export default Vue.extend({
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: 'file'
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
@ -45,8 +48,8 @@ export default Vue.extend({
|
||||
this.$refs.window.close();
|
||||
},
|
||||
|
||||
onChangeSelection(files) {
|
||||
this.selected = files;
|
||||
onChangeSelection(xs) {
|
||||
this.selected = xs;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -42,11 +42,20 @@ import { faDownload, faLink, faICursor, faTrashAlt } from '@fortawesome/free-sol
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XFileThumbnail
|
||||
},
|
||||
|
||||
props: {
|
||||
file: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isSelected: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
selectMode: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
@ -54,10 +63,6 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
XFileThumbnail
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isDragging: false
|
||||
@ -65,12 +70,10 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
computed: {
|
||||
// TODO: parentへの参照を無くす
|
||||
browser(): any {
|
||||
return this.$parent;
|
||||
},
|
||||
isSelected(): boolean {
|
||||
return this.browser.selectedFiles.some(f => f.id == this.file.id);
|
||||
},
|
||||
title(): string {
|
||||
return `${this.file.name}\n${this.file.type} ${Vue.filter('bytes')(this.file.size)}`;
|
||||
}
|
||||
@ -79,7 +82,7 @@ export default Vue.extend({
|
||||
methods: {
|
||||
onClick(ev) {
|
||||
if (this.selectMode) {
|
||||
this.browser.chooseFile(this.file);
|
||||
this.$emit('chosen', this.file);
|
||||
} else {
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
|
@ -21,6 +21,7 @@
|
||||
<p class="upload" v-if="$store.state.settings.uploadFolder == folder.id">
|
||||
{{ $t('uploadFolder') }}
|
||||
</p>
|
||||
<button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -36,6 +37,16 @@ export default Vue.extend({
|
||||
folder: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isSelected: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
selectMode: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -56,7 +67,12 @@ export default Vue.extend({
|
||||
return this.folder.name;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkboxClicked(e) {
|
||||
this.$emit('chosen', this.folder);
|
||||
},
|
||||
|
||||
onClick() {
|
||||
this.browser.move(this.folder);
|
||||
},
|
||||
@ -241,10 +257,24 @@ export default Vue.extend({
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
* {
|
||||
*:not(.checkbox) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
> .checkbox {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #fff;
|
||||
border: solid 1px #000;
|
||||
|
||||
&.checked {
|
||||
background: var(--accent);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-draghover] {
|
||||
&:after {
|
||||
content: "";
|
||||
|
@ -3,9 +3,9 @@
|
||||
<nav>
|
||||
<div class="path" @contextmenu.prevent.stop="() => {}">
|
||||
<x-nav-folder :class="{ current: folder == null }"/>
|
||||
<template v-for="folder in hierarchyFolders">
|
||||
<span class="separator"><fa :icon="faAngleRight"/></span>
|
||||
<x-nav-folder :folder="folder" :key="folder.id"/>
|
||||
<template v-for="f in hierarchyFolders">
|
||||
<span class="separator" :key="f.id + ':separator'"><fa :icon="faAngleRight"/></span>
|
||||
<x-nav-folder :folder="f" :key="f.id"/>
|
||||
</template>
|
||||
<span class="separator" v-if="folder != null"><fa :icon="faAngleRight"/></span>
|
||||
<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
|
||||
@ -20,15 +20,15 @@
|
||||
>
|
||||
<div class="contents" ref="contents">
|
||||
<div class="folders" ref="foldersContainer" v-if="folders.length > 0">
|
||||
<x-folder v-for="folder in folders" :key="folder.id" class="folder" :folder="folder"/>
|
||||
<x-folder v-for="f in folders" :key="f.id" class="folder" :folder="f" :select-mode="select === 'folder'" :is-selected="selectedFolders.some(x => x.id === f.id)" @chosen="chooseFolder"/>
|
||||
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
|
||||
<div class="padding" v-for="n in 16"></div>
|
||||
<div class="padding" v-for="(n, i) in 16" :key="i"></div>
|
||||
<mk-button v-if="moreFolders">{{ $t('loadMore') }}</mk-button>
|
||||
</div>
|
||||
<div class="files" ref="filesContainer" v-if="files.length > 0">
|
||||
<x-file v-for="file in files" :key="file.id" class="file" :file="file" :select-mode="selectMode"/>
|
||||
<x-file v-for="file in files" :key="file.id" class="file" :file="file" :select-mode="select === 'file'" :is-selected="selectedFiles.some(x => x.id === file.id)" @chosen="chooseFile"/>
|
||||
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
|
||||
<div class="padding" v-for="n in 16"></div>
|
||||
<div class="padding" v-for="(n, i) in 16" :key="i"></div>
|
||||
<mk-button v-if="moreFiles" @click="fetchMoreFiles">{{ $t('loadMore') }}</mk-button>
|
||||
</div>
|
||||
<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
|
||||
@ -81,10 +81,10 @@ export default Vue.extend({
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
selectMode: {
|
||||
type: Boolean,
|
||||
select: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: false
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
@ -102,6 +102,7 @@ export default Vue.extend({
|
||||
moreFolders: false,
|
||||
hierarchyFolders: [],
|
||||
selectedFiles: [],
|
||||
selectedFolders: [],
|
||||
uploadings: [],
|
||||
connection: null,
|
||||
|
||||
@ -392,6 +393,25 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
chooseFolder(folder) {
|
||||
const isAlreadySelected = this.selectedFolders.some(f => f.id == folder.id);
|
||||
if (this.multiple) {
|
||||
if (isAlreadySelected) {
|
||||
this.selectedFolders = this.selectedFolders.filter(f => f.id != folder.id);
|
||||
} else {
|
||||
this.selectedFolders.push(folder);
|
||||
}
|
||||
this.$emit('change-selection', this.selectedFolders);
|
||||
} else {
|
||||
if (isAlreadySelected) {
|
||||
this.$emit('selected', folder);
|
||||
} else {
|
||||
this.selectedFolders = [folder];
|
||||
this.$emit('change-selection', [folder]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
move(target) {
|
||||
if (target == null) {
|
||||
this.goRoot();
|
||||
|
@ -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: {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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: {
|
||||
|
@ -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"/>
|
||||
<div v-show="hpml.vars[value.var]">
|
||||
<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: {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,12 +1,13 @@
|
||||
<template>
|
||||
<div class="ngbfujlo">
|
||||
<mk-textarea :value="text" readonly style="margin: 0;"></mk-textarea>
|
||||
<mk-button class="button" primary @click="post()" :disabled="posting || posted">{{ posted ? $t('posted') : $t('post') }}</mk-button>
|
||||
<mk-button class="button" primary @click="post()" :disabled="posting || posted"><fa v-if="posted" :icon="faCheck"/><fa v-else :icon="faPaperPlane"/></mk-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../../i18n';
|
||||
import MkTextarea from '../ui/textarea.vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
@ -22,21 +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
|
||||
}
|
||||
@ -51,11 +53,14 @@ 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);
|
||||
data.append('i', this.$store.state.i.token);
|
||||
if (this.$store.state.settings.uploadFolder) {
|
||||
data.append('folderId', this.$store.state.settings.uploadFolder);
|
||||
}
|
||||
|
||||
fetch(apiUrl + '/drive/files/create', {
|
||||
method: 'POST',
|
||||
@ -73,7 +78,7 @@ export default Vue.extend({
|
||||
this.posting = true;
|
||||
const file = this.value.attachCanvasImage ? await this.upload() : null;
|
||||
this.$root.api('notes/create', {
|
||||
text: this.text,
|
||||
text: this.text === '' ? null : this.text,
|
||||
fileIds: file ? [file.id] : undefined,
|
||||
}).then(() => {
|
||||
this.posted = true;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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: {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<x-modal ref="modal" @closed="() => { $emit('closed'); destroyDom(); }">
|
||||
<div class="ebkgoccj" :class="{ noPadding }" @keydown="onKeydown">
|
||||
<div class="ebkgoccj" :class="{ noPadding }" @keydown="onKeydown" :style="{ width: `${width}px`, height: `${height}px` }">
|
||||
<div class="header">
|
||||
<button class="_button" v-if="withOkButton" @click="close()"><fa :icon="faTimes"/></button>
|
||||
<span class="title">
|
||||
@ -49,7 +49,17 @@ export default Vue.extend({
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 400
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 400
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -76,19 +86,12 @@ export default Vue.extend({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ebkgoccj {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
background: var(--panel);
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
> .header {
|
||||
$height: 58px;
|
||||
$height-narrow: 42px;
|
||||
|
@ -29,7 +29,6 @@ import { faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faListUl, faSatell
|
||||
import { faComments } from '@fortawesome/free-regular-svg-icons';
|
||||
import Progress from '../scripts/loading';
|
||||
import XTimeline from '../components/timeline.vue';
|
||||
import XTutorial from './index.home.tutorial.vue';
|
||||
import XPostForm from '../components/post-form.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
@ -41,7 +40,7 @@ export default Vue.extend({
|
||||
|
||||
components: {
|
||||
XTimeline,
|
||||
XTutorial,
|
||||
XTutorial: () => import('./index.home.tutorial.vue').then(m => m.default),
|
||||
XPostForm,
|
||||
},
|
||||
|
||||
|
@ -2,107 +2,57 @@
|
||||
<section class="uawsfosz _card">
|
||||
<div class="_title"><fa :icon="faCloud"/> {{ $t('drive') }}</div>
|
||||
<div class="_content">
|
||||
<mk-pagination :pagination="drivePagination" #default="{items}" class="drive" ref="drive">
|
||||
<div class="file" v-for="(file, i) in items" :key="file.id" @click="selected = file" :class="{ selected: selected && (selected.id === file.id) }">
|
||||
<x-file-thumbnail class="thumbnail" :file="file" fit="cover"/>
|
||||
<div class="body">
|
||||
<p class="name">
|
||||
<span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span>
|
||||
<span class="ext" v-if="file.name.lastIndexOf('.') != -1">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span>
|
||||
</p>
|
||||
<footer>
|
||||
<span class="type"><x-file-type-icon :type="file.type" class="icon"/>{{ file.type }}</span>
|
||||
<span class="separator"></span>
|
||||
<span class="data-size">{{ file.size | bytes }}</span>
|
||||
<span class="separator"></span>
|
||||
<span class="created-at"><fa :icon="faClock"/><mk-time :time="file.createdAt"/></span>
|
||||
<template v-if="file.isSensitive">
|
||||
<span class="separator"></span>
|
||||
<span class="nsfw"><fa :icon="faEyeSlash"/> {{ $t('nsfw') }}</span>
|
||||
</template>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</mk-pagination>
|
||||
</div>
|
||||
<div class="_footer">
|
||||
<mk-button primary inline :disabled="selected == null" @click="download()"><fa :icon="faDownload"/> {{ $t('download') }}</mk-button>
|
||||
<mk-button inline :disabled="selected == null" @click="del()"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</mk-button>
|
||||
<span>{{ $t('uploadFolder') }}: {{ uploadFolder ? uploadFolder.name : '-' }}</span>
|
||||
<mk-button primary @click="chooseUploadFolder()"><fa :icon="faFolderOpen"/> {{ $t('selectFolder') }}</mk-button>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faCloud, faDownload } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCloud, faFolderOpen } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faClock, faEyeSlash, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
|
||||
import XFileTypeIcon from '../../components/file-type-icon.vue';
|
||||
import XFileThumbnail from '../../components/drive-file-thumbnail.vue';
|
||||
import MkButton from '../../components/ui/button.vue';
|
||||
import MkPagination from '../../components/ui/pagination.vue';
|
||||
import i18n from '../../i18n';
|
||||
import { selectDriveFolder } from '../../scripts/select-drive-folder';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XFileTypeIcon,
|
||||
XFileThumbnail,
|
||||
MkPagination,
|
||||
MkButton,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
selected: null,
|
||||
connection: null,
|
||||
drivePagination: {
|
||||
endpoint: 'drive/files',
|
||||
limit: 10,
|
||||
},
|
||||
faCloud, faClock, faEyeSlash, faDownload, faTrashAlt
|
||||
uploadFolder: null,
|
||||
faCloud, faClock, faEyeSlash, faFolderOpen, faTrashAlt
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.connection = this.$root.stream.useSharedConnection('drive');
|
||||
|
||||
this.connection.on('fileCreated', this.onStreamDriveFileCreated);
|
||||
this.connection.on('fileUpdated', this.onStreamDriveFileUpdated);
|
||||
this.connection.on('fileDeleted', this.onStreamDriveFileDeleted);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.dispose();
|
||||
async created() {
|
||||
if (this.$store.state.settings.uploadFolder) {
|
||||
this.uploadFolder = await this.$root.api('drive/folders/show', {
|
||||
folderId: this.$store.state.settings.uploadFolder
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onStreamDriveFileCreated(file) {
|
||||
this.$refs.drive.prepend(file);
|
||||
},
|
||||
|
||||
onStreamDriveFileUpdated(file) {
|
||||
// TODO
|
||||
},
|
||||
|
||||
onStreamDriveFileDeleted(fileId) {
|
||||
this.$refs.drive.remove(x => x.id === fileId);
|
||||
},
|
||||
|
||||
download() {
|
||||
window.open(this.selected.url, '_blank');
|
||||
},
|
||||
|
||||
async del() {
|
||||
const { canceled } = await this.$root.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('driveFileDeleteConfirm', { name: this.selected.name }),
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
this.$root.api('drive/files/delete', {
|
||||
fileId: this.selected.id
|
||||
chooseUploadFolder() {
|
||||
selectDriveFolder(this.$root, false).then(async folder => {
|
||||
await this.$store.dispatch('settings/set', { key: 'uploadFolder', value: folder ? folder.id : null });
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
iconOnly: true, autoClose: true
|
||||
});
|
||||
if (this.$store.state.settings.uploadFolder) {
|
||||
this.uploadFolder = await this.$root.api('drive/folders/show', {
|
||||
folderId: this.$store.state.settings.uploadFolder
|
||||
});
|
||||
} else {
|
||||
this.uploadFolder = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -111,102 +61,6 @@ export default Vue.extend({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uawsfosz {
|
||||
> ._content {
|
||||
max-height: 350px;
|
||||
overflow: auto;
|
||||
|
||||
> .drive {
|
||||
> .file {
|
||||
display: grid;
|
||||
margin: 0 auto;
|
||||
grid-template-columns: 64px 1fr;
|
||||
grid-column-gap: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
&.selected {
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 0 8px var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
> .thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
> .body {
|
||||
display: block;
|
||||
word-break: break-all;
|
||||
padding-top: 4px;
|
||||
|
||||
> .name {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
word-break: break-word;
|
||||
|
||||
> .ext {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
> .tags {
|
||||
display: block;
|
||||
margin: 4px 0 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font-size: 0.5em;
|
||||
|
||||
> .tag {
|
||||
display: inline-block;
|
||||
margin: 0 5px 0 0;
|
||||
padding: 1px 5px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
> footer {
|
||||
display: block;
|
||||
margin: 4px 0 0 0;
|
||||
font-size: 0.7em;
|
||||
|
||||
> .separator {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
> .type {
|
||||
opacity: 0.7;
|
||||
|
||||
> .icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
> .data-size {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
> .created-at {
|
||||
opacity: 0.7;
|
||||
|
||||
> [data-icon] {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
> .nsfw {
|
||||
color: #bf4633;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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')
|
||||
|
@ -3,8 +3,9 @@ import { utils, values } from '@syuilo/aiscript';
|
||||
export function createAiScriptEnv(vm, opts) {
|
||||
let apiRequests = 0;
|
||||
return {
|
||||
USER_ID: values.STR(vm.$store.state.i.id),
|
||||
USER_USERNAME: values.STR(vm.$store.state.i.username),
|
||||
USER_ID: vm.$store.getters.isSignedIn ? values.STR(vm.$store.state.i.id) : values.NULL,
|
||||
USER_NAME: vm.$store.getters.isSignedIn ? values.STR(vm.$store.state.i.name) : values.NULL,
|
||||
USER_USERNAME: vm.$store.getters.isSignedIn ? values.STR(vm.$store.state.i.username) : values.NULL,
|
||||
'Mk:dialog': values.FN_NATIVE(async ([title, text, type]) => {
|
||||
await vm.$root.dialog({
|
||||
type: type ? type.value : 'info',
|
||||
|
@ -1,153 +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,
|
||||
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: {
|
||||
min: opts.value.has('min') ? opts.value.get('min').value : undefined,
|
||||
max: opts.value.has('max') ? opts.value.get('max').value : undefined,
|
||||
},
|
||||
pointLabels: {
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
} : {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
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({
|
||||
@ -164,6 +56,10 @@ export class ASEvaluator {
|
||||
log: (type, params) => {
|
||||
},
|
||||
});
|
||||
|
||||
this.aiscript.scope.opts.onUpdated = (name, value) => {
|
||||
this.eval();
|
||||
};
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
@ -171,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 : '',
|
||||
@ -185,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;
|
||||
}
|
||||
@ -200,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}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,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();
|
||||
@ -248,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') {
|
||||
@ -367,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) {
|
||||
@ -384,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -417,7 +341,7 @@ class Scope {
|
||||
}
|
||||
}
|
||||
|
||||
throw new AoiScriptError(
|
||||
throw new HpmlError(
|
||||
`No such variable '${name}' in scope '${this.name}'`, {
|
||||
scope: this.layerdStates
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* AoiScript
|
||||
* Hpml
|
||||
*/
|
||||
|
||||
import {
|
124
src/client/scripts/hpml/lib.ts
Normal file
124
src/client/scripts/hpml/lib.ts
Normal file
@ -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: (chart, easing) => {
|
||||
if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) {
|
||||
const 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,
|
||||
}
|
||||
}]
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
import DriveWindow from '../components/drive-window.vue';
|
||||
|
||||
export function selectDriveFile($root: any, multiple) {
|
||||
return new Promise((res, rej) => {
|
||||
const w = $root.new(DriveWindow, {
|
||||
multiple
|
||||
});
|
||||
w.$once('selected', files => {
|
||||
res(multiple ? files : files[0]);
|
||||
import('../components/drive-window.vue').then(m => m.default).then(dialog => {
|
||||
const w = $root.new(dialog, {
|
||||
type: 'file',
|
||||
multiple
|
||||
});
|
||||
w.$once('selected', files => {
|
||||
res(multiple ? files : files[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
13
src/client/scripts/select-drive-folder.ts
Normal file
13
src/client/scripts/select-drive-folder.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function selectDriveFolder($root: any, multiple) {
|
||||
return new Promise((res, rej) => {
|
||||
import('../components/drive-window.vue').then(m => m.default).then(dialog => {
|
||||
const w = $root.new(dialog, {
|
||||
type: 'folder',
|
||||
multiple
|
||||
});
|
||||
w.$once('selected', folders => {
|
||||
res(multiple ? folders : (folders.length === 0 ? null : folders[0]));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -43,7 +43,7 @@ export async function checkHitAntenna(antenna: Antenna, note: Note, noteUser: Us
|
||||
if (note.text == null) return false;
|
||||
|
||||
const matched = antenna.keywords.some(keywords =>
|
||||
keywords.every(keyword =>
|
||||
keywords.filter(keyword => keyword !== '').every(keyword =>
|
||||
antenna.caseSensitive
|
||||
? note.text!.includes(keyword)
|
||||
: note.text!.toLowerCase().includes(keyword.toLowerCase())
|
||||
@ -56,7 +56,7 @@ export async function checkHitAntenna(antenna: Antenna, note: Note, noteUser: Us
|
||||
if (note.text == null) return false;
|
||||
|
||||
const matched = antenna.excludeKeywords.some(keywords =>
|
||||
keywords.every(keyword =>
|
||||
keywords.filter(keyword => keyword !== '').every(keyword =>
|
||||
antenna.caseSensitive
|
||||
? note.text!.includes(keyword)
|
||||
: note.text!.toLowerCase().includes(keyword.toLowerCase())
|
||||
|
@ -25,7 +25,7 @@ export const meta = {
|
||||
},
|
||||
|
||||
category: {
|
||||
validator: $.optional.str
|
||||
validator: $.optional.nullable.str
|
||||
},
|
||||
|
||||
aliases: {
|
||||
|
@ -4,10 +4,7 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as webpack from 'webpack';
|
||||
import * as chalk from 'chalk';
|
||||
const { VueLoaderPlugin } = require('vue-loader');
|
||||
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
|
||||
class WebpackOnBuildPlugin {
|
||||
constructor(readonly callback: (stats: any) => void) {
|
||||
@ -118,10 +115,7 @@ module.exports = {
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
new ProgressBarPlugin({
|
||||
format: chalk` {cyan.bold Yes we can} {bold [}:bar{bold ]} {green.bold :percent} {gray :elapseds}`,
|
||||
clear: false
|
||||
}),
|
||||
new webpack.ProgressPlugin({}),
|
||||
new webpack.DefinePlugin({
|
||||
_VERSION_: JSON.stringify(meta.version),
|
||||
_LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]: [string, any]) => [k, v._lang_])),
|
||||
@ -135,7 +129,6 @@ module.exports = {
|
||||
output: {
|
||||
path: __dirname + '/built/client/assets',
|
||||
filename: `[name].${meta.version}.js`,
|
||||
chunkFilename: '[hash:5].[id].js',
|
||||
publicPath: `/assets/`
|
||||
},
|
||||
resolve: {
|
||||
@ -149,13 +142,13 @@ module.exports = {
|
||||
resolveLoader: {
|
||||
modules: ['node_modules']
|
||||
},
|
||||
externals: {
|
||||
moment: 'moment'
|
||||
cache: {
|
||||
type: 'filesystem',
|
||||
|
||||
buildDependencies: {
|
||||
config: [__filename]
|
||||
}
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [new TerserPlugin()]
|
||||
},
|
||||
cache: true,
|
||||
devtool: false, //'source-map',
|
||||
mode: isProduction ? 'production' : 'development'
|
||||
};
|
||||
|
Reference in New Issue
Block a user