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/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index 1c6ed53cae..989ec48ae2 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -8,7 +8,7 @@ -
+
0 }> @@ -23,13 +23,13 @@
-
+

ドロップですか?いいですよ、ボクはカワイイですからね

ドライブには何もありません。
右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。

このフォルダーは空です

-
+
@@ -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 @@ -275,379 +275,402 @@ }); }); - 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 + 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 this.opts.folder? - if this.opts.folder? and this.opts.folder != '' - this.move this.opts.folder - else + //if (this.opts.folder) + if (this.opts.folder && this.opts.folder != '') { + this.move(this.opts.folder); + } else { this.load(); + } + }); 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 + 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); + }); - this.onStreamDriveFileCreated = (file) => { - this.addFile file, true + this.onStreamDriveFileCreated = file => { + this.addFile(file, true); + }; - this.onStreamDriveFileUpdated = (file) => { - current = if this.folder? then this.folder.id else null - if current != file.folder_id - @remove-file file - else - this.addFile 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); + } + }; - this.onStreamDriveFolderCreated = (folder) => { - this.addFolder folder, true + this.onStreamDriveFolderCreated = folder => { + this.addFolder(folder, true); + }; - this.onStreamDriveFolderUpdated = (folder) => { - current = if this.folder? then this.folder.id else null - if current != folder.parent_id - this.removeFolder folder - else - this.addFolder 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); + } + }; - this.onmousedown = (e) => { - if (contains this.refs.folders-container, e.target) or (contains this.refs.files-container, e.target) - return true + this.onmousedown = e => { + if (contains(this.refs.foldersContainer, e.target) || contains(this.refs.filesContainer, e.target)) return true; - rect = this.refs.main.getBoundingClientRect(); + const rect = this.refs.main.getBoundingClientRect(); - left = e.pageX + this.refs.main.scroll-left - rect.left - window.pageXOffset - top = e.pageY + this.refs.main.scroll-top - rect.top - window.pageYOffset + const left = e.pageX + this.refs.main.scrollLeft - rect.left - window.pageXOffset + const top = e.pageY + this.refs.main.scrollTop - rect.top - window.pageYOffset - move = (e) => - this.refs.selection.style.display = 'block' + const move = e => { + this.refs.selection.style.display = 'block'; - cursorX = e.pageX + this.refs.main.scroll-left - rect.left - window.pageXOffset - cursorY = e.pageY + this.refs.main.scroll-top - rect.top - window.pageYOffset - w = cursorX - left - h = cursorY - top + 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 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' + 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'; + } - 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' + 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'; + } + }; - up = (e) => - document.documentElement.removeEventListener 'mousemove' move - document.documentElement.removeEventListener 'mouseup' up + up = e => { + document.documentElement.removeEventListener('mousemove', move); + document.documentElement.removeEventListener('mouseup', up); - this.refs.selection.style.display = 'none' + this.refs.selection.style.display = 'none'; + }; - document.documentElement.addEventListener 'mousemove' move - document.documentElement.addEventListener 'mouseup' up + document.documentElement.addEventListener('mousemove', move); + document.documentElement.addEventListener('mouseup', up); + }; - this.path-oncontextmenu = (e) => { + this.pathOncontextmenu = e => { e.preventDefault(); e.stopImmediatePropagation(); - return false + return false; + }; - this.ondragover = (e) => { + this.ondragover = e => { e.preventDefault(); e.stopPropagation(); // ドラッグ元が自分自身の所有するアイテムかどうか - if !@isDragSource + if (!this.isDragSource) { // ドラッグされてきたものがファイルだったら - if e.dataTransfer.effectAllowed == 'all' - e.dataTransfer.dropEffect = 'copy' - else - e.dataTransfer.dropEffect = 'move' - this.draghover = true - else + e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move'; + this.draghover = true; + } else { // 自分自身にはドロップさせない - e.dataTransfer.dropEffect = 'none' - return false + e.dataTransfer.dropEffect = 'none'; + return false; + } + }; - this.ondragenter = (e) => { + this.ondragenter = e => { e.preventDefault(); - if !@isDragSource - this.draghover = true + if (!this.isDragSource) this.draghover = true; + }; - this.ondragleave = (e) => { - this.draghover = false + this.ondragleave = e => { + this.draghover = false; + }; - this.ondrop = (e) => { + this.ondrop = e => { e.preventDefault(); e.stopPropagation(); - this.draghover = false + this.draghover = false; // ドロップされてきたものがファイルだったら - if e.dataTransfer.files.length > 0 - Array.prototype.forEach.call e.dataTransfer.files, (file) => - @upload file, this.folder - return false + if (e.dataTransfer.files.length > 0) { + e.dataTransfer.files.forEach(file => { + this.upload(file, this.folder); + }); + return false; + } // データ取得 - data = e.dataTransfer.get-data 'text' - if !data? - return false + const data = e.dataTransfer.getData('text'); + if (data == null) return false; // パース - obj = JSON.parse data + // TODO: JSONじゃなかったら中断 + const obj = JSON.parse(data); // (ドライブの)ファイルだったら - if obj.type == 'file' - file = obj.id - if (this.files.some (f) => f.id == file) - return false - @remove-file file + 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: if this.folder? then this.folder.id else null - }).then(() => { - // something - .catch (err, text-status) => - console.error err - + file_id: file, + folder_id: this.folder ? this.folder.id : null + }); // (ドライブの)フォルダーだったら - else if obj.type == 'folder' - folder = obj.id + } else if (obj.type == 'folder') { + const folder = obj.id; // 移動先が自分自身ならreject - if this.folder? and folder == this.folder.id - return false - if (this.folders.some (f) => f.id == folder) - return false - this.removeFolder folder + 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: if this.folder? then this.folder.id else null + folder_id: folder, + parent_id: this.folder ? this.folder.id : null }).then(() => { // something - .catch (err) => - if err == 'detected-circular-definition' - @dialog do - '操作を完了できません' - '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。' - [ - text: 'OK' - ] + }).catch(err => { + switch (err) { + case 'detected-circular-definition': + this.dialog('操作を完了できません', + '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。', [{ + text: 'OK' + }]); + break; + default: + alert('不明なエラー' + err); + } + }); + } - return false + return false; + }; - this.oncontextmenu = (e) => { + this.oncontextmenu = e => { e.preventDefault(); e.stopImmediatePropagation(); - ctx = document.body.appendChild(document.createElement('mk-drive-browser-base-contextmenu')); - ctx = riot.mount ctx, do + const ctx = riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-base-contextmenu')), { browser: this - ctx = ctx.0 - ctx.open do - x: e.pageX - window.pageXOffset + })[0]; + ctx.open({ + x: e.pageX - window.pageXOffset, y: e.pageY - window.pageYOffset + }); - return false + return false; + }; - this.select-local-file = () => { - this.refs.file-input.click(); + this.selectLocalFile = () => { + this.refs.fileInput.click(); + }; - this.url-upload = () => { - url <~ @input-dialog do - 'URLアップロード' - 'アップロードしたいファイルのURL' - null - - if url? and url != '' + this.urlUpload = () => { + this.inputDialog('URLアップロード', 'アップロードしたいファイルのURL', null, url => { this.api('drive/files/upload_from_url', { - url: url - folder_id: if this.folder? then this.folder.id else undefined + url: url, + folder_id: this.folder ? this.folder.id : undefined + }); - @dialog do - 'アップロードをリクエストしました' - 'アップロードが完了するまで時間がかかる場合があります。' - [ - text: 'OK' - ] + this.dialog('アップロードをリクエストしました', + 'アップロードが完了するまで時間がかかる場合があります。', [{ + text: 'OK' + }]); + }); + }; this.createFolder = () => { - name <~ @input-dialog do - 'フォルダー作成' - 'フォルダー名' - null + 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(); + }); + }); + }; - this.api('drive/folders/create', { - name: name - folder_id: if this.folder? then this.folder.id else undefined - }).then((folder) => { - this.addFolder folder, true - this.update(); - .catch (err) => - console.error err - - this.change-file-input = () => { - files = this.refs.file-input.files - for i from 0 to files.length - 1 - file = files.item i - @upload file, this.folder + this.changeFileInput = () => { + this.refs.fileInput.files.forEach(file => { + this.upload(file, this.folder); + }); + }; this.upload = (file, folder) => { - if folder? and typeof folder == 'object' - folder = folder.id - this.refs.uploader.upload file, folder + if (folder && typeof folder == 'object') folder = folder.id; + this.refs.uploader.upload(file, folder); + }; - this.get-selection = () => { - this.files.filter (file) -> file._selected + this.getSelection = () => { + this.files.filter(file => file._selected); + }; - this.newWindow = (folder-id) => { - browser = document.body.appendChild(document.createElement('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 + }); + }; - this.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.loading = true - this.update(); + this.update({ + fetching: true + }); this.api('drive/folders/show', { - folder_id: target-folder - }).then((folder) => { - this.folder = folder - this.hierarchyFolders = [] + folder_id: target + }).then(folder => { + this.folder = folder; + this.hierarchyFolders = []; - x = (f) => - @hierarchyFolders.unshift f - if f.parent? - x f.parent + const dive = folder => { + this.hierarchyFolders.unshift(folder); + if (folder.parent) dive(folder.parent); + }; - if folder.parent? - x folder.parent + if (folder.parent) dive(folder.parent); this.update(); this.load(); - .catch (err, text-status) -> - console.error err + }); + }; - this.add-folder = (folder, unshift = false) => { - current = if this.folder? then this.folder.id else null - if current != folder.parent_id - return + this.addFolder = (folder, unshift = false) => { + const current = this.folder ? this.folder.id : null; + if (current != folder.parent_id) return; - if (this.folders.some (f) => f.id == folder.id) - exist = (this.folders.map (f) -> f.id).index-of folder.id - this.folders[exist] = folder + 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 + return; + } - if unshift - this.folders.unshift folder - else - this.folders.push folder + if (unshift) { + this.folders.unshift(folder); + } else { + this.folders.push(folder); + } this.update(); + }; - this.add-file = (file, unshift = false) => { - current = if this.folder? then this.folder.id else null - if current != file.folder_id - return + this.addFile = (file, unshift = false) => { + const current = this.folder ? this.folder.id : null; + if (current != file.folder_id) return; - if (this.files.some (f) => f.id == file.id) - exist = (this.files.map (f) -> f.id).index-of file.id - this.files[exist] = file + 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 + return; + } - if unshift - this.files.unshift file - else - this.files.push file + if (unshift) { + this.files.unshift(file); + } else { + this.files.push(file); + } this.update(); + }; - this.remove-folder = (folder) => { - if typeof folder == 'object' - folder = folder.id - this.folders = this.folders.filter (f) -> f.id != folder + this.removeFolder = folder => { + if (typeof folder == 'object') folder = folder.id; + this.folders = this.folders.filter(f => f.id != folder); this.update(); + }; - this.remove-file = (file) => { - if typeof file == 'object' - file = file.id - this.files = this.files.filter (f) -> f.id != file + this.removeFile = file => { + if (typeof file == 'object') file = file.id; + this.files = this.files.filter(f => f.id != file); this.update(); + }; - this.go-root = () => { - if this.folder != null - this.folder = null - this.hierarchyFolders = [] - this.update(); - this.load(); + this.goRoot = () => { + // 既にrootにいるなら何もしない + if (this.folder == null) return; + + this.update({ + folder: null, + hierarchyFolders: [] + }); + this.load(); + }; this.load = () => { - this.folders = [] - this.files = [] - this.more-folders = false - this.more-files = false - this.loading = true - this.update(); + 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; // フォルダ一覧取得 this.api('drive/folders', { - folder_id: if this.folder? then this.folder.id else null - limit: folders-max + 1 - }).then((folders) => { - if folders.length == folders-max + 1 - this.more-folders = true - folders.pop! - load-folders := folders - complete! - .catch (err, text-status) => - console.error err + 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(); + }); // ファイル一覧取得 this.api('drive/files', { - folder_id: if this.folder? then this.folder.id else null - limit: files-max + 1 - }).then((files) => { - if files.length == files-max + 1 - this.more-files = true - files.pop! - load-files := files - complete! - .catch (err, text-status) => - console.error err + 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.forEach (folder) => - this.addFolder folder - load-files.forEach (file) => - this.addFile file - this.loading = false - this.update(); - else - flag := true + let flag = false; + complete = () => { + if (flag) { + fetchedFolders.forEach(folder => this.addFolder); + fetchedFiles.forEach(file => this.addFile); + this.update({ + fetching: false + }); + } else { + flag = true; + } + }; + };