diff options
| author | syuilo⭐️ <Syuilotan@yahoo.co.jp> | 2017-02-22 02:18:57 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-02-22 02:18:57 +0900 |
| commit | 82a28f4c052e9c931c4844f0f330ec301c111366 (patch) | |
| tree | 321f492a7ad024e568786b831dfc864adeb77aea /src/web | |
| parent | Update README.md (diff) | |
| parent | Fix bugs (diff) | |
| download | misskey-82a28f4c052e9c931c4844f0f330ec301c111366.tar.gz misskey-82a28f4c052e9c931c4844f0f330ec301c111366.tar.bz2 misskey-82a28f4c052e9c931c4844f0f330ec301c111366.zip | |
Merge pull request #193 from syuilo/no-tag-ls
No tag ls
Diffstat (limited to 'src/web')
176 files changed, 5192 insertions, 4702 deletions
diff --git a/src/web/app/auth/tags/form.tag b/src/web/app/auth/tags/form.tag index 99212febfc..4a236f7594 100644 --- a/src/web/app/auth/tags/form.tag +++ b/src/web/app/auth/tags/form.tag @@ -106,21 +106,25 @@ </style> <script> - @mixin \api + this.mixin('api'); - @session = @opts.session - @app = @session.app + this.session = this.opts.session; + this.app = this.session.app; - @cancel = ~> - @api \auth/deny do - token: @session.token - .then ~> - @trigger \denied + this.cancel = () => { + this.api('auth/deny', { + token: this.session.token + }).then(() => { + this.trigger('denied'); + }); + }; - @accept = ~> - @api \auth/accept do - token: @session.token - .then ~> - @trigger \accepted + this.accept = () => { + this.api('auth/accept', { + token: this.session.token + }).then(() => { + this.trigger('accepted'); + }); + }; </script> </mk-form> diff --git a/src/web/app/auth/tags/index.tag b/src/web/app/auth/tags/index.tag index b17d857db2..f80e9dd1bc 100644 --- a/src/web/app/auth/tags/index.tag +++ b/src/web/app/auth/tags/index.tag @@ -88,50 +88,60 @@ </style> <script> - @mixin \i - @mixin \api + this.mixin('i'); + this.mixin('api'); - @state = null - @fetching = true + this.state = null; + this.fetching = true; - @token = window.location.href.split \/ .pop! + this.token = window.location.href.split('/').pop(); - @on \mount ~> - if not @SIGNIN then return + this.on('mount', () => { + if (!this.SIGNIN) return; - # Fetch session - @api \auth/session/show do - token: @token - .then (session) ~> - @session = session - @fetching = false + // Fetch session + this.api('auth/session/show', { + token: this.token + }).then(session => { + this.session = session; + this.fetching = false; - # 既に連携していた場合 - if @session.app.is_authorized - @api \auth/accept do - token: @session.token - .then ~> - @accepted! - else - @state = \waiting - @update! + // 既に連携していた場合 + if (this.session.app.is_authorized) { + this.api('auth/accept', { + token: this.session.token + }).then(() => { + this.accepted(); + }); + } else { + this.update({ + state: 'waiting' + }); - @refs.form.on \denied ~> - @state = \denied - @update! + this.refs.form.on('denied', () => { + this.update({ + state: 'denied' + }); + }); - @refs.form.on \accepted @accepted + this.refs.form.on('accepted', this.accepted); + } + }).catch(error => { + this.update({ + fetching: false, + state: 'fetch-session-error' + }); + }); + }); - .catch (error) ~> - @fetching = false - @state = \fetch-session-error - @update! + this.accepted = () => { + this.update({ + state: 'accepted' + }); - @accepted = ~> - @state = \accepted - @update! - - if @session.app.callback_url - location.href = @session.app.callback_url + '?token=' + @session.token + if (this.session.app.callback_url) { + location.href = this.session.app.callback_url + '?token=' + this.session.token; + } + }; </script> </mk-index> diff --git a/src/web/app/boot.js b/src/web/app/boot.js index ab147eb562..06e457e2b3 100644 --- a/src/web/app/boot.js +++ b/src/web/app/boot.js @@ -27,13 +27,16 @@ riot.mixin({ // ↓ iOS待ちPolyfill (SEE: http://caniuse.com/#feat=fetch) require('whatwg-fetch'); -// ↓ NodeList、HTMLCollectionで forEach を使えるようにする +// ↓ NodeList、HTMLCollection、FileListで forEach を使えるようにする if (NodeList.prototype.forEach === undefined) { NodeList.prototype.forEach = Array.prototype.forEach; } if (HTMLCollection.prototype.forEach === undefined) { HTMLCollection.prototype.forEach = Array.prototype.forEach; } +if (FileList.prototype.forEach === undefined) { + FileList.prototype.forEach = Array.prototype.forEach; +} // ↓ iOSでプライベートモードだとlocalStorageが使えないので既存のメソッドを上書きする try { diff --git a/src/web/app/common/scripts/contains.js b/src/web/app/common/scripts/contains.js new file mode 100644 index 0000000000..fe73666193 --- /dev/null +++ b/src/web/app/common/scripts/contains.js @@ -0,0 +1,8 @@ +module.exports = function(parent, child) { + let node = child.parentNode; + while (node) { + if (node == parent) return true; + node = node.parentNode; + } + return false; +} diff --git a/src/web/app/common/tags/api-info.tag b/src/web/app/common/tags/api-info.tag index f3cef26509..d3b1e4c25d 100644 --- a/src/web/app/common/tags/api-info.tag +++ b/src/web/app/common/tags/api-info.tag @@ -21,6 +21,6 @@ text-decoration underline </style> <script> - @mixin \i + this.mixin('i'); </script> </mk-api-info> diff --git a/src/web/app/common/tags/authorized-apps.tag b/src/web/app/common/tags/authorized-apps.tag index 16e9d9c0c1..14795e49da 100644 --- a/src/web/app/common/tags/authorized-apps.tag +++ b/src/web/app/common/tags/authorized-apps.tag @@ -17,18 +17,17 @@ </style> <script> - @mixin \api + this.mixin('api'); - @apps = [] - @fetching = true + this.apps = []; + this.fetching = true; - @on \mount ~> - @api \i/authorized_apps - .then (apps) ~> - @apps = apps - @fetching = false - @update! - .catch (err) ~> - console.error err + this.on('mount', () => { + this.api('i/authorized_apps').then(apps => { + this.apps = apps; + this.fetching = false; + this.update(); + }); + }); </script> </mk-authorized-apps> diff --git a/src/web/app/common/tags/copyright.tag b/src/web/app/common/tags/copyright.tag index 368c4e3196..9c3f1f648b 100644 --- a/src/web/app/common/tags/copyright.tag +++ b/src/web/app/common/tags/copyright.tag @@ -1,11 +1,7 @@ -<mk-copyright><span>(c) syuilo 2014-2017</span> +<mk-copyright> + <span>(c) syuilo 2014-2017</span> <style> :scope display block - - - - - </style> </mk-copyright> diff --git a/src/web/app/common/tags/core-error.tag b/src/web/app/common/tags/core-error.tag index 5b5d163600..feac70fbea 100644 --- a/src/web/app/common/tags/core-error.tag +++ b/src/web/app/common/tags/core-error.tag @@ -1,8 +1,7 @@ <mk-core-error> - <!--i: i.fa.fa-times-circle--><img src="/_/resources/error.jpg" alt=""/> - <h1> - <mk-ripple-string>サーバーに接続できません</mk-ripple-string> - </h1> + <!--i: i.fa.fa-times-circle--> + <img src="/_/resources/error.jpg" alt=""/> + <h1>サーバーに接続できません</h1> <p class="text">インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから<a onclick={ retry }>再度お試し</a>ください。</p> <p class="thanks">いつもMisskeyをご利用いただきありがとうございます。</p> <style> @@ -57,8 +56,9 @@ </style> <script> - @retry = ~> - @unmount! - @opts.retry! + this.retry = () => { + this.unmount(); + this.opts.retry(); + } </script> </mk-core-error> diff --git a/src/web/app/common/tags/ellipsis.tag b/src/web/app/common/tags/ellipsis.tag index 58f1083954..97ef745d02 100644 --- a/src/web/app/common/tags/ellipsis.tag +++ b/src/web/app/common/tags/ellipsis.tag @@ -20,10 +20,5 @@ opacity 1 40% opacity 0 - - - - - </style> </mk-ellipsis> diff --git a/src/web/app/common/tags/file-type-icon.tag b/src/web/app/common/tags/file-type-icon.tag index 37cae49993..55c473bcd4 100644 --- a/src/web/app/common/tags/file-type-icon.tag +++ b/src/web/app/common/tags/file-type-icon.tag @@ -5,6 +5,6 @@ display inline </style> <script> - @kind = @opts.type.split \/ .0 + this.kind = this.opts.type.split('/')[0]; </script> </mk-file-type-icon> diff --git a/src/web/app/common/tags/index.js b/src/web/app/common/tags/index.js index 21d817dbd2..90f03825e2 100644 --- a/src/web/app/common/tags/index.js +++ b/src/web/app/common/tags/index.js @@ -1,7 +1,6 @@ require('./core-error.tag'); require('./url.tag'); require('./url-preview.tag'); -require('./ripple-string.tag'); require('./time.tag'); require('./file-type-icon.tag'); require('./uploader.tag'); @@ -24,3 +23,4 @@ require('./messaging/room.tag'); require('./messaging/message.tag'); require('./messaging/index.tag'); require('./messaging/form.tag'); +require('./stream-indicator.tag'); diff --git a/src/web/app/common/tags/introduction.tag b/src/web/app/common/tags/introduction.tag index 24fe86e997..fda011efff 100644 --- a/src/web/app/common/tags/introduction.tag +++ b/src/web/app/common/tags/introduction.tag @@ -21,9 +21,5 @@ margin 0 text-align center - - - - </style> </mk-introduction> diff --git a/src/web/app/common/tags/messaging/form.tag b/src/web/app/common/tags/messaging/form.tag index d6750fb9ec..4e5f5262af 100644 --- a/src/web/app/common/tags/messaging/form.tag +++ b/src/web/app/common/tags/messaging/form.tag @@ -2,9 +2,15 @@ <textarea ref="text" onkeypress={ onkeypress } onpaste={ onpaste } placeholder="ここにメッセージを入力"></textarea> <div class="files"></div> <mk-uploader ref="uploader"></mk-uploader> - <button class="send" onclick={ send } disabled={ sending } title="メッセージを送信"><i class="fa fa-paper-plane" if={ !sending }></i><i class="fa fa-spinner fa-spin" if={ sending }></i></button> - <button class="attach-from-local" type="button" title="PCから画像を添付する"><i class="fa fa-upload"></i></button> - <button class="attach-from-drive" type="button" title="アルバムから画像を添付する"><i class="fa fa-folder-open"></i></button> + <button class="send" onclick={ send } disabled={ sending } title="メッセージを送信"> + <i class="fa fa-paper-plane" if={ !sending }></i><i class="fa fa-spinner fa-spin" if={ sending }></i> + </button> + <button class="attach-from-local" type="button" title="PCから画像を添付する"> + <i class="fa fa-upload"></i> + </button> + <button class="attach-from-drive" type="button" title="アルバムから画像を添付する"> + <i class="fa fa-folder-open"></i> + </button> <input name="file" type="file" accept="image/*"/> <style> :scope @@ -111,49 +117,60 @@ </style> <script> - @mixin \api + this.mixin('api'); - @onpaste = (e) ~> - data = e.clipboard-data - items = data.items - for i from 0 to items.length - 1 - item = items[i] - switch (item.kind) - | \file => - @upload item.get-as-file! + this.onpaste = (e) => { + const data = e.clipboardData; + const items = data.items; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + if (item.kind == 'file') { + this.upload(item.getAsFile()); + } + } + }; - @onkeypress = (e) ~> - if (e.which == 10 || e.which == 13) && e.ctrl-key - @send! + this.onkeypress = (e) => { + if ((e.which == 10 || e.which == 13) && e.ctrlKey) { + this.send(); + } + }; - @select-file = ~> - @refs.file.click! + this.selectFile = () => { + this.refs.file.click(); + }; - @select-file-from-drive = ~> - browser = document.body.append-child document.create-element \mk-select-file-from-drive-window - event = riot.observable! - riot.mount browser, do - multiple: true + this.selectFileFromDrive = () => { + const browser = document.body.appendChild(document.createElement('mk-select-file-from-drive-window')); + const event = riot.observable(); + riot.mount(browser, { + multiple: true, event: event - event.one \selected (files) ~> - files.for-each @add-file + }); + event.one('selected', files => { + files.forEach(this.addFile); + }); + }; - @send = ~> - @sending = true - @api \messaging/messages/create do - user_id: @opts.user.id - text: @refs.text.value - .then (message) ~> - @clear! - .catch (err) ~> - console.error err - .then ~> - @sending = false - @update! + this.send = () => { + this.sending = true; + this.api('messaging/messages/create', { + user_id: this.opts.user.id, + text: this.refs.text.value + }).then(message => { + this.clear(); + }).catch(err => { + console.error(err); + }).then(() => { + this.sending = false; + this.update(); + }); + }; - @clear = ~> - @refs.text.value = '' - @files = [] - @update! + this.clear = () => { + this.refs.text.value = ''; + this.files = []; + this.update(); + }; </script> </mk-messaging-form> diff --git a/src/web/app/common/tags/messaging/index.tag b/src/web/app/common/tags/messaging/index.tag index 69f78ba8e3..2dbf76bd9a 100644 --- a/src/web/app/common/tags/messaging/index.tag +++ b/src/web/app/common/tags/messaging/index.tag @@ -286,72 +286,88 @@ </style> <script> - @mixin \i - @mixin \api + this.mixin('i'); + this.mixin('api'); - @search-result = [] + this.searchResult = []; - @on \mount ~> - @api \messaging/history - .then (history) ~> - @is-loading = false - history.for-each (message) ~> - message.is_me = message.user_id == @I.id - message._click = ~> - if message.is_me - @trigger \navigate-user message.recipient - else - @trigger \navigate-user message.user - @history = history - @update! - .catch (err) ~> - console.error err + this.on('mount', () => { + this.api('messaging/history').then(history => { + this.isLoading = false; + history.forEach(message => { + message.is_me = message.user_id == this.I.id + message._click = () => { + this.trigger('navigate-user', message.is_me ? message.recipient : message.user); + }; + }); + this.history = history; + this.update(); + }); + }); - @search = ~> - q = @refs.search.value - if q == '' - @search-result = [] - else - @api \users/search do - query: q - max: 5 - .then (users) ~> - users.for-each (user) ~> - user._click = ~> - @trigger \navigate-user user - @search-result = [] - @search-result = users - @update! - .catch (err) ~> - console.error err + this.search = () => { + const q = this.refs.search.value; + if (q == '') { + this.searchResult = []; + return; + } + this.api('users/search', { + query: q, + max: 5 + }).then(users => { + users.forEach(user => { + user._click = () => { + this.trigger('navigate-user', user); + this.searchResult = []; + }; + }); + this.update({ + searchResult: users + }); + }); + }; - @on-search-keydown = (e) ~> - key = e.which - switch (key) - | 9, 40 => # Key[TAB] or Key[↓] - e.prevent-default! - e.stop-propagation! - @refs.search-result.child-nodes[0].focus! + this.onSearchKeydown = e => { + switch (e.which) { + case 9: // [TAB] + case 40: // [↓] + e.preventDefault(); + e.stopPropagation(); + this.refs.searchResult.childNodes[0].focus(); + break; + } + }; - @on-search-result-keydown = (i, e) ~> - key = e.which - switch (key) - | 10, 13 => # Key[ENTER] - e.prevent-default! - e.stop-propagation! - @search-result[i]._click! - | 27 => # Key[ESC] - e.prevent-default! - e.stop-propagation! - @refs.search.focus! - | 38 => # Key[↑] - e.prevent-default! - e.stop-propagation! - (@refs.search-result.child-nodes[i].previous-element-sibling || @refs.search-result.child-nodes[@search-result.length - 1]).focus! - | 9, 40 => # Key[TAB] or Key[↓] - e.prevent-default! - e.stop-propagation! - (@refs.search-result.child-nodes[i].next-element-sibling || @refs.search-result.child-nodes[0]).focus! + this.onSearchResultKeydown = (i, e) => { + const cancel = () => { + e.preventDefault(); + e.stopPropagation(); + }; + switch (true) { + case e.which == 10: // [ENTER] + case e.which == 13: // [ENTER] + cancel(); + this.searchResult[i]._click(); + break; + + case e.which == 27: // [ESC] + cancel(); + this.refs.search.focus(); + break; + + case e.which == 9 && e.shiftKey: // [TAB] + [Shift] + case e.which == 38: // [↑] + cancel(); + (this.refs.searchResult.childNodes[i].previousElementSibling || this.refs.searchResult.childNodes[this.searchResult.length - 1]).focus(); + break; + + case e.which == 9: // [TAB] + case e.which == 40: // [↓] + cancel(); + (this.refs.searchResult.childNodes[i].nextElementSibling || this.refs.searchResult.childNodes[0]).focus(); + break; + } + }; </script> </mk-messaging> diff --git a/src/web/app/common/tags/messaging/message.tag b/src/web/app/common/tags/messaging/message.tag index 5765ffa6c8..de763c779a 100644 --- a/src/web/app/common/tags/messaging/message.tag +++ b/src/web/app/common/tags/messaging/message.tag @@ -203,28 +203,32 @@ </style> <script> - @mixin \i - @mixin \text + this.mixin('i'); + this.mixin('text'); - @message = @opts.message - @message.is_me = @message.user.id == @I.id + this.message = this.opts.message; + this.message.is_me = this.message.user.id == this.I.id; - @on \mount ~> - if @message.text? - tokens = @analyze @message.text + this.on('mount', () => { + if (this.message.text) { + const tokens = this.analyze(this.message.text); - @refs.text.innerHTML = @compile tokens + this.refs.text.innerHTML = this.compile(tokens); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); - # URLをプレビュー + // URLをプレビュー tokens - .filter (t) -> t.type == \link - .map (t) ~> - @preview = @refs.text.append-child document.create-element \mk-url-preview - riot.mount @preview, do + .filter(t => t.type == 'link') + .map(t => { + const el = this.refs.text.appendChild(document.createElement('mk-url-preview')); + riot.mount(el, { url: t.content + }); + }); + } + }); </script> </mk-messaging-message> diff --git a/src/web/app/common/tags/messaging/room.tag b/src/web/app/common/tags/messaging/room.tag index 5882a7fa40..c7fed91db3 100644 --- a/src/web/app/common/tags/messaging/room.tag +++ b/src/web/app/common/tags/messaging/room.tag @@ -124,101 +124,117 @@ </style> <script> - @mixin \i - @mixin \api - @mixin \messaging-stream + this.mixin('i'); + this.mixin('api'); + this.mixin('messaging-stream'); - @user = @opts.user - @init = true - @sending = false - @messages = [] + this.user = this.opts.user; + this.init = true; + this.sending = false; + this.messages = []; - @connection = new @MessagingStreamConnection @I, @user.id + this.connection = new this.MessagingStreamConnection(this.I, this.user.id); - @on \mount ~> - @connection.event.on \message @on-message - @connection.event.on \read @on-read + this.on('mount', () => { + this.connection.event.on('message', this.onMessage); + this.connection.event.on('read', this.onRead); - document.add-event-listener \visibilitychange @on-visibilitychange + document.addEventListener('visibilitychange', this.onVisibilitychange); - @api \messaging/messages do - user_id: @user.id - .then (messages) ~> - @init = false - @messages = messages.reverse! - @update! - @scroll-to-bottom! - .catch (err) ~> - console.error err + this.api('messaging/messages', { + user_id: this.user.id + }).then(messages => { + this.init = false; + this.messages = messages.reverse(); + this.update(); + this.scrollToBottom(); + }); + }); - @on \unmount ~> - @connection.event.off \message @on-message - @connection.event.off \read @on-read - @connection.close! + this.on('unmount', () => { + this.connection.event.off('message', this.onMessage); + this.connection.event.off('read', this.onRead); + this.connection.close(); - document.remove-event-listener \visibilitychange @on-visibilitychange + document.removeEventListener('visibilitychange', this.onVisibilitychange); + }); - @on \update ~> - @messages.for-each (message) ~> - date = (new Date message.created_at).get-date! - month = (new Date message.created_at).get-month! + 1 - message._date = date - message._datetext = month + '月 ' + date + '日' + this.on('update', () => { + this.messages.forEach(message => { + const date = (new Date(message.created_at)).getDate(); + const month = (new Date(message.created_at)).getMonth() + 1; + message._date = date; + message._datetext = month + '月 ' + date + '日'; + }); + }); - @on-message = (message) ~> - is-bottom = @is-bottom! + this.onMessage = (message) => { + const isbottom = this.isBottom(); - @messages.push message - if message.user_id != @I.id and not document.hidden - @connection.socket.send JSON.stringify do - type: \read + this.messages.push(message); + if (message.user_id != this.I.id && !document.hidden) { + this.connection.socket.send(JSON.stringify({ + type: 'read', id: message.id - @update! + })); + } + this.update(); - if is-bottom - # Scroll to bottom - @scroll-to-bottom! - else if message.user_id != @I.id - # Notify - @notify '新しいメッセージがあります' + if (isBottom) { + // Scroll to bottom + this.scrollToBottom(); + } else if (message.user_id != this.I.id) { + // Notify + this.notify('新しいメッセージがあります'); + } + }; - @on-read = (ids) ~> - if not Array.isArray ids then ids = [ids] - ids.for-each (id) ~> - if (@messages.some (x) ~> x.id == id) - exist = (@messages.map (x) -> x.id).index-of id - @messages[exist].is_read = true - @update! + this.onRead = ids => { + if (!Array.isArray(ids)) ids = [ids]; + ids.forEach(id => { + if (this.messages.some(x => x.id == id)) { + const exist = this.messages.map(x => x.id).indexOf(id); + this.messages[exist].is_read = true; + this.update(); + } + }); + }; - @is-bottom = ~> - current = @root.scroll-top + @root.offset-height - max = @root.scroll-height - current > (max - 32) + this.isBottom = () => { + const current = this.root.scrollTop + this.root.offsetHeight; + const max = this.root.scrollHeight; + return current > (max - 32); + }; - @scroll-to-bottom = ~> - @root.scroll-top = @root.scroll-height + this.scrollToBottom = () => { + this.root.scrollTop = this.root.scrollHeight; + }; - @notify = (message) ~> - n = document.create-element \p - n.inner-HTML = '<i class="fa fa-arrow-circle-down"></i>' + message - n.onclick = ~> - @scroll-to-bottom! - n.parent-node.remove-child n - @refs.notifications.append-child n + this.notify = message => { + const n = document.createElement('p'); + n.innerHTML = '<i class="fa fa-arrow-circle-down"></i>' + message; + n.onclick = () => { + this.scrollToBottom(); + n.parentNode.removeChild(n); + }; + this.refs.notifications.appendChild(n); - set-timeout ~> - n.style.opacity = 0 - set-timeout ~> - n.parent-node.remove-child n - , 1000ms - , 4000ms + setTimeout(() => { + n.style.opacity = 0; + setTimeout(() => n.parentNode.removeChild(n), 1000); + }, 4000); + }; - @on-visibilitychange = ~> - if document.hidden then return - @messages.for-each (message) ~> - if message.user_id != @I.id and not message.is_read - @connection.socket.send JSON.stringify do - type: \read + this.onVisibilitychange = () => { + if (document.hidden) return; + this.messages.forEach(message => { + if (message.user_id !== this.I.id && !message.is_read) { + this.connection.socket.send(JSON.stringify({ + type: 'read', id: message.id + })); + } + }); + }; </script> </mk-messaging-room> diff --git a/src/web/app/common/tags/number.tag b/src/web/app/common/tags/number.tag index c878c842e2..7dcbceba6a 100644 --- a/src/web/app/common/tags/number.tag +++ b/src/web/app/common/tags/number.tag @@ -2,17 +2,17 @@ <style> :scope display inline - </style> <script> - @on \mount ~> - # バグ? https://github.com/riot/riot/issues/2103 - #value = @opts.value - value = @opts.riot-value - max = @opts.max + this.on('mount', () => { + // https://github.com/riot/riot/issues/2103 + //value = this.opts.value + let value = this.opts.riotValue; + const max = this.opts.max; - if max? then if value > max then value = max + if (max != null && value > max) value = max; - @root.innerHTML = value.to-locale-string! + this.root.innerHTML = value.toLocaleString(); + }); </script> </mk-number> diff --git a/src/web/app/common/tags/poll-editor.tag b/src/web/app/common/tags/poll-editor.tag index 1c9c668f0b..9d9b28c763 100644 --- a/src/web/app/common/tags/poll-editor.tag +++ b/src/web/app/common/tags/poll-editor.tag @@ -86,26 +86,31 @@ </style> <script> - @choices = ['', ''] + this.choices = ['', '']; - @oninput = (i, e) ~> - @choices[i] = e.target.value + this.oninput = (i, e) => { + this.choices[i] = e.target.value; + } - @add = ~> - @choices.push '' - @update! - @refs.choices.child-nodes[@choices.length - 1].child-nodes[0].focus! + this.add = () => { + this.choices.push(''); + this.update(); + this.refs.choices.childNodes[this.choices.length - 1].childNodes[0].focus(); + } - @remove = (i) ~> - @choices = @choices.filter((_, _i) -> _i != i) - @update! + this.remove = (i) => { + this.choices = this.choices.filter((_, _i) => _i != i); + this.update(); + } - @destroy = ~> - @opts.ondestroy! + this.destroy = () => { + this.opts.ondestroy(); + } - @get = ~> + this.get = () => { return { - choices: @choices.filter (choice) -> choice != '' + choices: this.choices.filter(choice => choice != '') } + } </script> </mk-poll-editor> diff --git a/src/web/app/common/tags/poll.tag b/src/web/app/common/tags/poll.tag index 426bb44281..6ddaf77595 100644 --- a/src/web/app/common/tags/poll.tag +++ b/src/web/app/common/tags/poll.tag @@ -68,32 +68,37 @@ </style> <script> - @mixin \api + this.mixin('api'); - @post = @opts.post - @poll = @post.poll - @total = @poll.choices.reduce ((a, b) -> a + b.votes), 0 - @is-voted = @poll.choices.some (c) -> c.is_voted - @result = @is-voted + this.post = this.opts.post; + this.poll = this.post.poll; + this.total = this.poll.choices.reduce((a, b) => a + b.votes, 0); + this.isVoted = this.poll.choices.some(c => c.is_voted); + this.result = this.isVoted; - @toggle-result = ~> - @result = !@result + this.toggleResult = () => { + this.result = !this.result; + } - @vote = (id) ~> - if (@poll.choices.some (c) -> c.is_voted) then return - @api \posts/polls/vote do - post_id: @post.id + this.vote = (id) => { + if (this.poll.choices.some(c => c.is_voted)) return; + this.api('posts/polls/vote', { + post_id: this.post.id, choice: id - .then ~> - @poll.choices.for-each (c) -> - if c.id == id - c.votes++ - c.is_voted = true - @update do - poll: @poll - is-voted: true - result: true - total: @total + 1 - + }).then(() => { + this.poll.choices.forEach(c => { + if (c.id == id) { + c.votes++; + c.is_voted = true; + } + }); + this.update({ + poll: this.poll, + isVoted: true, + result: true, + total: this.total + 1 + }); + }); + } </script> </mk-poll> diff --git a/src/web/app/common/tags/raw.tag b/src/web/app/common/tags/raw.tag index 609c53e7e9..0637675c45 100644 --- a/src/web/app/common/tags/raw.tag +++ b/src/web/app/common/tags/raw.tag @@ -4,5 +4,5 @@ display inline </style> - <script>@root.innerHTML = @opts.content</script> + <script>this.root.innerHTML = this.opts.content</script> </mk-raw> diff --git a/src/web/app/common/tags/ripple-string.tag b/src/web/app/common/tags/ripple-string.tag deleted file mode 100644 index d3303e6ba6..0000000000 --- a/src/web/app/common/tags/ripple-string.tag +++ /dev/null @@ -1,26 +0,0 @@ -<mk-ripple-string><yield/> - <style> - :scope - display inline - - > span - animation ripple-string 5s infinite ease-in-out both - - @keyframes ripple-string - 0%, 50%, 100% - opacity 1 - 25% - opacity 0.5 - - </style> - <script> - @on \mount ~> - text = @root.innerHTML - @root.innerHTML = '' - (text.split '').for-each (c, i) ~> - ce = document.create-element \span - ce.innerHTML = c - ce.style.animation-delay = (i / 10) + 's' - @root.append-child ce - </script> -</mk-ripple-string> diff --git a/src/web/app/common/tags/signin-history.tag b/src/web/app/common/tags/signin-history.tag index ffc837891d..3868980058 100644 --- a/src/web/app/common/tags/signin-history.tag +++ b/src/web/app/common/tags/signin-history.tag @@ -48,28 +48,30 @@ </style> <script> - @mixin \api - @mixin \stream + this.mixin('api'); + this.mixin('stream'); - @history = [] - @fetching = true + this.history = []; + this.fetching = true; - @on \mount ~> - @api \i/signin_history - .then (history) ~> - @history = history - @fetching = false - @update! - .catch (err) ~> - console.error err + this.on('mount', () => { + this.api('i/signin_history').then(history => { + this.update({ + fetching: false, + history: history + }); + }); - @stream.on \signin @on-signin + this.stream.on('signin', this.onSignin); + }); - @on \unmount ~> - @stream.off \signin @on-signin + this.on('unmount', () => { + this.stream.off('signin', this.onSignin); + }); - @on-signin = (signin) ~> - @history.unshift signin - @update! + this.onSignin = signin => { + this.history.unshift(signin); + this.update(); + }; </script> </mk-signin-history> diff --git a/src/web/app/common/tags/signin.tag b/src/web/app/common/tags/signin.tag index 28d73b037f..c44ae3d6ee 100644 --- a/src/web/app/common/tags/signin.tag +++ b/src/web/app/common/tags/signin.tag @@ -97,42 +97,50 @@ </style> <script> - @mixin \api + this.mixin('api'); - @user = null - @signing = false + this.user = null; + this.signing = false; - @oninput = ~> - @api \users/show do - username: @refs.username.value - .then (user) ~> - @user = user - @trigger \user user - @update! + this.oninput = () => { + this.api('users/show', { + username: this.refs.username.value + }).then(user => { + this.user = user; + this.trigger('user', user); + this.update(); + }); + }; - @onsubmit = (e) ~> - e.prevent-default! + this.onsubmit = e => { + e.preventDefault(); - if @refs.username.value == '' - @refs.username.focus! - return false - if @refs.password.value == '' - @refs.password.focus! - return false + if (this.refs.username.value == '') { + this.refs.username.focus(); + return false; + } + if (this.refs.password.value == '') { + this.refs.password.focus(); + return false; + } - @signing = true - @update! + this.update({ + signing: true + }); - @api \signin do - username: @refs.username.value - password: @refs.password.value - .then ~> - location.reload! - .catch ~> - alert 'something happened' - @signing = false - @update! + this.api('signin', { + username: this.refs.username.value, + password: this.refs.password.value + }).then(() => { + location.reload(); + }).catch(() => { + alert('something happened'); + this.update({ + signing: false + }); + }); - false + return false; + }; </script> </mk-signin> diff --git a/src/web/app/common/tags/signup.tag b/src/web/app/common/tags/signup.tag index 7af72807a5..f0358e2328 100644 --- a/src/web/app/common/tags/signup.tag +++ b/src/web/app/common/tags/signup.tag @@ -174,120 +174,126 @@ </style> <script> - @mixin \api - @mixin \get-password-strength + this.mixin('api'); + this.mixin('get-password-strength'); - @username-state = null - @password-strength = '' - @password-retype-state = null - @recaptchaed = false + this.usernameState = null; + this.passwordStrength = ''; + this.passwordRetypeState = null; + this.recaptchaed = false; - window.on-recaptchaed = ~> - @recaptchaed = true - @update! + window.onEecaptchaed = () => { + this.recaptchaed = true; + this.update(); + }; - window.on-recaptcha-expired = ~> - @recaptchaed = false - @update! + window.onRecaptchaExpired = () => { + this.recaptchaed = false; + this.update(); + }; - @on \mount ~> - head = (document.get-elements-by-tag-name \head).0 - script = document.create-element \script - ..set-attribute \src \https://www.google.com/recaptcha/api.js - head.append-child script + this.on('mount', () => { + const head = document.getElementsByTagName('head')[0]; + const script = document.createElement('script'); + script.setAttribute('src', 'https://www.google.com/recaptcha/api.js'); + head.appendChild(script); + }); - @on-change-username = ~> - username = @refs.username.value + this.onChangeUsername = () => { + const username = this.refs.username.value; - if username == '' - @username-state = null - @update! - return + if (username == '') { + this.update({ + usernameState: null + }); + return; + } - err = switch - | not username.match /^[a-zA-Z0-9\-]+$/ => \invalid-format - | username.length < 3chars => \min-range - | username.length > 20chars => \max-range - | _ => null + const err = + !username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' : + username.length < 3 ? 'min-range' : + username.length > 20 ? 'max-range' : + null; - if err? - @username-state = err - @update! - else - @username-state = \wait - @update! + if (err) { + this.update({ + usernameState: err + }); + return; + } - @api \username/available do - username: username - .then (result) ~> - if result.available - @username-state = \ok - else - @username-state = \unavailable - @update! - .catch (err) ~> - @username-state = \error - @update! + this.update({ + usernameState: 'wait' + }); - @on-change-password = ~> - password = @refs.password.value - - if password == '' - @password-strength = '' - return - - strength = @get-password-strength password + this.api('username/available', { + username: username + }).then(result => { + this.update({ + usernameState: result.available ? 'ok' : 'unavailable' + }); + }).catch(err => { + this.update({ + usernameState: 'error' + }); + }); + }; - if strength > 0.3 - @password-strength = \medium - if strength > 0.7 - @password-strength = \high - else - @password-strength = \low + this.onChangePassword = () => { + const password = this.refs.password.value; - @update! + if (password == '') { + this.passwordStrength = ''; + return; + } - @refs.password-metar.style.width = (strength * 100) + \% + const strength = this.getPasswordStrength(password); + this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low'; + this.update(); + this.refs.passwordMetar.style.width = `${strength * 100}%`; + }; - @on-change-password-retype = ~> - password = @refs.password.value - retyped-password = @refs.password-retype.value + this.onChangePasswordRetype = () => { + const password = this.refs.password.value; + const retypedPassword = this.refs.passwordRetype.value; - if retyped-password == '' - @password-retype-state = null - return + if (retypedPassword == '') { + this.passwordRetypeState = null; + return; + } - if password == retyped-password - @password-retype-state = \match - else - @password-retype-state = \not-match + this.passwordRetypeState = password == retypedPassword ? 'match' : 'not-match'; + }; - @onsubmit = (e) ~> - e.prevent-default! + this.onsubmit = e => { + e.preventDefault(); - username = @refs.username.value - password = @refs.password.value + const username = this.refs.username.value; + const password = this.refs.password.value; - locker = document.body.append-child document.create-element \mk-locker + const locker = document.body.appendChild(document.createElement('mk-locker')); - @api \signup do - username: username - password: password - 'g-recaptcha-response': grecaptcha.get-response! - .then ~> - @api \signin do - username: username + this.api('signup', { + username: username, + password: password, + 'g-recaptcha-response': grecaptcha.getResponse() + }).then(() => { + this.api('signin', { + username: username, password: password - .then ~> + }).then(() => { location.href = CONFIG.url - .catch ~> - alert '何らかの原因によりアカウントの作成に失敗しました。再度お試しください。' + }); + }).catch(() => { + alert('何らかの原因によりアカウントの作成に失敗しました。再度お試しください。'); - grecaptcha.reset! - @recaptchaed = false + grecaptcha.reset(); + this.recaptchaed = false; - locker.parent-node.remove-child locker + locker.parentNode.removeChild(locker); + }); - false + return false; + }; </script> </mk-signup> diff --git a/src/web/app/common/tags/special-message.tag b/src/web/app/common/tags/special-message.tag index 53c54c9816..41bd5fe32a 100644 --- a/src/web/app/common/tags/special-message.tag +++ b/src/web/app/common/tags/special-message.tag @@ -20,8 +20,8 @@ </style> <script> - now = new Date! - @d = now.get-date! - @m = now.get-month! + 1 + const now = new Date(); + this.d = now.getDate(); + this.m = now.getMonth() + 1; </script> </mk-special-message> diff --git a/src/web/app/common/tags/stream-indicator.tag b/src/web/app/common/tags/stream-indicator.tag new file mode 100644 index 0000000000..7d343a438a --- /dev/null +++ b/src/web/app/common/tags/stream-indicator.tag @@ -0,0 +1,65 @@ +<mk-stream-indicator> + <p if={ state == 'initializing' }> + <i class="fa fa-spinner fa-spin"></i> + <span>接続中<mk-ellipsis></mk-ellipsis></span> + </p> + <p if={ state == 'reconnecting' }> + <i class="fa fa-spinner fa-spin"></i> + <span>切断されました 接続中<mk-ellipsis></mk-ellipsis></span> + </p> + <p if={ state == 'connected' }> + <i class="fa fa-check"></i> + <span>接続完了</span> + </p> + <style> + :scope + display block + pointer-events none + position fixed + z-index 16384 + bottom 8px + right 8px + margin 0 + padding 6px 12px + font-size 0.9em + color #fff + background rgba(0, 0, 0, 0.8) + + > p + display block + margin 0 + + > i + margin-right 0.25em + + </style> + <script> + this.mixin('stream'); + + this.on('before-mount', () => { + this.state = this.getStreamState(); + + if (this.state == 'connected') { + this.root.style.opacity = 0; + } + }); + + this.streamStateEv.on('connected', () => { + this.state = this.getStreamState(); + this.update(); + setTimeout(() => { + Velocity(this.root, { + opacity: 0 + }, 200, 'linear'); + }, 1000); + }); + + this.streamStateEv.on('closed', () => { + this.state = this.getStreamState(); + this.update(); + Velocity(this.root, { + opacity: 1 + }, 0); + }); + </script> +</mk-stream-indicator> diff --git a/src/web/app/common/tags/time.tag b/src/web/app/common/tags/time.tag index 0c9a6d6f90..ad34115f60 100644 --- a/src/web/app/common/tags/time.tag +++ b/src/web/app/common/tags/time.tag @@ -1,41 +1,50 @@ <mk-time> - <time datetime={ opts.time }><span if={ mode == 'relative' }>{ relative }</span><span if={ mode == 'absolute' }>{ absolute }</span><span if={ mode == 'detail' }>{ absolute } ({ relative })</span></time> + <time datetime={ opts.time }> + <span if={ mode == 'relative' }>{ relative }</span> + <span if={ mode == 'absolute' }>{ absolute }</span> + <span if={ mode == 'detail' }>{ absolute } ({ relative })</span> + </time> <script> - @time = new Date @opts.time - @mode = @opts.mode || \relative - @tickid = null + this.time = new Date(this.opts.time); + this.mode = this.opts.mode || 'relative'; + this.tickid = null; - @absolute = - @time.get-full-year! + \年 + - @time.get-month! + 1 + \月 + - @time.get-date! + \日 + + this.absolute = + this.time.getFullYear() + '年' + + this.time.getMonth() + 1 + '月' + + this.time.getDate() + '日' + ' ' + - @time.get-hours! + \時 + - @time.get-minutes! + \分 + this.time.getHours() + '時' + + this.time.getMinutes() + '分'; - @on \mount ~> - if @mode == \relative or @mode == \detail - @tick! - @tickid = set-interval @tick, 1000ms + this.on('mount', () => { + if (this.mode == 'relative' || this.mode == 'detail') { + this.tick(); + this.tickid = setInterval(this.tick, 1000); + } + }); - @on \unmount ~> - if @mode == \relative or @mode == \detail - clear-interval @tickid + this.on('unmount', () => { + if (this.mode === 'relative' || this.mode === 'detail') { + clearInterval(this.tickid); + } + }); - @tick = ~> - now = new Date! - ago = (now - @time) / 1000ms - @relative = switch - | ago >= 31536000s => ~~(ago / 31536000s) + '年前' - | ago >= 2592000s => ~~(ago / 2592000s) + 'ヶ月前' - | ago >= 604800s => ~~(ago / 604800s) + '週間前' - | ago >= 86400s => ~~(ago / 86400s) + '日前' - | ago >= 3600s => ~~(ago / 3600s) + '時間前' - | ago >= 60s => ~~(ago / 60s) + '分前' - | ago >= 10s => ~~(ago % 60s) + '秒前' - | ago >= 0s => 'たった今' - | ago < 0s => '未来' - | _ => 'なぞのじかん' - @update! + this.tick = () => { + const now = new Date(); + const ago = (now - this.time) / 1000/*ms*/; + this.relative = + ago >= 31536000 ? ~~(ago / 31536000) + '年前' : + ago >= 2592000 ? ~~(ago / 2592000) + 'ヶ月前' : + ago >= 604800 ? ~~(ago / 604800) + '週間前' : + ago >= 86400 ? ~~(ago / 86400) + '日前' : + ago >= 3600 ? ~~(ago / 3600) + '時間前' : + ago >= 60 ? ~~(ago / 60) + '分前' : + ago >= 10 ? ~~(ago % 60) + '秒前' : + ago >= 0 ? 'たった今' : + ago < 0 ? '未来' : + 'なぞのじかん'; + this.update(); + }; </script> </mk-time> diff --git a/src/web/app/common/tags/twitter-setting.tag b/src/web/app/common/tags/twitter-setting.tag index 162ccd2928..6996c45b4d 100644 --- a/src/web/app/common/tags/twitter-setting.tag +++ b/src/web/app/common/tags/twitter-setting.tag @@ -24,6 +24,6 @@ color #8899a6 </style> <script> - @mixin \i + this.mixin('i'); </script> </mk-twitter-setting> diff --git a/src/web/app/common/tags/uploader.tag b/src/web/app/common/tags/uploader.tag index 275a26c019..51520d9abd 100644 --- a/src/web/app/common/tags/uploader.tag +++ b/src/web/app/common/tags/uploader.tag @@ -140,56 +140,59 @@ </style> <script> - @mixin \i + this.mixin('i'); - @uploads = [] + this.uploads = []; - - @upload = (file, folder) ~> - id = Math.random! + this.upload = (file, folder) => { + const id = Math.random(); - ctx = - id: id - name: file.name || \untitled + const ctx = { + id: id, + name: file.name || 'untitled', progress: undefined + }; - @uploads.push ctx - @trigger \change-uploads @uploads - @update! + this.uploads.push(ctx); + this.trigger('change-uploads', this.uploads); + this.update(); - reader = new FileReader! - reader.onload = (e) ~> - ctx.img = e.target.result - @update! - reader.read-as-data-URL file + const reader = new FileReader(); + reader.onload = e => { + ctx.img = e.target.result; + this.update(); + }; + reader.readAsDataURL(file); - data = new FormData! - data.append \i @I.token - data.append \file file + const data = new FormData(); + data.append('i', this.I.token); + data.append('file', file); - if folder? - data.append \folder_id folder + if (folder) data.append('folder_id', folder); - xhr = new XMLHttpRequest! - xhr.open \POST CONFIG.apiUrl + '/drive/files/create' true - xhr.onload = (e) ~> - drive-file = JSON.parse e.target.response + const xhr = new XMLHttpRequest(); + xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const driveFile = JSON.parse(e.target.response); - @trigger \uploaded drive-file + this.trigger('uploaded', driveFile); - @uploads = @uploads.filter (x) -> x.id != id - @trigger \change-uploads @uploads + this.uploads = this.uploads.filter(x => x.id != id); + this.trigger('change-uploads', this.uploads); - @update! + this.update(); + }; - xhr.upload.onprogress = (e) ~> - if e.length-computable - if ctx.progress == undefined - ctx.progress = {} - ctx.progress.max = e.total - ctx.progress.value = e.loaded - @update! + xhr.upload.onprogress = e => { + if (e.lengthComputable) { + if (ctx.progress == undefined) ctx.progress = {}; + ctx.progress.max = e.total; + ctx.progress.value = e.loaded; + this.update(); + } + }; - xhr.send data + xhr.send(data); + }; </script> </mk-uploader> diff --git a/src/web/app/common/tags/url-preview.tag b/src/web/app/common/tags/url-preview.tag index 7aab9d94e0..6daed4dbdf 100644 --- a/src/web/app/common/tags/url-preview.tag +++ b/src/web/app/common/tags/url-preview.tag @@ -91,22 +91,24 @@ </style> <script> - @mixin \api + this.mixin('api'); - @url = @opts.url - @loading = true + this.url = this.opts.url; + this.loading = true; - @on \mount ~> - fetch CONFIG.url + '/api:url?url=' + @url - .then (res) ~> - info <~ res.json!.then - @title = info.title - @description = info.description - @thumbnail = info.thumbnail - @icon = info.icon - @sitename = info.sitename + this.on('mount', () => { + fetch(CONFIG.url + '/api:url?url=' + this.url).then(res => { + res.json().then(info => { + this.title = info.title; + this.description = info.description; + this.thumbnail = info.thumbnail; + this.icon = info.icon; + this.sitename = info.sitename; - @loading = false - @update! + this.loading = false; + this.update(); + }); + }); + }); </script> </mk-url-preview> diff --git a/src/web/app/common/tags/url.tag b/src/web/app/common/tags/url.tag index d4284b61bf..0ad9e72b5d 100644 --- a/src/web/app/common/tags/url.tag +++ b/src/web/app/common/tags/url.tag @@ -30,19 +30,20 @@ </style> <script> - @url = @opts.href + this.url = this.opts.href; - @on \before-mount ~> - parser = document.create-element \a - parser.href = @url + this.on('before-mount', () => { + parser = document.createElement('a'); + parser.href = this.url; - @schema = parser.protocol - @hostname = parser.hostname - @port = parser.port - @pathname = parser.pathname - @query = parser.search - @hash = parser.hash + this.schema = parser.protocol; + this.hostname = parser.hostname; + this.port = parser.port; + this.pathname = parser.pathname; + this.query = parser.search; + this.hash = parser.hash; - @update! + this.update(); + }); </script> </mk-url> diff --git a/src/web/app/desktop/tags/analog-clock.tag b/src/web/app/desktop/tags/analog-clock.tag index d2458a7789..dcf4acaff8 100644 --- a/src/web/app/desktop/tags/analog-clock.tag +++ b/src/web/app/desktop/tags/analog-clock.tag @@ -6,100 +6,90 @@ display block width 256px height 256px - </style> <script> - @on \mount ~> - @draw! - @clock = set-interval @draw, 1000ms + const Vec2 = function(x, y) { + this.x = x; + this.y = y; + }; - @on \unmount ~> - clear-interval @clock + this.on('mount', () => { + this.draw() + this.clock = setInterval(this.draw, 1000); + }); - @draw = ~> - now = new Date! - s = now.get-seconds! - m = now.get-minutes! - h = now.get-hours! + this.on('unmount', () => { + clearInterval(this.clock); + }); - vec2 = (x, y) -> - @x = x - @y = y + this.draw = () => { + const now = new Date(); + const s = now.getSeconds(); + const m = now.getMinutes(); + const h = now.getHours(); - ctx = @refs.canvas.get-context \2d - canv-w = @refs.canvas.width - canv-h = @refs.canvas.height - ctx.clear-rect 0, 0, canv-w, canv-h + const ctx = this.refs.canvas.getContext('2d'); + const canvW = this.refs.canvas.width; + const canvH = this.refs.canvas.height; + ctx.clearRect(0, 0, canvW, canvH); - # 背景 - center = (Math.min (canv-w / 2), (canv-h / 2)) - line-start = center * 0.90 - line-end-short = center * 0.87 - line-end-long = center * 0.84 - for i from 0 to 59 by 1 - angle = Math.PI * i / 30 - uv = new vec2 (Math.sin angle), (-Math.cos angle) - ctx.begin-path! - ctx.line-width = 1 - ctx.move-to do - (canv-w / 2) + uv.x * line-start - (canv-h / 2) + uv.y * line-start - if i % 5 == 0 - ctx.stroke-style = 'rgba(255, 255, 255, 0.2)' - ctx.line-to do - (canv-w / 2) + uv.x * line-end-long - (canv-h / 2) + uv.y * line-end-long - else - ctx.stroke-style = 'rgba(255, 255, 255, 0.1)' - ctx.line-to do - (canv-w / 2) + uv.x * line-end-short - (canv-h / 2) + uv.y * line-end-short - ctx.stroke! + { // 背景 + const center = Math.min((canvW / 2), (canvH / 2)); + const lineStart = center * 0.90; + const shortLineEnd = center * 0.87; + const longLineEnd = center * 0.84; + for (let i = 0; i < 60; i++) { + const angle = Math.PI * i / 30; + const uv = new Vec2(Math.sin(angle), -Math.cos(angle)); + ctx.beginPath(); + ctx.lineWidth = 1; + ctx.moveTo((canvW / 2) + uv.x * lineStart, (canvH / 2) + uv.y * lineStart); + if (i % 5 == 0) { + ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)'; + ctx.lineTo((canvW / 2) + uv.x * longLineEnd, (canvH / 2) + uv.y * longLineEnd); + } else { + ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)'; + ctx.lineTo((canvW / 2) + uv.x * shortLineEnd, (canvH / 2) + uv.y * shortLineEnd); + } + ctx.stroke(); + } + } - # 分 - angle = Math.PI * (m + s / 60) / 30 - length = (Math.min canv-w, canv-h) / 2.6 - uv = new vec2 (Math.sin angle), (-Math.cos angle) - ctx.begin-path! - ctx.stroke-style = \#ffffff - ctx.line-width = 2 - ctx.move-to do - (canv-w / 2) - uv.x * length / 5 - (canv-h / 2) - uv.y * length / 5 - ctx.line-to do - (canv-w / 2) + uv.x * length - (canv-h / 2) + uv.y * length - ctx.stroke! + { // 分 + const angle = Math.PI * (m + s / 60) / 30; + const length = Math.min(canvW, canvH) / 2.6; + const uv = new Vec2(Math.sin(angle), -Math.cos(angle)); + ctx.beginPath(); + ctx.strokeStyle = '#ffffff'; + ctx.lineWidth = 2; + ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5); + ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length); + ctx.stroke(); + } - # 時 - angle = Math.PI * (h % 12 + m / 60) / 6 - length = (Math.min canv-w, canv-h) / 4 - uv = new vec2 (Math.sin angle), (-Math.cos angle) - ctx.begin-path! - #ctx.stroke-style = \#ffffff - ctx.stroke-style = CONFIG.theme-color - ctx.line-width = 2 - ctx.move-to do - (canv-w / 2) - uv.x * length / 5 - (canv-h / 2) - uv.y * length / 5 - ctx.line-to do - (canv-w / 2) + uv.x * length - (canv-h / 2) + uv.y * length - ctx.stroke! + { // 時 + const angle = Math.PI * (h % 12 + m / 60) / 6; + const length = Math.min(canvW, canvH) / 4; + const uv = new Vec2(Math.sin(angle), -Math.cos(angle)); + ctx.beginPath(); + ctx.strokeStyle = CONFIG.themeColor; + ctx.lineWidth = 2; + ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5); + ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length); + ctx.stroke(); + } - # 秒 - angle = Math.PI * s / 30 - length = (Math.min canv-w, canv-h) / 2.6 - uv = new vec2 (Math.sin angle), (-Math.cos angle) - ctx.begin-path! - ctx.stroke-style = 'rgba(255, 255, 255, 0.5)' - ctx.line-width = 1 - ctx.move-to do - (canv-w / 2) - uv.x * length / 5 - (canv-h / 2) - uv.y * length / 5 - ctx.line-to do - (canv-w / 2) + uv.x * length - (canv-h / 2) + uv.y * length - ctx.stroke! + { // 秒 + const angle = Math.PI * s / 30; + const length = Math.min(canvW, canvH) / 2.6; + const uv = new Vec2(Math.sin(angle), -Math.cos(angle)); + ctx.beginPath(); + ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)'; + ctx.lineWidth = 1; + ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5); + ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length); + ctx.stroke(); + } + }; </script> </mk-analog-clock> diff --git a/src/web/app/desktop/tags/autocomplete-suggestion.tag b/src/web/app/desktop/tags/autocomplete-suggestion.tag index 4aea8d8881..c7cc29dc19 100644 --- a/src/web/app/desktop/tags/autocomplete-suggestion.tag +++ b/src/web/app/desktop/tags/autocomplete-suggestion.tag @@ -80,108 +80,118 @@ </style> <script> - @mixin \api + const contains = require('../../common/scripts/contains'); - @q = @opts.q - @textarea = @opts.textarea - @loading = true - @users = [] - @select = -1 + this.mixin('api'); - @on \mount ~> - @textarea.add-event-listener \keydown @on-keydown + this.q = this.opts.q; + this.textarea = this.opts.textarea; + this.fetching = true; + this.users = []; + this.select = -1; - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.add-event-listener \mousedown @mousedown + this.on('mount', () => { + this.textarea.addEventListener('keydown', this.onKeydown); - @api \users/search_by_username do - query: @q - limit: 30users - .then (users) ~> - @users = users - @loading = false - @update! - .catch (err) ~> - console.error err + document.querySelectorAll('body *').forEach(el => { + el.addEventListener('mousedown', this.mousedown); + }); - @on \unmount ~> - @textarea.remove-event-listener \keydown @on-keydown + this.api('users/search_by_username', { + query: this.q, + limit: 30 + }).then(users => { + this.update({ + fetching: false, + users: users + }); + }); + }); - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.remove-event-listener \mousedown @mousedown + this.on('unmount', () => { + this.textarea.removeEventListener('keydown', this.onKeydown); - @mousedown = (e) ~> - if (!contains @root, e.target) and (@root != e.target) - @close! + document.querySelectorAll('body *').forEach(el => { + el.removeEventListener('mousedown', this.mousedown); + }); + }); - @on-click = (e) ~> - @complete e.item + this.mousedown = e => { + if (!contains(this.root, e.target) && (this.root != e.target)) this.close(); + }; - @on-keydown = (e) ~> - key = e.which - switch (key) - | 10, 13 => # Key[ENTER] - if @select != -1 - e.prevent-default! - e.stop-propagation! - @complete @users[@select] - else - @close! - | 27 => # Key[ESC] - e.prevent-default! - e.stop-propagation! - @close! - | 38 => # Key[↑] - if @select != -1 - e.prevent-default! - e.stop-propagation! - @select-prev! - else - @close! - | 9, 40 => # Key[TAB] or Key[↓] - e.prevent-default! - e.stop-propagation! - @select-next! - | _ => - @close! + this.onClick = e => { + this.complete(e.item); + }; - @select-next = ~> - @select++ + this.onKeydown = e => { + const cancel = () => { + e.preventDefault(); + e.stopPropagation(); + }; - if @select >= @users.length - @select = 0 + switch (e.which) { + case 10: // [ENTER] + case 13: // [ENTER] + if (this.select !== -1) { + cancel(); + this.complete(this.users[this.select]); + } else { + this.close(); + } + break; - @apply-select! + case 27: // [ESC] + cancel(); + this.close(); + break; - @select-prev = ~> - @select-- + case 38: // [↑] + if (this.select !== -1) { + cancel(); + this.selectPrev(); + } else { + this.close(); + } + break; - if @select < 0 - @select = @users.length - 1 + case 9: // [TAB] + case 40: // [↓] + cancel(); + this.selectNext(); + break; - @apply-select! + default: + this.close(); + } + }; - @apply-select = ~> - @refs.users.children.for-each (el) ~> - el.remove-attribute \data-selected + this.selectNext = () => { + if (++this.select >= this.users.length) this.select = 0; + this.applySelect(); + }; - @refs.users.children[@select].set-attribute \data-selected \true - @refs.users.children[@select].focus! + this.selectPrev = () => { + if (--this.select < 0) this.select = this.users.length - 1; + this.applySelect(); + }; - @complete = (user) ~> - @opts.complete user + this.applySelect = () => { + this.refs.users.children.forEach(el => { + el.removeAttribute('data-selected'); + }); - @close = ~> - @opts.close! + this.refs.users.children[this.select].setAttribute('data-selected', 'true'); + this.refs.users.children[this.select].focus(); + }; + + this.complete = user => { + this.opts.complete(user); + }; + + this.close = () => { + this.opts.close(); + }; - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - return false </script> </mk-autocomplete-suggestion> diff --git a/src/web/app/desktop/tags/big-follow-button.tag b/src/web/app/desktop/tags/big-follow-button.tag index dfee12b2a0..9d12b5a53e 100644 --- a/src/web/app/desktop/tags/big-follow-button.tag +++ b/src/web/app/desktop/tags/big-follow-button.tag @@ -70,58 +70,74 @@ </style> <script> - @mixin \api - @mixin \is-promise - @mixin \stream + this.mixin('api'); + this.mixin('is-promise'); + this.mixin('stream'); - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @init = true - @wait = false + this.user = null; + this.userPromise = this.isPromise(this.opts.user) + ? this.opts.user + : Promise.resolve(this.opts.user); + this.init = true; + this.wait = false; - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @init = false - @update! - @stream.on \follow @on-stream-follow - @stream.on \unfollow @on-stream-unfollow + this.on('mount', () => { + this.userPromise.then(user => { + this.update({ + init: false, + user: user + }); + this.stream.on('follow', this.onStreamFollow); + this.stream.on('unfollow', this.onStreamUnfollow); + }); + }); - @on \unmount ~> - @stream.off \follow @on-stream-follow - @stream.off \unfollow @on-stream-unfollow + this.on('unmount', () => { + this.stream.off('follow', this.onStreamFollow); + this.stream.off('unfollow', this.onStreamUnfollow); + }); - @on-stream-follow = (user) ~> - if user.id == @user.id - @user = user - @update! + this.onStreamFollow = user => { + if (user.id == this.user.id) { + this.update({ + user: user + }); + } + }; - @on-stream-unfollow = (user) ~> - if user.id == @user.id - @user = user - @update! + this.onStreamUnfollow = user => { + if (user.id == this.user.id) { + this.update({ + user: user + }); + } + }; - @onclick = ~> - @wait = true - if @user.is_following - @api \following/delete do - user_id: @user.id - .then ~> - @user.is_following = false - .catch (err) -> - console.error err - .then ~> - @wait = false - @update! - else - @api \following/create do - user_id: @user.id - .then ~> - @user.is_following = true - .catch (err) -> - console.error err - .then ~> - @wait = false - @update! + this.onclick = () => { + this.wait = true; + if (this.user.is_following) { + this.api('following/delete', { + user_id: this.user.id + }).then(() => { + this.user.is_following = false; + }).catch(err => { + console.error(err); + }).then(() => { + this.wait = false; + this.update(); + }); + } else { + this.api('following/create', { + user_id: this.user.id + }).then(() => { + this.user.is_following = true; + }).catch(err => { + console.error(err); + }).then(() => { + this.wait = false; + this.update(); + }); + } + }; </script> </mk-big-follow-button> diff --git a/src/web/app/desktop/tags/contextmenu.tag b/src/web/app/desktop/tags/contextmenu.tag index b22948b7d4..8df11c3819 100644 --- a/src/web/app/desktop/tags/contextmenu.tag +++ b/src/web/app/desktop/tags/contextmenu.tag @@ -1,4 +1,5 @@ -<mk-contextmenu><yield /> +<mk-contextmenu> + <yield /> <style> :scope $width = 240px @@ -94,46 +95,45 @@ </style> <script> - @root.add-event-listener \contextmenu (e) ~> - e.prevent-default! + const contains = require('../../common/scripts/contains'); - @mousedown = (e) ~> - e.prevent-default! - if (!contains @root, e.target) and (@root != e.target) - @close! - return false + this.root.addEventListener('contextmenu', e => { + e.preventDefault(); + }); - @open = (pos) ~> - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.add-event-listener \mousedown @mousedown - @root.style.display = \block - @root.style.left = pos.x + \px - @root.style.top = pos.y + \px + this.mousedown = e => { + e.preventDefault(); + if (!contains(this.root, e.target) && (this.root != e.target)) this.close(); + return false; + }; - Velocity @root, \finish true - Velocity @root, { opacity: 0 } 0ms - Velocity @root, { + this.open = pos => { + document.querySelectorAll('body *').forEach(el => { + el.addEventListener('mousedown', this.mousedown); + }); + + this.root.style.display = 'block'; + this.root.style.left = pos.x + 'px'; + this.root.style.top = pos.y + 'px'; + + Velocity(this.root, 'finish', true); + Velocity(this.root, { opacity: 0 }, 0); + Velocity(this.root, { opacity: 1 - } { - queue: false - duration: 100ms - easing: \linear - } + }, { + queue: false, + duration: 100, + easing: 'linear' + }); + }; - @close = ~> - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.remove-event-listener \mousedown @mousedown - @trigger \closed - @unmount! + this.close = () => { + document.querySelectorAll('body *').forEach(el => { + el.removeEventListener('mousedown', this.mousedown); + }); - function contains(parent, child) - node = child.parent-node - while (node != null) - if (node == parent) - return true - node = node.parent-node - return false + this.trigger('closed'); + this.unmount(); + }; </script> </mk-contextmenu> diff --git a/src/web/app/desktop/tags/crop-window.tag b/src/web/app/desktop/tags/crop-window.tag index 8d27f4c512..2cadc29948 100644 --- a/src/web/app/desktop/tags/crop-window.tag +++ b/src/web/app/desktop/tags/crop-window.tag @@ -158,31 +158,37 @@ </style> <script> - @mixin \cropper + this.mixin('cropper'); - @image = @opts.file - @title = @opts.title - @aspect-ratio = @opts.aspect-ratio - @cropper = null + this.image = this.opts.file; + this.title = this.opts.title; + this.aspectRatio = this.opts.aspectRatio; + this.cropper = null; - @on \mount ~> - @img = @refs.window.refs.img - @cropper = new @Cropper @img, do - aspect-ratio: @aspect-ratio - highlight: no - view-mode: 1 + this.on('mount', () => { + this.img = this.refs.window.refs.img; + this.cropper = new this.Cropper(this.img, { + aspectRatio: this.aspectRatio, + highlight: false, + viewMode: 1 + }); + }); - @ok = ~> - @cropper.get-cropped-canvas!.to-blob (blob) ~> - @trigger \cropped blob - @refs.window.close! + this.ok = () => { + this.cropper.getCroppedCanvas().toBlob(blob => { + this.trigger('cropped', blob); + this.refs.window.close(); + }); + }; - @skip = ~> - @trigger \skiped - @refs.window.close! + this.skip = () => { + this.trigger('skiped'); + this.refs.window.close(); + }; - @cancel = ~> - @trigger \canceled - @refs.window.close! + this.cancel = () => { + this.trigger('canceled'); + this.refs.window.close(); + }; </script> </mk-crop-window> diff --git a/src/web/app/desktop/tags/dialog.tag b/src/web/app/desktop/tags/dialog.tag index 528779242e..c0df0b330f 100644 --- a/src/web/app/desktop/tags/dialog.tag +++ b/src/web/app/desktop/tags/dialog.tag @@ -79,69 +79,72 @@ </style> <script> - @can-through = if opts.can-through? then opts.can-through else true - @opts.buttons.for-each (button) ~> - button._onclick = ~> - if button.onclick? - button.onclick! - @close! + this.canThrough = opts.canThrough != null ? opts.canThrough : true; + this.opts.buttons.forEach(button => { + button._onclick = () => { + if (button.onclick) button.onclick(); + this.close(); + }; + }); - @on \mount ~> - @refs.header.innerHTML = @opts.title - @refs.body.innerHTML = @opts.text + this.on('mount', () => { + this.refs.header.innerHTML = this.opts.title; + this.refs.body.innerHTML = this.opts.text; - @refs.bg.style.pointer-events = \auto - Velocity @refs.bg, \finish true - Velocity @refs.bg, { + this.refs.bg.style.pointerEvents = 'auto'; + Velocity(this.refs.bg, 'finish', true); + Velocity(this.refs.bg, { opacity: 1 - } { - queue: false - duration: 100ms - easing: \linear - } + }, { + queue: false, + duration: 100, + easing: 'linear' + }); - Velocity @refs.main, { - opacity: 0 + Velocity(this.refs.main, { + opacity: 0, scale: 1.2 - } { + }, { duration: 0 - } - Velocity @refs.main, { - opacity: 1 + }); + Velocity(this.refs.main, { + opacity: 1, scale: 1 - } { - duration: 300ms + }, { + duration: 300, easing: [ 0, 0.5, 0.5, 1 ] - } + }); + }); - @close = ~> - @refs.bg.style.pointer-events = \none - Velocity @refs.bg, \finish true - Velocity @refs.bg, { + this.close = () => { + this.refs.bg.style.pointerEvents = 'none'; + Velocity(this.refs.bg, 'finish', true); + Velocity(this.refs.bg, { opacity: 0 - } { - queue: false - duration: 300ms - easing: \linear - } + }, { + queue: false, + duration: 300, + easing: 'linear' + }); - @refs.main.style.pointer-events = \none - Velocity @refs.main, \finish true - Velocity @refs.main, { - opacity: 0 + this.refs.main.style.pointerEvents = 'none'; + Velocity(this.refs.main, 'finish', true); + Velocity(this.refs.main, { + opacity: 0, scale: 0.8 - } { - queue: false - duration: 300ms - easing: [ 0.5, -0.5, 1, 0.5 ] - complete: ~> - @unmount! - } + }, { + queue: false, + duration: 300, + easing: [ 0.5, -0.5, 1, 0.5 ], + complete: () => this.unmount() + }); + }; - @bg-click = ~> - if @can-through - if @opts.on-through? - @opts.on-through! - @close! + this.bgClick = () => { + if (this.canThrough) { + if (this.opts.onThrough) this.opts.onThrough(); + this.close(); + } + }; </script> </mk-dialog> diff --git a/src/web/app/desktop/tags/donation.tag b/src/web/app/desktop/tags/donation.tag index 7d0056d36f..e313188f24 100644 --- a/src/web/app/desktop/tags/donation.tag +++ b/src/web/app/desktop/tags/donation.tag @@ -47,21 +47,22 @@ </style> <script> - @mixin \api - @mixin \i + this.mixin('api'); + this.mixin('i'); - @close = (e) ~> - e.prevent-default! - e.stop-propagation! + this.close = e => { + e.preventDefault(); + e.stopPropagation(); - @I.data.no_donation = true - @I.update! - @api \i/appdata/set do - data: JSON.stringify do - no_donation: @I.data.no_donation + this.I.data.no_donation = true; + this.I.update(); + this.api('i/appdata/set', { + data: JSON.stringify({ + no_donation: this.I.data.no_donation + }) + }); - @unmount! - - @parent.parent.set-root-layout! + this.unmount(); + }; </script> </mk-donation> diff --git a/src/web/app/desktop/tags/drive/base-contextmenu.tag b/src/web/app/desktop/tags/drive/base-contextmenu.tag index c3a613d32b..2a95de0cd5 100644 --- a/src/web/app/desktop/tags/drive/base-contextmenu.tag +++ b/src/web/app/desktop/tags/drive/base-contextmenu.tag @@ -13,26 +13,32 @@ </ul> </mk-contextmenu> <script> - @browser = @opts.browser + this.browser = this.opts.browser; - @on \mount ~> - @refs.ctx.on \closed ~> - @trigger \closed - @unmount! + this.on('mount', () => { + this.refs.ctx.on('closed', () => { + this.trigger('closed'); + this.unmount(); + }); + }); - @open = (pos) ~> - @refs.ctx.open pos + this.open = pos => { + this.refs.ctx.open(pos); + }; - @create-folder = ~> - @browser.create-folder! - @refs.ctx.close! + this.createFolder = () => { + this.browser.createFolder(); + this.refs.ctx.close(); + }; - @upload = ~> - @browser.select-local-file! - @refs.ctx.close! + this.upload = () => { + this.browser.selectLocalFile(); + this.refs.ctx.close(); + }; - @url-upload = ~> - @browser.url-upload! - @refs.ctx.close! + this.urlUpload = () => { + this.browser.urlUpload(); + this.refs.ctx.close(); + }; </script> </mk-drive-browser-base-contextmenu> diff --git a/src/web/app/desktop/tags/drive/browser-window.tag b/src/web/app/desktop/tags/drive/browser-window.tag index c975427893..a658e36063 100644 --- a/src/web/app/desktop/tags/drive/browser-window.tag +++ b/src/web/app/desktop/tags/drive/browser-window.tag @@ -28,19 +28,24 @@ </style> <script> - @mixin \api + this.mixin('api'); - @folder = if @opts.folder? then @opts.folder else null + this.folder = this.opts.folder ? this.opts.folder : null; - @on \mount ~> - @refs.window.on \closed ~> - @unmount! + this.on('mount', () => { + this.refs.window.on('closed', () => { + this.unmount(); + }); - @api \drive .then (info) ~> - @update do + this.api('drive').then(info => { + this.update({ usage: info.usage / info.capacity * 100 + }); + }); + }); - @close = ~> - @refs.window.close! + this.close = () => { + this.refs.window.close(); + }; </script> </mk-drive-browser-window> diff --git a/src/web/app/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index 1e8448dab2..1e8b17cfcd 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -8,7 +8,7 @@ </div> <input class="search" type="search" placeholder=" 検索"/> </nav> - <div class="main { uploading: uploads.length > 0, loading: loading }" ref="main" onmousedown={ onmousedown } ondragover={ ondragover } ondragenter={ ondragenter } ondragleave={ ondragleave } ondrop={ ondrop } oncontextmenu={ oncontextmenu }> + <div class="main { uploading: uploads.length > 0, fetching: fetching }" ref="main" onmousedown={ onmousedown } ondragover={ ondragover } ondragenter={ ondragenter } ondragleave={ ondragleave } ondrop={ ondrop } oncontextmenu={ oncontextmenu }> <div class="selection" ref="selection"></div> <div class="contents" ref="contents"> <div class="folders" ref="foldersContainer" if={ folders.length > 0 }> @@ -23,13 +23,13 @@ </virtual> <button if={ moreFiles }>もっと読み込む</button> </div> - <div class="empty" if={ files.length == 0 && folders.length == 0 && !loading }> + <div class="empty" if={ files.length == 0 && folders.length == 0 && !fetching }> <p if={ draghover }>ドロップですか?いいですよ、ボクはカワイイですからね</p> <p if={ !draghover && folder == null }><strong>ドライブには何もありません。</strong><br/>右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。</p> <p if={ !draghover && folder != null }>このフォルダーは空です</p> </div> </div> - <div class="loading" if={ loading }> + <div class="loading" if={ fetching }> <div class="spinner"> <div class="dot1"></div> <div class="dot2"></div> @@ -133,7 +133,7 @@ &, * user-select none - &.loading + &.fetching cursor wait !important * @@ -184,7 +184,7 @@ > p margin 0 - > .loading + > .fetching .spinner margin 100px auto width 40px @@ -238,418 +238,439 @@ </style> <script> - @mixin \api - @mixin \dialog - @mixin \input-dialog - @mixin \stream + const contains = require('../../../common/scripts/contains'); - @files = [] - @folders = [] - @hierarchy-folders = [] + this.mixin('api'); + this.mixin('dialog'); + this.mixin('input-dialog'); + this.mixin('stream'); - @uploads = [] + this.files = []; + this.folders = []; + this.hierarchyFolders = []; - # 現在の階層(フォルダ) - # * null でルートを表す - @folder = null + this.uploads = []; - @multiple = if @opts.multiple? then @opts.multiple else false + // 現在の階層(フォルダ) + // * null でルートを表す + this.folder = null; - # ドロップされようとしているか - @draghover = false + this.multiple = this.opts.multiple != null ? this.opts.multiple : false; - # 自信の所有するアイテムがドラッグをスタートさせたか - # (自分自身の階層にドロップできないようにするためのフラグ) - @is-drag-source = false + // ドロップされようとしているか + this.draghover = false; - @on \mount ~> - @refs.uploader.on \uploaded (file) ~> - @add-file file, true + // 自信の所有するアイテムがドラッグをスタートさせたか + // (自分自身の階層にドロップできないようにするためのフラグ) + this.isDragSource = false; - @refs.uploader.on \change-uploads (uploads) ~> - @uploads = uploads - @update! + this.on('mount', () => { + this.refs.uploader.on('uploaded', file => { + this.addFile(file, true); + }); - @stream.on \drive_file_created @on-stream-drive-file-created - @stream.on \drive_file_updated @on-stream-drive-file-updated - @stream.on \drive_folder_created @on-stream-drive-folder-created - @stream.on \drive_folder_updated @on-stream-drive-folder-updated + this.refs.uploader.on('change-uploads', uploads => { + this.update({ + uploads: uploads + }); + }); - # Riotのバグでnullを渡しても""になる - # https://github.com/riot/riot/issues/2080 - #if @opts.folder? - if @opts.folder? and @opts.folder != '' - @move @opts.folder - else - @load! + this.stream.on('drive_file_created', this.onStreamDriveFileCreated); + this.stream.on('drive_file_updated', this.onStreamDriveFileUpdated); + this.stream.on('drive_folder_created', this.onStreamDriveFolderCreated); + this.stream.on('drive_folder_updated', this.onStreamDriveFolderUpdated); - @on \unmount ~> - @stream.off \drive_file_created @on-stream-drive-file-created - @stream.off \drive_file_updated @on-stream-drive-file-updated - @stream.off \drive_folder_created @on-stream-drive-folder-created - @stream.off \drive_folder_updated @on-stream-drive-folder-updated + // Riotのバグでnullを渡しても""になる + // https://github.com/riot/riot/issues/2080 + //if (this.opts.folder) + if (this.opts.folder && this.opts.folder != '') { + this.move(this.opts.folder); + } else { + this.load(); + } + }); - @on-stream-drive-file-created = (file) ~> - @add-file file, true + this.on('unmount', () => { + this.stream.off('drive_file_created', this.onStreamDriveFileCreated); + this.stream.off('drive_file_updated', this.onStreamDriveFileUpdated); + this.stream.off('drive_folder_created', this.onStreamDriveFolderCreated); + this.stream.off('drive_folder_updated', this.onStreamDriveFolderUpdated); + }); - @on-stream-drive-file-updated = (file) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - @remove-file file - else - @add-file file, true + this.onStreamDriveFileCreated = file => { + this.addFile(file, true); + }; - @on-stream-drive-folder-created = (folder) ~> - @add-folder folder, true + this.onStreamDriveFileUpdated = file => { + const current = this.folder ? this.folder.id : null; + if (current != file.folder_id) { + this.removeFile(file); + } else { + this.addFile(file, true); + } + }; - @on-stream-drive-folder-updated = (folder) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - @remove-folder folder - else - @add-folder folder, true + this.onStreamDriveFolderCreated = folder => { + this.addFolder(folder, true); + }; - @onmousedown = (e) ~> - if (contains @refs.folders-container, e.target) or (contains @refs.files-container, e.target) - return true + this.onStreamDriveFolderUpdated = folder => { + const current = this.folder ? this.folder.id : null; + if (current != folder.parent_id) { + this.removeFolder(folder); + } else { + this.addFolder(folder, true); + } + }; - rect = @refs.main.get-bounding-client-rect! + this.onmousedown = e => { + if (contains(this.refs.foldersContainer, e.target) || contains(this.refs.filesContainer, e.target)) return true; - left = e.page-x + @refs.main.scroll-left - rect.left - window.page-x-offset - top = e.page-y + @refs.main.scroll-top - rect.top - window.page-y-offset + const rect = this.refs.main.getBoundingClientRect(); - move = (e) ~> - @refs.selection.style.display = \block + const left = e.pageX + this.refs.main.scrollLeft - rect.left - window.pageXOffset + const top = e.pageY + this.refs.main.scrollTop - rect.top - window.pageYOffset - cursor-x = e.page-x + @refs.main.scroll-left - rect.left - window.page-x-offset - cursor-y = e.page-y + @refs.main.scroll-top - rect.top - window.page-y-offset - w = cursor-x - left - h = cursor-y - top + const move = e => { + this.refs.selection.style.display = 'block'; - if w > 0 - @refs.selection.style.width = w + \px - @refs.selection.style.left = left + \px - else - @refs.selection.style.width = -w + \px - @refs.selection.style.left = cursor-x + \px + const cursorX = e.pageX + this.refs.main.scrollLeft - rect.left - window.pageXOffset; + const cursorY = e.pageY + this.refs.main.scrollTop - rect.top - window.pageYOffset; + const w = cursorX - left; + const h = cursorY - top; - if h > 0 - @refs.selection.style.height = h + \px - @refs.selection.style.top = top + \px - else - @refs.selection.style.height = -h + \px - @refs.selection.style.top = cursor-y + \px + if (w > 0) { + this.refs.selection.style.width = w + 'px'; + this.refs.selection.style.left = left + 'px'; + } else { + this.refs.selection.style.width = -w + 'px'; + this.refs.selection.style.left = cursorX + 'px'; + } - up = (e) ~> - document.document-element.remove-event-listener \mousemove move - document.document-element.remove-event-listener \mouseup up + if (h > 0) { + this.refs.selection.style.height = h + 'px'; + this.refs.selection.style.top = top + 'px'; + } else { + this.refs.selection.style.height = -h + 'px'; + this.refs.selection.style.top = cursorY + 'px'; + } + }; - @refs.selection.style.display = \none + up = e => { + document.documentElement.removeEventListener('mousemove', move); + document.documentElement.removeEventListener('mouseup', up); - document.document-element.add-event-listener \mousemove move - document.document-element.add-event-listener \mouseup up + this.refs.selection.style.display = 'none'; + }; - @path-oncontextmenu = (e) ~> - e.prevent-default! - e.stop-immediate-propagation! - return false + document.documentElement.addEventListener('mousemove', move); + document.documentElement.addEventListener('mouseup', up); + }; - @ondragover = (e) ~> - e.prevent-default! - e.stop-propagation! + this.pathOncontextmenu = e => { + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + }; - # ドラッグ元が自分自身の所有するアイテムかどうか - if !@is-drag-source - # ドラッグされてきたものがファイルだったら - if e.data-transfer.effect-allowed == \all - e.data-transfer.drop-effect = \copy - else - e.data-transfer.drop-effect = \move - @draghover = true - else - # 自分自身にはドロップさせない - e.data-transfer.drop-effect = \none - return false + this.ondragover = e => { + e.preventDefault(); + e.stopPropagation(); - @ondragenter = (e) ~> - e.prevent-default! - if !@is-drag-source - @draghover = true + // ドラッグ元が自分自身の所有するアイテムかどうか + if (!this.isDragSource) { + // ドラッグされてきたものがファイルだったら + e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move'; + this.draghover = true; + } else { + // 自分自身にはドロップさせない + e.dataTransfer.dropEffect = 'none'; + return false; + } + }; - @ondragleave = (e) ~> - @draghover = false + this.ondragenter = e => { + e.preventDefault(); + if (!this.isDragSource) this.draghover = true; + }; - @ondrop = (e) ~> - e.prevent-default! - e.stop-propagation! + this.ondragleave = e => { + this.draghover = false; + }; - @draghover = false + this.ondrop = e => { + e.preventDefault(); + e.stopPropagation(); - # ドロップされてきたものがファイルだったら - if e.data-transfer.files.length > 0 - Array.prototype.for-each.call e.data-transfer.files, (file) ~> - @upload file, @folder - return false + this.draghover = false; - # データ取得 - data = e.data-transfer.get-data 'text' - if !data? - return false + // ドロップされてきたものがファイルだったら + if (e.dataTransfer.files.length > 0) { + e.dataTransfer.files.forEach(file => { + this.upload(file, this.folder); + }); + return false; + } - # パース - obj = JSON.parse data + // データ取得 + const data = e.dataTransfer.getData('text'); + if (data == null) return false; - # (ドライブの)ファイルだったら - if obj.type == \file - file = obj.id - if (@files.some (f) ~> f.id == file) - return false - @remove-file file - @api \drive/files/update do - file_id: file - folder_id: if @folder? then @folder.id else null - .then ~> - # something - .catch (err, text-status) ~> - console.error err + // パース + // TODO: JSONじゃなかったら中断 + const obj = JSON.parse(data); - # (ドライブの)フォルダーだったら - else if obj.type == \folder - folder = obj.id - # 移動先が自分自身ならreject - if @folder? and folder == @folder.id - return false - if (@folders.some (f) ~> f.id == folder) - return false - @remove-folder folder - @api \drive/folders/update do - folder_id: folder - parent_id: if @folder? then @folder.id else null - .then ~> - # something - .catch (err) ~> - if err == 'detected-circular-definition' - @dialog do - '<i class="fa fa-exclamation-triangle"></i>操作を完了できません' - '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。' - [ - text: \OK - ] - - return false - - @oncontextmenu = (e) ~> - e.prevent-default! - e.stop-immediate-propagation! + // (ドライブの)ファイルだったら + if (obj.type == 'file') { + const file = obj.id; + if (this.files.some(f => f.id == file)) return false; + this.removeFile(file); + this.api('drive/files/update', { + file_id: file, + folder_id: this.folder ? this.folder.id : null + }); + // (ドライブの)フォルダーだったら + } else if (obj.type == 'folder') { + const folder = obj.id; + // 移動先が自分自身ならreject + if (this.folder && folder == this.folder.id) return false; + if (this.folders.some(f => f.id == folder)) return false; + this.removeFolder(folder); + this.api('drive/folders/update', { + folder_id: folder, + parent_id: this.folder ? this.folder.id : null + }).then(() => { + // something + }).catch(err => { + switch (err) { + case 'detected-circular-definition': + this.dialog('<i class="fa fa-exclamation-triangle"></i>操作を完了できません', + '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。', [{ + text: 'OK' + }]); + break; + default: + alert('不明なエラー' + err); + } + }); + } - ctx = document.body.append-child document.create-element \mk-drive-browser-base-contextmenu - ctx = riot.mount ctx, do - browser: @ - ctx = ctx.0 - ctx.open do - x: e.page-x - window.page-x-offset - y: e.page-y - window.page-y-offset + return false; + }; - return false + this.oncontextmenu = e => { + e.preventDefault(); + e.stopImmediatePropagation(); - @select-local-file = ~> - @refs.file-input.click! + const ctx = riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-base-contextmenu')), { + browser: this + })[0]; + ctx.open({ + x: e.pageX - window.pageXOffset, + y: e.pageY - window.pageYOffset + }); - @url-upload = ~> - url <~ @input-dialog do - 'URLアップロード' - 'アップロードしたいファイルのURL' - null + return false; + }; - if url? and url != '' - @api \drive/files/upload_from_url do - url: url - folder_id: if @folder? then @folder.id else undefined + this.selectLocalFile = () => { + this.refs.fileInput.click(); + }; - @dialog do - '<i class="fa fa-check"></i>アップロードをリクエストしました' - 'アップロードが完了するまで時間がかかる場合があります。' - [ - text: \OK - ] + this.urlUpload = () => { + this.inputDialog('URLアップロード', 'アップロードしたいファイルのURL', null, url => { + this.api('drive/files/upload_from_url', { + url: url, + folder_id: this.folder ? this.folder.id : undefined + }); - @create-folder = ~> - name <~ @input-dialog do - 'フォルダー作成' - 'フォルダー名' - null + this.dialog('<i class="fa fa-check"></i>アップロードをリクエストしました', + 'アップロードが完了するまで時間がかかる場合があります。', [{ + text: 'OK' + }]); + }); + }; - @api \drive/folders/create do - name: name - folder_id: if @folder? then @folder.id else undefined - .then (folder) ~> - @add-folder folder, true - @update! - .catch (err) ~> - console.error err + this.createFolder = () => { + this.inputDialog('フォルダー作成', 'フォルダー名', null, name => { + this.api('drive/folders/create', { + name: name, + folder_id: this.folder ? this.folder.id : undefined + }).then(folder => { + this.addFolder(folder, true); + this.update(); + }); + }); + }; - @change-file-input = ~> - files = @refs.file-input.files - for i from 0 to files.length - 1 - file = files.item i - @upload file, @folder + this.changeFileInput = () => { + this.refs.fileInput.files.forEach(file => { + this.upload(file, this.folder); + }); + }; - @upload = (file, folder) ~> - if folder? and typeof folder == \object - folder = folder.id - @refs.uploader.upload file, folder + this.upload = (file, folder) => { + if (folder && typeof folder == 'object') folder = folder.id; + this.refs.uploader.upload(file, folder); + }; - @get-selection = ~> - @files.filter (file) -> file._selected + this.getSelection = () => { + this.files.filter(file => file._selected); + }; - @new-window = (folder-id) ~> - browser = document.body.append-child document.create-element \mk-drive-browser-window - riot.mount browser, do - folder: folder-id + this.newWindow = folderId => { + riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-window')), { + folder: folderId + }); + }; - @move = (target-folder) ~> - if target-folder? and typeof target-folder == \object - target-folder = target-folder.id + this.move = target => { + if (target == null) { + this.goRoot(); + return; + } else if (typeof target == 'object') { + target = target.id; + } - if target-folder == null - @go-root! - return + this.update({ + fetching: true + }); - @loading = true - @update! + this.api('drive/folders/show', { + folder_id: target + }).then(folder => { + this.folder = folder; + this.hierarchyFolders = []; - @api \drive/folders/show do - folder_id: target-folder - .then (folder) ~> - @folder = folder - @hierarchy-folders = [] + const dive = folder => { + this.hierarchyFolders.unshift(folder); + if (folder.parent) dive(folder.parent); + }; - x = (f) ~> - @hierarchy-folders.unshift f - if f.parent? - x f.parent + if (folder.parent) dive(folder.parent); - if folder.parent? - x folder.parent + this.update(); + this.load(); + }); + }; - @update! - @load! - .catch (err, text-status) -> - console.error err + this.addFolder = (folder, unshift = false) => { + const current = this.folder ? this.folder.id : null; + if (current != folder.parent_id) return; - @add-folder = (folder, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - return + if (this.folders.some(f => f.id == folder.id)) { + const exist = this.folders.map(f => f.id).indexOf(folder.id); + this.folders[exist] = folder; + this.update(); + return; + } - if (@folders.some (f) ~> f.id == folder.id) - exist = (@folders.map (f) -> f.id).index-of folder.id - @folders[exist] = folder - @update! - return + if (unshift) { + this.folders.unshift(folder); + } else { + this.folders.push(folder); + } - if unshift - @folders.unshift folder - else - @folders.push folder + this.update(); + }; - @update! + this.addFile = (file, unshift = false) => { + const current = this.folder ? this.folder.id : null; + if (current != file.folder_id) return; - @add-file = (file, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - return + if (this.files.some(f => f.id == file.id)) { + const exist = this.files.map(f => f.id).indexOf(file.id); + this.files[exist] = file; + this.update(); + return; + } - if (@files.some (f) ~> f.id == file.id) - exist = (@files.map (f) -> f.id).index-of file.id - @files[exist] = file - @update! - return + if (unshift) { + this.files.unshift(file); + } else { + this.files.push(file); + } - if unshift - @files.unshift file - else - @files.push file + this.update(); + }; - @update! + this.removeFolder = folder => { + if (typeof folder == 'object') folder = folder.id; + this.folders = this.folders.filter(f => f.id != folder); + this.update(); + }; - @remove-folder = (folder) ~> - if typeof folder == \object - folder = folder.id - @folders = @folders.filter (f) -> f.id != folder - @update! + this.removeFile = file => { + if (typeof file == 'object') file = file.id; + this.files = this.files.filter(f => f.id != file); + this.update(); + }; - @remove-file = (file) ~> - if typeof file == \object - file = file.id - @files = @files.filter (f) -> f.id != file - @update! + this.goRoot = () => { + // 既にrootにいるなら何もしない + if (this.folder == null) return; - @go-root = ~> - if @folder != null - @folder = null - @hierarchy-folders = [] - @update! - @load! + this.update({ + folder: null, + hierarchyFolders: [] + }); + this.load(); + }; - @load = ~> - @folders = [] - @files = [] - @more-folders = false - @more-files = false - @loading = true - @update! + this.load = () => { + this.update({ + folders: [], + files: [], + moreFolders: false, + moreFiles: false, + fetching: true + }); - load-folders = null - load-files = null + let fetchedFolders = null; + let fetchedFiles = null; - folders-max = 30 - files-max = 30 + const foldersMax = 30; + const filesMax = 30; - # フォルダ一覧取得 - @api \drive/folders do - folder_id: if @folder? then @folder.id else null - limit: folders-max + 1 - .then (folders) ~> - if folders.length == folders-max + 1 - @more-folders = true - folders.pop! - load-folders := folders - complete! - .catch (err, text-status) ~> - console.error err + // フォルダ一覧取得 + this.api('drive/folders', { + folder_id: this.folder ? this.folder.id : null, + limit: foldersMax + 1 + }).then(folders => { + if (folders.length == foldersMax + 1) { + this.moreFolders = true; + folders.pop(); + } + fetchedFolders = folders; + complete(); + }); - # ファイル一覧取得 - @api \drive/files do - folder_id: if @folder? then @folder.id else null - limit: files-max + 1 - .then (files) ~> - if files.length == files-max + 1 - @more-files = true - files.pop! - load-files := files - complete! - .catch (err, text-status) ~> - console.error err + // ファイル一覧取得 + this.api('drive/files', { + folder_id: this.folder ? this.folder.id : null, + limit: filesMax + 1 + }).then(files => { + if (files.length == filesMax + 1) { + this.moreFiles = true; + files.pop(); + } + fetchedFiles = files; + complete(); + }); - flag = false - complete = ~> - if flag - load-folders.for-each (folder) ~> - @add-folder folder - load-files.for-each (file) ~> - @add-file file - @loading = false - @update! - else - flag := true + let flag = false; + const complete = () => { + if (flag) { + fetchedFolders.forEach(this.addFolder); + fetchedFiles.forEach(this.addFile); + this.update({ + fetching: false + }); + } else { + flag = true; + } + }; + }; - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - return false </script> </mk-drive-browser> diff --git a/src/web/app/desktop/tags/drive/file-contextmenu.tag b/src/web/app/desktop/tags/drive/file-contextmenu.tag index a2c9eb3f4e..29f1befc44 100644 --- a/src/web/app/desktop/tags/drive/file-contextmenu.tag +++ b/src/web/app/desktop/tags/drive/file-contextmenu.tag @@ -22,9 +22,6 @@ <li onclick={ parent.setBanner }> <p>バナーに設定</p> </li> - <li onclick={ parent.setWallpaper }> - <p>壁紙に設定</p> - </li> </ul> </li> <li class="has-child"> @@ -38,60 +35,58 @@ </ul> </mk-contextmenu> <script> - @mixin \api - @mixin \i - @mixin \update-avatar - @mixin \update-banner - @mixin \update-wallpaper - @mixin \input-dialog - @mixin \NotImplementedException - - @browser = @opts.browser - @file = @opts.file - - @on \mount ~> - @refs.ctx.on \closed ~> - @trigger \closed - @unmount! + this.mixin('api'); + this.mixin('i'); + this.mixin('update-avatar'); + this.mixin('update-banner'); + this.mixin('input-dialog'); + this.mixin('NotImplementedException'); - @open = (pos) ~> - @refs.ctx.open pos + this.browser = this.opts.browser; + this.file = this.opts.file; - @rename = ~> - @refs.ctx.close! + this.on('mount', () => { + this.refs.ctx.on('closed', () => { + this.trigger('closed'); + this.unmount(); + }); + }); - name <~ @input-dialog do - 'ファイル名の変更' - '新しいファイル名を入力してください' - @file.name + this.open = pos => { + this.refs.ctx.open(pos); + }; - @api \drive/files/update do - file_id: @file.id - name: name - .then ~> - # something - .catch (err) ~> - console.error err + this.rename = () => { + this.refs.ctx.close(); - @copy-url = ~> - @NotImplementedException! + this.inputDialog('ファイル名の変更', '新しいファイル名を入力してください', this.file.name, name => { + this.api('drive/files/update', { + file_id: this.file.id, + name: name + }) + }); + }; - @download = ~> - @refs.ctx.close! + this.copyUrl = () => { + this.NotImplementedException(); + }; - @set-avatar = ~> - @refs.ctx.close! - @update-avatar @I, null, @file + this.download = () => { + this.refs.ctx.close(); + }; - @set-banner = ~> - @refs.ctx.close! - @update-banner @I, null, @file + this.setAvatar = () => { + this.refs.ctx.close(); + this.updateAvatar(this.I, null, this.file); + }; - @set-wallpaper = ~> - @refs.ctx.close! - @update-wallpaper @I, null, @file + this.setBanner = () => { + this.refs.ctx.close(); + this.updateBanner(this.I, null, this.file); + }; - @add-app = ~> - @NotImplementedException! + this.addApp = () => { + this.NotImplementedException(); + }; </script> </mk-drive-browser-file-contextmenu> diff --git a/src/web/app/desktop/tags/drive/file.tag b/src/web/app/desktop/tags/drive/file.tag index 252e5ab1de..d92d4bbaf1 100644 --- a/src/web/app/desktop/tags/drive/file.tag +++ b/src/web/app/desktop/tags/drive/file.tag @@ -144,66 +144,76 @@ </style> <script> - @bytes-to-size = require '../../../common/scripts/bytes-to-size.js' + this.bytesToSize = require('../../../common/scripts/bytes-to-size'); - @mixin \i + this.mixin('i'); - @file = @opts.file - @browser = @parent + this.file = this.opts.file; + this.browser = this.parent; - @title = @file.name + '\n' + @file.type + ' ' + (@bytes-to-size @file.datasize) + this.title = `${this.file.name}\n${this.file.type} ${this.bytesToSize(this.file.datasize)}`; - @is-contextmenu-showing = false + this.isContextmenuShowing = false; - @onclick = ~> - if @browser.multiple - if @file._selected? - @file._selected = !@file._selected - else - @file._selected = true - @browser.trigger \change-selection @browser.get-selection! - else - if @file._selected - @browser.trigger \selected @file - else - @browser.files.for-each (file) ~> - file._selected = false - @file._selected = true - @browser.trigger \change-selection @file + this.onclick = () => { + if (this.browser.multiple) { + if (this.file._selected != null) { + this.file._selected = !this.file._selected; + } else { + this.file._selected = true; + } + this.browser.trigger('change-selection', this.browser.getSelection()); + } else { + if (this.file._selected) { + this.browser.trigger('selected', this.file); + } else { + this.browser.files.forEach(file => file._selected = false); + this.file._selected = true; + this.browser.trigger('change-selection', this.file); + } + } + }; - @oncontextmenu = (e) ~> - e.prevent-default! - e.stop-immediate-propagation! + this.oncontextmenu = e => { + e.preventDefault(); + e.stopImmediatePropagation(); - @is-contextmenu-showing = true - @update! - ctx = document.body.append-child document.create-element \mk-drive-browser-file-contextmenu - ctx = riot.mount ctx, do - browser: @browser - file: @file - ctx = ctx.0 - ctx.open do - x: e.page-x - window.page-x-offset - y: e.page-y - window.page-y-offset - ctx.on \closed ~> - @is-contextmenu-showing = false - @update! - return false + this.update({ + isContextmenuShowing: true + }); + const ctx = riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-file-contextmenu')), { + browser: this.browser, + file: this.file + })[0]; + ctx.open({ + x: e.pageX - window.pageXOffset, + y: e.pageY - window.pageYOffset + }); + ctx.on('closed', () => { + this.update({ + isContextmenuShowing: false + }); + }); + return false; + }; - @ondragstart = (e) ~> - e.data-transfer.effect-allowed = \move - e.data-transfer.set-data 'text' JSON.stringify do - type: \file - id: @file.id - file: @file - @is-dragging = true + this.ondragstart = e => { + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('text', JSON.stringify({ + type: 'file', + id: this.file.id, + file: this.file + })); + this.isDragging = true; - # 親ブラウザに対して、ドラッグが開始されたフラグを立てる - # (=あなたの子供が、ドラッグを開始しましたよ) - @browser.is-drag-source = true + // 親ブラウザに対して、ドラッグが開始されたフラグを立てる + // (=あなたの子供が、ドラッグを開始しましたよ) + this.browser.isDragSource = true; + }; - @ondragend = (e) ~> - @is-dragging = false - @browser.is-drag-source = false + this.ondragend = e => { + this.isDragging = false; + this.browser.isDragSource = false; + }; </script> </mk-drive-browser-file> diff --git a/src/web/app/desktop/tags/drive/folder-contextmenu.tag b/src/web/app/desktop/tags/drive/folder-contextmenu.tag index aea0904aa9..51e131f448 100644 --- a/src/web/app/desktop/tags/drive/folder-contextmenu.tag +++ b/src/web/app/desktop/tags/drive/folder-contextmenu.tag @@ -18,49 +18,45 @@ </ul> </mk-contextmenu> <script> - @mixin \api - @mixin \input-dialog + this.mixin('api'); + this.mixin('input-dialog'); - @browser = @opts.browser - @folder = @opts.folder + this.browser = this.opts.browser; + this.folder = this.opts.folder; - @open = (pos) ~> - @refs.ctx.open pos + this.open = pos => { + this.refs.ctx.open(pos); - @refs.ctx.on \closed ~> - @trigger \closed - @unmount! + this.refs.ctx.on('closed', () => { + this.trigger('closed'); + this.unmount(); + }); + }; - @move = ~> - @browser.move @folder.id - @refs.ctx.close! + this.move = () => { + this.browser.move(this.folder.id); + this.refs.ctx.close(); + }; - @new-window = ~> - @browser.new-window @folder.id - @refs.ctx.close! + this.newWindow = () => { + this.browser.newWindow(this.folder.id); + this.refs.ctx.close(); + }; - @create-folder = ~> - @browser.create-folder! - @refs.ctx.close! + this.createFolder = () => { + this.browser.createFolder(); + this.refs.ctx.close(); + }; - @upload = ~> - @browser.select-lcoal-file! - @refs.ctx.close! + this.rename = () => { + this.refs.ctx.close(); - @rename = ~> - @refs.ctx.close! - - name <~ @input-dialog do - 'フォルダ名の変更' - '新しいフォルダ名を入力してください' - @folder.name - - @api \drive/folders/update do - folder_id: @folder.id - name: name - .then ~> - # something - .catch (err) ~> - console.error err + this.inputialog('フォルダ名の変更', '新しいフォルダ名を入力してください', this.folder.name, name => { + this.api('drive/folders/update', { + folder_id: this.folder.id, + name: name + }); + }); + }; </script> </mk-drive-browser-folder-contextmenu> diff --git a/src/web/app/desktop/tags/drive/folder.tag b/src/web/app/desktop/tags/drive/folder.tag index b6d52f19e6..1b804e97a1 100644 --- a/src/web/app/desktop/tags/drive/folder.tag +++ b/src/web/app/desktop/tags/drive/folder.tag @@ -50,135 +50,152 @@ </style> <script> - @mixin \api - @mixin \dialog + this.mixin('api'); + this.mixin('dialog'); - @folder = @opts.folder - @browser = @parent + this.folder = this.opts.folder; + this.browser = this.parent; - @title = @folder.name - @hover = false - @draghover = false - @is-contextmenu-showing = false + this.title = this.folder.name; + this.hover = false; + this.draghover = false; + this.isContextmenuShowing = false; - @onclick = ~> - @browser.move @folder + this.onclick = () => { + this.browser.move(this.folder); + }; - @onmouseover = ~> - @hover = true + this.onmouseover = () => { + this.hover = true; + }; - @onmouseout = ~> - @hover = false + this.onmouseout = () => { + this.hover = false + }; - @ondragover = (e) ~> - e.prevent-default! - e.stop-propagation! + this.ondragover = e => { + e.preventDefault(); + e.stopPropagation(); - # 自分自身がドラッグされていない場合 - if !@is-dragging - # ドラッグされてきたものがファイルだったら - if e.data-transfer.effect-allowed == \all - e.data-transfer.drop-effect = \copy - else - e.data-transfer.drop-effect = \move - else - # 自分自身にはドロップさせない - e.data-transfer.drop-effect = \none - return false + // 自分自身がドラッグされていない場合 + if (!this.isDragging) { + // ドラッグされてきたものがファイルだったら + if (e.dataTransfer.effectAllowed === 'all') { + e.dataTransfer.dropEffect = 'copy'; + } else { + e.dataTransfer.dropEffect = 'move'; + } + } else { + // 自分自身にはドロップさせない + e.dataTransfer.dropEffect = 'none'; + } + return false; + }; - @ondragenter = ~> - if !@is-dragging - @draghover = true + this.ondragenter = () => { + if (!this.isDragging) this.draghover = true; + }; - @ondragleave = ~> - @draghover = false + this.ondragleave = () => { + this.draghover = false; + }; - @ondrop = (e) ~> - e.stop-propagation! - @draghover = false + this.ondrop = e => { + e.stopPropagation(); + this.draghover = false; - # ファイルだったら - if e.data-transfer.files.length > 0 - Array.prototype.for-each.call e.data-transfer.files, (file) ~> - @browser.upload file, @folder - return false + // ファイルだったら + if (e.dataTransfer.files.length > 0) { + e.dataTransfer.files.forEach(file => { + this.browser.upload(file, this.folder); + }); + return false; + }; - # データ取得 - data = e.data-transfer.get-data 'text' - if !data? - return false + // データ取得 + const data = e.dataTransfer.getData('text'); + if (data == null) return false; - # パース - obj = JSON.parse data + // パース + // TODO: Validate JSON + const obj = JSON.parse(data); - # (ドライブの)ファイルだったら - if obj.type == \file - file = obj.id - @browser.remove-file file - @api \drive/files/update do - file_id: file - folder_id: @folder.id - .then ~> - # something - .catch (err, text-status) ~> - console.error err + // (ドライブの)ファイルだったら + if (obj.type == 'file') { + const file = obj.id; + this.browser.removeFile(file); + this.api('drive/files/update', { + file_id: file, + folder_id: this.folder.id + }); + // (ドライブの)フォルダーだったら + } else if (obj.type == 'folder') { + const folder = obj.id; + // 移動先が自分自身ならreject + if (folder == this.folder.id) return false; + this.browser.removeFolder(folder); + this.api('drive/folders/update', { + folder_id: folder, + parent_id: this.folder.id + }).then(() => { + // something + }).catch(err => { + switch (err) { + case 'detected-circular-definition': + this.dialog('<i class="fa fa-exclamation-triangle"></i>操作を完了できません', + '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。', [{ + text: 'OK' + }]); + break; + default: + alert('不明なエラー' + err); + } + }); + } - # (ドライブの)フォルダーだったら - else if obj.type == \folder - folder = obj.id - # 移動先が自分自身ならreject - if folder == @folder.id - return false - @browser.remove-folder folder - @api \drive/folders/update do - folder_id: folder - parent_id: @folder.id - .then ~> - # something - .catch (err) ~> - if err == 'detected-circular-definition' - @dialog do - '<i class="fa fa-exclamation-triangle"></i>操作を完了できません' - '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。' - [ - text: \OK - ] + return false; + }; - return false + this.ondragstart = e => { + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('text', JSON.stringify({ + type: 'folder', + id: this.folder.id + })); + this.isDragging = true; - @ondragstart = (e) ~> - e.data-transfer.effect-allowed = \move - e.data-transfer.set-data 'text' JSON.stringify do - type: \folder - id: @folder.id - @is-dragging = true + // 親ブラウザに対して、ドラッグが開始されたフラグを立てる + // (=あなたの子供が、ドラッグを開始しましたよ) + this.browser.isDragSource = true; + }; - # 親ブラウザに対して、ドラッグが開始されたフラグを立てる - # (=あなたの子供が、ドラッグを開始しましたよ) - @browser.is-drag-source = true + this.ondragend = e => { + this.isDragging = false; + this.browser.isDragSource = false; + }; - @ondragend = (e) ~> - @is-dragging = false - @browser.is-drag-source = false + this.oncontextmenu = e => { + e.preventDefault(); + e.stopImmediatePropagation(); - @oncontextmenu = (e) ~> - e.prevent-default! - e.stop-immediate-propagation! + this.update({ + isContextmenuShowing: true + }); + const ctx = riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-folder-contextmenu')), { + browser: this.browser, + folder: this.folder + })[0]; + ctx.open({ + x: e.pageX - window.pageXOffset, + y: e.pageY - window.pageYOffset + }); + ctx.on('closed', () => { + this.update({ + isContextmenuShowing: false + }); + }); - @is-contextmenu-showing = true - @update! - ctx = document.body.append-child document.create-element \mk-drive-browser-folder-contextmenu - ctx = riot.mount ctx, do - browser: @browser - folder: @folder - ctx = ctx.0 - ctx.open do - x: e.page-x - window.page-x-offset - y: e.page-y - window.page-y-offset - ctx.on \closed ~> - @is-contextmenu-showing = false - @update! - - return false + return false; + }; </script> </mk-drive-browser-folder> diff --git a/src/web/app/desktop/tags/drive/nav-folder.tag b/src/web/app/desktop/tags/drive/nav-folder.tag index 632783d20b..e961ac491b 100644 --- a/src/web/app/desktop/tags/drive/nav-folder.tag +++ b/src/web/app/desktop/tags/drive/nav-folder.tag @@ -6,92 +6,93 @@ </style> <script> - @mixin \api + this.mixin('api'); - # Riotのバグでnullを渡しても""になる - # https://github.com/riot/riot/issues/2080 - #@folder = @opts.folder - @folder = if @opts.folder? and @opts.folder != '' then @opts.folder else null - @browser = @parent + // Riotのバグでnullを渡しても""になる + // https://github.com/riot/riot/issues/2080 + //this.folder = this.opts.folder + this.folder = this.opts.folder && this.opts.folder != '' ? this.opts.folder : null; + this.browser = this.parent; - @hover = false + this.hover = false; - @onclick = ~> - @browser.move @folder + this.onclick = () => { + this.browser.move(this.folder); + }; - @onmouseover = ~> - @hover = true + this.onmouseover = () => { + this.hover = true + }; - @onmouseout = ~> - @hover = false + this.onmouseout = () => { + this.hover = false + }; - @ondragover = (e) ~> - e.prevent-default! - e.stop-propagation! + this.ondragover = e => { + e.preventDefault(); + e.stopPropagation(); - # このフォルダがルートかつカレントディレクトリならドロップ禁止 - if @folder == null and @browser.folder == null - e.data-transfer.drop-effect = \none - # ドラッグされてきたものがファイルだったら - else if e.data-transfer.effect-allowed == \all - e.data-transfer.drop-effect = \copy - else - e.data-transfer.drop-effect = \move - return false + // このフォルダがルートかつカレントディレクトリならドロップ禁止 + if (this.folder == null && this.browser.folder == null) { + e.dataTransfer.dropEffect = 'none'; + // ドラッグされてきたものがファイルだったら + } else if (e.dataTransfer.effectAllowed == 'all') { + e.dataTransfer.dropEffect = 'copy'; + } else { + e.dataTransfer.dropEffect = 'move'; + } + return false; + }; - @ondragenter = ~> - if @folder != null or @browser.folder != null - @draghover = true + this.ondragenter = () => { + if (this.folder || this.browser.folder) this.draghover = true; + }; - @ondragleave = ~> - if @folder != null or @browser.folder != null - @draghover = false + this.ondragleave = () => { + if (this.folder || this.browser.folder) this.draghover = false; + }; - @ondrop = (e) ~> - e.stop-propagation! - @draghover = false + this.ondrop = e => { + e.stopPropagation(); + this.draghover = false; - # ファイルだったら - if e.data-transfer.files.length > 0 - Array.prototype.for-each.call e.data-transfer.files, (file) ~> - @browser.upload file, @folder - return false + // ファイルだったら + if (e.dataTransfer.files.length > 0) { + e.dataTransfer.files.forEach(file => { + this.browser.upload(file, this.folder); + }); + return false; + }; - # データ取得 - data = e.data-transfer.get-data 'text' - if !data? - return false + // データ取得 + const data = e.dataTransfer.getData('text'); + if (data == null) return false; - # パース - obj = JSON.parse data + // パース + // TODO: Validate JSON + const obj = JSON.parse(data); - # (ドライブの)ファイルだったら - if obj.type == \file - file = obj.id - @browser.remove-file file - @api \drive/files/update do - file_id: file - folder_id: if @folder? then @folder.id else null - .then ~> - # something - .catch (err, text-status) ~> - console.error err + // (ドライブの)ファイルだったら + if (obj.type == 'file') { + const file = obj.id; + this.browser.removeFile(file); + this.api('drive/files/update', { + file_id: file, + folder_id: this.folder ? this.folder.id : null + }); + // (ドライブの)フォルダーだったら + } else if (obj.type == 'folder') { + const folder = obj.id; + // 移動先が自分自身ならreject + if (this.folder && folder == this.folder.id) return false; + this.browser.removeFolder(folder); + this.api('drive/folders/update', { + folder_id: folder, + parent_id: this.folder ? this.folder.id : null + }); + } - # (ドライブの)フォルダーだったら - else if obj.type == \folder - folder = obj.id - # 移動先が自分自身ならreject - if @folder? and folder == @folder.id - return false - @browser.remove-folder folder - @api \drive/folders/update do - folder_id: folder - parent_id: if @folder? then @folder.id else null - .then ~> - # something - .catch (err, text-status) ~> - console.error err - - return false + return false; + }; </script> </mk-drive-browser-nav-folder> diff --git a/src/web/app/desktop/tags/ellipsis-icon.tag b/src/web/app/desktop/tags/ellipsis-icon.tag index 731c2525f1..8462bfc4af 100644 --- a/src/web/app/desktop/tags/ellipsis-icon.tag +++ b/src/web/app/desktop/tags/ellipsis-icon.tag @@ -33,9 +33,5 @@ 40% transform scale(1) - - - - </style> </mk-ellipsis-icon> diff --git a/src/web/app/desktop/tags/follow-button.tag b/src/web/app/desktop/tags/follow-button.tag index 1e82b5ed1a..1877e4a53f 100644 --- a/src/web/app/desktop/tags/follow-button.tag +++ b/src/web/app/desktop/tags/follow-button.tag @@ -67,58 +67,74 @@ </style> <script> - @mixin \api - @mixin \is-promise - @mixin \stream + this.mixin('api'); + this.mixin('is-promise'); + this.mixin('stream'); - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @init = true - @wait = false + this.user = null; + this.userPromise = this.isPromise(this.opts.user) + ? this.opts.user + : Promise.resolve(this.opts.user); + this.init = true; + this.wait = false; - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @init = false - @update! - @stream.on \follow @on-stream-follow - @stream.on \unfollow @on-stream-unfollow + this.on('mount', () => { + this.userPromise.then(user => { + this.update({ + init: false, + user: user + }); + this.stream.on('follow', this.onStreamFollow); + this.stream.on('unfollow', this.onStreamUnfollow); + }); + }); - @on \unmount ~> - @stream.off \follow @on-stream-follow - @stream.off \unfollow @on-stream-unfollow + this.on('unmount', () => { + this.stream.off('follow', this.onStreamFollow); + this.stream.off('unfollow', this.onStreamUnfollow); + }); - @on-stream-follow = (user) ~> - if user.id == @user.id - @user = user - @update! + this.onStreamFollow = user => { + if (user.id == this.user.id) { + this.update({ + user: user + }); + } + }; - @on-stream-unfollow = (user) ~> - if user.id == @user.id - @user = user - @update! + this.onStreamUnfollow = user => { + if (user.id == this.user.id) { + this.update({ + user: user + }); + } + }; - @onclick = ~> - @wait = true - if @user.is_following - @api \following/delete do - user_id: @user.id - .then ~> - @user.is_following = false - .catch (err) -> - console.error err - .then ~> - @wait = false - @update! - else - @api \following/create do - user_id: @user.id - .then ~> - @user.is_following = true - .catch (err) -> - console.error err - .then ~> - @wait = false - @update! + this.onclick = () => { + this.wait = true; + if (this.user.is_following) { + this.api('following/delete', { + user_id: this.user.id + }).then(() => { + this.user.is_following = false; + }).catch(err => { + console.error(err); + }).then(() => { + this.wait = false; + this.update(); + }); + } else { + this.api('following/create', { + user_id: this.user.id + }).then(() => { + this.user.is_following = true; + }).catch(err => { + console.error(err); + }).then(() => { + this.wait = false; + this.update(); + }); + } + }; </script> </mk-follow-button> diff --git a/src/web/app/desktop/tags/following-setuper.tag b/src/web/app/desktop/tags/following-setuper.tag index 1b2e5aafa0..3dc8fb54c7 100644 --- a/src/web/app/desktop/tags/following-setuper.tag +++ b/src/web/app/desktop/tags/following-setuper.tag @@ -1,6 +1,6 @@ <mk-following-setuper> <p class="title">気になるユーザーをフォロー:</p> - <div class="users" if={ !loading && users.length > 0 }> + <div class="users" if={ !fetching && users.length > 0 }> <div class="user" each={ users }><a class="avatar-anchor" href={ CONFIG.url + '/' + username }><img class="avatar" src={ avatar_url + '?thumbnail&size=42' } alt="" data-user-preview={ id }/></a> <div class="body"><a class="name" href={ CONFIG.url + '/' + username } target="_blank" data-user-preview={ id }>{ name }</a> <p class="username">@{ username }</p> @@ -8,8 +8,8 @@ <mk-follow-button user={ this }></mk-follow-button> </div> </div> - <p class="empty" if={ !loading && users.length == 0 }>おすすめのユーザーは見つかりませんでした。</p> - <p class="loading" if={ loading }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます + <p class="empty" if={ !fetching && users.length == 0 }>おすすめのユーザーは見つかりませんでした。</p> + <p class="fetching" if={ fetching }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます <mk-ellipsis></mk-ellipsis> </p><a class="refresh" onclick={ refresh }>もっと見る</a> <button class="close" onclick={ close } title="閉じる"><i class="fa fa-times"></i></button> @@ -81,7 +81,7 @@ text-align center color #aaa - > .loading + > .fetching margin 0 padding 16px text-align center @@ -123,41 +123,49 @@ </style> <script> - @mixin \api - @mixin \user-preview + this.mixin('api'); + this.mixin('user-preview'); - @users = null - @loading = true + this.users = null; + this.fetching = true; - @limit = 6users - @page = 0 + this.limit = 6; + this.page = 0; - @on \mount ~> - @load! + this.on('mount', () => { + this.fetch(); + }); - @load = ~> - @loading = true - @users = null - @update! + this.fetch = () => { + this.update({ + fetching: true, + users: null + }); - @api \users/recommendation do - limit: @limit - offset: @limit * @page - .then (users) ~> - @loading = false - @users = users - @update! - .catch (err, text-status) -> - console.error err + this.api('users/recommendation', { + limit: this.limit, + offset: this.limit * this.page + }).then(users => { + this.fetching = false + this.users = users + this.update({ + fetching: false, + users: users + }); + }); + }; - @refresh = ~> - if @users.length < @limit - @page = 0 - else - @page++ - @load! + this.refresh = () => { + if (this.users.length < this.limit) { + this.page = 0; + } else { + this.page++; + } + this.fetch(); + }; - @close = ~> - @unmount! + this.close = () => { + this.unmount(); + }; </script> </mk-following-setuper> diff --git a/src/web/app/desktop/tags/go-top.tag b/src/web/app/desktop/tags/go-top.tag deleted file mode 100644 index d43e68ea90..0000000000 --- a/src/web/app/desktop/tags/go-top.tag +++ /dev/null @@ -1,14 +0,0 @@ -<mk-go-top> - <button class="hidden" title="一番上へ"><i class="fa fa-angle-up"></i></button> - <script> - window.add-event-listener \load @on-scroll - window.add-event-listener \scroll @on-scroll - window.add-event-listener \resize @on-scroll - - @on-scroll = ~> - if $ window .scroll-top! > 500px - @remove-class \hidden - else - @add-class \hidden - </script> -</mk-go-top> diff --git a/src/web/app/desktop/tags/home-widgets/calendar.tag b/src/web/app/desktop/tags/home-widgets/calendar.tag index 3d62dc60c5..9aa4ac6326 100644 --- a/src/web/app/desktop/tags/home-widgets/calendar.tag +++ b/src/web/app/desktop/tags/home-widgets/calendar.tag @@ -106,43 +106,45 @@ </style> <script> - @draw = ~> - now = new Date! - nd = now.get-date! - nm = now.get-month! - ny = now.get-full-year! + this.draw = () => { + const now = new Date(); + const nd = now.getDate(); + const nm = now.getMonth(); + const ny = now.getFullYear(); - @year = ny - @month = nm + 1 - @day = nd - @week-day = [\日 \月 \火 \水 \木 \金 \土][now.get-day!] + this.year = ny; + this.month = nm + 1; + this.day = nd; + this.weekDay = ['日', '月', '火', '水', '木', '金', '土'][now.getDay()]; - @day-numer = (now - (new Date ny, nm, nd)) - @day-denom = 1000ms * 60s * 60m * 24h - @month-numer = (now - (new Date ny, nm, 1)) - @month-denom = (new Date ny, nm + 1, 1) - (new Date ny, nm, 1) - @year-numer = (now - (new Date ny, 0, 1)) - @year-denom = (new Date ny + 1, 0, 1) - (new Date ny, 0, 1) + this.dayNumer = now - new Date(ny, nm, nd); + this.dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/; + this.monthNumer = now - new Date(ny, nm, 1); + this.monthDenom = new Date(ny, nm + 1, 1) - new Date(ny, nm, 1); + this.yearNumer = now - new Date(ny, 0, 1); + this.yearDenom = new Date(ny + 1, 0, 1) - new Date(ny, 0, 1); - @day-p = @day-numer / @day-denom * 100 - @month-p = @month-numer / @month-denom * 100 - @year-p = @year-numer / @year-denom * 100 + this.dayP = this.dayNumer / this.dayDenom * 100; + this.monthP = this.monthNumer / this.monthDenom * 100; + this.yearP = this.yearNumer / this.yearDenom * 100; - @is-holiday = - (now.get-day! == 0 or now.get-day! == 6) + this.isHoliday = now.getDay() == 0 || now.getDay() == 6; - @special = - | nm == 0 and nd == 1 => \on-new-years-day - | _ => false + this.special = + nm == 0 && nd == 1 ? 'on-new-years-day' : + false; - @update! + this.update(); + }; - @draw! + this.draw(); - @on \mount ~> - @clock = set-interval @draw, 1000ms + this.on('mount', () => { + this.clock = setInterval(this.draw, 1000); + }); - @on \unmount ~> - clear-interval @clock + this.on('unmount', () => { + clearInterval(this.clock); + }); </script> </mk-calendar-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/donation.tag b/src/web/app/desktop/tags/home-widgets/donation.tag index 047ea5011d..57c86a8751 100644 --- a/src/web/app/desktop/tags/home-widgets/donation.tag +++ b/src/web/app/desktop/tags/home-widgets/donation.tag @@ -32,5 +32,5 @@ color #999 </style> - <script>@mixin \user-preview</script> + <script>this.mixin('user-preview');</script> </mk-donation-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/mentions.tag b/src/web/app/desktop/tags/home-widgets/mentions.tag index d683b0817b..6e6d891cbf 100644 --- a/src/web/app/desktop/tags/home-widgets/mentions.tag +++ b/src/web/app/desktop/tags/home-widgets/mentions.tag @@ -46,67 +46,73 @@ </style> <script> - @mixin \i - @mixin \api + this.mixin('i'); + this.mixin('api'); - @is-loading = true - @is-empty = false - @more-loading = false - @mode = \all + this.isLoading = true; + this.isEmpty = false; + this.moreLoading = false; + this.mode = 'all'; - @on \mount ~> - document.add-event-listener \keydown @on-document-keydown - window.add-event-listener \scroll @on-scroll + this.on('mount', () => { + document.addEventListener('keydown', this.onDocumentKeydown); + window.addEventListener('scroll', this.onScroll); - @fetch ~> - @trigger \loaded + this.fetch(() => this.trigger('loaded')); + }); - @on \unmount ~> - document.remove-event-listener \keydown @on-document-keydown - window.remove-event-listener \scroll @on-scroll + this.on('unmount', () => { + document.removeEventListener('keydown', this.onDocumentKeydown); + window.removeEventListener('scroll', this.onScroll); + }); - @on-document-keydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 84 # t - @refs.timeline.focus! + this.onDocumentKeydown = e => { + if (e.target.tagName != 'INPUT' && tag != 'TEXTAREA') { + if (e.which == 84) { // t + this.refs.timeline.focus(); + } + } + }; - @fetch = (cb) ~> - @api \posts/mentions do - following: @mode == \following - .then (posts) ~> - @is-loading = false - @is-empty = posts.length == 0 - @update! - @refs.timeline.set-posts posts - if cb? then cb! - .catch (err) ~> - console.error err - if cb? then cb! + this.fetch = cb => { + this.api('posts/mentions', { + following: this.mode == 'following' + }).then(posts => { + this.update({ + isLoading: false, + isEmpty: posts.length == 0 + }); + this.refs.timeline.setPosts(posts); + if (cb) cb(); + }); + }; - @more = ~> - if @more-loading or @is-loading or @refs.timeline.posts.length == 0 - return - @more-loading = true - @update! - @api \posts/mentions do - following: @mode == \following - max_id: @refs.timeline.tail!.id - .then (posts) ~> - @more-loading = false - @update! - @refs.timeline.prepend-posts posts - .catch (err) ~> - console.error err + this.more = () => { + if (this.moreLoading || this.isLoading || this.refs.timeline.posts.length == 0) return; + this.update({ + moreLoading: true + }); + this.api('posts/mentions', { + following: this.mode == 'following', + max_id: this.refs.timeline.tail().id + }).then(posts => { + this.update({ + moreLoading: false + }); + this.refs.timeline.prependPosts(posts); + }); + }; - @on-scroll = ~> - current = window.scroll-y + window.inner-height - if current > document.body.offset-height - 8 - @more! + this.onScroll = () => { + const current = window.scrollY + window.innerHeight; + if (current > document.body.offsetHeight - 8) this.more(); + }; - @set-mode = (mode) ~> - @update do + this.setMode = mode => { + this.update({ mode: mode - @fetch! + }); + this.fetch(); + }; </script> </mk-mentions-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/nav.tag b/src/web/app/desktop/tags/home-widgets/nav.tag index a792299a53..67affc75f9 100644 --- a/src/web/app/desktop/tags/home-widgets/nav.tag +++ b/src/web/app/desktop/tags/home-widgets/nav.tag @@ -13,9 +13,5 @@ i color #ccc - - - - </style> </mk-nav-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/notifications.tag b/src/web/app/desktop/tags/home-widgets/notifications.tag index b09ae976eb..5d71407b45 100644 --- a/src/web/app/desktop/tags/home-widgets/notifications.tag +++ b/src/web/app/desktop/tags/home-widgets/notifications.tag @@ -43,8 +43,9 @@ </style> <script> - @settings = ~> - w = riot.mount document.body.append-child document.create-element \mk-settings-window .0 - w.switch \notification + this.settings = () => { + const w = riot.mount(document.body.appendChild(document.createElement('mk-settings-window')))[0]; + w.switch('notification'); + }; </script> </mk-notifications-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/photo-stream.tag b/src/web/app/desktop/tags/home-widgets/photo-stream.tag index 6ce0fd33f7..7cbb07b4de 100644 --- a/src/web/app/desktop/tags/home-widgets/photo-stream.tag +++ b/src/web/app/desktop/tags/home-widgets/photo-stream.tag @@ -57,31 +57,36 @@ </style> <script> - @mixin \api - @mixin \stream + this.mixin('api'); + this.mixin('stream'); - @images = [] - @initializing = true + this.images = []; + this.initializing = true; - @on \mount ~> - @stream.on \drive_file_created @on-stream-drive-file-created + this.on('mount', () => { + this.stream.on('drive_file_created', this.onStreamDriveFileCreated); - @api \drive/stream do - type: 'image/*' - limit: 9images - .then (images) ~> - @initializing = false - @images = images - @update! + this.api('drive/stream', { + type: 'image/*', + limit: 9 + }).then(images => { + this.update({ + initializing: false, + images: images + }); + }); + }); - @on \unmount ~> - @stream.off \drive_file_created @on-stream-drive-file-created + this.on('unmount', () => { + this.stream.off('drive_file_created', this.onStreamDriveFileCreated); + }); - @on-stream-drive-file-created = (file) ~> - if /^image\/.+$/.test file.type - @images.unshift file - if @images.length > 9 - @images.pop! - @update! + this.onStreamDriveFileCreated = file => { + if (/^image\/.+$/.test(file.type)) { + this.images.unshift(file); + if (this.images.length > 9) this.images.pop(); + this.update(); + } + }; </script> </mk-photo-stream-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/profile.tag b/src/web/app/desktop/tags/home-widgets/profile.tag index 9f11072b7a..8ee2186149 100644 --- a/src/web/app/desktop/tags/home-widgets/profile.tag +++ b/src/web/app/desktop/tags/home-widgets/profile.tag @@ -41,15 +41,17 @@ </style> <script> - @mixin \i - @mixin \user-preview - @mixin \update-avatar - @mixin \update-banner + this.mixin('i'); + this.mixin('user-preview'); + this.mixin('update-avatar'); + this.mixin('update-banner'); - @set-avatar = ~> - @update-avatar @I + this.setAvatar = () => { + this.updateAvatar(this.I); + }; - @set-banner = ~> - @update-banner @I + this.setBanner = () => { + this.updateBanner(this.I); + }; </script> </mk-profile-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/rss-reader.tag b/src/web/app/desktop/tags/home-widgets/rss-reader.tag index 0efd5cbecc..c8700a8b63 100644 --- a/src/web/app/desktop/tags/home-widgets/rss-reader.tag +++ b/src/web/app/desktop/tags/home-widgets/rss-reader.tag @@ -64,31 +64,35 @@ </style> <script> - @mixin \api - @mixin \NotImplementedException + this.mixin('api'); + this.mixin('NotImplementedException'); - @url = 'http://news.yahoo.co.jp/pickup/rss.xml' - @items = [] - @initializing = true + this.url = 'http://news.yahoo.co.jp/pickup/rss.xml'; + this.items = []; + this.initializing = true; - @on \mount ~> - @fetch! - @clock = set-interval @fetch, 60000ms + this.on('mount', () => { + this.fetch(); + this.clock = setInterval(this.fetch, 60000); + }); - @on \unmount ~> - clear-interval @clock + this.on('unmount', () => { + clearInterval(this.clock); + }); - @fetch = ~> - @api CONFIG.url + '/api:rss' do - url: @url - .then (feed) ~> - @items = feed.rss.channel.item - @initializing = false - @update! - .catch (err) -> - console.error err + this.fetch = () => { + this.api(CONFIG.url + '/api:rss', { + url: this.url + }).then(feed => { + this.update({ + initializing: false, + items: feed.rss.channel.item + }); + }); + }; - @settings = ~> - @NotImplementedException! + this.settings = () => { + this.NotImplementedException(); + }; </script> </mk-rss-reader-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/timeline.tag b/src/web/app/desktop/tags/home-widgets/timeline.tag index 9f5bb3890e..a0a8790eaa 100644 --- a/src/web/app/desktop/tags/home-widgets/timeline.tag +++ b/src/web/app/desktop/tags/home-widgets/timeline.tag @@ -32,80 +32,87 @@ </style> <script> - @mixin \i - @mixin \api - @mixin \stream + this.mixin('i'); + this.mixin('api'); + this.mixin('stream'); - @is-loading = true - @is-empty = false - @more-loading = false - @no-following = @I.following_count == 0 + this.isLoading = true; + this.isEmpty = false; + this.moreLoading = false; + this.noFollowing = this.I.following_count == 0; - @on \mount ~> - @stream.on \post @on-stream-post - @stream.on \follow @on-stream-follow - @stream.on \unfollow @on-stream-unfollow + this.on('mount', () => { + this.stream.on('post', this.onStreamPost); + this.stream.on('follow', this.onStreamFollow); + this.stream.on('unfollow', this.onStreamUnfollow); - document.add-event-listener \keydown @on-document-keydown - window.add-event-listener \scroll @on-scroll + document.addEventListener('keydown', this.onDocumentKeydown); + window.addEventListener('scroll', this.onScroll); - @load ~> - @trigger \loaded + this.load(() => this.trigger('loaded')); + }); - @on \unmount ~> - @stream.off \post @on-stream-post - @stream.off \follow @on-stream-follow - @stream.off \unfollow @on-stream-unfollow + this.on('unmount', () => { + this.stream.off('post', this.onStreamPost); + this.stream.off('follow', this.onStreamFollow); + this.stream.off('unfollow', this.onStreamUnfollow); - document.remove-event-listener \keydown @on-document-keydown - window.remove-event-listener \scroll @on-scroll + document.removeEventListener('keydown', this.onDocumentKeydown); + window.removeEventListener('scroll', this.onScroll); + }); - @on-document-keydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 84 # t - @refs.timeline.focus! + this.onDocumentKeydown = e => { + if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') { + if (e.which == 84) { // t + this.refs.timeline.focus(); + } + } + }; - @load = (cb) ~> - @api \posts/timeline - .then (posts) ~> - @is-loading = false - @is-empty = posts.length == 0 - @update! - @refs.timeline.set-posts posts - if cb? then cb! - .catch (err) ~> - console.error err - if cb? then cb! + this.load = (cb) => { + this.api('posts/timeline').then(posts => { + this.update({ + isLoading: false, + isEmpty: posts.length == 0 + }); + this.refs.timeline.setPosts(posts); + if (cb) cb(); + }); + }; - @more = ~> - if @more-loading or @is-loading or @refs.timeline.posts.length == 0 - return - @more-loading = true - @update! - @api \posts/timeline do - max_id: @refs.timeline.tail!.id - .then (posts) ~> - @more-loading = false - @update! - @refs.timeline.prepend-posts posts - .catch (err) ~> - console.error err + this.more = () => { + if (this.moreLoading || this.isLoading || this.refs.timeline.posts.length == 0) return; + this.update({ + moreLoading: true + }); + this.api('posts/timeline', { + max_id: this.refs.timeline.tail().id + }).then(posts => { + this.update({ + moreLoading: false + }); + this.refs.timeline.prependPosts(posts); + }); + }; - @on-stream-post = (post) ~> - @is-empty = false - @update! - @refs.timeline.add-post post + this.onStreamPost = post => { + this.update({ + isEmpty: false + }); + this.refs.timeline.addPost(post); + }; - @on-stream-follow = ~> - @load! + this.onStreamFollow = () => { + this.load(); + }; - @on-stream-unfollow = ~> - @load! + this.onStreamUnfollow = () => { + this.load(); + }; - @on-scroll = ~> - current = window.scroll-y + window.inner-height - if current > document.body.offset-height - 8 - @more! + this.onScroll = () => { + const current = window.scrollY + window.innerHeight; + if (current > document.body.offsetHeight - 8) this.more(); + }; </script> </mk-timeline-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/tips.tag b/src/web/app/desktop/tags/home-widgets/tips.tag index 2552c266d7..27268f3ed3 100644 --- a/src/web/app/desktop/tags/home-widgets/tips.tag +++ b/src/web/app/desktop/tags/home-widgets/tips.tag @@ -29,43 +29,46 @@ </style> <script> - @tips = [ - '<kbd>t</kbd>でタイムラインにフォーカスできます' - '<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます' - '投稿フォームにはファイルをドラッグ&ドロップできます' - '投稿フォームにクリップボードにある画像データをペーストできます' - 'ドライブにファイルをドラッグ&ドロップしてアップロードできます' - 'ドライブでファイルをドラッグしてフォルダ移動できます' - 'ドライブでフォルダをドラッグしてフォルダ移動できます' - 'ホームをカスタマイズできます(準備中)' + this.tips = [ + '<kbd>t</kbd>でタイムラインにフォーカスできます', + '<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます', + '投稿フォームにはファイルをドラッグ&ドロップできます', + '投稿フォームにクリップボードにある画像データをペーストできます', + 'ドライブにファイルをドラッグ&ドロップしてアップロードできます', + 'ドライブでファイルをドラッグしてフォルダ移動できます', + 'ドライブでフォルダをドラッグしてフォルダ移動できます', + 'ホームをカスタマイズできます(準備中)', 'MisskeyはMIT Licenseです' ] - @on \mount ~> - @set! - @clock = set-interval @change, 20000ms + this.on('mount', () => { + this.set(); + this.clock = setInterval(this.change, 20000); + }); - @on \unmount ~> - clear-interval @clock + this.on('unmount', () => { + clearInterval(this.clock); + }); - @set = ~> - @refs.text.innerHTML = @tips[Math.floor Math.random! * @tips.length] - @update! + this.set = () => { + this.refs.text.innerHTML = this.tips[Math.floor(Math.random() * this.tips.length)]; + }; - @change = ~> - Velocity @refs.tip, { + this.change = () => { + Velocity(this.refs.tip, { opacity: 0 - } { - duration: 500ms - easing: \linear - complete: @set - } + }, { + duration: 500, + easing: 'linear', + complete: this.set + }); - Velocity @refs.tip, { + Velocity(this.refs.tip, { opacity: 1 - } { - duration: 500ms - easing: \linear - } + }, { + duration: 500, + easing: 'linear' + }); + }; </script> </mk-tips-home-widget> diff --git a/src/web/app/desktop/tags/home-widgets/user-recommendation.tag b/src/web/app/desktop/tags/home-widgets/user-recommendation.tag index 8e94090dc9..517d206a4d 100644 --- a/src/web/app/desktop/tags/home-widgets/user-recommendation.tag +++ b/src/web/app/desktop/tags/home-widgets/user-recommendation.tag @@ -109,44 +109,42 @@ </style> <script> - @mixin \api - @mixin \user-preview + this.mixin('api'); + this.mixin('user-preview'); - @users = null - @loading = true + this.users = null; + this.loading = true; - @limit = 3users - @page = 0 + this.limit = 3; + this.page = 0; - @on \mount ~> - @fetch! - @clock = set-interval ~> - if @users.length < @limit - @fetch true - , 60000ms + this.on('mount', () => { + this.fetch(); + }); - @on \unmount ~> - clear-interval @clock + this.fetch = () => { + this.update({ + loading: true, + users: null + }); + this.api('users/recommendation', { + limit: this.limit, + offset: this.limit * this.page + }).then(users => { + this.update({ + loading: false, + users: users + }); + }); + }; - @fetch = (quiet = false) ~> - @loading = true - @users = null - if not quiet then @update! - @api \users/recommendation do - limit: @limit - offset: @limit * @page - .then (users) ~> - @loading = false - @users = users - @update! - .catch (err, text-status) -> - console.error err - - @refresh = ~> - if @users.length < @limit - @page = 0 - else - @page++ - @fetch! + this.refresh = () => { + if (this.users.length < this.limit) { + this.page = 0; + } else { + this.page++; + } + this.fetch(); + }; </script> </mk-user-recommendation-home-widget> diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index b2ba4e2806..7a148d123c 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -58,33 +58,40 @@ </style> <script> - @mixin \i - @mode = @opts.mode || \timeline + this.mixin('i'); - # https://github.com/riot/riot/issues/2080 - if @mode == '' then @mode = \timeline + this.mode = this.opts.mode || 'timeline'; + // https://github.com/riot/riot/issues/2080 + if (this.mode == '') this.mode = 'timeline'; - @home = [] + this.home = []; - @on \mount ~> - @refs.tl.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.tl.on('loaded', () => { + this.trigger('loaded'); + }); - @I.data.home.for-each (widget) ~> - try - el = document.create-element \mk- + widget.name + \-home-widget - switch widget.place - | \left => @refs.left.append-child el - | \right => @refs.right.append-child el - @home.push (riot.mount el, do - id: widget.id + this.I.data.home.forEach(widget => { + try { + const el = document.createElement(`mk-${widget.name}-home-widget`); + switch (widget.place) { + case 'left': this.refs.left.appendChild(el); break; + case 'right': this.refs.right.appendChild(el); break; + } + this.home.push(riot.mount(el, { + id: widget.id, data: widget.data - .0) - catch e - # noop + })[0]); + } catch (e) { + // noop + } + }); + }); - @on \unmount ~> - @home.for-each (widget) ~> - widget.unmount! + this.on('unmount', () => { + this.home.forEach(widget => { + widget.unmount(); + }); + }); </script> </mk-home> diff --git a/src/web/app/desktop/tags/image-dialog.tag b/src/web/app/desktop/tags/image-dialog.tag index d7660bb953..91245dac95 100644 --- a/src/web/app/desktop/tags/image-dialog.tag +++ b/src/web/app/desktop/tags/image-dialog.tag @@ -35,41 +35,26 @@ </style> <script> - @image = @opts.image + this.image = this.opts.image; - @on \mount ~> - Velocity @root, { + this.on('mount', () => { + Velocity(this.root, { opacity: 1 - } { - duration: 100ms - easing: \linear - } + }, { + duration: 100, + easing: 'linear' + }); + }); - #Velocity @img, { - # scale: 1 - # opacity: 1 - #} { - # duration: 200ms - # easing: \ease-out - #} - - @close = ~> - Velocity @root, { + this.close = () => { + Velocity(this.root, { opacity: 0 - } { - duration: 100ms - easing: \linear - complete: ~> @unmount! - } + }, { + duration: 100, + easing: 'linear', + complete: () => this.unmount() + }); + }; - #Velocity @img, { - # scale: 0.9 - # opacity: 0 - #} { - # duration: 200ms - # easing: \ease-in - # complete: ~> - # @unmount! - #} </script> </mk-image-dialog> diff --git a/src/web/app/desktop/tags/images-viewer.tag b/src/web/app/desktop/tags/images-viewer.tag index 017395e7b4..83bce7bf4e 100644 --- a/src/web/app/desktop/tags/images-viewer.tag +++ b/src/web/app/desktop/tags/images-viewer.tag @@ -26,20 +26,22 @@ </style> <script> - @images = @opts.images - @image = @images.0 + this.images = this.opts.images; + this.image = this.images[0]; - @mousemove = (e) ~> - rect = @refs.view.get-bounding-client-rect! - mouse-x = e.client-x - rect.left - mouse-y = e.client-y - rect.top - xp = mouse-x / @refs.view.offset-width * 100 - yp = mouse-y / @refs.view.offset-height * 100 - @refs.view.style.background-position = xp + '% ' + yp + '%' + this.mousemove = e => { + const rect = this.refs.view.getBoundingClientRect(); + const mouseX = e.clientX - rect.left; + const mouseY = e.clientY - rect.top; + const xp = mouseX / this.refs.view.offsetWidth * 100; + const yp = mouseY / this.refs.view.offsetHeight * 100; + this.refs.view.style.backgroundPosition = xp + '% ' + yp + '%'; + }; - @click = ~> - dialog = document.body.append-child document.create-element \mk-image-dialog - riot.mount dialog, do - image: @image + this.click = () => { + riot.mount(document.body.appendChild(document.createElement('mk-image-dialog')), { + image: this.image + }); + }; </script> </mk-images-viewer> diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index ed100ef75c..6bbb774ee7 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -16,7 +16,6 @@ require('./crop-window.tag'); require('./settings.tag'); require('./settings-window.tag'); require('./analog-clock.tag'); -require('./go-top.tag'); require('./ui-header.tag'); require('./ui-header-account.tag'); require('./ui-header-notifications.tag'); @@ -42,7 +41,6 @@ require('./home-widgets/notifications.tag'); require('./home-widgets/rss-reader.tag'); require('./home-widgets/photo-stream.tag'); require('./home-widgets/broadcast.tag'); -require('./stream-indicator.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); diff --git a/src/web/app/desktop/tags/input-dialog.tag b/src/web/app/desktop/tags/input-dialog.tag index d9f4ae3f41..f343c4625a 100644 --- a/src/web/app/desktop/tags/input-dialog.tag +++ b/src/web/app/desktop/tags/input-dialog.tag @@ -1,13 +1,17 @@ <mk-input-dialog> - <mk-window ref="window" is-modal={ true } width={ '500px' }><yield to="header"><i class="fa fa-i-cursor"></i>{ parent.title }</yield> -<yield to="content"> - <div class="body"> - <input ref="text" oninput={ parent.update } onkeydown={ parent.onKeydown } placeholder={ parent.placeholder }/> - </div> - <div class="action"> - <button class="cancel" onclick={ parent.cancel }>キャンセル</button> - <button class="ok" disabled={ !parent.allowEmpty && refs.text.value.length == 0 } onclick={ parent.ok }>決定</button> - </div></yield> + <mk-window ref="window" is-modal={ true } width={ '500px' }> + <yield to="header"> + <i class="fa fa-i-cursor"></i>{ parent.title } + </yield> + <yield to="content"> + <div class="body"> + <input ref="text" oninput={ parent.update } onkeydown={ parent.onKeydown } placeholder={ parent.placeholder }/> + </div> + <div class="action"> + <button class="cancel" onclick={ parent.cancel }>キャンセル</button> + <button class="ok" disabled={ !parent.allowEmpty && refs.text.value.length == 0 } onclick={ parent.ok }>決定</button> + </div> + </yield> </mk-window> <style> :scope @@ -116,42 +120,48 @@ </style> <script> - @done = false + this.done = false; - @title = @opts.title - @placeholder = @opts.placeholder - @default = @opts.default - @allow-empty = if @opts.allow-empty? then @opts.allow-empty else true + this.title = this.opts.title; + this.placeholder = this.opts.placeholder; + this.default = this.opts.default; + this.allowEmpty = this.opts.allowEmpty != null ? this.opts.allowEmpty : true; - @on \mount ~> - @text = @refs.window.refs.text - if @default? - @text.value = @default - @text.focus! + this.on('mount', () => { + this.text = this.refs.window.refs.text; + if (this.default) this.text.value = this.default; + this.text.focus(); - @refs.window.on \closing ~> - if @done - @opts.on-ok @text.value - else - if @opts.on-cancel? - @opts.on-cancel! + this.refs.window.on('closing', () => { + if (this.done) { + this.opts.onOk(this.text.value); + } else { + if (this.opts.onCancel) this.opts.onCancel(); + } + }); - @refs.window.on \closed ~> - @unmount! + this.refs.window.on('closed', () => { + this.unmount(); + }); + }); - @cancel = ~> - @done = false - @refs.window.close! + this.cancel = () => { + this.done = false; + this.refs.window.close(); + }; - @ok = ~> - if not @allow-empty and @text.value == '' then return - @done = true - @refs.window.close! + this.ok = () => { + if (!this.allowEmpty && this.text.value == '') return; + this.done = true; + this.refs.window.close(); + }; - @on-keydown = (e) ~> - if e.which == 13 # Enter - e.prevent-default! - e.stop-propagation! - @ok! + this.onKeydown = e => { + if (e.which == 13) { // Enter + e.preventDefault(); + e.stopPropagation(); + this.ok(); + } + }; </script> </mk-input-dialog> diff --git a/src/web/app/desktop/tags/list-user.tag b/src/web/app/desktop/tags/list-user.tag index 03dda494aa..133efd2d1e 100644 --- a/src/web/app/desktop/tags/list-user.tag +++ b/src/web/app/desktop/tags/list-user.tag @@ -93,5 +93,5 @@ right 16px </style> - <script>@user = @opts.user</script> + <script>this.user = this.opts.user</script> </mk-list-user> diff --git a/src/web/app/desktop/tags/messaging/room-window.tag b/src/web/app/desktop/tags/messaging/room-window.tag index a7eddb591e..e8a9ed6acd 100644 --- a/src/web/app/desktop/tags/messaging/room-window.tag +++ b/src/web/app/desktop/tags/messaging/room-window.tag @@ -19,10 +19,12 @@ </style> <script> - @user = @opts.user + this.user = this.opts.user; - @on \mount ~> - @refs.window.on \closed ~> - @unmount! + this.on('mount', () => { + this.refs.window.on('closed', () => { + this.unmount(); + }); + }); </script> </mk-messaging-room-window> diff --git a/src/web/app/desktop/tags/messaging/window.tag b/src/web/app/desktop/tags/messaging/window.tag index f81fd6681b..c7af1dc2a2 100644 --- a/src/web/app/desktop/tags/messaging/window.tag +++ b/src/web/app/desktop/tags/messaging/window.tag @@ -19,13 +19,16 @@ </style> <script> - @on \mount ~> - @refs.window.on \closed ~> - @unmount! + this.on('mount', () => { + this.refs.window.on('closed', () => { + this.unmount(); + }); - @refs.window.refs.index.on \navigate-user (user) ~> - w = document.body.append-child document.create-element \mk-messaging-room-window - riot.mount w, do + this.refs.window.refs.index.on('navigate-user', user => { + riot.mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { user: user + }); + }); + }); </script> </mk-messaging-window> diff --git a/src/web/app/desktop/tags/notifications.tag b/src/web/app/desktop/tags/notifications.tag index 58851786b6..7ba74412ea 100644 --- a/src/web/app/desktop/tags/notifications.tag +++ b/src/web/app/desktop/tags/notifications.tag @@ -177,37 +177,41 @@ </style> <script> - @mixin \api - @mixin \stream - @mixin \user-preview - @mixin \get-post-summary + this.mixin('api'); + this.mixin('stream'); + this.mixin('user-preview'); + this.mixin('get-post-summary'); - @notifications = [] - @loading = true + this.notifications = []; + this.loading = true; - @on \mount ~> - @api \i/notifications - .then (notifications) ~> - @notifications = notifications - @loading = false - @update! - .catch (err, text-status) -> - console.error err + this.on('mount', () => { + this.api('i/notifications').then(notifications => { + this.update({ + loading: false, + notifications: notifications + }); + }); - @stream.on \notification @on-notification + this.stream.on('notification', this.onNotification); + }); - @on \unmount ~> - @stream.off \notification @on-notification + this.on('unmount', () => { + this.stream.off('notification', this.onNotification); + }); - @on-notification = (notification) ~> - @notifications.unshift notification - @update! + this.onNotification = notification => { + this.notifications.unshift(notification); + this.update(); + }; - @on \update ~> - @notifications.for-each (notification) ~> - date = (new Date notification.created_at).get-date! - month = (new Date notification.created_at).get-month! + 1 - notification._date = date - notification._datetext = month + '月 ' + date + '日' + this.on('update', () => { + this.notifications.forEach(notification => { + const date = new Date(notification.created_at).getDate(); + const month = new Date(notification.created_at).getMonth() + 1; + notification._date = date; + notification._datetext = `${month}月 ${date}日`; + }); + }); </script> </mk-notifications> diff --git a/src/web/app/desktop/tags/pages/entrance.tag b/src/web/app/desktop/tags/pages/entrance.tag index 57d11217cc..82ac8539ca 100644 --- a/src/web/app/desktop/tags/pages/entrance.tag +++ b/src/web/app/desktop/tags/pages/entrance.tag @@ -63,18 +63,24 @@ </style> <script> - @mode = \signin + this.mode = 'signin'; - @signup = ~> - @mode = \signup - @update! + this.signup = () => { + this.update({ + mode: 'signup' + }); + }; - @signin = ~> - @mode = \signin - @update! + this.signin = () => { + this.update({ + mode: 'signin' + }); + }; - @introduction = ~> - @mode = \introduction - @update! + this.introduction = () => { + this.update({ + mode: 'introduction' + }); + }; </script> </mk-entrance> diff --git a/src/web/app/desktop/tags/pages/entrance/signin.tag b/src/web/app/desktop/tags/pages/entrance/signin.tag index 1a5baac67e..bd4b47c7df 100644 --- a/src/web/app/desktop/tags/pages/entrance/signin.tag +++ b/src/web/app/desktop/tags/pages/entrance/signin.tag @@ -119,12 +119,16 @@ </style> <script> - @on \mount ~> - @refs.signin.on \user (user) ~> - @update do + this.on('mount', () => { + this.refs.signin.on('user', user => { + this.update({ user: user + }); + }); + }); - @introduction = ~> - @parent.introduction! + this.introduction = () => { + this.parent.introduction(); + }; </script> </mk-entrance-signin> diff --git a/src/web/app/desktop/tags/pages/entrance/signup.tag b/src/web/app/desktop/tags/pages/entrance/signup.tag index 1a777fe965..7ab53759c9 100644 --- a/src/web/app/desktop/tags/pages/entrance/signup.tag +++ b/src/web/app/desktop/tags/pages/entrance/signup.tag @@ -43,9 +43,5 @@ > i padding 14px - - - - </style> </mk-entrance-signup> diff --git a/src/web/app/desktop/tags/pages/home.tag b/src/web/app/desktop/tags/pages/home.tag index 51e5767704..e988cbc76e 100644 --- a/src/web/app/desktop/tags/pages/home.tag +++ b/src/web/app/desktop/tags/pages/home.tag @@ -5,43 +5,45 @@ <style> :scope display block - </style> <script> - @mixin \i - @mixin \api - @mixin \ui-progress - @mixin \stream - @mixin \get-post-summary - - @unread-count = 0 + this.mixin('i'); + this.mixin('api'); + this.mixin('ui-progress'); + this.mixin('stream'); + this.mixin('get-post-summary'); - @page = switch @opts.mode - | \timelie => \home - | \mentions => \mentions - | _ => \home + this.unreadCount = 0; - @on \mount ~> - @refs.ui.refs.home.on \loaded ~> - @Progress.done! + this.page = this.opts.mode || 'timeline'; - document.title = 'Misskey' - @Progress.start! - @stream.on \post @on-stream-post - document.add-event-listener \visibilitychange @window-on-visibilitychange, false + this.on('mount', () => { + this.refs.ui.refs.home.on('loaded', () => { + this.Progress.done(); + }); + document.title = 'Misskey'; + this.Progress.start(); + this.stream.on('post', this.onStreamPost); + document.addEventListener('visibilitychange', this.windowOnVisibilitychange, false); + }); - @on \unmount ~> - @stream.off \post @on-stream-post - document.remove-event-listener \visibilitychange @window-on-visibilitychange + this.on('unmount', () => { + this.stream.off('post', this.onStreamPost); + document.removeEventListener('visibilitychange', this.windowOnVisibilitychange); + }); - @on-stream-post = (post) ~> - if document.hidden and post.user_id !== @I.id - @unread-count++ - document.title = '(' + @unread-count + ') ' + @get-post-summary post + this.onStreamPost = post => { + if (document.hidden && post.user_id != this.I.id) { + this.unreadCount++; + document.title = `(${this.unreadCount}) ${this.getPostSummary(post)}`; + } + }; - @window-on-visibilitychange = ~> - if !document.hidden - @unread-count = 0 - document.title = 'Misskey' + this.windowOnVisibilitychange = () => { + if (!document.hidden) { + this.unreadCount = 0; + document.title = 'Misskey'; + } + }; </script> </mk-home-page> diff --git a/src/web/app/desktop/tags/pages/not-found.tag b/src/web/app/desktop/tags/pages/not-found.tag index a7cbad0b82..e62ea11008 100644 --- a/src/web/app/desktop/tags/pages/not-found.tag +++ b/src/web/app/desktop/tags/pages/not-found.tag @@ -1,54 +1,11 @@ <mk-not-found> <mk-ui> <main> - <h1>Not Found</h1><img src="/_/resources/rogge.jpg" alt=""/> - <div class="mask"></div> + <h1>Not Found</h1> </main> </mk-ui> <style> :scope display block - - main - display block - width 600px - margin 32px auto - - > img - display block - width 600px - height 459px - pointer-events none - user-select none - border-radius 16px - box-shadow 0 0 16px rgba(0, 0, 0, 0.1) - - > h1 - display block - margin 0 - padding 0 - position absolute - top 260px - left 225px - transform rotate(-12deg) - z-index 2 - color #444 - font-size 24px - line-height 20px - - > .mask - position absolute - top 262px - left 217px - width 126px - height 18px - transform rotate(-12deg) - background #D6D5DA - border-radius 2px 6px 7px 6px - - - - - </style> </mk-not-found> diff --git a/src/web/app/desktop/tags/pages/post.tag b/src/web/app/desktop/tags/pages/post.tag index fddc21deab..b04ba69dc5 100644 --- a/src/web/app/desktop/tags/pages/post.tag +++ b/src/web/app/desktop/tags/pages/post.tag @@ -16,17 +16,20 @@ </style> <script> - @mixin \ui-progress + this.mixin('ui-progress'); - @post = @opts.post + this.post = this.opts.post; - @on \mount ~> - @Progress.start! + this.on('mount', () => { + this.Progress.start(); - @refs.ui.refs.detail.on \post-fetched ~> - @Progress.set 0.5 + this.refs.ui.refs.detail.on('post-fetched', () => { + this.Progress.set(0.5); + }); - @refs.ui.refs.detail.on \loaded ~> - @Progress.done! + this.refs.ui.refs.detail.on('loaded', () => { + this.Progress.done(); + }); + }); </script> </mk-post-page> diff --git a/src/web/app/desktop/tags/pages/search.tag b/src/web/app/desktop/tags/pages/search.tag index 0c5a23c795..ace9e27ab9 100644 --- a/src/web/app/desktop/tags/pages/search.tag +++ b/src/web/app/desktop/tags/pages/search.tag @@ -5,15 +5,16 @@ <style> :scope display block - </style> <script> - @mixin \ui-progress + this.mixin('ui-progress'); - @on \mount ~> - @Progress.start! + this.on('mount', () => { + this.Progress.start(); - @refs.ui.refs.search.on \loaded ~> - @Progress.done! + this.refs.ui.refs.search.on('loaded', () => { + this.Progress.done(); + }); + }); </script> </mk-search-page> diff --git a/src/web/app/desktop/tags/pages/user.tag b/src/web/app/desktop/tags/pages/user.tag index be0501e045..767af31e9a 100644 --- a/src/web/app/desktop/tags/pages/user.tag +++ b/src/web/app/desktop/tags/pages/user.tag @@ -5,21 +5,23 @@ <style> :scope display block - </style> <script> - @mixin \ui-progress + this.mixin('ui-progress'); - @user = @opts.user + this.user = this.opts.user; - @on \mount ~> - @Progress.start! + this.on('mount', () => { + this.Progress.start(); - @refs.ui.refs.user.on \user-fetched (user) ~> - @Progress.set 0.5 + this.refs.ui.refs.user.on('user-fetched', user => { + this.Progress.set(0.5); document.title = user.name + ' | Misskey' + }); - @refs.ui.refs.user.on \loaded ~> - @Progress.done! + this.refs.ui.refs.user.on('loaded', () => { + this.Progress.done(); + }); + }); </script> </mk-user-page> diff --git a/src/web/app/desktop/tags/post-detail-sub.tag b/src/web/app/desktop/tags/post-detail-sub.tag index c4a651e371..f1b3c915cb 100644 --- a/src/web/app/desktop/tags/post-detail-sub.tag +++ b/src/web/app/desktop/tags/post-detail-sub.tag @@ -103,38 +103,45 @@ </style> <script> - @mixin \api - @mixin \text - @mixin \date-stringify - @mixin \user-preview + this.mixin('api'); + this.mixin('text'); + this.mixin('date-stringify'); + this.mixin('user-preview'); - @post = @opts.post + this.post = this.opts.post; - @url = CONFIG.url + '/' + @post.user.username + '/' + @post.id + this.url = CONFIG.url + '/' + this.post.user.username + '/' + this.post.id; - @title = @date-stringify @post.created_at + this.title = this.dateStringify(this.post.created_at); - @on \mount ~> - if @post.text? - tokens = @analyze @post.text - @refs.text.innerHTML = @compile tokens + this.on('mount', () => { + if (this.p.text) { + const tokens = this.analyze(this.p.text); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + this.refs.text.innerHTML = this.refs.text.innerHTML.replace('<p class="dummy"></p>', this.compile(tokens)); - @like = ~> - if @post.is_liked - @api \posts/likes/delete do - post_id: @post.id - .then ~> - @post.is_liked = false - @update! - else - @api \posts/likes/create do - post_id: @post.id - .then ~> - @post.is_liked = true - @update! + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); + } + }); + + this.like = () => { + if (this.post.is_liked) { + this.api('posts/likes/delete', { + post_id: this.post.id + }).then(() => { + this.post.is_liked = false; + this.update(); + }); + } else { + this.api('posts/likes/create', { + post_id: this.post.id + }).then(() => { + this.post.is_liked = true; + this.update(); + }); + } + }; </script> </mk-post-detail-sub> diff --git a/src/web/app/desktop/tags/post-detail.tag b/src/web/app/desktop/tags/post-detail.tag index 3c99babaaa..cc5fbeed88 100644 --- a/src/web/app/desktop/tags/post-detail.tag +++ b/src/web/app/desktop/tags/post-detail.tag @@ -329,108 +329,126 @@ </style> <script> - @mixin \api - @mixin \text - @mixin \user-preview - @mixin \date-stringify - @mixin \NotImplementedException + this.mixin('api'); + this.mixin('text'); + this.mixin('user-preview'); + this.mixin('date-stringify'); + this.mixin('NotImplementedException'); - @fetching = true - @loading-context = false - @content = null - @post = null + this.fetching = true; + this.loadingContext = false; + this.content = null; + this.post = null; - @on \mount ~> + this.on('mount', () => { + this.api('posts/show', { + post_id: this.opts.post + }).then(post => { + const isRepost = post.repost != null; + const p = isRepost ? post.repost : post; + this.update({ + fetching: false, + post: post, + isRepost: isRepost, + p: p, + title: this.dateStringify(p.created_at) + }); - @api \posts/show do - post_id: @opts.post - .then (post) ~> - @fetching = false - @post = post - @trigger \loaded + this.trigger('loaded'); - @is-repost = @post.repost? - @p = if @is-repost then @post.repost else @post + if (this.p.text) { + const tokens = this.analyze(this.p.text); - @title = @date-stringify @p.created_at + this.refs.text.innerHTML = this.compile(tokens); - @update! + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); - if @p.text? - tokens = @analyze @p.text - @refs.text.innerHTML = @compile tokens - - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e - - # URLをプレビュー + // URLをプレビュー tokens - .filter (t) -> t.type == \link - .map (t) ~> - @preview = @refs.text.append-child document.create-element \mk-url-preview - riot.mount @preview, do - url: t.content + .filter(t => t.type == 'link') + .map(t => { + riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), { + url: t.content + }); + }); + } - # Get likes - @api \posts/likes do - post_id: @p.id + // Get likes + this.api('posts/likes', { + post_id: this.p.id, limit: 8 - .then (likes) ~> - @likes = likes - @update! + }).then(likes => { + this.update({ + likes: likes + }); + }); - # Get reposts - @api \posts/reposts do - post_id: @p.id + // Get reposts + this.api('posts/reposts', { + post_id: this.p.id, limit: 8 - .then (reposts) ~> - @reposts = reposts - @update! + }).then(reposts => { + this.update({ + reposts: reposts + }); + }); - # Get replies - @api \posts/replies do - post_id: @p.id + // Get replies + this.api('posts/replies', { + post_id: this.p.id, limit: 8 - .then (replies) ~> - @replies = replies - @update! - - @update! + }).then(replies => { + this.update({ + replies: replies + }); + }); + }); + }); - @reply = ~> - form = document.body.append-child document.create-element \mk-post-form-window - riot.mount form, do - reply: @p + this.reply = () => { + riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), { + reply: this.p + }); + }; - @repost = ~> - form = document.body.append-child document.create-element \mk-repost-form-window - riot.mount form, do - post: @p + this.repost = () => { + riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), { + post: this.p + }); + }; - @like = ~> - if @p.is_liked - @api \posts/likes/delete do - post_id: @p.id - .then ~> - @p.is_liked = false - @update! - else - @api \posts/likes/create do - post_id: @p.id - .then ~> - @p.is_liked = true - @update! + this.like = () => { + if (this.p.is_liked) { + this.api('posts/likes/delete', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = false; + this.update(); + }); + } else { + this.api('posts/likes/create', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = true; + this.update(); + }); + } + }; - @load-context = ~> - @loading-context = true + this.loadContext = () => { + this.loadingContext = true; - # Get context - @api \posts/context do - post_id: @p.reply_to_id - .then (context) ~> - @context = context.reverse! - @loading-context = false - @update! + // Fetch context + this.api('posts/context', { + post_id: this.p.reply_to_id + }).then(context => { + this.update({ + loadContext: false, + content: context.reverse() + }); + }); + }; </script> </mk-post-detail> diff --git a/src/web/app/desktop/tags/post-form-window.tag b/src/web/app/desktop/tags/post-form-window.tag index fc1a254e20..4f2ea25389 100644 --- a/src/web/app/desktop/tags/post-form-window.tag +++ b/src/web/app/desktop/tags/post-form-window.tag @@ -32,24 +32,31 @@ </style> <script> - @uploading-files = [] - @files = [] + this.uploadingFiles = []; + this.files = []; - @on \mount ~> - @refs.window.refs.form.focus! + this.on('mount', () => { + this.refs.window.refs.form.focus(); - @refs.window.on \closed ~> - @unmount! + this.refs.window.on('closed', () => { + this.unmount(); + }); - @refs.window.refs.form.on \post ~> - @refs.window.close! + this.refs.window.refs.form.on('post', () => { + this.refs.window.close(); + }); - @refs.window.refs.form.on \change-uploading-files (files) ~> - @uploading-files = files - @update! + this.refs.window.refs.form.on('change-uploading-files', files => { + this.update({ + uploadingFiles: files + }); + }); - @refs.window.refs.form.on \change-files (files) ~> - @files = files - @update! + this.refs.window.refs.form.on('change-files', files => { + this.update({ + files: files + }); + }); + }); </script> </mk-post-form-window> diff --git a/src/web/app/desktop/tags/post-form.tag b/src/web/app/desktop/tags/post-form.tag index a0b6ea7d07..3b80eee5d5 100644 --- a/src/web/app/desktop/tags/post-form.tag +++ b/src/web/app/desktop/tags/post-form.tag @@ -305,161 +305,160 @@ </style> <script> - get-cat = require '../../common/scripts/get-cat' + const getCat = require('../../common/scripts/get-cat'); - @mixin \api - @mixin \notify - @mixin \autocomplete + this.mixin('api'); + this.mixin('notify'); + this.mixin('autocomplete'); - @wait = false - @uploadings = [] - @files = [] - @autocomplete = null - @poll = false + this.wait = false; + this.uploadings = []; + this.files = []; + this.autocomplete = null; + this.poll = false; - @in-reply-to-post = @opts.reply + this.inReplyToPost = this.opts.reply; - # https://github.com/riot/riot/issues/2080 - if @in-reply-to-post == '' then @in-reply-to-post = null + // https://github.com/riot/riot/issues/2080 + if (this.inReplyToPost == '') this.inReplyToPost = null; - @on \mount ~> - @refs.uploader.on \uploaded (file) ~> - @add-file file + this.on('mount', () => { + this.refs.uploader.on('uploaded', file => { + this.addFile(file); + }); - @refs.uploader.on \change-uploads (uploads) ~> - @trigger \change-uploading-files uploads + this.refs.uploader.on('change-uploads', uploads => { + this.trigger('change-uploading-files', uploads); + }); - @autocomplete = new @Autocomplete @refs.text - @autocomplete.attach! + this.autocomplete = new this.Autocomplete(this.refs.text); + this.autocomplete.attach(); + }); - @on \unmount ~> - @autocomplete.detach! + this.on('unmount', () => { + this.autocomplete.detach(); + }); - @focus = ~> - @refs.text.focus! + this.focus = () => { + this.refs.text.focus(); + }; - @clear = ~> - @refs.text.value = '' - @files = [] - @trigger \change-files - @update! + this.clear = () => { + this.refs.text.value = ''; + this.files = []; + this.trigger('change-files'); + this.update(); + }; - @ondragover = (e) ~> - e.stop-propagation! - @draghover = true - # ドラッグされてきたものがファイルだったら - if e.data-transfer.effect-allowed == \all - e.data-transfer.drop-effect = \copy - else - e.data-transfer.drop-effect = \move - return false + this.ondragover = e => { + e.stopPropagation(); + this.draghover = true; + e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move'; + return false; + }; - @ondragenter = (e) ~> - @draghover = true + this.ondragenter = e => { + this.draghover = true; + }; - @ondragleave = (e) ~> - @draghover = false + this.ondragleave = e => { + this.draghover = false; + }; - @ondrop = (e) ~> - e.prevent-default! - e.stop-propagation! - @draghover = false + this.ondrop = e => { + e.preventDefault(); + e.stopPropagation(); + this.draghover = false; - # ファイルだったら - if e.data-transfer.files.length > 0 - Array.prototype.for-each.call e.data-transfer.files, (file) ~> - @upload file - return false + // ファイルだったら + if (e.dataTransfer.files.length > 0) { + e.dataTransfer.files.forEach(this.upload); + } - # データ取得 - data = e.data-transfer.get-data 'text' - if !data? - return false + return false; + }; - try - # パース - obj = JSON.parse data + this.onkeydown = e => { + if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey)) this.post(); + }; - # (ドライブの)ファイルだったら - if obj.type == \file - @add-file obj.file - catch - # ignore + this.onpaste = e => { + e.clipboardData.items.forEach(item => { + if (item.kind == 'file') { + this.upload(item.getAsFile()); + } + }); + }; - return false + this.selectFile = () => { + this.refs.file.click(); + }; - @onkeydown = (e) ~> - if (e.which == 10 || e.which == 13) && (e.ctrl-key || e.meta-key) - @post! - - @onpaste = (e) ~> - data = e.clipboard-data - items = data.items - for i from 0 to items.length - 1 - item = items[i] - switch (item.kind) - | \file => - @upload item.get-as-file! - - @select-file = ~> - @refs.file.click! - - @select-file-from-drive = ~> - browser = document.body.append-child document.create-element \mk-select-file-from-drive-window - i = riot.mount browser, do + this.selectFileFromDrive = () => { + const i = riot.mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { multiple: true - i[0].one \selected (files) ~> - files.for-each @add-file + })[0]; + i.one('selected', files => { + files.forEach(this.addFile); + }); + }; - @change-file = ~> - files = @refs.file.files - for i from 0 to files.length - 1 - file = files.item i - @upload file + this.changeFile = () => { + this.refs.file.files.forEach(this.upload); + }; - @upload = (file) ~> - @refs.uploader.upload file + this.upload = file => { + this.refs.uploader.upload(file); + }; - @add-file = (file) ~> - file._remove = ~> - @files = @files.filter (x) -> x.id != file.id - @trigger \change-files @files - @update! + this.addFile = file => { + file._remove = () => { + this.files = this.files.filter(x => x.id != file.id); + this.trigger('change-files', this.files); + this.update(); + }; - @files.push file - @trigger \change-files @files - @update! + this.files.push(file); + this.trigger('change-files', this.files); + this.update(); + }; - @add-poll = ~> - @poll = true + this.addPoll = () => { + this.poll = true; + }; - @on-poll-destroyed = ~> - @update do + this.onPollDestroyed = () => { + this.update({ poll: false + }); + }; - @post = (e) ~> - @wait = true + this.post = e => { + this.wait = true; - files = if @files? and @files.length > 0 - then @files.map (f) -> f.id - else undefined + const files = this.files && this.files.length > 0 + ? this.files.map(f => f.id) + : undefined; - @api \posts/create do - text: @refs.text.value - media_ids: files - reply_to_id: if @in-reply-to-post? then @in-reply-to-post.id else undefined - poll: if @poll then @refs.poll.get! else undefined - .then (data) ~> - @trigger \post - @notify if @in-reply-to-post? then '返信しました!' else '投稿しました!' - .catch (err) ~> - console.error err - @notify '投稿できませんでした' - .then ~> - @wait = false - @update! + this.api('posts/create', { + text: this.refs.text.value, + media_ids: files, + reply_to_id: this.inReplyToPost ? this.inReplyToPost.id : undefined, + poll: this.poll ? this.refs.poll.get() : undefined + }).then(data => { + this.trigger('post'); + this.notify(this.inReplyToPost ? '返信しました!' : '投稿しました!'); + }).catch(err => { + this.notify('投稿できませんでした'); + }).then(() => { + this.update({ + wait: false + }); + }); + }; - @cat = ~> - @refs.text.value = @refs.text.value + get-cat! + this.cat = () => { + this.refs.text.value += getCat(); + }; </script> </mk-post-form> diff --git a/src/web/app/desktop/tags/post-preview.tag b/src/web/app/desktop/tags/post-preview.tag index c0514c323e..458a6f83f2 100644 --- a/src/web/app/desktop/tags/post-preview.tag +++ b/src/web/app/desktop/tags/post-preview.tag @@ -83,11 +83,11 @@ </style> <script> - @mixin \date-stringify - @mixin \user-preview + this.mixin('date-stringify'); + this.mixin('user-preview'); - @post = @opts.post + this.post = this.opts.post; - @title = @date-stringify @post.created_at + this.title = this.dateStringify(this.post.created_at); </script> </mk-post-preview> diff --git a/src/web/app/desktop/tags/progress-dialog.tag b/src/web/app/desktop/tags/progress-dialog.tag index c60746257b..760f869f6e 100644 --- a/src/web/app/desktop/tags/progress-dialog.tag +++ b/src/web/app/desktop/tags/progress-dialog.tag @@ -75,20 +75,25 @@ </style> <script> - @title = @opts.title - @value = parse-int @opts.value, 10 - @max = parse-int @opts.max, 10 + this.title = this.opts.title; + this.value = parseInt(this.opts.value, 10); + this.max = parseInt(this.opts.max, 10); - @on \mount ~> - @refs.window.on \closed ~> - @unmount! + this.on('mount', () => { + this.refs.window.on('closed', () => { + this.unmount(); + }); + }); - @update-progress = (value, max) ~> - @value = parse-int value, 10 - @max = parse-int max, 10 - @update! + this.updateProgress = (value, max) => { + this.update({ + value: parseInt(value, 10), + max: parseInt(max, 10) + }); + }; - @close = ~> - @refs.window.close! + this.close = () => { + this.refs.window.close(); + }; </script> </mk-progress-dialog> diff --git a/src/web/app/desktop/tags/repost-form-window.tag b/src/web/app/desktop/tags/repost-form-window.tag index 45a0cdae6d..75fe9f4829 100644 --- a/src/web/app/desktop/tags/repost-form-window.tag +++ b/src/web/app/desktop/tags/repost-form-window.tag @@ -12,25 +12,32 @@ </style> <script> - @on-document-keydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 27 # Esc - @refs.window.close! + this.onDocumentKeydown = e => { + if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') { + if (e.which == 27) { // Esc + this.refs.window.close(); + } + } + }; - @on \mount ~> - @refs.window.refs.form.on \cancel ~> - @refs.window.close! + this.on('mount', () => { + this.refs.window.refs.form.on('cancel', () => { + this.refs.window.close(); + }); - @refs.window.refs.form.on \posted ~> - @refs.window.close! + this.refs.window.refs.form.on('posted', () => { + this.refs.window.close(); + }); - document.add-event-listener \keydown @on-document-keydown + document.addEventListener('keydown', this.onDocumentKeydown); - @refs.window.on \closed ~> - @unmount! + this.refs.window.on('closed', () => { + this.unmount(); + }); + }); - @on \unmount ~> - document.remove-event-listener \keydown @on-document-keydown + this.on('unmount', () => { + document.removeEventListener('keydown', this.onDocumentKeydown); + }); </script> </mk-repost-form-window> diff --git a/src/web/app/desktop/tags/repost-form.tag b/src/web/app/desktop/tags/repost-form.tag index 2c07ff4b16..e5101d9f2c 100644 --- a/src/web/app/desktop/tags/repost-form.tag +++ b/src/web/app/desktop/tags/repost-form.tag @@ -114,31 +114,35 @@ </style> <script> - @mixin \api - @mixin \notify + this.mixin('api'); + this.mixin('notify'); - @wait = false - @quote = false + this.wait = false; + this.quote = false; - @cancel = ~> - @trigger \cancel + this.cancel = () => { + this.trigger('cancel'); + }; - @ok = ~> - @wait = true - @api \posts/create do - repost_id: @opts.post.id - text: if @quote then @refs.text.value else undefined - .then (data) ~> - @trigger \posted - @notify 'Repostしました!' - .catch (err) ~> - console.error err - @notify 'Repostできませんでした' - .then ~> - @wait = false - @update! + this.ok = () => { + this.wait = true; + this.api('posts/create', { + repost_id: this.opts.post.id, + text: this.quote ? this.refs.text.value : undefined + }).then(data => { + this.trigger('posted'); + this.notify('Repostしました!'); + }).catch(err => { + this.notify('Repostできませんでした'); + }).then(() => { + this.update({ + wait: false + }); + }); + }; - @onquote = ~> - @quote = true + this.onquote = () => { + this.quote = true; + }; </script> </mk-repost-form> diff --git a/src/web/app/desktop/tags/search-posts.tag b/src/web/app/desktop/tags/search-posts.tag index 2cc9b788ae..95ee33a5a4 100644 --- a/src/web/app/desktop/tags/search-posts.tag +++ b/src/web/app/desktop/tags/search-posts.tag @@ -28,59 +28,64 @@ </style> <script> - @mixin \api - @mixin \get-post-summary + this.mixin('api'); + this.mixin('get-post-summary'); - @query = @opts.query - @is-loading = true - @is-empty = false - @more-loading = false - @page = 0 + this.query = this.opts.query; + this.isLoading = true; + this.isEmpty = false; + this.moreLoading = false; + this.page = 0; - @on \mount ~> - document.add-event-listener \keydown @on-document-keydown - window.add-event-listener \scroll @on-scroll + this.on('mount', () => { + document.addEventListener('keydown', this.onDocumentKeydown); + window.addEventListener('scroll', this.onScroll); - @api \posts/search do - query: @query - .then (posts) ~> - @is-loading = false - @is-empty = posts.length == 0 - @update! - @refs.timeline.set-posts posts - @trigger \loaded - .catch (err) ~> - console.error err + this.api('posts/search', { + query: this.query + }).then(posts => { + this.update({ + isLoading: false, + isEmpty: posts.length == 0 + }); + this.refs.timeline.setPosts(posts); + this.trigger('loaded'); + }); + }); - @on \unmount ~> - document.remove-event-listener \keydown @on-document-keydown - window.remove-event-listener \scroll @on-scroll + this.on('unmount', () => { + document.removeEventListener('keydown', this.onDocumentKeydown); + window.removeEventListener('scroll', this.onScroll); + }); - @on-document-keydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 84 # t - @refs.timeline.focus! + this.onDocumentKeydown = e => { + if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') { + if (e.which == 84) { // t + this.refs.timeline.focus(); + } + } + }; - @more = ~> - if @more-loading or @is-loading or @timeline.posts.length == 0 - return - @more-loading = true - @update! - @api \posts/search do - query: @query - page: @page + 1 - .then (posts) ~> - @more-loading = false - @page++ - @update! - @refs.timeline.prepend-posts posts - .catch (err) ~> - console.error err + this.more = () => { + if (this.moreLoading || this.isLoading || this.timeline.posts.length == 0) return; + this.update({ + moreLoading: true + }); + this.api('posts/search', { + query: this.query, + page: this.page + 1 + }).then(posts => { + this.update({ + moreLoading: false, + page: page + 1 + }); + this.refs.timeline.prependPosts(posts); + }); + }; - @on-scroll = ~> - current = window.scroll-y + window.inner-height - if current > document.body.offset-height - 16 # 遊び - @more! + this.onScroll = () => { + const current = window.scrollY + window.innerHeight; + if (current > document.body.offsetHeight - 16) this.more(); + }; </script> </mk-search-posts> diff --git a/src/web/app/desktop/tags/search.tag b/src/web/app/desktop/tags/search.tag index d2561dfdca..681b4c8aed 100644 --- a/src/web/app/desktop/tags/search.tag +++ b/src/web/app/desktop/tags/search.tag @@ -23,10 +23,12 @@ </style> <script> - @query = @opts.query + this.query = this.opts.query; - @on \mount ~> - @refs.posts.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.posts.on('loaded', () => { + this.trigger('loaded'); + }); + }); </script> </mk-search> diff --git a/src/web/app/desktop/tags/select-file-from-drive-window.tag b/src/web/app/desktop/tags/select-file-from-drive-window.tag index f9ba9e3cc0..777073583f 100644 --- a/src/web/app/desktop/tags/select-file-from-drive-window.tag +++ b/src/web/app/desktop/tags/select-file-from-drive-window.tag @@ -131,31 +131,38 @@ </style> <script> - @file = [] + this.file = []; - @multiple = if @opts.multiple? then @opts.multiple else false - @title = @opts.title || '<i class="fa fa-file-o"></i>ファイルを選択' + this.multiple = this.opts.multiple != null ? this.opts.multiple : false; + this.title = this.opts.title || '<i class="fa fa-file-o"></i>ファイルを選択'; - @on \mount ~> - @refs.window.refs.browser.on \selected (file) ~> - @file = file - @ok! + this.on('mount', () => { + this.refs.window.refs.browser.on('selected', file => { + this.file = file; + this.ok(); + }); - @refs.window.refs.browser.on \change-selection (files) ~> - @file = files - @update! + this.refs.window.refs.browser.on('change-selection', files => { + this.file = files; + this.update(); + }); - @refs.window.on \closed ~> - @unmount! + this.refs.window.on('closed', () => { + this.unmount(); + }); + }); - @close = ~> - @refs.window.close! + this.close = () => { + this.refs.window.close(); + }; - @upload = ~> - @refs.window.refs.browser.select-local-file! + this.upload = () => { + this.refs.window.refs.browser.selectLocalFile(); + }; - @ok = ~> - @trigger \selected @file - @refs.window.close! + this.ok = () => { + this.trigger('selected', this.file); + this.refs.window.close(); + }; </script> </mk-select-file-from-drive-window> diff --git a/src/web/app/desktop/tags/set-avatar-suggestion.tag b/src/web/app/desktop/tags/set-avatar-suggestion.tag index 22a0de0f3a..335148ea5d 100644 --- a/src/web/app/desktop/tags/set-avatar-suggestion.tag +++ b/src/web/app/desktop/tags/set-avatar-suggestion.tag @@ -31,15 +31,17 @@ </style> <script> - @mixin \i - @mixin \update-avatar + this.mixin('i'); + this.mixin('update-avatar'); - @set = ~> - @update-avatar @I + this.set = () => { + this.updateAvatar(this.I); + }; - @close = (e) ~> - e.prevent-default! - e.stop-propagation! - @unmount! + this.close = e => { + e.preventDefault(); + e.stopPropagation(); + this.unmount(); + }; </script> </mk-set-avatar-suggestion> diff --git a/src/web/app/desktop/tags/set-banner-suggestion.tag b/src/web/app/desktop/tags/set-banner-suggestion.tag index 3ccaab108d..deddc478cc 100644 --- a/src/web/app/desktop/tags/set-banner-suggestion.tag +++ b/src/web/app/desktop/tags/set-banner-suggestion.tag @@ -31,15 +31,17 @@ </style> <script> - @mixin \i - @mixin \update-banner + this.mixin('i'); + this.mixin('update-banner'); - @set = ~> - @update-banner @I + this.set = () => { + this.updateBanner(this.I); + }; - @close = (e) ~> - e.prevent-default! - e.stop-propagation! - @unmount! + this.close = e => { + e.preventDefault(); + e.stopPropagation(); + this.unmount(); + }; </script> </mk-set-banner-suggestion> diff --git a/src/web/app/desktop/tags/settings-window.tag b/src/web/app/desktop/tags/settings-window.tag index 10bb48de76..cb78921d42 100644 --- a/src/web/app/desktop/tags/settings-window.tag +++ b/src/web/app/desktop/tags/settings-window.tag @@ -15,11 +15,14 @@ </style> <script> - @on \mount ~> - @refs.window.on \closed ~> - @unmount! + this.on('mount', () => { + this.refs.window.on('closed', () => { + this.unmount(); + }); + }); - @close = ~> - @refs.window.close! + this.close = () => { + this.refs.window.close(); + }; </script> </mk-settings-window> diff --git a/src/web/app/desktop/tags/settings.tag b/src/web/app/desktop/tags/settings.tag index 1c14514ac0..544e41c256 100644 --- a/src/web/app/desktop/tags/settings.tag +++ b/src/web/app/desktop/tags/settings.tag @@ -48,11 +48,6 @@ <p>API通信時に新鮮なユーザー情報をキャッシュすることでフェッチのオーバーヘッドを無くします。(実験的)</p> </label> <label class="checkbox"> - <input type="checkbox" checked={ I.data.debug } onclick={ updateDebug }/> - <p>開発者モード</p> - <p>デバッグ等の開発者モードを有効にします。</p> - </label> - <label class="checkbox"> <input type="checkbox" checked={ I.data.nya } onclick={ updateNya }/> <p><i>な</i>を<i>にゃ</i>に変換する</p> <p>攻撃的な投稿が多少和らぐ可能性があります。</p> @@ -198,46 +193,49 @@ </style> <script> - @mixin \i - @mixin \api - @mixin \dialog - @mixin \update-avatar - - @page = \account + this.mixin('i'); + this.mixin('api'); + this.mixin('notify'); + this.mixin('dialog'); + this.mixin('update-avatar'); - @set-page = (page) ~> - @page = page + this.page = 'account'; - @avatar = ~> - @update-avatar @I + this.setPage = page => { + this.page = page; + }; - @update-account = ~> - @api \i/update do - name: @refs.account-name.value - location: @refs.account-location.value - bio: @refs.account-bio.value - birthday: @refs.account-birthday.value - .then (i) ~> - alert \ok - .catch (err) ~> - console.error err + this.avatar = () => { + this.updateAvatar(this.I); + }; - @update-cache = ~> - @I.data.cache = !@I.data.cache - @api \i/appdata/set do - data: JSON.stringify do - cache: @I.data.cache + this.updateAccount = () => { + this.api('i/update', { + name: this.refs.accountName.value, + location: this.refs.accountLocation.value, + bio: this.refs.accountBio.value, + birthday: this.refs.accountBirthday.value + }).then(() => { + this.notify('プロフィールを更新しました'); + }); + }; - @update-debug = ~> - @I.data.debug = !@I.data.debug - @api \i/appdata/set do - data: JSON.stringify do - debug: @I.data.debug + this.updateCache = () => { + this.I.data.cache = !this.I.data.cache; + this.api('i/appdata/set', { + data: JSON.stringify({ + cache: this.I.data.cache + }) + }); + }; - @update-nya = ~> - @I.data.nya = !@I.data.nya - @api \i/appdata/set do - data: JSON.stringify do - nya: @I.data.nya + this.updateNya = () => { + this.I.data.nya = !this.I.data.nya; + this.api('i/appdata/set', { + data: JSON.stringify({ + nya: this.I.data.nya + }) + }); + }; </script> </mk-settings> diff --git a/src/web/app/desktop/tags/stream-indicator.tag b/src/web/app/desktop/tags/stream-indicator.tag deleted file mode 100644 index d2ab34574d..0000000000 --- a/src/web/app/desktop/tags/stream-indicator.tag +++ /dev/null @@ -1,54 +0,0 @@ -<mk-stream-indicator> - <p if={ state == 'initializing' }><i class="fa fa-spinner fa-spin"></i><span>接続中 - <mk-ellipsis></mk-ellipsis></span></p> - <p if={ state == 'reconnecting' }><i class="fa fa-spinner fa-spin"></i><span>切断されました 接続中 - <mk-ellipsis></mk-ellipsis></span></p> - <p if={ state == 'connected' }><i class="fa fa-check"></i><span>接続完了</span></p> - <style> - :scope - display block - pointer-events none - position fixed - z-index 16384 - bottom 8px - right 8px - margin 0 - padding 6px 12px - font-size 0.9em - color #fff - background rgba(0, 0, 0, 0.8) - - > p - display block - margin 0 - - > i - margin-right 0.25em - - </style> - <script> - @mixin \stream - - @on \before-mount ~> - @state = @get-stream-state! - - if @state == \connected - @root.style.opacity = 0 - - @stream-state-ev.on \connected ~> - @state = @get-stream-state! - @update! - set-timeout ~> - Velocity @root, { - opacity: 0 - } 200ms \linear - , 1000ms - - @stream-state-ev.on \closed ~> - @state = @get-stream-state! - @update! - Velocity @root, { - opacity: 1 - } 0ms - </script> -</mk-stream-indicator> diff --git a/src/web/app/desktop/tags/sub-post-content.tag b/src/web/app/desktop/tags/sub-post-content.tag index 72f570dd6a..e0509ab7d4 100644 --- a/src/web/app/desktop/tags/sub-post-content.tag +++ b/src/web/app/desktop/tags/sub-post-content.tag @@ -1,5 +1,11 @@ <mk-sub-post-content> - <div class="body"><a class="reply" if={ post.reply_to_id }><i class="fa fa-reply"></i></a><span ref="text"></span><a class="quote" if={ post.repost_id } href={ '/post:' + post.repost_id }>RP: ...</a></div> + <div class="body"> + <a class="reply" if={ post.reply_to_id }> + <i class="fa fa-reply"></i> + </a> + <span ref="text"></span> + <a class="quote" if={ post.repost_id } href={ '/post:' + post.repost_id }>RP: ...</a> + </div> <details if={ post.media }> <summary>({ post.media.length }つのメディア)</summary> <mk-images-viewer images={ post.media }></mk-images-viewer> @@ -28,18 +34,20 @@ </style> <script> - @mixin \text - @mixin \user-preview + this.mixin('text'); + this.mixin('user-preview'); - @post = @opts.post + this.post = this.opts.post; - @on \mount ~> - if @post.text? - tokens = @analyze @post.text - @refs.text.innerHTML = @compile tokens, false + this.on('mount', () => { + if (this.post.text) { + const tokens = this.analyze(this.post.text); + this.refs.text.innerHTML = this.compile(tokens, false); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); + } + }); </script> </mk-sub-post-content> diff --git a/src/web/app/desktop/tags/timeline-post-sub.tag b/src/web/app/desktop/tags/timeline-post-sub.tag index 5884927d75..905bc7aacf 100644 --- a/src/web/app/desktop/tags/timeline-post-sub.tag +++ b/src/web/app/desktop/tags/timeline-post-sub.tag @@ -8,15 +8,6 @@ </div> </div> </article> - <script> - @mixin \date-stringify - @mixin \user-preview - - @post = @opts.post - - @title = @date-stringify @post.created_at - - </script> <style> :scope display block @@ -97,4 +88,11 @@ font-size 80% </style> + <script> + this.mixin('date-stringify'); + this.mixin('user-preview'); + + this.post = this.opts.post; + this.title = this.dateStringify(this.post.created_at); + </script> </mk-timeline-post-sub> diff --git a/src/web/app/desktop/tags/timeline-post.tag b/src/web/app/desktop/tags/timeline-post.tag index 1549151fdb..440d5d9f42 100644 --- a/src/web/app/desktop/tags/timeline-post.tag +++ b/src/web/app/desktop/tags/timeline-post.tag @@ -55,8 +55,13 @@ <button class={ liked: p.is_liked } onclick={ like } title="善哉"><i class="fa fa-thumbs-o-up"></i> <p class="count" if={ p.likes_count > 0 }>{ p.likes_count }</p> </button> - <button onclick={ NotImplementedException }><i class="fa fa-ellipsis-h"></i></button> - <button onclick={ toggleDetail } title="詳細"><i class="fa fa-caret-down" if={ !isDetailOpened }></i><i class="fa fa-caret-up" if={ isDetailOpened }></i></button> + <button onclick={ NotImplementedException }> + <i class="fa fa-ellipsis-h"></i> + </button> + <button onclick={ toggleDetail } title="詳細"> + <i class="fa fa-caret-down" if={ !isDetailOpened }></i> + <i class="fa fa-caret-up" if={ isDetailOpened }></i> + </button> </footer> </div> </article> @@ -312,96 +317,124 @@ </style> <script> - @mixin \api - @mixin \text - @mixin \date-stringify - @mixin \user-preview - @mixin \NotImplementedException + this.mixin('api'); + this.mixin('text'); + this.mixin('date-stringify'); + this.mixin('user-preview'); + this.mixin('NotImplementedException'); - @post = @opts.post - @is-repost = @post.repost? and !@post.text? - @p = if @is-repost then @post.repost else @post + this.post = this.opts.post; + this.isRepost = this.post.repost && this.post.text == null; + this.p = this.isRepost ? this.post.repost : this.post; - @title = @date-stringify @p.created_at + this.title = this.dateStringify(this.p.created_at); - @url = CONFIG.url + '/' + @p.user.username + '/' + @p.id - @is-detail-opened = false + this.url = CONFIG.url + '/' + this.p.user.username + '/' + this.p.id; + this.isDetailOpened = false; - @on \mount ~> - if @p.text? - tokens = if @p._highlight? - then @analyze @p._highlight - else @analyze @p.text + this.on('mount', () => { + if (this.p.text) { + const tokens = this.analyze(this.p.text); - @refs.text.innerHTML = @refs.text.innerHTML.replace '<p class="dummy"></p>' if @p._highlight? - then @compile tokens, true, false - else @compile tokens + this.refs.text.innerHTML = this.refs.text.innerHTML.replace('<p class="dummy"></p>', this.compile(tokens)); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); - # URLをプレビュー + // URLをプレビュー tokens - .filter (t) -> t.type == \link - .map (t) ~> - @preview = @refs.text.append-child document.create-element \mk-url-preview - riot.mount @preview, do - url: t.content + .filter(t => t.type == 'link') + .map(t => { + riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), { + url: t.content + }); + }); + } + }); + + this.reply = () => { + riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), { + reply: this.p + }); + }; + + this.repost = () => { + riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), { + post: this.p + }); + }; + + this.like = () => { + if (this.p.is_liked) { + this.api('posts/likes/delete', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = false; + this.update(); + }); + } else { + this.api('posts/likes/create', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = true; + this.update(); + }); + } + }; + + this.toggleDetail = () => { + this.update({ + isDetailOpened: !this.isDetailOpened + }); + }; + + this.onKeyDown = e => { + let shouldBeCancel = true; - @reply = ~> - form = document.body.append-child document.create-element \mk-post-form-window - riot.mount form, do - reply: @p + switch (true) { + case e.which == 38: // [↑] + case e.which == 74: // [j] + case e.which == 9 && e.shiftKey: // [Shift] + [Tab] + focus(this.root, e => e.previousElementSibling); + break; - @repost = ~> - form = document.body.append-child document.create-element \mk-repost-form-window - riot.mount form, do - post: @p + case e.which == 40: // [↓] + case e.which == 75: // [k] + case e.which == 9: // [Tab] + focus(this.root, e => e.nextElementSibling); + break; - @like = ~> - if @p.is_liked - @api \posts/likes/delete do - post_id: @p.id - .then ~> - @p.is_liked = false - @update! - else - @api \posts/likes/create do - post_id: @p.id - .then ~> - @p.is_liked = true - @update! + case e.which == 81: // [q] + case e.which == 69: // [e] + this.repost(); + break; - @toggle-detail = ~> - @is-detail-opened = !@is-detail-opened - @update! + case e.which == 70: // [f] + case e.which == 76: // [l] + this.like(); + break; - @on-key-down = (e) ~> - should-be-cancel = true - switch - | e.which == 38 or e.which == 74 or (e.which == 9 and e.shift-key) => # ↑, j or Shift+Tab - focus @root, (e) -> e.previous-element-sibling - | e.which == 40 or e.which == 75 or e.which == 9 => # ↓, k or Tab - focus @root, (e) -> e.next-element-sibling - | e.which == 81 or e.which == 69 => # q or e - @repost! - | e.which == 70 or e.which == 76 => # f or l - @like! - | e.which == 82 => # r - @reply! - | _ => - should-be-cancel = false + case e.which == 82: // [r] + this.reply(); + break; + + default: + shouldBeCancel = false; + } - if should-be-cancel - e.prevent-default! + if (shouldBeCancel) e.preventDefault(); + }; - function focus(el, fn) - target = fn el - if target? - if target.has-attribute \tabindex - target.focus! - else - focus target, fn + function focus(el, fn) { + const target = fn(el); + if (target) { + if (target.hasAttribute('tabindex')) { + target.focus(); + } else { + focus(target, fn); + } + } + } </script> </mk-timeline-post> diff --git a/src/web/app/desktop/tags/timeline.tag b/src/web/app/desktop/tags/timeline.tag index 3439a426e3..a589adf5a0 100644 --- a/src/web/app/desktop/tags/timeline.tag +++ b/src/web/app/desktop/tags/timeline.tag @@ -3,7 +3,9 @@ <mk-timeline-post post={ post }></mk-timeline-post> <p class="date" if={ i != posts.length - 1 && post._date != posts[i + 1]._date }><span><i class="fa fa-angle-up"></i>{ post._datetext }</span><span><i class="fa fa-angle-down"></i>{ posts[i + 1]._datetext }</span></p> </virtual> - <footer data-yield="footer"><yield from="footer"/></footer> + <footer data-yield="footer"> + <yield from="footer"/> + </footer> <style> :scope display block @@ -44,36 +46,47 @@ </style> <script> - @posts = [] + this.posts = []; - @set-posts = (posts) ~> - @posts = posts - @update! + this.on('update', () => { + this.posts.forEach(post => { + const date = new Date(post.created_at).getDate(); + const month = new Date(post.created_at).getMonth() + 1; + post._date = date; + post._datetext = `${month}月 ${date}日`; + }); + }); - @prepend-posts = (posts) ~> - posts.for-each (post) ~> - @posts.push post - @update! + this.setPosts = posts => { + this.update({ + posts: posts + }); + }; - @add-post = (post) ~> - @posts.unshift post - @update! + this.prependPosts = posts => { + posts.forEach(post => { + this.posts.push(post); + this.update(); + }); + } - @clear = ~> - @posts = [] - @update! + this.addPost = post => { + this.posts.unshift(post); + this.update(); + }; - @focus = ~> - @root.children.0.focus! + this.tail = () => { + return this.posts[this.posts.length - 1]; + }; - @on \update ~> - @posts.for-each (post) ~> - date = (new Date post.created_at).get-date! - month = (new Date post.created_at).get-month! + 1 - post._date = date - post._datetext = month + '月 ' + date + '日' + this.clear = () => { + this.posts = []; + this.update(); + }; + + this.focus = () => { + this.root.children[0].focus(); + }; - @tail = ~> - @posts[@posts.length - 1] </script> </mk-timeline> diff --git a/src/web/app/desktop/tags/ui-header-account.tag b/src/web/app/desktop/tags/ui-header-account.tag index 6071995cec..c035529f79 100644 --- a/src/web/app/desktop/tags/ui-header-account.tag +++ b/src/web/app/desktop/tags/ui-header-account.tag @@ -159,54 +159,54 @@ </style> <script> - @mixin \i - @mixin \signout + const contains = require('../../common/scripts/contains'); - @is-open = false + this.mixin('i'); + this.mixin('signout'); - @on \before-unmount ~> - @close! + this.isOpen = false; - @toggle = ~> - if @is-open - @close! - else - @open! + this.on('before-unmount', () => { + this.close(); + }); - @open = ~> - @is-open = true - @update! - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.add-event-listener \mousedown @mousedown + this.toggle = () => { + this.isOpen ? this.close() : this.open(); + }; - @close = ~> - @is-open = false - @update! - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.remove-event-listener \mousedown @mousedown + this.open = () => { + this.update({ + isOpen: true + }); + document.querySelectorAll('body *').forEach(el => { + el.addEventListener('mousedown', this.mousedown); + }); + }; - @mousedown = (e) ~> - e.prevent-default! - if (!contains @root, e.target) and (@root != e.target) - @close! - return false + this.close = () => { + this.update({ + isOpen: false + }); + document.querySelectorAll('body *').forEach(el => { + el.removeEventListener('mousedown', this.mousedown); + }); + }; - @drive = ~> - @close! - riot.mount document.body.append-child document.create-element \mk-drive-browser-window + this.mousedown = e => { + e.preventDefault(); + if (!contains(this.root, e.target) && this.root != e.target) this.close(); + return false; + }; - @settings = ~> - @close! - riot.mount document.body.append-child document.create-element \mk-settings-window + this.drive = () => { + this.close(); + riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-window'))); + }; + + this.settings = () => { + this.close(); + riot.mount(document.body.appendChild(document.createElement('mk-settings-window'))); + }; - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - return false </script> </mk-ui-header-account> diff --git a/src/web/app/desktop/tags/ui-header-clock.tag b/src/web/app/desktop/tags/ui-header-clock.tag index 50536705bc..48b142509a 100644 --- a/src/web/app/desktop/tags/ui-header-clock.tag +++ b/src/web/app/desktop/tags/ui-header-clock.tag @@ -1,6 +1,10 @@ <mk-ui-header-clock> <div class="header"> - <time ref="time"></time> + <time ref="time"> + <span class="yyyymmdd">{ yyyy }/{ mm }/{ dd }</span> + <br> + <span class="hhnn">{ hh }<span style="visibility:{ now.getSeconds() % 2 == 0 ? 'visible' : 'hidden' }">:</span>{ nn }</span> + </time> </div> <div class="content"> <mk-analog-clock></mk-analog-clock> @@ -13,7 +17,7 @@ > .header padding 0 12px text-align center - font-size 0.5em + font-size 10px &, * cursor: default @@ -58,30 +62,24 @@ </style> <script> - @draw = ~> - now = new Date! + this.now = new Date(); - yyyy = now.get-full-year! - mm = (\0 + (now.get-month! + 1)).slice -2 - dd = (\0 + now.get-date!).slice -2 - yyyymmdd = "<span class='yyyymmdd'>#yyyy/#mm/#dd</span>" + this.draw = () => { + const now = this.now = new Date(); + this.yyyy = now.getFullYear(); + this.mm = ('0' + (now.getMonth() + 1)).slice(-2); + this.dd = ('0' + now.getDate()).slice(-2); + this.hh = ('0' + now.getHours()).slice(-2); + this.nn = ('0' + now.getMinutes()).slice(-2); + }; - hh = (\0 + now.get-hours!).slice -2 - mm = (\0 + now.get-minutes!).slice -2 - hhmm = "<span class='hhmm'>#hh:#mm</span>" + this.on('mount', () => { + this.draw(); + this.clock = setInterval(this.draw, 1000); + }); - if now.get-seconds! % 2 == 0 - hhmm .= replace \: '<span style=\'visibility:visible\'>:</span>' - else - hhmm .= replace \: '<span style=\'visibility:hidden\'>:</span>' - - @refs.time.innerHTML = "#yyyymmdd<br>#hhmm" - - @on \mount ~> - @draw! - @clock = set-interval @draw, 1000ms - - @on \unmount ~> - clear-interval @clock + this.on('unmount', () => { + clearInterval(this.clock); + }); </script> </mk-ui-header-clock> diff --git a/src/web/app/desktop/tags/ui-header-nav.tag b/src/web/app/desktop/tags/ui-header-nav.tag index 707a9366e8..9be1edea8c 100644 --- a/src/web/app/desktop/tags/ui-header-nav.tag +++ b/src/web/app/desktop/tags/ui-header-nav.tag @@ -1,113 +1,139 @@ <mk-ui-header-nav> <ul if={ SIGNIN }> - <li class="home { active: page == 'home' }"><a href={ CONFIG.url }><i class="fa fa-home"></i> - <p>ホーム</p></a></li> - <li class="messaging"><a onclick={ messaging }><i class="fa fa-comments"></i> - <p>メッセージ</p><i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i></a></li> - <li class="info"><a href="https://twitter.com/misskey_xyz" target="_blank"><i class="fa fa-info"></i> - <p>お知らせ</p></a></li> - <li class="tv"><a href="https://misskey.tk" target="_blank"><i class="fa fa-television"></i> - <p>MisskeyTV™</p></a></li> - <style> - :scope + <li class="home { active: page == 'home' }"> + <a href={ CONFIG.url }> + <i class="fa fa-home"></i> + <p>ホーム</p> + </a> + </li> + <li class="messaging"> + <a onclick={ messaging }> + <i class="fa fa-comments"></i> + <p>メッセージ</p> + <i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i> + </a> + </li> + <li class="info"> + <a href="https://twitter.com/misskey_xyz" target="_blank"> + <i class="fa fa-info"></i> + <p>お知らせ</p> + </a> + </li> + <li class="tv"> + <a href="https://misskey.tk" target="_blank"> + <i class="fa fa-television"></i> + <p>MisskeyTV™</p> + </a> + </li> + </ul> + <style> + :scope + display inline-block + margin 0 + padding 0 + line-height 3rem + vertical-align top + + > ul display inline-block margin 0 padding 0 - line-height 3rem vertical-align top + line-height 3rem + list-style none - > ul + > li display inline-block - margin 0 - padding 0 vertical-align top - line-height 3rem - list-style none + height 48px + line-height 48px + + &.active + > a + border-bottom solid 3px $theme-color - > li + > a display inline-block - vertical-align top - height 48px - line-height 48px + z-index 1 + height 100% + padding 0 24px + font-size 1em + font-variant small-caps + color #9eaba8 + text-decoration none + transition none + cursor pointer - &.active - > a - border-bottom solid 3px $theme-color + * + pointer-events none - > a - display inline-block - z-index 1 - height 100% - padding 0 24px - font-size 1em - font-variant small-caps - color #9eaba8 + &:hover + color darken(#9eaba8, 20%) text-decoration none - transition none - cursor pointer - - * - pointer-events none - &:hover - color darken(#9eaba8, 20%) - text-decoration none + > i:first-child + margin-right 8px - > i:first-child - margin-right 8px + > i:last-child + margin-left 5px + vertical-align super + font-size 10px + color $theme-color - > i:last-child - margin-left 5px - vertical-align super - font-size 10px - color $theme-color + @media (max-width 1100px) + margin-left -5px - @media (max-width 1100px) - margin-left -5px + > p + display inline + margin 0 - > p - display inline - margin 0 + @media (max-width 1100px) + display none - @media (max-width 1100px) - display none + @media (max-width 700px) + padding 0 12px - @media (max-width 700px) - padding 0 12px + </style> + <script> + this.mixin('i'); + this.mixin('api'); + this.mixin('stream'); - </style> - <script> - @mixin \i - @mixin \api - @mixin \stream + this.page = this.opts.page; - @page = @opts.page + this.on('mount', () => { + this.stream.on('read_all_messaging_messages', this.onReadAllMessagingMessages); + this.stream.on('unread_messaging_message', this.onUnreadMessagingMessage); - @on \mount ~> - @stream.on \read_all_messaging_messages @on-read-all-messaging-messages - @stream.on \unread_messaging_message @on-unread-messaging-message + // Fetch count of unread messaging messages + this.api('messaging/unread').then(res => { + if (res.count > 0) { + this.update({ + hasUnreadMessagingMessages: true + }); + } + }); + }); - # Fetch count of unread messaging messages - @api \messaging/unread - .then (count) ~> - if count.count > 0 - @has-unread-messaging-messages = true - @update! + this.on('unmount', () => { + this.stream.off('read_all_messaging_messages', this.onReadAllMessagingMessages); + this.stream.off('unread_messaging_message', this.onUnreadMessagingMessage); + }); - @on \unmount ~> - @stream.off \read_all_messaging_messages @on-read-all-messaging-messages - @stream.off \unread_messaging_message @on-unread-messaging-message + this.onReadAllMessagingMessages = () => { + this.update({ + hasUnreadMessagingMessages: false + }); + }; - @on-read-all-messaging-messages = ~> - @has-unread-messaging-messages = false - @update! + this.onUnreadMessagingMessage = () => { + this.update({ + hasUnreadMessagingMessages: true + }); + }; - @on-unread-messaging-message = ~> - @has-unread-messaging-messages = true - @update! - - @messaging = ~> - riot.mount document.body.append-child document.create-element \mk-messaging-window - </script> - </ul> + this.messaging = () => { + riot.mount(document.body.appendChild(document.createElement('mk-messaging-window'))); + }; + </script> </mk-ui-header-nav> diff --git a/src/web/app/desktop/tags/ui-header-notifications.tag b/src/web/app/desktop/tags/ui-header-notifications.tag index 65330a14e3..05a9e6d772 100644 --- a/src/web/app/desktop/tags/ui-header-notifications.tag +++ b/src/web/app/desktop/tags/ui-header-notifications.tag @@ -75,40 +75,36 @@ </style> <script> - @is-open = false + const contains = require('../../common/scripts/contains'); - @toggle = ~> - if @is-open - @close! - else - @open! + this.isOpen = false; - @open = ~> - @is-open = true - @update! - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.add-event-listener \mousedown @mousedown + this.toggle = () => { + this.isOpen ? this.close() : this.open(); + }; - @close = ~> - @is-open = false - @update! - all = document.query-selector-all 'body *' - Array.prototype.for-each.call all, (el) ~> - el.remove-event-listener \mousedown @mousedown + this.open = () => { + this.update({ + isOpen: true + }); + document.querySelectorAll('body *').forEach(el => { + el.addEventListener('mousedown', this.mousedown); + }); + }; - @mousedown = (e) ~> - e.prevent-default! - if (!contains @root, e.target) and (@root != e.target) - @close! - return false + this.close = () => { + this.update({ + isOpen: false + }); + document.querySelectorAll('body *').forEach(el => { + el.removeEventListener('mousedown', this.mousedown); + }); + }; - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - return false + this.mousedown = e => { + e.preventDefault(); + if (!contains(this.root, e.target) && this.root != e.target) this.close(); + return false; + }; </script> </mk-ui-header-notifications> diff --git a/src/web/app/desktop/tags/ui-header-post-button.tag b/src/web/app/desktop/tags/ui-header-post-button.tag index 071af0a158..ca380b06ea 100644 --- a/src/web/app/desktop/tags/ui-header-post-button.tag +++ b/src/web/app/desktop/tags/ui-header-post-button.tag @@ -35,7 +35,8 @@ </style> <script> - @post = (e) ~> - @parent.parent.open-post-form! + this.post = e => { + this.parent.parent.openPostForm(); + }; </script> </mk-ui-header-post-button> diff --git a/src/web/app/desktop/tags/ui-header-search.tag b/src/web/app/desktop/tags/ui-header-search.tag index 10ebe1da98..ff1a313cec 100644 --- a/src/web/app/desktop/tags/ui-header-search.tag +++ b/src/web/app/desktop/tags/ui-header-search.tag @@ -32,10 +32,11 @@ </style> <script> - @mixin \page + this.mixin('page'); - @onsubmit = (e) ~> - e.prevent-default! - @page '/search:' + @refs.q.value + this.onsubmit = e => { + e.preventDefault(); + this.page('/search:' + this.refs.q.value); + }; </script> </mk-ui-header-search> diff --git a/src/web/app/desktop/tags/ui-header.tag b/src/web/app/desktop/tags/ui-header.tag index 41b74181f9..4ab1789309 100644 --- a/src/web/app/desktop/tags/ui-header.tag +++ b/src/web/app/desktop/tags/ui-header.tag @@ -21,7 +21,7 @@ <style> :scope display block - position fixed + position sticky top 0 z-index 1024 width 100% @@ -80,6 +80,5 @@ display none </style> - - <script>@mixin \i</script> + <script>this.mixin('i');</script> </mk-ui-header> diff --git a/src/web/app/desktop/tags/ui-notification.tag b/src/web/app/desktop/tags/ui-notification.tag index 5f8583a391..34f310844e 100644 --- a/src/web/app/desktop/tags/ui-notification.tag +++ b/src/web/app/desktop/tags/ui-notification.tag @@ -22,23 +22,23 @@ </style> <script> - @on \mount ~> - Velocity @root, { - top: \0px - } { - duration: 500ms - easing: \ease-out - } + this.on('mount', () => { + Velocity(this.root, { + top: '0px' + }, { + duration: 500, + easing: 'ease-out' + }) - set-timeout ~> - Velocity @root, { - top: \-64px - } { - duration: 500ms - easing: \ease-out - complete: ~> - @unmount! - } - , 6000ms + setTimeout(() => { + Velocity(this.root, { + top: '-64px' + }, { + duration: 500, + easing: 'ease-out', + complete: () => this.unmount() + }); + }, 6000); + }); </script> </mk-ui-notification> diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag index e40e5c88e2..0669d252af 100644 --- a/src/web/app/desktop/tags/ui.tag +++ b/src/web/app/desktop/tags/ui.tag @@ -9,29 +9,29 @@ <style> :scope display block - </style> <script> - @mixin \i + this.mixin('i'); - @open-post-form = ~> - riot.mount document.body.append-child document.create-element \mk-post-form-window + this.openPostForm = () => { + riot.mount(document.body.appendChild(document.createElement('mk-post-form-window'))); + }; - @set-root-layout = ~> - @root.style.padding-top = @refs.header.root.client-height + \px + this.on('mount', () => { + document.addEventListener('keydown', this.onkeydown); + }); - @on \mount ~> - @set-root-layout! - document.add-event-listener \keydown @onkeydown + this.on('unmount', () => { + document.removeEventListener('keydown', this.onkeydown); + }); - @on \unmount ~> - document.remove-event-listener \keydown @onkeydown + this.onkeydown = e => { + if (e.target.tagName == 'input' || e.target.tagName == 'textarea') return; - @onkeydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 80 or e.which == 78 # p or n - e.prevent-default! - @open-post-form! + if (e.which == 80 || e.which == 78) { // p or n + e.preventDefault(); + this.openPostForm(); + } + }; </script> </mk-ui> diff --git a/src/web/app/desktop/tags/user-followers-window.tag b/src/web/app/desktop/tags/user-followers-window.tag index e70682c19a..a4a24d6673 100644 --- a/src/web/app/desktop/tags/user-followers-window.tag +++ b/src/web/app/desktop/tags/user-followers-window.tag @@ -15,5 +15,5 @@ border-radius 4px </style> - <script>@user = @opts.user</script> + <script>this.user = this.opts.user</script> </mk-user-followers-window> diff --git a/src/web/app/desktop/tags/user-followers.tag b/src/web/app/desktop/tags/user-followers.tag index 14f20b831e..f43e87de8a 100644 --- a/src/web/app/desktop/tags/user-followers.tag +++ b/src/web/app/desktop/tags/user-followers.tag @@ -7,16 +7,17 @@ </style> <script> - @mixin \api + this.mixin('api'); - @user = @opts.user + this.user = this.opts.user; - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/followers do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb + this.fetch = (iknow, limit, cursor, cb) => { + this.api('users/followers', { + user_id: this.user.id, + iknow: iknow, + limit: limit, + cursor: cursor ? cursor : undefined + }).then(cb); + }; </script> </mk-user-followers> diff --git a/src/web/app/desktop/tags/user-following-window.tag b/src/web/app/desktop/tags/user-following-window.tag index 4e25e8a3ca..6dbf3b05e9 100644 --- a/src/web/app/desktop/tags/user-following-window.tag +++ b/src/web/app/desktop/tags/user-following-window.tag @@ -15,5 +15,5 @@ border-radius 4px </style> - <script>@user = @opts.user</script> + <script>this.user = this.opts.user</script> </mk-user-following-window> diff --git a/src/web/app/desktop/tags/user-following.tag b/src/web/app/desktop/tags/user-following.tag index e21d391d4d..f2d21b3fed 100644 --- a/src/web/app/desktop/tags/user-following.tag +++ b/src/web/app/desktop/tags/user-following.tag @@ -7,16 +7,17 @@ </style> <script> - @mixin \api + this.mixin('api'); - @user = @opts.user + this.user = this.opts.user; - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/following do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb + this.fetch = (iknow, limit, cursor, cb) => { + this.api('users/following', { + user_id: this.user.id, + iknow: iknow, + limit: limit, + cursor: cursor ? cursor : undefined + }).then(cb); + }; </script> </mk-user-following> diff --git a/src/web/app/desktop/tags/user-graphs.tag b/src/web/app/desktop/tags/user-graphs.tag index 6d49c990ae..e673f7700b 100644 --- a/src/web/app/desktop/tags/user-graphs.tag +++ b/src/web/app/desktop/tags/user-graphs.tag @@ -34,7 +34,8 @@ </style> <script> - @on \mount ~> - @trigger \loaded + this.on('mount', () => { + this.trigger('loaded'); + }); </script> </mk-user-graphs> diff --git a/src/web/app/desktop/tags/user-header.tag b/src/web/app/desktop/tags/user-header.tag index d49b6498b5..c265357169 100644 --- a/src/web/app/desktop/tags/user-header.tag +++ b/src/web/app/desktop/tags/user-header.tag @@ -104,39 +104,42 @@ </style> <script> - @mixin \i - @mixin \update-banner - @mixin \NotImplementedException + this.mixin('i'); + this.mixin('update-banner'); + this.mixin('NotImplementedException'); - @user = @opts.user + this.user = this.opts.user; - @on \mount ~> - window.add-event-listener \load @scroll - window.add-event-listener \scroll @scroll - window.add-event-listener \resize @scroll + this.on('mount', () => { + window.addEventListener('load', this.scroll); + window.addEventListener('scroll', this.scroll); + window.addEventListener('resize', this.scroll); + }); - @on \unmount ~> - window.remove-event-listener \load @scroll - window.remove-event-listener \scroll @scroll - window.remove-event-listener \resize @scroll + this.on('unmount', () => { + window.removeEventListener('load', this.scroll); + window.removeEventListener('scroll', this.scroll); + window.removeEventListener('resize', this.scroll); + }); - @scroll = ~> - top = window.scroll-y - height = 280px + this.scroll = () => { + const top = window.scrollY; + const height = 280/*px*/; - pos = 50 - ((top / height) * 50) - @refs.banner.style.background-position = 'center ' + pos + '%' + const pos = 50 - ((top / height) * 50); + this.refs.banner.style.backgroundPosition = `center ${pos}%`; - blur = top / 32 - if blur <= 10 - @refs.banner.style.filter = 'blur(' + blur + 'px)' + const blur = top / 32 + if (blur <= 10) this.refs.banner.style.filter = `blur(${blur}px)`; + }; - @on-update-banner = ~> - if not @SIGNIN or @I.id != @user.id - return + this.onUpdateBanner = () => { + if (!this.SIGNIN || this.I.id != this.user.id) return; - @update-banner @I, (i) ~> - @user.banner_url = i.banner_url - @update! + this.updateBanner(this.I, i => { + this.user.banner_url = i.banner_url; + this.update(); + }); + }; </script> </mk-user-header> diff --git a/src/web/app/desktop/tags/user-home.tag b/src/web/app/desktop/tags/user-home.tag index 50fe1cbfad..759a57581d 100644 --- a/src/web/app/desktop/tags/user-home.tag +++ b/src/web/app/desktop/tags/user-home.tag @@ -35,10 +35,12 @@ </style> <script> - @user = @opts.user + this.user = this.opts.user; - @on \mount ~> - @refs.tl.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.tl.on('loaded', () => { + this.trigger('loaded'); + }); + }); </script> </mk-user-home> diff --git a/src/web/app/desktop/tags/user-photos.tag b/src/web/app/desktop/tags/user-photos.tag index 3d24422dea..86f12aceb9 100644 --- a/src/web/app/desktop/tags/user-photos.tag +++ b/src/web/app/desktop/tags/user-photos.tag @@ -57,30 +57,36 @@ </style> <script> - @mixin \api - @mixin \is-promise + this.mixin('api'); + this.mixin('is-promise'); - @images = [] - @initializing = true + this.images = []; + this.initializing = true; + this.user = null; + this.userPromise = this.isPromise(this.opts.user) + ? this.opts.user + : Promise.resolve(this.opts.user); - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user + this.on('mount', () => { + this.userPromise.then(user => { + this.update({ + user: user + }); - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @update! - - @api \users/posts do - user_id: @user.id - with_media: true - limit: 9posts - .then (posts) ~> - @initializing = false - posts.for-each (post) ~> - post.media.for-each (image) ~> - if @images.length < 9 - @images.push image - @update! + this.api('users/posts', { + user_id: this.user.id, + with_media: true, + limit: 9 + }).then(posts => { + this.initializing = false; + posts.forEach(post => { + post.media.forEach(media => { + if (this.images.length < 9) this.images.push(media); + }); + }); + this.update(); + }); + }); + }); </script> </mk-user-photos> diff --git a/src/web/app/desktop/tags/user-preview.tag b/src/web/app/desktop/tags/user-preview.tag index 7d140c0957..f9806534e2 100644 --- a/src/web/app/desktop/tags/user-preview.tag +++ b/src/web/app/desktop/tags/user-preview.tag @@ -97,47 +97,50 @@ </style> <script> - @mixin \i - @mixin \api + this.mixin('i'); + this.mixin('api'); - @u = @opts.user - @user = null - @user-promise = - if typeof @u == \string - new Promise (resolve, reject) ~> - @api \users/show do - user_id: if @u.0 == \@ then undefined else @u - username: if @u.0 == \@ then @u.substr 1 else undefined - .then (user) ~> - resolve user - else - Promise.resolve @u + this.u = this.opts.user; + this.user = null; + this.userPromise = + typeof this.u == 'string' ? + new Promise((resolve, reject) => { + this.api('users/show', { + user_id: this.u[0] == '@' ? undefined : this.u, + username: this.u[0] == '@' ? this.u.substr(1) : undefined + }).then(resolve); + }) + : Promise.resolve(this.u); - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @update! + this.on('mount', () => { + this.userPromise.then(user => { + this.update({ + user: user + }); + }); - Velocity @root, { - opacity: 0 - 'margin-top': \-8px - } 0ms - Velocity @root, { - opacity: 1 + Velocity(this.root, { + opacity: 0, + 'margin-top': '-8px' + }, 0); + Velocity(this.root, { + opacity: 1, 'margin-top': 0 - } { - duration: 200ms - easing: \ease-out - } + }, { + duration: 200, + easing: 'ease-out' + }); + }); - @close = ~> - Velocity @root, { - opacity: 0 - 'margin-top': \-8px - } { - duration: 200ms - easing: \ease-out - complete: ~> @unmount! - } + this.close = () => { + Velocity(this.root, { + opacity: 0, + 'margin-top': '-8px' + }, { + duration: 200, + easing: 'ease-out', + complete: () => this.unmount() + }); + }; </script> </mk-user-preview> diff --git a/src/web/app/desktop/tags/user-profile.tag b/src/web/app/desktop/tags/user-profile.tag index d8984e971d..03697fd5f3 100644 --- a/src/web/app/desktop/tags/user-profile.tag +++ b/src/web/app/desktop/tags/user-profile.tag @@ -80,20 +80,22 @@ </style> <script> - @age = require \s-age + this.age = require('s-age'); - @mixin \i + this.mixin('i'); - @user = @opts.user + this.user = this.opts.user; - @show-following = ~> - window = document.body.append-child document.create-element \mk-user-following-window - riot.mount window, do - user: @user + this.showFollowing = () => { + riot.mount(document.body.appendChild(document.createElement('mk-user-following-window')), { + user: this.user + }); + }; - @show-followers = ~> - window = document.body.append-child document.create-element \mk-user-followers-window - riot.mount window, do - user: @user + this.showFollowers = () => { + riot.mount(document.body.appendChild(document.createElement('mk-user-followers-window')), { + user: this.user + }); + }; </script> </mk-user-profile> diff --git a/src/web/app/desktop/tags/user-timeline.tag b/src/web/app/desktop/tags/user-timeline.tag index b0ed542a43..4851eb0a18 100644 --- a/src/web/app/desktop/tags/user-timeline.tag +++ b/src/web/app/desktop/tags/user-timeline.tag @@ -46,93 +46,89 @@ </style> <script> - @mixin \api - @mixin \is-promise - @mixin \get-post-summary + this.mixin('api'); + this.mixin('is-promise'); + this.mixin('get-post-summary'); - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @is-loading = true - @is-empty = false - @more-loading = false - @unread-count = 0 - @mode = \default + this.user = null; + this.userPromise = this.isPromise(this.opts.user) + ? this.opts.user + : Promise.resolve(this.opts.user); + this.isLoading = true; + this.isEmpty = false; + this.moreLoading = false; + this.unreadCount = 0; + this.mode = 'default'; - @on \mount ~> - document.add-event-listener \visibilitychange @window-on-visibilitychange, false - document.add-event-listener \keydown @on-document-keydown - window.add-event-listener \scroll @on-scroll + this.on('mount', () => { + document.addEventListener('keydown', this.onDocumentKeydown); + window.addEventListener('scroll', this.onScroll); - @user-promise.then (user) ~> - @user = user - @update! + this.userPromise.then(user => { + this.update({ + user: user + }); - @fetch ~> - @trigger \loaded + this.fetch(() => this.trigger('loaded')); + }); + }); - @on \unmount ~> - document.remove-event-listener \visibilitychange @window-on-visibilitychange - document.remove-event-listener \keydown @on-document-keydown - window.remove-event-listener \scroll @on-scroll + this.on('unmount', () => { + document.removeEventListener('keydown', this.onDocumentKeydown); + window.removeEventListener('scroll', this.onScroll); + }); - @on-document-keydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 84 # t - @refs.timeline.focus! + this.onDocumentKeydown = e => { + if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') { + if (e.which == 84) { // [t] + this.refs.timeline.focus(); + } + } + }; - @fetch = (cb) ~> - @api \users/posts do - user_id: @user.id - with_replies: @mode == \with-replies - .then (posts) ~> - @is-loading = false - @is-empty = posts.length == 0 - @update! - @refs.timeline.set-posts posts - if cb? then cb! - .catch (err) ~> - console.error err - if cb? then cb! + this.fetch = cb => { + this.api('users/posts', { + user_id: this.user.id, + with_replies: this.mode == 'with-replies' + }).then(posts => { + this.update({ + isLoading: false, + isEmpty: posts.length == 0 + }); + this.refs.timeline.setPosts(posts); + if (cb) cb(); + }); + }; - @more = ~> - if @more-loading or @is-loading or @refs.timeline.posts.length == 0 - return - @more-loading = true - @update! - @api \users/posts do - user_id: @user.id - with_replies: @mode == \with-replies - max_id: @refs.timeline.tail!.id - .then (posts) ~> - @more-loading = false - @update! - @refs.timeline.prepend-posts posts - .catch (err) ~> - console.error err + this.more = () => { + if (this.moreLoading || this.isLoading || this.refs.timeline.posts.length == 0) return; + this.update({ + moreLoading: true + }); + this.api('users/posts', { + user_id: this.user.id, + with_replies: this.mode == 'with-replies', + max_id: this.refs.timeline.tail().id + }).then(posts => { + this.update({ + moreLoading: false + }); + this.refs.timeline.prependPosts(posts); + }); + }; - @on-stream-post = (post) ~> - @is-empty = false - @update! - @refs.timeline.add-post post + this.onScroll = () => { + const current = window.scrollY + window.innerHeight; + if (current > document.body.offsetHeight - 16/*遊び*/) { + this.more(); + } + }; - if document.hidden - @unread-count++ - document.title = '(' + @unread-count + ') ' + @get-post-summary post - - @window-on-visibilitychange = ~> - if !document.hidden - @unread-count = 0 - document.title = 'Misskey' - - @on-scroll = ~> - current = window.scroll-y + window.inner-height - if current > document.body.offset-height - 16 # 遊び - @more! - - @set-mode = (mode) ~> - @update do + this.setMode = mode => { + this.update({ mode: mode - @fetch! + }); + this.fetch(); + }; </script> </mk-user-timeline> diff --git a/src/web/app/desktop/tags/user.tag b/src/web/app/desktop/tags/user.tag index 24f2e958a3..c128736183 100644 --- a/src/web/app/desktop/tags/user.tag +++ b/src/web/app/desktop/tags/user.tag @@ -32,20 +32,23 @@ </style> <script> - @mixin \api + this.mixin('api'); - @username = @opts.user - @page = if @opts.page? then @opts.page else \home - @fetching = true - @user = null + this.username = this.opts.user; + this.page = this.opts.page ? this.opts.page : 'home'; + this.fetching = true; + this.user = null; - @on \mount ~> - @api \users/show do - username: @username - .then (user) ~> - @fetching = false - @user = user - @update! - @trigger \loaded + this.on('mount', () => { + this.api('users/show', { + username: this.username + }).then(user => { + this.update({ + fetching: false, + user: user + }); + this.trigger('loaded'); + }); + }); </script> </mk-user> diff --git a/src/web/app/desktop/tags/users-list.tag b/src/web/app/desktop/tags/users-list.tag index 51edd2ee30..c94d0e228d 100644 --- a/src/web/app/desktop/tags/users-list.tag +++ b/src/web/app/desktop/tags/users-list.tag @@ -1,7 +1,9 @@ <mk-users-list> <nav> - <div><span data-is-active={ mode == 'all' } onclick={ setMode.bind(this, 'all') }>すべて<span>{ opts.count }</span></span> - <!-- ↓ https://github.com/riot/riot/issues/2080--><span if={ SIGNIN && opts.youKnowCount != '' } data-is-active={ mode == 'iknow' } onclick={ setMode.bind(this, 'iknow') }>知り合い<span>{ opts.youKnowCount }</span></span> + <div> + <span data-is-active={ mode == 'all' } onclick={ setMode.bind(this, 'all') }>すべて<span>{ opts.count }</span></span> + <!-- ↓ https://github.com/riot/riot/issues/2080--> + <span if={ SIGNIN && opts.youKnowCount != '' } data-is-active={ mode == 'iknow' } onclick={ setMode.bind(this, 'iknow') }>知り合い<span>{ opts.youKnowCount }</span></span> </div> </nav> <div class="users" if={ !fetching && users.length != 0 }> @@ -9,8 +11,10 @@ <mk-list-user user={ this }></mk-list-user> </div> </div> - <button class="more" if={ !fetching && next != null } onclick={ more } disabled={ moreFetching }><span if={ !moreFetching }>もっと</span><span if={ moreFetching }>読み込み中 - <mk-ellipsis></mk-ellipsis></span></button> + <button class="more" if={ !fetching && next != null } onclick={ more } disabled={ moreFetching }> + <span if={ !moreFetching }>もっと</span> + <span if={ moreFetching }>読み込み中<mk-ellipsis></mk-ellipsis></span> + </button> <p class="no" if={ !fetching && users.length == 0 }>{ opts.noUsers }</p> <p class="fetching" if={ fetching }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます <mk-ellipsis></mk-ellipsis> @@ -88,47 +92,50 @@ </style> <script> - @mixin \i + this.mixin('i'); - @limit = 30users - @mode = \all + this.limit = 30; + this.mode = 'all'; - @fetching = true - @more-fetching = false + this.fetching = true; + this.moreFetching = false; - @on \mount ~> - @fetch ~> - @trigger \loaded + this.on('mount', () => { + this.fetch(() => this.trigger('loaded')); + }); - @fetch = (cb) ~> - @fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - null - @users = obj.users - @next = obj.next - @fetching = false - @update! - if cb? then cb! + this.fetch = cb => { + this.update({ + fetching: true + }); + this.opts.fetch(this.mode == 'iknow', this.limit, null, obj => { + this.update({ + fetching: false, + users: obj.users, + next: obj.next + }); + if (cb) cb(); + }); + }; - @more = ~> - @more-fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - @cursor - @users = @users.concat obj.users - @next = obj.next - @more-fetching = false - @update! + this.more = () => { + this.update({ + moreFetching: true + }); + this.opts.fetch(this.mode == 'iknow', this.limit, this.cursor, obj => { + this.update({ + moreFetching: false, + users: this.users.concat(obj.users), + next: obj.next + }); + }); + }; - @set-mode = (mode) ~> - @update do + this.setMode = mode => { + this.update({ mode: mode - - @fetch! + }); + this.fetch(); + }; </script> </mk-users-list> diff --git a/src/web/app/desktop/tags/window.tag b/src/web/app/desktop/tags/window.tag index 323c294c2c..3e7da90769 100644 --- a/src/web/app/desktop/tags/window.tag +++ b/src/web/app/desktop/tags/window.tag @@ -192,328 +192,354 @@ </style> <script> - @min-height = 40px - @min-width = 200px + const contains = require('../../common/scripts/contains'); - @is-modal = if @opts.is-modal? then @opts.is-modal else false - @can-close = if @opts.can-close? then @opts.can-close else true - @is-flexible = !@opts.height? - @can-resize = not @is-flexible + this.minHeight = 40; + this.minWidth = 200; - @on \mount ~> - @refs.main.style.width = @opts.width || \530px - @refs.main.style.height = @opts.height || \auto + this.isModal = this.opts.isModal != null ? this.opts.isModal : false; + this.canClose = this.opts.canClose != null ? this.opts.canClose : true; + this.isFlexible = this.opts.height == null; + this.canResize = !this.isFlexible; - @refs.main.style.top = \15% - @refs.main.style.left = (window.inner-width / 2) - (@refs.main.offset-width / 2) + \px + this.on('mount', () => { + this.refs.main.style.width = this.opts.width || '530px'; + this.refs.main.style.height = this.opts.height || 'auto'; - @refs.header.add-event-listener \contextmenu (e) ~> - e.prevent-default! + this.refs.main.style.top = '15%'; + this.refs.main.style.left = (window.innerWidth / 2) - (this.refs.main.offsetWidth / 2) + 'px'; - window.add-event-listener \resize @on-browser-resize + this.refs.header.addEventListener('contextmenu', e => { + e.preventDefault(); + }); - @open! + window.addEventListener('resize', this.onBrowserResize); - @on \unmount ~> - window.remove-event-listener \resize @on-browser-resize + this.open(); + }); - @on-browser-resize = ~> - position = @refs.main.get-bounding-client-rect! - browser-width = window.inner-width - browser-height = window.inner-height - window-width = @refs.main.offset-width - window-height = @refs.main.offset-height + this.on('unmount', () => { + window.removeEventListener('resize', this.onBrowserResize); + }); - if position.left < 0 - @refs.main.style.left = 0 + this.onBrowserResize = () => { + const position = this.refs.main.getBoundingClientRect(); + const browserWidth = window.innerWidth; + const browserHeight = window.innerHeight; + const windowWidth = this.refs.main.offsetWidth; + const windowHeight = this.refs.main.offsetHeight; + if (position.left < 0) this.refs.main.style.left = 0; + if (position.top < 0) this.refs.main.style.top = 0; + if (position.left + windowWidth > browserWidth) this.refs.main.style.left = browserWidth - windowWidth + 'px'; + if (position.top + windowHeight > browserHeight) this.refs.main.style.top = browserHeight - windowHeight + 'px'; + }; - if position.top < 0 - @refs.main.style.top = 0 + this.open = () => { + this.trigger('opening'); - if position.left + window-width > browser-width - @refs.main.style.left = browser-width - window-width + \px + this.top(); - if position.top + window-height > browser-height - @refs.main.style.top = browser-height - window-height + \px - - @open = ~> - @trigger \opening - - @top! - - if @is-modal - @refs.bg.style.pointer-events = \auto - Velocity @refs.bg, \finish true - Velocity @refs.bg, { + if (this.isModal) { + this.refs.bg.style.pointerEvents = 'auto'; + Velocity(this.refs.bg, 'finish', true); + Velocity(this.refs.bg, { opacity: 1 - } { - queue: false - duration: 100ms - easing: \linear - } + }, { + queue: false, + duration: 100, + easing: 'linear' + }); + } - @refs.main.style.pointer-events = \auto - Velocity @refs.main, \finish true - Velocity @refs.main, {scale: 1.1} 0ms - Velocity @refs.main, { - opacity: 1 + this.refs.main.style.pointerEvents = 'auto'; + Velocity(this.refs.main, 'finish', true); + Velocity(this.refs.main, { scale: 1.1 }, 0); + Velocity(this.refs.main, { + opacity: 1, scale: 1 - } { - queue: false - duration: 200ms - easing: \ease-out - } + }, { + queue: false, + duration: 200, + easing: 'ease-out' + }); - #@refs.main.focus! + //this.refs.main.focus(); - set-timeout ~> - @trigger \opened - , 300ms + setTimeout(() => { + this.trigger('opened'); + }, 300); + }; - @close = ~> - @trigger \closing + this.close = () => { + this.trigger('closing'); - if @is-modal - @refs.bg.style.pointer-events = \none - Velocity @refs.bg, \finish true - Velocity @refs.bg, { + if (this.isModal) { + this.refs.bg.style.pointerEvents = 'none'; + Velocity(this.refs.bg, 'finish', true); + Velocity(this.refs.bg, { opacity: 0 - } { - queue: false - duration: 300ms - easing: \linear - } + }, { + queue: false, + duration: 300, + easing: 'linear' + }); + } - @refs.main.style.pointer-events = \none - Velocity @refs.main, \finish true - Velocity @refs.main, { - opacity: 0 + this.refs.main.style.pointerEvents = 'none'; + Velocity(this.refs.main, 'finish', true); + Velocity(this.refs.main, { + opacity: 0, scale: 0.8 - } { - queue: false - duration: 300ms + }, { + queue: false, + duration: 300, easing: [ 0.5, -0.5, 1, 0.5 ] - } + }); - set-timeout ~> - @trigger \closed - , 300ms + setTimeout(() => { + this.trigger('closed'); + }, 300); + }; - # 最前面へ移動します - @top = ~> - z = 0 + // 最前面へ移動します + this.top = () => { + let z = 0; - ws = document.query-selector-all \mk-window - ws.for-each (w) !~> - if w == @root then return - m = w.query-selector ':scope > .main' - mz = Number(document.default-view.get-computed-style m, null .z-index) - if mz > z then z := mz + const ws = document.querySelectorAll('mk-window'); + ws.forEach(w => { + if (w == this.root) return; + const m = w.querySelector(':scope > .main'); + const mz = Number(document.defaultView.getComputedStyle(m, null).zIndex); + if (mz > z) z = mz; + }); - if z > 0 - @refs.main.style.z-index = z + 1 - if @is-modal then @refs.bg.style.z-index = z + 1 + if (z > 0) { + this.refs.main.style.zIndex = z + 1; + if (this.isModal) this.refs.bg.style.zIndex = z + 1; + } + }; - @repel-move = (e) ~> - e.stop-propagation! - return true + this.repelMove = e => { + e.stopPropagation(); + return true; + }; - @bg-click = ~> - if @can-close - @close! + this.bgClick = () => { + if (this.canClose) this.close(); + }; - @on-body-mousedown = (e) ~> - @top! - true + this.onBodyMousedown = () => { + this.top(); + }; - # ヘッダー掴み時 - @on-header-mousedown = (e) ~> - e.prevent-default! + // ヘッダー掴み時 + this.onHeaderMousedown = e => { + e.preventDefault(); - if not contains @refs.main, document.active-element - @refs.main.focus! + if (!contains(this.refs.main, document.activeElement)) this.refs.main.focus(); - position = @refs.main.get-bounding-client-rect! + const position = this.refs.main.getBoundingClientRect(); - click-x = e.client-x - click-y = e.client-y - move-base-x = click-x - position.left - move-base-y = click-y - position.top - browser-width = window.inner-width - browser-height = window.inner-height - window-width = @refs.main.offset-width - window-height = @refs.main.offset-height + const clickX = e.clientX; + const clickY = e.clientY; + const moveBaseX = clickX - position.left; + const moveBaseY = clickY - position.top; + const browserWidth = window.innerWidth; + const browserHeight = window.innerHeight; + const windowWidth = this.refs.main.offsetWidth; + const windowHeight = this.refs.main.offsetHeight; - # 動かした時 - drag-listen (me) ~> - move-left = me.client-x - move-base-x - move-top = me.client-y - move-base-y + // 動かした時 + dragListen(me => { + let moveLeft = me.clientX - moveBaseX; + let moveTop = me.clientY - moveBaseY; - # 上はみ出し - if move-top < 0 - move-top = 0 + // 上はみ出し + if (moveTop < 0) moveTop = 0; - # 左はみ出し - if move-left < 0 - move-left = 0 + // 左はみ出し + if (moveLeft < 0) moveLeft = 0; - # 下はみ出し - if move-top + window-height > browser-height - move-top = browser-height - window-height + // 下はみ出し + if (moveTop + windowHeight > browserHeight) moveTop = browserHeight - windowHeight; - # 右はみ出し - if move-left + window-width > browser-width - move-left = browser-width - window-width + // 右はみ出し + if (moveLeft + windowWidth > browserWidth) moveLeft = browserWidth - windowWidth; - @refs.main.style.left = move-left + \px - @refs.main.style.top = move-top + \px + this.refs.main.style.left = moveLeft + 'px'; + this.refs.main.style.top = moveTop + 'px'; + }); + }; - # 上ハンドル掴み時 - @on-top-handle-mousedown = (e) ~> - e.prevent-default! + // 上ハンドル掴み時 + this.onTopHandleMousedown = e => { + e.preventDefault(); - base = e.client-y - height = parse-int((get-computed-style @refs.main, '').height, 10) - top = parse-int((get-computed-style @refs.main, '').top, 10) + const base = e.clientY; + const height = parseInt(getComputedStyle(this.refs.main, '').height, 10); + const top = parseInt(getComputedStyle(this.refs.main, '').top, 10); - # 動かした時 - drag-listen (me) ~> - move = me.client-y - base - if top + move > 0 - if height + -move > @min-height - @apply-transform-height height + -move - @apply-transform-top top + move - else # 最小の高さより小さくなろうとした時 - @apply-transform-height @min-height - @apply-transform-top top + (height - @min-height) - else # 上のはみ出し時 - @apply-transform-height top + height - @apply-transform-top 0 + // 動かした時 + dragListen(me => { + const move = me.clientY - base; + if (top + move > 0) { + if (height + -move > this.minHeight) { + this.applyTransformHeight(height + -move); + this.applyTransformTop(top + move); + } else { // 最小の高さより小さくなろうとした時 + this.applyTransformHeight(this.minHeight); + this.applyTransformTop(top + (height - this.minHeight)); + } + } else { // 上のはみ出し時 + this.applyTransformHeight(top + height); + this.applyTransformTop(0); + } + }); + }; - # 右ハンドル掴み時 - @on-right-handle-mousedown = (e) ~> - e.prevent-default! + // 右ハンドル掴み時 + this.onRightHandleMousedown = e => { + e.preventDefault(); - base = e.client-x - width = parse-int((get-computed-style @refs.main, '').width, 10) - left = parse-int((get-computed-style @refs.main, '').left, 10) - browser-width = window.inner-width + const base = e.clientX; + const width = parseInt(getComputedStyle(this.refs.main, '').width, 10); + const left = parseInt(getComputedStyle(this.refs.main, '').left, 10); + const browserWidth = window.innerWidth; - # 動かした時 - drag-listen (me) ~> - move = me.client-x - base - if left + width + move < browser-width - if width + move > @min-width - @apply-transform-width width + move - else # 最小の幅より小さくなろうとした時 - @apply-transform-width @min-width - else # 右のはみ出し時 - @apply-transform-width browser-width - left + // 動かした時 + dragListen(me => { + const move = me.clientX - base; + if (left + width + move < browserWidth) { + if (width + move > this.minWidth) { + this.applyTransformWidth(width + move); + } else { // 最小の幅より小さくなろうとした時 + this.applyTransformWidth(this.minWidth); + } + } else { // 右のはみ出し時 + this.applyTransformWidth(browserWidth - left); + } + }); + }; - # 下ハンドル掴み時 - @on-bottom-handle-mousedown = (e) ~> - e.prevent-default! + // 下ハンドル掴み時 + this.onBottomHandleMousedown = e => { + e.preventDefault(); - base = e.client-y - height = parse-int((get-computed-style @refs.main, '').height, 10) - top = parse-int((get-computed-style @refs.main, '').top, 10) - browser-height = window.inner-height + const base = e.clientY; + const height = parseInt(getComputedStyle(this.refs.main, '').height, 10); + const top = parseInt(getComputedStyle(this.refs.main, '').top, 10); + const browserHeight = window.innerHeight; - # 動かした時 - drag-listen (me) ~> - move = me.client-y - base - if top + height + move < browser-height - if height + move > @min-height - @apply-transform-height height + move - else # 最小の高さより小さくなろうとした時 - @apply-transform-height @min-height - else # 下のはみ出し時 - @apply-transform-height browser-height - top + // 動かした時 + dragListen(me => { + const move = me.clientY - base; + if (top + height + move < browserHeight) { + if (height + move > this.minHeight) { + this.applyTransformHeight(height + move); + } else { // 最小の高さより小さくなろうとした時 + this.applyTransformHeight(this.minHeight); + } + } else { // 下のはみ出し時 + this.applyTransformHeight(browserHeight - top); + } + }); + }; - # 左ハンドル掴み時 - @on-left-handle-mousedown = (e) ~> - e.prevent-default! + // 左ハンドル掴み時 + this.onLeftHandleMousedown = e => { + e.preventDefault(); - base = e.client-x - width = parse-int((get-computed-style @refs.main, '').width, 10) - left = parse-int((get-computed-style @refs.main, '').left, 10) + const base = e.clientX; + const width = parseInt(getComputedStyle(this.refs.main, '').width, 10); + const left = parseInt(getComputedStyle(this.refs.main, '').left, 10); - # 動かした時 - drag-listen (me) ~> - move = me.client-x - base - if left + move > 0 - if width + -move > @min-width - @apply-transform-width width + -move - @apply-transform-left left + move - else # 最小の幅より小さくなろうとした時 - @apply-transform-width @min-width - @apply-transform-left left + (width - @min-width) - else # 左のはみ出し時 - @apply-transform-width left + width - @apply-transform-left 0 + // 動かした時 + dragListen(me => { + const move = me.clientX - base; + if (left + move > 0) { + if (width + -move > this.minWidth) { + this.applyTransformWidth(width + -move); + this.applyTransformLeft(left + move); + } else { // 最小の幅より小さくなろうとした時 + this.applyTransformWidth(this.minWidth); + this.applyTransformLeft(left + (width - this.minWidth)); + } + } else { // 左のはみ出し時 + this.applyTransformWidth(left + width); + this.applyTransformLeft(0); + } + }); + }; - # 左上ハンドル掴み時 - @on-top-left-handle-mousedown = (e) ~> - @on-top-handle-mousedown e - @on-left-handle-mousedown e + // 左上ハンドル掴み時 + this.onTopLeftHandleMousedown = e => { + this.onTopHandleMousedown(e); + this.onLeftHandleMousedown(e); + }; - # 右上ハンドル掴み時 - @on-top-right-handle-mousedown = (e) ~> - @on-top-handle-mousedown e - @on-right-handle-mousedown e + // 右上ハンドル掴み時 + this.onTopRightHandleMousedown = e => { + this.onTopHandleMousedown(e); + this.onRightHandleMousedown(e); + }; - # 右下ハンドル掴み時 - @on-bottom-right-handle-mousedown = (e) ~> - @on-bottom-handle-mousedown e - @on-right-handle-mousedown e + // 右下ハンドル掴み時 + this.onBottomRightHandleMousedown = e => { + this.onBottomHandleMousedown(e); + this.onRightHandleMousedown(e); + }; - # 左下ハンドル掴み時 - @on-bottom-left-handle-mousedown = (e) ~> - @on-bottom-handle-mousedown e - @on-left-handle-mousedown e + // 左下ハンドル掴み時 + this.onBottomLeftHandleMousedown = e => { + this.onBottomHandleMousedown(e); + this.onLeftHandleMousedown(e); + }; - # 高さを適用 - @apply-transform-height = (height) ~> - @refs.main.style.height = height + \px + // 高さを適用 + this.applyTransformHeight = height => { + this.refs.main.style.height = height + 'px'; + }; - # 幅を適用 - @apply-transform-width = (width) ~> - @refs.main.style.width = width + \px + // 幅を適用 + this.applyTransformWidth = width => { + this.refs.main.style.width = width + 'px'; + }; - # Y座標を適用 - @apply-transform-top = (top) ~> - @refs.main.style.top = top + \px + // Y座標を適用 + this.applyTransformTop = top => { + this.refs.main.style.top = top + 'px'; + }; - # X座標を適用 - @apply-transform-left = (left) ~> - @refs.main.style.left = left + \px + // X座標を適用 + this.applyTransformLeft = left => { + this.refs.main.style.left = left + 'px'; + }; - function drag-listen fn - window.add-event-listener \mousemove fn - window.add-event-listener \mouseleave drag-clear.bind null fn - window.add-event-listener \mouseup drag-clear.bind null fn + function dragListen(fn) { + window.addEventListener('mousemove', fn); + window.addEventListener('mouseleave', dragClear.bind(null, fn)); + window.addEventListener('mouseup', dragClear.bind(null, fn)); + } - function drag-clear fn - window.remove-event-listener \mousemove fn - window.remove-event-listener \mouseleave drag-clear - window.remove-event-listener \mouseup drag-clear + function dragClear(fn) { + window.removeEventListener('mousemove', fn); + window.removeEventListener('mouseleave', dragClear); + window.removeEventListener('mouseup', dragClear); + } - @ondragover = (e) ~> - e.data-transfer.drop-effect = \none + this.ondragover = e => { + e.dataTransfer.dropEffect = 'none'; + }; - @on-keydown = (e) ~> - if e.which == 27 # Esc - if @can-close - e.prevent-default! - e.stop-propagation! - @close! + this.onKeydown = e => { + if (e.which == 27) { // Esc + if (this.canClose) { + e.preventDefault(); + e.stopPropagation(); + this.close(); + } + } + }; - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - return false </script> </mk-window> diff --git a/src/web/app/dev/tags/new-app-form.tag b/src/web/app/dev/tags/new-app-form.tag index 86e694e94e..e01be512fb 100644 --- a/src/web/app/dev/tags/new-app-form.tag +++ b/src/web/app/dev/tags/new-app-form.tag @@ -178,66 +178,75 @@ </style> <script> - @mixin \api + this.mixin('api'); - @nid-state = null + this.nidState = null; - @on-change-nid = ~> - nid = @refs.nid.value + this.onChangeNid = () => { + const nid = this.refs.nid.value; - if nid == '' - @nid-state = null - @update! - return + if (nid == '') { + this.update({ + nidState: null + }); + return; + } - err = switch - | not nid.match /^[a-zA-Z0-9\-]+$/ => \invalid-format - | nid.length < 3chars => \min-range - | nid.length > 30chars => \max-range - | _ => null + const err = + !nid.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' : + nid.length < 3 ? 'min-range' : + nid.length > 30 ? 'max-range' : + null; - if err? - @nid-state = err - @update! - else - @nid-state = \wait - @update! + if (err) { + this.update({ + nidState: err + }); + return; + } - @api \app/name_id/available do - name_id: nid - .then (result) ~> - if result.available - @nid-state = \ok - else - @nid-state = \unavailable - @update! - .catch (err) ~> - @nid-state = \error - @update! + this.update({ + nidState: 'wait' + }); - @onsubmit = ~> - name = @refs.name.value - nid = @refs.nid.value - description = @refs.description.value - cb = @refs.cb.value - permission = [] + this.api('app/name_id/available', { + name_id: nid + }).then(result => { + this.update({ + nidState: result.available ? 'ok' : 'unavailable' + }); + }).catch(err => { + this.update({ + nidState: 'error' + }); + }); + }; - @refs.permission.query-selector-all \input .for-each (el) ~> - if el.checked then permission.push el.value + this.onsubmit = () => { + const name = this.refs.name.value; + const nid = this.refs.nid.value; + const description = this.refs.description.value; + const cb = this.refs.cb.value; + const permission = []; - locker = document.body.append-child document.create-element \mk-locker + this.refs.permission.querySelectorAll('input').forEach(el => { + if (el.checked) permission.push(el.value); + }); - @api \app/create do - name: name - name_id: nid - description: description - callback_url: cb - permission: permission.join \, - .then ~> - location.href = '/apps' - .catch ~> - alert 'アプリの作成に失敗しました。再度お試しください。' + const locker = document.body.appendChild(document.createElement('mk-locker')); - locker.parent-node.remove-child locker + this.api('app/create', { + name: name, + name_id: nid, + description: description, + callback_url: cb, + permission: permission.join(',') + }).then(() => { + location.href = '/apps'; + }).catch(() => { + alert('アプリの作成に失敗しました。再度お試しください。'); + locker.parentNode.removeChild(locker); + }); + }; </script> </mk-new-app-form> diff --git a/src/web/app/dev/tags/pages/app.tag b/src/web/app/dev/tags/pages/app.tag index 7eaf9decf6..b25e0d8595 100644 --- a/src/web/app/dev/tags/pages/app.tag +++ b/src/web/app/dev/tags/pages/app.tag @@ -12,19 +12,21 @@ <style> :scope display block - </style> <script> - @mixin \api + this.mixin('api'); - @fetching = true + this.fetching = true; - @on \mount ~> - @api \app/show do - app_id: @opts.app - .then (app) ~> - @app = app - @fetching = false - @update! + this.on('mount', () => { + this.api('app/show', { + app_id: this.opts.app + }).then(app => { + this.update({ + fetching: false, + app: app + }); + }); + }); </script> </mk-app-page> diff --git a/src/web/app/dev/tags/pages/apps.tag b/src/web/app/dev/tags/pages/apps.tag index 03806c6da5..43db70fcf2 100644 --- a/src/web/app/dev/tags/pages/apps.tag +++ b/src/web/app/dev/tags/pages/apps.tag @@ -13,18 +13,21 @@ <style> :scope display block - </style> <script> - @mixin \api + this.mixin('api'); - @fetching = true + this.fetching = true; - @on \mount ~> - @api \my/apps - .then (apps) ~> - @fetching = false - @apps = apps - @update! + this.on('mount', () => { + this.api('my/apps').then(apps => { + this.fetching = false + this.apps = apps + this.update({ + fetching: false, + apps: apps + }); + }); + }); </script> </mk-apps-page> diff --git a/src/web/app/dev/tags/pages/index.tag b/src/web/app/dev/tags/pages/index.tag index ff2494212c..f863876fa7 100644 --- a/src/web/app/dev/tags/pages/index.tag +++ b/src/web/app/dev/tags/pages/index.tag @@ -2,10 +2,5 @@ <style> :scope display block - - - - - </style> </mk-index> diff --git a/src/web/app/mobile/tags/drive-selector.tag b/src/web/app/mobile/tags/drive-selector.tag index 7039ac26a3..753a2c3a9b 100644 --- a/src/web/app/mobile/tags/drive-selector.tag +++ b/src/web/app/mobile/tags/drive-selector.tag @@ -56,19 +56,24 @@ </style> <script> - @files = [] + this.files = []; - @on \mount ~> - @refs.browser.on \change-selected (files) ~> - @files = files - @update! + this.on('mount', () => { + this.refs.browser.on('change-selected', files => { + this.update({ + files: files + }); + }); + }); - @cancel = ~> - @trigger \canceled - @unmount! + this.cancel = () => { + this.trigger('canceled'); + this.unmount(); + }; - @ok = ~> - @trigger \selected @files - @unmount! + this.ok = () => { + this.trigger('selected', this.files); + this.unmount(); + }; </script> </mk-drive-selector> diff --git a/src/web/app/mobile/tags/drive.tag b/src/web/app/mobile/tags/drive.tag index 06ed54e762..35b9b65417 100644 --- a/src/web/app/mobile/tags/drive.tag +++ b/src/web/app/mobile/tags/drive.tag @@ -3,7 +3,7 @@ <p onclick={ goRoot }><i class="fa fa-cloud"></i>ドライブ</p> <virtual each={ folder in hierarchyFolders }> <span><i class="fa fa-angle-right"></i></span> - <p onclick={ _move }>{ folder.name }</p> + <p onclick={ move }>{ folder.name }</p> </virtual> <virtual if={ folder != null }> <span><i class="fa fa-angle-right"></i></span> @@ -14,7 +14,7 @@ <p>{ file.name }</p> </virtual> </nav> - <div class="browser { loading: loading }" if={ file == null }> + <div class="browser { loading: fetching }" if={ file == null }> <div class="folders" if={ folders.length > 0 }> <virtual each={ folder in folders }> <mk-drive-folder folder={ folder }></mk-drive-folder> @@ -27,11 +27,11 @@ </virtual> <p if={ moreFiles }>もっと読み込む</p> </div> - <div class="empty" if={ files.length == 0 && folders.length == 0 && !loading }> + <div class="empty" if={ files.length == 0 && folders.length == 0 && !fetching }> <p if={ !folder == null }>ドライブには何もありません。</p> <p if={ folder != null }>このフォルダーは空です</p> </div> - <div class="loading" if={ loading }> + <div class="loading" if={ fetching }> <div class="spinner"> <div class="dot1"></div> <div class="dot2"></div> @@ -128,250 +128,266 @@ </style> <script> - @mixin \api - @mixin \stream + this.mixin('api'); + this.mixin('stream'); - @files = [] - @folders = [] - @hierarchy-folders = [] - @selected-files = [] + this.files = []; + this.folders = []; + this.hierarchyFolders = []; + this.selectedFiles = []; - # 現在の階層(フォルダ) - # * null でルートを表す - @folder = null + // 現在の階層(フォルダ) + // * null でルートを表す + this.folder = null; - @file = null + this.file = null; - @is-select-mode = @opts.select? and @opts.select - @multiple = if @opts.multiple? then @opts.multiple else false + this.isSelectMode = this.opts.select; + this.multiple =this.opts.multiple; - @on \mount ~> - @stream.on \drive_file_created @on-stream-drive-file-created - @stream.on \drive_file_updated @on-stream-drive-file-updated - @stream.on \drive_folder_created @on-stream-drive-folder-created - @stream.on \drive_folder_updated @on-stream-drive-folder-updated + this.on('mount', () => { + this.stream.on('drive_file_created', this.onStreamDriveFileCreated); + this.stream.on('drive_file_updated', this.onStreamDriveFileUpdated); + this.stream.on('drive_folder_created', this.onStreamDriveFolderCreated); + this.stream.on('drive_folder_updated', this.onStreamDriveFolderUpdated); - # Riotのバグでnullを渡しても""になる - # https://github.com/riot/riot/issues/2080 - #if @opts.folder? - if @opts.folder? and @opts.folder != '' - @cd @opts.folder, true - else if @opts.file? and @opts.file != '' - @cf @opts.file, true - else - @load! + // Riotのバグでnullを渡しても""になる + // https://github.com/riot/riot/issues/2080 + //if (this.opts.folder) + //if (this.opts.file) + if (this.opts.folder && this.opts.folder != '') { + this.cd(this.opts.folder, true); + } else if (this.opts.file && this.opts.file != '') { + this.cf(this.opts.file, true); + } else { + this.load(); + } + }); - @on \unmount ~> - @stream.off \drive_file_created @on-stream-drive-file-created - @stream.off \drive_file_updated @on-stream-drive-file-updated - @stream.off \drive_folder_created @on-stream-drive-folder-created - @stream.off \drive_folder_updated @on-stream-drive-folder-updated + this.on('unmount', () => { + this.stream.off('drive_file_created', this.onStreamDriveFileCreated); + this.stream.off('drive_file_updated', this.onStreamDriveFileUpdated); + this.stream.off('drive_folder_created', this.onStreamDriveFolderCreated); + this.stream.off('drive_folder_updated', this.onStreamDriveFolderUpdated); + }); - @on-stream-drive-file-created = (file) ~> - @add-file file, true + this.onStreamDriveFileCreated = file => { + this.addFile(file, true); + }; - @on-stream-drive-file-updated = (file) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - @remove-file file - else - @add-file file, true + this.onStreamDriveFileUpdated = file => { + const current = this.folder ? this.folder.id : null; + if (current != file.folder_id) { + this.removeFile(file); + } else { + this.addFile(file, true); + } + }; - @on-stream-drive-folder-created = (folder) ~> - @add-folder folder, true + this.onStreamDriveFolderCreated = folder => { + this.addFolder(folder, true); + }; - @on-stream-drive-folder-updated = (folder) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - @remove-folder folder - else - @add-folder folder, true + this.onStreamDriveFolderUpdated = folder => { + const current = this.folder ? this.folder.id : null; + if (current != folder.parent_id) { + this.removeFolder(folder); + } else { + this.addFolder(folder, true); + } + }; - @_move = (ev) ~> - @move ev.item.folder + this.move = ev => { + this.cd(ev.item.folder); + }; - @move = (target-folder) ~> - @cd target-folder + this.cd = (target, silent = false) => { + this.file = null; - @cd = (target-folder, silent = false) ~> - @file = null + if (target == null) { + this.goRoot(); + return; + } else if (typeof target == 'object') target = target.id; - if target-folder? and typeof target-folder == \object - target-folder = target-folder.id + this.update({ + fetching: true + }); - if target-folder == null - @go-root! - return + this.api('drive/folders/show', { + folder_id: target + }).then(folder => { + this.folder = folder; + this.hierarchyFolders = []; - @loading = true - @update! + if (folder.parent) dive(folder.parent); - @api \drive/folders/show do - folder_id: target-folder - .then (folder) ~> - @folder = folder - @hierarchy-folders = [] + this.update(); + this.trigger('open-folder', this.folder, silent); + this.load(); + }); + }; - x = (f) ~> - @hierarchy-folders.unshift f - if f.parent? - x f.parent + this.addFolder = (folder, unshift = false) => { + const current = this.folder ? this.folder.id : null; + // 追加しようとしているフォルダが、今居る階層とは違う階層のものだったら中断 + if (current != folder.parent_id) return; - if folder.parent? - x folder.parent + // 追加しようとしているフォルダを既に所有してたら中断 + if (this.folders.some(f => f.id == folder.id)) return; - @update! - @trigger \open-folder @folder, silent - @load! - .catch (err, text-status) -> - console.error err + if (unshift) { + this.folders.unshift(folder); + } else { + this.folders.push(folder); + } - @add-folder = (folder, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - return + this.update(); + }; - if (@folders.some (f) ~> f.id == folder.id) - return + this.addFile = (file, unshift = false) => { + const current = this.folder ? this.folder.id : null; + // 追加しようとしているファイルが、今居る階層とは違う階層のものだったら中断 + if (current != file.folder_id) return; - if unshift - @folders.unshift folder - else - @folders.push folder + if (this.files.some(f => f.id == file.id)) { + const exist = this.files.map(f => f.id).indexOf(file.id); + this.files[exist] = file; + this.update(); + return; + } - @update! + if (unshift) { + this.files.unshift(file); + } else { + this.files.push(file); + } - @add-file = (file, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - return + this.update(); + }; - if (@files.some (f) ~> f.id == file.id) - exist = (@files.map (f) -> f.id).index-of file.id - @files[exist] = file - @update! - return + this.removeFolder = folder => { + if (typeof folder == 'object') folder = folder.id; + this.folders = this.folders.filter(f => f.id != folder); + this.update(); + }; - if unshift - @files.unshift file - else - @files.push file + this.removeFile = file => { + if (typeof file == 'object') file = file.id; + this.files = this.files.filter(f => f.id != file); + this.update(); + }; - @update! + this.goRoot = () => { + if (this.folder || this.file) { + this.update({ + file: null, + folder: null, + hierarchyFolders: [] + }); + this.trigger('move-root'); + this.load(); + } + }; - @remove-folder = (folder) ~> - if typeof folder == \object - folder = folder.id - @folders = @folders.filter (f) -> f.id != folder - @update! + this.load = () => { + this.update({ + folders: [], + files: [], + moreFolders: false, + moreFiles: false, + fetching: true + }); - @remove-file = (file) ~> - if typeof file == \object - file = file.id - @files = @files.filter (f) -> f.id != file - @update! + this.trigger('begin-load'); - @go-root = ~> - if @folder != null or @file != null - @file = null - @folder = null - @hierarchy-folders = [] - @update! - @trigger \move-root - @load! + let fetchedFolders = null; + let fetchedFiles = null; - @load = ~> - @folders = [] - @files = [] - @more-folders = false - @more-files = false - @loading = true - @update! + const foldersMax = 20; + const filesMax = 20; - @trigger \begin-load + // フォルダ一覧取得 + this.api('drive/folders', { + folder_id: this.folder ? this.folder.id : null, + limit: foldersMax + 1 + }).then(folders => { + if (folders.length == foldersMax + 1) { + this.moreFolders = true; + folders.pop(); + } + fetchedFolders = folders; + complete(); + }); - load-folders = null - load-files = null + // ファイル一覧取得 + this.api('drive/files', { + folder_id: this.folder ? this.folder.id : null, + limit: filesMax + 1 + }).then(files => { + if (files.length == filesMax + 1) { + this.moreFiles = true; + files.pop(); + } + fetchedFiles = files; + complete(); + }); - folders-max = 20 - files-max = 20 + let flag = false; + const complete = () => { + if (flag) { + fetchedFolders.forEach(this.addFolder); + fetchedFiles.forEach(this.addFile); + this.update({ + fetching: false + }); + // 一連の読み込みが完了したイベントを発行 + this.trigger('loaded'); + } else { + flag = true; + // 一連の読み込みが半分完了したイベントを発行 + this.trigger('load-mid'); + } + }; + }; - # フォルダ一覧取得 - @api \drive/folders do - folder_id: if @folder? then @folder.id else null - limit: folders-max + 1 - .then (folders) ~> - if folders.length == folders-max + 1 - @more-folders = true - folders.pop! - load-folders := folders - complete! - .catch (err, text-status) ~> - console.error err + this.chooseFile = file => { + if (this.isSelectMode) { + if (this.selectedFiles.some(f => f.id == file.id)) { + this.selectedFiles = this.selectedFiles.filter(f => f.id != file.id); + } else { + this.selectedFiles.push(file); + } + this.update(); + this.trigger('change-selected', this.selectedFiles); + } else { + this.cf(file); + } + }; - # ファイル一覧取得 - @api \drive/files do - folder_id: if @folder? then @folder.id else null - limit: files-max + 1 - .then (files) ~> - if files.length == files-max + 1 - @more-files = true - files.pop! - load-files := files - complete! - .catch (err, text-status) ~> - console.error err + this.cf = (file, silent = false) => { + if (typeof file == 'object') file = file.id; - flag = false - complete = ~> - if flag - load-folders.for-each (folder) ~> - @add-folder folder - load-files.for-each (file) ~> - @add-file file - @loading = false - @update! + this.update({ + fetching: true + }); - @trigger \loaded - else - flag := true - @trigger \load-mid - - @choose-file = (file) ~> - if @is-select-mode - exist = @selected-files.some (f) ~> f.id == file.id - if exist - @selected-files = (@selected-files.filter (f) ~> f.id != file.id) - else - @selected-files.push file - @update! - @trigger \change-selected @selected-files - else - @cf file - - @cf = (file, silent = false) ~> - if typeof file == \object - file = file.id - - @loading = true - @update! - - @api \drive/files/show do + this.api('drive/files/show', { file_id: file - .then (file) ~> - @file = file - @folder = null - @hierarchy-folders = [] + }).then(file => { + this.file = file; + this.folder = null; + this.hierarchyFolders = []; - x = (f) ~> - @hierarchy-folders.unshift f - if f.parent? - x f.parent + if (file.folder) dive(file.folder); - if file.folder? - x file.folder + this.update(); + this.trigger('open-file', this.file, silent); + }); + }; - @update! - @trigger \open-file @file, silent + const dive = folder => { + this.hierarchyFolders.unshift(folder); + if (folder.parent) dive(folder.parent); + }; </script> </mk-drive> diff --git a/src/web/app/mobile/tags/drive/file-viewer.tag b/src/web/app/mobile/tags/drive/file-viewer.tag index a0d4c44453..78a10b83b4 100644 --- a/src/web/app/mobile/tags/drive/file-viewer.tag +++ b/src/web/app/mobile/tags/drive/file-viewer.tag @@ -180,22 +180,23 @@ </style> <script> - @bytes-to-size = require '../../../common/scripts/bytes-to-size.js' - @get-gcd = require '../../../common/scripts/gcd.js' + this.bytesToSize = require('../../../common/scripts/bytes-to-size.js'); + this.getGcd = require('../../../common/scripts/gcd.js'); - @mixin \api + this.mixin('api'); - @file = @opts.file - @kind = @file.type.split \/ .0 - - @rename = ~> - name = window.prompt '名前を変更' @file.name - if name? and name != '' and name != @file.name - @api \drive/files/update do - file_id: @file.id - name: name - .then ~> - @parent.cf @file, true + this.file = this.opts.file; + this.kind = this.file.type.split('/')[0]; + this.rename = () => { + const name = window.prompt('名前を変更', this.file.name); + if (name == null || name == '' || name == this.file.name) return; + this.api('drive/files/update', { + file_id: this.file.id, + name: name + }).then(() => { + this.parent.cf(this.file, true); + }); + }; </script> </mk-drive-file-viewer> diff --git a/src/web/app/mobile/tags/drive/file.tag b/src/web/app/mobile/tags/drive/file.tag index 95f91e5ebc..4b8216219b 100644 --- a/src/web/app/mobile/tags/drive/file.tag +++ b/src/web/app/mobile/tags/drive/file.tag @@ -122,16 +122,18 @@ </style> <script> - @bytes-to-size = require '../../../common/scripts/bytes-to-size.js' + this.bytesToSize = require('../../../common/scripts/bytes-to-size'); - @browser = @parent - @file = @opts.file - @is-selected = @browser.selected-files.some (f) ~> f.id == @file.id + this.browser = this.parent; + this.file = this.opts.file; + this.isSelected = this.browser.selectedFiles.some(f => f.id == this.file.id); - @browser.on \change-selected (selects) ~> - @is-selected = selects.some (f) ~> f.id == @file.id + this.browser.on('change-selected', selections => { + this.isSelected = selections.some(f => f.id == this.file.id); + }); - @onclick = ~> - @browser.choose-file @file + this.onclick = () => { + this.browser.chooseFile(this.file); + }; </script> </mk-drive-file> diff --git a/src/web/app/mobile/tags/drive/folder.tag b/src/web/app/mobile/tags/drive/folder.tag index 82bef02625..27e86662c7 100644 --- a/src/web/app/mobile/tags/drive/folder.tag +++ b/src/web/app/mobile/tags/drive/folder.tag @@ -37,10 +37,11 @@ </style> <script> - @browser = @parent - @folder = @opts.folder + this.browser = this.parent; + this.folder = this.opts.folder; - @onclick = ~> - @browser.move @folder + this.onclick = () => { + this.browser.cd(this.folder); + }; </script> </mk-drive-folder> diff --git a/src/web/app/mobile/tags/follow-button.tag b/src/web/app/mobile/tags/follow-button.tag index ac7058aebd..ae6d19f593 100644 --- a/src/web/app/mobile/tags/follow-button.tag +++ b/src/web/app/mobile/tags/follow-button.tag @@ -48,58 +48,74 @@ </style> <script> - @mixin \api - @mixin \is-promise - @mixin \stream + this.mixin('api'); + this.mixin('is-promise'); + this.mixin('stream'); - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @init = true - @wait = false + this.user = null; + this.userPromise = this.isPromise(this.opts.user) + ? this.opts.user + : Promise.resolve(this.opts.user); + this.init = true; + this.wait = false; - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @init = false - @update! - @stream.on \follow @on-stream-follow - @stream.on \unfollow @on-stream-unfollow + this.on('mount', () => { + this.userPromise.then(user => { + this.update({ + init: false, + user: user + }); + this.stream.on('follow', this.onStreamFollow); + this.stream.on('unfollow', this.onStreamUnfollow); + }); + }); - @on \unmount ~> - @stream.off \follow @on-stream-follow - @stream.off \unfollow @on-stream-unfollow + this.on('unmount', () => { + this.stream.off('follow', this.onStreamFollow); + this.stream.off('unfollow', this.onStreamUnfollow); + }); - @on-stream-follow = (user) ~> - if user.id == @user.id - @user = user - @update! + this.onStreamFollow = user => { + if (user.id == this.user.id) { + this.update({ + user: user + }); + } + }; - @on-stream-unfollow = (user) ~> - if user.id == @user.id - @user = user - @update! + this.onStreamUnfollow = user => { + if (user.id == this.user.id) { + this.update({ + user: user + }); + } + }; - @onclick = ~> - @wait = true - if @user.is_following - @api \following/delete do - user_id: @user.id - .then ~> - @user.is_following = false - .catch (err) -> - console.error err - .then ~> - @wait = false - @update! - else - @api \following/create do - user_id: @user.id - .then ~> - @user.is_following = true - .catch (err) -> - console.error err - .then ~> - @wait = false - @update! + this.onclick = () => { + this.wait = true; + if (this.user.is_following) { + this.api('following/delete', { + user_id: this.user.id + }).then(() => { + this.user.is_following = false; + }).catch(err => { + console.error(err); + }).then(() => { + this.wait = false; + this.update(); + }); + } else { + this.api('following/create', { + user_id: this.user.id + }).then(() => { + this.user.is_following = true; + }).catch(err => { + console.error(err); + }).then(() => { + this.wait = false; + this.update(); + }); + } + }; </script> </mk-follow-button> diff --git a/src/web/app/mobile/tags/home-timeline.tag b/src/web/app/mobile/tags/home-timeline.tag index 2aa9127144..2cb051f32a 100644 --- a/src/web/app/mobile/tags/home-timeline.tag +++ b/src/web/app/mobile/tags/home-timeline.tag @@ -3,41 +3,49 @@ <style> :scope display block - </style> <script> - @mixin \api - @mixin \stream + this.mixin('api'); + this.mixin('stream'); - @init = new Promise (res, rej) ~> - @api \posts/timeline - .then (posts) ~> - res posts - @trigger \loaded + this.init = new Promise((res, rej) => { + this.api('posts/timeline').then(posts => { + res(posts); + this.trigger('loaded'); + }); + }); - @on \mount ~> - @stream.on \post @on-stream-post - @stream.on \follow @on-stream-follow - @stream.on \unfollow @on-stream-unfollow + this.on('mount', () => { + this.stream.on('post', this.onStreamPost); + this.stream.on('follow', this.onStreamFollow); + this.stream.on('unfollow', this.onStreamUnfollow); + }); - @on \unmount ~> - @stream.off \post @on-stream-post - @stream.off \follow @on-stream-follow - @stream.off \unfollow @on-stream-unfollow + this.on('unmount', () => { + this.stream.off('post', this.onStreamPost); + this.stream.off('follow', this.onStreamFollow); + this.stream.off('unfollow', this.onStreamUnfollow); + }); - @more = ~> - @api \posts/timeline do - max_id: @refs.timeline.tail!.id + this.more = () => { + this.api('posts/timeline', { + max_id: this.refs.timeline.tail().id + }); + }; - @on-stream-post = (post) ~> - @is-empty = false - @update! - @refs.timeline.add-post post + this.onStreamPost = post => { + this.update({ + isEmpty: false + }); + this.refs.timeline.addPost(post); + }; - @on-stream-follow = ~> - @fetch! + this.onStreamFollow = () => { + this.fetch(); + }; - @on-stream-unfollow = ~> - @fetch! + this.onStreamUnfollow = () => { + this.fetch(); + }; </script> </mk-home-timeline> diff --git a/src/web/app/mobile/tags/home.tag b/src/web/app/mobile/tags/home.tag index 78141ca9a7..2edfd656e4 100644 --- a/src/web/app/mobile/tags/home.tag +++ b/src/web/app/mobile/tags/home.tag @@ -13,8 +13,10 @@ </style> <script> - @on \mount ~> - @refs.tl.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.tl.on('loaded', () => { + this.trigger('loaded'); + }); + }); </script> </mk-home> diff --git a/src/web/app/mobile/tags/images-viewer.tag b/src/web/app/mobile/tags/images-viewer.tag index 05dc744cdb..f3724f21b6 100644 --- a/src/web/app/mobile/tags/images-viewer.tag +++ b/src/web/app/mobile/tags/images-viewer.tag @@ -18,10 +18,11 @@ </style> <script> - @images = @opts.images - @image = @images.0 + this.images = this.opts.images; + this.image = this.images[0]; - @click = ~> - window.open @image.url + this.click = () => { + window.open(this.image.url); + }; </script> </mk-images-viewer> diff --git a/src/web/app/mobile/tags/index.js b/src/web/app/mobile/tags/index.js index 2a8f2161c2..dec2be3325 100644 --- a/src/web/app/mobile/tags/index.js +++ b/src/web/app/mobile/tags/index.js @@ -1,7 +1,6 @@ require('./ui.tag'); require('./ui-header.tag'); require('./ui-nav.tag'); -require('./stream-indicator.tag'); require('./page/entrance.tag'); require('./page/entrance/signin.tag'); require('./page/entrance/signup.tag'); diff --git a/src/web/app/mobile/tags/notification-preview.tag b/src/web/app/mobile/tags/notification-preview.tag index c146c6f0f7..b93b92d919 100644 --- a/src/web/app/mobile/tags/notification-preview.tag +++ b/src/web/app/mobile/tags/notification-preview.tag @@ -107,7 +107,7 @@ </style> <script> - @mixin \get-post-summary - @notification = @opts.notification + this.mixin('get-post-summary'); + this.notification = this.opts.notification; </script> </mk-notification-preview> diff --git a/src/web/app/mobile/tags/notification.tag b/src/web/app/mobile/tags/notification.tag index b619c66980..d32e6b40ae 100644 --- a/src/web/app/mobile/tags/notification.tag +++ b/src/web/app/mobile/tags/notification.tag @@ -167,7 +167,7 @@ </style> <script> - @mixin \get-post-summary - @notification = @opts.notification + this.mixin('get-post-summary'); + this.notification = this.opts.notification; </script> </mk-notification> diff --git a/src/web/app/mobile/tags/notifications.tag b/src/web/app/mobile/tags/notifications.tag index 8207495795..e73877266e 100644 --- a/src/web/app/mobile/tags/notifications.tag +++ b/src/web/app/mobile/tags/notifications.tag @@ -57,37 +57,40 @@ </style> <script> - @mixin \api - @mixin \stream - @mixin \get-post-summary + this.mixin('api'); + this.mixin('stream'); + this.mixin('get-post-summary'); - @notifications = [] - @loading = true + this.notifications = []; + this.loading = true; - @on \mount ~> - @api \i/notifications - .then (notifications) ~> - @notifications = notifications - @loading = false - @update! - @trigger \loaded - .catch (err, text-status) -> - console.error err + this.on('mount', () => { + this.api('i/notifications').then(notifications => { + this.update({ + loading: false, + notifications: notifications + }); + }); - @stream.on \notification @on-notification + this.stream.on('notification', this.onNotification); + }); - @on \unmount ~> - @stream.off \notification @on-notification + this.on('unmount', () => { + this.stream.off('notification', this.onNotification); + }); - @on-notification = (notification) ~> - @notifications.unshift notification - @update! + this.onNotification = notification => { + this.notifications.unshift(notification); + this.update(); + }; - @on \update ~> - @notifications.for-each (notification) ~> - date = (new Date notification.created_at).get-date! - month = (new Date notification.created_at).get-month! + 1 - notification._date = date - notification._datetext = month + '月 ' + date + '日' + this.on('update', () => { + this.notifications.forEach(notification => { + const date = new Date(notification.created_at).getDate(); + const month = new Date(notification.created_at).getMonth() + 1; + notification._date = date; + notification._datetext = `${month}月 ${date}日`; + }); + }); </script> </mk-notifications> diff --git a/src/web/app/mobile/tags/notify.tag b/src/web/app/mobile/tags/notify.tag index aa45ce0cff..c97e70696c 100644 --- a/src/web/app/mobile/tags/notify.tag +++ b/src/web/app/mobile/tags/notify.tag @@ -16,23 +16,23 @@ </style> <script> - @on \mount ~> - Velocity @root, { - bottom: \0px - } { - duration: 500ms - easing: \ease-out - } + this.on('mount', () => { + Velocity(this.root, { + bottom: '0px' + }, { + duration: 500, + easing: 'ease-out' + }); - set-timeout ~> - Velocity @root, { - bottom: \-64px - } { - duration: 500ms - easing: \ease-out - complete: ~> - @unmount! - } - , 6000ms + setTimeout(() => { + Velocity(this.root, { + bottom: '-64px' + }, { + duration: 500, + easing: 'ease-out', + complete: () => this.unmount() + }); + }, 6000); + }); </script> </mk-notify> diff --git a/src/web/app/mobile/tags/page/drive.tag b/src/web/app/mobile/tags/page/drive.tag index ef83e4d5ba..a064a05598 100644 --- a/src/web/app/mobile/tags/page/drive.tag +++ b/src/web/app/mobile/tags/page/drive.tag @@ -5,57 +5,65 @@ <style> :scope display block - </style> <script> - @mixin \ui - @mixin \ui-progress + this.mixin('ui'); + this.mixin('ui-progress'); - @on \mount ~> - document.title = 'Misskey Drive' - @ui.trigger \title '<i class="fa fa-cloud"></i>ドライブ' + this.on('mount', () => { + document.title = 'Misskey Drive'; + this.ui.trigger('title', '<i class="fa fa-cloud"></i>ドライブ'); - @refs.ui.refs.browser.on \begin-load ~> - @Progress.start! + this.refs.ui.refs.browser.on('begin-load', () => { + this.Progress.start(); + }); - @refs.ui.refs.browser.on \loaded-mid ~> - @Progress.set 0.5 + this.refs.ui.refs.browser.on('loaded-mid', () => { + this.Progress.set(0.5); + }); - @refs.ui.refs.browser.on \loaded ~> - @Progress.done! + this.refs.ui.refs.browser.on('loaded', () => { + this.Progress.done(); + }); - @refs.ui.refs.browser.on \move-root ~> - title = 'Misskey Drive' + this.refs.ui.refs.browser.on('move-root', () => { + const title = 'Misskey Drive'; - # Rewrite URL - history.push-state null, title, '/i/drive' + // Rewrite URL + history.pushState(null, title, '/i/drive'); - document.title = title - @ui.trigger \title '<i class="fa fa-cloud"></i>ドライブ' + document.title = title; + this.ui.trigger('title', '<i class="fa fa-cloud"></i>ドライブ'); + }); - @refs.ui.refs.browser.on \open-folder (folder, silent) ~> - title = folder.name + ' | Misskey Drive' + this.refs.ui.refs.browser.on('open-folder', (folder, silent) => { + const title = folder.name + ' | Misskey Drive'; - if !silent - # Rewrite URL - history.push-state null, title, '/i/drive/folder/' + folder.id + if (!silent) { + // Rewrite URL + history.pushState(null, title, '/i/drive/folder/' + folder.id); + } - document.title = title - # TODO: escape html characters in folder.name - @ui.trigger \title '<i class="fa fa-folder-open"></i>' + folder.name + document.title = title; + // TODO: escape html characters in folder.name + this.ui.trigger('title', '<i class="fa fa-folder-open"></i>' + folder.name); + }); - @refs.ui.refs.browser.on \open-file (file, silent) ~> - title = file.name + ' | Misskey Drive' + this.refs.ui.refs.browser.on('open-file', (file, silent) => { + const title = file.name + ' | Misskey Drive'; - if !silent - # Rewrite URL - history.push-state null, title, '/i/drive/file/' + file.id + if (!silent) { + // Rewrite URL + history.pushState(null, title, '/i/drive/file/' + file.id); + } - document.title = title - # TODO: escape html characters in file.name - @ui.trigger \title '<mk-file-type-icon class="icon"></mk-file-type-icon>' + file.name - riot.mount \mk-file-type-icon do + document.title = title; + // TODO: escape html characters in file.name + this.ui.trigger('title', '<mk-file-type-icon class="icon"></mk-file-type-icon>' + file.name); + riot.mount('mk-file-type-icon', { type: file.type - + }); + }); + }); </script> </mk-drive-page> diff --git a/src/web/app/mobile/tags/page/entrance.tag b/src/web/app/mobile/tags/page/entrance.tag index 424c58da5d..452dff992e 100644 --- a/src/web/app/mobile/tags/page/entrance.tag +++ b/src/web/app/mobile/tags/page/entrance.tag @@ -43,18 +43,24 @@ </style> <script> - @mode = \signin + this.mode = 'signin'; - @signup = ~> - @mode = \signup - @update! + this.signup = () => { + this.update({ + mode: 'signup' + }); + }; - @signin = ~> - @mode = \signin - @update! + this.signin = () => { + this.update({ + mode: 'signin' + }); + }; - @introduction = ~> - @mode = \introduction - @update! + this.introduction = () => { + this.update({ + mode: 'introduction' + }); + }; </script> </mk-entrance> diff --git a/src/web/app/mobile/tags/page/entrance/signup.tag b/src/web/app/mobile/tags/page/entrance/signup.tag index 5209543886..c4b3ee9f38 100644 --- a/src/web/app/mobile/tags/page/entrance/signup.tag +++ b/src/web/app/mobile/tags/page/entrance/signup.tag @@ -34,9 +34,5 @@ > i padding 14px - - - - </style> </mk-entrance-signup> diff --git a/src/web/app/mobile/tags/page/home.tag b/src/web/app/mobile/tags/page/home.tag index 947e119b09..c93803fb02 100644 --- a/src/web/app/mobile/tags/page/home.tag +++ b/src/web/app/mobile/tags/page/home.tag @@ -5,41 +5,47 @@ <style> :scope display block - </style> <script> - @mixin \i - @mixin \ui - @mixin \ui-progress - @mixin \stream - @mixin \get-post-summary + this.mixin('i'); + this.mixin('ui'); + this.mixin('ui-progress'); + this.mixin('stream'); + this.mixin('get-post-summary'); - @unread-count = 0 + this.unreadCount = 0; - @on \mount ~> + this.on('mount', () => { document.title = 'Misskey' - @ui.trigger \title '<i class="fa fa-home"></i>ホーム' + this.ui.trigger('title', '<i class="fa fa-home"></i>ホーム'); - @Progress.start! + this.Progress.start(); - @stream.on \post @on-stream-post - document.add-event-listener \visibilitychange @window-on-visibilitychange, false + this.stream.on('post', this.onStreamPost); + document.addEventListener('visibilitychange', this.onVisibilitychange, false); - @refs.ui.refs.home.on \loaded ~> - @Progress.done! + this.refs.ui.refs.home.on('loaded', () => { + this.Progress.done(); + }); + }); - @on \unmount ~> - @stream.off \post @on-stream-post - document.remove-event-listener \visibilitychange @window-on-visibilitychange + this.on('unmount', () => { + this.stream.off('post', this.onStreamPost); + document.removeEventListener('visibilitychange', this.onVisibilitychange); + }); - @on-stream-post = (post) ~> - if document.hidden and post.user_id !== @I.id - @unread-count++ - document.title = '(' + @unread-count + ') ' + @get-post-summary post + this.onStreamPost = post => { + if (document.hidden && post.user_id !== this.I.id) { + this.unreadCount++; + document.title = `(${this.unreadCount}) ${this.getPostSummary(post)}`; + } + }; - @window-on-visibilitychange = ~> - if !document.hidden - @unread-count = 0 - document.title = 'Misskey' + this.onVisibilitychange = () => { + if (!document.hidden) { + this.unreadCount = 0; + document.title = 'Misskey'; + } + }; </script> </mk-home-page> diff --git a/src/web/app/mobile/tags/page/messaging-room.tag b/src/web/app/mobile/tags/page/messaging-room.tag index 2216d0c460..29657802a6 100644 --- a/src/web/app/mobile/tags/page/messaging-room.tag +++ b/src/web/app/mobile/tags/page/messaging-room.tag @@ -7,21 +7,24 @@ display block </style> <script> - @mixin \api - @mixin \ui + this.mixin('api'); + this.mixin('ui'); - @fetching = true + this.fetching = true; - @on \mount ~> - @api \users/show do - username: @opts.username - .then (user) ~> - @fetching = false - @user = user - @update! + this.on('mount', () => { + this.api('users/show', { + username: this.opts.username + }).then(user => { + this.update({ + fetching: false, + user: user + }); - document.title = 'メッセージ: ' + user.name + ' | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<i class="fa fa-comments-o"></i>' + user.name + document.title = `メッセージ: ${user.name} | Misskey`; + // TODO: ユーザー名をエスケープ + this.ui.trigger('title', '<i class="fa fa-comments-o"></i>' + user.name); + }); + }); </script> </mk-messaging-room-page> diff --git a/src/web/app/mobile/tags/page/messaging.tag b/src/web/app/mobile/tags/page/messaging.tag index dd277f46e9..fd94cbfa4a 100644 --- a/src/web/app/mobile/tags/page/messaging.tag +++ b/src/web/app/mobile/tags/page/messaging.tag @@ -7,15 +7,16 @@ display block </style> <script> - @mixin \ui - @mixin \page + this.mixin('ui'); + this.mixin('page'); - @on \mount ~> - document.title = 'Misskey | メッセージ' - @ui.trigger \title '<i class="fa fa-comments-o"></i>メッセージ' - - @refs.ui.refs.index.on \navigate-user (user) ~> - @page '/i/messaging/' + user.username + this.on('mount', () => { + document.title = 'Misskey | メッセージ'; + this.ui.trigger('title', '<i class="fa fa-comments-o"></i>メッセージ'); + this.refs.ui.refs.index.on('navigate-user', user => { + this.page('/i/messaging/' + user.username); + }); + }); </script> </mk-messaging-page> diff --git a/src/web/app/mobile/tags/page/new-post.tag b/src/web/app/mobile/tags/page/new-post.tag index e323f0d955..3ba549c8dc 100644 --- a/src/web/app/mobile/tags/page/new-post.tag +++ b/src/web/app/mobile/tags/page/new-post.tag @@ -3,10 +3,5 @@ <style> :scope display block - - - - - </style> </mk-new-post-page> diff --git a/src/web/app/mobile/tags/page/notifications.tag b/src/web/app/mobile/tags/page/notifications.tag index 18b6cc2834..1d35d79edc 100644 --- a/src/web/app/mobile/tags/page/notifications.tag +++ b/src/web/app/mobile/tags/page/notifications.tag @@ -8,16 +8,18 @@ </style> <script> - @mixin \ui - @mixin \ui-progress + this.mixin('ui'); + this.mixin('ui-progress'); - @on \mount ~> - document.title = 'Misskey | 通知' - @ui.trigger \title '<i class="fa fa-bell-o"></i>通知' + this.on('mount', () => { + document.title = 'Misskey | 通知'; + this.ui.trigger('title', '<i class="fa fa-bell-o"></i>通知'); - @Progress.start! + this.Progress.start(); - @refs.ui.refs.notifications.on \loaded ~> - @Progress.done! + this.refs.ui.refs.notifications.on('loaded', () => { + this.Progress.done(); + }); + }); </script> </mk-notifications-page> diff --git a/src/web/app/mobile/tags/page/post.tag b/src/web/app/mobile/tags/page/post.tag index a8ffb1c3c7..2c4eba37a0 100644 --- a/src/web/app/mobile/tags/page/post.tag +++ b/src/web/app/mobile/tags/page/post.tag @@ -18,21 +18,24 @@ </style> <script> - @mixin \ui - @mixin \ui-progress + this.mixin('ui'); + this.mixin('ui-progress'); - @post = @opts.post + this.post = this.opts.post; - @on \mount ~> - document.title = 'Misskey' - @ui.trigger \title '<i class="fa fa-sticky-note-o"></i>投稿' + this.on('mount', () => { + document.title = 'Misskey'; + this.ui.trigger('title', '<i class="fa fa-sticky-note-o"></i>投稿'); - @Progress.start! + this.Progress.start(); - @refs.ui.refs.post.on \post-fetched ~> - @Progress.set 0.5 + this.refs.ui.refs.post.on('post-fetched', () => { + this.Progress.set(0.5); + }); - @refs.ui.refs.post.on \loaded ~> - @Progress.done! + this.refs.ui.refs.post.on('loaded', () => { + this.Progress.done(); + }); + }); </script> </mk-post-page> diff --git a/src/web/app/mobile/tags/page/search.tag b/src/web/app/mobile/tags/page/search.tag index 31de7d9625..fbf741f2e6 100644 --- a/src/web/app/mobile/tags/page/search.tag +++ b/src/web/app/mobile/tags/page/search.tag @@ -5,20 +5,21 @@ <style> :scope display block - </style> <script> - @mixin \ui - @mixin \ui-progress + this.mixin('ui'); + this.mixin('ui-progress'); - @on \mount ~> - document.title = '検索: ' + @opts.query + ' | Misskey' - # TODO: クエリをHTMLエスケープ - @ui.trigger \title '<i class="fa fa-search"></i>' + @opts.query + this.on('mount', () => { + document.title = `検索: ${this.opts.query} | Misskey` + // TODO: クエリをHTMLエスケープ + this.ui.trigger('title', '<i class="fa fa-search"></i>' + this.opts.query); - @Progress.start! + this.Progress.start(); - @refs.ui.refs.search.on \loaded ~> - @Progress.done! + this.refs.ui.refs.search.on('loaded', () => { + this.Progress.done(); + }); + }); </script> </mk-search-page> diff --git a/src/web/app/mobile/tags/page/settings.tag b/src/web/app/mobile/tags/page/settings.tag index 99e7569f5b..59974e8cb6 100644 --- a/src/web/app/mobile/tags/page/settings.tag +++ b/src/web/app/mobile/tags/page/settings.tag @@ -13,10 +13,11 @@ display block </style> <script> - @mixin \ui + this.mixin('ui'); - @on \mount ~> - document.title = 'Misskey | 設定' - @ui.trigger \title '<i class="fa fa-cog"></i>設定' + this.on('mount', () => { + document.title = 'Misskey | 設定'; + this.ui.trigger('title', '<i class="fa fa-cog"></i>設定'); + }); </script> </mk-settings-page> diff --git a/src/web/app/mobile/tags/page/settings/api.tag b/src/web/app/mobile/tags/page/settings/api.tag index 69f4a47db0..e4f954f51a 100644 --- a/src/web/app/mobile/tags/page/settings/api.tag +++ b/src/web/app/mobile/tags/page/settings/api.tag @@ -7,10 +7,11 @@ display block </style> <script> - @mixin \ui + this.mixin('ui'); - @on \mount ~> - document.title = 'Misskey | API' - @ui.trigger \title '<i class="fa fa-key"></i>API' + this.on('mount', () => { + document.title = 'Misskey | API'; + this.ui.trigger('title', '<i class="fa fa-key"></i>API'); + }); </script> </mk-api-info-page> diff --git a/src/web/app/mobile/tags/page/settings/authorized-apps.tag b/src/web/app/mobile/tags/page/settings/authorized-apps.tag index abb8ba0fc0..84904c91e5 100644 --- a/src/web/app/mobile/tags/page/settings/authorized-apps.tag +++ b/src/web/app/mobile/tags/page/settings/authorized-apps.tag @@ -7,10 +7,11 @@ display block </style> <script> - @mixin \ui + this.mixin('ui'); - @on \mount ~> - document.title = 'Misskey | アプリケーション' - @ui.trigger \title '<i class="fa fa-puzzle-piece"></i>アプリケーション' + this.on('mount', () => { + document.title = 'Misskey | アプリケーション'; + this.ui.trigger('title', '<i class="fa fa-puzzle-piece"></i>アプリケーション'); + }); </script> </mk-authorized-apps-page> diff --git a/src/web/app/mobile/tags/page/settings/signin.tag b/src/web/app/mobile/tags/page/settings/signin.tag index 5886b53f9a..874cdf4856 100644 --- a/src/web/app/mobile/tags/page/settings/signin.tag +++ b/src/web/app/mobile/tags/page/settings/signin.tag @@ -7,10 +7,11 @@ display block </style> <script> - @mixin \ui + this.mixin('ui'); - @on \mount ~> - document.title = 'Misskey | ログイン履歴' - @ui.trigger \title '<i class="fa fa-sign-in"></i>ログイン履歴' + this.on('mount', () => { + document.title = 'Misskey | ログイン履歴'; + this.ui.trigger('title', '<i class="fa fa-sign-in"></i>ログイン履歴'); + }); </script> </mk-signin-history-page> diff --git a/src/web/app/mobile/tags/page/settings/twitter.tag b/src/web/app/mobile/tags/page/settings/twitter.tag index f6cde2e5a5..2026ab7daf 100644 --- a/src/web/app/mobile/tags/page/settings/twitter.tag +++ b/src/web/app/mobile/tags/page/settings/twitter.tag @@ -7,10 +7,11 @@ display block </style> <script> - @mixin \ui + this.mixin('ui'); - @on \mount ~> - document.title = 'Misskey | Twitter連携' - @ui.trigger \title '<i class="fa fa-twitter"></i>Twitter連携' + this.on('mount', () => { + document.title = 'Misskey | Twitter連携'; + this.ui.trigger('title', '<i class="fa fa-twitter"></i>Twitter連携'); + }); </script> </mk-twitter-setting-page> diff --git a/src/web/app/mobile/tags/page/user-followers.tag b/src/web/app/mobile/tags/page/user-followers.tag index 5856e60e02..249897be2c 100644 --- a/src/web/app/mobile/tags/page/user-followers.tag +++ b/src/web/app/mobile/tags/page/user-followers.tag @@ -5,32 +5,34 @@ <style> :scope display block - </style> <script> - @mixin \ui - @mixin \ui-progress - @mixin \api - - @fetching = true - @user = null + this.mixin('ui'); + this.mixin('ui-progress'); + this.mixin('api'); - @on \mount ~> - @Progress.start! + this.fetching = true; + this.user = null; - @api \users/show do - username: @opts.user - .then (user) ~> - @user = user - @fetching = false + this.on('mount', () => { + this.Progress.start(); - document.title = user.name + 'のフォロワー | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロワー' + this.api('users/show', { + username: this.opts.user + }).then(user => { + this.update({ + fetching: false, + user: user + }); - @update! + document.title = user.name + 'のフォロワー | Misskey'; + // TODO: ユーザー名をエスケープ + this.ui.trigger('title', '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロワー'); - @refs.ui.refs.list.on \loaded ~> - @Progress.done! + this.refs.ui.refs.list.on('loaded', () => { + this.Progress.done(); + }); + }); + }); </script> </mk-user-followers-page> diff --git a/src/web/app/mobile/tags/page/user-following.tag b/src/web/app/mobile/tags/page/user-following.tag index 14b006d3f9..a682715a02 100644 --- a/src/web/app/mobile/tags/page/user-following.tag +++ b/src/web/app/mobile/tags/page/user-following.tag @@ -5,32 +5,34 @@ <style> :scope display block - </style> <script> - @mixin \ui - @mixin \ui-progress - @mixin \api - - @fetching = true - @user = null + this.mixin('ui'); + this.mixin('ui-progress'); + this.mixin('api'); - @on \mount ~> - @Progress.start! + this.fetching = true; + this.user = null; - @api \users/show do - username: @opts.user - .then (user) ~> - @user = user - @fetching = false + this.on('mount', () => { + this.Progress.start(); - document.title = user.name + 'のフォロー | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロー' + this.api('users/show', { + username: this.opts.user + }).then(user => { + this.update({ + fetching: false, + user: user + }); - @update! + document.title = user.name + 'のフォロー | Misskey'; + // TODO: ユーザー名をエスケープ + this.ui.trigger('title', '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロー'); - @refs.ui.refs.list.on \loaded ~> - @Progress.done! + this.refs.ui.refs.list.on('loaded', () => { + this.Progress.done(); + }); + }); + }); </script> </mk-user-following-page> diff --git a/src/web/app/mobile/tags/page/user.tag b/src/web/app/mobile/tags/page/user.tag index 0ac8ed4e25..2a0e48426f 100644 --- a/src/web/app/mobile/tags/page/user.tag +++ b/src/web/app/mobile/tags/page/user.tag @@ -8,18 +8,20 @@ </style> <script> - @mixin \ui - @mixin \ui-progress + this.mixin('ui'); + this.mixin('ui-progress'); - @user = @opts.user + this.user = this.opts.user; - @on \mount ~> - @Progress.start! + this.on('mount', () => { + this.Progress.start(); - @refs.ui.refs.user.on \loaded (user) ~> - @Progress.done! - document.title = user.name + ' | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<i class="fa fa-user"></i>' + user.name + this.refs.ui.refs.user.on('loaded', user => { + this.Progress.done(); + document.title = user.name + ' | Misskey'; + // TODO: ユーザー名をエスケープ + this.ui.trigger('title', '<i class="fa fa-user"></i>' + user.name); + }); + }); </script> </mk-user-page> diff --git a/src/web/app/mobile/tags/post-detail.tag b/src/web/app/mobile/tags/post-detail.tag index 3856df0800..e8149e0982 100644 --- a/src/web/app/mobile/tags/post-detail.tag +++ b/src/web/app/mobile/tags/post-detail.tag @@ -329,102 +329,124 @@ </style> <script> - @mixin \api - @mixin \text - @mixin \get-post-summary - @mixin \open-post-form + this.mixin('api'); + this.mixin('text'); + this.mixin('get-post-summary'); + this.mixin('open-post-form'); - @fetching = true - @loading-context = false - @content = null - @post = null + this.fetching = true; + this.loadingContext = false; + this.content = null; + this.post = null; - @on \mount ~> - @api \posts/show do - post_id: @opts.post - .then (post) ~> - @post = post - @is-repost = @post.repost? - @p = if @is-repost then @post.repost else @post - @summary = @get-post-summary @p - @trigger \loaded - @fetching = false - @update! + this.on('mount', () => { + this.api('posts/show', { + post_id: this.opts.post + }).then(post => { + const isRepost = post.repost != null; + const p = isRepost ? post.repost : post; + this.update({ + fetching: false, + post: post, + isRepost: isRepost, + p: p + }); - if @p.text? - tokens = @analyze @p.text - @refs.text.innerHTML = @compile tokens + this.trigger('loaded'); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + if (this.p.text) { + const tokens = this.analyze(this.p.text); - # URLをプレビュー + this.refs.text.innerHTML = this.compile(tokens); + + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); + + // URLをプレビュー tokens - .filter (t) -> t.type == \link - .map (t) ~> - @preview = @refs.text.append-child document.create-element \mk-url-preview - riot.mount @preview, do - url: t.content + .filter(t => t.type == 'link') + .map(t => { + riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), { + url: t.content + }); + }); + } - # Get likes - @api \posts/likes do - post_id: @p.id + // Get likes + this.api('posts/likes', { + post_id: this.p.id, limit: 8 - .then (likes) ~> - @likes = likes - @update! + }).then(likes => { + this.update({ + likes: likes + }); + }); - # Get reposts - @api \posts/reposts do - post_id: @p.id + // Get reposts + this.api('posts/reposts', { + post_id: this.p.id, limit: 8 - .then (reposts) ~> - @reposts = reposts - @update! + }).then(reposts => { + this.update({ + reposts: reposts + }); + }); - # Get replies - @api \posts/replies do - post_id: @p.id + // Get replies + this.api('posts/replies', { + post_id: this.p.id, limit: 8 - .then (replies) ~> - @replies = replies - @update! + }).then(replies => { + this.update({ + replies: replies + }); + }); + }); + }); - @reply = ~> - @open-post-form do - reply: @p + this.reply = () => { + riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), { + reply: this.p + }); + }; - @repost = ~> - text = window.prompt '「' + @summary + '」をRepost' - if text? - @api \posts/create do - repost_id: @p.id - text: if text == '' then undefined else text + this.repost = () => { + riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), { + post: this.p + }); + }; - @like = ~> - if @p.is_liked - @api \posts/likes/delete do - post_id: @p.id - .then ~> - @p.is_liked = false - @update! - else - @api \posts/likes/create do - post_id: @p.id - .then ~> - @p.is_liked = true - @update! + this.like = () => { + if (this.p.is_liked) { + this.api('posts/likes/delete', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = false; + this.update(); + }); + } else { + this.api('posts/likes/create', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = true; + this.update(); + }); + } + }; - @load-context = ~> - @loading-context = true + this.loadContext = () => { + this.loadingContext = true; - # Get context - @api \posts/context do - post_id: @p.reply_to_id - .then (context) ~> - @context = context.reverse! - @loading-context = false - @update! + // Fetch context + this.api('posts/context', { + post_id: this.p.reply_to_id + }).then(context => { + this.update({ + loadContext: false, + content: context.reverse() + }); + }); + }; </script> </mk-post-detail> diff --git a/src/web/app/mobile/tags/post-form.tag b/src/web/app/mobile/tags/post-form.tag index 3d98a9832f..353db01540 100644 --- a/src/web/app/mobile/tags/post-form.tag +++ b/src/web/app/mobile/tags/post-form.tag @@ -10,7 +10,7 @@ </header> <div class="form"> <mk-post-preview if={ opts.reply } post={ opts.reply }></mk-post-preview> - <textarea ref="text" disabled={ wait } oninput={ update } onkeypress={ onkeypress } onpaste={ onpaste } placeholder={ opts.reply ? 'この投稿への返信...' : 'いまどうしてる?' }></textarea> + <textarea ref="text" disabled={ wait } oninput={ update } onkeydown={ onkeydown } onpaste={ onpaste } placeholder={ opts.reply ? 'この投稿への返信...' : 'いまどうしてる?' }></textarea> <div class="attaches" if={ files.length != 0 }> <ul class="files" ref="attaches"> <li class="file" each={ files }> @@ -182,103 +182,111 @@ </style> <script> - get-cat = require '../../common/scripts/get-cat' + const getCat = require('../../common/scripts/get-cat'); - @mixin \api + this.mixin('api'); - @wait = false - @uploadings = [] - @files = [] - @poll = false + this.wait = false; + this.uploadings = []; + this.files = []; + this.poll = false; - @on \mount ~> - @refs.uploader.on \uploaded (file) ~> - @add-file file + this.on('mount', () => { + this.refs.uploader.on('uploaded', file => { + this.addFile(file); + }); - @refs.uploader.on \change-uploads (uploads) ~> - @trigger \change-uploading-files uploads + this.refs.uploader.on('change-uploads', uploads => { + this.trigger('change-uploading-files', uploads); + }); - @refs.text.focus! + this.refs.text.focus(); + }); - @onkeypress = (e) ~> - if (e.char-code == 10 || e.char-code == 13) && e.ctrl-key - @post! - else - return true + this.onkeydown = e => { + if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey)) this.post(); + }; - @onpaste = (e) ~> - data = e.clipboard-data - items = data.items - for i from 0 to items.length - 1 - item = items[i] - switch (item.kind) - | \file => - @upload item.get-as-file! - return true + this.onpaste = e => { + e.clipboardData.items.forEach(item => { + if (item.kind == 'file') { + this.upload(item.getAsFile()); + } + }); + }; - @select-file = ~> - @refs.file.click! + this.selectFile = () => { + this.refs.file.click(); + }; - @select-file-from-drive = ~> - browser = document.body.append-child document.create-element \mk-drive-selector - browser = riot.mount browser, do + this.selectFileFromDrive = () => { + const i = riot.mount(document.body.appendChild(document.createElement('mk-drive-selector')), { multiple: true - .0 - browser.on \selected (files) ~> - files.for-each @add-file + })[0]; + i.one('selected', files => { + files.forEach(this.addFile); + }); + }; - @change-file = ~> - files = @refs.file.files - for i from 0 to files.length - 1 - file = files.item i - @upload file + this.changeFile = () => { + this.refs.file.files.forEach(this.upload); + }; - @upload = (file) ~> - @refs.uploader.upload file + this.upload = file => { + this.refs.uploader.upload(file); + }; - @add-file = (file) ~> - file._remove = ~> - @files = @files.filter (x) -> x.id != file.id - @trigger \change-files @files - @update! + this.addFile = file => { + file._remove = () => { + this.files = this.files.filter(x => x.id != file.id); + this.trigger('change-files', this.files); + this.update(); + }; - @files.push file - @trigger \change-files @files - @update! + this.files.push(file); + this.trigger('change-files', this.files); + this.update(); + }; - @add-poll = ~> - @poll = true + this.addPoll = () => { + this.poll = true; + }; - @on-poll-destroyed = ~> - @update do + this.onPollDestroyed = () => { + this.update({ poll: false + }); + }; - @post = ~> - @wait = true + this.post = () => { + this.wait = true; - files = if @files? and @files.length > 0 - then @files.map (f) -> f.id - else undefined + const files = this.files && this.files.length > 0 + ? this.files.map(f => f.id) + : undefined; - @api \posts/create do - text: @refs.text.value - media_ids: files - reply_to_id: if @opts.reply? then @opts.reply.id else undefined - poll: if @poll then @refs.poll.get! else undefined - .then (data) ~> - @trigger \post - @unmount! - .catch (err) ~> - console.error err - #@opts.ui.trigger \notification 'Error!' - @wait = false - @update! + this.api('posts/create', { + text: this.refs.text.value, + media_ids: files, + reply_to_id: this.inReplyToPost ? this.inReplyToPost.id : undefined, + poll: this.poll ? this.refs.poll.get() : undefined + }).then(data => { + this.trigger('post'); + this.unmount(); + }).catch(err => { + this.update({ + wait: false + }); + }); + }; - @cancel = ~> - @trigger \cancel - @unmount! + this.cancel = () => { + this.trigger('cancel'); + this.unmount(); + }; - @cat = ~> - @refs.text.value = @refs.text.value + get-cat! + this.cat = () => { + this.refs.text.value += getCat(); + }; </script> </mk-post-form> diff --git a/src/web/app/mobile/tags/post-preview.tag b/src/web/app/mobile/tags/post-preview.tag index d86ca86df6..aa1d5f9b29 100644 --- a/src/web/app/mobile/tags/post-preview.tag +++ b/src/web/app/mobile/tags/post-preview.tag @@ -90,5 +90,5 @@ color #717171 </style> - <script>@post = @opts.post</script> + <script>this.post = this.opts.post</script> </mk-post-preview> diff --git a/src/web/app/mobile/tags/search-posts.tag b/src/web/app/mobile/tags/search-posts.tag index 18d538c327..b0efe14636 100644 --- a/src/web/app/mobile/tags/search-posts.tag +++ b/src/web/app/mobile/tags/search-posts.tag @@ -7,26 +7,30 @@ </style> <script> - @mixin \api + this.mixin('api'); - @max = 30 - @offset = 0 + this.max = 30; + this.offset = 0; - @query = @opts.query - @with-media = @opts.with-media + this.query = this.opts.query; + this.withMedia = this.opts.withMedia; - @init = new Promise (res, rej) ~> - @api \posts/search do - query: @query - .then (posts) ~> - res posts - @trigger \loaded + this.init = new Promise((res, rej) => { + this.api('posts/search', { + query: this.query + }).then(posts => { + res(posts); + this.trigger('loaded'); + }); + }); - @more = ~> - @offset += @max - @api \posts/search do - query: @query - max: @max - offset: @offset + this.more = () => { + this.offset += this.max; + this.api('posts/search', { + query: this.query, + max: this.max, + offset: this.offset + }); + }; </script> </mk-search-posts> diff --git a/src/web/app/mobile/tags/search.tag b/src/web/app/mobile/tags/search.tag index 3cca973a26..831e5a3e34 100644 --- a/src/web/app/mobile/tags/search.tag +++ b/src/web/app/mobile/tags/search.tag @@ -3,13 +3,14 @@ <style> :scope display block - </style> <script> - @query = @opts.query + this.query = this.opts.query; - @on \mount ~> - @refs.posts.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.posts.on('loaded', () => { + this.trigger('loaded'); + }); + }); </script> </mk-search> diff --git a/src/web/app/mobile/tags/stream-indicator.tag b/src/web/app/mobile/tags/stream-indicator.tag deleted file mode 100644 index d2ab34574d..0000000000 --- a/src/web/app/mobile/tags/stream-indicator.tag +++ /dev/null @@ -1,54 +0,0 @@ -<mk-stream-indicator> - <p if={ state == 'initializing' }><i class="fa fa-spinner fa-spin"></i><span>接続中 - <mk-ellipsis></mk-ellipsis></span></p> - <p if={ state == 'reconnecting' }><i class="fa fa-spinner fa-spin"></i><span>切断されました 接続中 - <mk-ellipsis></mk-ellipsis></span></p> - <p if={ state == 'connected' }><i class="fa fa-check"></i><span>接続完了</span></p> - <style> - :scope - display block - pointer-events none - position fixed - z-index 16384 - bottom 8px - right 8px - margin 0 - padding 6px 12px - font-size 0.9em - color #fff - background rgba(0, 0, 0, 0.8) - - > p - display block - margin 0 - - > i - margin-right 0.25em - - </style> - <script> - @mixin \stream - - @on \before-mount ~> - @state = @get-stream-state! - - if @state == \connected - @root.style.opacity = 0 - - @stream-state-ev.on \connected ~> - @state = @get-stream-state! - @update! - set-timeout ~> - Velocity @root, { - opacity: 0 - } 200ms \linear - , 1000ms - - @stream-state-ev.on \closed ~> - @state = @get-stream-state! - @update! - Velocity @root, { - opacity: 1 - } 0ms - </script> -</mk-stream-indicator> diff --git a/src/web/app/mobile/tags/sub-post-content.tag b/src/web/app/mobile/tags/sub-post-content.tag index 2256bb3486..5ff01c5020 100644 --- a/src/web/app/mobile/tags/sub-post-content.tag +++ b/src/web/app/mobile/tags/sub-post-content.tag @@ -28,17 +28,19 @@ </style> <script> - @mixin \text + this.mixin('text'); - @post = @opts.post + this.post = this.opts.post; - @on \mount ~> - if @post.text? - tokens = @analyze @post.text - @refs.text.innerHTML = @compile tokens, false + this.on('mount', () => { + if (this.post.text) { + const tokens = this.analyze(this.post.text); + this.refs.text.innerHTML = this.compile(tokens, false); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); + } + }); </script> </mk-sub-post-content> diff --git a/src/web/app/mobile/tags/timeline-post-sub.tag b/src/web/app/mobile/tags/timeline-post-sub.tag index 8ffe84bbc9..5a944db733 100644 --- a/src/web/app/mobile/tags/timeline-post-sub.tag +++ b/src/web/app/mobile/tags/timeline-post-sub.tag @@ -97,5 +97,5 @@ font-size 80% </style> - <script>@post = @opts.post</script> + <script>this.post = this.opts.post</script> </mk-timeline-post-sub> diff --git a/src/web/app/mobile/tags/timeline-post.tag b/src/web/app/mobile/tags/timeline-post.tag index 9ffa2c918c..8662eadb8c 100644 --- a/src/web/app/mobile/tags/timeline-post.tag +++ b/src/web/app/mobile/tags/timeline-post.tag @@ -3,10 +3,19 @@ <mk-timeline-post-sub post={ p.reply_to }></mk-timeline-post-sub> </div> <div class="repost" if={ isRepost }> - <p><a class="avatar-anchor" href={ CONFIG.url + '/' + post.user.username }><img class="avatar" src={ post.user.avatar_url + '?thumbnail&size=64' } alt="avatar"/></a><i class="fa fa-retweet"></i><a class="name" href={ CONFIG.url + '/' + post.user.username }>{ post.user.name }</a>がRepost</p> + <p> + <a class="avatar-anchor" href={ CONFIG.url + '/' + post.user.username }> + <img class="avatar" src={ post.user.avatar_url + '?thumbnail&size=64' } alt="avatar"/> + </a> + <i class="fa fa-retweet"></i> + <a class="name" href={ CONFIG.url + '/' + post.user.username }>{ post.user.name }</a>がRepost + </p> <mk-time time={ post.created_at }></mk-time> </div> - <article><a class="avatar-anchor" href={ CONFIG.url + '/' + p.user.username }><img class="avatar" src={ p.user.avatar_url + '?thumbnail&size=96' } alt="avatar"/></a> + <article> + <a class="avatar-anchor" href={ CONFIG.url + '/' + p.user.username }> + <img class="avatar" src={ p.user.avatar_url + '?thumbnail&size=96' } alt="avatar"/> + </a> <div class="main"> <header> <a class="name" href={ CONFIG.url + '/' + p.user.username }>{ p.user.name }</a> @@ -286,62 +295,70 @@ </style> <script> - @mixin \api - @mixin \text - @mixin \get-post-summary - @mixin \open-post-form + this.mixin('api'); + this.mixin('text'); + this.mixin('get-post-summary'); + this.mixin('open-post-form'); - @post = @opts.post - @is-repost = @post.repost? and !@post.text? - @p = if @is-repost then @post.repost else @post - @summary = @get-post-summary @p - @url = CONFIG.url + '/' + @p.user.username + '/' + @p.id + this.post = this.opts.post; + this.isRepost = this.post.repost != null && this.post.text == null; + this.p = this.isRepost ? this.post.repost : this.post; + this.summary = this.getPostSummary(this.p); + this.url = CONFIG.url + '/' + this.p.user.username + '/' + this.p.id - @on \mount ~> - if @p.text? - tokens = if @p._highlight? - then @analyze @p._highlight - else @analyze @p.text + this.on('mount', () => { + if (this.p.text) { + const tokens = this.analyze(this.p.text); - @refs.text.innerHTML = @refs.text.innerHTML.replace '<p class="dummy"></p>' if @p._highlight? - then @compile tokens, true, false - else @compile tokens + this.refs.text.innerHTML = this.refs.text.innerHTML.replace('<p class="dummy"></p>', this.compile(tokens)); - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); + }); - # URLをプレビュー + // URLをプレビュー tokens - .filter (t) -> t.type == \link - .map (t) ~> - @preview = @refs.text.append-child document.create-element \mk-url-preview - riot.mount @preview, do - url: t.content + .filter(t => t.type == 'link') + .map(t => { + riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), { + url: t.content + }); + }); + } + }); - @reply = ~> - @open-post-form do - reply: @p + this.reply = () => { + this.openPostForm({ + reply: this.p + }); + }; - @repost = ~> - text = window.prompt '「' + @summary + '」をRepost' - if text? - @api \posts/create do - repost_id: @p.id - text: if text == '' then undefined else text + this.repost = () => { + const text = window.prompt(`「${this.summary}」をRepost`); + if (text) { + this.api('posts/create', { + repost_id: this.p.id, + text: text == '' ? undefined : text + }); + } + }; - @like = ~> - if @p.is_liked - @api \posts/likes/delete do - post_id: @p.id - .then ~> - @p.is_liked = false - @update! - else - @api \posts/likes/create do - post_id: @p.id - .then ~> - @p.is_liked = true - @update! + this.like = () => { + if (this.p.is_liked) { + this.api('posts/likes/delete', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = false; + this.update(); + }); + } else { + this.api('posts/likes/create', { + post_id: this.p.id + }).then(() => { + this.p.is_liked = true; + this.update(); + }); + } + }; </script> </mk-timeline-post> diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index c41016076e..421917d834 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -74,45 +74,58 @@ </style> <script> - @posts = [] - @init = true - @fetching = false - @can-fetch-more = true + this.posts = []; + this.init = true; + this.fetching = false; + this.canFetchMore = true; - @on \mount ~> - @opts.init.then (posts) ~> - @init = false - @set-posts posts + this.on('mount', () => { + this.opts.init.then(posts => { + this.init = false; + this.setPosts(posts); + }); + }); - @on \update ~> - @posts.for-each (post) ~> - date = (new Date post.created_at).get-date! - month = (new Date post.created_at).get-month! + 1 - post._date = date - post._datetext = month + '月 ' + date + '日' + this.on('update', () => { + this.posts.forEach(post => { + const date = new Date(post.created_at).getDate(); + const month = new Date(post.created_at).getMonth() + 1; + post._date = date; + post._datetext = `${month}月 ${date}日`; + }); + }); - @more = ~> - if @init or @fetching or @posts.length == 0 then return - @fetching = true - @update! - @opts.more!.then (posts) ~> - @fetching = false - @prepend-posts posts + this.more = () => { + if (this.init || this.fetching || this.posts.length == 0) return; + this.update({ + fetching: true + }); + this.opts.more().then(posts => { + this.fetching = false; + this.prependPosts(posts); + }); + }; - @set-posts = (posts) ~> - @posts = posts - @update! + this.setPosts = posts => { + this.update({ + posts: posts + }); + }; - @prepend-posts = (posts) ~> - posts.for-each (post) ~> - @posts.push post - @update! + this.prependPosts = posts => { + posts.forEach(post => { + this.posts.push(post); + this.update(); + }); + } - @add-post = (post) ~> - @posts.unshift post - @update! + this.addPost = post => { + this.posts.unshift(post); + this.update(); + }; - @tail = ~> - @posts[@posts.length - 1] + this.tail = () => { + return this.posts[this.posts.length - 1]; + }; </script> </mk-timeline> diff --git a/src/web/app/mobile/tags/ui-header.tag b/src/web/app/mobile/tags/ui-header.tag index d47c3610f9..30259ba911 100644 --- a/src/web/app/mobile/tags/ui-header.tag +++ b/src/web/app/mobile/tags/ui-header.tag @@ -13,7 +13,7 @@ $height = 48px display block - position fixed + position sticky top 0 z-index 1024 width 100% @@ -88,17 +88,15 @@ </style> <script> - @mixin \ui - @mixin \open-post-form + this.mixin('ui'); + this.mixin('open-post-form'); - @on \mount ~> - @opts.ready! + this.ui.on('title', title => { + if (this.refs.title) this.refs.title.innerHTML = title; + }); - @ui.on \title (title) ~> - if @refs.title? - @refs.title.innerHTML = title - - @post = ~> - @open-post-form! + this.post = () => { + this.openPostForm(); + }; </script> </mk-ui-header> diff --git a/src/web/app/mobile/tags/ui-nav.tag b/src/web/app/mobile/tags/ui-nav.tag index a5dbd4cbaf..23d07efdc4 100644 --- a/src/web/app/mobile/tags/ui-nav.tag +++ b/src/web/app/mobile/tags/ui-nav.tag @@ -117,15 +117,13 @@ </style> <script> - @mixin \i - @mixin \page + this.mixin('i'); + this.mixin('page'); - @on \mount ~> - @opts.ready! - - @search = ~> - query = window.prompt \検索 - if query? and query != '' - @page '/search:' + query + this.search = () => { + const query = window.prompt('検索'); + if (query == null || query == '') return; + this.page('/search:' + query); + }; </script> </mk-ui-nav> diff --git a/src/web/app/mobile/tags/ui.tag b/src/web/app/mobile/tags/ui.tag index c3ffe90978..3b3c6823d0 100644 --- a/src/web/app/mobile/tags/ui.tag +++ b/src/web/app/mobile/tags/ui.tag @@ -1,7 +1,7 @@ <mk-ui> <div class="global" ref="global"> - <mk-ui-header ref="header" ready={ ready }></mk-ui-header> - <mk-ui-nav ref="nav" ready={ ready }></mk-ui-nav> + <mk-ui-header ref="header"></mk-ui-header> + <mk-ui-nav ref="nav"></mk-ui-nav> <div class="content" ref="main"><yield /></div> </div> <mk-stream-indicator></mk-stream-indicator> @@ -14,38 +14,27 @@ background #fff </style> <script> - @mixin \stream + this.mixin('stream'); - @ready-count = 0 - @is-drawer-opening = false + this.isDrawerOpening = false; - #@ui.on \notification (text) ~> - # alert text + this.on('mount', () => { + this.stream.on('notification', this.onStreamNotification); + }); - @on \mount ~> - @stream.on \notification @on-stream-notification - @ready! + this.on('unmount', () => { + this.stream.off('notification', this.onStreamNotification); + }); - @on \unmount ~> - @stream.off \notification @on-stream-notification + this.toggleDrawer = () => { + this.isDrawerOpening = !this.isDrawerOpening; + this.refs.nav.root.style.display = this.isDrawerOpening ? 'block' : 'none'; + }; - @ready = ~> - @ready-count++ - - if @ready-count == 2 - @init-view-position! - - @init-view-position = ~> - top = @refs.header.root.offset-height - @refs.main.style.padding-top = top + \px - - @toggle-drawer = ~> - @is-drawer-opening = !@is-drawer-opening - @refs.nav.root.style.display = if @is-drawer-opening then \block else \none - - @on-stream-notification = (notification) ~> - el = document.body.append-child document.create-element \mk-notify - riot.mount el, do + this.onStreamNotification = notification => { + riot.mount(document.body.appendChild(document.createElement('mk-notify')), { notification: notification + }); + }; </script> </mk-ui> diff --git a/src/web/app/mobile/tags/user-followers.tag b/src/web/app/mobile/tags/user-followers.tag index f328ab61de..e939da6c6e 100644 --- a/src/web/app/mobile/tags/user-followers.tag +++ b/src/web/app/mobile/tags/user-followers.tag @@ -6,20 +6,23 @@ </style> <script> - @mixin \api + this.mixin('api'); - @user = @opts.user + this.user = this.opts.user; - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/followers do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb + this.fetch = (iknow, limit, cursor, cb) => { + this.api('users/followers', { + user_id: this.user.id, + iknow: iknow, + limit: limit, + cursor: cursor ? cursor : undefined + }).then(cb); + }; - @on \mount ~> - @refs.list.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.list.on('loaded', () => { + this.trigger('loaded'); + }); + }); </script> </mk-user-followers> diff --git a/src/web/app/mobile/tags/user-following.tag b/src/web/app/mobile/tags/user-following.tag index 29f3680b65..778eb08e1c 100644 --- a/src/web/app/mobile/tags/user-following.tag +++ b/src/web/app/mobile/tags/user-following.tag @@ -6,20 +6,23 @@ </style> <script> - @mixin \api + this.mixin('api'); - @user = @opts.user + this.user = this.opts.user; - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/following do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb + this.fetch = (iknow, limit, cursor, cb) => { + this.api('users/following', { + user_id: this.user.id, + iknow: iknow, + limit: limit, + cursor: cursor ? cursor : undefined + }).then(cb); + }; - @on \mount ~> - @refs.list.on \loaded ~> - @trigger \loaded + this.on('mount', () => { + this.refs.list.on('loaded', () => { + this.trigger('loaded'); + }); + }); </script> </mk-user-following> diff --git a/src/web/app/mobile/tags/user-preview.tag b/src/web/app/mobile/tags/user-preview.tag index 2e600a8171..09cfeb49e7 100644 --- a/src/web/app/mobile/tags/user-preview.tag +++ b/src/web/app/mobile/tags/user-preview.tag @@ -85,5 +85,5 @@ color #717171 </style> - <script>@user = @opts.user</script> + <script>this.user = this.opts.user</script> </mk-user-preview> diff --git a/src/web/app/mobile/tags/user-timeline.tag b/src/web/app/mobile/tags/user-timeline.tag index 9646dda9e7..fb316dbdf9 100644 --- a/src/web/app/mobile/tags/user-timeline.tag +++ b/src/web/app/mobile/tags/user-timeline.tag @@ -9,23 +9,27 @@ </style> <script> - @mixin \api + this.mixin('api'); - @user = @opts.user - @with-media = @opts.with-media + this.user = this.opts.user; + this.withMedia = this.opts.withMedia; - @init = new Promise (res, rej) ~> - @api \users/posts do - user_id: @user.id - with_media: @with-media - .then (posts) ~> - res posts - @trigger \loaded + this.init = new Promise((res, rej) => { + this.api('users/posts', { + user_id: this.user.id, + with_media: this.withMedia + }).then(posts => { + res(posts); + this.trigger('loaded'); + }); + }); - @more = ~> - @api \users/posts do - user_id: @user.id - with_media: @with-media - max_id: @refs.timeline.tail!.id + this.more = () => { + this.api('users/posts', { + user_id: this.user.id, + with_media: this.withMedia, + max_id: this.refs.timeline.tail().id + }); + }; </script> </mk-user-timeline> diff --git a/src/web/app/mobile/tags/user.tag b/src/web/app/mobile/tags/user.tag index 37900bb617..9d95e99144 100644 --- a/src/web/app/mobile/tags/user.tag +++ b/src/web/app/mobile/tags/user.tag @@ -3,20 +3,43 @@ <header> <div class="banner" style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' }></div> <div class="body"> - <div class="top"><a class="avatar"><img src={ user.avatar_url + '?thumbnail&size=160' } alt="avatar"/></a> + <div class="top"> + <a class="avatar"> + <img src={ user.avatar_url + '?thumbnail&size=160' } alt="avatar"/> + </a> <mk-follow-button if={ SIGNIN && I.id != user.id } user={ user }></mk-follow-button> </div> <div class="title"> - <h1>{ user.name }</h1><span class="username">@{ user.username }</span><span class="followed" if={ user.is_followed }>フォローされています</span> + <h1>{ user.name }</h1> + <span class="username">@{ user.username }</span> + <span class="followed" if={ user.is_followed }>フォローされています</span> </div> <div class="bio">{ user.bio }</div> <div class="info"> - <p class="location" if={ user.location }><i class="fa fa-map-marker"></i>{ user.location }</p> - <p class="birthday" if={ user.birthday }><i class="fa fa-birthday-cake"></i>{ user.birthday.replace('-', '年').replace('-', '月') + '日' } ({ age(user.birthday) }歳)</p> + <p class="location" if={ user.location }> + <i class="fa fa-map-marker"></i>{ user.location } + </p> + <p class="birthday" if={ user.birthday }> + <i class="fa fa-birthday-cake"></i>{ user.birthday.replace('-', '年').replace('-', '月') + '日' } ({ age(user.birthday) }歳) + </p> + </div> + <div class="friends"> + <a href="{ user.username }/following"> + <b>{ user.following_count }</b> + <i>フォロー</i> + </a> + <a href="{ user.username }/followers"> + <b>{ user.followers_count }</b> + <i>フォロワー</i> + </a> </div> - <div class="friends"><a href="{ user.username }/following"><b>{ user.following_count }</b><i>フォロー</i></a><a href="{ user.username }/followers"><b>{ user.followers_count }</b><i>フォロワー</i></a></div> </div> - <nav><a data-is-active={ page == 'posts' } onclick={ goPosts }>投稿</a><a data-is-active={ page == 'media' } onclick={ goMedia }>メディア</a><a data-is-active={ page == 'graphs' } onclick={ goGraphs }>グラフ</a><a data-is-active={ page == 'likes' } onclick={ goLikes }>いいね</a></nav> + <nav> + <a data-is-active={ page == 'posts' } onclick={ go.bind(null, 'posts') }>投稿</a> + <a data-is-active={ page == 'media' } onclick={ go.bind(null, 'media') }>メディア</a> + <a data-is-active={ page == 'graphs' } onclick={ go.bind(null, 'graphs') }>グラフ</a> + <a data-is-active={ page == 'likes' } onclick={ go.bind(null, 'likes') }>いいね</a> + </nav> </header> <div class="body"> <mk-user-timeline if={ page == 'posts' } user={ user }></mk-user-timeline> @@ -154,38 +177,30 @@ </style> <script> - @age = require \s-age - - @mixin \i - @mixin \api - - @username = @opts.user - @page = if @opts.page? then @opts.page else \posts - @fetching = true - - @on \mount ~> - @api \users/show do - username: @username - .then (user) ~> - @fetching = false - @user = user - @trigger \loaded user - @update! + this.age = require('s-age'); - @go-posts = ~> - @page = \posts - @update! + this.mixin('i'); + this.mixin('api'); - @go-media = ~> - @page = \media - @update! + this.username = this.opts.user; + this.page = this.opts.page ? this.opts.page : 'posts'; + this.fetching = true; - @go-graphs = ~> - @page = \graphs - @update! + this.on('mount', () => { + this.api('users/show', { + username: this.username + }).then(user => { + this.fetching = false; + this.user = user; + this.trigger('loaded', user); + this.update(); + }); + }); - @go-likes = ~> - @page = \likes - @update! + this.go = page => { + this.update({ + page: page + }); + }; </script> </mk-user> diff --git a/src/web/app/mobile/tags/users-list.tag b/src/web/app/mobile/tags/users-list.tag index a45d2a9e07..82dfa3df45 100644 --- a/src/web/app/mobile/tags/users-list.tag +++ b/src/web/app/mobile/tags/users-list.tag @@ -70,47 +70,50 @@ </style> <script> - @mixin \i + this.mixin('i'); - @limit = 30users - @mode = \all + this.limit = 30; + this.mode = 'all'; - @fetching = true - @more-fetching = false + this.fetching = true; + this.moreFetching = false; - @on \mount ~> - @fetch ~> - @trigger \loaded + this.on('mount', () => { + this.fetch(() => this.trigger('loaded')); + }); - @fetch = (cb) ~> - @fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - null - @users = obj.users - @next = obj.next - @fetching = false - @update! - if cb? then cb! + this.fetch = cb => { + this.update({ + fetching: true + }); + this.opts.fetch(this.mode == 'iknow', this.limit, null, obj => { + this.update({ + fetching: false, + users: obj.users, + next: obj.next + }); + if (cb) cb(); + }); + }; - @more = ~> - @more-fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - @cursor - @users = @users.concat obj.users - @next = obj.next - @more-fetching = false - @update! + this.more = () => { + this.update({ + moreFetching: true + }); + this.opts.fetch(this.mode == 'iknow', this.limit, this.cursor, obj => { + this.update({ + moreFetching: false, + users: this.users.concat(obj.users), + next: obj.next + }); + }); + }; - @set-mode = (mode) ~> - @update do + this.setMode = mode => { + this.update({ mode: mode - - @fetch! + }); + this.fetch(); + }; </script> </mk-users-list> |