summaryrefslogtreecommitdiff
path: root/src/web/app/desktop/scripts
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2016-12-29 07:49:51 +0900
committersyuilo <syuilotan@yahoo.co.jp>2016-12-29 07:49:51 +0900
commitb3f42e62af698a67c2250533c437569559f1fdf9 (patch)
treecdf6937576e99cccf85e6fa3aa8860a1173c7cfb /src/web/app/desktop/scripts
downloadsharkey-b3f42e62af698a67c2250533c437569559f1fdf9.tar.gz
sharkey-b3f42e62af698a67c2250533c437569559f1fdf9.tar.bz2
sharkey-b3f42e62af698a67c2250533c437569559f1fdf9.zip
Initial commit :four_leaf_clover:
Diffstat (limited to 'src/web/app/desktop/scripts')
-rw-r--r--src/web/app/desktop/scripts/autocomplete.ls108
-rw-r--r--src/web/app/desktop/scripts/dialog.ls17
-rw-r--r--src/web/app/desktop/scripts/follow-scroll.ls56
-rw-r--r--src/web/app/desktop/scripts/fuck-ad-block.ls19
-rw-r--r--src/web/app/desktop/scripts/input-dialog.ls13
-rw-r--r--src/web/app/desktop/scripts/notify.ls6
-rw-r--r--src/web/app/desktop/scripts/open-window.ls8
-rw-r--r--src/web/app/desktop/scripts/stream.ls38
-rw-r--r--src/web/app/desktop/scripts/update-avatar.ls81
-rw-r--r--src/web/app/desktop/scripts/update-banner.ls81
-rw-r--r--src/web/app/desktop/scripts/update-wallpaper.ls35
-rw-r--r--src/web/app/desktop/scripts/user-preview.ls74
12 files changed, 536 insertions, 0 deletions
diff --git a/src/web/app/desktop/scripts/autocomplete.ls b/src/web/app/desktop/scripts/autocomplete.ls
new file mode 100644
index 0000000000..636bb7f277
--- /dev/null
+++ b/src/web/app/desktop/scripts/autocomplete.ls
@@ -0,0 +1,108 @@
+# Autocomplete
+#================================
+
+get-caret-coordinates = require 'textarea-caret-position'
+riot = require 'riot'
+
+# オートコンプリートを管理するクラスです。
+class Autocomplete
+
+ @textarea = null
+ @suggestion = null
+
+ # 対象のテキストエリアを与えてインスタンスを初期化します。
+ (textarea) ~>
+ @textarea = textarea
+
+ # このインスタンスにあるテキストエリアの入力のキャプチャを開始します。
+ attach: ~>
+ @textarea.add-event-listener \input @on-input
+
+ # このインスタンスにあるテキストエリアの入力のキャプチャを解除します。
+ detach: ~>
+ @textarea.remove-event-listener \input @on-input
+ @close!
+
+ # テキスト入力時
+ on-input: ~>
+ @close!
+
+ caret = @textarea.selection-start
+ text = @textarea.value.substr 0 caret
+
+ mention-index = text.last-index-of \@
+
+ if mention-index == -1
+ return
+
+ username = text.substr mention-index + 1
+
+ if not username.match /^[a-zA-Z0-9-]+$/
+ return
+
+ @open \user username
+
+ # サジェストを提示します。
+ open: (type, q) ~>
+ # 既に開いているサジェストは閉じる
+ @close!
+
+ # サジェスト要素作成
+ suggestion = document.create-element \mk-autocomplete-suggestion
+
+ # ~ サジェストを表示すべき位置を計算 ~
+
+ caret-position = get-caret-coordinates @textarea, @textarea.selection-start
+
+ rect = @textarea.get-bounding-client-rect!
+
+ x = rect.left + window.page-x-offset + caret-position.left
+ y = rect.top + window.page-y-offset + caret-position.top
+
+ suggestion.style.left = x + \px
+ suggestion.style.top = y + \px
+
+ # 要素追加
+ el = document.body.append-child suggestion
+
+ # マウント
+ mounted = riot.mount el, do
+ textarea: @textarea
+ complete: @complete
+ close: @close
+ type: type
+ q: q
+
+ @suggestion = mounted.0
+
+ # サジェストを閉じます。
+ close: ~>
+ if !@suggestion?
+ return
+
+ @suggestion.unmount!
+ @suggestion = null
+
+ @textarea.focus!
+
+ # オートコンプリートする
+ complete: (user) ~>
+ @close!
+ value = user.username
+
+ caret = @textarea.selection-start
+ source = @textarea.value
+
+ before = source.substr 0 caret
+ trimed-before = before.substring 0 before.last-index-of \@
+ after = source.substr caret
+
+ # 結果を挿入する
+ @textarea.value = trimed-before + \@ + value + ' ' + after
+
+ # キャレットを戻す
+ @textarea.focus!
+ pos = caret + value.length
+ @textarea.set-selection-range pos, pos
+
+module.exports = Autocomplete
diff --git a/src/web/app/desktop/scripts/dialog.ls b/src/web/app/desktop/scripts/dialog.ls
new file mode 100644
index 0000000000..f3dd6cea1b
--- /dev/null
+++ b/src/web/app/desktop/scripts/dialog.ls
@@ -0,0 +1,17 @@
+# Dialog
+#================================
+
+riot = require 'riot'
+
+module.exports = (title, text, buttons, can-through, on-through) ~>
+ dialog = document.body.append-child document.create-element \mk-dialog
+ controller = riot.observable!
+ riot.mount dialog, do
+ controller: controller
+ title: title
+ text: text
+ buttons: buttons
+ can-through: can-through
+ on-through: on-through
+ controller.trigger \open
+ return controller
diff --git a/src/web/app/desktop/scripts/follow-scroll.ls b/src/web/app/desktop/scripts/follow-scroll.ls
new file mode 100644
index 0000000000..5072e9c583
--- /dev/null
+++ b/src/web/app/desktop/scripts/follow-scroll.ls
@@ -0,0 +1,56 @@
+class Follower
+ (el) ->
+ @follower = el
+ @last-scroll-top = window.scroll-y
+ @initial-follower-top = @follower.get-bounding-client-rect!.top
+ @page-top = 48
+
+ follow: ->
+ window-height = window.inner-height
+ follower-height = @follower.offset-height
+
+ scroll-top = window.scroll-y
+ scroll-bottom = scroll-top + window-height
+
+ follower-top = @follower.get-bounding-client-rect!.top + scroll-top
+ follower-bottom = follower-top + follower-height
+
+ height-delta = Math.abs window-height - follower-height
+ scroll-delta = @last-scroll-top - scroll-top
+
+ is-scrolling-down = (scroll-top > @last-scroll-top)
+ is-window-larger = (window-height > follower-height)
+
+ console.log @initial-follower-top
+
+ if (is-window-larger && scroll-top > @initial-follower-top) || (!is-window-larger && scroll-top > @initial-follower-top + height-delta)
+ @follower.class-list.add \fixed
+ else if !is-scrolling-down && scroll-top + @page-top <= @initial-follower-top
+ @follower.class-list.remove \fixed
+ @follower.style.top = 0
+ return
+
+ drag-bottom-down = (follower-bottom <= scroll-bottom && is-scrolling-down)
+ drag-top-up = (follower-top >= scroll-top + @page-top && !is-scrolling-down)
+
+ if drag-bottom-down
+ console.log \down
+ @follower.style.top = if is-window-larger then 0 else -height-delta + \px
+ else if drag-top-up
+ console.log \up
+ @follower.style.top = @page-top + \px
+ else if @follower.class-list.contains \fixed
+ console.log \-
+ current-top = parse-int @follower.style.top, 10
+
+ min-top = -height-delta
+ scrolled-top = current-top + scroll-delta
+
+ is-page-at-bottom = (scroll-top + window-height >= document.body.offset-height)
+ new-top = if is-page-at-bottom then min-top else scrolled-top
+
+ @follower.style.top = new-top + \px
+
+ @last-scroll-top = scroll-top
+
+module.exports = Follower
diff --git a/src/web/app/desktop/scripts/fuck-ad-block.ls b/src/web/app/desktop/scripts/fuck-ad-block.ls
new file mode 100644
index 0000000000..55431fcd00
--- /dev/null
+++ b/src/web/app/desktop/scripts/fuck-ad-block.ls
@@ -0,0 +1,19 @@
+# FUCK AD BLOCK
+#================================
+
+require 'fuck-adblock'
+dialog = require './dialog.ls'
+
+module.exports = ~>
+ if fuck-ad-block == undefined
+ ad-block-detected!
+ else
+ fuck-ad-block.on-detected ad-block-detected
+
+function ad-block-detected
+ dialog do
+ '<i class="fa fa-exclamation-triangle"></i>広告ブロッカーを無効にしてください'
+ '<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。'
+ [
+ text: \OK
+ ]
diff --git a/src/web/app/desktop/scripts/input-dialog.ls b/src/web/app/desktop/scripts/input-dialog.ls
new file mode 100644
index 0000000000..f75b12dd01
--- /dev/null
+++ b/src/web/app/desktop/scripts/input-dialog.ls
@@ -0,0 +1,13 @@
+# Input Dialog
+#================================
+
+riot = require 'riot'
+
+module.exports = (title, placeholder, default-value, on-ok, on-cancel) ~>
+ dialog = document.body.append-child document.create-element \mk-input-dialog
+ riot.mount dialog, do
+ title: title
+ placeholder: placeholder
+ default: default-value
+ on-ok: on-ok
+ on-cancel: on-cancel
diff --git a/src/web/app/desktop/scripts/notify.ls b/src/web/app/desktop/scripts/notify.ls
new file mode 100644
index 0000000000..919bbc3dcf
--- /dev/null
+++ b/src/web/app/desktop/scripts/notify.ls
@@ -0,0 +1,6 @@
+riot = require \riot
+
+module.exports = (message) ~>
+ notification = document.body.append-child document.create-element \mk-ui-notification
+ riot.mount notification, do
+ message: message
diff --git a/src/web/app/desktop/scripts/open-window.ls b/src/web/app/desktop/scripts/open-window.ls
new file mode 100644
index 0000000000..4388272ecf
--- /dev/null
+++ b/src/web/app/desktop/scripts/open-window.ls
@@ -0,0 +1,8 @@
+riot = require \riot
+
+function open(name, opts)
+ window = document.body.append-child document.create-element name
+ riot.mount window, opts
+
+riot.mixin \open-window do
+ open-window: open
diff --git a/src/web/app/desktop/scripts/stream.ls b/src/web/app/desktop/scripts/stream.ls
new file mode 100644
index 0000000000..f84d6097a7
--- /dev/null
+++ b/src/web/app/desktop/scripts/stream.ls
@@ -0,0 +1,38 @@
+# Stream
+#================================
+
+stream = require '../../common/scripts/stream.ls'
+get-post-summary = require '../../common/scripts/get-post-summary.ls'
+riot = require \riot
+
+module.exports = (me) ~>
+ s = stream me
+
+ s.event.on \drive_file_created (file) ~>
+ n = new Notification 'ファイルがアップロードされました' do
+ body: file.name
+ icon: file.url + '?thumbnail&size=64'
+ set-timeout (n.close.bind n), 5000ms
+
+ s.event.on \mention (post) ~>
+ n = new Notification "#{post.user.name}さんから:" do
+ body: get-post-summary post
+ icon: post.user.avatar_url + '?thumbnail&size=64'
+ set-timeout (n.close.bind n), 6000ms
+
+ s.event.on \reply (post) ~>
+ n = new Notification "#{post.user.name}さんから返信:" do
+ body: get-post-summary post
+ icon: post.user.avatar_url + '?thumbnail&size=64'
+ set-timeout (n.close.bind n), 6000ms
+
+ s.event.on \quote (post) ~>
+ n = new Notification "#{post.user.name}さんが引用:" do
+ body: get-post-summary post
+ icon: post.user.avatar_url + '?thumbnail&size=64'
+ set-timeout (n.close.bind n), 6000ms
+
+ riot.mixin \stream do
+ stream: s.event
+ get-stream-state: s.get-state
+ stream-state-ev: s.state-ev
diff --git a/src/web/app/desktop/scripts/update-avatar.ls b/src/web/app/desktop/scripts/update-avatar.ls
new file mode 100644
index 0000000000..513a59074c
--- /dev/null
+++ b/src/web/app/desktop/scripts/update-avatar.ls
@@ -0,0 +1,81 @@
+# Update Avatar
+#================================
+
+riot = require 'riot'
+dialog = require './dialog.ls'
+api = require '../../common/scripts/api.ls'
+
+module.exports = (I, cb, file = null) ~>
+
+ @file-selected = (file) ~>
+ cropper = document.body.append-child document.create-element \mk-crop-window
+ cropper = riot.mount cropper, do
+ file: file
+ title: 'アバターとして表示する部分を選択'
+ aspect-ratio: 1 / 1
+ .0
+ cropper.on \cropped (blob) ~>
+ data = new FormData!
+ data.append \i I.token
+ data.append \file blob, file.name + '.cropped.png'
+ api I, \drive/folders/find do
+ name: 'アイコン'
+ .then (icon-folder) ~>
+ if icon-folder.length == 0
+ api I, \drive/folders/create do
+ name: 'アイコン'
+ .then (icon-folder) ~>
+ @uplaod data, icon-folder
+ else
+ @uplaod data, icon-folder.0
+ cropper.on \skiped ~>
+ @set file
+
+ @uplaod = (data, folder) ~>
+
+ progress = document.body.append-child document.create-element \mk-progress-dialog
+ progress = riot.mount progress, do
+ title: '新しいアバターをアップロードしています'
+ .0
+
+ if folder?
+ data.append \folder_id folder.id
+
+ xhr = new XMLHttpRequest!
+ xhr.open \POST CONFIG.api.url + \/drive/files/create true
+ xhr.onload = (e) ~>
+ file = JSON.parse e.target.response
+ progress.close!
+ @set file
+
+ xhr.upload.onprogress = (e) ~>
+ if e.length-computable
+ progress.update-progress e.loaded, e.total
+
+ xhr.send data
+
+ @set = (file) ~>
+ api I, \i/update do
+ avatar_id: file.id
+ .then (i) ~>
+ dialog do
+ '<i class="fa fa-info-circle"></i>アバターを更新しました'
+ '新しいアバターが反映されるまで時間がかかる場合があります。'
+ [
+ text: \わかった
+ ]
+ if cb? then cb i
+ .catch (err) ~>
+ console.error err
+ #@opts.ui.trigger \notification 'Error!'
+
+ if file?
+ @file-selected file
+ else
+ browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
+ browser = riot.mount browser, do
+ multiple: false
+ title: '<i class="fa fa-picture-o"></i>アバターにする画像を選択'
+ .0
+ browser.one \selected (file) ~>
+ @file-selected file
diff --git a/src/web/app/desktop/scripts/update-banner.ls b/src/web/app/desktop/scripts/update-banner.ls
new file mode 100644
index 0000000000..5754cdcdb1
--- /dev/null
+++ b/src/web/app/desktop/scripts/update-banner.ls
@@ -0,0 +1,81 @@
+# Update Banner
+#================================
+
+riot = require 'riot'
+dialog = require './dialog.ls'
+api = require '../../common/scripts/api.ls'
+
+module.exports = (I, cb, file = null) ~>
+
+ @file-selected = (file) ~>
+ cropper = document.body.append-child document.create-element \mk-crop-window
+ cropper = riot.mount cropper, do
+ file: file
+ title: 'バナーとして表示する部分を選択'
+ aspect-ratio: 16 / 9
+ .0
+ cropper.on \cropped (blob) ~>
+ data = new FormData!
+ data.append \i I.token
+ data.append \file blob, file.name + '.cropped.png'
+ api I, \drive/folders/find do
+ name: 'バナー'
+ .then (banner-folder) ~>
+ if banner-folder.length == 0
+ api I, \drive/folders/create do
+ name: 'バナー'
+ .then (banner-folder) ~>
+ @uplaod data, banner-folder
+ else
+ @uplaod data, banner-folder.0
+ cropper.on \skiped ~>
+ @set file
+
+ @uplaod = (data, folder) ~>
+
+ progress = document.body.append-child document.create-element \mk-progress-dialog
+ progress = riot.mount progress, do
+ title: '新しいバナーをアップロードしています'
+ .0
+
+ if folder?
+ data.append \folder_id folder.id
+
+ xhr = new XMLHttpRequest!
+ xhr.open \POST CONFIG.api.url + \/drive/files/create true
+ xhr.onload = (e) ~>
+ file = JSON.parse e.target.response
+ progress.close!
+ @set file
+
+ xhr.upload.onprogress = (e) ~>
+ if e.length-computable
+ progress.update-progress e.loaded, e.total
+
+ xhr.send data
+
+ @set = (file) ~>
+ api I, \i/update do
+ banner_id: file.id
+ .then (i) ~>
+ dialog do
+ '<i class="fa fa-info-circle"></i>バナーを更新しました'
+ '新しいバナーが反映されるまで時間がかかる場合があります。'
+ [
+ text: \わかりました。
+ ]
+ if cb? then cb i
+ .catch (err) ~>
+ console.error err
+ #@opts.ui.trigger \notification 'Error!'
+
+ if file?
+ @file-selected file
+ else
+ browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
+ browser = riot.mount browser, do
+ multiple: false
+ title: '<i class="fa fa-picture-o"></i>バナーにする画像を選択'
+ .0
+ browser.one \selected (file) ~>
+ @file-selected file
diff --git a/src/web/app/desktop/scripts/update-wallpaper.ls b/src/web/app/desktop/scripts/update-wallpaper.ls
new file mode 100644
index 0000000000..49632400c0
--- /dev/null
+++ b/src/web/app/desktop/scripts/update-wallpaper.ls
@@ -0,0 +1,35 @@
+# Update Wallpaper
+#================================
+
+riot = require 'riot'
+dialog = require './dialog.ls'
+api = require '../../common/scripts/api.ls'
+
+module.exports = (I, cb, file = null) ~>
+
+ @set = (file) ~>
+ api I, \i/appdata/set do
+ data: JSON.stringify do
+ wallpaper: file.id
+ .then (i) ~>
+ dialog do
+ '<i class="fa fa-info-circle"></i>壁紙を更新しました'
+ '新しい壁紙が反映されるまで時間がかかる場合があります。'
+ [
+ text: \はい
+ ]
+ if cb? then cb i
+ .catch (err) ~>
+ console.error err
+ #@opts.ui.trigger \notification 'Error!'
+
+ if file?
+ @set file
+ else
+ browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
+ browser = riot.mount browser, do
+ multiple: false
+ title: '<i class="fa fa-picture-o"></i>壁紙にする画像を選択'
+ .0
+ browser.one \selected (file) ~>
+ @set file
diff --git a/src/web/app/desktop/scripts/user-preview.ls b/src/web/app/desktop/scripts/user-preview.ls
new file mode 100644
index 0000000000..0c5a67aedb
--- /dev/null
+++ b/src/web/app/desktop/scripts/user-preview.ls
@@ -0,0 +1,74 @@
+# User Preview
+#================================
+
+riot = require \riot
+
+riot.mixin \user-preview do
+ init: ->
+ @on \mount ~>
+ scan.call @
+ @on \updated ~>
+ scan.call @
+
+ function scan
+ elems = @root.query-selector-all '[data-user-preview]:not([data-user-preview-attached])'
+ elems.for-each attach.bind @
+
+function attach el
+ el.set-attribute \data-user-preview-attached true
+ user = el.get-attribute \data-user-preview
+
+ tag = null
+
+ show-timer = null
+ hide-timer = null
+
+ el.add-event-listener \mouseover ~>
+ clear-timeout show-timer
+ clear-timeout hide-timer
+ show-timer := set-timeout ~>
+ show!
+ , 500ms
+
+ el.add-event-listener \mouseleave ~>
+ clear-timeout show-timer
+ clear-timeout hide-timer
+ hide-timer := set-timeout ~>
+ close!
+ , 500ms
+
+ @on \unmount ~>
+ clear-timeout show-timer
+ clear-timeout hide-timer
+ close!
+
+ function show
+ if tag?
+ return
+
+ preview = document.create-element \mk-user-preview
+
+ rect = el.get-bounding-client-rect!
+ x = rect.left + el.offset-width + window.page-x-offset
+ y = rect.top + window.page-y-offset
+
+ preview.style.top = y + \px
+ preview.style.left = x + \px
+
+ preview.add-event-listener \mouseover ~>
+ clear-timeout hide-timer
+
+ preview.add-event-listener \mouseleave ~>
+ clear-timeout show-timer
+ hide-timer := set-timeout ~>
+ close!
+ , 500ms
+
+ tag := riot.mount (document.body.append-child preview), do
+ user: user
+ .0
+
+ function close
+ if tag?
+ tag.close!
+ tag := null