Backport fixes from master branch

This commit is contained in:
Zixaphir 2014-03-20 09:37:27 -07:00
parent af87eea3fb
commit 18db3994b6
6 changed files with 203 additions and 243 deletions

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.4.1 - 2014-03-15 * 4chan X - Version 1.4.1 - 2014-03-20
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/Spittie/4chan-x/blob/master/LICENSE * https://github.com/Spittie/4chan-x/blob/master/LICENSE

View File

@ -24,7 +24,7 @@
// ==/UserScript== // ==/UserScript==
/* /*
* 4chan X - Version 1.4.1 - 2014-03-15 * 4chan X - Version 1.4.1 - 2014-03-20
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/Spittie/4chan-x/blob/master/LICENSE * https://github.com/Spittie/4chan-x/blob/master/LICENSE
@ -8453,28 +8453,26 @@
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node); ExpandComment.callbacks.push(this.node);
} }
if (Conf['Title Link']) {
$.sync('CachedTitles', Linkify.titleSync);
}
return Post.callbacks.push({ return Post.callbacks.push({
name: 'Linkify', name: 'Linkify',
cb: this.node cb: this.node
}); });
}, },
node: function() { events: function(post) {
var data, el, end, endNode, i, index, items, length, link, links, node, result, saved, snapshot, space, test, word, _i, _len, _ref; var el, i, items;
if (this.isClone) { i = 0;
if (Conf['Embedding']) { items = $$('.embedder', post.nodes.comment);
i = 0; while (el = items[i++]) {
items = $$('.embed', this.nodes.comment); $.on(el, 'click', Linkify.cb.toggle);
while (el = items[i++]) { if ($.hasClass(el, 'embedded')) {
$.on(el, 'click', Linkify.cb.toggle); Linkify.cb.toggle.call(el);
if ($.hasClass(el, 'embedded')) {
Linkify.cb.toggle.call(el);
}
}
} }
return; }
},
node: function() {
var data, end, endNode, i, index, length, link, links, node, result, saved, snapshot, space, test, word;
if (this.isClone) {
return (Conf['Embedding'] ? Linkify.events(this) : null);
} }
if (!Linkify.regString.test(this.info.comment)) { if (!Linkify.regString.test(this.info.comment)) {
return; return;
@ -8486,7 +8484,7 @@
links = []; links = [];
while (node = snapshot.snapshotItem(i++)) { while (node = snapshot.snapshotItem(i++)) {
data = node.data; data = node.data;
if (node.parentElement.nodeName === "A" || !data) { if (!data || node.parentElement.nodeName === "A") {
continue; continue;
} }
while (result = test.exec(data)) { while (result = test.exec(data)) {
@ -8518,25 +8516,20 @@
} }
} }
} }
_ref = links.reverse(); i = links.length;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { while (i--) {
link = _ref[_i]; link = links[i];
this.nodes.links.push(Linkify.makeLink(link, this)); Linkify.embedProcess(Linkify.makeLink(link, this));
link.detach();
} }
if (!(Conf['Embedding'] || Conf['Link Title'])) { },
return; embedProcess: function(link) {
} var data;
links = this.nodes.links; if (data = Linkify.services(link)) {
i = 0; if (Conf['Embedding']) {
while (link = links[i++]) { Linkify.embed(data);
if (data = Linkify.services(link)) { }
if (Conf['Embedding']) { if (Conf['Link Title']) {
Linkify.embed(data); return Linkify.title(data);
}
if (Conf['Link Title']) {
Linkify.title(data);
}
} }
} }
}, },
@ -8549,7 +8542,7 @@
return range; return range;
}, },
makeLink: function(range) { makeLink: function(range) {
var a, char, i, text; var a, i, t, text;
text = range.toString(); text = range.toString();
i = 0; i = 0;
while (/[(\[{<>]/.test(text.charAt(i))) { while (/[(\[{<>]/.test(text.charAt(i))) {
@ -8565,8 +8558,8 @@
} }
} }
i = 0; i = 0;
while (/[)\]}>.,]/.test(char = text.charAt(text.length - (1 + i)))) { while (/[)\]}>.,]/.test(t = text.charAt(text.length - (1 + i)))) {
if (!(/[.,]/.test(char) || (text.match(/[()\[\]{}<>]/g)).length % 2)) { if (!(/[.,]/.test(t) || (text.match(/[()\[\]{}<>]/g)).length % 2)) {
break; break;
} }
i++; i++;
@ -8591,6 +8584,7 @@
}); });
$.add(a, range.extractContents()); $.add(a, range.extractContents());
range.insertNode(a); range.insertNode(a);
range.detach();
return a; return a;
}, },
services: function(link) { services: function(link) {
@ -8599,10 +8593,9 @@
_ref = Linkify.types; _ref = Linkify.types;
for (key in _ref) { for (key in _ref) {
type = _ref[key]; type = _ref[key];
if (!(match = type.regExp.exec(href))) { if (match = type.regExp.exec(href)) {
continue; return [key, match[1], match[2], link];
} }
return [key, match[1], match[2], link];
} }
}, },
embed: function(data) { embed: function(data) {
@ -8631,7 +8624,7 @@
if (Conf['Auto-embed']) { if (Conf['Auto-embed']) {
Linkify.cb.toggle.call(embed); Linkify.cb.toggle.call(embed);
} }
data.push(embed); return data.push(embed);
}, },
title: function(data) { title: function(data) {
var embed, err, key, link, options, service, title, titles, uid; var embed, err, key, link, options, service, title, titles, uid;
@ -8649,9 +8642,9 @@
} }
} else { } else {
try { try {
$.cache(service.api(uid), function() { return $.cache(service.api(uid), (function() {
return title = Linkify.cb.title(this, data); return Linkify.cb.title(this, data);
}, { }), {
responseType: 'json' responseType: 'json'
}); });
} catch (_error) { } catch (_error) {
@ -8659,17 +8652,9 @@
if (link) { if (link) {
link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"; link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>";
} }
return;
}
if (title) {
titles[uid] = [title, Date.now()];
return $.set('CachedTitles', titles);
} }
} }
}, },
titleSync: function(value) {
return Conf['CachedTitles'] = value;
},
cb: { cb: {
toggle: function() { toggle: function() {
var string, _ref; var string, _ref;
@ -8695,26 +8680,26 @@
$.addClass(el, a.dataset.key); $.addClass(el, a.dataset.key);
return el; return el;
}, },
title: function(response, data) { title: function(req, data) {
var embed, key, link, options, service, text, uid; var embed, key, link, options, service, status, text, uid;
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4]; key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4];
status = req.status;
service = Linkify.types[key].title; service = Linkify.types[key].title;
switch (response.status) { text = "[" + key + "] " + ((function() {
case 200: switch (status) {
case 304: case 200:
text = "" + (service.text(response.response)); case 304:
if (Conf['Embedding']) { return service.text(req.response);
embed.dataset.title = text; case 404:
} return "Not Found";
break; case 403:
case 404: return "Forbidden or Private";
text = "[" + key + "] Not Found"; default:
break; return "" + status + "'d";
case 403: }
text = "[" + key + "] Forbidden or Private"; })());
break; if (Conf['Embedding'] && (status === 200 || status === 304)) {
default: embed.dataset.title = text;
text = "[" + key + "] " + this.status + "'d";
} }
if (link) { if (link) {
return link.textContent = text; return link.textContent = text;
@ -12460,8 +12445,8 @@
if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) { if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) {
return; return;
} }
$.on(window, 'popstate', Navigate.popstate);
$.ready(function() { $.ready(function() {
$.on(window, 'popstate', Navigate.popstate);
Navigate.makeBreadCrumb(window.location, g.VIEW, g.BOARD.ID, g.THREADID); Navigate.makeBreadCrumb(window.location, g.VIEW, g.BOARD.ID, g.THREADID);
return $.add(Index.navLinks, Navigate.el); return $.add(Index.navLinks, Navigate.el);
}); });
@ -12674,7 +12659,9 @@
Index.update(); Index.update();
} }
} }
e.preventDefault(); if (e != null) {
e.preventDefault();
}
return; return;
} }
$.addClass(Index.button, 'fa-spin'); $.addClass(Index.button, 'fa-spin');
@ -12682,7 +12669,7 @@
if ('f' === boardID || 'f' === g.BOARD.ID) { if ('f' === boardID || 'f' === g.BOARD.ID) {
return; return;
} }
if (e) { if (e != null) {
e.preventDefault(); e.preventDefault();
} }
if (Index.isSearching) { if (Index.isSearching) {
@ -13645,11 +13632,10 @@
}); });
$.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]); $.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]);
} }
if (!(Conf['JSON Navigation'] && g.VIEW === 'index')) { if (!Conf['JSON Navigation'] || g.VIEW === 'thread') {
Main.initThread(); Main.initThread();
} else {
$.event('4chanXInitFinished');
} }
$.event('4chanXInitFinished');
test = $.el('span'); test = $.el('span');
test.classList.add('a', 'b'); test.classList.add('a', 'b');
if (test.className !== 'a b') { if (test.className !== 'a b') {
@ -13704,7 +13690,6 @@
} }
Thread.callbacks.execute(threads); Thread.callbacks.execute(threads);
Post.callbacks.execute(posts); Post.callbacks.execute(posts);
$.event('4chanXInitFinished');
} }
return $.get('previousversion', null, function(_arg) { return $.get('previousversion', null, function(_arg) {
var changelog, el, previousversion; var changelog, el, previousversion;

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript // Generated by CoffeeScript
/* /*
* 4chan X - Version 1.4.1 - 2014-03-15 * 4chan X - Version 1.4.1 - 2014-03-20
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/Spittie/4chan-x/blob/master/LICENSE * https://github.com/Spittie/4chan-x/blob/master/LICENSE
@ -8468,28 +8468,26 @@
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node); ExpandComment.callbacks.push(this.node);
} }
if (Conf['Title Link']) {
$.sync('CachedTitles', Linkify.titleSync);
}
return Post.callbacks.push({ return Post.callbacks.push({
name: 'Linkify', name: 'Linkify',
cb: this.node cb: this.node
}); });
}, },
node: function() { events: function(post) {
var data, el, end, endNode, i, index, items, length, link, links, node, result, saved, snapshot, space, test, word, _i, _len, _ref; var el, i, items;
if (this.isClone) { i = 0;
if (Conf['Embedding']) { items = $$('.embedder', post.nodes.comment);
i = 0; while (el = items[i++]) {
items = $$('.embed', this.nodes.comment); $.on(el, 'click', Linkify.cb.toggle);
while (el = items[i++]) { if ($.hasClass(el, 'embedded')) {
$.on(el, 'click', Linkify.cb.toggle); Linkify.cb.toggle.call(el);
if ($.hasClass(el, 'embedded')) {
Linkify.cb.toggle.call(el);
}
}
} }
return; }
},
node: function() {
var data, end, endNode, i, index, length, link, links, node, result, saved, snapshot, space, test, word;
if (this.isClone) {
return (Conf['Embedding'] ? Linkify.events(this) : null);
} }
if (!Linkify.regString.test(this.info.comment)) { if (!Linkify.regString.test(this.info.comment)) {
return; return;
@ -8501,7 +8499,7 @@
links = []; links = [];
while (node = snapshot.snapshotItem(i++)) { while (node = snapshot.snapshotItem(i++)) {
data = node.data; data = node.data;
if (node.parentElement.nodeName === "A" || !data) { if (!data || node.parentElement.nodeName === "A") {
continue; continue;
} }
while (result = test.exec(data)) { while (result = test.exec(data)) {
@ -8533,25 +8531,20 @@
} }
} }
} }
_ref = links.reverse(); i = links.length;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { while (i--) {
link = _ref[_i]; link = links[i];
this.nodes.links.push(Linkify.makeLink(link, this)); Linkify.embedProcess(Linkify.makeLink(link, this));
link.detach();
} }
if (!(Conf['Embedding'] || Conf['Link Title'])) { },
return; embedProcess: function(link) {
} var data;
links = this.nodes.links; if (data = Linkify.services(link)) {
i = 0; if (Conf['Embedding']) {
while (link = links[i++]) { Linkify.embed(data);
if (data = Linkify.services(link)) { }
if (Conf['Embedding']) { if (Conf['Link Title']) {
Linkify.embed(data); return Linkify.title(data);
}
if (Conf['Link Title']) {
Linkify.title(data);
}
} }
} }
}, },
@ -8564,7 +8557,7 @@
return range; return range;
}, },
makeLink: function(range) { makeLink: function(range) {
var a, char, i, text; var a, i, t, text;
text = range.toString(); text = range.toString();
i = 0; i = 0;
while (/[(\[{<>]/.test(text.charAt(i))) { while (/[(\[{<>]/.test(text.charAt(i))) {
@ -8580,8 +8573,8 @@
} }
} }
i = 0; i = 0;
while (/[)\]}>.,]/.test(char = text.charAt(text.length - (1 + i)))) { while (/[)\]}>.,]/.test(t = text.charAt(text.length - (1 + i)))) {
if (!(/[.,]/.test(char) || (text.match(/[()\[\]{}<>]/g)).length % 2)) { if (!(/[.,]/.test(t) || (text.match(/[()\[\]{}<>]/g)).length % 2)) {
break; break;
} }
i++; i++;
@ -8606,6 +8599,7 @@
}); });
$.add(a, range.extractContents()); $.add(a, range.extractContents());
range.insertNode(a); range.insertNode(a);
range.detach();
return a; return a;
}, },
services: function(link) { services: function(link) {
@ -8614,10 +8608,9 @@
_ref = Linkify.types; _ref = Linkify.types;
for (key in _ref) { for (key in _ref) {
type = _ref[key]; type = _ref[key];
if (!(match = type.regExp.exec(href))) { if (match = type.regExp.exec(href)) {
continue; return [key, match[1], match[2], link];
} }
return [key, match[1], match[2], link];
} }
}, },
embed: function(data) { embed: function(data) {
@ -8646,7 +8639,7 @@
if (Conf['Auto-embed']) { if (Conf['Auto-embed']) {
Linkify.cb.toggle.call(embed); Linkify.cb.toggle.call(embed);
} }
data.push(embed); return data.push(embed);
}, },
title: function(data) { title: function(data) {
var embed, err, key, link, options, service, title, titles, uid; var embed, err, key, link, options, service, title, titles, uid;
@ -8664,9 +8657,9 @@
} }
} else { } else {
try { try {
$.cache(service.api(uid), function() { return $.cache(service.api(uid), (function() {
return title = Linkify.cb.title(this, data); return Linkify.cb.title(this, data);
}, { }), {
responseType: 'json' responseType: 'json'
}); });
} catch (_error) { } catch (_error) {
@ -8674,17 +8667,9 @@
if (link) { if (link) {
link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"; link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>";
} }
return;
}
if (title) {
titles[uid] = [title, Date.now()];
return $.set('CachedTitles', titles);
} }
} }
}, },
titleSync: function(value) {
return Conf['CachedTitles'] = value;
},
cb: { cb: {
toggle: function() { toggle: function() {
var string, _ref; var string, _ref;
@ -8710,26 +8695,26 @@
$.addClass(el, a.dataset.key); $.addClass(el, a.dataset.key);
return el; return el;
}, },
title: function(response, data) { title: function(req, data) {
var embed, key, link, options, service, text, uid; var embed, key, link, options, service, status, text, uid;
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4]; key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4];
status = req.status;
service = Linkify.types[key].title; service = Linkify.types[key].title;
switch (response.status) { text = "[" + key + "] " + ((function() {
case 200: switch (status) {
case 304: case 200:
text = "" + (service.text(response.response)); case 304:
if (Conf['Embedding']) { return service.text(req.response);
embed.dataset.title = text; case 404:
} return "Not Found";
break; case 403:
case 404: return "Forbidden or Private";
text = "[" + key + "] Not Found"; default:
break; return "" + status + "'d";
case 403: }
text = "[" + key + "] Forbidden or Private"; })());
break; if (Conf['Embedding'] && (status === 200 || status === 304)) {
default: embed.dataset.title = text;
text = "[" + key + "] " + this.status + "'d";
} }
if (link) { if (link) {
return link.textContent = text; return link.textContent = text;
@ -12471,11 +12456,16 @@
Navigate = { Navigate = {
path: window.location.pathname, path: window.location.pathname,
init: function() { init: function() {
var popstateHack;
if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) { if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) {
return; return;
} }
popstateHack = function() {
$.off(window, 'popstate', popstateHack);
return $.on(window, 'popstate', Navigate.popstate);
};
$.on(window, 'popstate', popstateHack);
$.ready(function() { $.ready(function() {
$.on(window, 'popstate', Navigate.popstate);
Navigate.makeBreadCrumb(window.location, g.VIEW, g.BOARD.ID, g.THREADID); Navigate.makeBreadCrumb(window.location, g.VIEW, g.BOARD.ID, g.THREADID);
return $.add(Index.navLinks, Navigate.el); return $.add(Index.navLinks, Navigate.el);
}); });
@ -12688,7 +12678,9 @@
Index.update(); Index.update();
} }
} }
e.preventDefault(); if (e != null) {
e.preventDefault();
}
return; return;
} }
$.addClass(Index.button, 'fa-spin'); $.addClass(Index.button, 'fa-spin');
@ -12696,7 +12688,7 @@
if ('f' === boardID || 'f' === g.BOARD.ID) { if ('f' === boardID || 'f' === g.BOARD.ID) {
return; return;
} }
if (e) { if (e != null) {
e.preventDefault(); e.preventDefault();
} }
if (Index.isSearching) { if (Index.isSearching) {
@ -13657,11 +13649,10 @@
}); });
$.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]); $.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]);
} }
if (!(Conf['JSON Navigation'] && g.VIEW === 'index')) { if (!Conf['JSON Navigation'] || g.VIEW === 'thread') {
Main.initThread(); Main.initThread();
} else {
$.event('4chanXInitFinished');
} }
$.event('4chanXInitFinished');
try { try {
return localStorage.getItem('4chan-settings'); return localStorage.getItem('4chan-settings');
} catch (_error) { } catch (_error) {
@ -13701,7 +13692,6 @@
} }
Thread.callbacks.execute(threads); Thread.callbacks.execute(threads);
Post.callbacks.execute(posts); Post.callbacks.execute(posts);
$.event('4chanXInitFinished');
} }
return $.get('previousversion', null, function(_arg) { return $.get('previousversion', null, function(_arg) {
var changelog, el, previousversion; var changelog, el, previousversion;

View File

@ -187,10 +187,10 @@ Main =
$.before styleSelector.previousSibling, [$.tn '['; passLink, $.tn ']\u00A0\u00A0'] $.before styleSelector.previousSibling, [$.tn '['; passLink, $.tn ']\u00A0\u00A0']
# Parse HTML or skip it and start building from JSON. # Parse HTML or skip it and start building from JSON.
unless Conf['JSON Navigation'] and g.VIEW is 'index' if !Conf['JSON Navigation'] or g.VIEW is 'thread'
Main.initThread() Main.initThread()
else
$.event '4chanXInitFinished' $.event '4chanXInitFinished'
<% if (type === 'userscript') { %> <% if (type === 'userscript') { %>
test = $.el 'span' test = $.el 'span'
@ -233,8 +233,6 @@ Main =
Thread.callbacks.execute threads Thread.callbacks.execute threads
Post.callbacks.execute posts Post.callbacks.execute posts
$.event '4chanXInitFinished'
$.get 'previousversion', null, ({previousversion}) -> $.get 'previousversion', null, ({previousversion}) ->
return if previousversion is g.VERSION return if previousversion is g.VERSION
if previousversion if previousversion

View File

@ -3,9 +3,18 @@ Navigate =
init: -> init: ->
return if g.BOARD.ID is 'f' or !Conf['JSON Navigation'] return if g.BOARD.ID is 'f' or !Conf['JSON Navigation']
<% if (type === 'crx') { %>
# blink/webkit throw a popstate on page load. Not what we want.
popstateHack = ->
$.off window, 'popstate', popstateHack
$.on window, 'popstate', Navigate.popstate
$.on window, 'popstate', popstateHack
<% } else { %>
$.on window, 'popstate', Navigate.popstate
<% } %>
$.ready -> $.ready ->
# blink/webkit throw a popstate on page load. Not what we want.
$.on window, 'popstate', Navigate.popstate
Navigate.makeBreadCrumb window.location, g.VIEW, g.BOARD.ID, g.THREADID Navigate.makeBreadCrumb window.location, g.VIEW, g.BOARD.ID, g.THREADID
$.add Index.navLinks, Navigate.el $.add Index.navLinks, Navigate.el
@ -173,8 +182,7 @@ Navigate =
navigate: (e) -> navigate: (e) ->
return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org' return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org'
if e if e
if e.shiftKey or e.ctrlKey or (e.type is 'click' and e.button isnt 0) # Not simply a left click return if e.shiftKey or e.ctrlKey or (e.type is 'click' and e.button isnt 0) # Not simply a left click
return
if @pathname is Navigate.path if @pathname is Navigate.path
if g.VIEW is 'thread' if g.VIEW is 'thread'
@ -182,7 +190,7 @@ Navigate =
else else
unless Index.searchTest() unless Index.searchTest()
Index.update() Index.update()
e.preventDefault() e?.preventDefault()
return return
$.addClass Index.button, 'fa-spin' $.addClass Index.button, 'fa-spin'
@ -190,7 +198,7 @@ Navigate =
[_, boardID, view, threadID] = @pathname.split '/' [_, boardID, view, threadID] = @pathname.split '/'
return if 'f' in [boardID, g.BOARD.ID] return if 'f' in [boardID, g.BOARD.ID]
e.preventDefault() if e e?.preventDefault()
Index.clearSearch() if Index.isSearching Index.clearSearch() if Index.isSearching
Navigate.title = -> return Navigate.title = -> return

View File

@ -5,35 +5,30 @@ Linkify =
if Conf['Comment Expansion'] if Conf['Comment Expansion']
ExpandComment.callbacks.push @node ExpandComment.callbacks.push @node
if Conf['Title Link']
$.sync 'CachedTitles', Linkify.titleSync
Post.callbacks.push Post.callbacks.push
name: 'Linkify' name: 'Linkify'
cb: @node cb: @node
events: (post) ->
i = 0
items = $$ '.embedder', post.nodes.comment
while el = items[i++]
$.on el, 'click', Linkify.cb.toggle
Linkify.cb.toggle.call el if $.hasClass el, 'embedded'
return
node: -> node: ->
if @isClone return (if Conf['Embedding'] then Linkify.events @ else null) if @isClone
if Conf['Embedding']
i = 0
items = $$ '.embed', @nodes.comment
while el = items[i++]
$.on el, 'click', Linkify.cb.toggle
Linkify.cb.toggle.call el if $.hasClass el, 'embedded'
return
return unless Linkify.regString.test @info.comment return unless Linkify.regString.test @info.comment
test = /[^\s'"]+/g test = /[^\s'"]+/g
space = /[\s'"]/ space = /[\s'"]/
snapshot = $.X './/br|.//text()', @nodes.comment snapshot = $.X './/br|.//text()', @nodes.comment
i = 0 i = 0
links = [] links = []
while node = snapshot.snapshotItem i++ while node = snapshot.snapshotItem i++
{data} = node {data} = node
continue if node.parentElement.nodeName is "A" or not data continue if !data or node.parentElement.nodeName is "A"
while result = test.exec data while result = test.exec data
{index} = result {index} = result
@ -58,41 +53,33 @@ Linkify =
i-- i--
break break
if Linkify.regString.exec word links.push Linkify.makeRange node, endNode, index, length if Linkify.regString.exec word
links.push Linkify.makeRange node, endNode, index, length
break unless test.lastIndex and node is endNode break unless test.lastIndex and node is endNode
for link in links.reverse() i = links.length
@nodes.links.push Linkify.makeLink link, @ while i--
link.detach() link = links[i]
Linkify.embedProcess Linkify.makeLink link, @
return unless Conf['Embedding'] or Conf['Link Title']
{links} = @nodes
i = 0
while link = links[i++]
if data = Linkify.services link
Linkify.embed data if Conf['Embedding']
Linkify.title data if Conf['Link Title']
return return
embedProcess: (link) ->
if data = Linkify.services link
Linkify.embed data if Conf['Embedding']
Linkify.title data if Conf['Link Title']
regString: ///( regString: ///(
# http, magnet, ftp, etc # http, magnet, ftp, etc
(https?|mailto|git|magnet|ftp|irc):( (https?|mailto|git|magnet|ftp|irc):(
[a-z\d%/] [a-z\d%/]
) )
| | # This should account for virtually all links posted without http:
# This should account for virtually all links posted without http:
[-a-z\d]+[.]( [-a-z\d]+[.](
aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2} aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2}
)(/|(?!.)) )(/|(?!.))
| | # IPv4 Addresses
# IPv4 Addresses
[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3} [\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}
| | # E-mails
# E-mails
[-\w\d.@]+@[a-z\d.-]+\.[a-z\d] [-\w\d.@]+@[a-z\d.-]+\.[a-z\d]
)///i )///i
@ -105,7 +92,7 @@ Linkify =
makeLink: (range) -> makeLink: (range) ->
text = range.toString() text = range.toString()
# Clean leading brackets, > # Clean start of range
i = 0 i = 0
i++ while /[(\[{<>]/.test text.charAt i i++ while /[(\[{<>]/.test text.charAt i
@ -115,10 +102,10 @@ Linkify =
range.setStart range.startContainer, range.startOffset + i if i range.setStart range.startContainer, range.startOffset + i if i
# Clean hanging brackets, commas, periods # Clean end of range
i = 0 i = 0
while /[)\]}>.,]/.test char = text.charAt text.length - (1 + i) while /[)\]}>.,]/.test t = text.charAt text.length - (1 + i)
break unless /[.,]/.test(char) or (text.match /[()\[\]{}<>]/g).length % 2 break unless /[.,]/.test(t) or (text.match /[()\[\]{}<>]/g).length % 2
i++ i++
if i if i
@ -128,6 +115,7 @@ Linkify =
if i if i
range.setEnd range.endContainer, range.endOffset - i range.setEnd range.endContainer, range.endOffset - i
# Make our link 'valid' if it is formatted incorrectly.
unless /(https?|mailto|git|magnet|ftp|irc):/.test text unless /(https?|mailto|git|magnet|ftp|irc):/.test text
text = ( text = (
if /@/.test text if /@/.test text
@ -141,15 +129,17 @@ Linkify =
rel: 'nofollow noreferrer' rel: 'nofollow noreferrer'
target: '_blank' target: '_blank'
href: text href: text
# Insert the range into the anchor, the anchor into the range's DOM location, and destroy the range.
$.add a, range.extractContents() $.add a, range.extractContents()
range.insertNode a range.insertNode a
range.detach()
a a
services: (link) -> services: (link) ->
href = link.href {href} = link
for key, type of Linkify.types when match = type.regExp.exec href
for key, type of Linkify.types
continue unless match = type.regExp.exec href
return [key, match[1], match[2], link] return [key, match[1], match[2], link]
return return
@ -161,9 +151,7 @@ Linkify =
href: 'javascript:;' href: 'javascript:;'
textContent: '(embed)' textContent: '(embed)'
for name, value of {key, href, uid, options} embed.dataset[name] = value for name, value of {key, href, uid, options}
embed.dataset[name] = value
embed.dataset.nodedata = link.innerHTML embed.dataset.nodedata = link.innerHTML
$.addClass link, "#{embed.dataset.key}" $.addClass link, "#{embed.dataset.key}"
@ -171,13 +159,10 @@ Linkify =
$.on embed, 'click', Linkify.cb.toggle $.on embed, 'click', Linkify.cb.toggle
$.after link, [$.tn(' '), embed] $.after link, [$.tn(' '), embed]
if Conf['Auto-embed'] Linkify.cb.toggle.call embed if Conf['Auto-embed']
Linkify.cb.toggle.call embed
data.push embed data.push embed
return
title: (data) -> title: (data) ->
[key, uid, options, link, embed] = data [key, uid, options, link, embed] = data
return unless service = Linkify.types[key].title return unless service = Linkify.types[key].title
@ -190,20 +175,11 @@ Linkify =
embed.dataset.title = title[0] embed.dataset.title = title[0]
else else
try try
$.cache service.api(uid), $.cache service.api(uid), (-> Linkify.cb.title @, data), responseType: 'json'
-> title = Linkify.cb.title @, data
,
responseType: 'json'
catch err catch err
if link if link
link.innerHTML = "[#{key}] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>" link.innerHTML = "[#{key}] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"
return return
if title
titles[uid] = [title, Date.now()]
$.set 'CachedTitles', titles
titleSync: (value) ->
Conf['CachedTitles'] = value
cb: cb:
toggle: -> toggle: ->
@ -239,21 +215,24 @@ Linkify =
return el return el
title: (response, data) -> title: (req, data) ->
[key, uid, options, link, embed] = data [key, uid, options, link, embed] = data
{status} = req
service = Linkify.types[key].title service = Linkify.types[key].title
switch response.status
text = "[#{key}] #{switch status
when 200, 304 when 200, 304
text = "#{service.text response.response}" service.text req.response
if Conf['Embedding']
embed.dataset.title = text
when 404 when 404
text = "[#{key}] Not Found" "Not Found"
when 403 when 403
text = "[#{key}] Forbidden or Private" "Forbidden or Private"
else else
text = "[#{key}] #{@status}'d" "#{status}'d"
link.textContent = text if link }"
embed.dataset.title = text if Conf['Embedding'] and status in [200, 304]
link.textContent = text if link
types: types:
audio: audio: