From bc9a8283c66d7588f931d4b802f7ab1fa7aa3226 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 18:05:35 +0900 Subject: なんかもうめっちゃ変えた MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/web/app/desktop/scripts/autocomplete.js | 130 -------------------- src/web/app/desktop/scripts/autocomplete.ts | 132 +++++++++++++++++++++ src/web/app/desktop/scripts/dialog.js | 16 --- src/web/app/desktop/scripts/dialog.ts | 16 +++ src/web/app/desktop/scripts/fuck-ad-block.js | 18 --- src/web/app/desktop/scripts/fuck-ad-block.ts | 20 ++++ src/web/app/desktop/scripts/input-dialog.js | 12 -- src/web/app/desktop/scripts/input-dialog.ts | 12 ++ .../desktop/scripts/not-implemented-exception.js | 8 -- .../desktop/scripts/not-implemented-exception.ts | 8 ++ src/web/app/desktop/scripts/notify.js | 8 -- src/web/app/desktop/scripts/notify.ts | 8 ++ src/web/app/desktop/scripts/password-dialog.js | 11 -- src/web/app/desktop/scripts/password-dialog.ts | 11 ++ src/web/app/desktop/scripts/update-avatar.js | 87 -------------- src/web/app/desktop/scripts/update-avatar.ts | 87 ++++++++++++++ src/web/app/desktop/scripts/update-banner.js | 87 -------------- src/web/app/desktop/scripts/update-banner.ts | 87 ++++++++++++++ 18 files changed, 381 insertions(+), 377 deletions(-) delete mode 100644 src/web/app/desktop/scripts/autocomplete.js create mode 100644 src/web/app/desktop/scripts/autocomplete.ts delete mode 100644 src/web/app/desktop/scripts/dialog.js create mode 100644 src/web/app/desktop/scripts/dialog.ts delete mode 100644 src/web/app/desktop/scripts/fuck-ad-block.js create mode 100644 src/web/app/desktop/scripts/fuck-ad-block.ts delete mode 100644 src/web/app/desktop/scripts/input-dialog.js create mode 100644 src/web/app/desktop/scripts/input-dialog.ts delete mode 100644 src/web/app/desktop/scripts/not-implemented-exception.js create mode 100644 src/web/app/desktop/scripts/not-implemented-exception.ts delete mode 100644 src/web/app/desktop/scripts/notify.js create mode 100644 src/web/app/desktop/scripts/notify.ts delete mode 100644 src/web/app/desktop/scripts/password-dialog.js create mode 100644 src/web/app/desktop/scripts/password-dialog.ts delete mode 100644 src/web/app/desktop/scripts/update-avatar.js create mode 100644 src/web/app/desktop/scripts/update-avatar.ts delete mode 100644 src/web/app/desktop/scripts/update-banner.js create mode 100644 src/web/app/desktop/scripts/update-banner.ts (limited to 'src/web/app/desktop/scripts') diff --git a/src/web/app/desktop/scripts/autocomplete.js b/src/web/app/desktop/scripts/autocomplete.js deleted file mode 100644 index 8ca516e2a9..0000000000 --- a/src/web/app/desktop/scripts/autocomplete.js +++ /dev/null @@ -1,130 +0,0 @@ -const getCaretCoordinates = require('textarea-caret'); -import * as riot from 'riot'; - -/** - * オートコンプリートを管理するクラス。 - */ -class Autocomplete { - - /** - * 対象のテキストエリアを与えてインスタンスを初期化します。 - */ - constructor(textarea) { - // BIND --------------------------------- - this.onInput = this.onInput.bind(this); - this.complete = this.complete.bind(this); - this.close = this.close.bind(this); - // -------------------------------------- - - this.suggestion = null; - this.textarea = textarea; - } - - /** - * このインスタンスにあるテキストエリアの入力のキャプチャを開始します。 - */ - attach() { - this.textarea.addEventListener('input', this.onInput); - } - - /** - * このインスタンスにあるテキストエリアの入力のキャプチャを解除します。 - */ - detach() { - this.textarea.removeEventListener('input', this.onInput); - this.close(); - } - - /** - * [Private] テキスト入力時 - */ - onInput() { - this.close(); - - const caret = this.textarea.selectionStart; - const text = this.textarea.value.substr(0, caret); - - const mentionIndex = text.lastIndexOf('@'); - - if (mentionIndex == -1) return; - - const username = text.substr(mentionIndex + 1); - - if (!username.match(/^[a-zA-Z0-9-]+$/)) return; - - this.open('user', username); - } - - /** - * [Private] サジェストを提示します。 - */ - open(type, q) { - // 既に開いているサジェストは閉じる - this.close(); - - // サジェスト要素作成 - const tag = document.createElement('mk-autocomplete-suggestion'); - - // ~ サジェストを表示すべき位置を計算 ~ - - const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); - - const rect = this.textarea.getBoundingClientRect(); - - const x = rect.left + window.pageXOffset + caretPosition.left; - const y = rect.top + window.pageYOffset + caretPosition.top; - - tag.style.left = x + 'px'; - tag.style.top = y + 'px'; - - // 要素追加 - const el = document.body.appendChild(tag); - - // マウント - this.suggestion = riot.mount(el, { - textarea: this.textarea, - complete: this.complete, - close: this.close, - type: type, - q: q - })[0]; - } - - /** - * [Private] サジェストを閉じます。 - */ - close() { - if (this.suggestion == null) return; - - this.suggestion.unmount(); - this.suggestion = null; - - this.textarea.focus(); - } - - /** - * [Private] オートコンプリートする - */ - complete(user) { - this.close(); - - const value = user.username; - - const caret = this.textarea.selectionStart; - const source = this.textarea.value; - - const before = source.substr(0, caret); - const trimmedBefore = before.substring(0, before.lastIndexOf('@')); - const after = source.substr(caret); - - // 結果を挿入する - this.textarea.value = trimmedBefore + '@' + value + ' ' + after; - - // キャレットを戻す - this.textarea.focus(); - const pos = caret + value.length; - this.textarea.setSelectionRange(pos, pos); - } -} - -export default Autocomplete; diff --git a/src/web/app/desktop/scripts/autocomplete.ts b/src/web/app/desktop/scripts/autocomplete.ts new file mode 100644 index 0000000000..9df7aae08d --- /dev/null +++ b/src/web/app/desktop/scripts/autocomplete.ts @@ -0,0 +1,132 @@ +import getCaretCoordinates = require('textarea-caret'); +import * as riot from 'riot'; + +/** + * オートコンプリートを管理するクラス。 + */ +class Autocomplete { + private suggestion: any; + private textarea: any; + + /** + * 対象のテキストエリアを与えてインスタンスを初期化します。 + */ + constructor(textarea) { + // BIND --------------------------------- + this.onInput = this.onInput.bind(this); + this.complete = this.complete.bind(this); + this.close = this.close.bind(this); + // -------------------------------------- + + this.suggestion = null; + this.textarea = textarea; + } + + /** + * このインスタンスにあるテキストエリアの入力のキャプチャを開始します。 + */ + public attach() { + this.textarea.addEventListener('input', this.onInput); + } + + /** + * このインスタンスにあるテキストエリアの入力のキャプチャを解除します。 + */ + public detach() { + this.textarea.removeEventListener('input', this.onInput); + this.close(); + } + + /** + * テキスト入力時 + */ + private onInput() { + this.close(); + + const caret = this.textarea.selectionStart; + const text = this.textarea.value.substr(0, caret); + + const mentionIndex = text.lastIndexOf('@'); + + if (mentionIndex == -1) return; + + const username = text.substr(mentionIndex + 1); + + if (!username.match(/^[a-zA-Z0-9-]+$/)) return; + + this.open('user', username); + } + + /** + * サジェストを提示します。 + */ + private open(type, q) { + // 既に開いているサジェストは閉じる + this.close(); + + // サジェスト要素作成 + const tag = document.createElement('mk-autocomplete-suggestion'); + + // ~ サジェストを表示すべき位置を計算 ~ + + const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); + + const rect = this.textarea.getBoundingClientRect(); + + const x = rect.left + window.pageXOffset + caretPosition.left; + const y = rect.top + window.pageYOffset + caretPosition.top; + + tag.style.left = x + 'px'; + tag.style.top = y + 'px'; + + // 要素追加 + const el = document.body.appendChild(tag); + + // マウント + this.suggestion = (riot as any).mount(el, { + textarea: this.textarea, + complete: this.complete, + close: this.close, + type: type, + q: q + })[0]; + } + + /** + * サジェストを閉じます。 + */ + private close() { + if (this.suggestion == null) return; + + this.suggestion.unmount(); + this.suggestion = null; + + this.textarea.focus(); + } + + /** + * オートコンプリートする + */ + private complete(user) { + this.close(); + + const value = user.username; + + const caret = this.textarea.selectionStart; + const source = this.textarea.value; + + const before = source.substr(0, caret); + const trimmedBefore = before.substring(0, before.lastIndexOf('@')); + const after = source.substr(caret); + + // 結果を挿入する + this.textarea.value = trimmedBefore + '@' + value + ' ' + after; + + // キャレットを戻す + this.textarea.focus(); + const pos = caret + value.length; + this.textarea.setSelectionRange(pos, pos); + } +} + +export default Autocomplete; diff --git a/src/web/app/desktop/scripts/dialog.js b/src/web/app/desktop/scripts/dialog.js deleted file mode 100644 index c502d3fcb8..0000000000 --- a/src/web/app/desktop/scripts/dialog.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as riot from 'riot'; - -export default (title, text, buttons, canThrough, onThrough) => { - const dialog = document.body.appendChild(document.createElement('mk-dialog')); - const controller = riot.observable(); - riot.mount(dialog, { - controller: controller, - title: title, - text: text, - buttons: buttons, - canThrough: canThrough, - onThrough: onThrough - }); - controller.trigger('open'); - return controller; -}; diff --git a/src/web/app/desktop/scripts/dialog.ts b/src/web/app/desktop/scripts/dialog.ts new file mode 100644 index 0000000000..816ba4b5f5 --- /dev/null +++ b/src/web/app/desktop/scripts/dialog.ts @@ -0,0 +1,16 @@ +import * as riot from 'riot'; + +export default (title, text, buttons, canThrough?, onThrough?) => { + const dialog = document.body.appendChild(document.createElement('mk-dialog')); + const controller = riot.observable(); + (riot as any).mount(dialog, { + controller: controller, + title: title, + text: text, + buttons: buttons, + canThrough: canThrough, + onThrough: onThrough + }); + controller.trigger('open'); + return controller; +}; diff --git a/src/web/app/desktop/scripts/fuck-ad-block.js b/src/web/app/desktop/scripts/fuck-ad-block.js deleted file mode 100644 index ccfc43ce6e..0000000000 --- a/src/web/app/desktop/scripts/fuck-ad-block.js +++ /dev/null @@ -1,18 +0,0 @@ -require('fuckadblock'); -import dialog from './dialog'; - -export default () => { - if (fuckAdBlock === undefined) { - adBlockDetected(); - } else { - fuckAdBlock.onDetected(adBlockDetected); - } -}; - -function adBlockDetected() { - dialog('広告ブロッカーを無効にしてください', - 'Misskeyは広告を掲載していませんが、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。', - [{ - text: 'OK' - }]); -} diff --git a/src/web/app/desktop/scripts/fuck-ad-block.ts b/src/web/app/desktop/scripts/fuck-ad-block.ts new file mode 100644 index 0000000000..3307ba2f30 --- /dev/null +++ b/src/web/app/desktop/scripts/fuck-ad-block.ts @@ -0,0 +1,20 @@ +require('fuckadblock'); +import dialog from './dialog'; + +declare var fuckAdBlock: any; + +export default () => { + if (fuckAdBlock === undefined) { + adBlockDetected(); + } else { + fuckAdBlock.onDetected(adBlockDetected); + } +}; + +function adBlockDetected() { + dialog('広告ブロッカーを無効にしてください', + 'Misskeyは広告を掲載していませんが、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。', + [{ + text: 'OK' + }]); +} diff --git a/src/web/app/desktop/scripts/input-dialog.js b/src/web/app/desktop/scripts/input-dialog.js deleted file mode 100644 index 954fabfb67..0000000000 --- a/src/web/app/desktop/scripts/input-dialog.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as riot from 'riot'; - -export default (title, placeholder, defaultValue, onOk, onCancel) => { - const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); - return riot.mount(dialog, { - title: title, - placeholder: placeholder, - 'default': defaultValue, - onOk: onOk, - onCancel: onCancel - }); -}; diff --git a/src/web/app/desktop/scripts/input-dialog.ts b/src/web/app/desktop/scripts/input-dialog.ts new file mode 100644 index 0000000000..b06d011c6b --- /dev/null +++ b/src/web/app/desktop/scripts/input-dialog.ts @@ -0,0 +1,12 @@ +import * as riot from 'riot'; + +export default (title, placeholder, defaultValue, onOk, onCancel) => { + const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); + return (riot as any).mount(dialog, { + title: title, + placeholder: placeholder, + 'default': defaultValue, + onOk: onOk, + onCancel: onCancel + }); +}; diff --git a/src/web/app/desktop/scripts/not-implemented-exception.js b/src/web/app/desktop/scripts/not-implemented-exception.js deleted file mode 100644 index dd00c7662f..0000000000 --- a/src/web/app/desktop/scripts/not-implemented-exception.js +++ /dev/null @@ -1,8 +0,0 @@ -import dialog from './dialog'; - -export default () => { - dialog('Not implemented yet', - '要求された操作は実装されていません。
Misskeyの開発に参加する', [{ - text: 'OK' - }]); -}; diff --git a/src/web/app/desktop/scripts/not-implemented-exception.ts b/src/web/app/desktop/scripts/not-implemented-exception.ts new file mode 100644 index 0000000000..dd00c7662f --- /dev/null +++ b/src/web/app/desktop/scripts/not-implemented-exception.ts @@ -0,0 +1,8 @@ +import dialog from './dialog'; + +export default () => { + dialog('Not implemented yet', + '要求された操作は実装されていません。
Misskeyの開発に参加する', [{ + text: 'OK' + }]); +}; diff --git a/src/web/app/desktop/scripts/notify.js b/src/web/app/desktop/scripts/notify.js deleted file mode 100644 index e58a8e4d36..0000000000 --- a/src/web/app/desktop/scripts/notify.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as riot from 'riot'; - -export default message => { - const notification = document.body.appendChild(document.createElement('mk-ui-notification')); - riot.mount(notification, { - message: message - }); -}; diff --git a/src/web/app/desktop/scripts/notify.ts b/src/web/app/desktop/scripts/notify.ts new file mode 100644 index 0000000000..2e6cbdeed8 --- /dev/null +++ b/src/web/app/desktop/scripts/notify.ts @@ -0,0 +1,8 @@ +import * as riot from 'riot'; + +export default message => { + const notification = document.body.appendChild(document.createElement('mk-ui-notification')); + (riot as any).mount(notification, { + message: message + }); +}; diff --git a/src/web/app/desktop/scripts/password-dialog.js b/src/web/app/desktop/scripts/password-dialog.js deleted file mode 100644 index 2bdc93e421..0000000000 --- a/src/web/app/desktop/scripts/password-dialog.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as riot from 'riot'; - -export default (title, onOk, onCancel) => { - const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); - return riot.mount(dialog, { - title: title, - type: 'password', - onOk: onOk, - onCancel: onCancel - }); -}; diff --git a/src/web/app/desktop/scripts/password-dialog.ts b/src/web/app/desktop/scripts/password-dialog.ts new file mode 100644 index 0000000000..39d7f3db7a --- /dev/null +++ b/src/web/app/desktop/scripts/password-dialog.ts @@ -0,0 +1,11 @@ +import * as riot from 'riot'; + +export default (title, onOk, onCancel) => { + const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); + return (riot as any).mount(dialog, { + title: title, + type: 'password', + onOk: onOk, + onCancel: onCancel + }); +}; diff --git a/src/web/app/desktop/scripts/update-avatar.js b/src/web/app/desktop/scripts/update-avatar.js deleted file mode 100644 index 165c90567c..0000000000 --- a/src/web/app/desktop/scripts/update-avatar.js +++ /dev/null @@ -1,87 +0,0 @@ -import * as riot from 'riot'; -import CONFIG from '../../common/scripts/config'; -import dialog from './dialog'; -import api from '../../common/scripts/api'; - -export default (I, cb, file = null) => { - const fileSelected = file => { - const cropper = riot.mount(document.body.appendChild(document.createElement('mk-crop-window')), { - file: file, - title: 'アバターとして表示する部分を選択', - aspectRatio: 1 / 1 - })[0]; - - cropper.on('cropped', blob => { - const data = new FormData(); - data.append('i', I.token); - data.append('file', blob, file.name + '.cropped.png'); - - api(I, 'drive/folders/find', { - name: 'アイコン' - }).then(iconFolder => { - if (iconFolder.length === 0) { - api(I, 'drive/folders/create', { - name: 'アイコン' - }).then(iconFolder => { - upload(data, iconFolder); - }); - } else { - upload(data, iconFolder[0]); - } - }); - }); - - cropper.on('skipped', () => { - set(file); - }); - }; - - const upload = (data, folder) => { - const progress = riot.mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { - title: '新しいアバターをアップロードしています' - })[0]; - - if (folder) data.append('folder_id', folder.id); - - const xhr = new XMLHttpRequest(); - xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); - xhr.onload = e => { - const file = JSON.parse(e.target.response); - progress.close(); - set(file); - }; - - xhr.upload.onprogress = e => { - if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); - }; - - xhr.send(data); - }; - - const set = file => { - api(I, 'i/update', { - avatar_id: file.id - }).then(i => { - dialog('アバターを更新しました', - '新しいアバターが反映されるまで時間がかかる場合があります。', - [{ - text: 'わかった' - }]); - - if (cb) cb(i); - }); - }; - - if (file) { - fileSelected(file); - } else { - const browser = riot.mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { - multiple: false, - title: 'アバターにする画像を選択' - })[0]; - - browser.one('selected', file => { - fileSelected(file); - }); - } -}; diff --git a/src/web/app/desktop/scripts/update-avatar.ts b/src/web/app/desktop/scripts/update-avatar.ts new file mode 100644 index 0000000000..5fd7f2d3d1 --- /dev/null +++ b/src/web/app/desktop/scripts/update-avatar.ts @@ -0,0 +1,87 @@ +import * as riot from 'riot'; +import CONFIG from '../../common/scripts/config'; +import dialog from './dialog'; +import api from '../../common/scripts/api'; + +export default (I, cb, file = null) => { + const fileSelected = file => { + const cropper = (riot as any).mount(document.body.appendChild(document.createElement('mk-crop-window')), { + file: file, + title: 'アバターとして表示する部分を選択', + aspectRatio: 1 / 1 + })[0]; + + cropper.on('cropped', blob => { + const data = new FormData(); + data.append('i', I.token); + data.append('file', blob, file.name + '.cropped.png'); + + api(I, 'drive/folders/find', { + name: 'アイコン' + }).then(iconFolder => { + if (iconFolder.length === 0) { + api(I, 'drive/folders/create', { + name: 'アイコン' + }).then(iconFolder => { + upload(data, iconFolder); + }); + } else { + upload(data, iconFolder[0]); + } + }); + }); + + cropper.on('skipped', () => { + set(file); + }); + }; + + const upload = (data, folder) => { + const progress = (riot as any).mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { + title: '新しいアバターをアップロードしています' + })[0]; + + if (folder) data.append('folder_id', folder.id); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const file = JSON.parse((e.target as any).response); + progress.close(); + set(file); + }; + + xhr.upload.onprogress = e => { + if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); + }; + + xhr.send(data); + }; + + const set = file => { + api(I, 'i/update', { + avatar_id: file.id + }).then(i => { + dialog('アバターを更新しました', + '新しいアバターが反映されるまで時間がかかる場合があります。', + [{ + text: 'わかった' + }]); + + if (cb) cb(i); + }); + }; + + if (file) { + fileSelected(file); + } else { + const browser = (riot as any).mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { + multiple: false, + title: 'アバターにする画像を選択' + })[0]; + + browser.one('selected', file => { + fileSelected(file); + }); + } +}; diff --git a/src/web/app/desktop/scripts/update-banner.js b/src/web/app/desktop/scripts/update-banner.js deleted file mode 100644 index d83b2bf1b1..0000000000 --- a/src/web/app/desktop/scripts/update-banner.js +++ /dev/null @@ -1,87 +0,0 @@ -import * as riot from 'riot'; -import CONFIG from '../../common/scripts/config'; -import dialog from './dialog'; -import api from '../../common/scripts/api'; - -export default (I, cb, file = null) => { - const fileSelected = file => { - const cropper = riot.mount(document.body.appendChild(document.createElement('mk-crop-window')), { - file: file, - title: 'バナーとして表示する部分を選択', - aspectRatio: 16 / 9 - })[0]; - - cropper.on('cropped', blob => { - const data = new FormData(); - data.append('i', I.token); - data.append('file', blob, file.name + '.cropped.png'); - - api(I, 'drive/folders/find', { - name: 'バナー' - }).then(iconFolder => { - if (iconFolder.length === 0) { - api(I, 'drive/folders/create', { - name: 'バナー' - }).then(iconFolder => { - upload(data, iconFolder); - }); - } else { - upload(data, iconFolder[0]); - } - }); - }); - - cropper.on('skipped', () => { - set(file); - }); - }; - - const upload = (data, folder) => { - const progress = riot.mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { - title: '新しいバナーをアップロードしています' - })[0]; - - if (folder) data.append('folder_id', folder.id); - - const xhr = new XMLHttpRequest(); - xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); - xhr.onload = e => { - const file = JSON.parse(e.target.response); - progress.close(); - set(file); - }; - - xhr.upload.onprogress = e => { - if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); - }; - - xhr.send(data); - }; - - const set = file => { - api(I, 'i/update', { - banner_id: file.id - }).then(i => { - dialog('バナーを更新しました', - '新しいバナーが反映されるまで時間がかかる場合があります。', - [{ - text: 'わかりました。' - }]); - - if (cb) cb(i); - }); - }; - - if (file) { - fileSelected(file); - } else { - const browser = riot.mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { - multiple: false, - title: 'バナーにする画像を選択' - })[0]; - - browser.one('selected', file => { - fileSelected(file); - }); - } -}; diff --git a/src/web/app/desktop/scripts/update-banner.ts b/src/web/app/desktop/scripts/update-banner.ts new file mode 100644 index 0000000000..23a671c44d --- /dev/null +++ b/src/web/app/desktop/scripts/update-banner.ts @@ -0,0 +1,87 @@ +import * as riot from 'riot'; +import CONFIG from '../../common/scripts/config'; +import dialog from './dialog'; +import api from '../../common/scripts/api'; + +export default (I, cb, file = null) => { + const fileSelected = file => { + const cropper = (riot as any).mount(document.body.appendChild(document.createElement('mk-crop-window')), { + file: file, + title: 'バナーとして表示する部分を選択', + aspectRatio: 16 / 9 + })[0]; + + cropper.on('cropped', blob => { + const data = new FormData(); + data.append('i', I.token); + data.append('file', blob, file.name + '.cropped.png'); + + api(I, 'drive/folders/find', { + name: 'バナー' + }).then(iconFolder => { + if (iconFolder.length === 0) { + api(I, 'drive/folders/create', { + name: 'バナー' + }).then(iconFolder => { + upload(data, iconFolder); + }); + } else { + upload(data, iconFolder[0]); + } + }); + }); + + cropper.on('skipped', () => { + set(file); + }); + }; + + const upload = (data, folder) => { + const progress = (riot as any).mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { + title: '新しいバナーをアップロードしています' + })[0]; + + if (folder) data.append('folder_id', folder.id); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const file = JSON.parse((e.target as any).response); + progress.close(); + set(file); + }; + + xhr.upload.onprogress = e => { + if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); + }; + + xhr.send(data); + }; + + const set = file => { + api(I, 'i/update', { + banner_id: file.id + }).then(i => { + dialog('バナーを更新しました', + '新しいバナーが反映されるまで時間がかかる場合があります。', + [{ + text: 'わかりました。' + }]); + + if (cb) cb(i); + }); + }; + + if (file) { + fileSelected(file); + } else { + const browser = (riot as any).mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { + multiple: false, + title: 'バナーにする画像を選択' + })[0]; + + browser.one('selected', file => { + fileSelected(file); + }); + } +}; -- cgit v1.2.3-freya