Alice
view release on metacpan or search on metacpan
share/static/alice.js view on Meta::CPAN
clean.push("<"+nick+">");
}
if (message) {
var body = message.innerHTML.stripTags();
body = body.replace(/^\s+/, "");
body = body.replace(/\s+$/, "");
clean.push(body);
}
if (clean.length) lines.push(
clean.join(" ").replace(/\n/g, "").escapeHTML());
});
node.update(lines.join("<br>"));
node.cleanWhitespace();
},
epochToLocal: function(epoch, format) {
var date = new Date(parseInt(epoch) * 1000);
if (!date) return epoch;
var hours = date.getHours();
if (format == "12") {
var ap;
if (hours >= 12) {
if (hours > 12) hours -= 12;
ap = "p";
} else {
ap = "a"
}
return sprintf("%d:%02d%s", hours, date.getMinutes(), ap);
}
return sprintf("%02d:%02d", hours, date.getMinutes());
},
makeLinksClickable: function(elem) {
var children = elem.childNodes;
var length = children.length;
for (var i=0; i < length; i++) {
var node = children[i];
if (node.nodeName != "#text") {
Alice.makeLinksClickable(node);
}
else if (node.nodeValue.match(Alice.RE.url)) {
var span = new Element("SPAN");
span.innerHTML = node.nodeValue.escapeHTML().replace(
Alice.RE.url, '<a href="$1" target="_blank" rel="noreferrer">$1</a>');
node.parentNode.replaceChild(span, node);
}
}
},
growlNotify: function(message) {
if (window.fluid) {
window.fluid.showGrowlNotification({
title: message.subject,
description: message.body,
priority: 1,
sticky: false,
identifier: message.msgid
});
}
else if (window.webkitNotifications) {
if (window.webkitNotifications.checkPermission() == 0) {
var popup = window.webkitNotifications.createNotification(
"http://static.usealice.org/image/alice.png",
message.subject,
message.body
);
popup.ondisplay = function() {
setTimeout(function () {popup.cancel();}, 5000);
};
popup.show();
}
}
},
isSpecialKey: function(keyCode) {
var special_keys = [
16,27,9,32,13,8,145,20,144,19,45,36,46,35,33,34,37,38,39,
40,17,18,91,112,113,114,115,116,117,118,119,120,121,122,123,
224
];
return special_keys.indexOf(keyCode) > -1;
},
playAudio: function(image, audio) {
image.src = '/static/image/pause.png';
if (! audio) {
var url = image.nextSibling.href;
audio = new Audio(url);
audio.addEventListener('ended', function () {
image.src = '/static/image/play.png';
image.onclick = function () { Alice.playAudio(image, audio) };
});
}
audio.play();
image.onclick = function() {
audio.pause();
this.src = '/static/image/play.png';
this.onclick = function () { Alice.playAudio(this, audio) };
};
},
joinChannel: function() {
var network = $('join_network').value;
var channel = $('join_channel').value;
if (!network || !channel) {
alert("Must select a channel and network!");
return;
}
var win = alice.activeWindow();
alice.connection.sendMessage({
source: win.id,
msg: "/join -"+network+" "+channel
});
alice.input.disabled = false;
$('join').remove();
share/static/alice.js view on Meta::CPAN
},
toggleHelp: function() {
var help = $('help');
help.visible() ? help.hide() : help.show();
},
toggleJoin: function() {
this.connection.get("/join", function (transport) {
this.input.disabled = true;
$('windows').insert(transport.responseText);
}.bind(this));
},
toggleConfig: function(e) {
this.connection.get("/config", function (transport) {
this.input.disabled = true;
$('windows').insert(transport.responseText);
}.bind(this));
if (e) e.stop();
},
togglePrefs: function(e) {
this.connection.get("/prefs", function (transport) {
this.input.disabled = true;
$('windows').insert(transport.responseText);
}.bind(this));
if (e) e.stop();
},
toggleTabsets: function(e) {
this.connection.get("/tabsets", function (transport) {
this.input.disabled = true;
$('windows').insert(transport.responseText);
Alice.tabsets.focusIndex(0);
}.bind(this));
},
windows: function () {
return this.window_map.values();
},
nth_window: function(n) {
var tab = this.tabs.down('.visible:not(.info_tab)', n - 1);
if (tab) {
var m = tab.id.match(/([^_]+)_tab/);
if (m) {
return this.window_map.get(m[1]);
}
}
},
info_window: function(n) {
return this.windows().find(function(win) {
if (win.type == "info") return win;
});
},
openWindow: function(serialized, msgid) {
if (!msgid) msgid = this.msgid();
var win = new Alice.Window(this, serialized, msgid);
this.addWindow(win);
return win;
},
addWindow: function(win) {
this.window_map.set(win.id, win);
if (window.fluid)
window.fluid.addDockMenuItem(win.title, win.focus.bind(win));
},
removeWindow: function(win) {
this.tabs_layout = this.tabs.getLayout();
this.windows().invoke("updateTabLayout");
if (win.active) this.focusLast();
if (window.fluid)
window.fluid.removeDockMenuItem(win.title);
if (win.id == this.previousFocus.id) {
this.previousFocus = 0;
}
this.window_map.unset(win.id);
this.connection.closeWindow(win);
win = null;
},
getWindow: function(windowId) {
return this.window_map.get(windowId);
},
activeWindow: function() {
var windows = this.windows();
for (var i=0; i < windows.length; i++) {
if (windows[i].active) return windows[i];
}
for (var i=0; i < windows.length; i++) {
if (windows[i].type != "info") return windows[i];
}
if (windows[0]) return windows[0];
},
addFilters: function(list) {
this.message_filters = this.message_filters.concat(list);
},
applyFilters: function(li, win) {
if (li.hasClassName("filtered")) return;
var length = this.base_filters.length;
for (var i=0; i < length; i++) {
this.base_filters[i].call(this, li, win);
}
li.addClassName("filtered");
if (li.hasClassName("message")) {
var msg = li.down("div.msg");
var length = this.message_filters.length;
for (var i=0; i < length; i++) {
var stop = this.message_filters[i].call(this, msg, win);
share/static/alice.js view on Meta::CPAN
Sortable.create('tabs', {
overlap: 'horizontal',
constraint: 'horizontal',
format: /(.+)/,
only: ["info_tab", "channel_tab", "privmsg_tab"],
onUpdate: function (res) {
var tabs = res.childElements();
var order = tabs.collect(function(t){
var m = t.id.match(/([^_]+)_tab/);
if (m) return m[1]
});
if (order.length) this.connection.sendTabOrder(order);
setTimeout(function(){
this.windows().invoke("updateTabLayout");
this.activeWindow().shiftTab();
}.bind(this), 100);
}.bind(this)
});
},
addMissed: function() {
if (!window.fluid) return;
window.fluid.dockBadge ? window.fluid.dockBadge++ :
window.fluid.dockBadge = 1;
},
clearMissed: function() {
if (!window.fluid) return;
window.fluid.dockBadge = "";
},
ready: function() {
this.freeze();
setTimeout(this.updateOverflowMenus.bind(this), 1000);
this.fetchOembeds(function() {
this.connection.connect(function() {
this.focusHash() || this.activeWindow().focus();
}.bind(this));
}.bind(this));
},
log: function () {
var win = this.activeWindow();
for (var i=0; i < arguments.length; i++) {
if (window.console && window.console.log) {
console.log(arguments[i]);
}
if (this.options.debug == "true") {
if (win) {
win.addMessage({
html: '<li class="message monospace"><div class="left">console</div><div class="msg">'+arguments[i].toString()+'</div></li>'
});
}
}
}
},
msgid: function() {
var ids = this.windows().map(function(w){return w.msgid});
return Math.max.apply(Math, ids);
},
setSource: function(id) {
$('source').value = id;
},
showSet: function(name) {
var ids = this.tabsets[name];
if (ids) {
var elem = $('tabset_menu').select('li').find(function(li) {
return li.innerHTML.unescapeHTML() == name;
});
elem.up('ul').select('li').invoke('removeClassName', 'selectedset');
elem.addClassName('selectedset');
this.windows().each(function(win) {
ids.indexOf(win.id) >= 0 || win.type == "privmsg" ? win.show() : win.hide();
});
this.selectSet(name);
var active = this.activeWindow();
if (!active.visible) {
active = this.nextWindow();
}
if (active) active.shiftTab();
setTimeout(this.updateOverflowMenus.bind(this), 2000);
}
},
selectSet: function(name) {
var hash = window.location.hash;
hash = hash.replace(/^[^\/]*/, name);
window.location.hash = hash;
window.location = window.location.toString();
this.selectedSet = name;
},
clearSet: function(elem) {
elem.up('ul').select('li').invoke('removeClassName', 'selectedset');
elem.addClassName('selectedset');
this.windows().invoke("show");
this.selectSet('');
this.updateOverflowMenus();
this.activeWindow().shiftTab();
},
currentSetContains: function(win) {
var set = this.selectedSet;
if (win.type == "channel" && set && this.tabsets[set]) {
return (this.tabsets[set].indexOf(win.id) >= 0);
}
return true;
},
displayTopic: function(new_topic) {
this.topic.update(new_topic || "no topic set");
share/static/alice.js view on Meta::CPAN
}
else {
params = form;
}
params['stream'] = this.id;
new Ajax.Request('/say', {
method: 'post',
parameters: params,
on401: this.gotoLogin,
onException: function (request, exception) {
alert("There was an error sending a message.");
}
});
return true;
},
closeConnection: function() {
this.aborting = true;
if (this.request && this.request.transport)
this.request.transport.abort();
this.aborting = false;
},
closeWindow: function(win) {
new Ajax.Request('/say', {
method: 'post',
on401: this.gotoLogin,
parameters: {
source: win.id,
msg: "/close",
stream: this.id
}
});
},
requestWindow: function(title, windowId, message) {
new Ajax.Request('/say', {
method: 'post',
parameters: {
source: windowId,
msg: "/create " + title,
stream: this.id
},
on401: this.gotoLogin,
onSuccess: function (transport) {
this.handleUpdate(transport);
if (message) {
setTimeout(function() {
this.application.displayMessage(message)
}.bind(this), 1000);
}
}.bind(this)
});
}
});
Alice.Window = Class.create({
initialize: function(application, serialized, msgid) {
this.application = application;
this.element = $(serialized['id']);
this.title = serialized['title'];
this.type = serialized['type'];
this.hashtag = serialized['hashtag'];
this.id = this.element.identify();
this.active = false;
this.topic = serialized['topic'];
this.tab = $(this.id + "_tab");
this.tab_layout = this.tab.getLayout();
this.tabButton = $(this.id + "_tab_button");
this.messages = this.element.down('.messages');
this.visibleNick = "";
this.visibleNickTimeout = "";
this.lasttimestamp = new Date(0);
this.nicks = [];
this.nicks_order = [];
this.statuses = [];
this.messageLimit = this.application.isMobile ? 50 : 100;
this.chunkSize = this.messageLimit / 2;
this.msgid = msgid || 0;
this.visible = true;
this.forceScroll = false;
this.lastScrollPosition = 0;
this.setupEvents();
},
hide: function() {
this.element.hide();
this.tab.addClassName('hidden');
this.tab.removeClassName('visible');
this.visible = false;
},
show: function() {
this.element.show();
this.tab.addClassName('visible');
this.tab.removeClassName('hidden');
this.visible = true;
this.updateTabLayout();
},
setupEvents: function() {
this.application.supportsTouch ? this.setupTouchEvents() : this.setupMouseEvents();
},
setupTouchEvents: function() {
this.messages.observe("touchstart", function (e) {
this.showNick(e);
}.bind(this));
this.tab.observe("touchstart", function (e) {
e.stop();
if (!this.active) this.focus();
}.bind(this));
this.tabButton.observe("touchstart", function(e) {
if (this.active) {
e.stop();
confirm("Are you sure you want to close this tab?") && this.close()
}
}.bind(this));
},
setupMouseEvents: function() {
this.tab.observe("mousedown", function(e) {
if (!this.active) {this.focus(); this.focusing = true}
}.bind(this));
this.tab.observe("click", function(e) {this.focusing = false}.bind(this));
this.tabButton.observe("click", function(e) {
if (this.active && !this.focusing)
if (this.type != "channel" || confirm("Are you sure you want to leave "+this.title+"?"))
this.close()
}.bind(this));
this.messages.observe("mouseover", this.showNick.bind(this));
},
checkScrollBack: function() {
if (this.active && this.element.scrollTop == 0) {
clearInterval(this.scrollListener);
var first = this.messages.down("li[id]");
if (first) {
first = first.id.replace("msg-", "") - 1;
this.messageLimit += this.chunkSize;
}
else {
first = this.msgid;
}
this.application.log("requesting chunk" + first);
this.tab.addClassName("loading");
this.application.getBacklog(this, first, this.chunkSize);
}
else {
clearTimeout(this.scrollListener);
this.scrollListener = setTimeout(this.checkScrollBack.bind(this), 1000);
}
},
clearMessages: function() {
clearTimeout(this.scrollListener);
this.messages.update("");
this.lastNick = "";
},
updateTabLayout: function() {
this.tab_layout = this.tab.getLayout();
},
getTabPosition: function() {
var shift = this.application.tabShift();
var tabs_width = this.application.tabsWidth();
var tab_width = this.tab_layout.get("width");
var offset_left = this.tab_layout.get("left") + shift;
var offset_right = tabs_width - (offset_left + tab_width);
var overflow_right = Math.abs(Math.min(0, offset_right));
var overflow_left = Math.abs(Math.min(0, offset_left));
return {
right: overflow_right,
left: overflow_left
};
},
shiftTab: function() {
var left = null
, time = 0
, pos = this.getTabPosition();
if (pos.left) {
this.application.shiftTabs(pos.left);
}
else if (pos.right) {
this.application.shiftTabs(-pos.right);
}
},
unFocus: function() {
this.lastScrollPosition = this.captureScrollPosition();
this.active = false;
this.element.removeClassName('active');
this.tab.removeClassName('active');
clearTimeout(this.scrollListener);
this.addFold();
},
share/static/alice.js view on Meta::CPAN
if (classname) classes.push(classname);
classes.each(function(c){this.tab.addClassName(c)}.bind(this));
this.application.highlightChannelSelect(this.id, classes);
this.statuses = classes;
},
disable: function () {
this.markRead();
this.tab.addClassName('disabled');
},
enable: function () {
this.tab.removeClassName('disabled');
},
close: function(event) {
this.tab.remove();
this.element.remove();
this.application.removeWindow(this);
},
showHappyAlert: function (message) {
this.messages.insert(
"<li class='event happynotice'><div class='msg'>"+message+"</div></li>"
);
this.scrollToPosition(0);
},
showAlert: function (message) {
this.messages.insert(
"<li class='event notice'><div class='msg'>"+message+"</div></li>"
);
this.scrollToPosition(0);
},
announce: function (message) {
message = message.escapeHTML();
this.messages.insert(
"<li class='message monospaced announce'><div class='msg'>"+message+"</div></li>"
);
this.scrollToPosition(0);
},
trimMessages: function() {
this.messages.select("li").reverse().slice(this.messageLimit).invoke("remove");
},
addChunk: function(chunk) {
if (chunk.nicks) this.updateNicks(chunk.nicks);
clearTimeout(this.scrollListener);
if (chunk.range.length == 0) {
this.scrollBackEmpty = true;
this.tab.removeClassName("loading");
return;
}
var position = this.captureScrollPosition();
if (chunk['range'][0] > this.msgid) {
this.messages.insert({"bottom": chunk['html']});
this.trimMessages();
this.msgid = chunk['range'][1];
}
else {
this.bulk_insert = true;
this.messages.insert({"top": chunk['html']});
}
this.messages.select("li:not(.filtered)").each(function (li) {
this.application.applyFilters(li, this);
}.bind(this));
this.bulk_insert = false;
this.scrollToPosition(position);
setTimeout(function(){this.removeClassName("loading")}.bind(this.tab), 1000);
this.scrollListener = setTimeout(this.checkScrollBack.bind(this), 1000);
},
addMessage: function(message) {
if (!message.html || message.msgid <= this.msgid) return;
if (message.msgid) this.msgid = message.msgid;
if (message.nicks) this.updateNicks(message.nicks);
var position = this.captureScrollPosition();
this.messages.insert(message.html);
this.trimMessages();
this.scrollToPosition(position);
var li = this.messages.select("li").last();
this.application.applyFilters(li, this);
this.scrollToPosition(position);
if (message.event == "topic") {
this.topic = message.body;
if (this.active) this.application.displayTopic(this.topic);
}
this.element.redraw();
this.promoteNick(message.nick);
},
promoteNick: function(nick) {
if (this.nicks_order.last() == nick) return;
var index = this.nicks_order.indexOf(nick);
if (index > -1) this.nicks_order.splice(index, 1);
this.nicks_order.push(nick);
},
captureScrollPosition: function() {
if (!this.active) return;
if (this.forceScroll) return 0;
var bottom = this.element.scrollTop + this.element.offsetHeight;
var height = this.element.scrollHeight;
return height - bottom;
},
scrollToPosition: function(position) {
if (!this.active) return;
this.element.scrollTop = this.element.scrollHeight - this.element.offsetHeight - position;
},
getNicknames: function () {
return this.nicks.sort(function(a, b) {
var pos_a = this.nicks_order.indexOf(a),
pos_b = this.nicks_order.indexOf(b);
if (pos_a == pos_b)
return a.toLowerCase().localeCompare(b.toLowerCase());
else if (pos_a > pos_b)
return -1;
else if (pos_a < pos_b)
return 1;
( run in 0.490 second using v1.01-cache-2.11-cpan-5735350b133 )