Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

機能追加(4/4): 短縮URLの展開機能を追加 #223

Merged
merged 1 commit into from
Nov 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ namespace app {
["zoom_ratio_video", "200"],
["image_height_fix", "on"],
["delay_scroll_time", "600"],
["expand_short_url", "none"],
["expand_short_url_timeout", "3000"],
["aa_font", "aa"],
["popup_trigger", "click"],
["ngwords", ""],
Expand Down
7 changes: 5 additions & 2 deletions src/core/HTTP.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
///<reference path="../global.d.ts" />

namespace app.HTTP {
"use strict";

Expand Down Expand Up @@ -70,7 +72,7 @@ namespace app.HTTP {

resonseHeaders = Request.parseHTTPHeader(xhr.getAllResponseHeaders());

callback(new Response(xhr.status, resonseHeaders, xhr.responseText));
callback(new Response(xhr.status, resonseHeaders, xhr.responseText, xhr.responseURL));
});

xhr.addEventListener("timeout", () => {
Expand Down Expand Up @@ -115,7 +117,8 @@ namespace app.HTTP {
constructor (
public status:number,
public headers:{[index:string]:string;} = {},
public body:string = null
public body:string = null,
public responseURL: string = null
) {
}
}
Expand Down
37 changes: 37 additions & 0 deletions src/core/URL.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
///<reference path="HTTP.ts" />
///<reference path="../app.ts" />

namespace app {
export namespace URL {
export const CH_BOARD_REG = /^(http:\/\/[\w\.]+\/test\/read\.cgi\/\w+\/\d+).*?$/;
Expand Down Expand Up @@ -127,6 +130,38 @@ namespace app {

return str.slice(1);
}

export const SHORT_URL_REG = /^h?ttps?:\/\/(?:amba\.to|amzn\.to|bit\.ly|buff\.ly|cas\.st|dlvr\.it|fb\.me|g\.co|goo\.gl|htn\.to|ift\.tt|is\.gd|itun\.es|j\.mp|jump\.cx|ow\.ly|p\.tl|prt\.nu|snipurl\.com|spoti\.fi|t\.co|tiny\.cc|tinyurl\.com|tl\.gd|tr\.im|trib\.al|url\.ie|urx\.nu|urx2\.nu|urx3\.nu|ur0\.pw|wk\.tk|xrl\.us)\/.+/;

export function expandShortURL (a: HTMLElement, shortUrl: string): any {
var dfd = $.Deferred();
var finalUrl: string = "";

var req = new app.HTTP.Request("HEAD", shortUrl);
req.timeout = parseInt(app.config.get("expand_short_url_timeout"));

req.send((res) => {
if (res.status === 0 || res.status >= 400) {
return dfd.resolve(a, null);
}
finalUrl = res.responseURL;
// 無限ループの防止
if (finalUrl === shortUrl) {
return dfd.resolve(a, null);
}
// 取得したURLが短縮URLだった場合は再帰呼出しする
if (SHORT_URL_REG.test(finalUrl)) {
expandShortURL(a, finalUrl).done( (a, finalUrl) => {
return dfd.resolve(a, finalUrl);
});
// 短縮URL以外なら終了
} else {
return dfd.resolve(a, finalUrl);
}
});

return dfd.promise();
}
}
}

Expand All @@ -152,5 +187,7 @@ namespace app {
export var parse_query = app.URL.parseQuery;
export var parse_hashquery = app.URL.parseHashQuery;
export var build_param = app.URL.buildQueryString;
export const SHORT_URL_REG = app.URL.SHORT_URL_REG;
export var expandShortURL = app.URL.expandShortURL;
}
}
4 changes: 4 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
namespace UI {
declare var Animate:any;
}

interface XMLHttpRequest {
responseURL: string;
}
3 changes: 2 additions & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"notifications",
"webRequest",
"webRequestBlocking",
"http://*/"
"http://*/",
"https://*/"
],
"app" : {
"launch" : {
Expand Down
118 changes: 97 additions & 21 deletions src/ui/ThreadContent.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -772,33 +772,109 @@ class UI.ThreadContent
break
return

app.util.concurrent(@container.querySelectorAll(".message > a:not(.thumbnail):not(.has_thumbnail)"), (a) ->
return app.ImageReplaceDat.do(a, a.href).done( (a, res, err) ->
addThumbnail(a, res.text, "image", res.referrer, res.cookie) unless err?
# Audioの確認
if app.config.get("audio_supported") is "on"
if /\.(?:mp3|m4a|wav|oga|spx)(?:[\?#:&].*)?$/.test(a.href)
addThumbnail(a, a.href, "audio")
if (
app.config.get("audio_supported_ogg") is "on" and
/\.(?:ogg|ogx)(?:[\?#:&].*)?$/.test(a.href)
)
addThumbnail(a, a.href, "audio")
# Videoの確認
if app.config.get("video_supported") is "on"
if /\.(?:mp4|m4v|webm|ogv)(?:[\?#:&].*)?$/.test(a.href)
addThumbnail(a, a.href, "video")
if (
app.config.get("video_supported_ogg") is "on" and
/\.(?:ogg|ogx)(?:[\?#:&].*)?$/.test(a.href)
# 展開URL追加処理
addExpandedURL = (sourceA, finalUrl) ->
sourceA.classList.add("has_expandedURL")

expandedURL = document.createElement("div")
expandedURL.className = "expandedURL"
expandedURL.setAttribute("short-url", sourceA.href)
if app.config.get("expand_short_url") is "popup"
expandedURL.classList.add("hide_data")

if finalUrl
expandedURLLink = document.createElement("a")
expandedURLLink.textContent = finalUrl
expandedURLLink.href = app.safe_href(finalUrl)
expandedURLLink.target = "_blank"
expandedURL.appendChild(expandedURLLink)
else
expandedURL.classList.add("expand_error")
expandedURLLink = null

sib = sourceA
while true
pre = sib
sib = pre.nextSibling
if !sib? or sib.nodeName is "BR"
if sib?.nextSibling?.classList?.contains("expandedURL")
continue
if not pre.classList?.contains("expandedURL")
sourceA.parentNode.insertBefore(document.createElement("br"), sib)
sourceA.parentNode.insertBefore(expandedURL, sib)
break

return expandedURLLink

# MediaTypeの取得
getMediaType = (href, dftValue) ->
mediaType = null
# Audioの確認
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

元々Audio/VideoがImageReplaceDatの処理後だったのがそうでなくなってます
おそらく817行目のあとにくるべきかと

if /\.(?:mp3|m4a|wav|oga|spx)(?:[\?#:&].*)?$/.test(href)
mediaType = "audio"
if (
app.config.get("audio_supported_ogg") is "on" and
/\.(?:ogg|ogx)(?:[\?#:&].*)?$/.test(href)
)
mediaType = "audio"
# Videoの確認
if /\.(?:mp4|m4v|webm|ogv)(?:[\?#:&].*)?$/.test(href)
mediaType = "video"
if (
app.config.get("video_supported_ogg") is "on" and
/\.(?:ogg|ogx)(?:[\?#:&].*)?$/.test(href)
)
mediaType = "video"
# 初期値の設定と有効性のチェック
switch mediaType
when null
mediaType = dftValue
when "audio"
mediaType = null if app.config.get("audio_supported") is "off"
when "video"
mediaType = null if app.config.get("video_supported") is "off"
return mediaType

checkUrl = (a) ->
d2 = $.Deferred()
if app.config.get("expand_short_url") isnt "none"
if app.url.SHORT_URL_REG.test(a.href)
# 短縮URLの展開
app.url.expandShortURL(a, a.href).done( (a, finalUrl) ->
newLink = addExpandedURL(a, finalUrl)
if finalUrl
d2.resolve(newLink, newLink.href)
else
d2.resolve(a, a.href)
return
)
addThumbnail(a, a.href, "video")
return
else
d2.resolve(a, a.href)
else
d2.resolve(a, a.href)
return d2.promise()

app.util.concurrent(@container.querySelectorAll(
".message > a:not(.thumbnail):not(.has_thumbnail):not(.expandedURL):not(.has_expandedURL)"
), (a) ->
checkUrl(a).then( (a, link) ->
return app.ImageReplaceDat.do(a, link)
).then( (a, res, err) ->
# MediaTypeの設定
unless err?
href = res.text
mediaType = getMediaType(href, "image")
else
href = a.href
mediaType = getMediaType(href, null)
# サムネイルの追加
addThumbnail(a, href, mediaType, res.referrer, res.cookie) if mediaType
)
).always(=>
d.resolve()
return
)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app.util.concurrentではだめですか?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

既存の方法ですっきりさせたいのですが、短縮URLの展開後のサムネイルの確認などがあり、それぞれの終了時の処理内容など、うまい方法がないか検討中です。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkUrl = (a) ->
  d = new $.Deffered()
  if app.config.get("expand_short_url") isnt "none"
    if app.url.checkShortURL(a.href)
      app.url.expandShortURL(a, a.href).done( (a, finalUrl) ->
        newLink = addExpandedURL(a, finalUrl)
        if finalUrl
          d.resolve(a, newLink)
        else
          d.resolve(a, a.href)
        return
      )
    else
      d.resolve(a, a.href)
  else
    d.resolve(a, a.href)
  return d.promise()
  
app.util.concurrent(@container.querySelectorAll(".message > a:not(.thumbnail):not(.has_thumbnail)"), (a) ->
  checkUrl(a).done( (a, link) ->
    return app.ImageReplaceDat.do(a, link)
  ).done( (a, res, err) ->
    # addThumbnail関連
  )
)

これでどうでしょう?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

提案ありがとうございます。
非同期プログラミングに不慣れな身としては何がなんだか。と言った感じですが試してみます。

return
return
)
Expand Down
17 changes: 17 additions & 0 deletions src/view/config.haml
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@
遅延スクロールの待機時間:
%input.direct(type="number" name="delay_scroll_time" min="0" max="5000")ms

%section
%h2 短縮URLの展開
%div
%label
%input.direct(name="expand_short_url" type="radio" value="none" checked)
何もしない
%label
%input.direct(name="expand_short_url" type="radio" value="inline")
本文内に表示する
%label
%input.direct(name="expand_short_url" type="radio" value="popup")
マウスを重ねた時にポップアップする
%br
%label
タイムアウト:
%input.direct(type="number" name="expand_short_url_timeout" min="0")ms

%section
%h2 アスキーアート表示
%div
Expand Down
21 changes: 20 additions & 1 deletion src/view/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,26 @@ app.main = ->
tmp = JSON.stringify(type: "request_reload", force_update: true, kind: request.kind, mes: request.mes, name: request.name, mail: request.mail, title: request.title, thread_url: request.thread_url)
iframe.contentWindow.postMessage(tmp, location.origin)

# リクエスト・ヘッダーの監視
chrome.webRequest.onBeforeSendHeaders.addListener (details) ->
replaceHeader = (name, value) ->
for header in details.requestHeaders
if header.name.toLowerCase() is name
header.value = value
break
return

# 短縮URLの展開でのt.coに対する例外
if details.method is "HEAD" and app.URL.getDomain(details.url) is "t.co"
replaceHeader("user-agent", "")

return {requestHeaders: details.requestHeaders}
,{
urls: ["*://t.co/*"],
types: ["xmlhttprequest"]
}
,["blocking", "requestHeaders"]

#viewからのメッセージを監視
window.addEventListener "message", (e) ->
return if e.origin isnt location.origin or typeof e.data isnt "string"
Expand Down Expand Up @@ -850,4 +870,3 @@ app.main = ->
)
return
return

19 changes: 19 additions & 0 deletions src/view/thread.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,25 @@ app.boot "/view/thread.html", ->
app.view_thread._controlVideoCursor(@, e.type)
return

# 展開済みURLのポップアップ
.on "mouseenter", ".has_expandedURL", (e) ->
return if app.config.get("expand_short_url") isnt "popup"
popup_helper this, e, =>
targetUrl = this.href

frag = document.createDocumentFragment()
sib = this
while true
sib = sib.nextSibling
if sib?.classList?.contains("expandedURL") and
sib?.getAttribute("short-url") is targetUrl
frag.appendChild(sib.cloneNode(true))
break

frag.querySelector(".expandedURL").classList.remove("hide_data")
$popup = $("<div>").append(frag)
return

#クイックジャンプパネル
do ->
jump_hoge =
Expand Down
29 changes: 29 additions & 0 deletions src/view/thread.scss
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,35 @@ header {
}
}

.expandedURL {
position: relative;
display: inline-block;
margin: 5px 10px;

> a {
font-style: italic;
}
&::before {
margin-right: 10px;
content: "(" attr(short-url) ") →";
}
> .thumbnail {
margin-left: 30px;
}
&.expand_error::after {
content: "展開できませんでした。";
}

.popup & {
display: block;
padding: 5px;
}
}

.hide_data {
display: none;
}

.popup {
position: fixed;
z-index: $z-index-popup;
Expand Down