This commit is contained in:
syuilo 2017-02-20 20:13:42 +09:00
parent 3a39a36bed
commit 2a3a5d4b50
35 changed files with 402 additions and 367 deletions

View File

@ -114,13 +114,13 @@
this.cancel = () => { this.cancel = () => {
this.api('auth/deny', { this.api('auth/deny', {
token: @session.token token: @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: @session.token
.then => }).then(() => {
this.trigger('accepted'); this.trigger('accepted');
</script> </script>
</mk-form> </mk-form>

View File

@ -110,7 +110,7 @@
if @session.app.is_authorized if @session.app.is_authorized
this.api('auth/accept', { this.api('auth/accept', {
token: @session.token token: @session.token
.then => }).then(() => {
@accepted! @accepted!
else else
this.state = 'waiting' this.state = 'waiting'

View File

@ -0,0 +1,8 @@
module.exports = function(parent, child) {
let node = child.parentNode;
while (node) {
if (node == parent) return true;
node = node.parentNode;
}
return false;
}

View File

@ -126,7 +126,7 @@
this.api('signin', { this.api('signin', {
username: this.refs.username.value username: this.refs.username.value
password: this.refs.password.value password: this.refs.password.value
.then => }).then(() => {
location.reload(); location.reload();
.catch => .catch =>
alert 'something happened' alert 'something happened'

View File

@ -277,11 +277,11 @@
username: username, username: username,
password: password, password: password,
'g-recaptcha-response': grecaptcha.getResponse() 'g-recaptcha-response': grecaptcha.getResponse()
.then => }).then(() => {
this.api('signin', { this.api('signin', {
username: username username: username
password: password password: password
.then => }).then(() => {
location.href = CONFIG.url location.href = CONFIG.url
.catch => .catch =>
alert '何らかの原因によりアカウントの作成に失敗しました。再度お試しください。' alert '何らかの原因によりアカウントの作成に失敗しました。再度お試しください。'

View File

@ -6,100 +6,92 @@
display block display block
width 256px width 256px
height 256px height 256px
</style> </style>
<script> <script>
class Vec2 {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
this.on('mount', () => { this.on('mount', () => {
@draw! this.draw()
this.clock = setInterval @draw, 1000ms this.clock = setInterval(this.draw, 1000);
});
this.on('unmount', () => { this.on('unmount', () => {
clearInterval @clock clearInterval(this.clock);
});
this.draw = () => { this.draw = () => {
const now = new Date(); const now = new Date();
s = now.get-seconds! const s = now.getSeconds();
m = now.getMinutes() const m = now.getMinutes();
h = now.getHours() const h = now.getHours();
vec2 = (x, y) -> const ctx = this.refs.canvas.getContext('2d');
this.x = x const canvW = this.refs.canvas.width;
this.y = y const canvH = this.refs.canvas.height;
ctx.clearRect(0, 0, canvW, canvH);
ctx = this.refs.canvas.get-context '2d' { // 背景
canv-w = this.refs.canvas.width const center = Math.min((canvW / 2), (canvH / 2));
canv-h = this.refs.canvas.height const lineStart = center * 0.90;
ctx.clear-rect 0, 0, canv-w, canv-h const shortLineEnd = center * 0.87;
const longLineEnd = center * 0.84;
for (let i = 0; i < 60; i++) {
const angle = Math.PI * i / 30;
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo((canv-w / 2) + uv.x * lineStart, (canv-h / 2) + uv.y * lineStart);
if (i % 5 == 0) {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
ctx.lineTo((canv-w / 2) + uv.x * longLineEnd, (canv-h / 2) + uv.y * longLineEnd);
} else {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineTo((canv-w / 2) + uv.x * shortLineEnd, (canv-h / 2) + uv.y * shortLineEnd);
}
ctx.stroke();
}
}
// 背景 { // 分
center = (Math.min (canv-w / 2), (canv-h / 2)) const angle = Math.PI * (m + s / 60) / 30;
line-start = center * 0.90 const length = Math.min(canvW, canvH) / 2.6;
line-end-short = center * 0.87 const uv = new vec2(Math.sin(angle), -Math.cos(angle));
line-end-long = center * 0.84 ctx.beginPath();
for i from 0 to 59 by 1 ctx.strokeStyle = '#ffffff';
angle = Math.PI * i / 30 ctx.lineWidth = 2;
uv = new vec2 (Math.sin angle), (-Math.cos angle) ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
ctx.begin-path! ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
ctx.line-width = 1 ctx.stroke();
ctx.move-to do }
(canv-w / 2) + uv.x * line-start
(canv-h / 2) + uv.y * line-start
if i % 5 == 0
ctx.stroke-style = 'rgba(255, 255, 255, 0.2)'
ctx.line-to do
(canv-w / 2) + uv.x * line-end-long
(canv-h / 2) + uv.y * line-end-long
else
ctx.stroke-style = 'rgba(255, 255, 255, 0.1)'
ctx.line-to do
(canv-w / 2) + uv.x * line-end-short
(canv-h / 2) + uv.y * line-end-short
ctx.stroke!
// 分 { // 時
angle = Math.PI * (m + s / 60) / 30 const angle = Math.PI * (h % 12 + m / 60) / 6;
length = (Math.min canv-w, canv-h) / 2.6 const length = Math.min(canvW, canvH) / 4;
uv = new vec2 (Math.sin angle), (-Math.cos angle) const uv = new vec2(Math.sin(angle), -Math.cos(angle));
ctx.begin-path! ctx.beginPath();
ctx.stroke-style = '#ffffff' ctx.strokeStyle = CONFIG.themeColor;
ctx.line-width = 2 ctx.lineWidth = 2;
ctx.move-to do ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
(canv-w / 2) - uv.x * length / 5 ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
(canv-h / 2) - uv.y * length / 5 ctx.stroke();
ctx.line-to do }
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
// 時 { // 秒
angle = Math.PI * (h % 12 + m / 60) / 6 const angle = Math.PI * s / 30;
length = (Math.min canv-w, canv-h) / 4 const length = Math.min(canvW, canvH) / 2.6;
uv = new vec2 (Math.sin angle), (-Math.cos angle) const uv = new vec2(Math.sin(angle), -Math.cos(angle));
ctx.begin-path! ctx.beginPath();
#ctx.stroke-style = '#ffffff' ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.stroke-style = CONFIG.theme-color ctx.lineWidth = 1;
ctx.line-width = 2 ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
ctx.move-to do ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
(canv-w / 2) - uv.x * length / 5 ctx.stroke();
(canv-h / 2) - uv.y * length / 5 }
ctx.line-to do };
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
// 秒
angle = Math.PI * s / 30
length = (Math.min canv-w, canv-h) / 2.6
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
ctx.stroke-style = 'rgba(255, 255, 255, 0.5)'
ctx.line-width = 1
ctx.move-to do
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
</script> </script>
</mk-analog-clock> </mk-analog-clock>

View File

@ -80,108 +80,118 @@
</style> </style>
<script> <script>
const contains = require('../../common/scripts/contains');
this.mixin('api'); this.mixin('api');
this.q = this.opts.q this.q = this.opts.q;
this.textarea = this.opts.textarea this.textarea = this.opts.textarea;
this.loading = true this.fetching = true;
this.users = [] this.users = [];
this.select = -1 this.select = -1;
this.on('mount', () => { this.on('mount', () => {
@textarea.addEventListener 'keydown' this.on-keydown this.textarea.addEventListener('keydown', this.onKeydown);
all = document.query-selector-all 'body *' document.querySelectorAll('body *').forEach(el => {
Array.prototype.forEach.call all, (el) => el.addEventListener('mousedown', this.mousedown);
el.addEventListener 'mousedown' @mousedown });
this.api('users/search_by_username', { this.api('users/search_by_username', {
query: @q query: this.q,
limit: 30users limit: 30
}).then((users) => { }).then(users => {
this.users = users this.update({
this.loading = false fetching: false,
this.update(); users: users
.catch (err) => });
console.error err });
});
this.on('unmount', () => { this.on('unmount', () => {
@textarea.removeEventListener 'keydown' this.on-keydown this.textarea.removeEventListener('keydown', this.onKeydown);
all = document.query-selector-all 'body *' document.querySelectorAll('body *').forEach(el => {
Array.prototype.forEach.call all, (el) => el.removeEventListener('mousedown', this.mousedown);
el.removeEventListener 'mousedown' @mousedown });
});
this.mousedown = (e) => { this.mousedown = e => {
if (!contains this.root, e.target) and (this.root != e.target) if (!contains(this.root, e.target) && (this.root != e.target)) this.close();
@close(); };
this.on-click = (e) => { this.onClick = e => {
@complete e.item this.complete(e.item);
};
this.on-keydown = (e) => { this.onKeydown = e => {
key = e.which const cancel = () => {
switch (key)
| 10, 13 => // Key[ENTER]
if @select != -1
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@complete this.users[@select] };
else
@close();
| 27 => // Key[ESC]
e.preventDefault();
e.stopPropagation();
@close();
| 38 => // Key[↑]
if @select != -1
e.preventDefault();
e.stopPropagation();
@select-prev!
else
@close();
| 9, 40 => // Key[TAB] or Key[↓]
e.preventDefault();
e.stopPropagation();
@select-next!
| _ =>
@close();
this.select-next = () => { switch (e.which) {
@select++ case 10: // [ENTER]
case 13: // [ENTER]
if (this.select !== -1) {
cancel();
this.complete(this.users[this.select]);
} else {
this.close();
}
break;
if @select >= this.users.length case 27: // [ESC]
this.select = 0 cancel();
this.close();
break;
@apply-select! case 38: // [↑]
if (this.select !== -1) {
cancel();
this.selectPrev();
} else {
this.close();
}
break;
this.select-prev = () => { case 9: // [TAB]
@select-- case 40: // [↓]
cancel();
this.selectNext();
break;
if @select < 0 default:
this.select = this.users.length - 1 this.close();
}
};
@apply-select! this.selectNext = () => {
if (++this.select >= this.users.length) this.select = 0;
this.applySelect();
};
this.apply-select = () => { this.selectPrev = () => {
this.refs.users.children.forEach (el) => if (--this.select < 0) this.select = this.users.length - 1;
el.remove-attribute 'data-selected' this.applySelect();
};
this.refs.users.children[@select].setAttribute 'data-selected' \true this.applySelect = () => {
this.refs.users.children[@select].focus(); this.refs.users.children.forEach(el => {
el.removeAttribute('data-selected');
});
this.complete = (user) => { this.refs.users.children[this.select].setAttribute('data-selected', 'true');
this.opts.complete user this.refs.users.children[this.select].focus();
};
this.complete = user => {
this.opts.complete(user);
};
this.close = () => { this.close = () => {
this.opts.close(); this.opts.close();
};
function contains(parent, child)
node = child.parentNode
while node?
if node == parent
return true
node = node.parentNode
return false
</script> </script>
</mk-autocomplete-suggestion> </mk-autocomplete-suggestion>

View File

@ -106,21 +106,21 @@
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>

View File

@ -1,4 +1,5 @@
<mk-contextmenu><yield /> <mk-contextmenu>
<yield />
<style> <style>
:scope :scope
$width = 240px $width = 240px
@ -94,46 +95,45 @@
</style> </style>
<script> <script>
this.root.addEventListener 'contextmenu' (e) => const contains = require('../../common/scripts/contains');
this.root.addEventListener('contextmenu', e => {
e.preventDefault(); e.preventDefault();
});
this.mousedown = (e) => { this.mousedown = e => {
e.preventDefault(); e.preventDefault();
if (!contains this.root, e.target) and (this.root != e.target) if (!contains(this.root, e.target) && (this.root != e.target)) this.close();
@close(); return false;
return false };
this.open = (pos) => { this.open = pos => {
all = document.query-selector-all 'body *' document.querySelectorAll('body *').forEach(el => {
Array.prototype.forEach.call all, (el) => el.addEventListener('mousedown', this.mousedown);
el.addEventListener 'mousedown' @mousedown });
this.root.style.display = 'block'
this.root.style.left = pos.x + 'px'
this.root.style.top = pos.y + 'px'
Velocity(this.root, 'finish' true this.root.style.display = 'block';
Velocity(this.root, { opacity: 0 } 0ms this.root.style.left = pos.x + 'px';
this.root.style.top = pos.y + 'px';
Velocity(this.root, 'finish', true);
Velocity(this.root, { opacity: 0 }, 0);
Velocity(this.root, { Velocity(this.root, {
opacity: 1 opacity: 1
}, { }, {
queue: false queue: false,
duration: 100ms duration: 100,
easing: 'linear' easing: 'linear'
} });
};
this.close = () => { this.close = () => {
all = document.query-selector-all 'body *' document.querySelectorAll('body *').forEach(el => {
Array.prototype.forEach.call all, (el) => el.removeEventListener('mousedown', this.mousedown);
el.removeEventListener 'mousedown' @mousedown });
this.trigger('closed'); this.trigger('closed');
this.unmount(); this.unmount();
};
function contains(parent, child)
node = child.parentNode
while (node != null)
if (node == parent)
return true
node = node.parentNode
return false
</script> </script>
</mk-contextmenu> </mk-contextmenu>

View File

@ -79,69 +79,72 @@
</style> </style>
<script> <script>
this.can-through = if opts.can-through? then opts.can-through else true this.canThrough = opts.canThrough != null ? opts.canThrough : true;
this.opts.buttons.forEach (button) => this.opts.buttons.forEach(button => {
button._onclick = => button._onclick = () => {
if button.onclick? if (button.onclick) button.onclick();
button.onclick(); this.close();
@close(); };
});
this.on('mount', () => { this.on('mount', () => {
this.refs.header.innerHTML = this.opts.title this.refs.header.innerHTML = this.opts.title;
this.refs.body.innerHTML = this.opts.text this.refs.body.innerHTML = this.opts.text;
this.refs.bg.style.pointer-events = 'auto' this.refs.bg.style.pointerEvents = 'auto';
Velocity(this.refs.bg, 'finish' true Velocity(this.refs.bg, 'finish', true);
Velocity(this.refs.bg, { Velocity(this.refs.bg, {
opacity: 1 opacity: 1
}, { }, {
queue: false queue: false,
duration: 100ms duration: 100,
easing: 'linear' easing: 'linear'
} });
Velocity(this.refs.main, { Velocity(this.refs.main, {
opacity: 0 opacity: 0,
scale: 1.2 scale: 1.2
}, { }, {
duration: 0 duration: 0
} });
Velocity(this.refs.main, { Velocity(this.refs.main, {
opacity: 1 opacity: 1,
scale: 1 scale: 1
}, { }, {
duration: 300ms duration: 300,
easing: [ 0, 0.5, 0.5, 1 ] easing: [ 0, 0.5, 0.5, 1 ]
} });
});
this.close = () => { this.close = () => {
this.refs.bg.style.pointer-events = 'none' this.refs.bg.style.pointerEvents = 'none';
Velocity(this.refs.bg, 'finish' true Velocity(this.refs.bg, 'finish', true);
Velocity(this.refs.bg, { Velocity(this.refs.bg, {
opacity: 0 opacity: 0
}, { }, {
queue: false queue: false,
duration: 300ms duration: 300,
easing: 'linear' easing: 'linear'
} });
this.refs.main.style.pointer-events = 'none' this.refs.main.style.pointerEvents = 'none';
Velocity(this.refs.main, 'finish' true Velocity(this.refs.main, 'finish', true);
Velocity(this.refs.main, { Velocity(this.refs.main, {
opacity: 0 opacity: 0,
scale: 0.8 scale: 0.8
}, { }, {
queue: false queue: false,
duration: 300ms duration: 300,
easing: [ 0.5, -0.5, 1, 0.5 ] easing: [ 0.5, -0.5, 1, 0.5 ],
complete: => complete: () => this.unmount()
this.unmount(); });
} };
this.bg-click = () => { this.bgClick = () => {
if @can-through if (this.canThrough) {
if this.opts.on-through? if (this.opts.onThrough) this.opts.onThrough();
this.opts.on-through! this.close();
@close(); }
};
</script> </script>
</mk-dialog> </mk-dialog>

View File

@ -408,7 +408,7 @@
this.api('drive/files/update', { this.api('drive/files/update', {
file_id: file file_id: file
folder_id: if this.folder? then this.folder.id else null folder_id: if this.folder? then this.folder.id else null
.then => }).then(() => {
// something // something
.catch (err, text-status) => .catch (err, text-status) =>
console.error err console.error err
@ -425,7 +425,7 @@
this.api('drive/folders/update', { this.api('drive/folders/update', {
folder_id: folder folder_id: folder
parent_id: if this.folder? then this.folder.id else null parent_id: if this.folder? then this.folder.id else null
.then => }).then(() => {
// something // something
.catch (err) => .catch (err) =>
if err == 'detected-circular-definition' if err == 'detected-circular-definition'

View File

@ -68,7 +68,7 @@
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(() => {
// something // something
.catch (err) => .catch (err) =>
console.error err console.error err

View File

@ -54,7 +54,7 @@
this.api('drive/folders/update', { this.api('drive/folders/update', {
folder_id: this.folder.id folder_id: this.folder.id
name: name name: name
.then => }).then(() => {
// something // something
.catch (err) => .catch (err) =>
console.error err console.error err

View File

@ -118,7 +118,7 @@
this.api('drive/files/update', { this.api('drive/files/update', {
file_id: file file_id: file
folder_id: this.folder.id folder_id: this.folder.id
.then => }).then(() => {
// something // something
.catch (err, text-status) => .catch (err, text-status) =>
console.error err console.error err
@ -133,7 +133,7 @@
this.api('drive/folders/update', { this.api('drive/folders/update', {
folder_id: folder folder_id: folder
parent_id: this.folder.id parent_id: this.folder.id
.then => }).then(() => {
// something // something
.catch (err) => .catch (err) =>
if err == 'detected-circular-definition' if err == 'detected-circular-definition'

View File

@ -72,7 +72,7 @@
this.api('drive/files/update', { this.api('drive/files/update', {
file_id: file file_id: file
folder_id: if this.folder? then this.folder.id else null folder_id: if this.folder? then this.folder.id else null
.then => }).then(() => {
// something // something
.catch (err, text-status) => .catch (err, text-status) =>
console.error err console.error err
@ -87,7 +87,7 @@
this.api('drive/folders/update', { this.api('drive/folders/update', {
folder_id: folder folder_id: folder
parent_id: if this.folder? then this.folder.id else null parent_id: if this.folder? then this.folder.id else null
.then => }).then(() => {
// something // something
.catch (err, text-status) => .catch (err, text-status) =>
console.error err console.error err

View File

@ -33,9 +33,5 @@
40% 40%
transform scale(1) transform scale(1)
</style> </style>
</mk-ellipsis-icon> </mk-ellipsis-icon>

View File

@ -103,21 +103,21 @@
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>

View File

@ -1,14 +0,0 @@
<mk-go-top>
<button class="hidden" title="一番上へ"><i class="fa fa-angle-up"></i></button>
<script>
window.addEventListener 'load' this.on-scroll
window.addEventListener 'scroll' this.on-scroll
window.addEventListener 'resize' this.on-scroll
this.on-scroll = () => {
if $ window .scroll-top! > 500px
@remove-class 'hidden'
else
@add-class 'hidden'
</script>
</mk-go-top>

View File

@ -16,7 +16,6 @@ require('./crop-window.tag');
require('./settings.tag'); require('./settings.tag');
require('./settings-window.tag'); require('./settings-window.tag');
require('./analog-clock.tag'); require('./analog-clock.tag');
require('./go-top.tag');
require('./ui-header.tag'); require('./ui-header.tag');
require('./ui-header-account.tag'); require('./ui-header-account.tag');
require('./ui-header-notifications.tag'); require('./ui-header-notifications.tag');

View File

@ -1,13 +1,17 @@
<mk-input-dialog> <mk-input-dialog>
<mk-window ref="window" is-modal={ true } width={ '500px' }><yield to="header"><i class="fa fa-i-cursor"></i>{ parent.title }</yield> <mk-window ref="window" is-modal={ true } width={ '500px' }>
<yield to="content"> <yield to="header">
<i class="fa fa-i-cursor"></i>{ parent.title }
</yield>
<yield to="content">
<div class="body"> <div class="body">
<input ref="text" oninput={ parent.update } onkeydown={ parent.onKeydown } placeholder={ parent.placeholder }/> <input ref="text" oninput={ parent.update } onkeydown={ parent.onKeydown } placeholder={ parent.placeholder }/>
</div> </div>
<div class="action"> <div class="action">
<button class="cancel" onclick={ parent.cancel }>キャンセル</button> <button class="cancel" onclick={ parent.cancel }>キャンセル</button>
<button class="ok" disabled={ !parent.allowEmpty && refs.text.value.length == 0 } onclick={ parent.ok }>決定</button> <button class="ok" disabled={ !parent.allowEmpty && refs.text.value.length == 0 } onclick={ parent.ok }>決定</button>
</div></yield> </div>
</yield>
</mk-window> </mk-window>
<style> <style>
:scope :scope
@ -116,18 +120,17 @@
</style> </style>
<script> <script>
this.done = false this.done = false;
this.title = this.opts.title this.title = this.opts.title;
this.placeholder = this.opts.placeholder this.placeholder = this.opts.placeholder;
this.default = this.opts.default this.default = this.opts.default;
this.allow-empty = if this.opts.allow-empty? then this.opts.allow-empty else true this.allowEmpty = this.opts.allowEmpty != null ? this.opts.allowEmpty : true;
this.on('mount', () => { this.on('mount', () => {
this.text = this.refs.window.refs.text this.text = this.refs.window.refs.text;
if @default? if (this.default) this.text.value = this.default;
@text.value = @default this.text.focus();
@text.focus();
this.refs.window.on('closing', () => { this.refs.window.on('closing', () => {
if @done if @done
@ -138,6 +141,7 @@
this.refs.window.on('closed', () => { this.refs.window.on('closed', () => {
this.unmount(); this.unmount();
});
this.cancel = () => { this.cancel = () => {
this.done = false this.done = false
@ -148,7 +152,7 @@
this.done = true this.done = true
this.refs.window.close(); this.refs.window.close();
this.on-keydown = (e) => { this.onKeydown = (e) => {
if e.which == 13 // Enter if e.which == 13 // Enter
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();

View File

@ -127,13 +127,13 @@
if this.post.is_liked if this.post.is_liked
this.api('posts/likes/delete', { this.api('posts/likes/delete', {
post_id: this.post.id post_id: this.post.id
.then => }).then(() => {
this.post.is_liked = false this.post.is_liked = false
this.update(); this.update();
else else
this.api('posts/likes/create', { this.api('posts/likes/create', {
post_id: this.post.id post_id: this.post.id
.then => }).then(() => {
this.post.is_liked = true this.post.is_liked = true
this.update(); this.update();
</script> </script>

View File

@ -412,13 +412,13 @@
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();

View File

@ -455,7 +455,7 @@
.catch (err) => .catch (err) =>
console.error err console.error err
@notify '投稿できませんでした' @notify '投稿できませんでした'
.then => }).then(() => {
this.wait = false this.wait = false
this.update(); this.update();

View File

@ -127,14 +127,14 @@
this.wait = true this.wait = true
this.api('posts/create', { this.api('posts/create', {
repost_id: this.opts.post.id repost_id: this.opts.post.id
text: if @quote then this.refs.text.value else undefined text: if this.quote then this.refs.text.value else undefined
}).then((data) => { }).then((data) => {
this.trigger('posted'); this.trigger('posted');
@notify 'Repostしました' @notify 'Repostしました'
.catch (err) => .catch (err) =>
console.error err console.error err
@notify 'Repostできませんでした' @notify 'Repostできませんでした'
.then => }).then(() => {
this.wait = false this.wait = false
this.update(); this.update();

View File

@ -42,7 +42,7 @@
window.addEventListener 'scroll' this.on-scroll window.addEventListener 'scroll' this.on-scroll
this.api('posts/search', { this.api('posts/search', {
query: @query query: this.query
}).then((posts) => { }).then((posts) => {
this.is-loading = false this.is-loading = false
this.is-empty = posts.length == 0 this.is-empty = posts.length == 0
@ -68,7 +68,7 @@
this.more-loading = true this.more-loading = true
this.update(); this.update();
this.api('posts/search', { this.api('posts/search', {
query: @query query: this.query
page: this.page + 1 page: this.page + 1
}).then((posts) => { }).then((posts) => {
this.more-loading = false this.more-loading = false

View File

@ -1,5 +1,11 @@
<mk-sub-post-content> <mk-sub-post-content>
<div class="body"><a class="reply" if={ post.reply_to_id }><i class="fa fa-reply"></i></a><span ref="text"></span><a class="quote" if={ post.repost_id } href={ '/post:' + post.repost_id }>RP: ...</a></div> <div class="body">
<a class="reply" if={ post.reply_to_id }>
<i class="fa fa-reply"></i>
</a>
<span ref="text"></span>
<a class="quote" if={ post.repost_id } href={ '/post:' + post.repost_id }>RP: ...</a>
</div>
<details if={ post.media }> <details if={ post.media }>
<summary>({ post.media.length }つのメディア)</summary> <summary>({ post.media.length }つのメディア)</summary>
<mk-images-viewer images={ post.media }></mk-images-viewer> <mk-images-viewer images={ post.media }></mk-images-viewer>
@ -31,15 +37,17 @@
this.mixin('text'); this.mixin('text');
this.mixin('user-preview'); this.mixin('user-preview');
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

@ -324,7 +324,7 @@
this.mixin('NotImplementedException'); this.mixin('NotImplementedException');
this.post = this.opts.post; this.post = this.opts.post;
this.isRepost = this.post.repost != null && this.post.text == null; this.isRepost = this.post.repost && this.post.text == null;
this.p = this.isRepost ? this.post.repost : this.post; this.p = this.isRepost ? this.post.repost : this.post;
this.title = this.dateStringify(this.p.created_at); this.title = this.dateStringify(this.p.created_at);
@ -354,58 +354,87 @@
}); });
this.reply = () => { this.reply = () => {
form = document.body.appendChild(document.createElement('mk-post-form-window')); riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), {
riot.mount form, do
reply: this.p reply: this.p
});
};
this.repost = () => { this.repost = () => {
form = document.body.appendChild(document.createElement('mk-repost-form-window')); riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), {
riot.mount form, do
post: this.p post: this.p
});
};
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.toggle-detail = () => { this.toggleDetail = () => {
this.is-detail-opened = !@is-detail-opened this.update({
this.update(); isDetailOpened: !this.isDetailOpened
});
};
this.on-key-down = (e) => { this.onKeyDown = e => {
should-be-cancel = true let shouldBeCancel = true;
switch
| e.which == 38 or e.which == 74 or (e.which == 9 and e.shift-key) => // ↑, j or Shift+Tab
focus this.root, (e) -> e.previousElementSibling
| e.which == 40 or e.which == 75 or e.which == 9 => // ↓, k or Tab
focus this.root, (e) -> e.nextElementSibling
| e.which == 81 or e.which == 69 => // q or e
@repost!
| e.which == 70 or e.which == 76 => // f or l
@like!
| e.which == 82 => // r
@reply!
| _ =>
should-be-cancel = false
if should-be-cancel switch (true) {
e.preventDefault(); case e.which == 38: // [↑]
case e.which == 74: // [j]
case e.which == 9 && e.shiftKey: // [Shift] + [Tab]
focus(this.root, e => e.previousElementSibling);
break;
function focus(el, fn) case e.which == 40: // [↓]
target = fn el case e.which == 75: // [k]
if target? case e.which == 9: // [Tab]
if target.has-attribute 'tabindex' focus(this.root, e => e.nextElementSibling);
break;
case e.which == 81: // [q]
case e.which == 69: // [e]
this.repost();
break;
case e.which == 70: // [f]
case e.which == 76: // [l]
this.like();
break;
case e.which == 82: // [r]
this.reply();
break;
default:
shouldBeCancel = false;
}
if (shouldBeCancel) e.preventDefault();
};
function focus(el, fn) {
const target = fn(el);
if (target) {
if (target.hasAttribute('tabindex')) {
target.focus(); target.focus();
else } else {
focus target, fn focus(target, fn);
}
}
}
</script> </script>
</mk-timeline-post> </mk-timeline-post>

View File

@ -501,7 +501,7 @@
this.ondragover = (e) => { this.ondragover = (e) => {
e.dataTransfer.dropEffect = 'none' e.dataTransfer.dropEffect = 'none'
this.on-keydown = (e) => { this.onKeydown = (e) => {
if e.which == 27 // Esc if e.which == 27 // Esc
if @can-close if @can-close
e.preventDefault(); e.preventDefault();

View File

@ -233,7 +233,7 @@
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 'アプリの作成に失敗しました。再度お試しください。'

View File

@ -192,9 +192,9 @@
name = window.prompt '名前を変更' this.file.name name = window.prompt '名前を変更' this.file.name
if name? and name != '' and name != this.file.name if name? and name != '' and name != this.file.name
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>

View File

@ -84,21 +84,21 @@
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>

View File

@ -406,13 +406,13 @@
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();

View File

@ -9,24 +9,24 @@
<script> <script>
this.mixin('api'); this.mixin('api');
this.max = 30 this.max = 30;
this.offset = 0 this.offset = 0;
this.query = this.opts.query this.query = this.opts.query;
this.with-media = this.opts.with-media 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: @query query: this.query
}).then((posts) => { }).then(posts => {
res posts res posts
this.trigger('loaded'); this.trigger('loaded');
this.more = () => { this.more = () => {
@offset += @max this.offset += this.max;
this.api('posts/search', { this.api('posts/search', {
query: @query query: this.query
max: @max max: this.max
offset: @offset offset: this.offset
</script> </script>
</mk-search-posts> </mk-search-posts>

View File

@ -11,21 +11,21 @@
<script> <script>
this.mixin('api'); this.mixin('api');
this.user = this.opts.user this.user = this.opts.user;
this.with-media = this.opts.with-media 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: @with-media with_media: @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: @with-media 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>