Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)
// This JavaScript file is automatically generated by js-tool.
// Do NOT read it! Do NOT edit it! Edit the source code instead.
// LJ Inline Expander 0.2.10 (beta) 2008-03-03
// ------------------------------------------
// Copyright (c) 2007-2008 Ilya Dogolazky
// Released under the GPL license, see http://www.gnu.org/copyleft/gpl.html for details
// ------------------------------------------
// ==UserScript==
// @name LJ Inline Expander
// @namespace http://www.math.uni-bonn.de/people/ilyad/lj/expander
// @description Makes it possible to open lj-cuts, read comments, and unfold the comments threads directly on the friends list page.
// @include http://*.livejournal.com/*
// ==/UserScript==
// use Dumper ; // This module can not be redistributed :-(
function Dumper(a) {return a;}
// File Debug.js
Debug.level = function(l) // 0:nothing, 1:errors only 2: errors and warnings 3:all messages
{
Debug.current_level = l ;
}
// oops! GM_log accepts only one parameter!
// http://wiki.greasespot.net/index.php?title=GM_log&diff=1764&oldid=1762 :-(
Debug.gm = function(level, cl, msg)
{
if(cl>level)
{
var ar = [] ;
for(var i=0; i<msg.length; ++i)
ar.push(msg[i]) ;
GM_log(ar.join(""), 2-level) ;
}
}
Debug.level(3) ;
Debug.log = function() { Debug.gm(2, Debug.current_level, arguments) ; }
Debug.warn = function() { Debug.gm(1, Debug.current_level, arguments) ; }
Debug.error = function() { Debug.gm(0, Debug.current_level, arguments) ; }
Debug.prototype.log = function() { this.log_member(2, arguments) ; }
Debug.prototype.warn = function() { this.log_member(1, arguments) ; }
Debug.prototype.error = function() { this.log_member(0, arguments) ; }
Debug.prototype.log_member = function(level, msg)
{
Debug.gm(level, this.enabled(), msg) ;
}
Debug.prototype.enabled = function()
{
if(this.absolute)
return this.current_level ;
else
return Math.min(this.current_level, Debug.current_level) ;
}
function Debug(level)
{
this.absolute = (level<0) ;
if(this.absolute)
level = -level ;
this.current_level = level ;
}
// vim:tw=0:smartindent
// End of file Debug.js
// File Dialog.js
// use Debug: already included
Dialog.list = {} ;
Dialog.register = function(attr, init_cb, handler_cb)
{
if(Dialog.list[attr]!=null)
Debug.error("Dialog '", attr, "' already exists") ;
Dialog.list[attr] = new Dialog(attr, init_cb, handler_cb) ;
return Dialog.list[attr] ;
}
Dialog.prototype.display = function()
{
// weird bug?
try
{
var by_attr = Xpath.aNode([this.attr,"iframe"]) ;
}
catch(e)
{
Debug.error("oops! can't call Xpath.aNode([", this.attr, "])") ;
}
if(this.ifrm!=by_attr)
{
Debug.warning("by_attr != this.ifrm, fixing...") ;
this.ifrm = by_attr ;
}
if(this.ifrm.visibility=="visible")
return ;
this.init(this) ;
this.form.innerHTML = this.html ;
for each(var button in Xpath.aList([this.actn,"*"], this.form))
button.addEventListener("click", this, false) ;
this.ifrm.style.visibility = "visible" ;
}
Dialog.prototype.hide = function()
{
if(this.ifrm.style.visibility=="hidden")
return ;
this.ifrm.style.visibility="hidden" ;
this.form.innerHTML = this.html = "" ;
}
Dialog.prototype.checkbox = function(o_name, label)
{
var checked = (GM_getValue(o_name)=="yes") ? "checked" : null ;
return this.tag("label") +
this.tag("input", [this.gmvl,o_name, "type","checkbox", checked,null]) +
label +
this.tag("/label") ;
}
Dialog.prototype.radio = function(o_name, value, label)
{
var checked = (GM_getValue(o_name)==value) ? "checked" : null ;
if(label==null) label = value ;
return this.tag("label") +
this.tag("input", [this.gmvl,o_name, "name",o_name, "type","radio", "value",value, checked,null]) +
label +
this.tag("/label") ;
}
Dialog.prototype.text = function(o_name, cols, rows)
{
if(rows==null) rows = 1 ;
if(cols==null) cols = 2 ;
return (rows==1) ? this.textLine(o_name, cols) : this.textArea(o_name, cols, rows) ;
}
Dialog.prototype.button = function(text, action)
{
return this.tag("input", [this.actn,action, "type","button", "value",text]) ;
}
Dialog.prototype.textArea = function(o_name, cols, rows) // private member, don't use it :-)
{
return this.tag("textarea",[this.gmvl,o_name, "rows",rows, "cols",cols]) +
GM_getValue(o_name) +
this.tag("/textarea") ;
}
Dialog.prototype.textLine = function(o_name, cols) // private member, don't use it :-)
{
var old_value = GM_getValue(o_name) ;
return this.tag("input",[this.gmvl,o_name, "type","text", "cols",cols, "value",old_value]) ;
}
Dialog.prototype.attrList = function(arg) // private member, don't use it :-)
{
var res = "" ;
while(arg.length)
{
var key = arg.shift() ;
var value = arg.shift() ;
if(key==null) continue ;
res += ' ' + key ;
if(value!=null)
res += '="' + value + '"'
res += ' ' ;
}
return res ;
}
Dialog.prototype.tag = function(name, arg) // private member, don't use it :-)
{
if(arg==null) arg=[] ;
return "<" + name.toUpperCase() + " " + this.attrList(arg) + ">" ;
} ;
Dialog.prototype.gm_save = function()
{
for each(var ctl in Xpath.aList([this.gmvl], this.form))
{
var tag = ctl.nodeName.toLowerCase() ;
if(tag=="input" && ctl.type=="checkbox")
GM_setValue(ctl.getAttribute(this.gmvl), (ctl.checked)?"yes":"no") ;
else if(tag=="input" && ctl.type=="radio")
{
if(ctl.checked)
GM_setValue(ctl.getAttribute(this.gmvl), ctl.value+"") ;
}
else if((tag=="input" && ctl.type=="text") || tag=="textarea")
GM_setValue(ctl.getAttribute(this.gmvl), ctl.value) ;
else
alert("Unknown input element: tag=" + tag + " value=" + ctl.value + " type=" + ctl.type) ;
}
}
Dialog.prototype.handleEvent = function(event)
{
var button = event.currentTarget ;
var res = this.hdlr(this, button.getAttribute(this.actn), event) ;
if(res)
this.hide() ;
}
Dialog.show = function(attr, flag)
{
if(!Dialog.list[attr])
alert("Dialog '"+attr+"' doesn't exist") ;
if(flag)
Dialog.list[attr].display(attr) ;
else
Dialog.list[attr].hide(attr) ;
} ;
function Dialog(attr, init_cb, handler_cb)
{
this.attr = attr ;
this.init = init_cb ;
this.hdlr = handler_cb ;
this.actn = attr + '-action' ;
this.gmvl = attr + '-gmvlue' ;
this.form = null ;
this.box = null ;
this.html = "" ; // it's a public member
this.ifrm = document.createElement("iframe") ;
this.ifrm.style.visibility="hidden" ;
Debug.log("irfame created") ;
this.box = document.createElement("div") ;
this.form = document.createElement("form") ;
var that = this ;
this.ifrm.addEventListener("load", function() {
this.contentDocument.body.innerHTML = '<p style="visibility: hidden;">Empty page (about:blank)</p>' ;
Debug.log("about:blank loaded") ;
this.contentDocument.body.insertBefore(that.box, null) ;
Debug.log("box inserted") ;
this.contentDocument.body.insertBefore(that.form, null) ;
Debug.log("form inserted") ;
}, false);
this.ifrm.src = "about:blank" ;
document.body.appendChild(this.ifrm) ;
this.ifrm.style.position="fixed" ;
this.ifrm.style.zIndex = 239 ;
this.ifrm.style.top = "0%" ;
this.ifrm.style.left = "0%" ;
this.ifrm.style.right = "0%" ;
this.ifrm.style.bottom = "0%" ;
this.ifrm.style.border = "0px solid" ;
this.ifrm.setAttribute(this.attr, "iframe") ;
this.box.style.position = "absolute" ;
this.box.style.background = "black" ;
this.box.style.top = "0%" ;
this.box.style.left = "0%" ;
this.box.style.right = "0%" ;
this.box.style.bottom = "0%" ;
this.box.style.border = "solid 0px" ;
this.box.style.MozOpacity = "0.2" ;
this.box.style.opacity = "0.2" ; // CSS-3 ready!
this.form.style.position = "absolute" ;
this.form.style.overflow = "auto" ;
this.form.style.background = "wheat" ;
this.form.style.top = "3%" ;
this.form.style.left = "3%" ;
this.form.style.right = "3%" ;
this.form.style.bottom = "3%" ;
this.form.style.border = "double 3px" ;
this.form.style.padding = "4px" ;
}
Dialog.prototype.style = function()
{
return this.form.style ;
}
// vim:tw=0:smartindent
// End of file Dialog.js
// File Dom.js
// given two elements 'a' and 'b'; and a common major 'top'
// (it means a<=top and b<=top)
// find minimal common major (supremum):
// sup = min{x|a<=x, b<=x}
function sup(a,b,top)
{
var pa=path_to_ancestor(a,top), pb=path_to_ancestor(b,top) ;
// GM_log("pa="+pa+" pb="+pb) ;
var last_eq ;
while(pa.length>0 && pb.length>0 && pa[0]==pb[0])
{
last_eq = pa[0] ;
pa.shift() ;
pb.shift() ;
}
return last_eq ;
}
function path_to_ancestor(a, top)
{
var res = [] ;
while(a!=top)
{
// GM_log("a="+a+" top"+top) ;
res.unshift(a) ;
a = a.parentNode ;
}
res.unshift(top) ;
return res ;
}
function is_descendant(that, node)
{
for(var x=that; x; x=x.parentNode)
if(x==node)
return true ;
return false ;
}
function nbsp_html(count)
{
if(count==null)
count = 1 ;
html = "" ;
for(var i=0; i<count; ++i)
html += " " ;
return html ;
}
function nbsp_node(count)
{
var span = document.createElement("span") ;
span.innerHTML = nbsp_html(count) ;
return span ;
}
// End of file Dom.js
// File GM_huge.js
GM_huge.setValue = function (option, value)
{
GM_setValue(option, "xxx"+value) ;
}
GM_huge.getValue =function (option)
{
var v = GM_getValue(option) ;
if(v==null)
return null ;
return v.match(/^xxx(.*)/) [1] ;
}
function GM_huge()
{
}
// End of file GM_huge.js
// File Lj.js
// use Debug: already included
// File Xpath.js
Xpath.list = function(xpath, root, order)
{
if(!root)
root = window.document ;
var result = [] ;
var snapshot = document.evaluate(xpath, root, null, (order ? XPathResult.ORDERED_NODE_SNAPSHOT_TYPE : XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE), null) ;
for(var i=0; i<snapshot.snapshotLength; ++i)
result.push(snapshot.snapshotItem(i)) ;
return result ;
}
Xpath.node = function(xpath, root)
{
return Xpath.list(xpath, root, false)[0] ;
}
Xpath.aNode = function (hash, root)
{
var list = Xpath.aList(hash, root) ;
if(list.length==0)
return null ;
if(list.length>1)
GM_log("Multiply nodes found in Xpath.aNode("+hash+")") ;
return list[0] ;
}
Xpath.aList = function(list, root, order)
{
var xpath = Xpath.aXpath(list) ;
return Xpath.list(xpath, root, order) ;
}
Xpath.aXpath = function (list)
{
var s = [] ;
while(list.length>0)
{
var key = list.shift() ;
var value = list.shift() ;
var at = "@" + key ;
s.push((value==null || value=="*") ? at : at+"='" + value + "'") ;
}
return "descendant::*["+s.join(" and ")+"]" ;
}
function Xpath()
{}
// End of file Xpath.js
// File Uri.js
function Uri(str)
{
var t = str.match(/^(.*?)#(.*)$/) ;
if(t)
{
str = t[1] ;
this.fragment = t[2] ;
}
this.location = str ;
t = str.match(/^(.*?)\?(.*)$/) ;
if(t)
{
str = t[1] ;
var q = t[2] ;
}
this.path = str ;
this.query = new Object ;
if(q)
{
for each(var qq in q.split('&'))
{
var i = qq.search("=") ;
if(i==-1)
{
var key = qq ;
var value = undefined
}
else
{
var key = qq.substr(0,i) ;
var value = qq.substr(i+1) ;
}
this.query[key] = value ;
}
}
}
Uri.prototype.originalLocation = function()
{
return this.location ;
}
Uri.prototype.toString = function()
{
var res = this.path ;
var qq = [] ;
for(var key in this.query)
{
var q = key+'' ;
var value = this.query[key] ;
if(value!=undefined)
q += '=' + value ;
qq.push(q)
}
if(qq.length)
res += "?" + qq.join("&") ;
if(this.fragment)
res += "#" + this.fragment ;
return res ;
}
if(new Debug(0).enabled())
{
var u = new Uri(window.location.toString()) ;
alert(Dumper(u)+"\n----\n"+u.toString()) ;
}
// End of file Uri.js
// Searches for the LJ entry containing given document node
function find_lj_entry(node)
{
const xp_list =
[
'ancestor::*[@class="post"]',
'ancestor::*[@class="entry"]',
'ancestor::*[@class="entrybox"]',
'ancestor::*[@class="entryHolder"]',
'ancestor::*[@class="comment_wrapper"]',
'ancestor::*[name()="DIV" or name()="TD"][1]'
] ;
for each(xp in xp_list)
{
var entry = Xpath.list(xp, node, true) ;
if(entry.length==0)
continue ;
if(entry.length>1)
GM_log("Oops, many entry nodes found in "+xp) ;
return entry[0] ;
}
return null ;
}
// Searches for the comments document node of given LJ entry
function find_lj_comments(entry)
{
const comments_xpath = 'descendant::*[@class="comments" or @class="entry-footer"]' ;
var comments_node = Xpath.node(comments_xpath, entry);
return comments_node ;
}
function parent_of_cut(link)
{
if(link==null || !link.href.match(/#cutid\d+$/))
return null ;
var parent=link.parentNode ;
if(!parent)
return null ;
if(parent.nodeName.toUpperCase()!="B")
return null ;
if(!parent.innerHTML.match(/^\(/))
return null ;
if(!parent.innerHTML.match(/\)$/))
return null ;
return parent ;
}
function count_comments_pages(text)
{
var page = document.createElement('span') ;
page.innerHTML = text ;
var max_x = 0 ;
const links_xpath = 'descendant::a[@href]' ;
var links = document.evaluate(links_xpath,page,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null) ;
// GM_log("links.snapshotLength="+links.snapshotLength+" length(text)="+text.length) ;
for(var i=0; i<links.snapshotLength; ++i)
{
var href = links.snapshotItem(i).href ;
var re = '/\\d+\\.html\\?format=light\\&page=(\\d+)#comments$' ;
var a = href.match(re) ;
if(a && links.snapshotItem(i).innerHTML=="["+a[1]+"]")
{
// GM_log(href+"..."+a+"-----"+(a?a[1]:"noprop")+links.snapshotItem(i).innerHTML) ;
var x = a[1]-0 ; // I hope, "-0" will cause converting to int
if(max_x<x)
max_x=x ;
}
}
// GM_log("max_x="+max_x)
return max_x ;
}
// Extracts journal's name and the entry id from the entry URL
Lj.extract_id = function(url)
{
var reg_exps = [
"^http://community.[^/]+/([^/]+)/(\\d+)\\.html$",
"^http://syndicated.[^/]+/([^/]+)/(\\d+)\\.html$",
"^http://users.[^/]+/([^/]+)/(\\d+)\\.html$",
"^http://[^/]+/users/([^/]+)/(\\d+)\\.html$",
"^http://[^/]+/community/([^/]+)/(\\d+)\\.html$",
"^http://(.*?)\\.[^/]+/(\\d+)\\.html$"
] ;
for each(var re in reg_exps)
{
var a = url.match(re) ;
if(a)
return a ;
}
}
function find_all_entries()
{
if(GM_getValue(UO_ADD_TO_ENTRIES)!="yes")
return ;
var comment_boxes_xp = 'descendant::*[@class="comments" or @class="entry-footer" or @class="entrylinks" or @class="asset-meta" or @class="Comment" or @class="short_entry" or @class="full_entry" or @class="index"]' ;
for each(var that in Xpath.list(comment_boxes_xp))
{
// var that = cn[i] ;
var entry = find_lj_entry(that) ;
var links = Xpath.list("descendant::*[@href]", that, true) ;
// UGLY HACK :-( needed for some weird styles, like that of ru-linux.livejournal.com
if(that.nodeName.toUpperCase()=="A" && that.href && that.getAttribute("class")=="comments")
links.push(that) ;
var found = false ;
for(var j=0; !found && j<links.length; ++j)
{
var link = links[j] ;
var entry_url = extract_entry_url(link.href) ;
if(entry_url)
{
found = true ;
var cntrl = create_control(V_COMMENTS, entry_url, 0) ;
var ancestor = link.parentNode ;
ancestor.insertBefore(nbsp_node(), link) ;
ancestor.insertBefore(cntrl, link) ;
// var bebe = new Bebe() ;
// ancestor.insertBefore(bebe.node(), link) ;
// bebe.e.addEventListener("click", bebe, false) ;
var span = document.createElement('span') ;
span.innerHTML = nbsp_html() + "|" + nbsp_html() ;
ancestor.insertBefore(span, link) ;
// GM_log("entry: "+entry.nodeName.toUpperCase()+entry.innerHTML) ;
// GM_log("that : "+that .nodeName.toUpperCase()+ that.innerHTML) ;
var anchor ;
if(entry.parentNode.nodeName.toUpperCase()=="TR")
var anchor = that ;
else if(entry.parentNode.nodeName.toUpperCase()=="DIV")
var anchor = entry ;
else if(entry.parentNode.nodeName.toUpperCase()=="P")
var anchor = entry ;
else
document.body.innerHTML = "<b>Ooops: entry.parentNode is a "+entry.parentNode.nodeName+"<br/>entry_url="+entry_url+"</b>" ;
anchor.setAttribute(A_ANCHOR, 'yes') ;
anchor.setAttribute(A_URL, entry_url) ;
anchor.setAttribute(A_CUT, 0) ;
update_state(V_NOBOX, entry_url, 0) ;
var x=new Debug(0) ;
if(x.enabled())
{
anchor.style.background = "blue" ; // debugging
entry.style.background = "yellow" ;
that.style.background = "green" ;
var boxik = document.createElement("blockquote") ;
boxik.style.padding = "20px" ;
boxik.style.border = "1px solid rgb(255,0,255)" ;
boxik.innerHTML = "<b>ai karamba: "+entry.parentNode.nodeName+"<BR>"+entry_url+"</b>" ;
anchor.parentNode.insertBefore(boxik, anchor.nextSibling) ;
}
}
}
}
}
Lj.colorize = function()
{
var found = false ;
Debug.log("colorize") ;
for each(var st in Lj.styles)
{
for each(var entry in Xpath.list(st.entryXpath))
{
found = true ;
var user = Xpath.node(st.userXpath, entry) ;
var text = Xpath.node(st.textXpath, entry) ;
var tags = Xpath.list(st.tagXpath, entry) ;
if(text) text.style.background = "green" ;
if(user) user.parentNode.style.background = "red" ;
if(tags.length) for each(var t in tags) t.parentNode.style.background = "blue" ;
Debug.log(user, text, tags) ;
entry.style.background = "wheat" ;
}
if(found)
{
Debug.log("Style found! ", st.name) ;
break ;
}
}
}
Lj.styles = [
// Nautical Generator - checked (dimrub)
{
name: 'Nautical Generator',
entryXpath: '//table[@class=\'entrybox\']',
userXpath: './/a[@class = \"index\"]//font/text()',
tagXpath: './/a[@rel=\'tag\']/text()',
textXpath: './/td[@bgcolor="#ffffff"]',
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry.nextSibling);
remember(par, entry);
}
},
// Punquin Elegant
{
name: 'Punquin Elegant',
entryXpath: '//table[@class=\'entry\']',
userXpath: './/a[1]/text()',
tagXpath: './/a[@rel=\'tag\']/text()',
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry.nextSibling);
remember(par, entry);
}
},
// Martial Blue - checked (lev_m)
{
name: 'Martial Blue',
entryXpath: "//div[@class='box']",
userXpath: ".//span[@class = 'ljuser']/a[2]/text()",
tagXpath: ".//div[@class='ljtags']//a[@rel=\'tag\']/text()",
textXpath: "./div[@class='entry']",
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry);
}
},
// A Sturdy Gesture
{
name: 'A Sturdy Gesture',
entryXpath: "//div[@class='box']",
userXpath: ".//div[@class='entry']//a[2]/text()",
tagXpath: ".//div[@class='entry']//a[@rel=\'tag\']/text()",
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry);
}
},
// Smooth Sailing - checked (annyway)
{
name: 'Smooth Sailing',
entryXpath: "//div[@class='entryHolder']",
userXpath: ".//span[@class='ljuser']//b/text()",
tagXpath: ".//span[@class='entryMetadata-content']/a[contains(@href, 'tag')]/text()",
textXpath: ".//div[@class='entryText']",
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry);
}
},
// Unearthed - checked (zhuzh)
{
name: 'Unearthed',
entryXpath: "//table[@class='DropShadow']",
userXpath: ".//span[@class='ljuser']//b/text()",
tagXpath: ".//div[@class='ljtags']/a[contains(@href, 'tag')]/text()",
textXpath: ".//td[@class='BoxContents']",
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry);
}
},
// Flexible Squares - checked (sciuro)
{
name: 'Flexible Squares',
entryXpath: "//div[@class='subcontent']",
userXpath: ".//div[@class='userpicfriends']//a/font/text()",
tagXpath: ".//a[@rel='tag']/text()",
textXpath: ".//div[@class='entry_text']",
removeFunction: function(entry) {
par = entry.parentNode;
remember(par, entry);
remember(par, entry.nextSibling);
remember(par, entry.nextSibling.nextSibling);
}
},
// Component - checked (benjamin-vn)
{
name: 'Component',
entryXpath: "//table[tbody/tr/td/@class='entryHolderBg']",
userXpath: ".//span[@class='ljuser']//a/b/text()",
tagXpath: ".//a[@rel='tag']/text()",
textXpath: ".//td[@class='entryHolderBg'][3]//td[@class='entry']/div[not(contains(@class, 'entry'))]", //div",
removeFunction: function(entry) {
par = entry.parentNode;
var curEntry = entry;
remember(par, entry);
do {
curEntry = curEntry.nextSibling;
remember(par, curEntry);
} while (!curEntry.tagName || curEntry.tagName != 'TABLE');
}
},
];
function Lj()
{
}
// End of file Lj.js
// use Xpath: already included
// File Update.js
// File Utils.js
// removes one (if any) trailing "\n" from the string
// Schould it remove cntrl-M??
Utils.chomp = function (str)
{
if(str.length>0 && str.charAt(str.length-1)=="\n")
return str.substr(0,str.length-1) ;
else
return str ;
}
Utils.get_url = function(url, cb)
{
GM_xmlhttpRequest({method: "GET", url: url, onload: function(xhr) { cb(xhr.responseText); } });
}
Utils.uniqueAttribute = function(script_name)
{
return script_name.replace(/[^a-zA-Z]/g, "-").toLowerCase() ;
}
function Utils()
{
}
// End of file Utils.js
// use Dialog: already included
// use GM_huge: already included
Update.O_LAST_CHECK_TIME = "time-of-last-update-check" ;
Update.V_INSTALL = "install" ;
Update.V_CANCEL = "cancel" ;
Update.V_PREF = "pref" ;
function Update(name, url, version, version_url)
{
this.script_name = name ;
this.script_url = url ;
this.current_version = version ;
this.version_url = version_url ;
this.dialog_name = Utils.uniqueAttribute(name) + "-update-dialog" ;
this.new_version = null ;
var d = Dialog.register(this.dialog_name, Update.init_dialog, Update.dialog_callback) ;
d.Update = this ;
s=d.style() ;
s.background = "blue" ;
s.color = "white" ;
s.fontSize = "139%" ;
s.top = "25%" ;
s.left = "25%" ;
s.right = "25%" ;
s.bottom = "25%" ;
s.border = "double 3px" ;
s.padding = "14px" ;
}
Update.prototype.check = function(cf, preferences)
{
// this.interval = interval ;
this.pref_dialog = preferences ;
if(cf==0)
return ;
cf = cf * 1000 ; // milli!!!-seconds
var last = GM_huge.getValue(Update.O_LAST_CHECK_TIME) ;
if(last && (Date.now()-last < cf))
return ;
( function(that) { Utils.get_url(that.version_url, function(text) {
Debug.log(text) ;
text = Utils.chomp(text) ;
var update = that.need_update(text) ;
if(update==0) // successfully checked
GM_huge.setValue(Update.O_LAST_CHECK_TIME, Date.now()) ;
if(update>0) // script should be updated
{
that.new_version = text ;
Dialog.show(that.dialog_name, true) ;
}
}) ; })(this) ;
}
Update.prototype.need_update = function(ver)
{
const re = /^(\d+)\.(\d+)\.(\d+)$/ ;
var local = this.current_version.match(re) ;
var remote = ver.match(re) ;
if(!local || !remote)
return -1 ; // can't check
for(var i=1; i<=3; ++i)
{
var r = parseInt(remote[i]) ;
var l = parseInt(local[i]) ;
if(r > l)
return 1 ; // new!
if(r < l)
return 0 ; // older? wow!!!
}
return 0 ; // successfully checked, no new version
}
Update.init_dialog = function(that)
{
var p = "" ;
if(that.Update.pref_dialog)
p = nbsp_html(10) + that.button("Edit preferences", Update.V_PREF) ;
that.html =
"<p>" +
"The version "+that.Update.new_version+" of "+that.Update.script_name+" is now ready for download "+
"(currently installed is version "+that.Update.current_version+"). "+
"Install new version?</p>" +
"<hr>" +
'<p>' +
'<center>' +
that.button("Install now", Update.V_INSTALL) + nbsp_html(10) +
that.button("Probably later", Update.V_CANCEL) + p ;
'</center>' + '</p>' +
"" ;
}
Update.dialog_callback = function(that, action)
{
if(action==Update.V_INSTALL)
{
setTimeout(function(){Dialog.show(that.Update.dialog_name, false);}, 1000) ;
GM_openInTab(that.Update.script_url) ;
}
if(action==Update.V_PREF)
{
Dialog.show(that.Update.pref_dialog, true) ;
}
GM_huge.setValue(Update.O_LAST_CHECK_TIME, Date.now()) ;
return true ;
}
// vim:tw=0:smartindent
// End of file Update.js
// use Utils: already included
// use Uri: already included
Debug.level(0) ;
const SCRIPT_NAME="LJ Inline Expander" ;
const VERSION="0.2.10" ;
const VERSION_URL = "http://www.math.uni-bonn.de/people/ilyad/lj/expander/version.txt" ;
const DIRECTORY="http://www.math.uni-bonn.de/people/ilyad/lj/expander" ;
const SCRIPT_URL="http://userscripts.org/scripts/source/16758.user.js" ;
const SCRIPT_PREFIX = Utils.uniqueAttribute(SCRIPT_NAME) ;
const UO_CHECK_FREQUENCY = "update-check-frequency" ;
const UO_ADD_CUT_CONTROL = "add-cut-control" ;
const UO_ADD_COMMENT_CONTROL = "add-comment-control" ;
const UO_ADD_COMMENT_INBOX = "add-comment-control-inbox" ;
const UO_ADD_TO_ENTRIES = "add-comment-control-to-postings" ;
const UO_USE_BLINK_HTML = "use-blink-html-tag" ;
const UO_FORMAT_LIGHT_INBOX = "use-param-format-inbox" ;
const UO_STYLE_MINE_INBOX = "use-param-style-inbox" ;
const A_URL = SCRIPT_PREFIX + "-attribute-url" ;
const A_CUT = SCRIPT_PREFIX + "-attribute-cut" ;
const A_TODO = SCRIPT_PREFIX + "-attribute-todo" ;
const A_ANCHOR = SCRIPT_PREFIX + "-attribute-anchor" ;
const A_BOX = SCRIPT_PREFIX + "-attribute-box" ;
const A_FOOTER = SCRIPT_PREFIX + "-attribute-footer" ;
const A_CONTROL = SCRIPT_PREFIX + "-attribute-control" ;
const A_CTL_STATUS = SCRIPT_PREFIX + "-attribute-ctl-status" ;
const A_SAVED_LOCATION = SCRIPT_PREFIX + "-saved-location" ;
const A_PREFERENCES = SCRIPT_PREFIX + "-preferences" ;
const A_DOWNLOAD_IFRAME = SCRIPT_PREFIX + "-download-iframe" ;
const A_DOWNLOAD_FORM = SCRIPT_PREFIX + "-download-form" ;
const A_PARENT_FRAGMENT = SCRIPT_PREFIX + "-parent-fragment" ;
const A_FOLDED_THREAD = SCRIPT_PREFIX + "-folded-thread" ;
const A_SHIFT = SCRIPT_PREFIX + "-shift-unfolded-comments" ;
const A_UNFOLD_URL = SCRIPT_PREFIX + "-unfold-url" ;
const A_LOADING = SCRIPT_PREFIX + "-loading" ;
const A_DUMMY = SCRIPT_PREFIX + "-attribute-dummy" ;
const V_COMMENTS = "comments" ;
const V_CUT = "cut" ;
const V_NOBOX = "nobox" ;
const V_STATUS_ON = "on" ;
const V_STATUS_OFF = "off" ;
const V_SAVE = "save preferences" ;
const V_CANCEL = "cancel and reset preferences" ;
const V_EDIT = "edit-preferences" ;
const V_FORM = "preferences form" ;
check_user_options() ;
var pref = Dialog.register(A_PREFERENCES, preferences_init, preferences_callback) ;
GM_registerMenuCommand(SCRIPT_NAME+" Preferences" , function(){Dialog.show(A_PREFERENCES,true);});
var u = new Update(SCRIPT_NAME, SCRIPT_URL, VERSION, VERSION_URL) ;
u.check(GM_getValue(UO_CHECK_FREQUENCY), A_PREFERENCES) ;
main() ;
// Lj.colorize() ;
find_all_entries() ;
unsafeWindow.onbeforeunload = function() {} ; // I do not understand, why do I need it :-(
function main()
{
var links = Xpath.list('//a[contains(@href , "#cutid")]') ;
for(var i=0; i<links.length; ++i)
{
var that = links[i] ;
var m = that.href.match(/#cutid(\d+)$/) ;
if(!m)
continue ;
var cutid = m[1] ;
var entry_url = extract_entry_url(that.href) ;
if(!entry_url)
continue ;
var anchor = parent_of_cut(that) ;
if(!anchor)
continue ;
var ctl1 = create_control(V_CUT, entry_url, cutid) ;
var ctl2 = create_control(V_COMMENTS, entry_url, cutid) ;
if(GM_getValue(UO_ADD_CUT_CONTROL)=="yes")
{
anchor.insertBefore(ctl1, that) ;
anchor.insertBefore(nbsp_node(), that) ;
}
if(GM_getValue(UO_ADD_COMMENT_CONTROL)=="yes")
{
anchor.insertBefore(ctl2, that.nextSibling) ;
anchor.insertBefore(nbsp_node(), that.nextSibling) ;
}
anchor.setAttribute(A_ANCHOR, 'yes') ;
anchor.setAttribute(A_URL, entry_url) ;
anchor.setAttribute(A_CUT, cutid) ;
update_state(V_NOBOX, entry_url, cutid) ;
}
}
function DOIT(event)
{
this.removeEventListener("click",DOIT,false) ;
var entry_url = this.getAttribute(A_URL) ;
var cut_id = this.getAttribute(A_CUT) ;
var control = this.getAttribute(A_CONTROL) ;
var status = this.getAttribute(A_CTL_STATUS) ;
var todo = (status==V_STATUS_OFF) ? V_NOBOX : control ;
var box = Xpath.aNode([A_BOX,'*', A_URL,entry_url, A_CUT,cut_id]) ;
var box_status = box ? box.getAttribute(A_BOX) : V_NOBOX ;
if(todo==V_NOBOX) // && box
{
if(cut_id>0)
{
var entry_node = find_lj_entry(this) ;
unhideChildren(entry_node) ;
}
var need_scrolling = is_descendant(this, box) ;
box.parentNode.removeChild(box) ;
if(need_scrolling)
{
var scroll_to = Xpath.aNode([A_CONTROL,'*', A_URL,entry_url, A_CUT,cut_id]) ;
var underlyingFoo = scroll_to.wrappedJSObject || scroll_to ;
underlyingFoo.scrollIntoView() ;
}
}
else
{
if(box_status==V_NOBOX)
{
box = create_box(entry_url, cut_id, todo) ;
if(cut_id>0)
set_header(box, 0, "[ Loading lj-cut"+dots()+"]", false) ;
var anchor = Xpath.aNode([A_ANCHOR,'*', A_URL,entry_url, A_CUT,cut_id]) ;
if(cut_id==0 && anchor.getAttribute("class")=="entrybox") // UGLY HACK! needed for S2-Generator
{
box.style.textAlign = "left" ;
box.style.backgroundColor = "white" ;
box.style.color = "black" ;
}
anchor.parentNode.insertBefore(box, anchor.nextSibling) ;
if(cut_id>0)
{
var entry_node = find_lj_entry(this) ;
var comments_node = find_lj_comments(entry_node) ;
if(comments_node)
{
var supremum = sup(box, comments_node, entry_node) ;
var p = comments_node ;
var q = comments_node ;
while(p && p!=supremum)
{
q = p ;
p = p.parentNode ;
}
comments_node = q ;
// GM_log("new comments_node = " + comments_node.innerHTML) ;
}
hideChildren(box, comments_node, entry_node) ;
}
}
if(todo==V_COMMENTS)
{
enlarge_box(box, 1) ; // create space for comments
set_header(box, 1, "[ Loading comments"+dots()+"]", false) ;
}
set_loading_attribute(box, box.childNodes[0], true) ;
( function(entry_url,cut_id,box,box_status,todo) { Utils.get_url(light(entry_url), function(html_text) {
if(box_status==V_NOBOX && cut_id>0)
{
var cut_text = extract_cut(html_text, cut_id) ;
// box.style.border = "1px solid rgb(0, 170, 170)" ;
box.style.paddingTop = "10px" ;
set_loading_attribute(box, box.childNodes[0], false) ;
box.childNodes[0].innerHTML = cut_text ;
}
Xpath.aNode([A_FOOTER], box).style.display = "" ; // show footer, if hidden
if(todo=="comments")
{
var pages = count_comments_pages(html_text) ;
// GM_log(pages+" pages counted") ;
var comments = extract_comments(html_text, entry_url, cut_id, 0) ;
insert_comments(box, 1, comments, pages>1) ;
set_loading_attribute(box, box.childNodes[0], false) ; // some magic :-)
enlarge_box(box, pages) ;
for(var pg=2; pg<=pages; ++pg)
{
//var loading = document.createElement("B") ;
//loading.innerHTML = "[Loading comments (page #"+pg+")]" ;
//insert_comments(box, pg, loading, true) ;
set_loading_attribute(box, box.childNodes[pg], true) ;
set_header(box, pg, "[ Loading comments (page #"+pg+")"+dots()+"]", false) ;
( function(entry_url,box,pg) { Utils.get_url(light(entry_url)+"&page="+pg, function(html_text) {
var comments_page = extract_comments(html_text, entry_url, cut_id, 0) ;
insert_comments(box, pg, comments_page, true) ;
}) ; })(entry_url,box,pg) ;
}
}
}) ; })(entry_url,cut_id,box,box_status,todo) ;
}
update_state(todo, entry_url, cut_id) ;
var x = new Debug(0) ;
if(x.enabled())
{
this.href= "http://www.livejournal.com" ;
}
else
event.preventDefault() ;
this.addEventListener("click",DOIT,false) ;
}
function find_footer(box)
{
// XXX probably is'll not work because of race condition
return box.childNodes[box.childNodes.length-1] ;
}
function create_footer(entry_url, cut_id)
{
var footer = document.createElement("div") ;
footer.style.display = "none" ;
footer.setAttribute(A_FOOTER, "yes") ;
footer.setAttribute(A_URL, entry_url) ;
footer.setAttribute(A_CUT, cut_id) ;
var td_nbsp = "<td>"+nbsp_html()+nbsp_html()+"</td>" ;
var dummy = "<span "+A_DUMMY+"='yes'></span>"
var link = "<a href='"+entry_url+"'>Link</a>" ;
var comm = "<a href='"+entry_url+"?mode=reply'>Leave"+nbsp_html()+"a"+nbsp_html()+"comment</a>" ;
footer.innerHTML =
"<table><tbody><tr>" +
"<td>"+dummy+"</td>" +
td_nbsp +
"<td width='50%'><hr /></td>" +
"<td><b>"+nbsp_html()+link+nbsp_html()+"|"+nbsp_html()+comm+nbsp_html()+"</b></td>" +
"<td width='50%'><hr /></td>" +
td_nbsp +
"<td>"+dummy+"</td>" +
"</tr></tbody></table>" ;
var dummy_nodes = Xpath.aList([A_DUMMY], footer) ;
// GM_log(dummy_nodes) ;
var ctl = [V_CUT, V_COMMENTS] ;
for(var i=0; i<2 ; ++i)
{
var c = dummy_nodes[i];
var a = create_control(ctl[i], entry_url, cut_id) ;
c.parentNode.insertBefore(a, c) ;
c.parentNode.removeChild(c) ;
}
return footer ;
}
function create_control(ctl_type, url, cutid)
{
var tt = document.createElement("a") ;
tt.href = url+ (cutid? "#cutid"+cutid: "") ;
tt.innerHTML = "<tt>xxx</tt>" ;
// tt.style.cursor = "pointer" ;
tt.style.textDecoration= "none" ;
tt.addEventListener("click", DOIT, false) ;
tt.setAttribute(A_CONTROL, ctl_type) ;
tt.setAttribute(A_URL, url) ;
tt.setAttribute(A_CUT, cutid) ;
if(false)
tt.style.background = "yellow" ;
return tt ;
}
function set_box_color(box, color)
{
box.style.border = "1px solid "+color ;
}
function create_box(entry_url, cut_id, status)
{
var box = document.createElement('blockquote') ;
box.style.padding = "20px" ;
box.style.align = "left" ;
// box.style.background = "white" ;
set_box_color(box, "rgb(0,0,255)") ;
box.setAttribute(A_URL, entry_url) ;
box.setAttribute(A_CUT, cut_id) ;
box.setAttribute(A_BOX, status) ;
var footer = create_footer(entry_url, cut_id) ;
box.insertBefore(footer, null) ;
enlarge_box(box, 0) ;
return box ;
}
function clear_box_page(box, page)
{
var div = box.childNodes[page] ;
div.innerHTML = "<div></div><div></div>" ;
}
function enlarge_box(box, max_page)
{
var N = max_page + 2 - box.childNodes.length ;
for(var i=0; i<N; ++i)
{
var div = document.createElement('div') ;
box.insertBefore(div, find_footer(box)) ; // before the footer
clear_box_page(box, box.childNodes.length-2) ;
// GM_log("enlarge_box: max_page="+max_page+", i="+i+", box contains: "+box.innerHTML) ;
}
}
function update_state(state, entry_url, cut_id)
{
var buttons = Xpath.aList([A_CONTROL,'*', A_URL,entry_url, A_CUT,cut_id]) ;
for each(a in buttons)
{
b = a.firstChild ;
var type = a.getAttribute(A_CONTROL) ;
var need_comments_control = true ;
if(state!=V_NOBOX && type==V_COMMENTS)
{
var box = Xpath.aNode([A_BOX,'*', A_URL,entry_url, A_CUT,cut_id]) ;
var is_inbox_control = is_descendant(b, box) ;
if(is_inbox_control && GM_getValue(UO_ADD_COMMENT_INBOX)!="yes")
need_comments_control = false ;
}
if(state==V_NOBOX)
b.textContent = (type==V_CUT) ? "+++" : "===" ;
else if(state==V_CUT)
b.textContent = (type==V_COMMENTS && need_comments_control) ? "===" : "---" ;
else
b.textContent = "---" ;
a.setAttribute(A_CTL_STATUS, b.textContent=="---" ? V_STATUS_OFF : V_STATUS_ON) ;
var title ;
if(type==V_CUT)
title = "Open lj-cut..." ;
if(type==V_COMMENTS && cut_id>0)
title = "Open lj-cut and comments..." ;
if(cut_id==0)
title = "Open comments..." ;
if(b.textContent=="---")
title = "Close box" ;
b.title = title ;
}
}
// 50% --- by the courtesy of lj-user "dadcaptain"
function set_header(box, page, text, hr)
{
var div = box.childNodes[page].childNodes[0] ;
if(hr)
div.innerHTML = "<table width='100%'><tbody><tr><td width='50%'><hr></td><td><B> "+text+" </B></td><td width='50%'><hr></td></tr></tbody></table>"
else
div.innerHTML = "<b>" + text + "</b>" ;
}
function insert_comments(box, pageno, node, flag)
{
var page_box = box.childNodes[pageno] ;
while(page_box.hasChildNodes())
page_box.removeChild(page_box.childNodes[0]) ;
clear_box_page(box, pageno) ;
const nbsp = " " ;
set_header(box, pageno, "Comments"+(flag?nbsp+"[page"+nbsp+"#"+ pageno+"]":""), true) ;
page_box.childNodes[1].insertBefore(node, null) ;
set_loading_attribute(box, page_box, false)
}
function set_loading_attribute(box, child, yesno)
{
if(yesno)
{
child.setAttribute(A_LOADING,'yes') ;
set_box_color(box, "rgb(255,0,0)") ;
}
else
{
child.setAttribute(A_LOADING, 'no') ;
if(Xpath.aList([A_LOADING, "yes"], box).length == 0)
set_box_color(box, "rgb(170,170,170)") ;
}
}
// This function hides recursively all children nodes of the node 'start' standing
// after the node 'ref'. The node 'skip' is skipped (together with all its children)
var FLAG ; // TODO must it be a global variable??? No! No! I'll transform it to some stupid class member
function hideChildren(ref, skip, start)
{
FLAG = false ;
hc(ref, skip, start) ;
}
function hc(ref, skip, current)
{
if(current==ref)
FLAG = true ;
if(current==skip || current==ref)
return ;
if(FLAG)
{
if(current.style)
current.style.display = 'none' ;
else
{
if(current.parentNode.style.display!="none")
{
var span = document.createElement('span') ;
span.innerHTML = current.textContent ;
span.style.display = "none" ;
current.parentNode.insertBefore(span, current) ;
current.parentNode.removeChild(current) ;
}
}
}
var children = current.childNodes;
for(var i=0; i<children.length; ++i)
hc(ref, skip, children[i]) ;
}
// Recursively deletes the 'none' display style from document nodes
function unhideChildren(node)
{
if(node.style && node.style.display=="none")
node.style.display = "" ;
var children = node.childNodes;
for(var i=0; i<children.length; ++i)
unhideChildren(children[i]) ;
}
function extract_cut(text, cut_no)
{
var c1 = '<a name="cutid'+cut_no +'+"></a>' ;
var co = "</div><br style='clear: both' /><hr width='100%' size='2' align='center' />" ;
var pos1 = text.search(c1) ;
var pos2 = text.search(co) ;
// GM_log("pos1="+pos1+" pos2="+pos2) ;
if(pos1==-1 || pos2==-1)
return "<b>Oops! Can't extract cut #"+cut_no+" from this post.</b>" ;
// GM_log("cut="+text.substr(pos1+c1.length-1, pos2-pos1-c1.length+1)) ;
return text.substr(pos1+c1.length-1, pos2-pos1-c1.length+1) ;
}
function extract_comments(text, entry, cutid, delta_shift)
{
var page = document.createElement('span') ;
page.innerHTML = text ;
const comment_xpath = 'descendant::span[@id]' ;
var comments = document.evaluate(comment_xpath,page,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null) ;
var result = document.createElement('span') ;
for(var i=0; i<comments.snapshotLength; ++i)
{
var span = comments.snapshotItem(i) ;
var table = span.firstChild ;
var id = comment_to_tid(table) ;
if(!id)
continue ;
if(!table.getAttribute("class")) // folded or screend/deleted comment
{
table.setAttribute(A_FOLDED_THREAD, id) ;
// Debug.log("FOLDED ", id) ;
var subj = Xpath.node("./tbody/tr/td[2]/a",table, true) ;
if(subj)
{
var hyphen = document.createTextNode(" - ") ;
var unfold = document.createElement("a") ;
unfold.innerHTML = "Unfold" ;
var target = new Uri(entry) ;
target.query.format = "light" ;
target.query.thread = id ;
unfold.setAttribute(A_UNFOLD_URL, target.toString()) ;
unfold.addEventListener("click", unfold_thread, false) ;
if(GM_getValue(UO_FORMAT_LIGHT_INBOX)!="yes")
delete target.query.format ;
if(GM_getValue(UO_STYLE_MINE_INBOX)=="yes")
target.query.style = "mine" ;
target.fragment = "t" + id ;
unfold.href = target ;
subj.parentNode.insertBefore(unfold, subj.nextSibling) ;
subj.parentNode.insertBefore(hyphen, unfold) ;
var img = Xpath.node("./tbody/tr/td/img[@height=1 and @width]", table) ;
var shift = 0 ;
if(img)
shift = parseInt(img.width) ;
unfold.setAttribute(A_SHIFT, shift+delta_shift) ;
}
}
else // usual comment box --- need to rewrite "link"
{
var a = Xpath.node("./tbody/tr[1]/td[2]/font[3]/a[@href]", table) ;
var target = new Uri(a.href) ;
if(GM_getValue(UO_FORMAT_LIGHT_INBOX)!="yes")
delete target.query.format ;
if(GM_getValue(UO_STYLE_MINE_INBOX)=="yes")
target.query.style = "mine" ;
a.href = target.toString() ;
}
result.insertBefore(span , null) ;
var a = document.createElement("a") ;
a.name = jump_name(entry, cutid, id);
result.insertBefore(a, span ) ;
for each(var lnk in Xpath.list("./tbody/tr[2]/td/p/font/a", table))
{
var u = new Uri(lnk.href) ;
var x = new Debug(3) ;
if(GM_getValue(UO_FORMAT_LIGHT_INBOX)!="yes")
delete u.query.format ;
if(GM_getValue(UO_STYLE_MINE_INBOX)=="yes")
u.query.style = "mine" ;
lnk.href = u.toString() ;
var target = lnk.href.match(/#t(\d+)$/) ;
if(!target)
{
if(lnk.href.match("replyto="+id) && x.enabled())
lnk.innerHTML += " - reply" ;
}
else if(target[1]==id)
{
if(x.enabled())
lnk.innerHTML += " - thread " + id ;
var target = new Uri(entry) ;
target.query.format = "light" ;
target.query.thread = id ;
lnk.setAttribute(A_UNFOLD_URL, target.toString()) ;
var img = Xpath.node("./tbody/tr/td/img[@height=1 and @width]", table) ;
var shift = 0 ;
if(img)
shift = parseInt(img.width) ;
lnk.setAttribute(A_SHIFT, shift+delta_shift) ;
lnk.addEventListener("click", unfold_thread, false) ;
}
else
{
if(x.enabled())
lnk.innerHTML += " - parent - " + jump_name(entry, cutid, target[1]) ;
lnk.setAttribute(A_PARENT_FRAGMENT, jump_name(entry, cutid, target[1])) ;
lnk.addEventListener("click", jump_to_parent, false) ;
lnk.title = "Jump to parent" ;
}
}
}
return result ;
}
function extract_comments_obsolete_2008_03_03(text, entry, cutid, delta_shift)
{
var page = document.createElement('span') ;
page.innerHTML = text ;
const comment_xpath = 'descendant::table' ;
var comments = document.evaluate(comment_xpath,page,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null) ;
var result = document.createElement('span') ;
for(var i=0; i<comments.snapshotLength; ++i)
{
var table = comments.snapshotItem(i) ;
var id = comment_to_tid(table) ;
if(!id)
continue ;
if(!table.id) // folded or screend/deleted comment
{
table.setAttribute(A_FOLDED_THREAD, id) ;
// Debug.log("FOLDED ", id) ;
var subj = Xpath.node("./tbody/tr/td[2]/a",table, true) ;
if(subj)
{
var hyphen = document.createTextNode(" - ") ;
var unfold = document.createElement("a") ;
unfold.innerHTML = "Unfold" ;
var target = new Uri(entry) ;
target.query.format = "light" ;
target.query.thread = id ;
unfold.setAttribute(A_UNFOLD_URL, target.toString()) ;
unfold.addEventListener("click", unfold_thread, false) ;
if(GM_getValue(UO_FORMAT_LIGHT_INBOX)!="yes")
delete target.query.format ;
if(GM_getValue(UO_STYLE_MINE_INBOX)=="yes")
target.query.style = "mine" ;
target.fragment = "t" + id ;
unfold.href = target ;
subj.parentNode.insertBefore(unfold, subj.nextSibling) ;
subj.parentNode.insertBefore(hyphen, unfold) ;
var img = Xpath.node("./tbody/tr/td/img[@height=1 and @width]", table) ;
var shift = 0 ;
if(img)
shift = parseInt(img.width) ;
unfold.setAttribute(A_SHIFT, shift+delta_shift) ;
}
}
else // usual comment box --- need to rewrite "link"
{
var a = Xpath.node("./tbody/tr[1]/td[2]/font[3]/a[@href]", table) ;
var target = new Uri(a.href) ;
if(GM_getValue(UO_FORMAT_LIGHT_INBOX)!="yes")
delete target.query.format ;
if(GM_getValue(UO_STYLE_MINE_INBOX)=="yes")
target.query.style = "mine" ;
a.href = target.toString() ;
}
result.insertBefore(table, null) ;
var a = document.createElement("a") ;
a.name = jump_name(entry, cutid, id);
result.insertBefore(a, table) ;
for each(var lnk in Xpath.list("./tbody/tr[2]/td/p/font/a", table))
{
var u = new Uri(lnk.href) ;
var x = new Debug(3) ;
if(GM_getValue(UO_FORMAT_LIGHT_INBOX)!="yes")
delete u.query.format ;
if(GM_getValue(UO_STYLE_MINE_INBOX)=="yes")
u.query.style = "mine" ;
lnk.href = u.toString() ;
var target = lnk.href.match(/#t(\d+)$/) ;
if(!target)
{
if(lnk.href.match("replyto="+id) && x.enabled())
lnk.innerHTML += " - reply" ;
}
else if(target[1]==id)
{
if(x.enabled())
lnk.innerHTML += " - thread " + id ;
var target = new Uri(entry) ;
target.query.format = "light" ;
target.query.thread = id ;
lnk.setAttribute(A_UNFOLD_URL, target.toString()) ;
var img = Xpath.node("./tbody/tr/td/img[@height=1 and @width]", table) ;
var shift = 0 ;
if(img)
shift = parseInt(img.width) ;
lnk.setAttribute(A_SHIFT, shift+delta_shift) ;
lnk.addEventListener("click", unfold_thread, false) ;
}
else
{
if(x.enabled())
lnk.innerHTML += " - parent - " + jump_name(entry, cutid, target[1]) ;
lnk.setAttribute(A_PARENT_FRAGMENT, jump_name(entry, cutid, target[1])) ;
lnk.addEventListener("click", jump_to_parent, false) ;
lnk.title = "Jump to parent" ;
}
}
}
return result ;
}
function unfold_thread(event)
{
event.preventDefault() ;
Debug.log("unfold_thread handler: ", this.getAttribute(A_UNFOLD_URL)) ;
var shift = this.getAttribute(A_SHIFT) ;
var box = Xpath.node("ancestor::*[@"+A_BOX+"]", this) ;
var entry = box.getAttribute(A_URL) ;
var cutid = box.getAttribute(A_CUT) ;
set_loading_attribute(box, this, true) ;
( function(box,that,shift,entry,cutid) { Utils.get_url(that.getAttribute(A_UNFOLD_URL), function(html_text) {
replace_folded_comments(that, html_text, box, shift,entry,cutid) ;
}) ; }) (box,this, shift,entry,cutid) ;
event.preventDefault() ;
}
function replace_folded_comments(that, text, box, shift,entry,cutid)
{
Debug.log("replace_folded_comments") ;
set_loading_attribute(box, that, false) ;
var body = extract_comments(text, entry, cutid, parseInt(shift)) ;
document.body.appendChild(body) ;
for each(var t in Xpath.list(".//table[@class='talk-comment']", body))
{
Debug.log(1) ;
Debug.log("parentNode: ", t.parentNode.nodeName) ;
Debug.log("parentNode.id: ", t.parentNode.id) ;
var id = t.parentNode.id.match(/ljcmt(\d+)/) ;
if(!id)
continue ;
Debug.log(2) ;
id = id[1] ;
var folded = Xpath.aNode([A_FOLDED_THREAD, id], box) ;
if(!folded)
continue ;
Debug.log(3) ;
var img = Xpath.node("./tbody/tr/td/img[@height=1 and @width]", t) ;
if(img)
img.width += parseInt(shift) ;
Debug.log(4) ;
folded.parentNode.replaceChild(t, folded) ;
Debug.log(5) ;
}
}
function jump_to_parent(event)
{
var fragment = this.getAttribute(A_PARENT_FRAGMENT) ;
if(fragment)
{
var u = new Uri(window.location.toString()) ;
window.location = u.originalLocation() + "#" + fragment ;
event.preventDefault() ;
}
}
function jump_name(entry_url, cutid, thread_id)
{
var a = Lj.extract_id(entry_url) ;
var c = (cutid!="0" ? cutid + "-" : "") ;
return a[1]+"-"+a[2]+"-"+c+"t"+thread_id ;
}
// returns numerical comments ID (as 12345 in <a name="t12345"> tag)
// returns null unless it's a comment
// The 'node' argument should be a <table> tag
function comment_to_tid_obsolete_2008_03_03(node)
{
// the following nodes are comments:
// 1) <a name="t1234"></a><table>...</table> --- normal comment
// 2) <p><a name="t1234></a></p> <table>...</table> --- deleted/screened comment
var prev = node.previousSibling ;
if(!prev || !prev.nodeName) return null ;
var nodename = prev.nodeName.toUpperCase() ;
if(nodename=="P")
{
if(!prev.childNodes || !prev.childNodes[0]) return null ;
prev = prev.childNodes[0] ;
if(!prev || !prev.nodeName) return null ;
nodename = prev.nodeName.toUpperCase() ;
}
if(nodename!="A") return null ;
if(!prev.name) return null ;
var a = prev.name.match("^t(\\d+)$") ;
if(!a) return null ;
return a[1] ;
}
function comment_to_tid(node)
{
// the following node is a comment:
// 1) <span id="ljcmt0000000"><table>...</table>
var parent = node.parentNode ;
// Debug.level(4);
Debug.log(parent.nodeName) ;
if(parent.nodeName.toLowerCase()!="span")
return null ;
var id = parent.getAttribute("id") ;
Debug.log(node.id) ;
if(!id)
return null ;
var a = id.match("^ljcmt(\\d+)$") ;
if(!a) return null ;
return a[1] ;
}
function extract_entry_url(url)
{
var u = new Uri(url) ;
return u.path ;
}
function extract_entry_url_obsolete(url)
{
var a = url.match("^(http://[^/]+/\\d+\\.html)") ;
// GM_log("url="+url+" a="+a) ;
if(a) return a[1] ;
a = url.match("^(http://community.[^/]+/[^/]+/\\d+\\.html)") ;
if(a) return a[1] ;
a = url.match("^(http://syndicated.[^/]+/[^/]+/\\d+\\.html)") ;
if(a) return a[1] ;
a = url.match("^(http://users.[^/]+/[^/]+/\\d+\\.html)") ;
if(a) return a[1] ;
}
// Creates an URL for the retrieving of the given LJ posting in "light format"
function light(url)
{
var u = new Uri(url) ;
u.query.format = "light" ;
return u.toString() ;
}
function light_obsolete(url)
{
var ch ;
if(url.search(/\?/)==-1)
ch = '?' ;
else
ch ='&' ;
var a = url.search(/#/) ;
if(a!=-1)
url = url.substr(0,a) ;
// GM_log("returns: "+url + ch + "format=light") ;
return url + ch + "format=light" ;
}
function dots()
{
if(GM_getValue(UO_USE_BLINK_HTML)=="yes")
return " <BLINK>...</BLINK> " ;
else
return " ... " ;
}
function check_user_options()
{
if(!GM_getValue(UO_CHECK_FREQUENCY))
GM_setValue(UO_CHECK_FREQUENCY, 60*60*24+"") ; // Daily
var opt_yes = [ UO_ADD_CUT_CONTROL, UO_ADD_COMMENT_INBOX, UO_USE_BLINK_HTML, UO_ADD_TO_ENTRIES, UO_FORMAT_LIGHT_INBOX ] ;
for each(var o in opt_yes)
if(!GM_getValue(o))
GM_setValue(o, "yes") ;
var opt_no = [ UO_ADD_COMMENT_CONTROL, UO_STYLE_MINE_INBOX ] ;
for each(var oo in opt_no)
if(!GM_getValue(oo))
GM_setValue(oo, "no") ;
}
function preferences_init(that)
{
that.html =
'<p>'+'<fieldset>'+
'<legend> Controls in Livejournal friend list </legend>' +
that.checkbox(UO_ADD_CUT_CONTROL, "Add <tt><b>+++</b></tt> control opening lj-cuts to every <b>(Read more...)</b> link") + '<br>' +
that.checkbox(UO_ADD_COMMENT_CONTROL, "Add <tt><b>===</b></tt> control opening lj-cuts and comments to every <b>(Read more...)</b> link ") + '<br>' +
that.checkbox(UO_ADD_COMMENT_INBOX, "Add <tt><b>===</b></tt> control opening comments to every opened lj-cut box") + '<br>' +
that.checkbox(UO_ADD_TO_ENTRIES, "Add <tt><b>===</b></tt> control to every posting (experimental option)") + '<br>' +
'</fieldset>'+
'<fieldset>' +
'<legend> In-box links </legend>' +
that.checkbox(UO_FORMAT_LIGHT_INBOX, "Don't remove <tt>format=light</tt> parameter") + '<br>' +
that.checkbox(UO_STYLE_MINE_INBOX, "Add <tt>style=mine</tt> parameter") + '<br>' +
'</fieldset>'+
'<fieldset>'+
'<legend> Automatically download new versions of '+SCRIPT_NAME+' </legend>' +
'Check for new version: <br>' +
nbsp_html() + that.radio(UO_CHECK_FREQUENCY, 0, "Never (inadvisable)") + '<br>' +
nbsp_html() + that.radio(UO_CHECK_FREQUENCY, 3600*24*14,"Once every fortnight") + '<br>' +
nbsp_html() + that.radio(UO_CHECK_FREQUENCY, 3600*24, "Daily (recommended)") + '<br>' +
nbsp_html() + that.radio(UO_CHECK_FREQUENCY, 3600, "Every hour") + '<br>' +
nbsp_html() + that.radio(UO_CHECK_FREQUENCY, 60, "Every minute (why not?)") + '<br>' +
'</fieldset>' +
'<fieldset>' +
'<legend> Appearance </legend>' +
that.checkbox(UO_USE_BLINK_HTML, "Use deprecated <tt><BLINK></tt> HTML tag during downloads"+dots()) +
'</fieldset>'+
'</p><p>' + '<center>' +
that.button("Save preferences", V_SAVE) + nbsp_html(10) +
that.button("Cancel", V_CANCEL) + '</center>' + '</p>' +
"" ;
}
function preferences_callback(that, action)
{
if(action==V_SAVE)
{
that.gm_save() ;
alert("Preferences saved.\nDon't forget to reload page.") ;
}
return true ;
}
// vim:tw=0:smartindent