This commit is contained in:
syuilo 2017-02-22 01:05:23 +09:00
parent 23499c386e
commit 842c3e09ce
37 changed files with 680 additions and 659 deletions

View file

@ -108,19 +108,23 @@
<script>
this.mixin('api');
this.session = this.opts.session
this.app = @session.app
this.session = this.opts.session;
this.app = this.session.app;
this.cancel = () => {
this.api('auth/deny', {
token: @session.token
token: this.session.token
}).then(() => {
this.trigger('denied');
});
};
this.accept = () => {
this.api('auth/accept', {
token: @session.token
token: this.session.token
}).then(() => {
this.trigger('accepted');
});
};
</script>
</mk-form>

View file

@ -91,47 +91,57 @@
this.mixin('i');
this.mixin('api');
this.state = null
this.fetching = true
this.state = null;
this.fetching = true;
this.token = window.location.href.split '/' .pop!
this.token = window.location.href.split('/').pop();
this.on('mount', () => {
if not this.SIGNIN then return
if (!this.SIGNIN) return;
// Fetch session
this.api('auth/session/show', {
token: @token
}).then((session) => {
this.session = session
this.fetching = false
token: this.token
}).then(session => {
this.session = session;
this.fetching = false;
// 既に連携していた場合
if @session.app.is_authorized
if (this.session.app.is_authorized) {
this.api('auth/accept', {
token: @session.token
token: this.session.token
}).then(() => {
@accepted!
else
this.state = 'waiting'
this.update();
this.accepted();
});
} else {
this.update({
state: 'waiting'
});
this.refs.form.on('denied', () => {
this.state = 'denied'
this.update();
this.update({
state: 'denied'
});
});
this.refs.form.on 'accepted' @accepted
.catch (error) =>
this.fetching = false
this.state = 'fetch-session-error'
this.update();
this.refs.form.on('accepted', this.accepted);
}
}).catch(error => {
this.update({
fetching: false,
state: 'fetch-session-error'
});
});
});
this.accepted = () => {
this.state = 'accepted'
this.update();
this.update({
state: 'accepted'
});
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>

View file

@ -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>

View file

@ -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');

View file

@ -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>
this.on('mount', () => {
text = this.root.innerHTML
this.root.innerHTML = ''
(text.split '').forEach (c, i) =>
ce = document.createElement 'span'
ce.innerHTML = c
ce.style.animationDelay = (i / 10) + 's'
this.root.appendChild ce
</script>
</mk-ripple-string>

View file

@ -1,9 +1,16 @@
<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>
<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

View file

@ -41,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');

View file

@ -455,6 +455,7 @@
wait: false
});
});
};
this.cat = () => {
this.refs.text.value += getCat();

View file

@ -180,64 +180,73 @@
<script>
this.mixin('api');
this.nid-state = null
this.nidState = null;
this.on-change-nid = () => {
nid = this.refs.nid.value
this.onChangeNid = () => {
const nid = this.refs.nid.value;
if nid == ''
this.nid-state = null
this.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?
this.nid-state = err
this.update();
else
this.nid-state = 'wait'
this.update();
if (err) {
this.update({
nidState: err
});
return;
}
this.update({
nidState: 'wait'
});
this.api('app/name_id/available', {
name_id: nid
}).then((result) => {
if result.available
this.nid-state = 'ok'
else
this.nid-state = 'unavailable'
this.update();
.catch (err) =>
this.nid-state = 'error'
this.update();
}).then(result => {
this.update({
nidState: result.available ? 'ok' : 'unavailable'
});
}).catch(err => {
this.update({
nidState: 'error'
});
});
};
this.onsubmit = () => {
name = this.refs.name.value
nid = this.refs.nid.value
description = this.refs.description.value
cb = this.refs.cb.value
permission = []
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 = [];
this.refs.permission.query-selector-all 'input' .forEach (el) =>
if el.checked then permission.push el.value
this.refs.permission.querySelectorAll('input').forEach(el => {
if (el.checked) permission.push(el.value);
});
locker = document.body.appendChild(document.createElement('mk-locker'));
const locker = document.body.appendChild(document.createElement('mk-locker'));
this.api('app/create', {
name: name
name_id: nid
description: description
callback_url: cb
permission: permission.join ','
name: name,
name_id: nid,
description: description,
callback_url: cb,
permission: permission.join(',')
}).then(() => {
location.href = '/apps'
.catch =>
alert 'アプリの作成に失敗しました。再度お試しください。'
locker.parentNode.removeChild locker
location.href = '/apps';
}).catch(() => {
alert('アプリの作成に失敗しました。再度お試しください。');
locker.parentNode.removeChild(locker);
});
};
</script>
</mk-new-app-form>

View file

@ -12,19 +12,21 @@
<style>
:scope
display block
</style>
<script>
this.mixin('api');
this.fetching = true
this.fetching = true;
this.on('mount', () => {
this.api('app/show', {
app_id: this.opts.app
}).then((app) => {
this.app = app
this.fetching = false
this.update();
}).then(app => {
this.update({
fetching: false,
app: app
});
});
});
</script>
</mk-app-page>

View file

@ -13,18 +13,21 @@
<style>
:scope
display block
</style>
<script>
this.mixin('api');
this.fetching = true
this.fetching = true;
this.on('mount', () => {
this.api 'my/apps'
}).then((apps) => {
this.api('my/apps').then(apps => {
this.fetching = false
this.apps = apps
this.update();
this.update({
fetching: false,
apps: apps
});
});
});
</script>
</mk-apps-page>

View file

@ -2,10 +2,5 @@
<style>
:scope
display block
</style>
</mk-index>

View file

@ -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>
@ -131,247 +131,263 @@
this.mixin('api');
this.mixin('stream');
this.files = []
this.folders = []
this.hierarchyFolders = []
this.selected-files = []
this.files = [];
this.folders = [];
this.hierarchyFolders = [];
this.selectedFiles = [];
// 現在の階層(フォルダ)
// * null でルートを表す
this.folder = null
this.folder = null;
this.file = null
this.file = null;
this.is-select-mode = this.opts.select? and this.opts.select
this.multiple = if this.opts.multiple? then this.opts.multiple else false
this.isSelectMode = this.opts.select;
this.multiple =this.opts.multiple;
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
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 != ''
@cd this.opts.folder, true
else if this.opts.file? and this.opts.file != ''
@cf this.opts.file, true
else
//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();
}
});
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);
}
};
@_move = (ev) =>
this.move ev.item.folder
this.move = ev => {
this.move(ev.item.folder);
};
this.move = (target-folder) => {
@cd target-folder
this.cd = (target, silent = false) => {
this.file = null;
this.cd = (target-folder, silent = false) => {
this.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
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
if folder.parent?
x folder.parent
if (folder.parent) dive(folder.parent);
this.update();
this.trigger 'open-folder' this.folder, silent
this.trigger('open-folder', this.folder, silent);
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)
return
// 追加しようとしているフォルダを既に所有してたら中断
if (this.folders.some(f => f.id == folder.id)) 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 or this.file != null
this.file = null
this.folder = null
this.hierarchyFolders = []
this.update();
this.goRoot = () => {
if (this.folder || this.file) {
this.update({
file: null,
folder: null,
hierarchyFolders: []
});
this.trigger('move-root');
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
});
this.trigger('begin-load');
load-folders = null
load-files = null
let fetchedFolders = null;
let fetchedFiles = null;
folders-max = 20
files-max = 20
const foldersMax = 20;
const filesMax = 20;
// フォルダ一覧取得
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
flag = false
complete = =>
if flag
load-folders.forEach (folder) =>
this.addFolder folder
load-files.forEach (file) =>
this.addFile file
this.loading = false
this.update();
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();
});
let flag = false;
complete = () => {
if (flag) {
fetchedFolders.forEach(folder => this.addFolder);
fetchedFiles.forEach(file => this.addFile);
this.update({
fetching: false
});
// 一連の読み込みが完了したイベントを発行
this.trigger('loaded');
else
flag := true
} else {
flag = true;
// 一連の読み込みが半分完了したイベントを発行
this.trigger('load-mid');
}
};
};
this.choose-file = (file) => {
if @is-select-mode
exist = @selected-files.some (f) => f.id == file.id
if exist
this.selected-files = (@selected-files.filter (f) => { f.id != file.id)
else
@selected-files.push file
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' @selected-files
else
@cf file
this.trigger('change-selected', this.selectedFiles);
} else {
this.cf(file);
}
};
this.cf = (file, silent = false) => {
if typeof file == 'object'
file = file.id
if (typeof file == 'object') file = file.id;
this.loading = true
this.update();
this.update({
fetching: true
});
this.api('drive/files/show', {
file_id: file
}).then((file) => {
this.file = file
this.folder = null
this.hierarchyFolders = []
}).then(file => {
this.file = file;
this.folder = null;
this.hierarchyFolders = [];
x = (f) =>
@hierarchyFolders.unshift f
if f.parent?
x f.parent
if file.folder?
x file.folder
if (file.folder) dive(file.folder);
this.update();
this.trigger 'open-file' this.file, silent
this.trigger('open-file', this.file, silent);
});
};
const dive = folder => {
this.hierarchyFolders.unshift(folder);
if (folder.parent) dive(folder.parent);
};
</script>
</mk-drive>

View file

@ -185,17 +185,18 @@
this.mixin('api');
this.file = this.opts.file
this.kind = this.file.type.split '/' .0
this.file = this.opts.file;
this.kind = this.file.type.split('/')[0];
this.rename = () => {
name = window.prompt '名前を変更' this.file.name
if name? and name != '' and name != this.file.name
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
this.parent.cf(this.file, true);
});
};
</script>
</mk-drive-file-viewer>

View file

@ -124,14 +124,16 @@
<script>
this.bytesToSize = require('../../../common/scripts/bytesToSize.js');
this.browser = this.parent
this.file = this.opts.file
this.is-selected = this.browser.selected-files.some (f) => f.id == this.file.id
this.browser = this.parent;
this.file = this.opts.file;
this.isSelected = this.browser.selectedFiles.some(f => f.id == this.file.id);
this.browser.on('change-selected', (selects) => {
this.is-selected = selects.some (f) => f.id == this.file.id
this.browser.on('change-selected', selections => {
this.isSelected = selections.some(f => f.id == this.file.id);
});
this.onclick = () => {
this.browser.choose-file this.file
this.browser.chooseFile(this.file);
};
</script>
</mk-drive-file>

View file

@ -37,10 +37,11 @@
</style>
<script>
this.browser = this.parent
this.folder = this.opts.folder
this.browser = this.parent;
this.folder = this.opts.folder;
this.onclick = () => {
this.browser.move this.folder
this.browser.move(this.folder);
};
</script>
</mk-drive-folder>

View file

@ -52,54 +52,70 @@
this.mixin('is-promise');
this.mixin('stream');
this.user = null
this.user-promise = if @is-promise this.opts.user then this.opts.user else Promise.resolve this.opts.user
this.init = true
this.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;
this.on('mount', () => {
this.user-promise}).then((user) => {
this.user = user
this.init = false
this.update();
this.stream.on 'follow' this.on-stream-follow
this.stream.on 'unfollow' this.on-stream-unfollow
this.userPromise.then(user => {
this.update({
init: false,
user: user
});
this.stream.on('follow', this.onStreamFollow);
this.stream.on('unfollow', this.onStreamUnfollow);
});
});
this.on('unmount', () => {
this.stream.off 'follow' this.on-stream-follow
this.stream.off 'unfollow' this.on-stream-unfollow
this.stream.off('follow', this.onStreamFollow);
this.stream.off('unfollow', this.onStreamUnfollow);
});
this.on-stream-follow = (user) => {
if user.id == this.user.id
this.user = user
this.update();
this.onStreamFollow = user => {
if (user.id == this.user.id) {
this.update({
user: user
});
}
};
this.on-stream-unfollow = (user) => {
if user.id == this.user.id
this.user = user
this.update();
this.onStreamUnfollow = user => {
if (user.id == this.user.id) {
this.update({
user: user
});
}
};
this.onclick = () => {
this.wait = true
if this.user.is_following
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
this.user.is_following = false;
}).catch(err => {
console.error(err);
}).then(() => {
this.wait = false
this.wait = false;
this.update();
else
});
} else {
this.api('following/create', {
user_id: this.user.id
}).then(() => {
this.user.is_following = true
.catch (err) ->
console.error err
this.user.is_following = true;
}).catch(err => {
console.error(err);
}).then(() => {
this.wait = false
this.wait = false;
this.update();
});
}
};
</script>
</mk-follow-button>

View file

@ -18,10 +18,11 @@
</style>
<script>
this.images = this.opts.images
this.image = @images.0
this.images = this.opts.images;
this.image = this.images[0];
this.click = () => {
window.open @image.url
window.open(this.image.url);
};
</script>
</mk-images-viewer>

View file

@ -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');

View file

@ -108,6 +108,6 @@
</style>
<script>
this.mixin('get-post-summary');
this.notification = this.opts.notification
this.notification = this.opts.notification;
</script>
</mk-notification-preview>

View file

@ -168,6 +168,6 @@
</style>
<script>
this.mixin('get-post-summary');
this.notification = this.opts.notification
this.notification = this.opts.notification;
</script>
</mk-notification>

View file

@ -61,33 +61,36 @@
this.mixin('stream');
this.mixin('get-post-summary');
this.notifications = []
this.loading = true
this.notifications = [];
this.loading = true;
this.on('mount', () => {
this.api 'i/notifications'
}).then((notifications) => {
this.notifications = notifications
this.loading = false
this.update();
this.trigger('loaded');
.catch (err, text-status) ->
console.error err
this.api('i/notifications').then(notifications => {
this.update({
loading: false,
notifications: notifications
});
});
this.stream.on 'notification' this.on-notification
this.stream.on('notification', this.onNotification);
});
this.on('unmount', () => {
this.stream.off 'notification' this.on-notification
this.stream.off('notification', this.onNotification);
});
this.on-notification = (notification) => {
@notifications.unshift notification
this.onNotification = notification => {
this.notifications.unshift(notification);
this.update();
};
this.on('update', () => {
@notifications.forEach (notification) =>
date = (new Date notification.created_at).getDate()
month = (new Date notification.created_at).getMonth() + 1
notification._date = date
notification._datetext = month + '月 ' + date + '日'
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>

View file

@ -20,19 +20,19 @@
Velocity(this.root, {
bottom: '0px'
}, {
duration: 500ms
duration: 500,
easing: 'ease-out'
}
});
setTimeout =>
setTimeout(() => {
Velocity(this.root, {
bottom: '-64px'
}, {
duration: 500ms
easing: 'ease-out'
complete: =>
this.unmount();
}
, 6000ms
duration: 500,
easing: 'ease-out',
complete: () => this.unmount()
});
}, 6000);
});
</script>
</mk-notify>

