/usr/share/psi-plus/themes/chatview/util.js is in psi-plus-webkit 0.16.330-1.3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | window[chatServer.jsNamespace()] = function() {
var htmlSource = document.createElement("div"); //manages appendHtml
var server = window.chatServer;
var chat = {
console : server.console,
adapter : {
receiveObject : function(data) {
chat.util.showCriticalError("Adapter is not loaded. output impossible!\n\nData was:" + chat.util.props(data));
}
},
util: {
showCriticalError : function(text) {
var e=document.body || document.documentElement.appendChild(document.createElement("body"));
var er = e.appendChild(document.createElement("div"))
er.style.cssText = "background-color:red;color:white;border:1px solid black;padding:1em;margin:1em;font-weight:bold";
er.innerHTML = chat.util.escapeHtml(text).replace(/\n/, "<br/>");
},
// just for debug
escapeHtml : function(html) {
return html.split("&").join("&").split( "<").join("<").split(">").join(">");
},
// just for debug
props : function(e, rec) {
var ret='';
for (var i in e) {
var gotValue = true;
var val = null;
try {
val = e[i];
} catch(err) {
val = err.toString();
gotValue = false;
}
if (gotValue) {
if (val instanceof Object && rec && val.constructor != Date) {
ret+=i+" = "+val.constructor.name+"{"+chat.util.props(val, rec)+"}\n";
} else {
if (val instanceof Function) {
ret+=i+" = Function: "+i+"\n";
} else {
ret+=i+" = "+(val === null?"null\n":val.constructor.name+"(\""+val+"\")\n");
}
}
} else {
ret+=i+" = [CAN'T GET VALUE: "+val+"]\n";
}
}
return ret;
},
// replaces <icon name="icon_name" text="icon_text" />
// with <img src="icon://psi/icon_name" title="icon_text" />
icon2img : function (obj) {
var img = document.createElement('img');
img.src = "icon:" + obj.getAttribute("name");
img.title = obj.getAttribute("text");
var ib = obj.nextSibling
while (obj.firstChild) obj.parentNode.insertBefore(obj.firstChild, ib);
obj.parentNode.replaceChild(img, obj);
},
// replaces all occurrence of <icon> by function above
replaceIcons : function(el) {
var icon, icons = [], i, els;
while (true) {
els = el.getElementsByTagName("icon");
if (els.length == 0) break;
for (i=0; i<els.length; i++) {
chat.util.icon2img(els[i]);
}
}
},
updateObject : function(object, update) {
for (var i in update) {
object[i] = update[i]
}
},
findStyleSheet : function (sheet, selector) {
for (var i=0; i<sheet.cssRules.length; i++) {
if (sheet.cssRules[i].selectorText == selector)
return sheet.cssRules[i];
}
return false;
},
appendHtml : function(dest, html) {
htmlSource.innerHTML = html;
chat.util.replaceIcons(htmlSource);
while (htmlSource.firstChild) dest.appendChild(htmlSource.firstChild);
},
siblingHtml : function(dest, html) {
htmlSource.innerHTML = html;
chat.util.replaceIcons(htmlSource);
while (htmlSource.firstChild) dest.parentNode.insertBefore(htmlSource.firstChild, dest);
},
ensureDeleted : function(id) {
if (id) {
var el = document.getElementById(id);
if (el) {
el.parentNode.removeChild(el);
}
}
},
loadXML : function(path, allowEmpty) {
allowEmpty = allowEmpty || false;
text = server.getFileContents(path);
if (!text && !allowEmpty) {
throw new Error("File " + path + " is empty. can't parse xml");
}
try {
return new DOMParser().parseFromString(text, "text/xml");
} catch (e) {
server.console("failed to parse xml from file " + path);
throw e;
}
}
},
WindowScroller : function(animate) {
var o=this, state, timerId
var ignoreNextScroll = false;
o.animate = animate;
o.atBottom = true; //just a state of aspiration
var animationStep = function() {
timerId = null;
var before = document.height - (window.innerHeight+window.pageYOffset);
var step = before;
if (o.animate) {
step = step>200?200:(step<8?step:Math.floor(step/1.7));
}
ignoreNextScroll = true;
window.scrollTo(0, document.height - window.innerHeight - before + step);
if (before>0) {
timerId = setTimeout(animationStep, 70); //next step in 250ms even if we are already at bottom (control shot)
}
}
var startAnimation = function() {
if (timerId) return;
if (document.height > window.innerHeight) { //if we have what to scroll
timerId = setTimeout(animationStep, 0);
}
}
var stopAnimation = function() {
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
}
//timeout to be sure content rerendered correctly
window.addEventListener("resize", function() {setTimeout(function(){
if (o.atBottom) { //immediatelly scroll to bottom if we wish it
window.scrollTo(0, document.height - window.innerHeight);
}
}, 0);}, false);
//let's consider scroll may happen only by user action
window.addEventListener("scroll", function(){
if (ignoreNextScroll) {
ignoreNextScroll = false;
return;
}
stopAnimation();
o.atBottom = document.height == (window.innerHeight+window.pageYOffset);
}, false);
//EXTERNAL API
// checks current state of scroll and wish and activates necessary actions
o.invalidate = function() {
if (o.atBottom) {
startAnimation();
}
}
o.force = function() {
o.atBottom = true;
o.invalidate();
}
}
}
return chat;
}();
"ok"; // just an indicator for script loader
|