function message(inParent, inID, inAccountID, inUsername, inTimeAgo, inMessage, inReplies) {
this.idString = function() {
// Generate id string for divs associated with this object
if (this.isRoot())
return "root";
else
return this.id;
} // function idString
this.isRoot = function() {
return (typeof(this.parent) === "undefined")
} // function isRoot
this.increaseReplies = function() {
// The number of replies isn't reported for the root
if (this.isRoot())
return true;
// Increase replies
this.replies++;
document.getElementById('discussion_msg' + this.idString() + '_numreplies').innerHTML = this.replies + ' replies';
} // function increaseReplies
this.updateRepliesLeft = function(inRepliesLeft) {
// Update replies
this.repliesLeft = inRepliesLeft;
// If there are no replies left hide the button
if (inRepliesLeft <= 0) {
document.getElementById('discussion_msg' + this.idString() + '_repliesleft').style.display = 'none';
}
// Otherwise display the button
else {
if (this.isRoot())
document.getElementById('discussion_msg' + this.idString() + '_repliesleft').innerHTML = 'load more messages (' + inRepliesLeft + ')';
else
document.getElementById('discussion_msg' + this.idString() + '_repliesleft').innerHTML = 'load more replies (' + inRepliesLeft + ')';
}
} // function updateRepliesLeft
this.hidePostingReply = function() {
document.getElementById('discussion_msg' + this.idString() + '_postingreply').style.display = 'none';
}
this.showPostingReply = function() {
document.getElementById('discussion_msg' + this.idString() + '_postingreply').style.display = 'block';
}
this.hideLoadingReplies = function() {
document.getElementById('discussion_msg' + this.idString() + '_loadingreplies').style.display = 'none';
}
this.showLoadingReplies = function() {
document.getElementById('discussion_msg' + this.idString() + '_loadingreplies').style.display = 'block';
}
this.loadChildren = function(inStartAfterMessageID, inEndOnMessageID) {
// Say loading
this.showLoadingReplies();
// Set up http request object
var http;
if (XMLHttpRequest)
http = new XMLHttpRequest();
else if (ActiveXObject)
http = new ActiveXObject("Microsoft.XMLHTTP");
// Pass the message ID if this isn't the root
var paramMessageID = '';
if (!this.isRoot())
paramMessageID = '&mid=' + this.id;
// Are we starting after a message id?
var paramStartAfter = '';
if (typeof(inStartAfterMessageID) !== 'undefined')
paramStartAfter = '&startafter=' + inStartAfterMessageID;
// Are we ending on a message id?
var paramEndOn = '';
if (typeof(inStartAfterMessageID) !== 'undefined')
paramEndOn = '&endon=' + inEndOnMessageID;
// Request data
http.open('GET', 'http://' + domain() + '/ajax/discussion_getreplies.php?did=' + globalDiscussionID + paramMessageID + paramStartAfter + paramEndOn);
http.onreadystatechange = function (inParentID) { return function() {
// When ready with data
if (http.readyState == 4) {
// Get the parent message object (needed even if error to hide loading text)
parentMessage = globalRootMessage;
if (inParentID != null)
parentMessage = globalRootMessage.getMessageByID(inParentID);
// Success
if (http.status == 200) {
// Check for an error
var error = http.responseXML.getElementsByTagName("error");
if (error.item(0) != null) {
alert('Error: ' + error.item(0).childNodes[0].nodeValue);
}
else {
// Load XML and determine which message the replies are for
var root = http.responseXML.getElementsByTagName("replies").item(0);
var parentMessage;
// Add each message
for (var i = 0; i < root.getElementsByTagName("reply").length; i++) {
// Create the div for this message
document.getElementById('discussion_msg' + parentMessage.idString() + '_replies').innerHTML +=
'
';
// Create the message object, which sets up the html
parentMessage.children.push( new message( parentMessage,
root.getElementsByTagName("reply").item(i).getAttribute('id'),
root.getElementsByTagName("reply").item(i).getAttribute('accountid'),
root.getElementsByTagName("reply").item(i).getAttribute('username'),
root.getElementsByTagName("reply").item(i).getAttribute('timeago'),
root.getElementsByTagName("reply").item(i).childNodes[0].nodeValue,
root.getElementsByTagName("reply").item(i).getAttribute('replies')
));
// Pulse the child
parentMessage.children[parentMessage.children.length - 1].pulseTitle();
}
// Mark some messages as loaded
parentMessage.loadedSomeReplies = true;
// Set the number of messages remaining to load
parentMessage.updateRepliesLeft(root.getAttribute('repliesleft'));
// If this is part of an initial load sequence then keep going or display the messages
if (typeof(window.globalMessageLoadSequence) !== 'undefined' && window.globalMessageLoadSequence.length > 0) {
// Check that the message was loaded properly
var curMID = window.globalMessageLoadSequence.shift();
if (!globalRootMessage.getMessageByID(curMID)) {
alert('Error loading message.');
return false;
}
// Show the replies
globalRootMessage.getMessageByID(curMID).parent.showReplies();
// No problem -- show the messages or load the next message
if (window.globalMessageLoadSequence.length > 0) {
globalRootMessage.getMessageByID(curMID).loadChildren(null, window.globalMessageLoadSequence[0]);
}
else {
document.getElementById('discussion_loading').style.display = 'none';
document.getElementById('discussion_msgroot').style.display = 'block';
globalRootMessage.getMessageByID(curMID).highlight();
globalRootMessage.getMessageByID(curMID).scrollTo();
globalPulsingEnabled = true;
}
}
else {
// Initial load over -- allow pulsing
globalPulsingEnabled = true;
}
}
}
// Failure
else {
alert('Error retrieving messages.');
}
// Hide loading icon
parentMessage.hideLoadingReplies();
// Check if there are any messages and if not show "no messages"
globalRootMessage.updateNoMessagesText();
}
}}(this.id); // Pass parameters to return function
http.send(null);
} // function loadChildren
this.updateNoMessagesText = function() {
// Check if there are any messages and if not show "no messages"
if (globalRootMessage.children.length == 0)
document.getElementById('discussion_empty').style.display = 'block';
else
document.getElementById('discussion_empty').style.display = 'none';
} // function updateNoMessagesText
this.setHTML = function() {
// If this is the root then over-ride the margin-left style
var marginText = '';
if (this.isRoot())
marginText = ' style="margin-left: 0;"';
// Set HMTL: anchor name
buildHTML = '';
buildHTML += '';
// Set HTML: title
if (!this.isRoot()) {
buildHTML += '';
}
// Set HTML: message
if (!this.isRoot()) {
buildHTML += '' + this.message + '
';
}
// Set HTML: actions
buildHTML += '';
if (!this.isRoot()) {
// Highlight the number of replies if there are some
var numRepliesStyle = '';
if (this.replies > 0)
numRepliesStyle = 'border-bottom: 1px solid #900;';
// Add to HTML
buildHTML += '
' + this.replies + ' replies';
if (globalLoggedIn) {
buildHTML += '
reply';
}
}
else {
if (globalLoggedIn) {
buildHTML += '
post message';
}
else {
buildHTML += 'You must be logged in to post a message.';
}
}
buildHTML += '
';
// Set HTML: replyform
if (globalLoggedIn) {
buildHTML += '';
}
// Set HTML: postingreply
buildHTML += '';
buildHTML += '
Posting reply...
';
buildHTML += '
';
buildHTML += '
';
// Set HTML: replies
buildHTML += '';
// Set HTML: loadingreplies
buildHTML += '';
buildHTML += '
Loading messages...
';
buildHTML += '
';
buildHTML += '
';
// Set HTML: morereplies
buildHTML += '';
if (this.isRoot()) {
buildHTML += '
';
}
else {
buildHTML += '
';
}
buildHTML += '
';
// Set HTML
document.getElementById('discussion_msg' + this.idString()).innerHTML = buildHTML;
}
this.postReply = function() {
// Check if a reply was entered
if (document.getElementById("discussion_msg" + this.idString() + "_replytext").value == '') {
alert('Please enter a message.');
document.getElementById("discussion_msg" + this.idString() + "_replytext").focus();
return false;
}
// Say posting reply
this.showPostingReply();
// Set up http request object
var http;
if (XMLHttpRequest)
http = new XMLHttpRequest();
else if (ActiveXObject)
http = new ActiveXObject("Microsoft.XMLHTTP");
// Set up parameters
var params = 'did=' + globalDiscussionID;
if (!this.isRoot())
params += '&pid=' + this.id;
params += '&message=' + encodeURIComponent(document.getElementById("discussion_msg" + this.idString() + "_replytext").value);
// Request
http.open("POST", 'http://' + domain() + '/ajax/discussion_post.php', true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function (inParentID, inReplyText) { return function() {
// When ready with data
if (http.readyState == 4) {
// Get the parent message object (needed even if error to hide loading text)
var parentMessage = globalRootMessage;
if (inParentID != null)
parentMessage = globalRootMessage.getMessageByID(inParentID);
// Success
if (http.status == 200) {
// Check for an error
var error = http.responseXML.getElementsByTagName("error");
if (error.item(0) != null) {
alert('Error: ' + error.item(0).childNodes[0].nodeValue);
}
else {
// Load XML and determine which message the reply is for
var root = http.responseXML.getElementsByTagName("success").item(0);
var newMessageID = root.getAttribute("id");
// Create the div for this message at the beginning of the container
document.getElementById('discussion_msg' + parentMessage.idString() + '_replies').innerHTML =
''
+ document.getElementById('discussion_msg' + parentMessage.idString() + '_replies').innerHTML;
// Add the object to the beginning of children array (creates its own html)
for (var i = parentMessage.children.length; i > 0; i--)
parentMessage.children[i] = parentMessage.children[i-1]
parentMessage.children[0] = new message( parentMessage,
newMessageID,
globalAccountID,
globalUsername,
'0 minutes ago',
htmlspecialchars(inReplyText),
0
);
// Increase the number of replies
parentMessage.increaseReplies();
// Pulse reply title or parent num replies depending on whether replies are visible
if (document.getElementById('discussion_msg' + parentMessage.idString() + '_replies').style.display != 'block')
parentMessage.pulseNumReplies();
else
parentMessage.children[0].pulseTitle();
}
}
// Failure
else {
alert('Error posting message.');
}
// Check if there are any messages and if not show "no messages"
globalRootMessage.updateNoMessagesText();
// Hide 'posting reply' message
parentMessage.hidePostingReply();
}
} }(this.id, document.getElementById("discussion_msg" + this.idString() + "_replytext").value); // Pass parameters to onreadystatechange
http.send(params);
// Reset and hide the reply form
document.getElementById("discussion_msg" + this.idString() + "_replytext").value = '';
this.hideReplyForm(false);
} // function postReply
this.loadMoreReplies = function() {
this.loadChildren(this.children[this.children.length-1].id);
} // function loadMoreReplies
this.toggleReplyForm = function(inPulse) {
// Switch visibility
if (document.getElementById('discussion_msg' + this.idString() + '_replyform').style.display != 'block')
this.showReplyForm(inPulse);
else
this.hideReplyForm(inPulse);
} // function toggleReplyForm
this.showReplyForm = function(inPulse) {
// Switch visibility
document.getElementById('discussion_msg' + this.idString() + '_replyform').style.display = 'block';
// Set focus
document.getElementById('discussion_msg' + this.idString() + '_replytext').focus();
// Pulse the reply form title
if (typeof(inPulse) !== 'undefined' && inPulse == true)
this.pulseReplyFormTitle();
} // function showReplyForm
this.hideReplyForm = function(inPulse) {
// Switch visibility
document.getElementById('discussion_msg' + this.idString() + '_replyform').style.display = 'none';
// Pulse title
if (typeof(inPulse) !== 'undefined' && inPulse == true)
this.pulseTitle();
} // function hideReplyForm
this.showReplies = function() {
// If there are no replies then abort
// Except root, since we don't know how many replies there are
if (this.replies <= 0 && !this.isRoot())
return true;
// Load children if necessary
if (!this.loadedSomeReplies)
this.loadChildren();
// Show replies and "more replies" button
var replies = document.getElementById('discussion_msg' + this.idString() + '_replies');
var moreReplies = document.getElementById('discussion_msg' + this.idString() + '_morereplies');
replies.style.display = 'block';
moreReplies.style.display = 'block';
// Pulse all the replies
for (i = 0; i < this.children.length; i++)
this.children[i].pulseTitle();
} // function showReplies
this.hideReplies = function() {
var replies = document.getElementById('discussion_msg' + this.idString() + '_replies');
var moreReplies = document.getElementById('discussion_msg' + this.idString() + '_morereplies');
replies.style.display = 'none';
moreReplies.style.display = 'none';
this.pulseTitle();
} // function hideReplies
this.toggleReplies = function() {
if (document.getElementById('discussion_msg' + this.idString() + '_replies').style.display != 'block') {
this.showReplies();
}
else {
this.hideReplies();
}
} // function toggleReplies
this.getMessageByID = function(inMessageID) {
// If this is the message return self, otherwise recurse on children
if (inMessageID == this.id || (inMessageID == 'root' && this.isRoot())) {
return this;
}
else {
for (key in this.children) {
var res = this.children[key].getMessageByID(inMessageID);
if (res)
return res;
}
}
return false;
} // function getMessageByID
this.loadDescendentByID = function(inID) {
// Hide the discussion and show the loading notice
document.getElementById('discussion_loading').style.display = 'block';
document.getElementById('discussion_msgroot').style.display = 'none';
// Set up http request object to get ancestor IDs
var http;
if (XMLHttpRequest)
http = new XMLHttpRequest();
else if (ActiveXObject)
http = new ActiveXObject("Microsoft.XMLHTTP");
// Request data
http.open('GET', 'http://' + domain() + '/ajax/discussion_getancestorids.php?mid=' + inID);
http.onreadystatechange = function () {
// When ready with data
if (http.readyState == 4) {
// Success
if (http.status == 200) {
// Load XML and cycle through ancestor ids
var root = http.responseXML.getElementsByTagName("ids").item(0);
// Add each ancestor id
window.globalMessageLoadSequence = [];
for (var i = 0; i < root.getElementsByTagName("id").length; i++)
window.globalMessageLoadSequence.push(root.getElementsByTagName("id").item(i).childNodes[0].nodeValue);
window.globalMessageLoadSequence.push(inID);
// Start loading the first message
globalRootMessage.loadChildren(null, window.globalMessageLoadSequence[0]);
}
// Failure
else {
// Alert error
alert('Error displaying message.');
// Hide loading display
globalRootMessage.updateNoMessagesText();
document.getElementById('discussion_loading').style.display = 'none';
document.getElementById('discussion_msgroot').style.display = 'block';
}
}
}
http.send(null);
} // function loadDescendentByID
this.scrollTo = function() {
// curLocation = window.location.href;
// window.location = curLocation.substring(0, curLocation.indexOf('#') - 1) + '#msg_' + this.idString();
window.location.href = '#msg_' + this.idString();
} // function scrollTo
this.highlight = function() {
document.getElementById('discussion_msg' + this.idString() + '_title').style.backgroundColor = '#161616';
} // function highlight
this.pulseTitle = function() {
// No pulsing the root
if (!this.isRoot() && globalPulsingEnabled == true)
pulse('discussion_msg' + this.idString() + '_title');
} // function pulseTitle
this.pulseReplyFormTitle = function() {
if (globalPulsingEnabled == true)
pulse('discussion_msg' + this.idString() + '_replyformtitle');
} // function pulseReplyFormTitle
this.pulseNumReplies = function() {
if (globalPulsingEnabled == true)
pulse('discussion_msg' + this.idString() + '_numreplies');
} // function pulseNumReplies
// Constructor
this.children = [];
this.loadedSomeReplies = false;
// These variables are null for the root message object
if (typeof(inParent) !== "undefined") {
this.parent = inParent;
this.id = inID;
this.accountID = inAccountID;
this.username = inUsername;
this.timeAgo = inTimeAgo;
this.message = inMessage; // This will contain markdown HTML and no user HTML -- do not escape
this.replies = inReplies;
}
// Set up the HTML
this.setHTML();
}
function pulse(inDivID) {
pulseIteration(inDivID, 1);
} // function pulse
function pulseIteration(inDivID, inIterationNumber) {
// Set max iterations
var maxIterations = 35;
// Set the new color
var rgb = Math.round(35 * (1 - inIterationNumber / maxIterations) + 3);
var bgColor = 'rgb(' + rgb + ', ' + rgb + ', ' + rgb + ')';
document.getElementById(inDivID).style.backgroundColor = bgColor;
// Continue iterating if necessary or reset background color
if (inIterationNumber < maxIterations)
setTimeout('pulseIteration("' + inDivID + '", ' + (inIterationNumber + 1) + ');', 50);
else
document.getElementById(inDivID).style.backgroundColor = '';
} // function pulseIteration