View file

@ -342,89 +342,111 @@
this.on('mount', () => {
this.api('posts/show', {
post_id: this.opts.post
}).then((post) => {
this.post = post
this.is-repost = this.post.repost?
this.p = if @is-repost then this.post.repost else this.post
this.summary = @get-post-summary this.p
}).then(post => {
const isRepost = post.repost != null;
const p = isRepost ? post.repost : post;
this.update({
fetching: false,
post: post,
isRepost: isRepost,
p: p
});
this.trigger('loaded');
this.fetching = false
this.update();
if this.p.text?
tokens = @analyze this.p.text
this.refs.text.innerHTML = @compile tokens
if (this.p.text) {
const tokens = this.analyze(this.p.text);
this.refs.text.children.forEach (e) =>
if e.tag-name == 'MK-URL'
riot.mount e
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) =>
this.preview = this.refs.text.appendChild(document.createElement('mk-url-preview'));
riot.mount this.preview, do
.filter(t => t.type == 'link')
.map(t => {
riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), {
url: t.content
});
});
}
// Get likes
this.api('posts/likes', {
post_id: this.p.id
post_id: this.p.id,
limit: 8
}).then((likes) => {
this.likes = likes
this.update();
}).then(likes => {
this.update({
likes: likes
});
});
// Get reposts
this.api('posts/reposts', {
post_id: this.p.id
post_id: this.p.id,
limit: 8
}).then((reposts) => {
this.reposts = reposts
this.update();
}).then(reposts => {
this.update({
reposts: reposts
});
});
// Get replies
this.api('posts/replies', {
post_id: this.p.id
post_id: this.p.id,
limit: 8
}).then((replies) => {
this.replies = replies
this.update();
}).then(replies => {
this.update({
replies: replies
});
});
});
});
this.reply = () => {
this.openPostForm do
riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), {
reply: this.p
});
};
this.repost = () => {
text = window.prompt '「' + @summary + '」をRepost'
if text?
this.api('posts/create', {
repost_id: this.p.id
text: if text == '' then undefined else text
riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), {
post: this.p
});
};
this.like = () => {
if this.p.is_liked
if (this.p.is_liked) {
this.api('posts/likes/delete', {
post_id: this.p.id
}).then(() => {
this.p.is_liked = false
this.p.is_liked = false;
this.update();
else
});
} else {
this.api('posts/likes/create', {
post_id: this.p.id
}).then(() => {
this.p.is_liked = true
this.p.is_liked = true;
this.update();
});
}
};
this.load-context = () => {
this.loading-context = true
this.loadContext = () => {
this.loadingContext = true;
// Get context
// Fetch context
this.api('posts/context', {
post_id: this.p.reply_to_id
}).then((context) => {
this.context = context.reverse!
this.loading-context = false
this.update();
}).then(context => {
this.update({
loadContext: false,
content: context.reverse()
});
});
};
</script>
</mk-post-detail>

View file

@ -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');
getCat = require('../../common/scripts/get-cat');
this.mixin('api');
this.wait = false
this.uploadings = []
this.files = []
this.poll = false
this.wait = false;
this.uploadings = [];
this.files = [];
this.poll = false;
this.on('mount', () => {
this.refs.uploader.on('uploaded', (file) => {
this.addFile file
this.refs.uploader.on('uploaded', file => {
this.addFile(file);
});
this.refs.uploader.on('change-uploads', (uploads) => {
this.trigger 'change-uploading-files' uploads
this.refs.uploader.on('change-uploads', uploads => {
this.trigger('change-uploading-files', uploads);
});
this.refs.text.focus();
});
this.onkeypress = (e) => {
if (e.char-code == 10 || e.char-code == 13) && e.ctrlKey
this.post!
else
return true
this.onkeydown = e => {
if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.meta-key)) this.post();
};
this.onpaste = (e) => {
data = e.clipboardData
items = data.items
for i from 0 to items.length - 1
item = items[i]
switch (item.kind)
| 'file' =>
@upload item.getAsFile();
return true
this.onpaste = e => {
e.clipboardData.items.forEach(item => {
if (item.kind == 'file') {
this.upload(item.getAsFile());
}
});
};
this.select-file = () => {
this.selectFile = () => {
this.refs.file.click();
};
this.select-file-from-drive = () => {
browser = document.body.appendChild(document.createElement('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.forEach this.addFile
})[0];
i.one('selected', files => {
files.forEach(this.addFile);
});
};
this.change-file = () => {
files = this.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);
};
this.upload = (file) => {
this.refs.uploader.upload file
this.upload = file => {
this.refs.uploader.upload(file);
};
this.add-file = (file) => {
file._remove = =>
this.files = this.files.filter (x) -> x.id != file.id
this.trigger 'change-files' this.files
this.addFile = file => {
file._remove = () => {
this.files = this.files.filter(x => x.id != file.id);
this.trigger('change-files', this.files);
this.update();
};
this.files.push file
this.trigger 'change-files' this.files
this.files.push(file);
this.trigger('change-files', this.files);
this.update();
};
this.add-poll = () => {
this.poll = true
this.addPoll = () => {
this.poll = true;
};
this.on-poll-destroyed = () => {
@update do
this.onPollDestroyed = () => {
this.update({
poll: false
});
};
this.post = () => {
this.wait = true
this.wait = true;
files = if this.files? and this.files.length > 0
then this.files.map (f) -> f.id
else undefined
const files = this.files && this.files.length > 0
? this.files.map(f => f.id)
: undefined;
this.api('posts/create', {
text: this.refs.text.value
media_ids: files
reply_to_id: if this.opts.reply? then this.opts.reply.id else undefined
poll: if this.poll then this.refs.poll.get! else undefined
}).then((data) => {
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) =>
console.error err
#this.opts.ui.trigger 'notification' 'Error!'
this.wait = false
this.update();
}).catch(err => {
this.update({
wait: false
});
});
};
this.cancel = () => {
this.trigger('cancel');
this.unmount();
};
this.cat = () => {
this.refs.text.value = this.refs.text.value + get-cat!
this.refs.text.value += getCat();
};
</script>
</mk-post-form>

View file

@ -15,18 +15,22 @@
this.query = this.opts.query;
this.withMedia = this.opts.withMedia;
this.init = new Promise (res, rej) =>
this.init = new Promise((res, rej) => {
this.api('posts/search', {
query: this.query
}).then(posts => {
res posts
res(posts);
this.trigger('loaded');
});
});
this.more = () => {
this.offset += this.max;
this.api('posts/search', {
query: this.query
max: this.max
query: this.query,
max: this.max,
offset: this.offset
});
};
</script>
</mk-search-posts>

View file

@ -3,13 +3,14 @@
<style>
:scope
display block
</style>
<script>
this.query = this.opts.query
this.query = this.opts.query;
this.on('mount', () => {
this.refs.posts.on('loaded', () => {
this.trigger('loaded');
});
});
</script>
</mk-search>

View file

@ -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>
this.mixin('stream');
this.on('before-mount', () => {
this.state = this.getStreamState();
if this.state == 'connected'
this.root.style.opacity = 0
this.stream-state-ev.on('connected', () => {
this.state = this.getStreamState();
this.update();
setTimeout =>
Velocity(this.root, {
opacity: 0
} 200ms 'linear'
, 1000ms
this.stream-state-ev.on('closed', () => {
this.state = this.getStreamState();
this.update();
Velocity(this.root, {
opacity: 1
} 0ms
</script>
</mk-stream-indicator>

View file

@ -30,15 +30,17 @@
<script>
this.mixin('text');
this.post = this.opts.post
this.post = this.opts.post;
this.on('mount', () => {
if this.post.text?
tokens = @analyze this.post.text
this.refs.text.innerHTML = @compile tokens, false
if (this.post.text) {
const tokens = this.analyze(this.post.text);
this.refs.text.innerHTML = this.compile(tokens, false);
this.refs.text.children.forEach (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>

View file

@ -344,7 +344,7 @@
};
this.like = () => {
if (this.p.is_liked)
if (this.p.is_liked) {
this.api('posts/likes/delete', {
post_id: this.p.id
}).then(() => {

View file

@ -13,7 +13,7 @@
$height = 48px
display block
position fixed
position sticky
top 0
z-index 1024
width 100%
@ -91,10 +91,6 @@
this.mixin('ui');
this.mixin('open-post-form');
this.on('mount', () => {
this.opts.ready();
});
this.ui.on('title', title => {
if (this.refs.title) this.refs.title.innerHTML = title;
});

View file

@ -120,12 +120,10 @@
this.mixin('i');
this.mixin('page');
this.on('mount', () => {
this.opts.ready!
this.search = () => {
query = window.prompt '検索'
if query? and query != ''
this.page '/search:' + query
const query = window.prompt('検索');
if (query == null || query == '') return;
this.page('/search:' + query);
};
</script>
</mk-ui-nav>

View file

@ -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>
@ -16,36 +16,25 @@
<script>
this.mixin('stream');
this.ready-count = 0
this.is-drawer-opening = false
#this.ui.on('notification', (text) => {
// alert text
this.isDrawerOpening = false;
this.on('mount', () => {
this.stream.on 'notification' this.on-stream-notification
@ready!
this.stream.on('notification', this.onStreamNotification);
});
this.on('unmount', () => {
this.stream.off 'notification' this.on-stream-notification
this.stream.off('notification', this.onStreamNotification);
});
this.ready = () => {
@ready-count++
this.toggleDrawer = () => {
this.isDrawerOpening = !this.isDrawerOpening;
this.refs.nav.root.style.display = this.isDrawerOpening ? 'block' : 'none';
};
if @ready-count == 2
@init-view-position!
this.init-view-position = () => {
top = this.refs.header.root.offset-height
this.refs.main.style.padding-top = top + 'px'
this.toggle-drawer = () => {
this.is-drawer-opening = !@is-drawer-opening
this.refs.nav.root.style.display = if @is-drawer-opening then 'block' else 'none'
this.on-stream-notification = (notification) => {
el = document.body.appendChild(document.createElement('mk-notify'));
riot.mount el, do
this.onStreamNotification = notification => {
riot.mount(document.body.appendChild(document.createElement('mk-notify')), {
notification: notification
});
};
</script>
</mk-ui>

View file

@ -8,18 +8,21 @@
<script>
this.mixin('api');
this.user = this.opts.user
this.user = this.opts.user;
this.fetch = (iknow, limit, cursor, cb) => {
this.api('users/followers', {
user_id: this.user.id
iknow: iknow
limit: limit
cursor: if cursor? then cursor else undefined
.then cb
user_id: this.user.id,
iknow: iknow,
limit: limit,
cursor: cursor ? cursor : undefined
}).then(cb);
};
this.on('mount', () => {
this.refs.list.on('loaded', () => {
this.trigger('loaded');
});
};
</script>
</mk-user-followers>

View file

@ -8,18 +8,21 @@
<script>
this.mixin('api');
this.user = this.opts.user
this.user = this.opts.user;
this.fetch = (iknow, limit, cursor, cb) => {
this.api('users/following', {
user_id: this.user.id
iknow: iknow
limit: limit
cursor: if cursor? then cursor else undefined
.then cb
user_id: this.user.id,
iknow: iknow,
limit: limit,
cursor: cursor ? cursor : undefined
}).then(cb);
};
this.on('mount', () => {
this.refs.list.on('loaded', () => {
this.trigger('loaded');
});
});
</script>
</mk-user-following>

View file

@ -14,18 +14,22 @@
this.user = this.opts.user;
this.withMedia = this.opts.withMedia;
this.init = new Promise (res, rej) =>
this.init = new Promise((res, rej) => {
this.api('users/posts', {
user_id: this.user.id
with_media: @withMedia
user_id: this.user.id,
with_media: this.withMedia
}).then(posts => {
res posts
res(posts);
this.trigger('loaded');
});
});
this.more = () => {
this.api('users/posts', {
user_id: this.user.id
with_media: this.withMedia
max_id: this.refs.timeline.tail!.id
user_id: this.user.id,
with_media: this.withMedia,
max_id: this.refs.timeline.tail().id
});
};
</script>
</mk-user-timeline>

View file

@ -72,45 +72,48 @@
<script>
this.mixin('i');
this.limit = 30users
this.mode = 'all'
this.limit = 30;
this.mode = 'all';
this.fetching = true
this.more-fetching = false
this.fetching = true;
this.moreFetching = false;
this.on('mount', () => {
@fetch =>
this.trigger('loaded');
this.fetch(() => this.trigger('loaded'));
});
this.fetch = (cb) => {
this.fetching = true
this.update();
obj <~ this.opts.fetch do
this.mode == 'iknow'
@limit
null
this.users = obj.users
this.next = obj.next
this.fetching = false
this.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();
});
};
this.more = () => {
this.more-fetching = true
this.update();
obj <~ this.opts.fetch do
this.mode == 'iknow'
@limit
@cursor
this.users = this.users.concat obj.users
this.next = obj.next
this.more-fetching = false
this.update();
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
});
});
};
this.set-mode = (mode) => {
@update do
this.setMode = mode => {
this.update({
mode: mode
@fetch!
});
this.fetch();
};
</script>
</mk-users-list>