|
// このファイルは更新しません |
|
// 最新のスクリプトは下記をご確認ください。 |
|
// https://p.eriri.net/tj-deck/main.js |
|
// https://p.eriri.net/tj-deck/tj-deck.js |
|
class TJScrollTask { |
|
constructor($target, x, duration) { |
|
this.$t = $target; |
|
this.x = x; |
|
this.d = duration; |
|
this.sl = $target.scrollLeft; |
|
this.sTime = Date.now(); |
|
this.ended = false; |
|
|
|
this._bindAnim = this._anim.bind(this); |
|
|
|
requestAnimationFrame(this._bindAnim); |
|
} |
|
|
|
stop() { |
|
if (this.ended) return; |
|
this.ended = true; |
|
cancelAnimationFrame(this._bindAnim); |
|
} |
|
|
|
_anim() { |
|
if (this.ended) return; |
|
var t = (Date.now()-this.sTime)/this.d, |
|
b = this.sl, |
|
c = this.x - this.sl, |
|
d = 1; |
|
if (t > 1 && !this.ended) { |
|
this.stop(); |
|
t = 1; |
|
} |
|
this.$t.scrollLeft = this._easeOut(t, b, c, d); |
|
if (t < 1) requestAnimationFrame(this._bindAnim); |
|
} |
|
_easeOut(t, b, c, d) { |
|
t /= d; |
|
t = t-1; |
|
return c*(t*t*t + 1) + b; |
|
} |
|
} |
|
|
|
class TJTweetDeck { |
|
constructor() { |
|
this.$wrap = document.querySelector("#container"); |
|
} |
|
back() { |
|
|
|
// モーダルが表示中なら消して終了 |
|
var $mdlDismiss = document.querySelector(".mdl-dismiss"); |
|
if ($mdlDismiss) { |
|
$mdlDismiss.click(); |
|
return; |
|
} |
|
|
|
// ツイートパネルが表示中なら消して終了 |
|
if (this.isShownDrawer()) { |
|
this.hideDrawer(); |
|
return; |
|
} |
|
|
|
// カラムに戻るボタンがあれば押して終了 |
|
var $clm = this.getClosestColumn(this.$wrap.scrollLeft); |
|
var $backToHome = $clm.querySelector(".js-column-back"); |
|
if ($backToHome) { |
|
$backToHome.click(); |
|
return; |
|
} |
|
|
|
} |
|
// 何か表示中ならtrue |
|
isShownItem() { |
|
return !!document.querySelector(".mdl-dismiss") || this.isShownDrawer(); |
|
} |
|
// ドロワーが表示中ならtrue |
|
isShownDrawer() { |
|
return !!document.querySelector(".hide-detail-view-inline"); |
|
} |
|
// ドロワーを非表示にする |
|
hideDrawer() { |
|
var $btn = document.querySelector(".js-hide-drawer"); |
|
if ($btn) $btn.click(); |
|
} |
|
// ドロワーを表示する |
|
showDrawer() { |
|
var $btn = document.querySelector(".js-show-drawer"); |
|
if ($btn) $btn.click(); |
|
} |
|
|
|
// 戻るボタンを管理する |
|
manageBack() { |
|
history.pushState(null, null, ""); |
|
window.addEventListener("popstate", function (event) { |
|
this.back(); |
|
history.pushState(null, null, ""); |
|
}.bind(this)); |
|
} |
|
|
|
// 横スクロールを管理する |
|
manageScroll() { |
|
var sPos; |
|
var sTime = Date.now(); |
|
var prevPos; |
|
var $prevClm; |
|
var flag = null;// -1:開始前, 0:縦方向, 1:横方向 |
|
var scrollTask; |
|
window.addEventListener("touchstart", function (event) { |
|
if (event.touches.length > 1 || this.isShownItem()) return; |
|
sPos = this._getPosObj(event); |
|
prevPos = sPos; |
|
flag = -1; |
|
sTime = Date.now(); |
|
$prevClm = this.getClosestColumn(this.$wrap.scrollLeft); |
|
}.bind(this)); |
|
window.addEventListener("touchmove", function (event) { |
|
if (!flag) return; |
|
if (flag < 0) { |
|
var pos = this._getPosObj(event); |
|
if (Math.abs(pos.x - sPos.x) < Math.abs(pos.y - sPos.y)) { |
|
flag = 0; |
|
return; |
|
} else { |
|
flag = 1; |
|
} |
|
} |
|
if (flag == 1) { |
|
if (scrollTask) scrollTask.stop(); |
|
var pos = this._getPosObj(event); |
|
this.$wrap.scrollLeft += prevPos.x - pos.x; |
|
prevPos = pos; |
|
} |
|
}.bind(this)); |
|
window.addEventListener("touchend", function (event) { |
|
if (flag < 1) return; |
|
flag = null; |
|
var time = Date.now(), |
|
pos = prevPos, |
|
distance = sPos.x - pos.x; |
|
|
|
var $targetClm; |
|
// スワイプ時 |
|
if (Math.abs(distance) / (time-sTime) >= 0.5) { |
|
if (distance > 0) { |
|
$targetClm = $prevClm.nextElementSibling; |
|
} else { |
|
$targetClm = $prevClm.previousElementSibling; |
|
} |
|
} |
|
else { |
|
$targetClm = this.getClosestColumn(this.$wrap.scrollLeft); |
|
} |
|
if ($targetClm) { |
|
if (scrollTask) scrollTask.stop(); |
|
|
|
scrollTask = new TJScrollTask(this.$wrap, $targetClm.offsetLeft, 500); |
|
} |
|
}.bind(this)); |
|
} |
|
|
|
getClosestColumn(sL) { |
|
var clms = document.querySelectorAll("section.column"); |
|
for (var i=0; i < clms.length; i++) { |
|
var distance = Math.abs(sL - clms[i].offsetLeft); |
|
if (distance <= clms[i].offsetWidth/2) { |
|
return clms[i]; |
|
} |
|
} |
|
return clms[0]; |
|
} |
|
|
|
_getPosObj(event) { |
|
return { |
|
x: event.touches[0].pageX, |
|
y: event.touches[0].pageY |
|
} |
|
} |
|
|
|
|
|
hideMenu() { |
|
document.body.classList.add("tj_hide_menu"); |
|
} |
|
showMenu() { |
|
document.body.classList.remove("tj_hide_menu"); |
|
} |
|
|
|
addTweetBtn() { |
|
var $btn = document.createElement("button"); |
|
$btn.classList.add("tj_tweet_btn", "Button", "Button--primary", "tweet-button"); |
|
$btn.innerHTML = `<i class="Icon icon-compose"></i>`; |
|
$btn.addEventListener("click", this.showDrawer); |
|
// document.body.insertBefore($btn, document.body.firstChild); |
|
document.querySelector(".js-app-content").appendChild($btn); |
|
} |
|
|
|
addStyle() { |
|
var $head = document.querySelector("head"), |
|
$style = document.createElement("style"); |
|
$style.rel = "stylesheet"; |
|
$style.type = "text/css"; |
|
$style.innerHTML = |
|
` |
|
body.tj_hide_menu { |
|
position: fixed; |
|
width: calc(100% + 50px); |
|
height: 100%; |
|
margin-left: -50px; |
|
} |
|
|
|
.tj_tweet_btn { |
|
position: fixed!important; |
|
width: 50px!important; |
|
height: 50px!important; |
|
bottom: 1em!important; |
|
right: 1em!important; |
|
padding: 0; |
|
background-color: #1da1f2; |
|
color: #fff; |
|
border-radius: 36px; |
|
font-size: 16px; |
|
line-height: 1em; |
|
text-align: center; |
|
box-shadow: 1px 1px 5px rgba(0, 0, 0, .5); |
|
|
|
z-index: 200; |
|
} |
|
.hide-detail-view-inline .tj_tweet_btn { |
|
display: none; |
|
} |
|
.tj_tweet_btn .icon-compose { |
|
display: inline-block; |
|
margin-top: 0; |
|
margin-left: 2px; |
|
font-size: 20px; |
|
} |
|
|
|
.application { |
|
z-index: auto; |
|
} |
|
|
|
/* カラムの余白をなくす */ |
|
.app-columns { |
|
padding: 0!important; |
|
} |
|
|
|
/* カラムを幅いっぱいに表示 */ |
|
.column { |
|
width: ${document.body.clientWidth}px!important; |
|
max-width: 600px!important; |
|
margin: 0!important; |
|
} |
|
|
|
/* カラムの設定をabsoluteに */ |
|
.js-column-options-container { |
|
position: absolute!important; |
|
width: 100%; |
|
} |
|
|
|
/* サイドパネルを表示したときにメインを動かなくする */ |
|
.application > .app-content { |
|
margin-right: 0!important; |
|
transform: translateX(0px)!important; |
|
} |
|
|
|
/* メインエリアのスクロールを禁止 */ |
|
#container { |
|
overflow: hidden!important; |
|
} |
|
|
|
/* サイドパネルを幅いっぱいに表示 */ |
|
.js-drawer { |
|
width: ${document.body.clientWidth}px!important; |
|
max-width: 600px!important; |
|
left: -${document.body.clientWidth}px!important; |
|
} |
|
.hide-detail-view-inline .js-drawer {/* 表示中 */ |
|
width: ${document.body.clientWidth}px!important; |
|
max-width: 600px!important; |
|
left: 0!important; |
|
z-index: 201!important; |
|
} |
|
.hide-detail-view-inline .js-drawer:after { |
|
display: none!important; |
|
} |
|
|
|
/* ツイートボタンを大きく */ |
|
.js-docked-compose .js-send-button { |
|
width: 100px!important; |
|
text-align: center; |
|
} |
|
|
|
/* サイドパネルのフッターを消す */ |
|
.js-docked-compose > footer { |
|
display: none!important; |
|
} |
|
.js-docked-compose .compose-content { |
|
bottom: 0!important; |
|
} |
|
|
|
/* サイドパネルのヘッダーを消す */ |
|
.js-compose-header { |
|
position: absolute!important; |
|
right: 20px!important; |
|
border: 0!important; |
|
} |
|
header.js-compose-header div.compose-title { |
|
display: none!important; |
|
} |
|
.js-account-selector-grid-toggle { |
|
margin-right: 50px!important; |
|
} |
|
|
|
/* モーダルの位置調整 */ |
|
.overlay:before, |
|
.ovl-plain:before, |
|
.ovl:before { |
|
display: none!important; |
|
} |
|
|
|
/* モーダルのメディア表示調整 */ |
|
.js-modal-panel .js-embeditem {/* 画面いっぱいに表示 */ |
|
height: 100%!important; |
|
top: 0!important; |
|
bottom: 0!important; |
|
} |
|
.js-modal-panel .js-embeditem iframe { |
|
max-width: 100%!important; |
|
max-height: 100%!important; |
|
} |
|
.js-modal-panel .js-med-tweet {/* ツイートを非表示 */ |
|
display: none!important; |
|
} |
|
`; |
|
$head.appendChild($style); |
|
} |
|
} |
|
|
|
|
|
|
|
var tj_tweetdeck = new TJTweetDeck(); |
|
tj_tweetdeck.addStyle(); |
|
tj_tweetdeck.manageScroll(); |
|
tj_tweetdeck.manageBack(); |
|
tj_tweetdeck.hideMenu(); |
|
tj_tweetdeck.addTweetBtn(); |