Skip to content

Instantly share code, notes, and snippets.

@roykolak
Forked from tmm1/README.md
Created February 11, 2011 20:33
Show Gist options
  • Save roykolak/822968 to your computer and use it in GitHub Desktop.
Save roykolak/822968 to your computer and use it in GitHub Desktop.

Screenshots

Use it

Propane 1.1.0

Install

curl https://gist.github.com/raw/820001/enhancer.js > /Applications/Propane.app/Contents/Resources/enhancer.js
echo >> /Applications/Propane.app/Contents/Resources/enhancer.js
curl https://gist.github.com/raw/820001/avatars.js >> /Applications/Propane.app/Contents/Resources/enhancer.js

Uninstall

curl https://gist.github.com/raw/820001/enhancer.js > /Applications/Propane.app/Contents/Resources/enhancer.js

Propane 1.1.1 pre-build (download)

Install

mkdir -p ~/Library/Application\ Support/Propane/unsupported/
curl https://gist.github.com/raw/820001/avatars.js > ~/Library/Application\ Support/Propane/unsupported/caveatPatchor.js

Uninstall

rm ~/Library/Application\ Support/Propane/unsupported/caveatPatchor.js
var displayAvatars = true;
if (displayAvatars) {
Object.extend(Campfire.Chat.prototype, {
installResponder: function(name) {
var slug = name.toLowerCase();
if (this[slug] == null) {
Campfire.Responders.push(name);
this[slug] = new Campfire[name](this);
this.listeners.push(this[slug]);
}
}
});
Object.extend(Campfire.Message.prototype, {
authorID: function() {
if (Element.hasClassName(this.element, 'you'))
return this.chat.userID;
var idtext = (this.element.className.match(/\s*user_(\d+)\s*/) || [])[1];
return parseInt(idtext) || 0;
},
addAvatar: function() {
if (this.actsLikeTextMessage()) {
var author = this.authorElement(),
avatar = '';
if (author.visible()) {
author.hide()
if (this.bodyCell.select('strong').length == 0) {
this.bodyCell.insert({top: '<strong>'+this.author()+'</strong><br>'})
this.bodyCell.insert({top: 'authorid: this.authorID()'})
if (false) {
avatar = 'http://globase.heroku.com/redirect/gh.gravatars.' + this.authorID() + '?default=https://github.com/images/gravatars/gravatar-140.png';
} else {
avatar = author.getAttribute('data-avatar') || 'http://asset1.37img.com/global/missing/avatar.png?r=3';
}
author.insert({after: '<img alt="'+this.author()+'" width="32" height="32" align="top" style="margin-left: 5px; border-radius:3px" src="'+avatar+'">'});
}
}
}
}
});
if (!swizzle) {
/* This is the same as Campfire's inbuild augment() function that is defined for mobile safari*/
function swizzle(klass, methods) {
var wrappedMethods = {}, methodName;
for (methodName in methods) {
wrappedMethods[methodName] = klass.prototype[methodName].wrap(methods[methodName]);
}
klass.addMethods(wrappedMethods);
}
}
/* if you can wrap rather than rewrite, use swizzle like this: */
swizzle(Campfire.Message, {
setAuthorVisibilityInRelationTo: function($super, message) {
$super(message)
this.addAvatar();
}
});
/* defining a new responder is probably the best way to insulate your hacks from Campfire and Propane */
Campfire.AvatarMangler = Class.create({
initialize: function(chat) {
this.chat = chat;
chat.transcript.element.childElements().each(function(elem){
if (elem.match('tr.message')) {
var msg = new Campfire.Message(chat, elem)
msg.addAvatar()
}
})
this.chat.layoutmanager.layout();
this.chat.windowmanager.scrollToBottom();
},
onMessagesInserted: function(messages) {
var scrolledToBottom = this.chat.windowmanager.isScrolledToBottom();
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
message.addAvatar();
}
if (scrolledToBottom)
this.chat.windowmanager.scrollToBottom();
}
});
/* Here is how to install your responder into the running chat */
window.chat.installResponder("AvatarMangler");
}
if (window.propane) {
Object.extend(Campfire.Chat.prototype, {
installPropaneResponder: function() {
if (this["propaneresponder"] == null) {
this["propaneresponder"] = new Campfire["PropaneResponder"](this);
this.listeners.push(this["propaneresponder"]);
}
},
});
Object.extend(Campfire.LayoutManager.prototype, {
getChatAuthorColumnWidth: function() {
var element = this.firstVisibleMessageBodyElement();
if (!element) return 0;
return Position.cumulativeOffset(element)[0] -
Position.cumulativeOffset(this.chat.transcript.element)[0];
},
firstVisibleMessageBodyElement: function() {
var messages = this.chat.transcript.messages;
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
if (!message.element.hasClassName('propane_hidden_enterleave') && message.element.visible()) {
return message.element.getElementsByTagName('td')[1];
}
}
return null;
}
});
Object.extend(Campfire.SoundManager.prototype, {
play: function(sound, force) {
if (!force) return;
window.propane.playCampfireSound(sound);
}
});
Object.extend(Campfire.Transcript.prototype, {
highlightMessageByID: function(message_id) {
try {
var cell = this.bodyCellByMessageID(message_id);
if (cell != null) {
cell.visualEffect("highlight", { duration: 2 });
}
} catch (e) {
}
},
bodyCellByMessageID: function(message_id) {
try {
var message = this.getMessageById(message_id);
if (message != null) {
return message.bodyCell;
}
} catch (e) {
}
return null;
}
});
Campfire.PropaneResponder = Class.create({
initialize: function(chat) {
this.chat = chat;
},
authorID: function(message) {
if (Element.hasClassName(message.element, 'you'))
return this.chat.userID;
var idtext = (message.element.className.match(/\s*user_(\d+)\s*/) || [])[1];
return parseInt(idtext) || 0;
},
onMessageAccepted: function(element, messageID) {
window.propane.messageAccepted(messageID);
},
onMessagesInsertedBeforeDisplay: function(messages) {
if (!window.propane.hideEnterLeaveMessages()) {
return;
}
if (!window.propane.notifyEnterLeaveMessages()) {
this.hideEnterLeaveForMessages(messages);
return;
}
if (this.lastHiddenTimestamp && messages[0].kind != 'timestamp') {
this.lastHiddenTimestamp.element.removeClassName('propane_hidden_enterleave');
}
this.lastHiddenTimestamp = null;
this.lastVisibleTimestamp = null;
},
onMessagesInserted: function(messages) {
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
var body;
try {
if (message.kind == "upload") {
body = message.bodyCell.querySelector("a").getAttribute('href');
}
else if (message.kind == "sound") {
body = message.getSound();
}
else {
var bodyElement = message.bodyElement();
var bodyElementImage = bodyElement.querySelector("img");
if (message.kind == "text" && bodyElementImage != null) {
body = bodyElementImage.src;
} else {
body = bodyElement.textContent;
}
}
} catch (e) {
body = "";
}
var authorText = null;
if (message.kind != 'timestamp') {
authorText = message.author();
}
window.propane.messageInserted(message.id(), this.authorID(message), authorText, message.kind, body);
}
},
hideEnterLeave: function() {
this.lastVisibleTimestamp = null;
this.lastHiddenTimestamp = null;
var messages = this.chat.transcript.messages;
this.hideEnterLeaveForMessages(messages);
},
noteVisibleTimestamp: function(timestampMessage) {
timestampMessage.setAuthorVisibilityInRelationTo(this.lastVisibleTimestamp);
timestampMessage.element.removeClassName('propane_hidden_enterleave');
this.lastVisibleTimestamp = timestampMessage;
this.lastHiddenTimestamp = null;
},
noteHiddenTimestamp: function(timestampMessage) {
timestampMessage.element.addClassName('propane_hidden_enterleave');
this.lastHiddenTimestamp = timestampMessage;
},
hideEnterLeaveForMessages: function(messages) {
var latestTimestamp = null;
var stampable = false;
if (this.lastHiddenTimestamp) {
latestTimestamp = this.lastHiddenTimestamp;
} else if (this.lastVisibleTimestamp) {
latestTimestamp = this.lastVisibleTimestamp;
stampable = true;
}
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
if (message.kind == 'timestamp') {
if (latestTimestamp) {
if (stampable) {
this.noteVisibleTimestamp(latestTimestamp);
} else {
this.noteHiddenTimestamp(latestTimestamp);
}
}
latestTimestamp = message;
stampable = false;
} else if (message.kind == 'enter' || message.kind == 'leave' || message.kind == 'kick') {
message.element.addClassName('propane_hidden_enterleave');
} else {
stampable = true;
}
}
if (latestTimestamp) {
if (stampable) {
this.noteVisibleTimestamp(latestTimestamp);
} else {
this.noteHiddenTimestamp(latestTimestamp);
}
}
this.chat.layoutmanager.layout();
},
showEnterLeave: function() {
var scrolledToBottom = this.chat.windowmanager.isScrolledToBottom();
this.lastVisibleTimestamp = null;
this.lastHiddenTimestamp = null;
var latestTimestamp = null;
var messages = this.chat.transcript.messages;
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
if (message.kind == 'timestamp') {
message.setAuthorVisibilityInRelationTo(latestTimestamp);
message.element.removeClassName('propane_hidden_enterleave');
latestTimestamp = message;
} else if (message.kind == 'enter' || message.kind == 'leave' || message.kind == 'kick') {
message.element.removeClassName('propane_hidden_enterleave');
}
}
this.chat.layoutmanager.layout();
if (scrolledToBottom) {
this.chat.windowmanager.scrollToBottom();
}
},
});
/*
Want to be notified as soon as participants change - DOM mutation events
are a pain in the arse because they get fired too soon and too often.
So I'm going to be evil instead.
*/
Ajax.Responders.register({
onComplete: function(response){
try {
var responseText = response.transport.responseText;
if (responseText != null && responseText.match(/Element.update\("participants"/)) {
window.propane.participantsUpdated();
} else if (responseText != null && responseText.match(/Element.update\("conference_control"/)) {
window.propane.conferenceUpdated();
}
} catch (e) {
// do nothing
}
}
});
Campfire.Responders.push("PropaneResponder");
window.chat.installPropaneResponder();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment