(function(){ var ns = __namespace( "Astro.Blog.Components.Comment" ); /** @type {System.Cycle} */ var Cycle = __import( "System.Cycle" ); /** @type {System.Debug} */ var debug = __import( "System.Debug" ); /** @type {System.Cycle.Trigger} */ var Trigger = __import( "System.Cycle.Trigger" ); /** @type {System.utils.IKey} */ var IKey = __import( "System.utils.IKey" ); /** @type {System.utils.EventKey} */ var EventKey = __import( "System.utils.EventKey" ); /** @type {System.utils.DataKey} */ var DataKey = __import( "System.utils.DataKey" ); /** @type {System.utils.Perf} */ var Perf = __import( "System.utils.Perf" ); /** @type {Dandelion} */ var Dand = __import( "Dandelion" ); /** @type {Dandelion.IDOMElement} */ var IDOMElement = __import( "Dandelion.IDOMElement" ); /** @type {Astro.Bootstrap} */ var Bootstrap = __import( "Astro.Bootstrap" ); /** @type {Astro.Blog.Config} */ var Conf = __import( "Astro.Blog.Config" ); /** @type {Astro.Blog.Components.Bubble} */ var Bubble = __import( "Astro.Blog.Components.Bubble" ); var postData = __import( "System.Net.postData" ); /** @type {_3rdParty_.Recaptcha} */ var Recaptcha; /** @type {_AstConf_.UserInfo} */ var currentUser = Conf.get( "UserInfo" ); /** @type {_AstConf_.Comment} */ var Config = Conf.get( "Comment" ); /** @type {_AstConf_.Article} */ var article = Conf.get( "Article" ); /*{{{ Validation Methods */ var v_match = function( str, regEx ) { // Optional string is empty if( !str ) return true; // Not empty, validate if( str.match( regEx ) != null ) return str; return false; }; var validateMail = function ( str ) { return v_match( str, /^[\_]*([a-z0-9]+(\.|\_*)?)+@([a-z][a-z0-9\-]+(\.|\-*\.))+[a-z]{2,6}$/ ); }; var validateURL = function ( str ) { return v_match( str, /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/ ); }; /* End Validation Methods}}}*/ var wrapc = Dand.wrapc; var init = function () { // TODO: should add controls to be able to remove comments var contentHaveText = false , nameHaveText = false , fieldReady = false , releaseReplyLock , captcha_wrapper , submit_button , cBubble , button , cHeight = 0 , elmH = "1.2em" , cp = Dand.id( "c_input_panel" ) , contentField = Dand.id( "content_field" ) , nameField = Dand.id( "name_field" ) , c_body = Dand.id( "comment_body" ) // If nameField exists, we assume logged in , loggedIn = !nameField , contentHadHaveText = false , commentInput = function () { // trim whitespaces contentHaveText = contentField.value.trim(); if( contentHaveText != contentHadHaveText ) { fieldReadyTrigger(); contentHadHaveText = contentHaveText; } } , nameHadHaveText = false , nameInput = function () { // trim whitespaces nameHaveText = nameField.value.trim(); if( nameHadHaveText != nameHaveText ) { fieldReadyTrigger(); nameHadHaveText = nameHaveText; } } , doReply = function () { var c_reply = this; // This will ensure capcha_wrapper is set fieldReadyTrigger(); // Set comment id submit_button.setAttribute( new DataKey( "cid", c_reply.getAttribute( "value" ) ) ); // Close reply indicator Dand.id("ri_switch").style.top = "0"; // If this button is not that button button && ( c_reply != button ) && releaseReplyButton(); // Lock reply button c_reply.setAttribute("locked", "1"); c_reply.onclick = null; c_reply.style.cursor = "default"; c_reply.style.background = "Crimson"; c_reply.style.width = "1.2em"; c_reply.style.right = "-1.2em"; // Configure release lock button = c_reply; var rf = Dand.id( "recaptcha_field" ); if( rf && rf.hasChildNodes() ) { // if capcha opened closeCaptcha(); hideSubmit(); Cycle.delay( function() { closeInputPanel( reviveInputpanel.bind( c_reply.parentNode.parentNode ) ) }, 500); } else { Cycle.delay( function() { closeInputPanel( reviveInputpanel.bind( c_reply.parentNode.parentNode ) ) }, 250); } } , releaseReplyButton = function () { button.removeAttribute("locked"); button.onclick = doReply.bind(button); button.style.cursor = button.style.background = button.style.width = button.style.right = ""; } , fieldReadyTrigger = loggedIn ? /* Overload */ function () { // Get wrapper captcha_wrapper || (captcha_wrapper = Dand.id( "capcha_wrapper", true )); submit_button || ( submit_button = Dand.id( "c_submit", true ) ); if(contentHaveText) { // show submit button showSubmit(); fieldReady = true; } else { // hide submit button hideSubmit(); fieldReady = false; } } : /* Overload */ function () { captcha_wrapper || (captcha_wrapper = Dand.id( "capcha_wrapper", true )); submit_button || ( submit_button = Dand.id( "c_submit", true ) ); // Create capcha if(!fieldReady && contentHaveText && nameHaveText) { createCaptcha(); // show submit button showSubmit(); fieldReady = true; } else if(!(contentHaveText || nameHaveText)) { // hide submit button hideSubmit(); fieldReady = false; } } , submitComment = loggedIn ? /* Overload */ function () { // Postdata var p = { "article_id": article.id , "name": currentUser.name , "website": currentUser.website , "avatar": currentUser.avatar } // pass-through obj , comment_id = submit_button.getDAttribute( "cid" ); p.article_id = article.id; // Set comment id if available comment_id && ( p["comment_id"] = comment_id ); hideSubmit(); if( getFieldsValidated(p) ) { popBubble(); // Post the data, bind obj to Handler postData( Config.processor, p, commentSuccess.bind(p), commentFailed ); } else { Cycle.delay( showSubmit, 1500 ); } } : /* Overload */ function () { var p = { "article_id": article.id } , comment_id = submit_button.getDAttribute( "cid" ); // Set comment id if available comment_id && ( p["comment_id"] = comment_id ); hideSubmit(); if( getFieldsValidated( p ) ) { popBubble(); captcha_wrapper.readOnly = true; closeCaptcha(); // Post the data, bind obj to Handler postData( Config.processor, p, commentSuccess.bind(p), commentFailed ); } else { Cycle.delay( showSubmit, 1500 ); } } , commentSuccess = function ( obj ) { // Pass Color = Green cBubble.setColor("YellowGreen"); // Popup Success message cBubble.pop("Success"); // blurp after 1 sec Cycle.delay( function (){ cBubble.blurp(); }, 1500 ); generateCommentStack( this, obj ); } // Input panel control , closeInputPanel = function (handler) { cHeight = cp.clientHeight; cp.style.transition = "all 0s"; cp.style.height = cHeight + "px"; cp.style.overflow = "hidden"; // Delay for 10 millisec for establishing transition properties Cycle.next(function() { this.style.transition = ""; }.bind(cp)); Trigger.transition(cp.style, "", function() { cp.style.padding = "0"; cp.style.height = "0"; }); // After transition finished, remove input panel Trigger.height(cp, 0, function() { cp.parentNode.removeChild(cp); // Pass panel to handler if(handler) handler(); }); } , openInputPanel = function () { cp.style.padding = ""; cp.style.height = cHeight + "px"; // Delay for 500 millisec waiting for transition finished Cycle.delay(function() { cp.style.transition = "all 0s"; cp.style.height = ""; cp.style.overflow = ""; Dand.id("ri_switch").style.top = ""; fieldReady = false; fieldReadyTrigger(); }, 500); } , reviveInputpanel = function () { this.appendChild(cp); Cycle.next(openInputPanel); } // Comments submission and handling , commentFailed = function (obj) { // Handle error here to prevent accidental catch by caller try { if(obj != null) { if(obj.reload) { // reload the recaptcha createCaptcha(); Cycle.delay(showSubmit, 1500); // Wrong answer. var f = Dand.id("false_capcha"); Cycle.delay( function() { this.innerHTML = "Wrong answer, please re-enter."; this.style.height = "1.2em"; }.bind(f), 500 ); Cycle.delay(function (){cBubble.blurp();}, 500); } else { // Reload not needed, serious error had occurred Cycle.delay(function (){cBubble.blurp();}, 500); Cycle.delay(function () { cBubble.setColor("red"); cBubble.pop("Server error"); }, 1000); } } else { // reload the recaptcha createCaptcha(); Cycle.delay(showSubmit, 1500); Cycle.delay(function (){cBubble.blurp();}, 500); Cycle.delay(function () { cBubble.setColor("red"); cBubble.pop("Cannot connect"); }, 1000); } } catch(e) { debug.Error(e); } } , submitKey = new EventKey("Click", submitComment) // Enter key , captchaKey = new EventKey("KeyDown", function(e) { if(e.keyCode == 13) submitComment(); }) , _showSubmit = function () { // prevent multiple prop assign if( !submit_button.hasListener( submitKey ) ) { submit_button.style.width = "1.2em"; submit_button.style.right = "-1.2em"; submit_button.style.cursor = "pointer"; } submit_button.addEventListener( submitKey ); } , _hideSubmit = function () { // prevent multiple prop assign if( submit_button.hasListener( submitKey ) ) { submit_button.style.cursor = "default"; submit_button.style.width = ""; submit_button.style.right = ""; } submit_button.removeEventListener( submitKey ); } , showSubmit = loggedIn ? /* Overload */ _showSubmit : /* Overload */ function () { _showSubmit(); captcha_wrapper.addEventListener(captchaKey); } , hideSubmit = loggedIn ? /* Overload */ _hideSubmit : /* Overload */ function () { _hideSubmit(); captcha_wrapper.removeEventListener(captchaKey); } , generateCommentStack = function ( rObj, obj ) { var // Hold for transitions c_ind, c_cont, cpole // The info stack , _c_info = wrapc("c_info", [ wrapc("fls", rObj.website ? Dand.wrapne( "a", rObj.name, IKey.quickDef( "target", "_blank", "href", rObj.website ) ) : rObj.name ) , wrapc( "flsf", obj.time ) ]) // loggedIn Overload , c_info = loggedIn ? wrapc("cu_stack", [ _c_info , Dand.textNode(" ") , wrapc("cu_avatar" , Dand.wrapna( "img", IKey.quickDef( "src", rObj.avatar, "alt", "avatar" ) ) )] ) : _c_info // Generate comment stack , c_stack = rObj["comment_id"] // Reply Structure ? wrapc("reply", wrapc("c_cont", [ c_ind = wrapc("r_indicator") , wrapc("c_text", rObj.content) , c_info ])) : wrapc("c_comm", [ c_ind = wrapc("c_indicator") , c_cont = wrapc("c_cont", [ cpole = wrapc("cpole") , wrapc("c_text", rObj.content) , c_info ]) ] ) ; // Remove transition properties c_stack.style.transition = "all 0s"; // Close Input panel closeInputPanel( null ); // Remove false_fields for(var i in fields) { i = Dand.id("false_" + fields[i]); i.parentNode.removeChild(i); } c_stack.style.opacity = 0; cp.parentNode.insertBefore( c_stack, cp ); c_stack.style.marginTop = ( -c_stack.clientHeight ) + "px"; // if nocomment notice exist, remove it if( i = Dand.id("nocomment") ) { i.style.transition = "all 0s"; i.style.width = "658px"; i.style.height = "22px"; i.style.overflow = "hidden"; // transition Cycle.next(function() { this.style.transition = ""; this.style.margin = "0"; this.style.width = "0"; this.style.padding = "0"; this.style.height = "0"; }.bind(i)); // Pending remove Trigger.height(i, 0, function(){ this.parentNode.removeChild(this); }.bind(i)); } // Delay for 10 millisec for establishing transition properties Cycle.next( function() { this.style.transition = ""; }.bind( c_stack ) ); Cycle.delay(function() { this.style.marginTop = ""; this.style.opacity = 1; }.bind(c_stack), 600); } //// Captcha , createCaptcha = loggedIn ? function() {} : function () { // Remove capcha Dand.id( "recaptcha_field", true ).clear(); try { Recaptcha.render( "recaptcha_field", { "theme": "light" , "sitekey": Config.siteKey } ); } catch( ex ) { } openCaptcha(); } , openCaptcha = loggedIn ? function() {} :function () { var rf = Dand.id( "recaptcha_field" ); var k = function () { return ( 0 < this.a.clientHeight ); }.bind({ a: rf }); Trigger.register( k , function() { captcha_wrapper.style.height = rf.clientHeight + "px"; } , 50 ); } , closeCaptcha = loggedIn ? function() {} :function () { captcha_wrapper.style.height = "0"; } // Validation , fields = loggedIn ? ["content"] : ["content", "name", "email", "website"] , _getFieldsValidated = function (obj) { var name, field, falsefield, f; for(var i in fields) { name = fields[i]; field = name + "_field"; falsefield = "false_" + name; f = Dand.id( falsefield ); f.style.height = 0; switch(name) { case "name": if(!( obj[name] = Dand.id(field).value.trim() )) Cycle.delay( function() { this.style.height = elmH; }.bind(f), 500 ); break; case "content": if(!( obj[name] = Dand.id(field).value.trim() )) Cycle.delay( function() { this.style.height = elmH; }.bind(f), 500 ); break; case "website": if(!( obj[name] = validateURL( Dand.id(field).value.trim() ))) { obj[name] = false; Cycle.delay( function() { this.style.height = elmH; }.bind(f), 500 ); } else { if(obj[name] == true) delete obj[name] } break; case "email": if(!( obj[name] = validateMail( Dand.id(field).value.trim() ) )) { obj[name] = false; Cycle.delay( function() { this.style.height = elmH; }.bind(f), 500 ); } else { if(obj[name] == true) delete obj[name] } break; } } for(var i in obj) if(!obj[i]) return false; return true; } , getFieldsValidated = loggedIn ? /* Overload */ _getFieldsValidated : /* Overload */ function(obj) { var f = Dand.id("false_capcha"); f.style.height = 0; // get the response field if(!( obj["recaptcha_response_field"] = Recaptcha.getResponse().trim() )) { Cycle.delay( function() { this.innerHTML = "You need to prove that you are a human"; this.style.height = elmH; }.bind(f) , 500 ); } // get the challenge field // else obj["recaptcha_challenge_field"] = Recaptcha.get_challenge(); return _getFieldsValidated(obj); } , showReplyButton = function () { this.style.width = "1.2em"; this.style.right = "-1.2em"; } , hideReplyButton = function () { if(!this.getAttribute("locked")) this.style.width = this.style.right = ""; } , popBubble = function () { if(cBubble == null) { // create a new bubble cBubble = new Bubble(); document.body.appendChild( cBubble.init() ); // pop message cBubble.setColor( "cornflowerblue" ); Cycle.next( function () { cBubble.pop("Submitting"); } ); } } ; if( !loggedIn ) { IDOMElement( nameField ).addEventListener( "Input", nameInput ); } IDOMElement( contentField ).addEventListener( "Input", commentInput ); var l = c_body.childNodes, c_id; for( var i in l ) { if( l[i].nodeType == 1 && ( c_id = IDOMElement( l[i] ).getDAttribute("value") ) ) { var reply_button = Dand.id("c_reply_" + c_id); reply_button.onclick = doReply.bind(reply_button); l[i].onmouseover = showReplyButton.bind(reply_button); l[i].onmouseout = hideReplyButton.bind(reply_button); } } var stage = c_body.parentNode BotanJS.addEventListener( "Responsive" /** e @type {Astro.Blog.Events.Responsive} */ , function( e ) { e.data.ratio < 1 ? stage.style.width = "100%" : stage.style.width = "" ; } ); if( !loggedIn ) { var limit = 5; var i = 0; var reUUID = Perf.uuid; Cycle.perma( reUUID, function() { if( limit < i ++ ) { var mesg = Dand.glass( "c_so_sorry" ); if( mesg.length ) mesg[0].style.display = "block"; } if( Recaptcha = window["grecaptcha"] ) { Cycle.permaRemove( reUUID ); debug.Info( "Recaptcha instance is up" ); } } , 500 ); } }; Bootstrap.regInit( init ); })();