1// The cookie name to use for storing the blog-side comment session cookie. 2var mtCookieName = "mt_blog_user"; 3var mtCookieDomain = ".montrealites.ca"; 4var mtCookiePath = "/"; 5var mtCookieTimeout = 14400; 6 7 8function mtHide(id) { 9 var el = (typeof id == "string") ? document.getElementById(id) : id; 10 if (el) el.style.display = 'none'; 11} 12 13 14function mtShow(id) { 15 var el = (typeof id == "string") ? document.getElementById(id) : id; 16 if (el) el.style.display = 'block'; 17} 18 19 20function mtAttachEvent(eventName,func) { 21 var onEventName = 'on' + eventName; 22 var old = window[onEventName]; 23 if( typeof old != 'function' ) 24 window[onEventName] = func; 25 else { 26 window[onEventName] = function( evt ) { 27 old( evt ); 28 return func( evt ); 29 }; 30 } 31} 32 33 34function mtFireEvent(eventName,param) { 35 var fn = window['on' + eventName]; 36 if (typeof fn == 'function') return fn(param); 37 return; 38} 39 40if(!this.JSON){JSON={};}(function(){function f(n){return n<10?'0'+n:n;}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}if(typeof rep==='function'){value=rep.call(holder,key,value);}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}return str('',{'':value});};}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}return reviver.call(holder,key,value);}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}throw new SyntaxError('JSON.parse');};}}()); 41 42var MT = window.MT || {}; 43 44MT.cons = function () { 45 return { 46 LOG : 'log', 47 WARN : 'warn', 48 DEBUG : 'debug', 49 INFO : 'info', 50 ERR : 'error', 51 JSON : 'json' 52 }; 53}(); 54 55 56MT.core = function (o) { 57 var _debug = false;
58 59 return { 60 61 connect : function (url,respType,respHandler) { 62 var xh = mtGetXmlHttp(); 63 if (!xh) return false; 64 65 xh.onreadystatechange = function() { 66 if ( xh.readyState == 4 ) { 67 if ( xh.status && ( xh.status != 200 ) ) { 68 // error - ignore 69 } else { 70 switch (respType) { 71 case 'json': 72 respHandler(JSON.parse(xh.responseText)); 73 break; 74 75 case 'xml': 76 break; 77 78 case 'text': 79 break; 80 } 81 } 82 } 83 }; 84 85 xh.open('GET',url); 86 xh.send(null); 87 }, 88 89 getEl : function (el) { 90 return MT.util.checkNodeType(el)==='element' ? id : (document.getElementById(el) || false); 91 }, 92 93 addEvent : function (el,type,func,obj) { 94 if(!obj && document.addEventListener) { 95 el.addEventListener(type,func,false); 96 } else if(obj && document.addEventListener) { 97 el.addEventListener(type,function () { 98 func.call(obj,event); 99 },false); 100 } else { 101 if(obj) { 102 el.attachEvent('on' + type,function () { 103 func.call(obj,event); 104 }); 105 } else { 106 el.attachEvent('on' + type,function () { 107 func.call(el,event); 108 }); 109 } 110 } 111 }, 112 113 114 log : function (level,msg) { 115 if(_debug && window.console) { 116 switch(level) { 117 case 'warn': 118 case 'debug': 119 case 'info': 120 case 'error': 121 case 'log': 122 console[level](msg); 123 break; 124 125 default: 126 return false; 127 } 128 } else { 129 return false; 130 } 131 } 132 } 133}(); 134 135 136MT.util = function () { 137 return { 138 toggleVisibility : { 139 show : function () { 140 var i = arguments.length; 141 142 while(i--) { 143 if(MT.util.checkNodeType(arguments[i])==='element') { 144 arguments[i].style.visibility = 'visible'; 145 } else { 146 MT.core.getEl(arguments[i]).style.visibility = 'visible'; 147 } 148 } 149 }, 150 151 hide : function () { 152 var i = arguments.length; 153 while(i--) { 154 if(MT.util.checkNodeType(arguments[i])==='element') { 155 arguments[i].style.visibility = 'hidden'; 156 } else { 157 MT.core.getEl(arguments[i]).style.visibility = 'hidden'; 158 } 159 } 160 } 161 }, 162 163 toggleDisplay : { 164 show : function () { 165 var i = arguments.length; 166 while(i--) { 167 if(MT.util.checkNodeType(arguments[i])==='element') { 168 arguments[i].style.display = ''; 169 } else { 170 MT.core.getEl(arguments[i]).style.display = ''; 171 } 172 } 173 }, 174 175 hide : function () { 176 var i = arguments.length; 177 while(i--) { 178 if(MT.util.checkNodeType(arguments[i])==='element') { 179 arguments[i].style.display = 'none'; 180 } else { 181 MT.core.getEl(arguments[i]).style.display = 'none'; 182 } 183 } 184 } 185 }, 186 187 188 findDefiningParent : function (origin) { 189 if(MT.util.checkNodeType(origin)==='element') { 190 for(var node=origin.parentNode;node.parentNode;node=node.parentNode) { 191 if((node.hasAttribute && node.hasAttribute('id')) || node.getAttribute('id')) { 192 return node; 193 } 194 } 195 } 196 return false; 197 }, 198 199 200 checkNodeType : function (obj) { 201 if (obj && obj.nodeName){ 202 switch (obj.nodeType) { 203 case 1: return 'element'; 204 case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; 205 } 206 } 207 } 208 } 209}(); 210 211 212(function () { 213 var M = MT.core, 214 c = MT.cons, 215 u = MT.util, 216 cache, 217 isLoading, 218 direction, 219 currentComments, 220 commentAnchor, 221 commentArrId, 222 commentsPerPage, 223 commentsTotalPages, 224 loadingIcon, 225 pageNum, 226 commentsOffset, 227 totalComments, 228 entryID, 229 commentContentDiv, 230 topNav, 231 nav,
232 currentCommentsSpan, 233 topCurrentCommentsSpan; 234 235 M.addEvent(window,'load',_init); 236 237 /** 238 * Initializes the class 239 * 240 * @return void 241 */ 242 function _init () { 243 if(!MT.entryCommentCount) { 244 return; 245 } 246 247 _initializeVariables(); 248 _setCommentOffset(false); 249 _checkForAnchor(); 250 _setCurrentComments(); 251 _toggleNavLinks(); 252 _initializeEvents(); 253 } 254 255 256 function _initializeVariables() { 257 cache = {}; 258 isLoading = false; 259 commentAnchor = ''; 260 commentArrId = ''; 261 commentsPerPage = MT.commentsPerPage || 50; 262 currentComments = ''; 263 direction = 'ascend'; 264 entryID = MT.entryID; 265 totalComments = MT.entryCommentCount; 266 commentsTotalPages = Math.ceil(totalComments / commentsPerPage); 267 pageNum = 1; 268 269 loadingIcon = "<img title='Loading...' src='../../../mt-static/images/indicator.white.gif' alt='Loading' />"; 270 271 commentContentDiv = M.getEl("comments-content"); 272 topNav = M.getEl("top-comment-nav"); 273 nav = M.getEl("comment-nav"); 274 275 currentCommentsSpan = M.getEl("current-comments"); 276 topCurrentCommentsSpan = M.getEl("top-current-comments"); 277 } 278 279 function _initializeEvents() { 280 if (commentsPerPage < totalComments) { 281 M.addEvent(nav,'click',_handleEvents); 282 M.addEvent(topNav,'click',_handleEvents); 283 } 284 } 285 286 287 function _checkForAnchor() { 288 var found = String(window.location.hash).match( /comment-(\d{1,6})/ ); 289 290 if (found) { 291 M.log(c.DEBUG,found); 292 if (!M.getEl(found[0]).hasOwnProperty('className')) { 293 if (_findIdMatch(found[1])) { 294 pageNum = Math.floor(commentArrId / commentsPerPage) + 1; 295 M.log(c.DEBUG,'Comment Array Id: ' + commentArrId); 296 M.log(c.DEBUG,'Comments Per Page: ' + commentsPerPage); 297 M.log(c.DEBUG,'Page Number: ' + pageNum); 298 M.log(c.DEBUG,'Comment Offset: ' + _getCommentOffset()); 299 _updateComments(); 300 } 301 } 302 } 303 } 304 305 306 function _setCommentOffset() { 307 commentsOffset = commentsPerPage * (pageNum-1); 308 } 309 310 311 function _getCommentOffset() { 312 return commentsOffset; 313 } 314 315 316 function _handleEvents (e) { 317 var origin = e.target || e.srcElement, 318 parentId; 319 320 // stupid IE 321 origin = origin.id && M.getEl(origin.id) || false; 322 323 if(origin) { 324 parentId = u.checkNodeType(origin.parentNode)==='element' && origin.parentNode.getAttribute('id') && origin.parentNode.id; 325 } else { 326 return false; 327 } 328 329 switch(origin.nodeName) { 330 case 'A': 331 switch (parentId) { 332 case 'prev-comments': 333 case 'top-prev-comments': 334 if(e.preventDefault) { 335 e.preventDefault(); 336 } else { 337 e.returnValue = false;
338 } 339 if(!isLoading) { 340 _previousPage(); 341 } 342 break; 343 case 'next-comments': 344 case 'top-next-comments': 345 if(e.preventDefault) { 346 e.preventDefault(); 347 } else { 348 e.returnValue = false; 349 } 350 if(!isLoading) { 351 _nextPage(); 352 } 353 break; 354 } 355 break; 356 } 357 } 358 359 360 function _toggleNavLinks () { 361 M.log(c.DEBUG,M.getEl('top-prev-comments')); 362 if(pageNum <= commentsTotalPages && pageNum !== 1) { 363 u.toggleVisibility.show('prev-comments'); 364 u.toggleVisibility.show('top-prev-comments'); 365 } 366 367 if(pageNum >= 1 && pageNum !== commentsTotalPages) { 368 u.toggleVisibility.show('next-comments'); 369 u.toggleVisibility.show('top-next-comments'); 370 } 371 372 if(pageNum===1 || nav.style.visibility==='hidden') { 373 u.toggleVisibility.hide('prev-comments'); 374 u.toggleVisibility.hide('top-prev-comments'); 375 } 376 377 if(pageNum===commentsTotalPages || nav.style.visibility==='hidden') { 378 u.toggleVisibility.hide('next-comments'); 379 u.toggleVisibility.hide('top-next-comments'); 380 } 381 } 382 383 384 function _nextPage () { 385 if(pageNum < commentsTotalPages) { 386 pageNum++; 387 _updateComments(); 388 } 389 } 390 391 392 function _previousPage() { 393 if(pageNum > 1) { 394 pageNum--; 395 _updateComments(); 396 } 397 } 398 399 400 function _findIdMatch (id) { 401 var len = MT.commentIds.length; 402 403 while (len--) { 404 if (MT.commentIds[len] == id) { 405 commentAnchor = "comment-" + id; 406 commentArrId = len; 407 return true; 408 } 409 } 410 411 return false; 412 } 413 414 415 function _setCurrentComments() { 416 var commentsOnPage = pageNum != commentsTotalPages ? commentsOffset + commentsPerPage : totalComments; 417 418 _setCurrentCommentsContent([commentsOffset+1," - ",commentsOnPage].join('')); 419 } 420 421 422 function _setCurrentCommentsContent(currentCommentsHTML) { 423 currentCommentsSpan.innerHTML = currentCommentsHTML; 424 topCurrentCommentsSpan.innerHTML = currentCommentsHTML; 425 } 426 427 428 function _setCommentContent(commentHTML) { 429 commentContentDiv.innerHTML = commentHTML; 430 } 431 432 433 function _updateComments() { 434 var comments, jsonUrl; 435 isLoading = true; 436 _setCurrentCommentsContent(loadingIcon); 437 _setCommentOffset(); 438 439 jsonUrl = [ 440 "http://www.montrealites.ca/cgi-bin/mt/hLaSx4qew0QL-q1sS7eTgQ2wIg-c0mn3mts.cgi?__mode=comment_listing&direction=", 441 direction, 442 "&entry_id=", 443 entryID, 444 "&limit=", 445 commentsPerPage, 446 "&offset=", 447 _getCommentOffset() 448 ].join(''); 449 450 if (!commentAnchor) { 451 commentAnchor = "comments-content"; 452 } 453 454 if(cache.hasOwnProperty(jsonUrl)) { 455 _refreshComments(cache[jsonUrl]); 456 isLoading = false; 457 } else { 458 M.connect(jsonUrl,c.JSON,function (json) { 459 cache[jsonUrl] = json.comments; 460 _refreshComments(json.comments); 461 isLoading = false; 462 }); 463 } 464 } 465 466 467 function _refreshComments(commentData) { 468 _setCommentContent(commentData); 469 _setCurrentComments(); 470 window.location.hash = 'reset'; 471 window.location.hash = commentAnchor; 472 _toggleNavLinks(); 473 } 474})(); 475 476 477function mtRelativeDate(ts, fds) { 478 var now = new Date(); 479 var ref = ts; 480 var delta = Math.floor((now.getTime() - ref.getTime()) / 1000); 481 482 var str; 483 if (delta < 60) { 484 str = 'moments ago'; 485 } else if (delta <= 86400) { 486 // less than 1 day 487 var hours = Math.floor(delta / 3600); 488 var min = Math.floor((delta % 3600) / 60); 489 if (hours == 1) 490 str = '1 hour ago'; 491 else if (hours > 1) 492 str = '2 hours ago'.replace(/2/, hours); 493 else if (min == 1) 494 str = '1 minute ago'; 495 else 496 str = '2 minutes ago'.replace(/2/, min); 497 } else if (delta <= 604800) { 498 // less than 1 week 499 var days = Math.floor(delta / 86400); 500 var hours = Math.floor((delta % 86400) / 3600); 501 if (days == 1) 502 str = '1 day ago'; 503 else if (days > 1) 504 str = '2 days ago'.replace(/2/, days); 505 else if (hours == 1) 506 str = '1 hour ago'; 507 else 508 str = '2 hours ago'.replace(/2/, hours); 509 } 510 return str ? str : fds; 511} 512 513 514function mtEditLink(entry_id, author_id) { 515 516 517} 518 519 520function mtCommentFormOnFocus() { 521 // if CAPTCHA is enabled, this causes the captcha image to be 522 // displayed if it hasn't been already. 523 mtShowCaptcha(); 524} 525 526 527var mtCaptchaVisible = false;
528function mtShowCaptcha() { 529 var u = mtGetUser(); 530 if ( u && u.is_authenticated ) return; 531 if (mtCaptchaVisible) return; 532 var div = document.getElementById('comments-open-captcha'); 533 if (div) { 534 div.innerHTML = ''; 535 mtCaptchaVisible = true; 536 } 537} 538 539 540 541var is_preview; 542var user; 543 544function mtSetUser(u) { 545 if (u) { 546 // persist this 547 user = u; 548 mtSaveUser(); 549 // sync up user greeting 550 mtFireEvent('usersignin'); 551 } 552} 553 554 555function mtEscapeJS(s) { 556 s = s.replace(/'/g, "'"); 557 return s; 558} 559 560 561function mtUnescapeJS(s) { 562 s = s.replace(/'/g, "'"); 563 return s; 564} 565 566 567function mtBakeUserCookie(u) { 568 var str = ""; 569 if (u.name) str += "name:'" + mtEscapeJS(u.name) + "';"; 570 if (u.url) str += "url:'" + mtEscapeJS(u.url) + "';"; 571 if (u.email) str += "email:'" + mtEscapeJS(u.email) + "';"; 572 if (u.is_authenticated) str += "is_authenticated:'1';"; 573 if (u.profile) str += "profile:'" + mtEscapeJS(u.profile) + "';"; 574 if (u.userpic) str += "userpic:'" + mtEscapeJS(u.userpic) + "';"; 575 if (u.sid) str += "sid:'" + mtEscapeJS(u.sid) + "';"; 576 str += "is_trusted:'" + (u.is_trusted ? "1" : "0") + "';"; 577 str += "is_author:'" + (u.is_author ? "1" : "0") + "';"; 578 str += "is_banned:'" + (u.is_banned ? "1" : "0") + "';"; 579 str += "can_post:'" + (u.can_post ? "1" : "0") + "';"; 580 str += "can_comment:'" + (u.can_comment ? "1" : "0") + "';"; 581 str = str.replace(/;$/, ''); 582 return str; 583} 584 585 586function mtUnbakeUserCookie(s) { 587 if (!s) return; 588 589 var u = {}; 590 var m; 591 while (m = s.match(/^((name|url|email|is_authenticated|profile|userpic|sid|is_trusted|is_author|is_banned|can_post|can_comment):'([^']+?)';?)/)) { 592 s = s.substring(m[1].length); 593 if (m[2].match(/^(is|can)_/)) // boolean fields 594 u[m[2]] = m[3] == '1' ? true : false; 595 else 596 u[m[2]] = mtUnescapeJS(m[3]); 597 } 598 if (u.is_authenticated) { 599 u.is_anonymous = false; 600 } else { 601 u.is_anonymous = true; 602 u.can_post = false; 603 u.is_author = false; 604 u.is_banned = false; 605 u.is_trusted = false; 606 } 607 return u; 608} 609 610 611function mtGetUser() { 612 if (!user) { 613 var cookie = mtGetCookie(mtCookieName); 614 if (!cookie) return; 615 user = mtUnbakeUserCookie(cookie); 616 if (! user) { 617 user = {}; 618 user.is_anonymous = true; 619 user.can_post = false; 620 user.is_author = false; 621 user.is_banned = false; 622 user.is_trusted = false; 623 } 624 } 625 return user; 626} 627 628 629var mtFetchedUser = false; 630 631function mtFetchUser(cb) { 632 if (!cb) cb = 'mtSetUser'; 633 if ( ( cb == 'mtSetUser' ) && mtGetUser() ) { 634 var url = document.URL; 635 url = url.replace(/#.+$/, ''); 636 url += '#comments-open'; 637 location.href = url; 638 } else { 639 // we aren't using AJAX for this, since we may have to request 640 // from a different domain. JSONP to the rescue. 641 mtFetchedUser = true; 642 var u = mtGetUser(); 643 var script = document.createElement('script'); 644 var ts = new Date().getTime(); 645 script.src = 'http://www.montrealites.ca/cgi-bin/mt/hLaSx4qew0QL-q1sS7eTgQ2wIg-c0mn3mts.cgi?__mode=userinfo&blog_id=125&jsonp=' + cb + '&ts=' + ts + '&sid=' + u.sid; 646 (document.getElementsByTagName('head'))[0].appendChild(script); 647 } 648} 649 650function mtVerifySession(cb) { 651 if (!cb) return; 652 var script = document.createElement('script'); 653 var ts = new Date().getTime(); 654 var u = mtGetUser(); 655 script.src = 'http://www.montrealites.ca/cgi-bin/mt/hLaSx4qew0QL-q1sS7eTgQ2wIg-c0mn3mts.cgi?__mode=verify_session&blog_id=125&jsonp=' + cb + '&ts=' + ts + '&sid=' + u.sid; 656 (document.getElementsByTagName('head'))[0].appendChild(script); 657} 658 659 660 661function mtRememberMeOnClick(b) { 662 if (!b.checked) 663 mtClearUser(b.form); 664 return true; 665} 666 667 668 669var mtRequestSubmitted = false; 670function mtCommentOnSubmit(f) { 671 if (!mtRequestSubmitted) { 672 mtRequestSubmitted = true; 673 674 if (f.armor) 675 f.armor.value = '99078c7fe09d3963958aeebeba6ea9ce3ee626ce'; 676 if (f.bakecookie && f.bakecookie.checked) 677 mtSaveUser(f); 678 679 // disable submit buttons 680 if (f.preview_button) f.preview_button.disabled = true; 681 if (f.post) f.post.disabled = true; 682 683 var u = mtGetUser(); 684 if ( !is_preview && ( u && u.is_authenticated ) ) { 685 // validate session; then submit 686 mtVerifySession('mtCommentSessionVerify'); 687 return false;
688 } 689 690 return true; 691 } 692 return false; 693} 694 695function mtCommentSessionVerify(app_user) { 696 var f = document['comments_form']; 697 if ( app_user && app_user.verified ) { 698 f.submit(); 699 } else { 700 alert('Your session has expired. Please sign in again to comment.'); 701 mtClearUser(); 702 mtFireEvent('usersignin'); 703 704 mtShow('comments-form'); 705 mtHide('comments-open-footer'); 706 707 } 708} 709 710function mtUserOnLoad() { 711 var u = mtGetUser(); 712 713 // if the user is authenticated, hide the 'anonymous' fields 714 // and any captcha input if already shown 715 if ( document.getElementById('comments-form')) { 716 if ( u && u.is_authenticated ) { 717 mtShow('comments-form'); 718 mtHide('comments-open-data'); 719 if (mtCaptchaVisible) 720 mtHide('comments-open-captcha'); 721 } else { 722 723 mtHide('comments-form'); 724 725 } 726 if ( u && u.is_banned ) 727 mtHide('comments-form'); 728 729 // if we're previewing a comment, make sure the captcha 730 // field is visible 731 if (is_preview) 732 mtShowCaptcha(); 733 else 734 mtShowGreeting(); 735 736 // populate anonymous comment fields if user is cookied as anonymous 737 var cf = document['comments_form']; 738 if (cf) { 739 if (u && u.is_anonymous) { 740 if (u.email) cf.email.value = u.email; 741 if (u.name) cf.author.value = u.name; 742 if (u.url) cf.url.value = u.url; 743 if (cf.bakecookie) 744 cf.bakecookie.checked = u.name || u.email; 745 } else { 746 if (u && u.sid && cf.sid) 747 cf.sid.value = u.sid; 748 } 749 if (cf.post && cf.post.disabled) 750 cf.post.disabled = false; 751 if (cf.preview_button && cf.preview_button.disabled) 752 cf.preview_button.disabled = false; 753 mtRequestSubmitted = false; 754 } 755 } 756} 757 758 759 760 761function mtEntryOnLoad() { 762 var cf = document['comments_form']; 763 if (cf && cf.preview) cf.preview.value = ''; 764 mtHide('trackbacks-info'); 765 766 mtFireEvent('usersignin'); 767} 768 769function mtEntryOnUnload() { 770 if (mtRequestSubmitted) { 771 var cf = document['comments_form']; 772 if (cf) { 773 if (cf.post && cf.post.disabled) 774 cf.post.disabled = false; 775 if (cf.preview_button && cf.preview_button.disabled) 776 cf.preview_button.disabled = false; 777 } 778 mtRequestSubmitted = false; 779 } 780 return true; 781} 782 783mtAttachEvent('usersignin', mtUserOnLoad); 784 785 786 787function mtSignIn() { 788 var doc_url = document.URL; 789 doc_url = doc_url.replace(/#.+/, ''); 790 var url = 'http://www.montrealites.ca/cgi-bin/mt/mt-cp.cgi?__mode=login&blog_id=125'; 791 if (is_preview) { 792 if ( document['comments_form'] ) { 793 var entry_id = document['comments_form'].entry_id.value; 794 url += '&entry_id=' + entry_id; 795 } else { 796 url += '&return_url=http%3A%2F%2Fwww.montrealites.ca%2Fmontrealites_words%2F'; 797 } 798 } else { 799 url += '&return_url=' + encodeURIComponent(doc_url); 800 } 801 mtClearUser(); 802 location.href = url; 803} 804 805function mtSignInOnClick(sign_in_element) { 806 var el; 807 if (sign_in_element) { 808 // display throbber 809 el = document.getElementById(sign_in_element); 810 if (!el) // legacy MT 4.x element id 811 el = document.getElementById('comment-form-external-auth'); 812 } 813 if (el) 814 el.innerHTML = 'Signing in... <span class="status-indicator"> </span>'; 815 816 mtClearUser(); // clear any 'anonymous' user cookie to allow sign in 817 mtSignIn(); 818 return false; 819} 820 821function mtSetUserOrLogin(u) { 822 if (u && u.is_authenticated) { 823 mtSetUser(u); 824 } else { 825 // user really isn't logged in; so let's do this! 826 mtSignIn(); 827 } 828} 829 830 831function mtSignOut(entry_id) { 832 mtClearUser(); 833 var doc_url = document.URL; 834 doc_url = doc_url.replace(/#.+/, ''); 835 var url = 'http://www.montrealites.ca/cgi-bin/mt/mt-cp.cgi?__mode=logout&static=0&blog_id=125'; 836 if (is_preview) { 837 if ( document['comments_form'] ) { 838 var entry_id = document['comments_form'].entry_id.value;
839 url += '&entry_id=' + entry_id; 840 } else { 841 url += '&return_url=http%3A%2F%2Fwww.montrealites.ca%2Fmontrealites_words%2F'; 842 } 843 } else { 844 url += '&return_url=' + encodeURIComponent(doc_url); 845 } 846 location.href = url; 847} 848 849 850function mtSignOutOnClick() { 851 mtSignOut(); 852 return false; 853} 854 855 856 857function mtShowGreeting() { 858 859 var reg_reqd = true; 860 861 var cf = document['comments_form']; 862 if (!cf) return; 863 864 var el = document.getElementById('comment-greeting'); 865 if (!el) // legacy MT 4.x element id 866 el = document.getElementById('comment-form-external-auth'); 867 if (!el) return; 868 869 var eid = cf.entry_id; 870 var entry_id; 871 if (eid) entry_id = eid.value; 872 873 var phrase; 874 var u = mtGetUser(); 875 876 if ( u && u.is_authenticated ) { 877 if ( u.is_banned ) { 878 phrase = 'You do not have permission to comment on this blog. (\<a href=\"javas\cript:void(0);\" onclick=\"return mtSignOutOnClick();\"\>sign out\<\/a\>)'; 879 } else { 880 var user_link; 881 if ( u.is_author ) { 882 user_link = '<a href="http://www.montrealites.ca/cgi-bin/mt/hLaSx4qew0QL-q1sS7eTgQ2wIg-c0mn3mts.cgi?__mode=edit_profile&blog_id=125&return_url=' + encodeURIComponent( location.href ); 883 user_link += '">' + u.name + '</a>'; 884 } else { 885 // registered user, but not a user with posting rights 886 if (u.url) 887 user_link = '<a href="' + u.url + '">' + u.name + '</a>'; 888 else 889 user_link = u.name; 890 } 891 // TBD: supplement phrase with userpic if one is available. 892 phrase = 'Thanks for signing in, __NAME__. (\<a href=\"javas\cript:void(0)\" onclick=\"return mtSignOutOnClick();\"\>sign out\<\/a\>)'; 893 phrase = phrase.replace(/__NAME__/, user_link); 894 } 895 } else { 896 if (reg_reqd) { 897 phrase = '\<a href=\"javas\cript:void(0)\" onclick=\"return mtSignInOnClick(\'comment-greeting\')\"\>Sign in\<\/a\> to comment.'; 898 } else { 899 phrase = '\<a href=\"javas\cript:void(0)\" onclick=\"return mtSignInOnClick(\'comment-greeting\')\"\>Sign in\<\/a\> to comment, or comment anonymously.'; 900 } 901 } 902 el.innerHTML = phrase; 903 904} 905 906 907 908function mtReplyCommentOnClick(parent_id, author) { 909 mtShow('comment-form-reply'); 910 911 var checkbox = document.getElementById('comment-reply'); 912 var label = document.getElementById('comment-reply-label'); 913 var text = document.getElementById('comment-text'); 914 915 // Populate label with new values 916 var reply_text = 'Replying to \<a href=\"#comment-__PARENT__\" onclick=\"location.href=this.href; return false\"\>comment from __AUTHOR__\<\/a\>'; 917 reply_text = reply_text.replace(/__PARENT__/, parent_id); 918 reply_text = reply_text.replace(/__AUTHOR__/, author); 919 label.innerHTML = reply_text; 920 921 checkbox.value = parent_id; 922 checkbox.checked = true; 923 try { 924 // text field may be hidden 925 text.focus(); 926 } catch(e) { 927 } 928 929 mtSetCommentParentID(); 930} 931 932 933function mtSetCommentParentID() { 934 var checkbox = document.getElementById('comment-reply'); 935 var parent_id_field = document.getElementById('comment-parent-id'); 936 if (!checkbox || !parent_id_field) return; 937 938 var pid = 0; 939 if (checkbox.checked == true) 940 pid = checkbox.value; 941 parent_id_field.value = pid; 942} 943 944 945function mtSaveUser(f) { 946 // We can't reliably store the user cookie during a preview. 947 if (is_preview) return; 948 949 var u = mtGetUser(); 950 951 if (f && (!u || u.is_anonymous)) { 952 if ( !u ) { 953 u = {}; 954 u.is_authenticated = false; 955 u.can_comment = true; 956 u.is_author = false; 957 u.is_banned = false; 958 u.is_anonymous = true; 959 u.is_trusted = false; 960 } 961 if (f.author != undefined) u.name = f.author.value; 962 if (f.email != undefined) u.email = f.email.value; 963 if (f.url != undefined) u.url = f.url.value; 964 } 965 966 if (!u) return; 967 968 var cache_period = mtCookieTimeout * 1000; 969 970 // cache anonymous user info for a long period if the 971 // user has requested to be remembered 972 if (u.is_anonymous && f && f.bakecookie && f.bakecookie.checked) 973 cache_period = 365 * 24 * 60 * 60 * 1000; 974 975 var now = new Date(); 976 mtFixDate(now); 977 now.setTime(now.getTime() + cache_period); 978 979 var cmtcookie = mtBakeUserCookie(u); 980 mtSetCookie(mtCookieName, cmtcookie, now, mtCookiePath, mtCookieDomain, 981 location.protocol == 'https:'); 982} 983 984 985function mtClearUser() { 986 user = null; 987 mtDeleteCookie(mtCookieName, mtCookiePath, mtCookieDomain, 988 location.protocol == 'https:'); 989} 990 991 992function mtSetCookie(name, value, expires, path, domain, secure) { 993 if (domain && ( domain.match(/^\.?localhost$/) || domain.match(/^[0-9\.]+$/) )) 994 domain = null; 995 var curCookie = name + "=" + encodeURIComponent(value) + 996 (expires ? "; expires=" + expires.toGMTString() : "") + 997 (path ? "; path=" + path : "") + 998 (domain ? "; domain=" + domain : "") + 999 (secure ? "; secure" : ""); 1000 document.cookie = curCookie; 1001} 1002 1003 1004function mtGetCookie(name) {
1005 var prefix = name + '='; 1006 var c = document.cookie; 1007 var cookieStartIndex = c.indexOf(prefix); 1008 if (cookieStartIndex == -1) 1009 return ''; 1010 var cookieEndIndex = c.indexOf(";", cookieStartIndex + prefix.length); 1011 if (cookieEndIndex == -1) 1012 cookieEndIndex = c.length; 1013 var this_cookie = c.substring(cookieStartIndex + prefix.length, cookieEndIndex); 1014 if ( this_cookie.match(/\%u/i) ) { 1015 return ''; 1016 } 1017 return decodeURIComponent( this_cookie ); 1018} 1019 1020 1021function mtDeleteCookie(name, path, domain, secure) { 1022 if (mtGetCookie(name)) { 1023 if (domain && domain.match(/^\.?localhost$/)) 1024 domain = null; 1025 document.cookie = name + "=" + 1026 (path ? "; path=" + path : "") + 1027 (domain ? "; domain=" + domain : "") + 1028 (secure ? "; secure" : "") + 1029 "; expires=Thu, 01-Jan-70 00:00:01 GMT"; 1030 } 1031} 1032 1033function mtFixDate(date) { 1034 var skew = (new Date(0)).getTime(); 1035 if (skew > 0) 1036 date.setTime(date.getTime() - skew); 1037} 1038 1039 1040function mtGetXmlHttp() { 1041 if ( !window.XMLHttpRequest ) { 1042 window.XMLHttpRequest = function() { 1043 var types = [ 1044 "Microsoft.XMLHTTP", 1045 "MSXML2.XMLHTTP.5.0", 1046 "MSXML2.XMLHTTP.4.0", 1047 "MSXML2.XMLHTTP.3.0", 1048 "MSXML2.XMLHTTP" 1049 ]; 1050 1051 for ( var i = 0; i < types.length; i++ ) { 1052 try { 1053 return new ActiveXObject( types[ i ] ); 1054 } catch( e ) {} 1055 } 1056 1057 return undefined; 1058 }; 1059 } 1060 if ( window.XMLHttpRequest ) 1061 return new XMLHttpRequest(); 1062} 1063 1064// BEGIN: fast browser onload init 1065// Modifications by David Davis, DWD 1066// Dean Edwards/Matthias Miller/John Resig 1067// http://dean.edwards.name/weblog/2006/06/again/?full#comment5338 1068 1069function mtInit() { 1070 // quit if this function has already been called 1071 if (arguments.callee.done) return; 1072 1073 // flag this function so we don't do the same thing twice 1074 arguments.callee.done = true; 1075 1076 // kill the timer 1077 // DWD - check against window 1078 if ( window._timer ) clearInterval(window._timer); 1079 1080 // DWD - fire the window onload now, and replace it 1081 if ( window.onload && ( window.onload !== window.mtInit ) ) { 1082 window.onload(); 1083 window.onload = function() {}; 1084 } 1085 1086 1087 mtInitCommenter(); 1088 1089 1090} 1091 1092/* for Mozilla/Opera9 */ 1093if (document.addEventListener) { 1094 document.addEventListener("DOMContentLoaded", mtInit, false); 1095} 1096 1097/* for Internet Explorer */ 1098/*@cc_on @*/ 1099/*@if (@_win32) 1100document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); 1101var script = document.getElementById("__ie_onload"); 1102script.onreadystatechange = function() { 1103 if (this.readyState == "complete") { 1104 mtInit(); // call the onload handler 1105 } 1106}; 1107/*@end @*/ 1108 1109/* for Safari */ 1110if (/WebKit/i.test(navigator.userAgent)) { // sniff 1111 _timer = setInterval(function() { 1112 if (/loaded|complete/.test(document.readyState)) { 1113 mtInit(); // call the onload handler 1114 } 1115 }, 10); 1116} 1117 1118/* for other browsers */ 1119window.onload = mtInit; 1120 1121// END: fast browser onload init 1122 1123 1124 1125 1126function mtLoggedIn(ott) { 1127 var script = document.createElement('script'); 1128 var ts = new Date().getTime(); 1129 script.src = 'http://www.montrealites.ca/cgi-bin/mt/hLaSx4qew0QL-q1sS7eTgQ2wIg-c0mn3mts.cgi?__mode=userinfo&jsonp=mtSaveUserInfo&ott=' + ott; 1130 (document.getElementsByTagName('head'))[0].appendChild(script); 1131} 1132 1133function mtRefreshUserInfo(sid) { 1134 var script = document.createElement('script'); 1135 var ts = new Date().getTime(); 1136 script.src = 'http://www.montrealites.ca/cgi-bin/mt/hLaSx4qew0QL-q1sS7eTgQ2wIg-c0mn3mts.cgi?__mode=userinfo&jsonp=mtSaveUserInfo&sid=' + sid; 1137 (document.getElementsByTagName('head'))[0].appendChild(script); 1138} 1139 1140function mtSaveUserInfo (u) { 1141 if ( u.error ) { 1142 if ( !user ) { 1143 alert('The sign-in attempt was not successful; please try again.'); 1144 } 1145 return; 1146 } 1147 user = null; 1148 var cmtcookie = mtBakeUserCookie(u); 1149 var now = new Date(); 1150 var cache_period = mtCookieTimeout * 1000; 1151 1152 // cache anonymous user info for a long period if the 1153 // user has requested to be remembered 1154 mtFixDate(now); 1155 now.setTime(now.getTime() + cache_period); 1156 mtSetCookie(mtCookieName, cmtcookie, now, mtCookiePath, mtCookieDomain, 1157 location.protocol == 'https:'); 1158 mtFireEvent('usersignin'); 1159} 1160 1161function mtInitCommenter () { 1162 /*** 1163 * If request contains a '#_login' or '#_logout' hash, use this to 1164 * also delete the blog-side user cookie, since we're coming back from 1165 * a login, logout or edit profile operation. 1166 */ 1167 1168 var hash = ( window.location.hash ); 1169 hash.match( /^#_(.*)$/ ); 1170 var command = RegExp.$1 || ''; 1171 if ( command === 'refresh' ) { 1172 // Back from profile edit screen. 1173 // Reload userinfo with current session ID. 1174 var u = mtGetUser(); 1175 user = null; 1176 mtRefreshUserInfo(u.sid); 1177 } 1178 else if ( command === 'logout' ) { 1179 // clear any logged in state 1180 mtClearUser(); 1181 mtFireEvent('usersignin'); 1182 } 1183 else if ( command.match( /^login_(.*)$/ ) ) { 1184 var sid = RegExp.$1; 1185 var u = mtGetUser(); 1186 if ( u && u.sid && u.sid == sid ) { 1187 mtFireEvent('usersignin'); 1188 } 1189 else { 1190 mtLoggedIn(sid); 1191 } 1192 } 1193 else { 1194 mtFireEvent('usersignin'); 1195 } 1196} 1197 1198 1199 1200/** 1201 * menuMatic 1202 * @version 0.68.3 (beta) 1203 * @author Jason J. Jaeger | greengeckodesign.com 1204 * @copyright 2008 Jason John Jaeger 1205 * @license MIT-style License 1206 *Permission is hereby granted, free of charge, to any person obtaining a copy 1207 *of this software and associated documentation files (the "Software"), to deal 1208 *in the Software without restriction, including without limitation the rights 1209 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1210 *copies of the Software, and to permit persons to whom the Software is 1211 *furnished to do so, subject to the following conditions: 1212 * 1213 *The above copyright notice and this permission notice shall be included in 1214 *all copies or substantial portions of the Software. 1215 * 1216 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1217 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1218 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1219 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1220 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1221 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 1222 *THE SOFTWARE. 1223 * 1224 * @changeLog_________________________________________________________________________________ 1225 * 1226 * Nov 15th 2008 1227 * JJJ - incremented version to 0.68.3 1228 * - Fixed bug which occured when ol was used instead of ul.. was because you cannot use selectors such 1229 * as 'ul, ol' with getParent() and getNext() despite the mootool documentation saying "if Selectors 1230 * is included, a full CSS selector can be passed." 1231 * 1232 * Nov 4th 2008 1233 * JJJ - incremented version to 0.68.2 1234 * - Removed extranious comma which threw an error in IE. (Thanks to Robert S. for catching that) 1235 * - Added check to change the opacity to 99.9 if it is over 99 due to the fact that 1236 * setting the opaicty to 100% in safari caused misc strange behaviour (thanks to Roland Barker 1237 * at xnau webdesign for reporting this one) 1238 * 1239 * Nov 3rd 2008 1240 * JJJ - Renamed menuWidth option to stretchMainMenu and made it work much quicker 1241 * 1242 * Nov 2nd 2008
1243 * JJJ - Finished adding several callback functions 1244 * - Added fixHasLayoutBug option 1245 * 1246 * Oct 4th 2008 1247 * JJJ - Continued to go through code to optimize and clean it up 1248 * - Added center option 1249 * 1250 * Sept 28th 2008 1251 * JJJ - Incremented version to 0.68 1252 * - Began optimizing & better commenting code 1253 * 1254 * Sept 16th 2008 1255 * JJJ - Incremented version to 0.67 1256 * - Specifically set each submenu z-index on show, incrementing each time. Set z-index back to 1 on hide. 1257 * 1258 * Sept 14th 2008 1259 * JJJ - Added bottom edge detection and redirection (if bottom of subsequent submenu is lower than the scrollheight of the body) 1260 * 1261 * Sept 10th 2008 1262 * JJJ - Did a google search for MooMenu and it looks like that name is already being used, so I must reluctently change the name. 1263 * The name I have chose to move forward with is: MenuMatic. 1264 * 1265 * Sept 8th 2008 1266 * JJJ - Incremented version to 0.66 1267 * - Fixed IE bug whiched caused some events to be incorrectly attached to parent buttons causing sub submenus to not open 1268 * correctly when transitions are enabled. This error was introduced in 0.65. 1269 * 1270 * August 10th 2008 1271 * JJJ - Incremented verion to 0.65 1272 * - Fixed bug with edge detection and redirection 1273 * - Improved javascript and CSS to assure the submenus will always be on top 1274 * - Improved edge detection and redirection logic 1275 * - Added subMenusContainerId option so that if you have multiple MooMenu instances on a page they can be styled differently 1276 * 1277 * May 7th 2008 1278 * JJJ - Incremented version to 0.64 1279 * - Fixed bug with that occured when firing events 1280 * 1281 * April 28th 2008: 1282 * JJJ - Incremented version to 0.63 1283 * - Added killDivider option 1284 * - Removed focus on hover since it adds browser default dotted outline 1285 * - Changed menuWidth option to use actual width of nav element (so it can be set in css) instead of a width set in javascript 1286 * 1287 * Feb 17th 2008: 1288 * JJJ - Incremented version to 0.62 1289 * - Added mmbClassName and mmbFocusedClassName options to allow morphing of main menu btns 1290 * 1291 * Feb 16th 2008: 1292 * JJJ - Incremented version to 0.61 1293 * - Made changes to options syntax. 1294 * - Improved keyboard accessability to take into account a menu's orientation, and its x and y direction when using arrow keys 1295 * - Added matchWidthMode option. 1296 * 1297 * Feb 14th 2008: 1298 * JJJ - Incremented version to 0.60 1299 * - Added menuWidth option to simulate a table based layout for the main menu when the orienation is horizontal 1300 **/ 1301 1302 1303/* 1304 * To Do: 1305 * 1306 * 1. Make screencast tutorials 1307 * 1308 * 2. Add more examples to website 1309 * 1310 * 3. Clean up/optimize CSS / make easier to edit 1311 * 1312 * 4. Make online generator 1313 * 1314 * 5. Add rounded corners option 1315 * 1316 * 6. Add drop shadow option 1317 * 1318 * 7. Add sound integration 1319 * 1320 */ 1321 1322var MenuMatic = new Class({ 1323Implements: Options, 1324options: { 1325 id: 'nav',//the id of the main menu (ul or ol) 1326 subMenusContainerId:'subMenusContainer',//id of the container div that will be generated to hold the submenus 1327 1328//subMenu behavior 1329effect: 'slide & fade',// 'slide', 'fade', 'slide & fade', or null 1330duration: 600,//duration of the effect in milliseconds 1331physics: Fx.Transitions.Pow.easeOut,//how the effect behaves 1332hideDelay: 1000,//in milliseconds, how long you have after moving your mouse off of the submenus before they dissapear 1333 1334//layout 1335stretchMainMenu:false,//stretch main menu btn widths to fit within the width {set in the css} of the parent UL or OL 1336matchWidthMode:false,//initial submenus match their parent button's width 1337orientation: 'horizontal',//horizontal or vertical 1338direction:{x: 'right',y: 'down' },//for submenus ( relative to the parent button )left or right, up or down 1339tweakInitial:{ x:0, y:0},//if you need to tweak the placement of the initial submenus 1340tweakSubsequent:{ x:0, y:0 },//if you need to tweak the placement of the subsequent submenus 1341center: false,// will attempt to center main nav element 1342 1343//dynamic style 1344opacity: 95,//of the submenus 1345mmbFocusedClassName:null,//main menu button classname, used for morphing to focused state 1346mmbClassName:null,//main menu button classname, used for morphing back to original state 1347killDivider:null, 1348 1349fixHasLayoutBug:false, 1350 1351onHideAllSubMenusNow_begin: (function(){}), 1352onHideAllSubMenusNow_complete: (function(){}), 1353 1354onInit_begin: (function(){}), 1355onInit_complete: (function(){}) 1356 1357 }, 1358 1359hideAllMenusTimeout:null, 1360allSubMenus:[], 1361subMenuZindex:1, 1362 1363initialize: function(options){ 1364//if(Browser.Engine.webkit419){return;} 1365 this.setOptions(options); 1366this.options.onInit_begin(); 1367if(this.options.opacity > 99){this.options.opacity = 99.9;} 1368this.options.opacity = this.options.opacity /100; 1369 1370Element.implement({ 1371 getId: function(){ 1372//If this element does not have an id, give it a unique one 1373 if(!this.id){ 1374var uniqueId = this.get('tag') + "-" + $time(); 1375while($(uniqueId)){ 1376//make sure it is absolutely unique 1377uniqueId = this.get('tag') + "-" + $time(); 1378} 1379this.id = uniqueId; 1380} 1381 return this.id; 1382 } 1383}); 1384 1385//initialize directions 1386this.options.direction.x = this.options.direction.x.toLowerCase(); 1387this.options.direction.y = this.options.direction.y.toLowerCase(); 1388if(this.options.direction.x === 'right'){ 1389this.options.direction.xInverse = 'left'; 1390}else if(this.options.direction.x === 'left'){ 1391this.options.direction.xInverse = 'right'; 1392} 1393if(this.options.direction.y === 'up'){ 1394this.options.direction.yInverse = 'down'; 1395}else if(this.options.direction.y === 'down'){ 1396this.options.direction.yInverse = 'up'; 1397} 1398 1399var links = $(this.options.id).getElements('a'); 1400 1401links.each(function(item,index){ 1402 1403//store parent links & child menu info 1404item.store('parentLinks', item.getParent().getParents('li').getFirst('a')); 1405 1406item.store('parentLinks',item.retrieve('parentLinks').erase(item.retrieve('parentLinks').getFirst())); 1407item.store('childMenu',item.getNext('ul') || item.getNext('ol')); 1408 1409//determine submenu type 1410theSubMenuType = 'subsequent'; 1411 1412//console.log($(this.options.id).getElements('ul, ol')); 1413//console.log(item.getParent(['body ul,ol'])); 1414 1415//console.log($(item.getParent('ul') || item.getParent('ol') )); 1416 1417if( $(item.getParent('ul') || item.getParent('ol') ).id === this.options.id){theSubMenuType = 'initial';} 1418item.store('subMenuType',theSubMenuType ); 1419 1420//add classes to parents 1421if(theSubMenuType === 'initial' && $(item.getNext('ul') || item.getNext('ol') )){ 1422item.addClass('mainMenuParentBtn'); 1423}else if($(item.getNext('ul') || item.getNext('ol') )){ 1424item.addClass('subMenuParentBtn'); 1425} 1426}.bind(this)); 1427 1428//rip the submenus apart into separate divs inside of subMenusContainer 1429var subMenusContainer = new Element('div', { 'id': this.options.subMenusContainerId}).inject( $(document.body) ,'bottom'); 1430$(this.options.id).getElements('ul, ol').each(function(item,index){ 1431new Element('div',{'class': 'smOW'}).inject(subMenusContainer).grab(item); 1432}.bind(this)); 1433 1434//set tabindex to -1 so tabbing through links in page does not go through hidden links in submenus container, since arrow keys can be used to navigate through submenus 1435subMenusContainer.getElements('a').set('tabindex','-1'); 1436 1437links.each(function(item,index){ 1438//only apply to links with subMenus
1439if (!item.retrieve('childMenu')) {return;} 1440 1441//update childMenu pointer to look at smOW DIVs 1442item.store('childMenu', item.retrieve('childMenu').getParent('div')); 1443 1444//add to allSubMenus array 1445this.allSubMenus.include(item.retrieve('childMenu')); 1446 1447//store parentSubMenus 1448item.store('parentSubMenus',item.retrieve('parentLinks').retrieve('childMenu')); 1449 1450//now create the MenuMaticSubMenu class instances 1451var aSubMenu = new MenuMaticSubMenu(this.options,this, item); 1452 1453}.bind(this)); 1454 1455//attach event handlers to non-parent main menu buttons 1456var nonParentBtns = $(this.options.id).getElements('a').filter(function(item, index){ return !item.retrieve('childMenu'); }); 1457nonParentBtns.each(function(item, index){ 1458item.addEvents({ 1459'mouseenter': function(e){ 1460//e = new Event(e).stop(); 1461this.hideAllSubMenusNow(); 1462if(this.options.mmbClassName && this.options.mmbFocusedClassName){ 1463$(item).retrieve('btnMorph', new Fx.Morph(item, { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel'})).start(this.options.mmbFocusedClassName); 1464} 1465}.bind(this), 1466 1467'focus': function(e){ 1468//e = new Event(e).stop(); 1469this.hideAllSubMenusNow(); 1470if(this.options.mmbClassName && this.options.mmbFocusedClassName){ 1471$(item).retrieve('btnMorph', new Fx.Morph(item, { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel'})).start(this.options.mmbFocusedClassName); 1472} 1473}.bind(this), 1474 1475'mouseleave':function(e){ 1476//e = new Event(e).stop(); 1477if (this.options.mmbClassName && this.options.mmbFocusedClassName) { 1478$(item).retrieve('btnMorph', new Fx.Morph(item, {'duration': (this.options.duration * 5),transition: this.options.physics,link: 'cancel'})).start(this.options.mmbClassName); 1479} 1480}.bind(this), 1481 1482'blur':function(e){ 1483//e = new Event(e).stop(); 1484if (this.options.mmbClassName && this.options.mmbFocusedClassName) { 1485$(item).retrieve('btnMorph', new Fx.Morph(item, {'duration': (this.options.duration * 5),transition: this.options.physics,link: 'cancel'})).start(this.options.mmbClassName); 1486} 1487}.bind(this), 1488 1489'keydown' : function(e){ 1490 var event = new Event(e); 1491if (e.key === 'up' || e.key === 'down' || e.key === 'left' || e.key === 'right') {e.stop();} 1492 1493if( e.key === 'left' && this.options.orientation === 'horizontal' || 1494e.key === 'up' && this.options.orientation === 'vertical'){ 1495 1496if(item.getParent('li').getPrevious('li')){ 1497item.getParent('li').getPrevious('li').getFirst('a').focus(); 1498}else{ 1499item.getParent('li').getParent().getLast('li').getFirst('a').focus(); 1500} 1501}else if(e.key === 'right' && this.options.orientation === 'horizontal' || 1502 e.key === 'down' && this.options.orientation === 'vertical'){ 1503if(item.getParent('li').getNext('li')){ 1504item.getParent('li').getNext('li').getFirst('a').focus(); 1505}else{ 1506item.getParent('li').getParent().getFirst('li').getFirst('a').focus(); 1507} 1508} 1509}.bind(this) 1510}); 1511}, this); 1512 1513 1514this.stretch(); 1515this.killDivider(); 1516this.center(); 1517this.fixHasLayoutBug(); 1518this.options.onInit_complete(); 1519 }, 1520 1521fixHasLayoutBug:function(){ 1522if(Browser.Engine.trident && this.options.fixHasLayoutBug){ 1523$(this.options.id).getParents().setStyle('zoom',1); 1524$(this.options.id).setStyle('zoom',1); 1525$(this.options.id).getChildren().setStyle('zoom',1); 1526$(this.options.subMenusContainerId).setStyle('zoom',1); 1527$(this.options.subMenusContainerId).getChildren().setStyle('zoom',1); 1528} 1529}, 1530 1531center:function(){ 1532if(!this.options.center){return;} 1533$(this.options.id).setStyles({'left':'50%','margin-left': -($(this.options.id).getSize().x/2) }); 1534}, 1535 1536stretch:function(){ 1537//stretch main menu btn widths to fit within the width of the parent UL or OL 1538if(this.options.stretchMainMenu && this.options.orientation === 'horizontal'){ 1539var targetWidth = parseFloat($(this.options.id).getCoordinates().width) ; 1540var totalBtnWidth = 0; 1541var mainBtns = $(this.options.id).getElements('a'); 1542mainBtns.setStyles({'padding-left':0,'padding-right':0}); 1543mainBtns.each(function(item,index){ totalBtnWidth+= item.getSize().x; }.bind(this)); 1544if(targetWidth < totalBtnWidth){return;} 1545var increment = (targetWidth - totalBtnWidth)/ mainBtns.length; 1546mainBtns.each(function(item,index){ item.setStyle('width',item.getSize().x+increment);}.bind(this)); 1547mainBtns.getLast().setStyle('width',mainBtns.getLast().getSize().x-1); 1548} 1549}, 1550 1551killDivider:function(){ 1552if(this.options.killDivider && this.options.killDivider.toLowerCase() === 'first'){ 1553$($(this.options.id).getElements('li')[0]).setStyles({'background':'none'}); 1554}else if(this.options.killDivider && this.options.killDivider.toLowerCase() === 'last'){ 1555$($(this.options.id).getElements('li').getLast()).setStyles({'background':'none'}); 1556} 1557}, 1558 1559hideAllSubMenusNow: function(){ 1560this.options.onHideAllSubMenusNow_begin(); 1561$clear(this.hideAllMenusTimeout); 1562$$(this.allSubMenus).fireEvent('hide'); 1563this.options.onHideAllSubMenusNow_complete(); 1564} 1565 1566}); 1567 1568var MenuMaticSubMenu = new Class({ 1569Implements: Options, 1570Extends: MenuMatic, 1571 options: { 1572onSubMenuInit_begin: (function(subMenuClass){}), 1573onSubMenuInit_complete: (function(subMenuClass){}), 1574 1575onMatchWidth_begin: (function(subMenuClass){}), 1576onMatchWidth_complete: (function(subMenuClass){}), 1577 1578onHideSubMenu_begin: (function(subMenuClass){}), 1579onHideSubMenu_complete: (function(subMenuClass){}), 1580 1581onHideOtherSubMenus_begin: (function(subMenuClass){}), 1582onHideOtherSubMenus_complete: (function(subMenuClass){}), 1583 1584onHideAllSubMenus_begin: (function(subMenuClass){}), 1585onHideAllSubMenus_complete: (function(subMenuClass){}), 1586 1587onPositionSubMenu_begin: (function(subMenuClass){}), 1588onPositionSubMenu_complete: (function(subMenuClass){}), 1589 1590onShowSubMenu_begin: (function(subMenuClass){}), 1591onShowSubMenu_complete: (function(subMenuClass){}) 1592}, 1593root:null, 1594btn:null, 1595hidden:true, 1596myEffect:null, 1597 1598initialize: function(options,root,btn){ 1599this.setOptions(options); 1600this.root = root; 1601this.btn = btn;
1602this.childMenu = this.btn.retrieve('childMenu'); 1603this.subMenuType = this.btn.retrieve('subMenuType'); 1604this.childMenu = this.btn.retrieve('childMenu'); 1605this.parentSubMenus = $$(this.btn.retrieve('parentSubMenus')); 1606this.parentLinks = $$(this.btn.retrieve('parentLinks')); 1607this.parentSubMenu = $(this.parentSubMenus[0]); 1608if(this.parentSubMenu ){this.parentSubMenu =this.parentSubMenu.retrieve('class');} 1609this.childMenu.store('class',this); 1610this.btn.store('class',this); 1611this.childMenu.store('status','closed') 1612 1613this.options.onSubMenuInit_begin(this); 1614 1615//add hide Event 1616this.childMenu.addEvent('hide',function(){this.hideSubMenu();}.bind(this)); 1617 1618//add show Event 1619this.childMenu.addEvent('show',function(){this.showSubMenu();}.bind(this)); 1620 1621if(this.options.effect){ 1622this.myEffect = new Fx.Morph( 1623$(this.childMenu).getFirst(), {duration: this.options.duration, transition: this.options.physics, link: 'cancel' } 1624); 1625} 1626if(this.options.effect === 'slide' || this.options.effect === 'slide & fade'){ 1627if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' ) { 1628this.childMenu.getFirst().setStyle('margin-top','0' ); 1629}else { 1630this.childMenu.getFirst().setStyle('margin-left', '0'); 1631} 1632 1633}else if (this.options.effect === 'fade' || this.options.effect === 'slide & fade'){ 1634this.childMenu.getFirst().setStyle('opacity',0 ); 1635} 1636 1637if (this.options.effect != 'fade' && this.options.effect != 'slide & fade') { 1638this.childMenu.getFirst().setStyle('opacity',this.options.opacity); 1639} 1640 1641 1642//attach event handlers to non-parent sub menu buttons 1643var nonParentBtns = $(this.childMenu).getElements('a').filter(function(item, index){ return !item.retrieve('childMenu'); }); 1644nonParentBtns.each(function(item, index){ 1645$(item).addClass('subMenuBtn'); 1646 1647item.addEvents({ 1648'mouseenter': function(e){ 1649this.childMenu.fireEvent('show'); 1650this.cancellHideAllSubMenus(); 1651this.hideOtherSubMenus(); 1652}.bind(this), 1653 1654'focus': function(e){ 1655this.childMenu.fireEvent('show'); 1656this.cancellHideAllSubMenus(); 1657this.hideOtherSubMenus(); 1658}.bind(this), 1659 1660'mouseleave': function(e){ 1661this.cancellHideAllSubMenus(); 1662this.hideAllSubMenus(); 1663}.bind(this), 1664 1665'blur': function(e){ 1666this.cancellHideAllSubMenus(); 1667this.hideAllSubMenus(); 1668}.bind(this), 1669 1670'keydown' : function(e){ 1671 var event = new Event(e); 1672 1673if (e.key === 'up' || e.key === 'down' || e.key === 'left' || e.key === 'right' || e.key === 'tab') {e.stop();} 1674 1675if(e.key === 'up'){ 1676if(item.getParent('li').getPrevious('li')){ 1677//move focus to the next link up if possible 1678item.getParent('li').getPrevious('li').getFirst('a').focus(); 1679}else if(this.options.direction.y ==='down'){ 1680//move focus to the parent link 1681this.btn.focus(); 1682}else if(this.options.direction.y ==='up'){ 1683//move focus to the last link in the subMenu 1684item.getParent('li').getParent().getLast('li').getFirst('a').focus(); 1685} 1686}else if(e.key === 'down'){ 1687if(item.getParent('li').getNext('li')){ 1688//move focus to the next link down if possible 1689item.getParent('li').getNext('li').getFirst('a').focus(); 1690}else if(this.options.direction.y ==='down'){ 1691//move focus to the first link in the submenu 1692item.getParent('li').getParent().getFirst('li').getFirst('a').focus(); 1693}else if(this.options.direction.y ==='up'){ 1694//move focus to the parent link 1695this.btn.focus(); 1696} 1697}else if(e.key === this.options.direction.xInverse){ 1698this.btn.focus(); 1699} 1700}.bind(this) 1701}); 1702 1703}, this); 1704 1705$(this.btn).removeClass('subMenuBtn'); 1706 1707if (this.subMenuType == 'initial') { 1708this.btn.addClass('mainParentBtn'); 1709}else{ 1710this.btn.addClass('subParentBtn'); 1711} 1712 1713//attach event handlers to parent button 1714$(this.btn).addEvents({ 1715'mouseenter' : function(e){ 1716//e = new Event(e).stop(); 1717this.cancellHideAllSubMenus(); 1718this.hideOtherSubMenus(); 1719this.showSubMenu(); 1720if(this.subMenuType === 'initial' && this.options.mmbClassName && this.options.mmbFocusedClassName){ 1721$(this.btn).retrieve('btnMorph', new Fx.Morph($(this.btn), { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel' })).start(this.options.mmbFocusedClassName); 1722} 1723}.bind(this), 1724 1725'focus' : function(e){ 1726//e = new Event(e).stop(); 1727this.cancellHideAllSubMenus(); 1728this.hideOtherSubMenus(); 1729this.showSubMenu(); 1730if(this.subMenuType === 'initial' && this.options.mmbClassName && this.options.mmbFocusedClassName){ 1731$(this.btn).retrieve('btnMorph', new Fx.Morph($(this.btn), { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel' })).start(this.options.mmbFocusedClassName); 1732} 1733}.bind(this), 1734 1735'mouseleave': function(e){ 1736//e = new Event(e).stop(); 1737this.cancellHideAllSubMenus(); 1738this.hideAllSubMenus(); 1739}.bind(this), 1740 1741'blur': function(e){ 1742//e = new Event(e).stop(); 1743this.cancellHideAllSubMenus(); 1744this.hideAllSubMenus(); 1745}.bind(this), 1746 1747'keydown' : function(e){ 1748 e = new Event(e) 1749if (e.key === 'up' || e.key === 'down' || e.key === 'left' || e.key === 'right') {e.stop();} 1750 1751if(!this.parentSubMenu){ 1752//main menu parent buttons 1753if( 1754this.options.orientation === 'horizontal' && e.key === this.options.direction.y || 1755this.options.orientation === 'vertical' && e.key === this.options.direction.x 1756){ 1757if(this.options.direction.y ==='down'){ 1758//move focus to the first link in the child menu 1759this.childMenu.getFirst().getFirst('li').getFirst('a').focus(); 1760}else if(this.options.direction.y ==='up'){ 1761//move focus to the first link in the child menu 1762this.childMenu.getFirst().getLast('li').getFirst('a').focus(); 1763} 1764}else if( 1765this.options.orientation === 'horizontal' && e.key === 'left' || 1766this.options.orientation === 'vertical' && e.key === this.options.direction.yInverse 1767){ 1768//move focus to the previous link if possible, if not, move focus to the last link in the menu 1769if(this.btn.getParent().getPrevious()){ 1770this.btn.getParent().getPrevious().getFirst().focus(); 1771}else{ 1772this.btn.getParent().getParent().getLast().getFirst().focus(); 1773} 1774}else if( 1775this.options.orientation === 'horizontal' && e.key === 'right' || 1776this.options.orientation === 'vertical' && e.key === this.options.direction.y 1777){ 1778//move focus to the next link if possible, if not, move focus to the first link in the menu 1779if (this.btn.getParent().getNext()) { 1780this.btn.getParent().getNext().getFirst().focus(); 1781}else{ 1782this.btn.getParent().getParent().getFirst().getFirst().focus(); 1783} 1784} 1785}else{ 1786if(e.key === 'tab'){e.stop();} 1787//submenu parent buttons 1788if (e.key === 'up') { 1789if (this.btn.getParent('li').getPrevious('li')) { 1790//move focus to the next link up 1791this.btn.getParent('li').getPrevious('li').getFirst('a').focus(); 1792}else if(this.options.direction.y === 'down'){ 1793//move focus to the parent link 1794this.parentSubMenu.btn.focus(); 1795}else if(this.options.direction.y === 'up'){ 1796//move focus to the bottom link in this submenu 1797this.btn.getParent('li').getParent().getLast('li').getFirst('a').focus(); 1798} 1799}else if(e.key === 'down'){ 1800if(this.btn.getParent('li').getNext('li')){ 1801//move focus to the next link down 1802this.btn.getParent('li').getNext('li').getFirst('a').focus(); 1803}else if(this.options.direction.y === 'down'){ 1804//move focus to the top link in this submenu 1805this.btn.getParent('li').getParent().getFirst('li').getFirst('a').focus(); 1806}else if(this.options.direction.y === 'up'){ 1807//move focus to the parent link 1808this.parentSubMenu.btn.focus(); 1809} 1810}else if(e.key === this.options.direction.xInverse){ 1811this.parentSubMenu.btn.focus(); 1812}else if(e.key === this.options.direction.x){ 1813if(this.options.direction.y === 'down'){ 1814this.childMenu.getFirst().getFirst('li').getFirst('a').focus(); 1815}else if(this.options.direction.y === 'up'){ 1816//this.childMenu.getFirst().getLast('li').getFirst('a').focus(); 1817} 1818} 1819} 1820}.bind(this) 1821}); 1822 1823this.options.onSubMenuInit_complete(this); 1824 1825 }, 1826 1827matchWidth:function(){ 1828if (this.widthMatched || !this.options.matchWidthMode || this.subMenuType === 'subsequent'){return;} 1829this.options.onMatchWidth_begin(this); 1830var parentWidth = this.btn.getCoordinates().width; 1831$(this.childMenu).getElements('a').each(function(item,index){ 1832var borderWidth = parseFloat($(this.childMenu).getFirst().getStyle('border-left-width')) + parseFloat($(this.childMenu).getFirst().getStyle('border-right-width')); 1833var paddingWidth = parseFloat(item.getStyle('padding-left')) + parseFloat(item.getStyle('padding-right')); 1834var offset = borderWidth + paddingWidth ; 1835if(parentWidth > item.getCoordinates().width){ 1836item.setStyle('width',parentWidth - offset); 1837item.setStyle('margin-right',-borderWidth); 1838} 1839}.bind(this)); 1840this.width = this.childMenu.getFirst().getCoordinates().width; 1841this.widthMatched = true; 1842this.options.onMatchWidth_complete(this); 1843}, 1844 1845hideSubMenu: function() { 1846if(this.childMenu.retrieve('status') === 'closed'){return;} 1847this.options.onHideSubMenu_begin(this); 1848if (this.subMenuType == 'initial') { 1849if(this.options.mmbClassName && this.options.mmbFocusedClassName){ 1850$(this.btn).retrieve('btnMorph', new Fx.Morph($(this.btn), { 'duration':(this.options.duration), transition:this.options.physics, link:'cancel' })).start(this.options.mmbClassName ) 1851.chain(function(){ 1852$(this.btn).removeClass('mainMenuParentBtnFocused'); 1853$(this.btn).addClass('mainMenuParentBtn'); 1854}.bind(this)); 1855}else{ 1856$(this.btn).removeClass('mainMenuParentBtnFocused'); 1857$(this.btn).addClass('mainMenuParentBtn'); 1858} 1859}else{ 1860$(this.btn).removeClass('subMenuParentBtnFocused'); 1861$(this.btn).addClass('subMenuParentBtn'); 1862} 1863 1864this.childMenu.setStyle('z-index',1); 1865 1866if(this.options.effect && this.options.effect.toLowerCase() === 'slide'){ 1867if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'down') { 1868this.myEffect.start({ 'margin-top': -this.height }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1869}else if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'up') { 1870this.myEffect.start({ 'margin-top': this.height }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1871}else if(this.options.direction.x === 'right'){ 1872this.myEffect.start({ 'margin-left': -this.width }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1873}else if(this.options.direction.x === 'left'){ 1874this.myEffect.start({ 'margin-left': this.width }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1875} 1876}else if(this.options.effect == 'fade'){ 1877this.myEffect.start({ 'opacity': 0 }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1878}else if(this.options.effect == 'slide & fade'){ 1879 1880if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'down') { 1881this.myEffect.start({ 'margin-top': -this.height,opacity:0 }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1882}else if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'up') { 1883this.myEffect.start({ 'margin-top': this.height,opacity:0 }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1884}else if(this.options.direction.x === 'right'){ 1885this.myEffect.start({ 'margin-left': -this.width,opacity:0 }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1886}else if(this.options.direction.x === 'left'){ 1887this.myEffect.start({ 'margin-left': this.width, opacity:0 }).chain(function(){this.childMenu.style.display = "none";}.bind(this)); 1888} 1889}else{ 1890this.childMenu.style.display = "none"; 1891} 1892this.childMenu.store('status','closed'); 1893this.options.onHideSubMenu_complete(this); 1894}, 1895 1896hideOtherSubMenus: function() { 1897this.options.onHideOtherSubMenus_begin(this); 1898//set up otherSubMenus element collection 1899if(!this.btn.retrieve('otherSubMenus')){ 1900this.btn.store('otherSubMenus', $$(this.root.allSubMenus.filter(function(item){ return !this.btn.retrieve('parentSubMenus').contains(item) && item != this.childMenu; }.bind(this)) )); 1901} 1902this.parentSubMenus.fireEvent('show'); 1903this.btn.retrieve('otherSubMenus').fireEvent('hide'); 1904this.options.onHideOtherSubMenus_complete(this); 1905}, 1906 1907hideAllSubMenus: function(){ 1908this.options.onHideAllSubMenus_begin(this); 1909$clear(this.root.hideAllMenusTimeout); 1910this.root.hideAllMenusTimeout = (function(){ 1911$clear(this.hideAllMenusTimeout); 1912$$(this.root.allSubMenus).fireEvent('hide'); 1913}).bind(this).delay(this.options.hideDelay); 1914this.options.onHideAllSubMenus_complete(this); 1915}, 1916 1917cancellHideAllSubMenus: function(){ 1918$clear(this.root.hideAllMenusTimeout); 1919}, 1920 1921showSubMenu: function(now){ 1922if(this.childMenu.retrieve('status') === 'open'){return;} 1923this.options.onShowSubMenu_begin(this); 1924if (this.subMenuType == 'initial') { 1925$(this.btn).removeClass('mainMenuParentBtn'); 1926$(this.btn).addClass('mainMenuParentBtnFocused'); 1927}else{ 1928$(this.btn).removeClass('subMenuParentBtn'); 1929$(this.btn).addClass('subMenuParentBtnFocused'); 1930} 1931this.root.subMenuZindex++; 1932this.childMenu.setStyles({'display':'block','visibility':'hidden','z-index':this.root.subMenuZindex}); 1933 1934if(!this.width || !this.height ){ 1935this.width = this.childMenu.getFirst().getCoordinates().width; 1936this.height = this.childMenu.getFirst().getCoordinates().height; 1937this.childMenu.setStyle('height',this.height,'border'); 1938if(this.options.effect === 'slide' || this.options.effect === 'slide & fade'){ 1939if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' ) { 1940this.childMenu.getFirst().setStyle('margin-top','0' ); 1941if(this.options.direction.y === 'down'){ 1942this.myEffect.set({ 'margin-top': - this.height }); 1943}else if(this.options.direction.y === 'up'){ 1944this.myEffect.set({ 'margin-top': this.height }); 1945} 1946}else { 1947if(this.options.direction.x === 'left'){ 1948this.myEffect.set({ 'margin-left': this.width }); 1949}else{ 1950this.myEffect.set({ 'margin-left': -this.width }); 1951} 1952} 1953} 1954} 1955this.matchWidth(); 1956this.positionSubMenu(); 1957 1958if(this.options.effect === 'slide' ){ 1959this.childMenu.setStyles({'display':'block','visibility':'visible'}); 1960if (this.subMenuType === 'initial' && this.options.orientation === 'horizontal') { 1961if(now){ 1962this.myEffect.set({ 'margin-top': 0 }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1963}else{ 1964this.myEffect.start({ 'margin-top': 0 }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1965} 1966}else{ 1967if (now) { 1968this.myEffect.set({ 'margin-left': 0 }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1969}else{ 1970this.myEffect.start({ 'margin-left': 0 }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1971} 1972} 1973}else if(this.options.effect === 'fade' ){ 1974if (now) { 1975this.myEffect.set({'opacity': this.options.opacity}).chain(function(){this.showSubMenuComplete();}.bind(this)); 1976}else{ 1977this.myEffect.start({'opacity': this.options.opacity}).chain(function(){this.showSubMenuComplete();}.bind(this)); 1978} 1979}else if(this.options.effect == 'slide & fade'){ 1980this.childMenu.setStyles({'display':'block','visibility':'visible'}); 1981this.childMenu.getFirst().setStyles({'left':0}); 1982if (this.subMenuType === 'initial' && this.options.orientation === 'horizontal') { 1983if (now) { 1984this.myEffect.set({ 'margin-top': 0, 'opacity': this.options.opacity }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1985}else{ 1986this.myEffect.start({ 'margin-top': 0, 'opacity': this.options.opacity }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1987} 1988}else{ 1989if (now) { 1990if (this.options.direction.x === 'right') { 1991this.myEffect.set({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1992}else if (this.options.direction.x === 'left') { 1993this.myEffect.set({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1994} 1995}else{ 1996if (this.options.direction.x === 'right') { 1997this.myEffect.set({ 'margin-left': -this.width, 'opacity': this.options.opacity }); 1998this.myEffect.start({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){this.showSubMenuComplete();}.bind(this)); 1999}else if (this.options.direction.x === 'left') { 2000this.myEffect.start({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){this.showSubMenuComplete();}.bind(this)); 2001} 2002} 2003} 2004}else{ 2005this.childMenu.setStyles({'display':'block','visibility':'visible'}).chain(function(){this.showSubMenuComplete(this);}.bind(this)); 2006} 2007this.childMenu.store('status','open'); 2008 2009}, 2010 2011showSubMenuComplete:function(){ 2012this.options.onShowSubMenu_complete(this); 2013}, 2014 2015positionSubMenu: function(){ 2016this.options.onPositionSubMenu_begin(this); 2017this.childMenu.setStyle('width',this.width) ; 2018this.childMenu.getFirst().setStyle('width',this.width) ; 2019 2020//if any parent has bounced off a viewport edge, inherit that new di
2020rection 2021if (this.subMenuType === 'subsequent') { 2022if(this.parentSubMenu && this.options.direction.x != this.parentSubMenu.options.direction.x){ 2023if(this.parentSubMenu.options.direction.x === 'left' && this.options.effect && this.options.effect.contains('slide')){ 2024this.myEffect.set({ 'margin-left': this.width }); 2025} 2026} 2027this.options.direction.x = this.parentSubMenu.options.direction.x; 2028this.options.direction.xInverse = this.parentSubMenu.options.direction.xInverse; 2029this.options.direction.y = this.parentSubMenu.options.direction.y; 2030this.options.direction.yInverse = this.parentSubMenu.options.direction.yInverse; 2031} 2032 2033var top; 2034var overlap 2035if(this.subMenuType == 'initial'){ 2036if(this.options.direction.y === 'up'){ 2037if(this.options.orientation === 'vertical'){ 2038top = this.btn.getCoordinates().bottom - this.height + this.options.tweakInitial.y ; 2039}else{ 2040top = this.btn.getCoordinates().top - this.height + this.options.tweakInitial.y ; 2041} 2042this.childMenu.style.top = top+ 'px'; 2043}else if(this.options.orientation == 'horizontal'){ 2044this.childMenu.style.top = this.btn.getCoordinates().bottom + this.options.tweakInitial.y + 'px'; 2045}else if(this.options.orientation == 'vertical'){ 2046top = this.btn.getPosition().y + this.options.tweakInitial.y ; 2047if((top + this.childMenu.getSize().y) >= $(document.body).getScrollSize().y){ 2048overlap = (top + this.childMenu.getSize().y) - $(document.body).getScrollSize().y ; 2049top = top - overlap - 20; 2050} 2051this.childMenu.style.top = top+ 'px'; 2052} 2053if(this.options.orientation == 'horizontal'){ 2054this.childMenu.style.left = this.btn.getPosition().x + this.options.tweakInitial.x + 'px'; 2055}else if(this.options.direction.x == 'left'){ 2056this.childMenu.style.left = this.btn.getPosition().x - this.childMenu.getCoordinates().width + this.options.tweakInitial.x + 'px'; 2057}else if(this.options.direction.x == 'right'){ 2058this.childMenu.style.left = this.btn.getCoordinates().right + this.options.tweakInitial.x + 'px'; 2059} 2060}else if(this.subMenuType == 'subsequent'){ 2061 2062if(this.options.direction.y === 'down'){ 2063if( (this.btn.getCoordinates().top + this.options.tweakSubsequent.y+ this.childMenu.getSize().y) >= $(document.body).getScrollSize().y ){ 2064overlap = (this.btn.getCoordinates().top + this.options.tweakSubsequent.y+ this.childMenu.getSize().y) -$(document.body).getScrollSize().y ; 2065this.childMenu.style.top = (this.btn.getCoordinates().top + this.options.tweakSubsequent.y) - overlap - 20+ 'px'; 2066}else{ 2067this.childMenu.style.top = this.btn.getCoordinates().top + this.options.tweakSubsequent.y + 'px'; 2068} 2069}else if(this.options.direction.y === 'up'){ 2070if((this.btn.getCoordinates().bottom - this.height + this.options.tweakSubsequent.y)< 1){ 2071this.options.direction.y = 'down'; 2072this.options.direction.yInverse = 'up'; 2073this.childMenu.style.top = this.btn.getCoordinates().top + this.options.tweakSubsequent.y + 'px'; 2074}else{ 2075this.childMenu.style.top = this.btn.getCoordinates().bottom - this.height + this.options.tweakSubsequent.y + 'px'; 2076} 2077} 2078if(this.options.direction.x == 'left'){ 2079this.childMenu.style.left = this.btn.getCoordinates().left - this.childMenu.getCoordinates().width + this.options.tweakSubsequent.x + 'px'; 2080 2081if( this.childMenu.getPosition().x < 0){ 2082this.options.direction.x = 'right'; 2083this.options.direction.xInverse = 'left'; 2084this.childMenu.style.left = this.btn.getPosition().x + this.btn.getCoordinates().width + this.options.tweakSubsequent.x + 'px'; 2085 2086if(this.options.effect === 'slide' || this.options.effect === 'slide & fade'){ 2087this.myEffect.set({ 'margin-left': -this.width, 'opacity': this.options.opacity }); 2088} 2089} 2090}else if(this.options.direction.x == 'right'){ 2091this.childMenu.style.left = this.btn.getCoordinates().right + this.options.tweakSubsequent.x + 'px'; 2092var smRight = this.childMenu.getCoordinates().right; 2093var viewportRightEdge = document.getCoordinates().width + window.getScroll().x; 2094if( smRight > viewportRightEdge ){ 2095this.options.direction.x = 'left'; 2096this.options.direction.xInverse = 'right'; 2097this.childMenu.style.left = this.btn.getCoordinates().left - this.childMenu.getCoordinates().width + this.options.tweakSubsequent.x + 'px' 2098if (this.options.effect === 'slide' || this.options.effect === 'slide & fade') { 2099this.myEffect.set({'margin-left': this.width,'opacity': this.options.opacity}); 2100} 2101} 2102} 2103} 2104this.options.onPositionSubMenu_complete(this); 2105} 2106}); 2107/* 2108--- 2109 2110name: Core 2111 2112description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts. 2113 2114license: MIT-style license. 2115 2116copyright: Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). 2117 2118authors: The MooTools production team (http://mootools.net/developers/) 2119 2120inspiration: 2121 - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) 2122 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) 2123 2124provides: [MooTools, Native, Hash.base, Array.each, $util] 2125 2126... 2127*/ 2128 2129var MooTools = { 2130'version': '1.2.5', 2131'build': '008d8f0f2fcc2044e54fdd3635341aaab274e757' 2132}; 2133 2134var Native = function(options){ 2135options = options || {}; 2136var name = options.name; 2137var legacy = options.legacy; 2138var protect = options.protect; 2139var methods = options.implement; 2140var generics = options.generics; 2141var initialize = options.initialize; 2142var afterImplement = options.afterImplement || function(){}; 2143var object = initialize || legacy; 2144generics = generics !== false; 2145 2146object.constructor = Native;
2147object.$family = {name: 'native'}; 2148if (legacy && initialize) object.prototype = legacy.prototype; 2149object.prototype.constructor = object; 2150 2151if (name){ 2152var family = name.toLowerCase(); 2153object.prototype.$family = {name: family}; 2154Native.typize(object, family); 2155} 2156 2157var add = function(obj, name, method, force){ 2158if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; 2159if (generics) Native.genericize(obj, name, protect); 2160afterImplement.call(obj, name, method); 2161return obj; 2162}; 2163 2164object.alias = function(a1, a2, a3){ 2165if (typeof a1 == 'string'){ 2166var pa1 = this.prototype[a1]; 2167if ((a1 = pa1)) return add(this, a2, a1, a3); 2168} 2169for (var a in a1) this.alias(a, a1[a], a2); 2170return this; 2171}; 2172 2173object.implement = function(a1, a2, a3){ 2174if (typeof a1 == 'string') return add(this, a1, a2, a3); 2175for (var p in a1) add(this, p, a1[p], a2); 2176return this; 2177}; 2178 2179if (methods) object.implement(methods); 2180 2181return object; 2182}; 2183 2184Native.genericize = function(object, property, check){ 2185if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ 2186var args = Array.prototype.slice.call(arguments); 2187return object.prototype[property].apply(args.shift(), args); 2188}; 2189}; 2190 2191Native.implement = function(objects, properties){ 2192for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); 2193}; 2194 2195Native.typize = function(object, family){ 2196if (!object.type) object.type = function(item){ 2197return ($type(item) === family); 2198}; 2199}; 2200 2201(function(){ 2202var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; 2203for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); 2204 2205var types = {'boolean': Boolean, 'native': Native, 'object': Object}; 2206for (var t in types) Native.typize(types[t], t); 2207 2208var generics = { 2209'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], 2210'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] 2211}; 2212for (var g in generics){ 2213for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true); 2214} 2215})(); 2216 2217var Hash = new Native({ 2218 2219name: 'Hash', 2220 2221initialize: function(object){ 2222if ($type(object) == 'hash') object = $unlink(object.getClean()); 2223for (var key in object) this[key] = object[key]; 2224return this; 2225} 2226 2227}); 2228 2229Hash.implement({ 2230 2231forEach: function(fn, bind){ 2232for (var key in this){ 2233if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); 2234} 2235}, 2236 2237getClean: function(){ 2238var clean = {}; 2239for (var key in this){ 2240if (this.hasOwnProperty(key)) clean[key] = this[key]; 2241} 2242return clean; 2243}, 2244 2245getLength: function(){ 2246var length = 0; 2247for (var key in this){ 2248if (this.hasOwnProperty(key)) length++; 2249} 2250return length; 2251} 2252 2253}); 2254 2255Hash.alias('forEach', 'each'); 2256 2257Array.implement({ 2258 2259forEach: function(fn, bind){ 2260for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); 2261} 2262 2263}); 2264 2265Array.alias('forEach', 'each'); 2266 2267function $A(iterable){ 2268if (iterable.item){ 2269var l = iterable.length, array = new Array(l); 2270while (l--) array[l] = iterable[l]; 2271return array; 2272} 2273return Array.prototype.slice.call(iterable); 2274}; 2275 2276function $arguments(i){ 2277return function(){ 2278return arguments[i]; 2279}; 2280}; 2281 2282function $chk(obj){ 2283return !!(obj || obj === 0); 2284}; 2285 2286function $clear(timer){ 2287clearTimeout(timer); 2288clearInterval(timer); 2289return null; 2290}; 2291 2292function $defined(obj){ 2293return (obj != undefined); 2294}; 2295 2296function $each(iterable, fn, bind){ 2297var type = $type(iterable); 2298((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); 2299}; 2300 2301function $empty(){}; 2302 2303function $extend(original, extended){ 2304for (var key in (extended || {})) original[key] = extended[key]; 2305return original; 2306}; 2307 2308function $H(object){ 2309return new Hash(object); 2310}; 2311 2312function $lambda(value){ 2313return ($type(value) == 'function') ? value : function(){ 2314return value; 2315}; 2316}; 2317 2318function $merge(){ 2319var args = Array.slice(arguments); 2320args.unshift({});
2321return $mixin.apply(null, args); 2322}; 2323 2324function $mixin(mix){ 2325for (var i = 1, l = arguments.length; i < l; i++){ 2326var object = arguments[i]; 2327if ($type(object) != 'object') continue; 2328for (var key in object){ 2329var op = object[key], mp = mix[key]; 2330mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); 2331} 2332} 2333return mix; 2334}; 2335 2336function $pick(){ 2337for (var i = 0, l = arguments.length; i < l; i++){ 2338if (arguments[i] != undefined) return arguments[i]; 2339} 2340return null; 2341}; 2342 2343function $random(min, max){ 2344return Math.floor(Math.random() * (max - min + 1) + min); 2345}; 2346 2347function $splat(obj){ 2348var type = $type(obj); 2349return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; 2350}; 2351 2352var $time = Date.now || function(){ 2353return +new Date; 2354}; 2355 2356function $try(){ 2357for (var i = 0, l = arguments.length; i < l; i++){ 2358try { 2359return arguments[i](); 2360} catch(e){} 2361} 2362return null; 2363}; 2364 2365function $type(obj){ 2366if (obj == undefined) return false; 2367if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; 2368if (obj.nodeName){ 2369switch (obj.nodeType){ 2370case 1: return 'element'; 2371case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; 2372} 2373} else if (typeof obj.length == 'number'){ 2374if (obj.callee) return 'arguments'; 2375else if (obj.item) return 'collection'; 2376} 2377return typeof obj; 2378}; 2379 2380function $unlink(object){ 2381var unlinked; 2382switch ($type(object)){ 2383case 'object': 2384unlinked = {}; 2385for (var p in object) unlinked[p] = $unlink(object[p]); 2386break; 2387case 'hash': 2388unlinked = new Hash(object); 2389break; 2390case 'array': 2391unlinked = []; 2392for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); 2393break; 2394default: return object; 2395} 2396return unlinked; 2397}; 2398 2399 2400/* 2401--- 2402 2403name: Array 2404 2405description: Contains Array Prototypes like each, contains, and erase. 2406 2407license: MIT-style license. 2408 2409requires: [$util, Array.each] 2410 2411provides: Array 2412 2413... 2414*/ 2415 2416Array.implement({ 2417 2418every: function(fn, bind){ 2419for (var i = 0, l = this.length; i < l; i++){ 2420if (!fn.call(bind, this[i], i, this)) return false; 2421} 2422return true; 2423}, 2424 2425filter: function(fn, bind){ 2426var results = []; 2427for (var i = 0, l = this.length; i < l; i++){ 2428if (fn.call(bind, this[i], i, this)) results.push(this[i]); 2429} 2430return results; 2431}, 2432 2433clean: function(){ 2434return this.filter($defined); 2435}, 2436 2437indexOf: function(item, from){ 2438var len = this.length; 2439for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ 2440if (this[i] === item) return i; 2441} 2442return -1; 2443}, 2444 2445map: function(fn, bind){ 2446var results = []; 2447for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); 2448return results; 2449}, 2450 2451some: function(fn, bind){ 2452for (var i = 0, l = this.length; i < l; i++){ 2453if (fn.call(bind, this[i], i, this)) return true; 2454} 2455return false; 2456}, 2457 2458associate: function(keys){ 2459var obj = {}, length = Math.min(this.length, keys.length); 2460for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; 2461return obj; 2462}, 2463 2464link: function(object){ 2465var result = {}; 2466for (var i = 0, l = this.length; i < l; i++){ 2467for (var key in object){ 2468if (object[key](this[i])){ 2469result[key] = this[i]; 2470delete object[key]; 2471break; 2472} 2473} 2474} 2475return result; 2476}, 2477 2478contains: function(item, from){ 2479return this.indexOf(item, from) != -1; 2480}, 2481 2482extend: function(array){ 2483for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); 2484return this; 2485}, 2486 2487getLast: function(){ 2488return (this.length) ? this[this.length - 1] : null; 2489}, 2490 2491getRandom: function(){ 2492return (this.length) ? this[$random(0, this.length - 1)] : null; 2493}, 2494 2495include: function(item){ 2496if (!this.contains(item)) this.push(item); 2497return this; 2498}, 2499 2500combine: function(array){ 2501for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); 2502return this; 2503}, 2504 2505erase: function(item){ 2506for (var i = this.length; i--; i){ 2507if (this[i] === item) this.splice(i, 1); 2508} 2509return this; 2510}, 2511 2512empty: function(){ 2513this.length = 0; 2514return this; 2515}, 2516 2517flatten: function(){ 2518var array = []; 2519for (var i = 0, l = this.length; i < l; i++){ 2520var type = $type(this[i]); 2521if (!type) continue; 2522array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); 2523} 2524return array; 2525}, 2526 2527hexToRgb: function(array){ 2528if (this.length != 3) return null; 2529var rgb = this.map(function(value){ 2530if (value.length == 1) value += value; 2531return value.toInt(16); 2532}); 2533return (array) ? rgb : 'rgb(' + rgb + ')'; 2534}, 2535 2536rgbToHex: function(array){ 2537if (this.length < 3) return null; 2538if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; 2539var hex = []; 2540for (var i = 0; i < 3; i++){ 2541var bit = (this[i] - 0).toString(16); 2542hex.push((bit.length == 1) ? '0' + bit : bit); 2543} 2544return (array) ? hex : '#' + hex.join(''); 2545} 2546 2547}); 2548 2549 2550/* 2551--- 2552 2553name: String 2554
2555description: Contains String Prototypes like camelCase, capitalize, test, and toInt. 2556 2557license: MIT-style license. 2558 2559requires: Native 2560 2561provides: String 2562 2563... 2564*/ 2565 2566String.implement({ 2567 2568test: function(regex, params){ 2569return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); 2570}, 2571 2572contains: function(string, separator){ 2573return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; 2574}, 2575 2576trim: function(){ 2577return this.replace(/^\s+|\s+$/g, ''); 2578}, 2579 2580clean: function(){ 2581return this.replace(/\s+/g, ' ').trim(); 2582}, 2583 2584camelCase: function(){ 2585return this.replace(/-\D/g, function(match){ 2586return match.charAt(1).toUpperCase(); 2587}); 2588}, 2589 2590hyphenate: function(){ 2591return this.replace(/[A-Z]/g, function(match){ 2592return ('-' + match.charAt(0).toLowerCase()); 2593}); 2594}, 2595 2596capitalize: function(){ 2597return this.replace(/\b[a-z]/g, function(match){ 2598return match.toUpperCase(); 2599}); 2600}, 2601 2602escapeRegExp: function(){ 2603return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); 2604}, 2605 2606toInt: function(base){ 2607return parseInt(this, base || 10); 2608}, 2609 2610toFloat: function(){ 2611return parseFloat(this); 2612}, 2613 2614hexToRgb: function(array){ 2615var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); 2616return (hex) ? hex.slice(1).hexToRgb(array) : null; 2617}, 2618 2619rgbToHex: function(array){ 2620var rgb = this.match(/\d{1,3}/g); 2621return (rgb) ? rgb.rgbToHex(array) : null; 2622}, 2623 2624stripScripts: function(option){ 2625var scripts = ''; 2626var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){ 2627scripts += arguments[1] + '\n'; 2628return ''; 2629}); 2630if (option === true) $exec(scripts); 2631else if ($type(option) == 'function') option(scripts, text); 2632return text; 2633}, 2634 2635substitute: function(object, regexp){ 2636return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ 2637if (match.charAt(0) == '\\') return match.slice(1); 2638return (object[name] != undefined) ? object[name] : ''; 2639}); 2640} 2641 2642}); 2643 2644 2645/* 2646--- 2647 2648name: Function 2649 2650description: Contains Function Prototypes like create, bind, pass, and delay. 2651 2652license: MIT-style license. 2653 2654requires: [Native, $util] 2655 2656provides: Function 2657 2658... 2659*/ 2660 2661try { 2662delete Function.prototype.bind; 2663} catch(e){} 2664 2665Function.implement({ 2666 2667extend: function(properties){ 2668for (var property in properties) this[property] = properties[property]; 2669return this; 2670}, 2671 2672create: function(options){ 2673var self = this; 2674options = options || {}; 2675return function(event){ 2676var args = options.arguments; 2677args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); 2678if (options.event) args = [event || window.event].extend(args); 2679var returns = function(){ 2680return self.apply(options.bind || null, args); 2681}; 2682if (options.delay) return setTimeout(returns, options.delay); 2683if (options.periodical) return setInterval(returns, options.periodical); 2684if (options.attempt) return $try(returns); 2685return returns(); 2686}; 2687}, 2688 2689run: function(args, bind){ 2690return this.apply(bind, $splat(args)); 2691}, 2692 2693pass: function(args, bind){ 2694return this.create({bind: bind, arguments: args}); 2695}, 2696 2697bind: function(bind, args){ 2698return this.create({bind: bind, arguments: args}); 2699}, 2700 2701bindWithEvent: function(bind, args){ 2702return this.create({bind: bind, arguments: args, event: true}); 2703}, 2704 2705attempt: function(args, bind){ 2706return this.create({bind: bind, arguments: args, attempt: true})(); 2707}, 2708 2709delay: function(delay, bind, args){ 2710return this.create({bind: bind, arguments: args, delay: delay})(); 2711}, 2712 2713periodical: function(periodical, bind, args){ 2714return this.create({bind: bind, arguments: args, periodical: periodical})(); 2715} 2716 2717}); 2718 2719 2720/* 2721--- 2722 2723name: Number 2724 2725description: Contains Number Prototypes like limit, round, times, and ceil. 2726 2727license: MIT-style license. 2728 2729requires: [Native, $util] 2730 2731provides: Number 2732 2733... 2734*/ 2735 2736Number.implement({ 2737 2738limit: function(min, max){ 2739return Math.min(max, Math.max(min, this)); 2740}, 2741 2742round: function(precision){ 2743precision = Math.pow(10, precision || 0); 2744return Math.round(this * precision) / precision; 2745}, 2746 2747times: function(fn, bind){ 2748for (var i = 0; i < this; i++) fn.call(bind, i, this); 2749}, 2750 2751toFloat: function(){ 2752return parseFloat(this); 2753}, 2754 2755toInt: function(base){ 2756return parseInt(this, base || 10); 2757} 2758 2759}); 2760 2761Number.alias('times', 'each'); 2762 2763(function(math){ 2764var methods = {}; 2765math.each(function(name){ 2766if (!Number[name]) methods[name] = function(){ 2767return Math[name].apply(null, [this].concat($A(arguments))); 2768}; 2769}); 2770Number.implement(methods); 2771})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); 2772 2773 2774/* 2775--- 2776 2777name: Hash 2778 2779description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. 2780 2781license: MIT-style license. 2782 2783requires: Hash.base 2784 2785provides: Hash 2786 2787... 2788*/ 2789 2790Hash.implement({ 2791 2792has: Object.prototype.hasOwnProperty, 2793 2794keyOf: function(value){ 2795for (var key in this){ 2796if (this.hasOwnProperty(key) && this[key] === value) return key; 2797} 2798return null; 2799}, 2800 2801hasValue: function(value){ 2802return (Hash.keyOf(this, value) !== null); 2803}, 2804 2805extend: function(properties){ 2806Hash.each(properties || {}, function(value, key){ 2807Hash.set(this, key, value); 2808}, this); 2809return this; 2810}, 2811 2812combine: function(properties){ 2813Hash.each(properties || {}, function(value, key){ 2814Hash.include(this, key, value); 2815}, this); 2816return this; 2817}, 2818 2819erase: function(key){ 2820if (this.hasOwnProperty(key)) delete this[key]; 2821return this; 2822}, 2823 2824get: function(key){ 2825return (this.hasOwnProperty(key)) ? this[key] : null; 2826}, 2827 2828set: function(key, value){ 2829if (!this[key] || this.hasOwnProperty(key)) this[key] = value; 2830return this; 2831}, 2832 2833empty: function(){ 2834Hash.each(this, function(value, key){ 2835delete this[key]; 2836}, this); 2837return this; 2838}, 2839 2840include: function(key, value){ 2841if (this[key] == undefined) this[key] = value; 2842return this; 2843}, 2844 2845map: function(fn, bind){ 2846var results = new Hash; 2847Hash.each(this, function(value, key){ 2848results.set(key, fn.call(bind, value, key, this)); 2849}, this); 2850return results; 2851}, 2852 2853filter: function(fn, bind){ 2854var results = new Hash; 2855Hash.each(this, function(value, key){ 2856if (fn.call(bind, value, key, this)) results.set(key, value); 2857}, this); 2858return results; 2859}, 2860 2861every: function(fn, bind){ 2862for (var key in this){ 2863if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
2864} 2865return true; 2866}, 2867 2868some: function(fn, bind){ 2869for (var key in this){ 2870if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; 2871} 2872return false; 2873}, 2874 2875getKeys: function(){ 2876var keys = []; 2877Hash.each(this, function(value, key){ 2878keys.push(key); 2879}); 2880return keys; 2881}, 2882 2883getValues: function(){ 2884var values = []; 2885Hash.each(this, function(value){ 2886values.push(value); 2887}); 2888return values; 2889}, 2890 2891toQueryString: function(base){ 2892var queryString = []; 2893Hash.each(this, function(value, key){ 2894if (base) key = base + '[' + key + ']'; 2895var result; 2896switch ($type(value)){ 2897case 'object': result = Hash.toQueryString(value, key); break; 2898case 'array': 2899var qs = {}; 2900value.each(function(val, i){ 2901qs[i] = val; 2902}); 2903result = Hash.toQueryString(qs, key); 2904break; 2905default: result = key + '=' + encodeURIComponent(value); 2906} 2907if (value != undefined) queryString.push(result); 2908}); 2909 2910return queryString.join('&'); 2911} 2912 2913}); 2914 2915Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); 2916 2917 2918/* 2919--- 2920 2921name: Class 2922 2923description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. 2924 2925license: MIT-style license. 2926 2927requires: [$util, Native, Array, String, Function, Number, Hash] 2928 2929provides: Class 2930 2931... 2932*/ 2933 2934function Class(params){ 2935 2936if (params instanceof Function) params = {initialize: params}; 2937 2938var newClass = function(){ 2939Object.reset(this); 2940if (newClass._prototyping) return this; 2941this._current = $empty; 2942var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; 2943delete this._current; delete this.caller; 2944return value; 2945}.extend(this); 2946 2947newClass.implement(params); 2948 2949newClass.constructor = Class; 2950newClass.prototype.constructor = newClass; 2951 2952return newClass; 2953 2954}; 2955 2956Function.prototype.protect = function(){ 2957this._protected = true; 2958return this; 2959}; 2960 2961Object.reset = function(object, key){ 2962 2963if (key == null){ 2964for (var p in object) Object.reset(object, p); 2965return object; 2966} 2967 2968delete object[key]; 2969 2970switch ($type(object[key])){ 2971case 'object': 2972var F = function(){}; 2973F.prototype = object[key]; 2974var i = new F; 2975object[key] = Object.reset(i); 2976break; 2977case 'array': object[key] = $unlink(object[key]); break; 2978} 2979 2980return object; 2981 2982}; 2983 2984new Native({name: 'Class', initialize: Class}).extend({ 2985 2986instantiate: function(F){ 2987F._prototyping = true; 2988var proto = new F; 2989delete F._prototyping; 2990return proto; 2991}, 2992 2993wrap: function(self, key, method){ 2994if (method._origin) method = method._origin; 2995 2996return function(){ 2997if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); 2998var caller = this.caller, current = this._current; 2999this.caller = current; this._current = arguments.callee; 3000var result = method.apply(this, arguments); 3001this._current = current; this.caller = caller; 3002return result; 3003}.extend({_owner: self, _origin: method, _name: key}); 3004 3005} 3006 3007}); 3008 3009Class.implement({ 3010 3011implement: function(key, value){ 3012 3013if ($type(key) == 'object'){ 3014for (var p in key) this.implement(p, key[p]); 3015return this; 3016} 3017 3018var mutator = Class.Mutators[key]; 3019 3020if (mutator){ 3021value = mutator.call(this, value); 3022if (value == null) return this; 3023} 3024 3025var proto = this.prototype; 3026 3027switch ($type(value)){ 3028 3029case 'function': 3030if (value._hidden) return this; 3031proto[key] = Class.wrap(this, key, value); 3032break; 3033 3034case 'object': 3035var previous = proto[key]; 3036if ($type(previous) == 'object') $mixin(previous, value); 3037else proto[key] = $unlink(value); 3038break; 3039 3040case 'array': 3041proto[key] = $unlink(value); 3042break; 3043 3044default: proto[key] = value; 3045 3046} 3047 3048return this; 3049 3050} 3051 3052}); 3053 3054Class.Mutators = { 3055 3056Extends: function(parent){ 3057 3058this.parent = parent; 3059this.prototype = Class.instantiate(parent); 3060 3061this.implement('parent', function(){ 3062var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; 3063if (!previous) throw new Error('The method "' + name + '" has no parent.'); 3064return previous.apply(this, arguments); 3065}.protect()); 3066 3067}, 3068 3069Implements: function(items){ 3070$splat(items).each(function(item){ 3071if (item instanceof Function) item = Class.instantiate(item); 3072this.implement(item); 3073}, this); 3074 3075} 3076 3077}; 3078 3079 3080/* 3081--- 3082 3083name: Class.Extras 3084 3085description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. 3086 3087license: MIT-style license. 3088 3089requires: Class 3090 3091provides: [Chain, Events, Options, Class.Extras] 3092 3093... 3094*/ 3095 3096var Chain = new Class({ 3097 3098$chain: [], 3099 3100chain: function(){ 3101this.$chain.extend(Array.flatten(arguments)); 3102return this; 3103}, 3104 3105callChain: function(){ 3106return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
3107}, 3108 3109clearChain: function(){ 3110this.$chain.empty(); 3111return this; 3112} 3113 3114}); 3115 3116var Events = new Class({ 3117 3118$events: {}, 3119 3120addEvent: function(type, fn, internal){ 3121type = Events.removeOn(type); 3122if (fn != $empty){ 3123this.$events[type] = this.$events[type] || []; 3124this.$events[type].include(fn); 3125if (internal) fn.internal = true; 3126} 3127return this; 3128}, 3129 3130addEvents: function(events){ 3131for (var type in events) this.addEvent(type, events[type]); 3132return this; 3133}, 3134 3135fireEvent: function(type, args, delay){ 3136type = Events.removeOn(type); 3137if (!this.$events || !this.$events[type]) return this; 3138this.$events[type].each(function(fn){ 3139fn.create({'bind': this, 'delay': delay, 'arguments': args})(); 3140}, this); 3141return this; 3142}, 3143 3144removeEvent: function(type, fn){ 3145type = Events.removeOn(type); 3146if (!this.$events[type]) return this; 3147if (!fn.internal) this.$events[type].erase(fn); 3148return this; 3149}, 3150 3151removeEvents: function(events){ 3152var type; 3153if ($type(events) == 'object'){ 3154for (type in events) this.removeEvent(type, events[type]); 3155return this; 3156} 3157if (events) events = Events.removeOn(events); 3158for (type in this.$events){ 3159if (events && events != type) continue; 3160var fns = this.$events[type]; 3161for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); 3162} 3163return this; 3164} 3165 3166}); 3167 3168Events.removeOn = function(string){ 3169return string.replace(/^on([A-Z])/, function(full, first){ 3170return first.toLowerCase(); 3171}); 3172}; 3173 3174var Options = new Class({ 3175 3176setOptions: function(){ 3177this.options = $merge.run([this.options].extend(arguments)); 3178if (!this.addEvent) return this; 3179for (var option in this.options){ 3180if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; 3181this.addEvent(option, this.options[option]); 3182delete this.options[option]; 3183} 3184return this; 3185} 3186 3187}); 3188 3189 3190/* 3191--- 3192 3193name: Browser 3194 3195description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. 3196 3197license: MIT-style license. 3198 3199requires: [Native, $util] 3200 3201provides: [Browser, Window, Document, $exec] 3202 3203... 3204*/ 3205 3206var Browser = $merge({ 3207 3208Engine: {name: 'unknown', version: 0}, 3209 3210Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, 3211 3212Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, 3213 3214Plugins: {}, 3215 3216Engines: { 3217 3218presto: function(){ 3219return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); 3220}, 3221 3222trident: function(){ 3223return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); 3224}, 3225 3226webkit: function(){ 3227return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); 3228}, 3229 3230gecko: function(){ 3231return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); 3232} 3233 3234} 3235 3236}, Browser || {}); 3237 3238Browser.Platform[Browser.Platform.name] = true; 3239 3240Browser.detect = function(){ 3241 3242for (var engine in this.Engines){ 3243var version = this.Engines[engine](); 3244if (version){ 3245this.Engine = {name: engine, version: version}; 3246this.Engine[engine] = this.Engine[engine + version] = true; 3247break; 3248} 3249} 3250 3251return {name: engine, version: version}; 3252 3253}; 3254 3255Browser.detect(); 3256 3257Browser.Request = function(){ 3258return $try(function(){ 3259return new XMLHttpRequest(); 3260}, function(){ 3261return new ActiveXObject('MSXML2.XMLHTTP'); 3262}, function(){ 3263return new ActiveXObject('Microsoft.XMLHTTP'); 3264}); 3265}; 3266 3267Browser.Features.xhr = !!(Browser.Request()); 3268 3269Browser.Plugins.Flash = (function(){ 3270var version = ($try(function(){ 3271return navigator.plugins['Shockwave Flash'].description; 3272}, function(){ 3273return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); 3274}) || '0 r0').match(/\d+/g); 3275return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; 3276})(); 3277 3278function $exec(text){ 3279if (!text) return text; 3280if (window.execScript){ 3281window.execScript(text); 3282} else { 3283var script = document.createElement('script'); 3284script.setAttribute('type', 'text/javascript'); 3285script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; 3286document.head.appendChild(script); 3287document.head.removeChild(script); 3288} 3289return text; 3290}; 3291 3292Native.UID = 1; 3293 3294var $uid = (Browser.Engine.trident) ? function(item){ 3295return (item.uid || (item.uid = [Native.UID++]))[0]; 3296} : function(item){ 3297return item.uid || (item.uid = Native.UID++); 3298}; 3299 3300var Window = new Native({ 3301 3302name: 'Window', 3303 3304legacy: (Browser.Engine.trident) ? null: window.Window, 3305 3306initialize: function(win){ 3307$uid(win); 3308if (!win.Element){ 3309win.Element = $empty; 3310if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 3311win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; 3312} 3313win.document.window = win; 3314return $extend(win, Window.Prototype); 3315}, 3316 3317afterImplement: function(property, value){ 3318window[property] = Window.Prototype[property] = value; 3319} 3320 3321}); 3322 3323Window.Prototype = {$family: {name: 'window'}}; 3324 3325new Window(window); 3326
3327var Document = new Native({ 3328 3329name: 'Document', 3330 3331legacy: (Browser.Engine.trident) ? null: window.Document, 3332 3333initialize: function(doc){ 3334$uid(doc); 3335doc.head = doc.getElementsByTagName('head')[0]; 3336doc.html = doc.getElementsByTagName('html')[0]; 3337if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ 3338doc.execCommand("BackgroundImageCache", false, true); 3339}); 3340if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){ 3341doc.window.detachEvent('onunload', arguments.callee); 3342doc.head = doc.html = doc.window = null; 3343}); 3344return $extend(doc, Document.Prototype); 3345}, 3346 3347afterImplement: function(property, value){ 3348document[property] = Document.Prototype[property] = value; 3349} 3350 3351}); 3352 3353Document.Prototype = {$family: {name: 'document'}}; 3354 3355new Document(document); 3356 3357 3358/* 3359--- 3360 3361name: Element 3362 3363description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. 3364 3365license: MIT-style license. 3366 3367requires: [Window, Document, Array, String, Function, Number, Hash] 3368 3369provides: [Element, Elements, $, $$, Iframe] 3370 3371... 3372*/ 3373 3374var Element = new Native({ 3375 3376name: 'Element', 3377 3378legacy: window.Element, 3379 3380initialize: function(tag, props){ 3381var konstructor = Element.Constructors.get(tag); 3382if (konstructor) return konstructor(props); 3383if (typeof tag == 'string') return document.newElement(tag, props); 3384return document.id(tag).set(props); 3385}, 3386 3387afterImplement: function(key, value){ 3388Element.Prototype[key] = value; 3389if (Array[key]) return; 3390Elements.implement(key, function(){ 3391var items = [], elements = true; 3392for (var i = 0, j = this.length; i < j; i++){ 3393var returns = this[i][key].apply(this[i], arguments); 3394items.push(returns); 3395if (elements) elements = ($type(returns) == 'element'); 3396} 3397return (elements) ? new Elements(items) : items; 3398}); 3399} 3400 3401}); 3402 3403Element.Prototype = {$family: {name: 'element'}}; 3404 3405Element.Constructors = new Hash; 3406 3407var IFrame = new Native({ 3408 3409name: 'IFrame', 3410 3411generics: false, 3412 3413initialize: function(){ 3414var params = Array.link(arguments, {properties: Object.type, iframe: $defined}); 3415var props = params.properties || {}; 3416var iframe = document.id(params.iframe); 3417var onload = props.onload || $empty; 3418delete props.onload; 3419props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time()); 3420iframe = new Element(iframe || 'iframe', props); 3421var onFrameLoad = function(){ 3422var host = $try(function(){ 3423return iframe.contentWindow.location.host; 3424}); 3425if (!host || host == window.location.host){ 3426var win = new Window(iframe.contentWindow); 3427new Document(iframe.contentWindow.document); 3428$extend(win.Element.prototype, Element.Prototype); 3429} 3430onload.call(iframe.contentWindow, iframe.contentWindow.document); 3431}; 3432var contentWindow = $try(function(){ 3433return iframe.contentWindow; 3434}); 3435((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad); 3436return iframe; 3437} 3438 3439}); 3440 3441var Elements = new Native({ 3442 3443initialize: function(elements, options){ 3444options = $extend({ddup: true, cash: true}, options); 3445elements = elements || []; 3446if (options.ddup || options.cash){ 3447var uniques = {}, returned = []; 3448for (var i = 0, l = elements.length; i < l; i++){ 3449var el = document.id(elements[i], !options.cash); 3450if (options.ddup){ 3451if (uniques[el.uid]) continue; 3452uniques[el.uid] = true; 3453} 3454if (el) returned.push(el); 3455} 3456elements = returned; 3457} 3458return (options.cash) ? $extend(elements, this) : elements; 3459} 3460 3461}); 3462 3463Elements.implement({ 3464 3465filter: function(filter, bind){ 3466if (!filter) return this; 3467return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){ 3468return item.match(filter); 3469} : filter, bind)); 3470} 3471 3472}); 3473 3474(function(){ 3475 3476/*<ltIE8>*/ 3477var createElementAcceptsHTML; 3478try { 3479var x = document.createElement('<input name=x>'); 3480createElementAcceptsHTML = (x.name == 'x'); 3481} catch(e){} 3482 3483var escapeQuotes = function(html){ 3484return ('' + html).replace(/&/g,'&').replace(/"/g,'"'); 3485}; 3486/*</ltIE8>*/ 3487 3488Document.implement({ 3489 3490newElement: function(tag, props){ 3491if (props && props.checked != null) props.defaultChecked = props.checked; 3492/*<ltIE8>*/// Fix for readonly name and type properties in IE < 8 3493if (createElementAcceptsHTML && props){ 3494tag = '<' + tag; 3495if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"'; 3496if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"'; 3497tag += '>'; 3498delete props.name; 3499delete props.type; 3500} 3501/*</ltIE8>*/ 3502return this.id(this.createElement(tag)).set(props); 3503}, 3504 3505newTextNode: function(text){ 3506return this.createTextNode(text); 3507}, 3508 3509getDocument: function(){ 3510return this; 3511}, 3512 3513getWindow: function(){ 3514return this.window; 3515}, 3516 3517id: (function(){ 3518 3519var types = { 3520 3521string: function(id, nocash, doc){ 3522id = doc.getElementById(id);
3523return (id) ? types.element(id, nocash) : null; 3524}, 3525 3526element: function(el, nocash){ 3527$uid(el); 3528if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){ 3529var proto = Element.Prototype; 3530for (var p in proto) el[p] = proto[p]; 3531}; 3532return el; 3533}, 3534 3535object: function(obj, nocash, doc){ 3536if (obj.toElement) return types.element(obj.toElement(doc), nocash); 3537return null; 3538} 3539 3540}; 3541 3542types.textnode = types.whitespace = types.window = types.document = $arguments(0); 3543 3544return function(el, nocash, doc){ 3545if (el && el.$family && el.uid) return el; 3546var type = $type(el); 3547return (types[type]) ? types[type](el, nocash, doc || document) : null; 3548}; 3549 3550})() 3551 3552}); 3553 3554})(); 3555 3556if (window.$ == null) Window.implement({ 3557$: function(el, nc){ 3558return document.id(el, nc, this.document); 3559} 3560}); 3561 3562Window.implement({ 3563 3564$$: function(selector){ 3565if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector); 3566var elements = []; 3567var args = Array.flatten(arguments); 3568for (var i = 0, l = args.length; i < l; i++){ 3569var item = args[i]; 3570switch ($type(item)){ 3571case 'element': elements.push(item); break; 3572case 'string': elements.extend(this.document.getElements(item, true)); 3573} 3574} 3575return new Elements(elements); 3576}, 3577 3578getDocument: function(){ 3579return this.document; 3580}, 3581 3582getWindow: function(){ 3583return this; 3584} 3585 3586}); 3587 3588Native.implement([Element, Document], { 3589 3590getElement: function(selector, nocash){ 3591return document.id(this.getElements(selector, true)[0] || null, nocash); 3592}, 3593 3594getElements: function(tags, nocash){ 3595tags = tags.split(','); 3596var elements = []; 3597var ddup = (tags.length > 1); 3598tags.each(function(tag){ 3599var partial = this.getElementsByTagName(tag.trim()); 3600(ddup) ? elements.extend(partial) : elements = partial; 3601}, this); 3602return new Elements(elements, {ddup: ddup, cash: !nocash}); 3603} 3604 3605}); 3606 3607(function(){ 3608 3609var collected = {}, storage = {}; 3610var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'}; 3611 3612var get = function(uid){ 3613return (storage[uid] || (storage[uid] = {})); 3614}; 3615 3616var clean = function(item, retain){ 3617if (!item) return; 3618var uid = item.uid; 3619if (retain !== true) retain = false; 3620if (Browser.Engine.trident){ 3621if (item.clearAttributes){ 3622var clone = retain && item.cloneNode(false); 3623item.clearAttributes(); 3624if (clone) item.mergeAttributes(clone); 3625} else if (item.removeEvents){ 3626item.removeEvents(); 3627} 3628if ((/object/i).test(item.tagName)){ 3629for (var p in item){ 3630if (typeof item[p] == 'function') item[p] = $empty; 3631} 3632Element.dispose(item); 3633} 3634} 3635if (!uid) return; 3636collected[uid] = storage[uid] = null; 3637}; 3638 3639var purge = function(){ 3640Hash.each(collected, clean); 3641if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean); 3642if (window.CollectGarbage) CollectGarbage(); 3643collected = storage = null; 3644}; 3645 3646var walk = function(element, walk, start, match, all, nocash){ 3647var el = element[start || walk]; 3648var elements = []; 3649while (el){ 3650if (el.nodeType == 1 && (!match || Element.match(el, match))){ 3651if (!all) return document.id(el, nocash); 3652elements.push(el); 3653} 3654el = el[walk]; 3655} 3656return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null; 3657}; 3658 3659var attributes = { 3660'html': 'innerHTML', 3661'class': 'className', 3662'for': 'htmlFor', 3663'defaultValue': 'defaultValue', 3664'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent' 3665}; 3666var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer']; 3667var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']; 3668 3669bools = bools.associate(bools); 3670 3671Hash.extend(attributes, bools); 3672Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase))); 3673 3674var inserters = { 3675 3676before: function(context, element){ 3677if (element.parentNode) element.parentNode.insertBefore(context, element); 3678}, 3679 3680after: function(context, element){ 3681if (!element.parentNode) return; 3682var next = element.nextSibling; 3683(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context); 3684}, 3685 3686bottom: function(context, element){ 3687element.appendChild(context); 3688}, 3689 3690top: function(context, element){ 3691var first = element.firstChild; 3692(first) ? element.insertBefore(context, first) : element.appendChild(context); 3693} 3694 3695}; 3696 3697inserters.inside = inserters.bottom; 3698 3699Hash.each(inserters, function(inserter, where){ 3700 3701where = where.capitalize(); 3702 3703Element.implement('inject' + where, function(el){ 3704inserter(this, document.id(el, true)); 3705return this; 3706}); 3707 3708Element.implement('grab' + where, function(el){
3709inserter(document.id(el, true), this); 3710return this; 3711}); 3712 3713}); 3714 3715Element.implement({ 3716 3717set: function(prop, value){ 3718switch ($type(prop)){ 3719case 'object': 3720for (var p in prop) this.set(p, prop[p]); 3721break; 3722case 'string': 3723var property = Element.Properties.get(prop); 3724(property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value); 3725} 3726return this; 3727}, 3728 3729get: function(prop){ 3730var property = Element.Properties.get(prop); 3731return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop); 3732}, 3733 3734erase: function(prop){ 3735var property = Element.Properties.get(prop); 3736(property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); 3737return this; 3738}, 3739 3740setProperty: function(attribute, value){ 3741var key = attributes[attribute]; 3742if (value == undefined) return this.removeProperty(attribute); 3743if (key && bools[attribute]) value = !!value; 3744(key) ? this[key] = value : this.setAttribute(attribute, '' + value); 3745return this; 3746}, 3747 3748setProperties: function(attributes){ 3749for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); 3750return this; 3751}, 3752 3753getProperty: function(attribute){ 3754var key = attributes[attribute]; 3755var value = (key) ? this[key] : this.getAttribute(attribute, 2); 3756return (bools[attribute]) ? !!value : (key) ? value : value || null; 3757}, 3758 3759getProperties: function(){ 3760var args = $A(arguments); 3761return args.map(this.getProperty, this).associate(args); 3762}, 3763 3764removeProperty: function(attribute){ 3765var key = attributes[attribute]; 3766(key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute); 3767return this; 3768}, 3769 3770removeProperties: function(){ 3771Array.each(arguments, this.removeProperty, this); 3772return this; 3773}, 3774 3775hasClass: function(className){ 3776return this.className.contains(className, ' '); 3777}, 3778 3779addClass: function(className){ 3780if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); 3781return this; 3782}, 3783 3784removeClass: function(className){ 3785this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); 3786return this; 3787}, 3788 3789toggleClass: function(className){ 3790return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); 3791}, 3792 3793adopt: function(){ 3794Array.flatten(arguments).each(function(element){ 3795element = document.id(element, true); 3796if (element) this.appendChild(element); 3797}, this); 3798return this; 3799}, 3800 3801appendText: function(text, where){ 3802return this.grab(this.getDocument().newTextNode(text), where); 3803}, 3804 3805grab: function(el, where){ 3806inserters[where || 'bottom'](document.id(el, true), this); 3807return this; 3808}, 3809 3810inject: function(el, where){ 3811inserters[where || 'bottom'](this, document.id(el, true)); 3812return this; 3813}, 3814 3815replaces: function(el){ 3816el = document.id(el, true); 3817el.parentNode.replaceChild(this, el); 3818return this; 3819}, 3820 3821wraps: function(el, where){ 3822el = document.id(el, true); 3823return this.replaces(el).grab(el, where); 3824}, 3825 3826getPrevious: function(match, nocash){ 3827return walk(this, 'previousSibling', null, match, false, nocash); 3828}, 3829 3830getAllPrevious: function(match, nocash){ 3831return walk(this, 'previousSibling', null, match, true, nocash); 3832}, 3833 3834getNext: function(match, nocash){ 3835return walk(this, 'nextSibling', null, match, false, nocash); 3836}, 3837 3838getAllNext: function(match, nocash){ 3839return walk(this, 'nextSibling', null, match, true, nocash); 3840}, 3841 3842getFirst: function(match, nocash){ 3843return walk(this, 'nextSibling', 'firstChild', match, false, nocash); 3844}, 3845 3846getLast: function(match, nocash){ 3847return walk(this, 'previousSibling', 'lastChild', match, false, nocash); 3848}, 3849 3850getParent: function(match, nocash){ 3851return walk(this, 'parentNode', null, match, false, nocash); 3852}, 3853 3854getParents: function(match, nocash){ 3855return walk(this, 'parentNode', null, match, true, nocash); 3856}, 3857 3858getSiblings: function(match, nocash){ 3859return this.getParent().getChildren(match, nocash).erase(this); 3860}, 3861 3862getChildren: function(match, nocash){ 3863return walk(this, 'nextSibling', 'firstChild', match, true, nocash); 3864}, 3865 3866getWindow: function(){ 3867return this.ownerDocument.window; 3868}, 3869 3870getDocument: function(){ 3871return this.ownerDocument; 3872}, 3873 3874getElementById: function(id, nocash){ 3875var el = this.ownerDocument.getElementById(id); 3876if (!el) return null; 3877for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ 3878if (!parent) return null; 3879} 3880return document.id(el, nocash); 3881}, 3882 3883getSelected: function(){ 3884return new Elements($A(this.options).filter(function(option){ 3885return option.selected; 3886})); 3887}, 3888 3889getComputedStyle: function(property){ 3890if (this.currentStyle) return this.currentStyle[property.camelCase()]; 3891var computed = this.getDocument().defaultView.getComputedStyle(this, null); 3892return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; 3893}, 3894 3895toQueryString: function(){ 3896var queryString = []; 3897this.getElements('input, select, textarea', true).each(function(el){ 3898if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return; 3899var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){ 3900return opt.value; 3901}) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; 3902$splat(value).each(function(val){ 3903if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val)); 3904}); 3905}); 3906return queryString.join('&'); 3907}, 3908 3909clone: function(contents, keepid){ 3910contents = contents !== false; 3911var clone = this.cloneNode(contents); 3912var clean = function(node, element){ 3913if (!keepid) node.removeAttribute('id'); 3914if (Browser.Engine.trident){ 3915node.clearAttributes(); 3916node.mergeAttributes(element); 3917node.removeAttribute('uid'); 3918if (node.options){ 3919var no = node.options, eo = element.options; 3920for (var j = no.length; j--;) no[j].selected = eo[j].selected; 3921} 3922} 3923var prop = props[element.tagName.toLowerCase()]; 3924if (prop && element[prop]) node[prop] = element[prop]; 3925}; 3926 3927if (contents){ 3928var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); 3929for (var i = ce.length; i--;) clean(ce[i], te[i]); 3930} 3931 3932clean(clone, this); 3933return document.id(clone); 3934}, 3935 3936destroy: function(){ 3937Element.empty(this); 3938Element.dispose(this); 3939clean(this, true); 3940return null; 3941}, 3942 3943empty: function(){ 3944$A(this.childNodes).each(function(node){ 3945Element.destroy(node); 3946}); 3947return this; 3948}, 3949 3950dispose: function(){ 3951return (this.parentNode) ? this.parentNode.removeChild(this) : this; 3952}, 3953 3954hasChild: function(el){ 3955el = document.id(el, true); 3956if (!el) return false;
3957if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el); 3958return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16); 3959}, 3960 3961match: function(tag){ 3962return (!tag || (tag == this) || (Element.get(this, 'tag') == tag)); 3963} 3964 3965}); 3966 3967Native.implement([Element, Window, Document], { 3968 3969addListener: function(type, fn){ 3970if (type == 'unload'){ 3971var old = fn, self = this; 3972fn = function(){ 3973self.removeListener('unload', fn); 3974old(); 3975}; 3976} else { 3977collected[this.uid] = this; 3978} 3979if (this.addEventListener) this.addEventListener(type, fn, false); 3980else this.attachEvent('on' + type, fn); 3981return this; 3982}, 3983 3984removeListener: function(type, fn){ 3985if (this.removeEventListener) this.removeEventListener(type, fn, false); 3986else this.detachEvent('on' + type, fn); 3987return this; 3988}, 3989 3990retrieve: function(property, dflt){ 3991var storage = get(this.uid), prop = storage[property]; 3992if (dflt != undefined && prop == undefined) prop = storage[property] = dflt; 3993return $pick(prop); 3994}, 3995 3996store: function(property, value){ 3997var storage = get(this.uid); 3998storage[property] = value; 3999return this; 4000}, 4001 4002eliminate: function(property){ 4003var storage = get(this.uid); 4004delete storage[property]; 4005return this; 4006} 4007 4008}); 4009 4010window.addListener('unload', purge); 4011 4012})(); 4013 4014Element.Properties = new Hash; 4015 4016Element.Properties.style = { 4017 4018set: function(style){ 4019this.style.cssText = style; 4020}, 4021 4022get: function(){ 4023return this.style.cssText; 4024}, 4025 4026erase: function(){ 4027this.style.cssText = ''; 4028} 4029 4030}; 4031 4032Element.Properties.tag = { 4033 4034get: function(){ 4035return this.tagName.toLowerCase(); 4036} 4037 4038}; 4039 4040Element.Properties.html = (function(){ 4041var wrapper = document.createElement('div'); 4042 4043var translations = { 4044table: [1, '<table>', '</table>'], 4045select: [1, '<select>', '</select>'], 4046tbody: [2, '<table><tbody>', '</tbody></table>'], 4047tr: [3, '<table><tbody><tr>', '</tr></tbody></table>'] 4048}; 4049translations.thead = translations.tfoot = translations.tbody; 4050 4051var html = { 4052set: function(){ 4053var html = Array.flatten(arguments).join(''); 4054var wrap = Browser.Engine.trident && translations[this.get('tag')]; 4055if (wrap){ 4056var first = wrapper; 4057first.innerHTML = wrap[1] + html + wrap[2]; 4058for (var i = wrap[0]; i--;) first = first.firstChild; 4059this.empty().adopt(first.childNodes); 4060} else { 4061this.innerHTML = html; 4062} 4063} 4064}; 4065 4066html.erase = html.set; 4067 4068return html; 4069})(); 4070 4071if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = { 4072get: function(){ 4073if (this.innerText) return this.innerText; 4074var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body); 4075var text = temp.innerText; 4076temp.destroy(); 4077return text; 4078} 4079}; 4080 4081 4082/* 4083--- 4084 4085name: Element.Dimensions 4086 4087description: Contains methods to work with size, scroll, or positioning of Elements and the window object. 4088 4089license: MIT-style license. 4090 4091credits: 4092 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). 4093 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). 4094 4095requires: Element 4096 4097provides: Element.Dimensions 4098 4099... 4100*/ 4101 4102(function(){ 4103 4104Element.implement({ 4105 4106scrollTo: function(x, y){ 4107if (isBody(this)){ 4108this.getWindow().scrollTo(x, y); 4109} else { 4110this.scrollLeft = x; 4111this.scrollTop = y; 4112} 4113return this; 4114}, 4115 4116getSize: function(){ 4117if (isBody(this)) return this.getWindow().getSize(); 4118return {x: this.offsetWidth, y: this.offsetHeight}; 4119}, 4120 4121getScrollSize: function(){ 4122if (isBody(this)) return this.getWindow().getScrollSize(); 4123return {x: this.scrollWidth, y: this.scrollHeight}; 4124}, 4125 4126getScroll: function(){ 4127if (isBody(this)) return this.getWindow().getScroll(); 4128return {x: this.scrollLeft, y: this.scrollTop}; 4129}, 4130 4131getScrolls: function(){ 4132var element = this, position = {x: 0, y: 0}; 4133while (element && !isBody(element)){ 4134position.x += element.scrollLeft; 4135position.y += element.scrollTop; 4136element = element.parentNode; 4137} 4138return position; 4139}, 4140 4141getOffsetParent: function(){ 4142var element = this; 4143if (isBody(element)) return null; 4144if (!Browser.Engine.trident) return element.offsetParent; 4145while ((element = element.parentNode) && !isBody(element)){ 4146if (styleString(element, 'position') != 'static') return element; 4147} 4148return null; 4149}, 4150 4151getOffsets: function(){ 4152if (this.getBoundingClientRect){ 4153var bound = this.getBoundingClientRect(), 4154html = document.id(this.getDocument().documentElement), 4155htmlScroll = html.getScroll(),
4156elemScrolls = this.getScrolls(), 4157elemScroll = this.getScroll(), 4158isFixed = (styleString(this, 'position') == 'fixed'); 4159 4160return { 4161x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, 4162y: bound.top.toInt() + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop 4163}; 4164} 4165 4166var element = this, position = {x: 0, y: 0}; 4167if (isBody(this)) return position; 4168 4169while (element && !isBody(element)){ 4170position.x += element.offsetLeft; 4171position.y += element.offsetTop; 4172 4173if (Browser.Engine.gecko){ 4174if (!borderBox(element)){ 4175position.x += leftBorder(element); 4176position.y += topBorder(element); 4177} 4178var parent = element.parentNode; 4179if (parent && styleString(parent, 'overflow') != 'visible'){ 4180position.x += leftBorder(parent); 4181position.y += topBorder(parent); 4182} 4183} else if (element != this && Browser.Engine.webkit){ 4184position.x += leftBorder(element); 4185position.y += topBorder(element); 4186} 4187 4188element = element.offsetParent; 4189} 4190if (Browser.Engine.gecko && !borderBox(this)){ 4191position.x -= leftBorder(this); 4192position.y -= topBorder(this); 4193} 4194return position; 4195}, 4196 4197getPosition: function(relative){ 4198if (isBody(this)) return {x: 0, y: 0}; 4199var offset = this.getOffsets(), 4200scroll = this.getScrolls(); 4201var position = { 4202x: offset.x - scroll.x, 4203y: offset.y - scroll.y 4204}; 4205var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0}; 4206return {x: position.x - relativePosition.x, y: position.y - relativePosition.y}; 4207}, 4208 4209getCoordinates: function(element){ 4210if (isBody(this)) return this.getWindow().getCoordinates(); 4211var position = this.getPosition(element), 4212size = this.getSize(); 4213var obj = { 4214left: position.x, 4215top: position.y, 4216width: size.x, 4217height: size.y 4218}; 4219obj.right = obj.left + obj.width; 4220obj.bottom = obj.top + obj.height; 4221return obj; 4222}, 4223 4224computePosition: function(obj){ 4225return { 4226left: obj.x - styleNumber(this, 'margin-left'), 4227top: obj.y - styleNumber(this, 'margin-top') 4228}; 4229}, 4230 4231setPosition: function(obj){ 4232return this.setStyles(this.computePosition(obj)); 4233} 4234 4235}); 4236 4237 4238Native.implement([Document, Window], { 4239 4240getSize: function(){ 4241if (Browser.Engine.presto || Browser.Engine.webkit){ 4242var win = this.getWindow(); 4243return {x: win.innerWidth, y: win.innerHeight}; 4244} 4245var doc = getCompatElement(this); 4246return {x: doc.clientWidth, y: doc.clientHeight}; 4247}, 4248 4249getScroll: function(){ 4250var win = this.getWindow(), doc = getCompatElement(this); 4251return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; 4252}, 4253 4254getScrollSize: function(){ 4255var doc = getCompatElement(this), min = this.getSize(); 4256return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)}; 4257}, 4258 4259getPosition: function(){ 4260return {x: 0, y: 0}; 4261}, 4262 4263getCoordinates: function(){ 4264var size = this.getSize(); 4265return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; 4266} 4267 4268}); 4269 4270// private methods 4271
4272var styleString = Element.getComputedStyle; 4273 4274function styleNumber(element, style){ 4275return styleString(element, style).toInt() || 0; 4276}; 4277 4278function borderBox(element){ 4279return styleString(element, '-moz-box-sizing') == 'border-box'; 4280}; 4281 4282function topBorder(element){ 4283return styleNumber(element, 'border-top-width'); 4284}; 4285 4286function leftBorder(element){ 4287return styleNumber(element, 'border-left-width'); 4288}; 4289 4290function isBody(element){ 4291return (/^(?:body|html)$/i).test(element.tagName); 4292}; 4293 4294function getCompatElement(element){ 4295var doc = element.getDocument(); 4296return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 4297}; 4298 4299})(); 4300 4301//aliases 4302Element.alias('setPosition', 'position'); //compatability 4303 4304Native.implement([Window, Document, Element], { 4305 4306getHeight: function(){ 4307return this.getSize().y; 4308}, 4309 4310getWidth: function(){ 4311return this.getSize().x; 4312}, 4313 4314getScrollTop: function(){ 4315return this.getScroll().y; 4316}, 4317 4318getScrollLeft: function(){ 4319return this.getScroll().x; 4320}, 4321 4322getScrollHeight: function(){ 4323return this.getScrollSize().y; 4324}, 4325 4326getScrollWidth: function(){ 4327return this.getScrollSize().x; 4328}, 4329 4330getTop: function(){ 4331return this.getPosition().y; 4332}, 4333 4334getLeft: function(){ 4335return this.getPosition().x; 4336} 4337 4338}); 4339 4340 4341/* 4342--- 4343 4344name: Event 4345 4346description: Contains the Event Class, to make the event object cross-browser. 4347 4348license: MIT-style license. 4349 4350requires: [Window, Document, Hash, Array, Function, String] 4351 4352provides: Event 4353 4354... 4355*/ 4356 4357var Event = new Native({ 4358 4359name: 'Event', 4360 4361initialize: function(event, win){ 4362win = win || window; 4363var doc = win.document; 4364event = event || win.event; 4365if (event.$extended) return event; 4366this.$extended = true; 4367var type = event.type; 4368var target = event.target || event.srcElement; 4369while (target && target.nodeType == 3) target = target.parentNode; 4370 4371if (type.test(/key/)){ 4372var code = event.which || event.keyCode; 4373var key = Event.Keys.keyOf(code); 4374if (type == 'keydown'){ 4375var fKey = code - 111; 4376if (fKey > 0 && fKey < 13) key = 'f' + fKey; 4377} 4378key = key || String.fromCharCode(code).toLowerCase(); 4379} else if (type.match(/(click|mouse|menu)/i)){ 4380doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 4381var page = { 4382x: event.pageX || event.clientX + doc.scrollLeft, 4383y: event.pageY || event.clientY + doc.scrollTop 4384}; 4385var client = { 4386x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, 4387y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY 4388}; 4389if (type.match(/DOMMouseScroll|mousewheel/)){ 4390var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; 4391} 4392var rightClick = (event.which == 3) || (event.button == 2); 4393var related = null; 4394if (type.match(/over|out/)){ 4395switch (type){ 4396case 'mouseover': related = event.relatedTarget || event.fromElement; break; 4397case 'mouseout': related = event.relatedTarget || event.toElement; 4398} 4399if (!(function(){ 4400while (related && related.nodeType == 3) related = related.parentNode; 4401return true; 4402}).create({attempt: Browser.Engine.gecko})()) related = false; 4403} 4404} 4405 4406return $extend(this, { 4407event: event, 4408type: type, 4409 4410page: page, 4411client: client, 4412rightClick: rightClick, 4413 4414wheel: wheel, 4415 4416relatedTarget: related, 4417target: target, 4418 4419code: code, 4420key: key, 4421 4422shift: event.shiftKey, 4423control: event.ctrlKey, 4424alt: event.altKey, 4425meta: event.metaKey 4426}); 4427} 4428 4429}); 4430 4431Event.Keys = new Hash({ 4432'enter': 13, 4433'up': 38, 4434'down': 40, 4435'left': 37, 4436'right': 39, 4437'esc': 27, 4438'space': 32, 4439'backspace': 8, 4440'tab': 9, 4441'delete': 46 4442}); 4443 4444Event.implement({ 4445 4446stop: function(){ 4447return this.stopPropagation().preventDefault(); 4448}, 4449 4450stopPropagation: function(){ 4451if (this.event.stopPropagation) this.event.stopPropagation(); 4452else this.event.cancelBubble = true; 4453return this; 4454}, 4455 4456preventDefault: function(){ 4457if (this.event.preventDefault) this.event.preventDefault(); 4458else this.event.returnValue = false; 4459return this; 4460} 4461 4462}); 4463 4464 4465/* 4466--- 4467 4468name: Element.Event 4469 4470description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. 4471 4472license: MIT-style license. 4473 4474requires: [Element, Event] 4475 4476provides: Element.Event 4477 4478... 4479*/ 4480 4481Element.Properties.events = {set: function(events){ 4482this.addEvents(events); 4483}}; 4484 4485Native.implement([Element, Window, Document], {
4486 4487addEvent: function(type, fn){ 4488var events = this.retrieve('events', {}); 4489events[type] = events[type] || {'keys': [], 'values': []}; 4490if (events[type].keys.contains(fn)) return this; 4491events[type].keys.push(fn); 4492var realType = type, custom = Element.Events.get(type), condition = fn, self = this; 4493if (custom){ 4494if (custom.onAdd) custom.onAdd.call(this, fn); 4495if (custom.condition){ 4496condition = function(event){ 4497if (custom.condition.call(this, event)) return fn.call(this, event); 4498return true; 4499}; 4500} 4501realType = custom.base || realType; 4502} 4503var defn = function(){ 4504return fn.call(self); 4505}; 4506var nativeEvent = Element.NativeEvents[realType]; 4507if (nativeEvent){ 4508if (nativeEvent == 2){ 4509defn = function(event){ 4510event = new Event(event, self.getWindow()); 4511if (condition.call(self, event) === false) event.stop(); 4512}; 4513} 4514this.addListener(realType, defn); 4515} 4516events[type].values.push(defn); 4517return this; 4518}, 4519 4520removeEvent: function(type, fn){ 4521var events = this.retrieve('events'); 4522if (!events || !events[type]) return this; 4523var pos = events[type].keys.indexOf(fn); 4524if (pos == -1) return this; 4525events[type].keys.splice(pos, 1); 4526var value = events[type].values.splice(pos, 1)[0]; 4527var custom = Element.Events.get(type); 4528if (custom){ 4529if (custom.onRemove) custom.onRemove.call(this, fn); 4530type = custom.base || type; 4531} 4532return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this; 4533}, 4534 4535addEvents: function(events){ 4536for (var event in events) this.addEvent(event, events[event]); 4537return this; 4538}, 4539 4540removeEvents: function(events){ 4541var type; 4542if ($type(events) == 'object'){ 4543for (type in events) this.removeEvent(type, events[type]); 4544return this; 4545} 4546var attached = this.retrieve('events'); 4547if (!attached) return this; 4548if (!events){ 4549for (type in attached) this.removeEvents(type); 4550this.eliminate('events'); 4551} else if (attached[events]){ 4552while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]); 4553attached[events] = null; 4554} 4555return this; 4556}, 4557 4558fireEvent: function(type, args, delay){ 4559var events = this.retrieve('events'); 4560if (!events || !events[type]) return this; 4561events[type].keys.each(function(fn){ 4562fn.create({'bind': this, 'delay': delay, 'arguments': args})(); 4563}, this); 4564return this; 4565}, 4566 4567cloneEvents: function(from, type){ 4568from = document.id(from); 4569var fevents = from.retrieve('events'); 4570if (!fevents) return this; 4571if (!type){ 4572for (var evType in fevents) this.cloneEvents(from, evType); 4573} else if (fevents[type]){ 4574fevents[type].keys.each(function(fn){ 4575this.addEvent(type, fn); 4576}, this); 4577} 4578return this; 4579} 4580 4581}); 4582 4583// IE9 4584try { 4585if (typeof HTMLElement != 'undefined') 4586HTMLElement.prototype.fireEvent = Element.prototype.fireEvent; 4587} catch(e){} 4588 4589Element.NativeEvents = { 4590click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons 4591mousewheel: 2, DOMMouseScroll: 2, //mouse wheel 4592mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement 4593keydown: 2, keypress: 2, keyup: 2, //keyboard 4594focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements 4595load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window 4596error: 1, abort: 1, scroll: 1 //misc 4597}; 4598 4599(function(){ 4600 4601var $check = function(event){ 4602var related = event.relatedTarget; 4603if (related == undefined) return true; 4604if (related === false) return false; 4605return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related)); 4606}; 4607 4608Element.Events = new Hash({ 4609 4610mouseenter: { 4611base: 'mouseover', 4612condition: $check 4613}, 4614 4615mouseleave: { 4616base: 'mouseout', 4617condition: $check 4618}, 4619 4620mousewheel: { 4621base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel' 4622} 4623 4624}); 4625 4626})(); 4627 4628 4629/* 4630--- 4631 4632name: Element.Style 4633 4634description: Contains methods for interacting with the styles of Elements in a fashionable way. 4635 4636license: MIT-style license. 4637 4638requires: Element 4639 4640provides: Element.Style 4641 4642... 4643*/ 4644 4645Element.Properties.styles = {set: function(styles){ 4646this.setStyles(styles); 4647}}; 4648 4649Element.Properties.opacity = { 4650 4651set: function(opacity, novisibility){ 4652if (!novisibility){ 4653if (opacity == 0){ 4654if (this.style.visibility != 'hidden') this.style.visibility = 'hidden'; 4655} else { 4656if (this.style.visibility != 'visible') this.style.visibility = 'visible'; 4657} 4658} 4659if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; 4660if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; 4661this.style.opacity = opacity; 4662this.store('opacity', opacity); 4663}, 4664 4665get: function(){ 4666return this.retrieve('opacity', 1); 4667} 4668 4669}; 4670 4671Element.implement({ 4672 4673setOpacity: function(value){ 4674return this.set('opacity', value, true); 4675}, 4676 4677getOpacity: function(){ 4678return this.get('opacity'); 4679}, 4680 4681setStyle: function(property, value){ 4682switch (property){ 4683case 'opacity': return this.set('opacity', parseFloat(value)); 4684case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; 4685} 4686property = property.camelCase(); 4687if ($type(value) != 'string'){ 4688var map = (Element.Styles.get(property) || '@').split(' '); 4689value = $splat(value).map(function(val, i){ 4690if (!map[i]) return ''; 4691return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; 4692}).join(' '); 4693} else if (value == String(Number(value))){ 4694value = Math.round(value); 4695} 4696this.style[property] = value; 4697return this; 4698}, 4699 4700getStyle: function(property){ 4701switch (property){ 4702case 'opacity': return this.get('opacity'); 4703case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; 4704} 4705property = property.camelCase(); 4706var result = this.style[property]; 4707if (!$chk(result)){ 4708result = []; 4709for (var style in Element.ShortStyles){ 4710if (property != style) continue; 4711for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); 4712return result.join(' '); 4713} 4714result = this.getComputedStyle(property); 4715} 4716if (result){ 4717result = String(result); 4718var color = result.match(/rgba?\([\d\s,]+\)/); 4719if (color) result = result.replace(color[0], color[0].rgbToHex()); 4720} 4721if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){ 4722if (property.test(/^(height|width)$/)){ 4723var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; 4724values.each(function(value){
4725size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); 4726}, this); 4727return this['offset' + property.capitalize()] - size + 'px'; 4728} 4729if ((Browser.Engine.presto) && String(result).test('px')) return result; 4730if (property.test(/(border(.+)Width|margin|padding)/)) return '0px'; 4731} 4732return result; 4733}, 4734 4735setStyles: function(styles){ 4736for (var style in styles) this.setStyle(style, styles[style]); 4737return this; 4738}, 4739 4740getStyles: function(){ 4741var result = {}; 4742Array.flatten(arguments).each(function(key){ 4743result[key] = this.getStyle(key); 4744}, this); 4745return result; 4746} 4747 4748}); 4749 4750Element.Styles = new Hash({ 4751left: '@px', top: '@px', bottom: '@px', right: '@px', 4752width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', 4753backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', 4754fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', 4755margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', 4756borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', 4757zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' 4758}); 4759 4760Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; 4761 4762['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ 4763var Short = Element.ShortStyles; 4764var All = Element.Styles; 4765['margin', 'padding'].each(function(style){ 4766var sd = style + direction; 4767Short[style][sd] = All[sd] = '@px'; 4768}); 4769var bd = 'border' + direction; 4770Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; 4771var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; 4772Short[bd] = {}; 4773Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; 4774Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; 4775Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; 4776}); 4777 4778 4779/* 4780--- 4781 4782name: Fx 4783 4784description: Contains the basic animation logic to be extended by all other Fx Classes. 4785 4786license: MIT-style license. 4787 4788requires: [Chain, Events, Options] 4789 4790provides: Fx 4791 4792... 4793*/ 4794 4795var Fx = new Class({ 4796 4797Implements: [Chain, Events, Options], 4798 4799options: { 4800/* 4801onStart: $empty, 4802onCancel: $empty, 4803onComplete: $empty, 4804*/ 4805fps: 50, 4806unit: false, 4807duration: 500, 4808link: 'ignore' 4809}, 4810 4811initialize: function(options){ 4812this.subject = this.subject || this; 4813this.setOptions(options); 4814this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt(); 4815var wait = this.options.wait; 4816if (wait === false) this.options.link = 'cancel'; 4817}, 4818 4819getTransition: function(){ 4820return function(p){ 4821return -(Math.cos(Math.PI * p) - 1) / 2; 4822}; 4823}, 4824 4825step: function(){ 4826var time = $time(); 4827if (time < this.time + this.options.duration){ 4828var delta = this.transition((time - this.time) / this.options.duration); 4829this.set(this.compute(this.from, this.to, delta)); 4830} else { 4831this.set(this.compute(this.from, this.to, 1)); 4832this.complete(); 4833} 4834}, 4835 4836set: function(now){ 4837return now; 4838}, 4839 4840compute: function(from, to, delta){ 4841return Fx.compute(from, to, delta); 4842}, 4843 4844check: function(){ 4845if (!this.timer) return true; 4846switch (this.options.link){ 4847case 'cancel': this.cancel(); return true; 4848case 'chain': this.chain(this.caller.bind(this, arguments)); return false; 4849} 4850return false; 4851}, 4852 4853start: function(from, to){ 4854if (!this.check(from, to)) return this; 4855this.from = from; 4856this.to = to; 4857this.time = 0; 4858this.transition = this.getTransition(); 4859this.startTimer(); 4860this.onStart(); 4861return this; 4862}, 4863 4864complete: function(){ 4865if (this.stopTimer()) this.onComplete(); 4866return this; 4867}, 4868 4869cancel: function(){ 4870if (this.stopTimer()) this.onCancel(); 4871return this; 4872}, 4873 4874onStart: function(){ 4875this.fireEvent('start', this.subject); 4876}, 4877 4878onComplete: function(){ 4879this.fireEvent('complete', this.subject); 4880if (!this.callChain()) this.fireEvent('chainComplete', this.subject); 4881}, 4882 4883onCancel: function(){ 4884this.fireEvent('cancel', this.subject).clearChain(); 4885}, 4886 4887pause: function(){ 4888this.stopTimer(); 4889return this; 4890}, 4891 4892resume: function(){ 4893this.startTimer(); 4894return this; 4895}, 4896 4897stopTimer: function(){ 4898if (!this.timer) return false;
4899this.time = $time() - this.time; 4900this.timer = $clear(this.timer); 4901return true; 4902}, 4903 4904startTimer: function(){ 4905if (this.timer) return false; 4906this.time = $time() - this.time; 4907this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); 4908return true; 4909} 4910 4911}); 4912 4913Fx.compute = function(from, to, delta){ 4914return (to - from) * delta + from; 4915}; 4916 4917Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; 4918 4919 4920/* 4921--- 4922 4923name: Fx.CSS 4924 4925description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. 4926 4927license: MIT-style license. 4928 4929requires: [Fx, Element.Style] 4930 4931provides: Fx.CSS 4932 4933... 4934*/ 4935 4936Fx.CSS = new Class({ 4937 4938Extends: Fx, 4939 4940//prepares the base from/to object 4941 4942prepare: function(element, property, values){ 4943values = $splat(values); 4944var values1 = values[1]; 4945if (!$chk(values1)){ 4946values[1] = values[0]; 4947values[0] = element.getStyle(property); 4948} 4949var parsed = values.map(this.parse); 4950return {from: parsed[0], to: parsed[1]}; 4951}, 4952 4953//parses a value into an array 4954 4955parse: function(value){ 4956value = $lambda(value)(); 4957value = (typeof value == 'string') ? value.split(' ') : $splat(value); 4958return value.map(function(val){ 4959val = String(val); 4960var found = false; 4961Fx.CSS.Parsers.each(function(parser, key){ 4962if (found) return; 4963var parsed = parser.parse(val); 4964if ($chk(parsed)) found = {value: parsed, parser: parser}; 4965}); 4966found = found || {value: val, parser: Fx.CSS.Parsers.String}; 4967return found; 4968}); 4969}, 4970 4971//computes by a from and to prepared objects, using their parsers. 4972 4973compute: function(from, to, delta){ 4974var computed = []; 4975(Math.min(from.length, to.length)).times(function(i){ 4976computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); 4977}); 4978computed.$family = {name: 'fx:css:value'}; 4979return computed; 4980}, 4981 4982//serves the value as settable 4983 4984serve: function(value, unit){ 4985if ($type(value) != 'fx:css:value') value = this.parse(value); 4986var returned = []; 4987value.each(function(bit){ 4988returned = returned.concat(bit.parser.serve(bit.value, unit)); 4989}); 4990return returned; 4991}, 4992 4993//renders the change to an element 4994 4995render: function(element, property, value, unit){ 4996element.setStyle(property, this.serve(value, unit)); 4997}, 4998 4999//searches inside the page css to find the values for a selector 5000 5001search: function(selector){ 5002if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; 5003var to = {}; 5004Array.each(document.styleSheets, function(sheet, j){ 5005var href = sheet.href; 5006if (href && href.contains('://') && !href.contains(document.domain)) return; 5007var rules = sheet.rules || sheet.cssRules; 5008Array.each(rules, function(rule, i){ 5009if (!rule.style) return; 5010var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ 5011return m.toLowerCase(); 5012}) : null; 5013if (!selectorText || !selectorText.test('^' + selector + '$')) return; 5014Element.Styles.each(function(value, style){ 5015if (!rule.style[style] || Element.ShortStyles[style]) return; 5016value = String(rule.style[style]); 5017to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value; 5018}); 5019}); 5020}); 5021return Fx.CSS.Cache[selector] = to; 5022} 5023 5024}); 5025 5026Fx.CSS.Cache = {}; 5027 5028Fx.CSS.Parsers = new Hash({ 5029 5030Color: { 5031parse: function(value){ 5032if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); 5033return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; 5034}, 5035compute: function(from, to, delta){ 5036return from.map(function(value, i){ 5037return Math.round(Fx.compute(from[i], to[i], delta)); 5038}); 5039}, 5040serve: function(value){ 5041return value.map(Number); 5042} 5043}, 5044 5045Number: { 5046parse: parseFloat, 5047compute: Fx.compute, 5048serve: function(value, unit){ 5049return (unit) ? value + unit : value; 5050} 5051}, 5052 5053String: { 5054parse: $lambda(false), 5055compute: $arguments(1), 5056serve: $arguments(0) 5057} 5058 5059}); 5060 5061 5062/* 5063--- 5064 5065name: Fx.Morph 5066 5067description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. 5068 5069license: MIT-style license. 5070 5071requires: Fx.CSS 5072 5073provides: Fx.Morph 5074 5075... 5076*/ 5077 5078Fx.Morph = new Class({ 5079 5080Extends: Fx.CSS, 5081 5082initialize: function(element, options){ 5083this.element = this.subject = document.id(element); 5084this.parent(options); 5085}, 5086 5087set: function(now){ 5088if (typeof now == 'string') now = this.search(now); 5089for (var p in now) this.render(this.element, p, now[p], this.options.unit); 5090return this; 5091}, 5092 5093compute: function(from, to, delta){ 5094var now = {}; 5095for (var p in from) now[p] = this.parent(from[p], to[p], delta); 5096return now; 5097}, 5098 5099start: function(properties){ 5100if (!this.check(properties)) return this; 5101if (typeof properties == 'string') properties = this.search(properties); 5102var from = {}, to = {}; 5103for (var p in properties){ 5104var parsed = this.prepare(this.element, p, properties[p]); 5105from[p] = parsed.from; 5106to[p] = parsed.to; 5107} 5108return this.parent(from, to); 5109} 5110 5111}); 5112 5113Element.Properties.morph = { 5114 5115set: function(options){ 5116var morph = this.retrieve('morph'); 5117if (morph) morph.cancel(); 5118return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options)); 5119}, 5120 5121get: function(options){ 5122if (options || !this.retrieve('morph')){ 5123if (options || !this.retrieve('morph:options')) this.set('morph', options); 5124this.store('morph', new Fx.Morph(this, this.retrieve('morph:options'))); 5125} 5126return this.retrieve('morph'); 5127} 5128 5129}; 5130 5131Element.implement({ 5132 5133morph: function(props){ 5134this.get('morph').start(props); 5135return this; 5136} 5137 5138}); 5139 5140 5141/* 5142--- 5143 5144name: Fx.Transitions 5145 5146description: Contains a set of advanced transitions to be used with any of the Fx Classes. 5147 5148license: MIT-style license. 5149 5150credits: Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools. 5151 5152requires: Fx 5153 5154provides: Fx.Transitions 5155 5156... 5157*/ 5158 5159Fx.implement({ 5160 5161getTransition: function(){ 5162var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; 5163if (typeof trans == 'string'){ 5164var data = trans.split(':'); 5165trans = Fx.Transitions; 5166trans = trans[data[0]] || trans[data[0].capitalize()]; 5167if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; 5168} 5169return trans; 5170} 5171 5172}); 5173 5174Fx.Transition = function(transition, params){ 5175params = $splat(params); 5176return $extend(transition, { 5177easeIn: function(pos){ 5178return transition(pos, params); 5179}, 5180easeOut: function(pos){ 5181return 1 - transition(1 - pos, params); 5182}, 5183easeInOut: function(pos){ 5184return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; 5185} 5186}); 5187}; 5188 5189Fx.Transitions = new Hash({ 5190 5191linear: $arguments(0) 5192 5193}); 5194 5195Fx.Transitions.extend = function(transitions){ 5196for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); 5197}; 5198 5199Fx.Transitions.extend({ 5200 5201Pow: function(p, x){ 5202return Math.pow(p, x[0] || 6); 5203}, 5204 5205Expo: function(p){ 5206return Math.pow(2, 8 * (p - 1)); 5207}, 5208 5209Circ: function(p){ 5210return 1 - Math.sin(Math.acos(p)); 5211}, 5212 5213Sine: function(p){ 5214return 1 - Math.sin((1 - p) * Math.PI / 2); 5215}, 5216 5217Back: function(p, x){ 5218x = x[0] || 1.618; 5219return Math.pow(p, 2) * ((x + 1) * p - x); 5220}, 5221 5222Bounce: function(p){ 5223var value; 5224for (var a = 0, b = 1; 1; a += b, b /= 2){ 5225if (p >= (7 - 4 * a) / 11){ 5226value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); 5227break; 5228} 5229} 5230return value; 5231}, 5232 5233Elastic: function(p, x){ 5234return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); 5235} 5236 5237}); 5238 5239['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ 5240Fx.Transitions[transition] = new Fx.Transition(function(p){ 5241return Math.pow(p, [i + 2]); 5242}); 5243}); 5244 5245 5246/* 5247--- 5248 5249name: Fx.Tween 5250 5251description: Formerly Fx.Style, effect to transition any CSS property for an element. 5252 5253license: MIT-style license. 5254 5255requires: Fx.CSS 5256 5257provides: [Fx.Tween, Element.fade, Element.highlight] 5258 5259... 5260*/ 5261 5262Fx.Tween = new Class({ 5263 5264Extends: Fx.CSS, 5265 5266initialize: function(element, options){ 5267this.element = this.subject = document.id(element); 5268this.parent(options); 5269}, 5270 5271set: function(property, now){ 5272if (arguments.length == 1){ 5273now = property; 5274property = this.property || this.options.property; 5275} 5276this.render(this.element, property, now, this.options.unit); 5277return this; 5278}, 5279 5280start: function(property, from, to){ 5281if (!this.check(property, from, to)) return this; 5282var args = Array.flatten(arguments); 5283this.property = this.options.property || args.shift(); 5284var parsed = this.prepare(this.element, this.property, args); 5285return this.parent(parsed.from, parsed.to); 5286} 5287 5288}); 5289 5290Element.Properties.tween = { 5291 5292set: function(options){ 5293var tween = this.retrieve('tween'); 5294if (tween) tween.cancel(); 5295return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options)); 5296}, 5297 5298get: function(options){ 5299if (options || !this.retrieve('tween')){ 5300if (options || !this.retrieve('tween:options')) this.set('tween', options); 5301this.store('tween', new Fx.Tween(this, this.retrieve('tween:options'))); 5302} 5303return this.retrieve('tween'); 5304} 5305 5306}; 5307 5308Element.implement({ 5309 5310tween: function(property, from, to){ 5311this.get('tween').start(arguments); 5312return this; 5313}, 5314 5315fade: function(how){ 5316var fade = this.get('tween'), o = 'opacity', toggle; 5317how = $pick(how, 'toggle'); 5318switch (how){ 5319case 'in': fade.start(o, 1); break; 5320case 'out': fade.start(o, 0); break; 5321case 'show': fade.set(o, 1); break; 5322case 'hide': fade.set(o, 0); break; 5323case 'toggle': 5324var flag = this.retrieve('fade:flag', this.get('opacity') == 1); 5325fade.start(o, (flag) ? 0 : 1); 5326this.store('fade:flag', !flag); 5327toggle = true; 5328break; 5329default: fade.start(o, arguments); 5330} 5331if (!toggle) this.eliminate('fade:flag'); 5332return this; 5333}, 5334 5335highlight: function(start, end){ 5336if (!end){
5337end = this.retrieve('highlight:original', this.getStyle('background-color')); 5338end = (end == 'transparent') ? '#fff' : end; 5339} 5340var tween = this.get('tween'); 5341tween.start('background-color', start || '#ffff88', end).chain(function(){ 5342this.setStyle('background-color', this.retrieve('highlight:original')); 5343tween.callChain(); 5344}.bind(this)); 5345return this; 5346} 5347 5348}); 5349 5350 5351/* 5352--- 5353 5354name: Request 5355 5356description: Powerful all purpose Request Class. Uses XMLHTTPRequest. 5357 5358license: MIT-style license. 5359 5360requires: [Element, Chain, Events, Options, Browser] 5361 5362provides: Request 5363 5364... 5365*/ 5366 5367var Request = new Class({ 5368 5369Implements: [Chain, Events, Options], 5370 5371options: {/* 5372onRequest: $empty, 5373onComplete: $empty, 5374onCancel: $empty, 5375onSuccess: $empty, 5376onFailure: $empty, 5377onException: $empty,*/ 5378url: '', 5379data: '', 5380headers: { 5381'X-Requested-With': 'XMLHttpRequest', 5382'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 5383}, 5384async: true, 5385format: false, 5386method: 'post', 5387link: 'ignore', 5388isSuccess: null, 5389emulation: true, 5390urlEncoded: true, 5391encoding: 'utf-8', 5392evalScripts: false, 5393evalResponse: false, 5394noCache: false 5395}, 5396 5397initialize: function(options){ 5398this.xhr = new Browser.Request(); 5399this.setOptions(options); 5400this.options.isSuccess = this.options.isSuccess || this.isSuccess; 5401this.headers = new Hash(this.options.headers); 5402}, 5403 5404onStateChange: function(){ 5405if (this.xhr.readyState != 4 || !this.running) return; 5406this.running = false; 5407this.status = 0; 5408$try(function(){ 5409this.status = this.xhr.status; 5410}.bind(this)); 5411this.xhr.onreadystatechange = $empty; 5412if (this.options.isSuccess.call(this, this.status)){ 5413this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML}; 5414this.success(this.response.text, this.response.xml); 5415} else { 5416this.response = {text: null, xml: null}; 5417this.failure(); 5418} 5419}, 5420 5421isSuccess: function(){ 5422return ((this.status >= 200) && (this.status < 300)); 5423}, 5424 5425processScripts: function(text){ 5426if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text); 5427return text.stripScripts(this.options.evalScripts); 5428}, 5429 5430success: function(text, xml){ 5431this.onSuccess(this.processScripts(text), xml); 5432}, 5433 5434onSuccess: function(){ 5435this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); 5436}, 5437 5438failure: function(){ 5439this.onFailure(); 5440}, 5441 5442onFailure: function(){ 5443this.fireEvent('complete').fireEvent('failure', this.xhr); 5444}, 5445 5446setHeader: function(name, value){ 5447this.headers.set(name, value); 5448return this; 5449}, 5450 5451getHeader: function(name){ 5452return $try(function(){ 5453return this.xhr.getResponseHeader(name); 5454}.bind(this)); 5455}, 5456 5457check: function(){ 5458if (!this.running) return true; 5459switch (this.options.link){ 5460case 'cancel': this.cancel(); return true; 5461case 'chain': this.chain(this.caller.bind(this, arguments)); return false; 5462} 5463return false; 5464}, 5465 5466send: function(options){ 5467if (!this.check(options)) return this; 5468this.running = true; 5469 5470var type = $type(options); 5471if (type == 'string' || type == 'element') options = {data: options}; 5472 5473var old = this.options; 5474options = $extend({data: old.data, url: old.url, method: old.method}, options); 5475var data = options.data, url = String(options.url), method = options.method.toLowerCase(); 5476 5477switch ($type(data)){ 5478case 'element': data = document.id(data).toQueryString(); break; 5479case 'object': case 'hash': data = Hash.toQueryString(data); 5480} 5481 5482if (this.options.format){ 5483var format = 'format=' + this.options.format; 5484data = (data) ? format + '&' + data : format; 5485} 5486 5487if (this.options.emulation && !['get', 'post'].contains(method)){ 5488var _method = '_method=' + method; 5489data = (data) ? _method + '&' + data : _method; 5490method = 'post'; 5491} 5492 5493if (this.options.urlEncoded && method == 'post'){ 5494var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; 5495this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding); 5496} 5497 5498if (this.options.noCache){ 5499var noCache = 'noCache=' + new Date().getTime(); 5500data = (data) ? noCache + '&' + data : noCache; 5501} 5502 5503var trimPosition = url.lastIndexOf('/'); 5504if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); 5505 5506if (data && method == 'get'){ 5507url = url + (url.contains('?') ? '&' : '?') + data; 5508data = null; 5509} 5510 5511this.xhr.open(method.toUpperCase(), url, this.options.async); 5512 5513this.xhr.onreadystatechange = this.onStateChange.bind(this); 5514 5515this.headers.each(function(value, key){ 5516try { 5517this.xhr.setRequestHeader(key, value); 5518} catch (e){ 5519this.fireEvent('exception', [key, value]); 5520} 5521}, this); 5522 5523this.fireEvent('request'); 5524this.xhr.send(data); 5525if (!this.options.async) this.onStateChange(); 5526return this; 5527}, 5528 5529cancel: function(){ 5530if (!this.running) return this; 5531this.running = false;
5532this.xhr.abort(); 5533this.xhr.onreadystatechange = $empty; 5534this.xhr = new Browser.Request(); 5535this.fireEvent('cancel'); 5536return this; 5537} 5538 5539}); 5540 5541(function(){ 5542 5543var methods = {}; 5544['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ 5545methods[method] = function(){ 5546var params = Array.link(arguments, {url: String.type, data: $defined}); 5547return this.send($extend(params, {method: method})); 5548}; 5549}); 5550 5551Request.implement(methods); 5552 5553})(); 5554 5555Element.Properties.send = { 5556 5557set: function(options){ 5558var send = this.retrieve('send'); 5559if (send) send.cancel(); 5560return this.eliminate('send').store('send:options', $extend({ 5561data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') 5562}, options)); 5563}, 5564 5565get: function(options){ 5566if (options || !this.retrieve('send')){ 5567if (options || !this.retrieve('send:options')) this.set('send', options); 5568this.store('send', new Request(this.retrieve('send:options'))); 5569} 5570return this.retrieve('send'); 5571} 5572 5573}; 5574 5575Element.implement({ 5576 5577send: function(url){ 5578var sender = this.get('send'); 5579sender.send({data: this, url: url || sender.options.url}); 5580return this; 5581} 5582 5583}); 5584 5585 5586/* 5587--- 5588 5589name: Request.HTML 5590 5591description: Extends the basic Request Class with additional methods for interacting with HTML responses. 5592 5593license: MIT-style license. 5594 5595requires: [Request, Element] 5596 5597provides: Request.HTML 5598 5599... 5600*/ 5601 5602Request.HTML = new Class({ 5603 5604Extends: Request, 5605 5606options: { 5607update: false, 5608append: false, 5609evalScripts: true, 5610filter: false 5611}, 5612 5613processHTML: function(text){ 5614var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i); 5615text = (match) ? match[1] : text; 5616 5617var container = new Element('div'); 5618 5619return $try(function(){ 5620var root = '<root>' + text + '</root>', doc; 5621if (Browser.Engine.trident){ 5622doc = new ActiveXObject('Microsoft.XMLDOM'); 5623doc.async = false; 5624doc.loadXML(root); 5625} else { 5626doc = new DOMParser().parseFromString(root, 'text/xml'); 5627} 5628root = doc.getElementsByTagName('root')[0]; 5629if (!root) return null; 5630for (var i = 0, k = root.childNodes.length; i < k; i++){ 5631var child = Element.clone(root.childNodes[i], true, true); 5632if (child) container.grab(child); 5633} 5634return container; 5635}) || container.set('html', text); 5636}, 5637 5638success: function(text){ 5639var options = this.options, response = this.response; 5640 5641response.html = text.stripScripts(function(script){ 5642response.javascript = script; 5643}); 5644 5645var temp = this.processHTML(response.html); 5646 5647response.tree = temp.childNodes; 5648response.elements = temp.getElements('*'); 5649 5650if (options.filter) response.tree = response.elements.filter(options.filter); 5651if (options.update) document.id(options.update).empty().set('html', response.html); 5652else if (options.append) document.id(options.append).adopt(temp.getChildren()); 5653if (options.evalScripts) $exec(response.javascript); 5654 5655this.onSuccess(response.tree, response.elements, response.html, response.javascript); 5656} 5657 5658}); 5659 5660Element.Properties.load = { 5661 5662set: function(options){ 5663var load = this.retrieve('load'); 5664if (load) load.cancel(); 5665return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options)); 5666}, 5667 5668get: function(options){ 5669if (options || ! this.retrieve('load')){ 5670if (options || !this.retrieve('load:options')) this.set('load', options); 5671this.store('load', new Request.HTML(this.retrieve('load:options'))); 5672} 5673return this.retrieve('load'); 5674} 5675 5676}; 5677 5678Element.implement({ 5679 5680load: function(){ 5681this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type})); 5682return this; 5683} 5684 5685}); 5686 5687 5688/* 5689--- 5690 5691name: JSON 5692 5693description: JSON encoder and decoder. 5694 5695license: MIT-style license. 5696 5697see: <http://www.json.org/> 5698 5699requires: [Array, String, Number, Function, Hash] 5700 5701provides: JSON 5702 5703... 5704*/ 5705 5706var JSON = new Hash(this.JSON && { 5707stringify: JSON.stringify, 5708parse: JSON.parse 5709}).extend({ 5710 5711$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}, 5712 5713$replaceChars: function(chr){ 5714return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16); 5715}, 5716 5717encode: function(obj){ 5718switch ($type(obj)){ 5719case 'string': 5720return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; 5721case 'array': 5722return '[' + String(obj.map(JSON.encode).clean()) + ']'; 5723case 'object': case 'hash': 5724var string = []; 5725Hash.each(obj, function(value, key){ 5726var json = JSON.encode(value); 5727if (json) string.push(JSON.encode(key) + ':' + json); 5728}); 5729return '{' + string + '}'; 5730case 'number': case 'boolean': return String(obj); 5731case false: return 'null';
5732} 5733return null; 5734}, 5735 5736decode: function(string, secure){ 5737if ($type(string) != 'string' || !string.length) return null; 5738if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null; 5739return eval('(' + string + ')'); 5740} 5741 5742}); 5743 5744 5745/* 5746--- 5747 5748name: Request.JSON 5749 5750description: Extends the basic Request Class with additional methods for sending and receiving JSON data. 5751 5752license: MIT-style license. 5753 5754requires: [Request, JSON] 5755 5756provides: [Request.JSON] 5757 5758... 5759*/ 5760 5761Request.JSON = new Class({ 5762 5763Extends: Request, 5764 5765options: { 5766secure: true 5767}, 5768 5769initialize: function(options){ 5770this.parent(options); 5771this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'}); 5772}, 5773 5774success: function(text){ 5775this.response.json = JSON.decode(text, this.options.secure); 5776this.onSuccess(this.response.json, text); 5777} 5778 5779}); 5780 5781 5782/* 5783--- 5784 5785name: Cookie 5786 5787description: Class for creating, reading, and deleting browser Cookies. 5788 5789license: MIT-style license. 5790 5791credits: Based on the functions by Peter-Paul Koch (http://quirksmode.org). 5792 5793requires: Options 5794 5795provides: Cookie 5796 5797... 5798*/ 5799 5800var Cookie = new Class({ 5801 5802Implements: Options, 5803 5804options: { 5805path: false, 5806domain: false, 5807duration: false, 5808secure: false, 5809document: document 5810}, 5811 5812initialize: function(key, options){ 5813this.key = key; 5814this.setOptions(options); 5815}, 5816 5817write: function(value){ 5818value = encodeURIComponent(value); 5819if (this.options.domain) value += '; domain=' + this.options.domain; 5820if (this.options.path) value += '; path=' + this.options.path; 5821if (this.options.duration){ 5822var date = new Date(); 5823date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); 5824value += '; expires=' + date.toGMTString(); 5825} 5826if (this.options.secure) value += '; secure'; 5827this.options.document.cookie = this.key + '=' + value; 5828return this; 5829}, 5830 5831read: function(){ 5832var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); 5833return (value) ? decodeURIComponent(value[1]) : null; 5834}, 5835 5836dispose: function(){ 5837new Cookie(this.key, $merge(this.options, {duration: -1})).write(''); 5838return this; 5839} 5840 5841}); 5842 5843Cookie.write = function(key, value, options){ 5844return new Cookie(key, options).write(value); 5845}; 5846 5847Cookie.read = function(key){ 5848return new Cookie(key).read(); 5849}; 5850 5851Cookie.dispose = function(key, options){ 5852return new Cookie(key, options).dispose(); 5853}; 5854 5855 5856/* 5857--- 5858 5859name: DomReady 5860 5861description: Contains the custom event domready. 5862 5863license: MIT-style license. 5864 5865requires: Element.Event 5866 5867provides: DomReady 5868 5869... 5870*/ 5871 5872Element.Events.domready = { 5873 5874onAdd: function(fn){ 5875if (Browser.loaded) fn.call(this); 5876} 5877 5878}; 5879 5880(function(){ 5881 5882var domready = function(){ 5883if (Browser.loaded) return; 5884Browser.loaded = true; 5885window.fireEvent('domready'); 5886document.fireEvent('domready'); 5887}; 5888 5889window.addEvent('load', domready); 5890 5891if (Browser.Engine.trident){ 5892var temp = document.createElement('div'); 5893(function(){ 5894($try(function(){ 5895temp.doScroll(); // Technique by Diego Perini 5896return document.id(temp).inject(document.body).set('html', 'temp').dispose(); 5897})) ? domready() : arguments.callee.delay(50); 5898})(); 5899} else if (Browser.Engine.webkit && Browser.Engine.version < 525){ 5900(function(){ 5901(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); 5902})(); 5903} else { 5904document.addEvent('DOMContentLoaded', domready); 5905} 5906 5907})(); 5908 5909 5910/* 5911--- 5912 5913name: Selectors 5914 5915description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors. 5916 5917license: MIT-style license. 5918 5919requires: Element 5920 5921provides: Selectors 5922 5923... 5924*/ 5925 5926Native.implement([Document, Element], { 5927 5928getElements: function(expression, nocash){ 5929expression = expression.split(','); 5930var items, local = {}; 5931for (var i = 0, l = expression.length; i < l; i++){ 5932var selector = expression[i], elements = Selectors.Utils.search(this, selector, local); 5933if (i != 0 && elements.item) elements = $A(elements); 5934items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements); 5935} 5936return new Elements(items, {ddup: (expression.length > 1), cash: !nocash}); 5937} 5938 5939}); 5940 5941Element.implement({ 5942 5943match: function(selector){ 5944if (!selector || (selector == this)) return true; 5945var tagid = Selectors.Utils.parseTagAndID(selector); 5946var tag = tagid[0], id = tagid[1]; 5947if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
5948var parsed = Selectors.Utils.parseSelector(selector); 5949return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true; 5950} 5951 5952}); 5953 5954var Selectors = {Cache: {nth: {}, parsed: {}}}; 5955 5956Selectors.RegExps = { 5957id: (/#([\w-]+)/), 5958tag: (/^(\w+|\*)/), 5959quick: (/^(\w+|\*)$/), 5960splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g), 5961combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g) 5962}; 5963 5964Selectors.Utils = { 5965 5966chk: function(item, uniques){ 5967if (!uniques) return true; 5968var uid = $uid(item); 5969if (!uniques[uid]) return uniques[uid] = true; 5970return false; 5971}, 5972 5973parseNthArgument: function(argument){ 5974if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument]; 5975var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/); 5976if (!parsed) return false; 5977var inta = parseInt(parsed[1], 10); 5978var a = (inta || inta === 0) ? inta : 1; 5979var special = parsed[2] || false; 5980var b = parseInt(parsed[3], 10) || 0; 5981if (a != 0){ 5982b--; 5983while (b < 1) b += a; 5984while (b >= a) b -= a; 5985} else { 5986a = b; 5987special = 'index'; 5988} 5989switch (special){ 5990case 'n': parsed = {a: a, b: b, special: 'n'}; break; 5991case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break; 5992case 'even': parsed = {a: 2, b: 1, special: 'n'}; break; 5993case 'first': parsed = {a: 0, special: 'index'}; break; 5994case 'last': parsed = {special: 'last-child'}; break; 5995case 'only': parsed = {special: 'only-child'}; break; 5996default: parsed = {a: (a - 1), special: 'index'}; 5997} 5998 5999return Selectors.Cache.nth[argument] = parsed; 6000}, 6001 6002parseSelector: function(selector){ 6003if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector]; 6004var m, parsed = {classes: [], pseudos: [], attributes: []}; 6005while ((m = Selectors.RegExps.combined.exec(selector))){ 6006var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7]; 6007if (cn){ 6008parsed.classes.push(cn); 6009} else if (pn){ 6010var parser = Selectors.Pseudo.get(pn); 6011if (parser) parsed.pseudos.push({parser: parser, argument: pa}); 6012else parsed.attributes.push({name: pn, operator: '=', value: pa}); 6013} else if (an){ 6014parsed.attributes.push({name: an, operator: ao, value: av}); 6015} 6016} 6017if (!parsed.classes.length) delete parsed.classes; 6018if (!parsed.attributes.length) delete parsed.attributes; 6019if (!parsed.pseudos.length) delete parsed.pseudos; 6020if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null; 6021return Selectors.Cache.parsed[selector] = parsed; 6022}, 6023 6024parseTagAndID: function(selector){ 6025var tag = selector.match(Selectors.RegExps.tag); 6026var id = selector.match(Selectors.RegExps.id); 6027return [(tag) ? tag[1] : '*', (id) ? id[1] : false]; 6028}, 6029 6030filter: function(item, parsed, local){ 6031var i; 6032if (parsed.classes){ 6033for (i = parsed.classes.length; i--; i){ 6034var cn = parsed.classes[i]; 6035if (!Selectors.Filters.byClass(item, cn)) return false; 6036} 6037} 6038if (parsed.attributes){ 6039for (i = parsed.attributes.length; i--; i){ 6040var att = parsed.attributes[i]; 6041if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false; 6042} 6043} 6044if (parsed.pseudos){ 6045for (i = parsed.pseudos.length; i--; i){ 6046var psd = parsed.pseudos[i]; 6047if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false; 6048} 6049} 6050return true; 6051}, 6052 6053getByTagAndID: function(ctx, tag, id){ 6054if (id){ 6055var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true); 6056return (item && Selectors.Filters.byTag(item, tag)) ? [item] : []; 6057} else { 6058return ctx.getElementsByTagName(tag); 6059} 6060}, 6061 6062search: function(self, expression, local){ 6063var splitters = []; 6064 6065var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){ 6066splitters.push(m1); 6067return ':)' + m2; 6068}).split(':)'); 6069 6070var items, filtered, item; 6071 6072for (var i = 0, l = selectors.length; i < l; i++){ 6073 6074var selector = selectors[i]; 6075 6076if (i == 0 && Selectors.RegExps.quick.test(selector)){ 6077items = self.getElementsByTagName(selector); 6078continue; 6079} 6080 6081var splitter = splitters[i - 1]; 6082 6083var tagid = Selectors.Utils.parseTagAndID(selector); 6084var tag = tagid[0], id = tagid[1]; 6085 6086if (i == 0){ 6087items = Selectors.Utils.getByTagAndID(self, tag, id); 6088} else { 6089var uniques = {}, found = []; 6090for (var j = 0, k = items.length; j < k;
6090 j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques); 6091items = found; 6092} 6093 6094var parsed = Selectors.Utils.parseSelector(selector); 6095 6096if (parsed){ 6097filtered = []; 6098for (var m = 0, n = items.length; m < n; m++){ 6099item = items[m]; 6100if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item); 6101} 6102items = filtered; 6103} 6104 6105} 6106 6107return items; 6108 6109} 6110 6111}; 6112 6113Selectors.Getters = { 6114 6115' ': function(found, self, tag, id, uniques){ 6116var items = Selectors.Utils.getByTagAndID(self, tag, id); 6117for (var i = 0, l = items.length; i < l; i++){ 6118var item = items[i]; 6119if (Selectors.Utils.chk(item, uniques)) found.push(item); 6120} 6121return found; 6122}, 6123 6124'>': function(found, self, tag, id, uniques){ 6125var children = Selectors.Utils.getByTagAndID(self, tag, id); 6126for (var i = 0, l = children.length; i < l; i++){ 6127var child = children[i]; 6128if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child); 6129} 6130return found; 6131}, 6132 6133'+': function(found, self, tag, id, uniques){ 6134while ((self = self.nextSibling)){ 6135if (self.nodeType == 1){ 6136if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); 6137break; 6138} 6139} 6140return found; 6141}, 6142 6143'~': function(found, self, tag, id, uniques){ 6144while ((self = self.nextSibling)){ 6145if (self.nodeType == 1){ 6146if (!Selectors.Utils.chk(self, uniques)) break; 6147if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); 6148} 6149} 6150return found; 6151} 6152 6153}; 6154 6155Selectors.Filters = { 6156 6157byTag: function(self, tag){ 6158return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag)); 6159}, 6160 6161byID: function(self, id){ 6162return (!id || (self.id && self.id == id)); 6163}, 6164 6165byClass: function(self, klass){ 6166return (self.className && self.className.contains && self.className.contains(klass, ' ')); 6167}, 6168 6169byPseudo: function(self, parser, argument, local){ 6170return parser.call(self, argument, local); 6171}, 6172 6173byAttribute: function(self, name, operator, value){ 6174var result = Element.prototype.getProperty.call(self, name); 6175if (!result) return (operator == '!='); 6176if (!operator || value == undefined) return true; 6177switch (operator){ 6178case '=': return (result == value); 6179case '*=': return (result.contains(value)); 6180case '^=': return (result.substr(0, value.length) == value); 6181case '$=': return (result.substr(result.length - value.length) == value); 6182case '!=': return (result != value); 6183case '~=': return result.contains(value, ' '); 6184case '|=': return result.contains(value, '-'); 6185} 6186return false; 6187} 6188 6189}; 6190 6191Selectors.Pseudo = new Hash({ 6192 6193// w3c pseudo selectors 6194 6195checked: function(){ 6196return this.checked; 6197}, 6198 6199empty: function(){ 6200return !(this.innerText || this.textContent || '').length; 6201}, 6202 6203not: function(selector){ 6204return !Element.match(this, selector); 6205}, 6206 6207contains: function(text){ 6208return (this.innerText || this.textContent || '').contains(text); 6209}, 6210 6211'first-child': function(){ 6212return Selectors.Pseudo.index.call(this, 0); 6213}, 6214 6215'last-child': function(){ 6216var element = this; 6217while ((element = element.nextSibling)){ 6218if (element.nodeType == 1) return false; 6219} 6220return true; 6221}, 6222 6223'only-child': function(){ 6224var prev = this; 6225while ((prev = prev.previousSibling)){ 6226if (prev.nodeType == 1) return false; 6227} 6228var next = this; 6229while ((next = next.nextSibling)){ 6230if (next.nodeType == 1) return false; 6231} 6232return true; 6233}, 6234 6235'nth-child': function(argument, local){ 6236argument = (argument == undefined) ? 'n' : argument; 6237var parsed = Selectors.Utils.parseNthArgument(argument); 6238if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local); 6239var count = 0; 6240local.positions = local.positions || {}; 6241var uid = $uid(this); 6242if (!local.positions[uid]){ 6243var self = this; 6244while ((self = self.previousSibling)){ 6245if (self.nodeType != 1) continue; 6246count ++; 6247var position = local.positions[$uid(self)]; 6248if (position != undefined){ 6249count = position + count; 6250break; 6251} 6252} 6253local.positions[uid] = count; 6254} 6255return (local.positions[uid] % parsed.a == parsed.b); 6256}, 6257 6258// custom pseudo selectors 6259 6260index: function(index){ 6261var element = this, count = 0; 6262while ((element = element.previousSibling)){ 6263if (element.nodeType == 1 && ++count > index) return false;
6264} 6265return (count == index); 6266}, 6267 6268even: function(argument, local){ 6269return Selectors.Pseudo['nth-child'].call(this, '2n+1', local); 6270}, 6271 6272odd: function(argument, local){ 6273return Selectors.Pseudo['nth-child'].call(this, '2n', local); 6274}, 6275 6276selected: function(){ 6277return this.selected; 6278}, 6279 6280enabled: function(){ 6281return (this.disabled === false); 6282} 6283 6284}); 6285 6286 6287/* 6288--- 6289 6290name: Swiff 6291 6292description: Wrapper for embedding SWF movies. Supports External Interface Communication. 6293 6294license: MIT-style license. 6295 6296credits: Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. 6297 6298requires: [Options, $util] 6299 6300provides: Swiff 6301 6302... 6303*/ 6304 6305var Swiff = new Class({ 6306 6307Implements: [Options], 6308 6309options: { 6310id: null, 6311height: 1, 6312width: 1, 6313container: null, 6314properties: {}, 6315params: { 6316quality: 'high', 6317allowScriptAccess: 'always', 6318wMode: 'transparent', 6319swLiveConnect: true 6320}, 6321callBacks: {}, 6322vars: {} 6323}, 6324 6325toElement: function(){ 6326return this.object; 6327}, 6328 6329initialize: function(path, options){ 6330this.instance = 'Swiff_' + $time(); 6331 6332this.setOptions(options); 6333options = this.options; 6334var id = this.id = options.id || this.instance; 6335var container = document.id(options.container); 6336 6337Swiff.CallBacks[this.instance] = {}; 6338 6339var params = options.params, vars = options.vars, callBacks = options.callBacks; 6340var properties = $extend({height: options.height, width: options.width}, options.properties); 6341 6342var self = this; 6343 6344for (var callBack in callBacks){ 6345Swiff.CallBacks[this.instance][callBack] = (function(option){ 6346return function(){ 6347return option.apply(self.object, arguments); 6348}; 6349})(callBacks[callBack]); 6350vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; 6351} 6352 6353params.flashVars = Hash.toQueryString(vars); 6354if (Browser.Engine.trident){ 6355properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; 6356params.movie = path; 6357} else { 6358properties.type = 'application/x-shockwave-flash'; 6359properties.data = path; 6360} 6361var build = '<object id="' + id + '"'; 6362for (var property in properties) build += ' ' + property + '="' + properties[property] + '"'; 6363build += '>'; 6364for (var param in params){ 6365if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />'; 6366} 6367build += '</object>'; 6368this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; 6369}, 6370 6371replaces: function(element){ 6372element = document.id(element, true); 6373element.parentNode.replaceChild(this.toElement(), element); 6374return this; 6375}, 6376 6377inject: function(element){ 6378document.id(element, true).appendChild(this.toElement()); 6379return this; 6380}, 6381 6382remote: function(){ 6383return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments)); 6384} 6385 6386}); 6387 6388Swiff.CallBacks = {}; 6389 6390Swiff.remote = function(obj, fn){ 6391var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>'); 6392return eval(rs); 6393};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.