// 20070416 1725// Gregory's script; used to display a comment form and preview/submit the comment via XMLHttpRequest (ie, ajax)// www.gregory.hk// much of the code here is based on the sample given in Ajax in Action page 62 "The full lifecycle".// some of the logic is based on Movalog's SimpleThreaded plugin js code.var req = null;var previewORpost = null;// var READY_STATE_UNINITIALIZED = 0;// var READY_STATE_LOADING = 1;// var READY_STATE_LOADED = 2;// var READY_STATE_INTERACTIVE = 3;var READY_STATE_COMPLETE = 4;function respond (parent_id, parent_subject, parent_author) {	var el, txt;	// preset the parent values	if ( parent_id == 0 ) {		// new comment regarding the article.		el = document.getElementById ( 'cmt-form-header-parent' );		el.innerHTML = 'Create a new comment regarding the article: <em>' + parent_subject + '</em>';		// hide the parent comment text div		hide ( 'cmt-form-parent-cmtTxt' );		}	else {		// responding to a comment.		if ( parent_subject == '' && parent_author == '' )			txt = 'Respond to the specified comment:';		else {			txt = 'Respond to the comment';			if ( parent_subject != '' )				txt += ' <em>' + parent_subject + '</em>';			if ( parent_author != '' )				txt += ' posted by <em>' + parent_author + '</em>';			}		el = document.getElementById ('cmt-form-header-parent');		el.innerHTML = txt;				el = document.getElementById ( 'cmt-form-parent-cmtTxt' );		txt = document.getElementById ( 'comment-' + parent_id + '-body' );		el.innerHTML = txt.innerHTML;		}		// preset the form values	el = document.getElementById ( 'cmt-form-fld-parentId' );	el.value = parent_id;		// I have opted NOT to preset the subject field because it's usually a repeat	// of the parent comment's subject and therefore just a waste of space.	// if the subject is important, the author will specify it.		// 'turn off' the <select> elements	hideSelect();	// display the form	show ( 'cmt-form', 'block' );	// set the focus	el = document.getElementById ( 'cmt-form-fld-author' );	el.focus();	}function hide ( id ) {	var el = document.getElementById ( id );	if ( !el ) return false;	el.style.display = 'none';	}function show ( id, displayType ) {	var el = document.getElementById ( id );	if ( !el ) return false;	el.style.display = displayType;	}// IE <select> elements have a z-index bug.// they will 'burn through' any object above them including my form background divs.function hideSelect() {	if ( document.all ) {		var selectElements = document.all.tags('select');		for ( i=0; i<selectElements.length; i++ )			selectElements[i].style.visibility="hidden";		}	}function showSelect() {	if ( document.all ) {		var selectElements = document.all.tags('select');		for ( i=0; i<selectElements.length; i++ )			selectElements[i].style.visibility="visible";		}	}function resetBlockElement ( id ) {	var el = document.getElementById ( id );	if ( !el ) return false;	el.innerHTML = '';	}function resetFieldValue ( id ) {	var el = document.getElementById ( id );	if ( !el ) return false;	el.value = '';	}function previewComment () {	// posts the data to the server and displays the preview response.	// the preview is generated by the MT Comment Preview Template	// which has been trimmed down to only return the necessary information.	if ( !verifyParams() ) return false;	// apparently, MT requires the presence of the 'preview' param's value	// otherwise it returns the Comment Listing template instead of the Comment Preview template.	var params = 'preview=Preview' + assembleParams();	previewORpost = 'preview';	sendRequest ( params );		// post processing is handled by the onReadyState() function	}function displayPreview( cmtHtml ) {	var el;	// hide the form fields	hide ( 'cmt-form-newCmtData' );	hide ( 'cmt-form-errorDiv' );		// show the Previewing header	show ('cmt-form-header-previewing', 'block' );	// populate and show the preview div	el = document.getElementById ( 'cmt-form-previewDiv' );	el.innerHTML = cmtHtml;	show ( 'cmt-form-previewDiv', 'block' );	// hide the preview button and show the other buttons.	show ( 'cmt-form-btn-cancel', 'inline' );	show ( 'cmt-form-btn-edit', 'inline' );	hide ( 'cmt-form-btn-preview' );	show ( 'cmt-form-btn-post', 'inline' );	}function editComment() {	var el;		// hide the preview header and div	hide ( 'cmt-form-header-previewing' );	hide ( 'cmt-form-previewDiv' );	hide ( 'cmt-form-errorDiv' );	// show the form fields	show ( 'cmt-form-newCmtData', 'block' );		// hide the edit button and show the other buttons.	hide ( 'cmt-form-btn-edit' );	show ( 'cmt-form-btn-cancel', 'inline' );	show ( 'cmt-form-btn-preview', 'inline' );	show ( 'cmt-form-btn-post', 'inline' );	}function postComment () {	// posts the data to the server.	if ( !verifyParams() ) return false;		// apparently, MT requires the presence of the 'preview' param's value	// otherwise it returns the Comment Listing template instead of the Comment Preview template.	var params = 'post=Post' + assembleParams();	previewORpost = 'post';	sendRequest ( params );		// post processing is handled by the onReadyState() function	}function appendComment ( cmtHtml ) {	// posting would be best done followed by a reload.	// use the parent comment id to set the scroll position #hash.	// if it's an article comment, scroll down to the last comment.		var el, parent_id, preTxt, postTxt;		// we need the parent_id	el = document.getElementById ( 'cmt-form-fld-parentId' );	parent_id = el.value;		// is the comment in response to the article?	if ( parent_id == 0 ) {		// encase the comment code inside the required divs		preTxt = '<div class="comment-parent">\n<div class="comments-body">\n';		postTxt = '</div>\n</div>\n';		// append the comment code to comments_list		el = document.getElementById ( 'comments-list' );		el.innerHTML += ( preTxt + cmtHtml + postTxt );		}	else {		// does the parent comment already have children?		el = document.getElementById ( 'comment-' + parent_id + '-children' );		if ( el ) {			// encase the comment code inside the required divs			preTxt = '<div class="comments-child">\n<div class="comments-body">\n';			postTxt = '</div>\n</div>\n';			// append the comment as a comment child to the children div			el.innerHTML += ( preTxt + cmtHtml + postTxt );			}		else {			// the parent comment does not have children.			preTxt = '<div class="comments-children">\n<div class="comments-child">\n<div class="comments-body">\n';			postTxt = '</div>\n</div>\n</div>\n';			// is the parent comment a child of another comment?			el = document.getElementById ( 'comment-' + parent_id + '-child' );			if ( el ) {				// the parent comment is a child without children.				// append the comment as a child within a children div				el.innerHTML += ( preTxt + cmtHtml + postTxt );				}			else {				// the parent comment is a top level 'parent' comment.				el = document.getElementById ( 'comment-' + parent_id + '-parent' );				el.innerHTML += ( preTxt + cmtHtml + postTxt );				}			}		}		// hide form -- ie, cancelComment()	cancelComment();	}function displayError ( errorHtml ) {	var el;	// hide the form fields and the preview div	hide ( 'cmt-form-newCmtData' );	hide ( 'cmt-form-header-previewing' );	hide ( 'cmt-form-previewDiv' );		// populate and show the error div	el = document.getElementById ( 'cmt-form-errorDiv' );	el.innerHTML = errorHtml;	show ( 'cmt-form-errorDiv', 'block' );	// hide the preview and post buttons, show the cancel and edit buttons.	show ( 'cmt-form-btn-cancel', 'inline' );	show ( 'cmt-form-btn-edit', 'inline' );	hide ( 'cmt-form-btn-preview' );	hide ( 'cmt-form-btn-post' );	}function cancelComment () {	// called when the user cancels.	// also used after the post function to close down the form.	var el;	// hide the form	hide ( 'cmt-form' );		// 'turn on' the <select> elements again	showSelect();	// reset the divs	show ( 'cmt-form-newCmtData', 'block' );	hide ( 'cmt-form-header-previewing' );	hide ( 'cmt-form-previewDiv' );	hide ( 'cmt-form-errorDiv' );	// reset the buttons	show ( 'cmt-form-btn-cancel', 'inline' );	hide ( 'cmt-form-btn-edit' );	show ( 'cmt-form-btn-preview', 'inline' );	show ( 'cmt-form-btn-post', 'inline' );		// reset block elements	resetBlockElement ( 'cmt-form-header-parent' );	resetBlockElement ( 'cmt-form-parent-cmtTxt' );	resetBlockElement ( 'cmt-form-previewDiv' );	resetBlockElement ( 'cmt-form-errorDiv' );	// reset form field values	el = document.getElementById ( 'cmt-form-fld-parentId' );	el.value = 0;	// resetFieldValue ( 'cmt-form-fld-author' );	// resetFieldValue ( 'cmt-form-fld-email' );	// resetFieldValue ( 'cmt-form-fld-url' );	resetFieldValue ( 'cmt-form-fld-subject' );	resetFieldValue ( 'cmt-form-fld-cmtTxt' );	el = document.getElementById ( 'cmt-form-fld-subscribe' );	el.checked = 0;	}function verifyParams () {	// we require three values: the author's name and email address, and the comment text.	var el = document.getElementById ( 'cmt-form-fld-author' );	if ( el.value == '' ) {		alert ( 'Please enter your name into the \'Name\' field.');		el.focus();		return false;		}		el = document.getElementById ( 'cmt-form-fld-email' );	if ( el.value == '' ) {		alert ( 'Please enter your email into the \'Email\' field.');		el.focus();		return false;		}		el = document.getElementById ( 'cmt-form-fld-cmtTxt' );	if ( el.value == '' ) {		alert ( 'Please enter your comment into the \'Comment Text\' field.' );		el.focus();		return false;		}	return true;	}function assembleParams () {	var params = '';	// params = 'static=1';	// the presence of the 'static' param and its value normally affect what MT returns after a post,	// but we've hacked the MT/App/Comments.pm code to return the comment preview.	// with 'static=0' and 'arch=1'; --> returns the individual archive page.	// without 'static' and without 'arch'; --> returns the comment listing page.		// static = 1 should now return the correct entry_permalink#comment-id url in comment notification emails.	// I changed the MT/App/Comments.pm code in the post() routine to do this.	params += '&static=1';	params += getParam ( 'cmt-form-fld-entryId' );	params += getParam ( 'cmt-form-fld-ccode' );	params += getParam ( 'cmt-form-fld-parentId' );	params += getParam ( 'cmt-form-fld-author' );	params += getParam ( 'cmt-form-fld-email' );	params += getParam ( 'cmt-form-fld-url' );	params += getParam ( 'cmt-form-fld-subject' );	params += getParam ( 'cmt-form-fld-cmtTxt' );	// subscribe is a checkbox. special treatment.	var el = document.getElementById ( 'cmt-form-fld-subscribe' );	if ( el.checked == true )		params += '&subscribe=1';	return params;	}function getParam ( id ) {	var el = document.getElementById ( id );	if ( !el ) return '';		if ( id != 'cmt-form-fld-ccode' ) 		return '&' + el.name + '=' + escape( el.value );	else {		// the CCode value.		// special handling to get it because the js-generated element doesn't have an id.		// without this value, comments cannot be submitted.		// CCode is case-sensitive. if the param name is not 'CCode', CCode will ignore it.		var ccode = el.innerHTML;		ccode = ccode.replace ( /^[^|]+value="?(\d+)"?.+$/i, '$1' );		// in IE, the CCode is generated without quotes around the value field, AND		// a Return character is included after the <script> element. to include the Return		// in the replace grep expression, I've used [^|] instead of the normal . token.		//		// strange. from IE, the server returns the value parameter in the middle of the INPUT element.		// from OmniWeb, the server returns the value parameter at the end of the INPUT element.		return '&CCode=' + ccode;		}	}function sendRequest ( params ) {	req = initXMLHTTPRequest ();	if ( req ) {		// show the progress text		show ( 'cmt-form-progressDiv', 'block' );		// send the request		req.onreadystatechange = onReadyState;		req.open ( 'post', '/cgi-bin/mt/mt-c.cgi', true );		req.setRequestHeader ( 'Content-Type', 'application/x-www-form-urlencoded' );		req.send ( params );		}	}function initXMLHTTPRequest () {	var req = null;	if ( window.XMLHttpRequest )		req = new XMLHttpRequest ();	else if ( window.ActiveXObject )		req = new ActiveXObject ( 'Microsoft.XMLHTTP' );	return req;	}function onReadyState () {	if ( req.readyState == READY_STATE_COMPLETE ) {		// hide the progress text		hide ( 'cmt-form-progressDiv' );		var responseText;		try { responseText = req.responseText; }		catch ( e ) { return; }		if ( !responseText ) return;		if ( responseText.match (/^<h3>Comment Submission Error<\/h3>/) ) {			// MT returned a comment submission error.			// display the error			displayError ( responseText );			return false;			}				else if ( responseText.match ( /^JSON:/ ) ) {			// from movalog's code. may not be applicable to my MT server.			responseText = responseText.replace ( /^(.|\\n)*JSON:/, '' );			var json = eval ( '(' + responseText + ')' );			displayError ( json );			return false;			}		if ( previewORpost == 'preview' )			displayPreview ( responseText );		else			// displayError ( responseText ); // for testing purposes. what gets returned from a successful POST?			appendComment ( responseText );		}		return true;	}window.onload = function () {	// reset the form values	cancelComment ();	}
