This commit is contained in:
syuilo 2017-02-22 01:05:23 +09:00
parent 65d03dc9da
commit 2a1fab34df
37 changed files with 680 additions and 659 deletions

View File

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

View File

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

View File

@ -1,8 +1,7 @@
<mk-core-error> <mk-core-error>
<!--i: i.fa.fa-times-circle--><img src="/_/resources/error.jpg" alt=""/> <!--i: i.fa.fa-times-circle-->
<h1> <img src="/_/resources/error.jpg" alt=""/>
<mk-ripple-string>サーバーに接続できません</mk-ripple-string> <h1>サーバーに接続できません</h1>
</h1>
<p class="text">インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから<a onclick={ retry }>再度お試し</a>ください。</p> <p class="text">インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから<a onclick={ retry }>再度お試し</a>ください。</p>
<p class="thanks">いつもMisskeyをご利用いただきありがとうございます。</p> <p class="thanks">いつもMisskeyをご利用いただきありがとうございます。</p>
<style> <style>

View File

@ -1,7 +1,6 @@
require('./core-error.tag'); require('./core-error.tag');
require('./url.tag'); require('./url.tag');
require('./url-preview.tag'); require('./url-preview.tag');
require('./ripple-string.tag');
require('./time.tag'); require('./time.tag');
require('./file-type-icon.tag'); require('./file-type-icon.tag');
require('./uploader.tag'); require('./uploader.tag');
@ -24,3 +23,4 @@ require('./messaging/room.tag');
require('./messaging/message.tag'); require('./messaging/message.tag');
require('./messaging/index.tag'); require('./messaging/index.tag');
require('./messaging/form.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> <mk-stream-indicator>
<p if={ state == 'initializing' }><i class="fa fa-spinner fa-spin"></i><span>接続中 <p if={ state == 'initializing' }>
<mk-ellipsis></mk-ellipsis></span></p> <i class="fa fa-spinner fa-spin"></i>
<p if={ state == 'reconnecting' }><i class="fa fa-spinner fa-spin"></i><span>切断されました 接続中 <span>接続中<mk-ellipsis></mk-ellipsis></span>
<mk-ellipsis></mk-ellipsis></span></p> </p>
<p if={ state == 'connected' }><i class="fa fa-check"></i><span>接続完了</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> <style>
:scope :scope
display block display block

View File

@ -41,7 +41,6 @@ require('./home-widgets/notifications.tag');
require('./home-widgets/rss-reader.tag'); require('./home-widgets/rss-reader.tag');
require('./home-widgets/photo-stream.tag'); require('./home-widgets/photo-stream.tag');
require('./home-widgets/broadcast.tag'); require('./home-widgets/broadcast.tag');
require('./stream-indicator.tag');
require('./timeline.tag'); require('./timeline.tag');
require('./messaging/window.tag'); require('./messaging/window.tag');
require('./messaging/room-window.tag'); require('./messaging/room-window.tag');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
<p onclick={ goRoot }><i class="fa fa-cloud"></i>ドライブ</p> <p onclick={ goRoot }><i class="fa fa-cloud"></i>ドライブ</p>
<virtual each={ folder in hierarchyFolders }> <virtual each={ folder in hierarchyFolders }>
<span><i class="fa fa-angle-right"></i></span> <span><i class="fa fa-angle-right"></i></span>
<p onclick={ _move }>{ folder.name }</p> <p onclick={ move }>{ folder.name }</p>
</virtual> </virtual>
<virtual if={ folder != null }> <virtual if={ folder != null }>
<span><i class="fa fa-angle-right"></i></span> <span><i class="fa fa-angle-right"></i></span>
@ -14,7 +14,7 @@
<p>{ file.name }</p> <p>{ file.name }</p>
</virtual> </virtual>
</nav> </nav>
<div class="browser { loading: loading }" if={ file == null }> <div class="browser { loading: fetching }" if={ file == null }>
<div class="folders" if={ folders.length > 0 }> <div class="folders" if={ folders.length > 0 }>
<virtual each={ folder in folders }> <virtual each={ folder in folders }>
<mk-drive-folder folder={ folder }></mk-drive-folder> <mk-drive-folder folder={ folder }></mk-drive-folder>
@ -27,11 +27,11 @@
</virtual> </virtual>
<p if={ moreFiles }>もっと読み込む</p> <p if={ moreFiles }>もっと読み込む</p>
</div> </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>
<p if={ folder != null }>このフォルダーは空です</p> <p if={ folder != null }>このフォルダーは空です</p>
</div> </div>
<div class="loading" if={ loading }> <div class="loading" if={ fetching }>
<div class="spinner"> <div class="spinner">
<div class="dot1"></div> <div class="dot1"></div>
<div class="dot2"></div> <div class="dot2"></div>
@ -131,247 +131,263 @@
this.mixin('api'); this.mixin('api');
this.mixin('stream'); this.mixin('stream');
this.files = [] this.files = [];
this.folders = [] this.folders = [];
this.hierarchyFolders = [] this.hierarchyFolders = [];
this.selected-files = [] this.selectedFiles = [];
// 現在の階層(フォルダ) // 現在の階層(フォルダ)
// * null でルートを表す // * 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.isSelectMode = this.opts.select;
this.multiple = if this.opts.multiple? then this.opts.multiple else false this.multiple =this.opts.multiple;
this.on('mount', () => { this.on('mount', () => {
this.stream.on 'drive_file_created' this.onStreamDriveFileCreated this.stream.on('drive_file_created', this.onStreamDriveFileCreated);
this.stream.on 'drive_file_updated' this.onStreamDriveFileUpdated this.stream.on('drive_file_updated', this.onStreamDriveFileUpdated);
this.stream.on 'drive_folder_created' this.onStreamDriveFolderCreated this.stream.on('drive_folder_created', this.onStreamDriveFolderCreated);
this.stream.on 'drive_folder_updated' this.onStreamDriveFolderUpdated this.stream.on('drive_folder_updated', this.onStreamDriveFolderUpdated);
// Riotのバグでnullを渡しても""になる // Riotのバグでnullを渡しても""になる
// https://github.com/riot/riot/issues/2080 // https://github.com/riot/riot/issues/2080
#if this.opts.folder? //if (this.opts.folder)
if this.opts.folder? and this.opts.folder != '' //if (this.opts.file)
@cd this.opts.folder, true if (this.opts.folder && this.opts.folder != '') {
else if this.opts.file? and this.opts.file != '' this.cd(this.opts.folder, true);
@cf this.opts.file, true } else if (this.opts.file && this.opts.file != '') {
else this.cf(this.opts.file, true);
} else {
this.load(); this.load();
}
});
this.on('unmount', () => { this.on('unmount', () => {
this.stream.off 'drive_file_created' this.onStreamDriveFileCreated this.stream.off('drive_file_created', this.onStreamDriveFileCreated);
this.stream.off 'drive_file_updated' this.onStreamDriveFileUpdated this.stream.off('drive_file_updated', this.onStreamDriveFileUpdated);
this.stream.off 'drive_folder_created' this.onStreamDriveFolderCreated this.stream.off('drive_folder_created', this.onStreamDriveFolderCreated);
this.stream.off 'drive_folder_updated' this.onStreamDriveFolderUpdated this.stream.off('drive_folder_updated', this.onStreamDriveFolderUpdated);
});
this.onStreamDriveFileCreated = (file) => { this.onStreamDriveFileCreated = file => {
this.addFile file, true this.addFile(file, true);
};
this.onStreamDriveFileUpdated = (file) => { this.onStreamDriveFileUpdated = file => {
current = if this.folder? then this.folder.id else null const current = this.folder ? this.folder.id : null;
if current != file.folder_id if (current != file.folder_id) {
@remove-file file this.removeFile(file);
else } else {
this.addFile file, true this.addFile(file, true);
}
};
this.onStreamDriveFolderCreated = (folder) => { this.onStreamDriveFolderCreated = folder => {
this.addFolder folder, true this.addFolder(folder, true);
};
this.onStreamDriveFolderUpdated = (folder) => { this.onStreamDriveFolderUpdated = folder => {
current = if this.folder? then this.folder.id else null const current = this.folder ? this.folder.id : null;
if current != folder.parent_id if (current != folder.parent_id) {
this.removeFolder folder this.removeFolder(folder);
else } else {
this.addFolder folder, true this.addFolder(folder, true);
}
};
@_move = (ev) => this.move = ev => {
this.move ev.item.folder this.move(ev.item.folder);
};
this.move = (target-folder) => { this.cd = (target, silent = false) => {
@cd target-folder this.file = null;
this.cd = (target-folder, silent = false) => { if (target == null) {
this.file = null this.goRoot();
return;
} else if (typeof target == 'object') target = target.id;
if target-folder? and typeof target-folder == 'object' this.update({
target-folder = target-folder.id fetching: true
});
if target-folder == null
@go-root!
return
this.loading = true
this.update();
this.api('drive/folders/show', { this.api('drive/folders/show', {
folder_id: target-folder folder_id: target
}).then((folder) => { }).then(folder => {
this.folder = folder this.folder = folder;
this.hierarchyFolders = [] this.hierarchyFolders = [];
x = (f) => if (folder.parent) dive(folder.parent);
@hierarchyFolders.unshift f
if f.parent?
x f.parent
if folder.parent?
x folder.parent
this.update(); this.update();
this.trigger 'open-folder' this.folder, silent this.trigger('open-folder', this.folder, silent);
this.load(); this.load();
.catch (err, text-status) -> });
console.error err };
this.add-folder = (folder, unshift = false) => { this.addFolder = (folder, unshift = false) => {
current = if this.folder? then this.folder.id else null const current = this.folder ? this.folder.id : null;
if current != folder.parent_id // 追加しようとしているフォルダが、今居る階層とは違う階層のものだったら中断
return 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 if (unshift) {
this.folders.unshift folder this.folders.unshift(folder);
else } else {
this.folders.push folder this.folders.push(folder);
}
this.update(); this.update();
};
this.add-file = (file, unshift = false) => { this.addFile = (file, unshift = false) => {
current = if this.folder? then this.folder.id else null const current = this.folder ? this.folder.id : null;
if current != file.folder_id // 追加しようとしているファイルが、今居る階層とは違う階層のものだったら中断
return if (current != file.folder_id) return;
if (this.files.some (f) => f.id == file.id) if (this.files.some(f => f.id == file.id)) {
exist = (this.files.map (f) -> f.id).index-of file.id const exist = this.files.map(f => f.id).indexOf(file.id);
this.files[exist] = file this.files[exist] = file;
this.update(); this.update();
return return;
}
if unshift if (unshift) {
this.files.unshift file this.files.unshift(file);
else } else {
this.files.push file this.files.push(file);
}
this.update(); this.update();
};
this.remove-folder = (folder) => { this.removeFolder = folder => {
if typeof folder == 'object' if (typeof folder == 'object') folder = folder.id;
folder = folder.id this.folders = this.folders.filter(f => f.id != folder);
this.folders = this.folders.filter (f) -> f.id != folder
this.update(); this.update();
};
this.remove-file = (file) => { this.removeFile = file => {
if typeof file == 'object' if (typeof file == 'object') file = file.id;
file = file.id this.files = this.files.filter(f => f.id != file);
this.files = this.files.filter (f) -> f.id != file
this.update(); this.update();
};
this.go-root = () => { this.goRoot = () => {
if this.folder != null or this.file != null if (this.folder || this.file) {
this.file = null this.update({
this.folder = null file: null,
this.hierarchyFolders = [] folder: null,
this.update(); hierarchyFolders: []
});
this.trigger('move-root'); this.trigger('move-root');
this.load(); this.load();
}
};
this.load = () => { this.load = () => {
this.folders = [] this.update({
this.files = [] folders: [],
this.more-folders = false files: [],
this.more-files = false moreFolders: false,
this.loading = true moreFiles: false,
this.update(); fetching: true
});
this.trigger('begin-load'); this.trigger('begin-load');
load-folders = null let fetchedFolders = null;
load-files = null let fetchedFiles = null;
folders-max = 20 const foldersMax = 20;
files-max = 20 const filesMax = 20;
// フォルダ一覧取得 // フォルダ一覧取得
this.api('drive/folders', { this.api('drive/folders', {
folder_id: if this.folder? then this.folder.id else null folder_id: this.folder ? this.folder.id : null,
limit: folders-max + 1 limit: foldersMax + 1
}).then((folders) => { }).then(folders => {
if folders.length == folders-max + 1 if (folders.length == foldersMax + 1) {
this.more-folders = true this.moreFolders = true;
folders.pop! folders.pop();
load-folders := folders }
complete! fetchedFolders = folders;
.catch (err, text-status) => complete();
console.error err });
// ファイル一覧取得 // ファイル一覧取得
this.api('drive/files', { this.api('drive/files', {
folder_id: if this.folder? then this.folder.id else null folder_id: this.folder ? this.folder.id : null,
limit: files-max + 1 limit: filesMax + 1
}).then((files) => { }).then(files => {
if files.length == files-max + 1 if (files.length == filesMax + 1) {
this.more-files = true this.moreFiles = true;
files.pop! files.pop();
load-files := files }
complete! fetchedFiles = files;
.catch (err, text-status) => complete();
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();
let flag = false;
complete = () => {
if (flag) {
fetchedFolders.forEach(folder => this.addFolder);
fetchedFiles.forEach(file => this.addFile);
this.update({
fetching: false
});
// 一連の読み込みが完了したイベントを発行
this.trigger('loaded'); this.trigger('loaded');
else } else {
flag := true flag = true;
// 一連の読み込みが半分完了したイベントを発行
this.trigger('load-mid'); this.trigger('load-mid');
}
};
};
this.choose-file = (file) => { this.chooseFile = file => {
if @is-select-mode if (this.isSelectMode) {
exist = @selected-files.some (f) => f.id == file.id if (this.selectedFiles.some(f => f.id == file.id)) {
if exist this.selectedFiles = this.selectedFiles.filter(f => f.id != file.id);
this.selected-files = (@selected-files.filter (f) => { f.id != file.id) } else {
else this.selectedFiles.push(file);
@selected-files.push file }
this.update(); this.update();
this.trigger 'change-selected' @selected-files this.trigger('change-selected', this.selectedFiles);
else } else {
@cf file this.cf(file);
}
};
this.cf = (file, silent = false) => { this.cf = (file, silent = false) => {
if typeof file == 'object' if (typeof file == 'object') file = file.id;
file = file.id
this.loading = true this.update({
this.update(); fetching: true
});
this.api('drive/files/show', { this.api('drive/files/show', {
file_id: file file_id: file
}).then((file) => { }).then(file => {
this.file = file this.file = file;
this.folder = null this.folder = null;
this.hierarchyFolders = [] this.hierarchyFolders = [];
x = (f) => if (file.folder) dive(file.folder);
@hierarchyFolders.unshift f
if f.parent?
x f.parent
if file.folder?
x file.folder
this.update(); 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> </script>
</mk-drive> </mk-drive>

View File

@ -185,17 +185,18 @@
this.mixin('api'); this.mixin('api');
this.file = this.opts.file this.file = this.opts.file;
this.kind = this.file.type.split '/' .0 this.kind = this.file.type.split('/')[0];
this.rename = () => { this.rename = () => {
name = window.prompt '名前を変更' this.file.name const name = window.prompt('名前を変更', this.file.name);
if name? and name != '' and name != this.file.name if (name == null || name == '' || name == this.file.name) return;
this.api('drive/files/update', { this.api('drive/files/update', {
file_id: this.file.id, file_id: this.file.id,
name: name name: name
}).then(() => { }).then(() => {
this.parent.cf this.file, true this.parent.cf(this.file, true);
});
};
</script> </script>
</mk-drive-file-viewer> </mk-drive-file-viewer>

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
require('./ui.tag'); require('./ui.tag');
require('./ui-header.tag'); require('./ui-header.tag');
require('./ui-nav.tag'); require('./ui-nav.tag');
require('./stream-indicator.tag');
require('./page/entrance.tag'); require('./page/entrance.tag');
require('./page/entrance/signin.tag'); require('./page/entrance/signin.tag');
require('./page/entrance/signup.tag'); require('./page/entrance/signup.tag');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,13 +3,14 @@
<style> <style>
:scope :scope
display block display block
</style> </style>
<script> <script>
this.query = this.opts.query this.query = this.opts.query;
this.on('mount', () => { this.on('mount', () => {
this.refs.posts.on('loaded', () => { this.refs.posts.on('loaded', () => {
this.trigger('loaded'); this.trigger('loaded');
});
});
</script> </script>
</mk-search> </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> <script>
this.mixin('text'); this.mixin('text');
this.post = this.opts.post this.post = this.opts.post;
this.on('mount', () => { this.on('mount', () => {
if this.post.text? if (this.post.text) {
tokens = @analyze this.post.text const tokens = this.analyze(this.post.text);
this.refs.text.innerHTML = @compile tokens, false this.refs.text.innerHTML = this.compile(tokens, false);
this.refs.text.children.forEach (e) => this.refs.text.children.forEach(e => {
if e.tag-name == 'MK-URL' if (e.tagName == 'MK-URL') riot.mount(e);
riot.mount e });
}
});
</script> </script>
</mk-sub-post-content> </mk-sub-post-content>

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<mk-ui> <mk-ui>
<div class="global" ref="global"> <div class="global" ref="global">
<mk-ui-header ref="header" ready={ ready }></mk-ui-header> <mk-ui-header ref="header"></mk-ui-header>
<mk-ui-nav ref="nav" ready={ ready }></mk-ui-nav> <mk-ui-nav ref="nav"></mk-ui-nav>
<div class="content" ref="main"><yield /></div> <div class="content" ref="main"><yield /></div>
</div> </div>
<mk-stream-indicator></mk-stream-indicator> <mk-stream-indicator></mk-stream-indicator>
@ -16,36 +16,25 @@
<script> <script>
this.mixin('stream'); this.mixin('stream');
this.ready-count = 0 this.isDrawerOpening = false;
this.is-drawer-opening = false
#this.ui.on('notification', (text) => {
// alert text
this.on('mount', () => { this.on('mount', () => {
this.stream.on 'notification' this.on-stream-notification this.stream.on('notification', this.onStreamNotification);
@ready! });
this.on('unmount', () => { this.on('unmount', () => {
this.stream.off 'notification' this.on-stream-notification this.stream.off('notification', this.onStreamNotification);
});
this.ready = () => { this.toggleDrawer = () => {
@ready-count++ this.isDrawerOpening = !this.isDrawerOpening;
this.refs.nav.root.style.display = this.isDrawerOpening ? 'block' : 'none';
};
if @ready-count == 2 this.onStreamNotification = notification => {
@init-view-position! riot.mount(document.body.appendChild(document.createElement('mk-notify')), {
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
notification: notification notification: notification
});
};
</script> </script>
</mk-ui> </mk-ui>

View File

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

View File

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

View File

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

View File

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