diff options
-rw-r--r-- | js/menu.js | 237 | ||||
-rw-r--r-- | tests/js/menuTests.js | 191 | ||||
-rw-r--r-- | tests/js/qunit/jquery-1.8.0.min.js | 2 | ||||
-rw-r--r-- | tests/js/qunit/qunit-1.9.0.css | 231 | ||||
-rw-r--r-- | tests/js/qunit/qunit-1.9.0.js | 1932 | ||||
-rw-r--r-- | tests/js/testSuite.html | 17 |
6 files changed, 2510 insertions, 100 deletions
diff --git a/js/menu.js b/js/menu.js index dd57f4a22..5f9095768 100644 --- a/js/menu.js +++ b/js/menu.js @@ -25,53 +25,51 @@ var News = News || {}; 'Folder': 1, 'Filter': 2 // used for starred items or new items } - + News.MenuNodeType = MenuNodeType; /** * This is the basic menu used to construct and maintain the menu * @param cls the css class of the element - * @param id the id of the element */ - Menu = function(cls, id){ + Menu = function(cls){ this._class = cls; this._children = []; this._parent = false; - this._id = id; + this._rendered = false; + this._id = 0; this._$htmlElement = $('<ul>'); } - Menu.prototype.addChild = function(node){ - node.setParent(this); - this._children.push(node); - } + News.Menu = Menu; - Menu.prototype.setParent = function(node){ - this._parent = node; - } - /** - * Recursively traverse the menu and returns the - * Node element matching the type and id - * @return the node element + * Attaches a MenuNode to a node and renders it in the dom + * @param parentType the type of the parent node + * @param parentId the id of the parent node, if 0 the top menu is used + * @param node the MenuNode that should be created */ - Menu.prototype.findNode = function(id, type){ - for(var i=0; i<this._children.length; i++){ - var child = this._children[i]; - if(child._type === type && child._id === id){ - return child; - } else { - return child.findNode(type, id); - } + Menu.prototype.createNode = function(parentType, parentId, node){ + // if we pass the parentId 0 we assume the parent is the menu + var parentNode; + if(parentId === 0){ + parentNode = this; + } else { + parentNode = this._findNode(parentType, parentId); } + parentNode._addChildNode(node); + parentNode._$htmlElement.append(node.render()); } /** * Recursively remove all occurences of the node from the dom and * from the datastructure + * @param type the type of the node + * @param id the id of the node + * @return the childelemnt or undefined if not found */ - Menu.prototype.removeNode = function(id, type){ + Menu.prototype.removeNode = function(type, id){ var nodeIndex; for(var i=0; i<this._children.length; i++){ var child = this._children[i]; @@ -79,12 +77,25 @@ var News = News || {}; var nodeIndex = i; // if we have children, we need to remove their // html from the dom first then we need to - this._$htmlElement.remove(child); + child._$htmlElement.remove(); this._children.splice(nodeIndex, 1); + return child; } else { - child.removeNode(type, id); + var child = child.removeNode(type, id); + if(child !== undefined){ + return child; + } } } + return undefined; + } + + /** + * Updates a node in the menu + */ + Menu.prototype.updateNode = function(type, id, data){ + var node = this._findNode(type, id); + node.update(data); } /** @@ -118,36 +129,17 @@ var News = News || {}; Menu.prototype.populateFromJSON = function(json, attachToNode){ for(var i=0; i<json.length; i++){ var nodeInfo = json[i]; - var node = new MenuNode(nodeInfo.title, nodeInfo.id, - nodeInfo.type, nodeInfo.icon, nodeInfo.unreadCount); - attachToNode.addChild(node); + var nodeData = { + title: nodeInfo.title, + icon: nodeInfo.icon, + unreadCount: nodeInfo.unreadCount + }; + var node = new MenuNode(nodeInfo.type, nodeInfo.id, nodeData); + attachToNode._addChildNode(node); this.populateFromJSON(nodeInfo.children, node); } } - /** - * Sets the unreadcount for all items from json markup - * format of json is: - [ - { - id: '1', - type: 1, - unreadCount: 39 - }, - { - ... - } - ] - */ - Menu.prototype.setUnreadCountFromJSON = function(json){ - for(var i=0; i<json.length; i++){ - var element = json[i]; - var node = this.findNode(element.id, element.type); - node.setUnreadCount(element.unreadCount); - } - } - - Menu.prototype.render = function(){ var $html = this._$htmlElement.addClass(this._class).data('id', this._id); for(var i=0; i<this._children.length; i++){ @@ -155,76 +147,95 @@ var News = News || {}; var childHTML = child.render(); $html.append(childHTML); } + this._rendered = true; + return $html; } - News.Menu = Menu; + + /** + * Returns the number of elements in the menu + * @return the number of all children + */ + Menu.prototype.getSize = function(){ + var size = this._children.length; + for(var i=0; i<this._children.length; i++){ + size += this._children[i].getSize(); + } + return size; + } + + + // private + + /** + * Adds a node to the current one + * @param node the node which we want to add to the menu + */ + Menu.prototype._addChildNode = function(node){ + node._parent = this; + this._children.push(node); + } + + /** + * Recursively traverse the menu and returns the + * Node element matching the type and id + * @param type the type of the node (MenuNodeType) + * @param id the id of the node + * @return the node element or undefined + */ + Menu.prototype._findNode = function(type, id){ + for(var i=0; i<this._children.length; i++){ + var child = this._children[i]; + if(child._type === type && child._id === id){ + return child; + } else { + var childNode = child._findNode(type, id); + if(childNode !== undefined){ + return childNode; + } + } + } + return undefined; + } /** * Items which are in the menu - * @param title the caption of the menu item * @param type the type of the node, a MenuNodeType * @param id the id of the node. id and type must be unique! - * @param icon is the little image that appears left of the caption - * @param unreadCount the current count of unread items + * @param data the data array containing title, icon and unreadCount */ - MenuNode = function(title, id, type, icon, unreadCount){ + MenuNode = function(type, id, data){ this._type = type; this._id = id; - this._title = title; this._$htmlElement = $('<li>'); this._children = []; - this.setUnreadCount(unreadCount); - this.setIcon(icon); + this.update(data); } MenuNode.prototype = Object.create(Menu.prototype); + News.MenuNode = MenuNode; /** - * Sets the unread count and handles the appropriate css - * classes + * Updates the given values of a node + * @param data the array with the data, if parts are undefined, theyre not + * updated */ - MenuNode.prototype.setUnreadCount = function(unreadCount){ - unreadCount = parseInt(unreadCount); - - if(unreadCount === 0){ - this._$htmlElement.addClass('all_read'); - } - - if(this._unreadCount !== undefined && this._unreadCount === 0 - && unreadCount > 0){ - this._$htmlElement.removeClass('all_read'); + MenuNode.prototype.update = function(data){ + if(data.title !== undefined){ + this._title = data.title; + this._$htmlElement.children('.title').html(this._title); } - this._unreadCount = unreadCount; - } - - MenuNode.prototype.increaseUnreadCount = function(by){ - this._unreadCount += parseInt(by); - } - - MenuNode.prototype.decreaseUnreadCount = function(by){ - this._unreadCount -= parseInt(by); - } - - MenuNode.prototype.changeTitle = function(title){ - this._title = title; - this._$htmlElement.children('.title').html(this._title); - } - - MenuNode.prototype.setIcon = function(icon){ - if(icon !== undefined){ - this._icon = icon; + if(data.icon !== undefined){ + this._icon = data.icon; this._$htmlElement.css('background-image', this._icon); } - } - /** - * Toggles the selection class - */ - MenuNode.prototype.toggleSelected = function(){ - this._$htmlElement.toggle('selected'); + if(data.unreadCount !== undefined){ + this._setUnreadCount(data.unreadCount); + } } MenuNode.prototype.render = function(){ @@ -248,7 +259,7 @@ var News = News || {}; break; } - var $title = $('<span>').addClass('title').html(this._title); + var $title = $('<a>').addClass('title').html(this._title).attr('href', '#'); $elem.append($title); var $subNode = $('<ul>'); @@ -263,8 +274,34 @@ var News = News || {}; } return $elem; + } + + // private + + /** + * Sets the unread count and handles the appropriate css + * classes + */ + MenuNode.prototype._setUnreadCount = function(unreadCount){ + unreadCount = parseInt(unreadCount); + + if(unreadCount === 0){ + this._$htmlElement.addClass('all_read'); + } + + if(this._unreadCount !== undefined && this._unreadCount === 0 + && unreadCount > 0){ + this._$htmlElement.removeClass('all_read'); + } + + this._unreadCount = unreadCount; + } + + /** + * Toggles the selection class + */ + MenuNode.prototype._toggleSelected = function(){ + this._$htmlElement.toggle('selected'); } - - News.MenuNode = MenuNode; })();
\ No newline at end of file diff --git a/tests/js/menuTests.js b/tests/js/menuTests.js new file mode 100644 index 000000000..b0bebbed2 --- /dev/null +++ b/tests/js/menuTests.js @@ -0,0 +1,191 @@ +/** +* ownCloud - News app +* +* @author Bernhard Posselt +* Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +* +* This file is licensed under the Affero General Public License version 3 or later. +* See the COPYING-README file +* +*/ + +var News = News || {}; +var NewsTests = NewsTests || {}; + +// variables with are used again +NewsTests.jsonStruct = [ + { + id: 1, + title: 'hi', + type: News.MenuNodeType.Folder, + unreadCount: 1, + children: [ + { + id: 2, + title: 'hi too', + type: News.MenuNodeType.Feed, + unreadCount: 4, + children: [], + }, + { + id: 3, + title: 'hi 3', + type: News.MenuNodeType.Feed, + children: [], + unreadCount: 3, + }, + { + id: 2, + title: 'hi 3', + type: News.MenuNodeType.Folder, + children: [], + unreadCount: 13, + }, + ] + }, + { + id: 4, + title: 'hi 4', + type: News.MenuNodeType.Feed, + children: [], + unreadCount: 1, + }, + { + id: 5, + title: 'hi 4', + type: News.MenuNodeType.Feed, + children: [], + unreadCount: 50, + }, +]; + + +QUnit.testStart(function(){ + NewsTests.menu = new News.Menu('feed_menu'); + NewsTests.popMenu = new News.Menu('feed_menu'); + NewsTests.popMenu.populateFromJSON(NewsTests.jsonStruct, NewsTests.popMenu); + // empty menu + NewsTests.$menuContainer = $('<div>'); + NewsTests.$menuContainer.append(NewsTests.menu.render()); + NewsTests.$menuDomElem = NewsTests.$menuContainer.children('ul'); + // populated menu + NewsTests.$popMenuContainer = $('<div>'); + NewsTests.$popMenuContainer.append(NewsTests.popMenu.render()); + NewsTests.$popMenuDomElem = NewsTests.$popMenuContainer.children('ul'); + var menuData = { + title: 'this is rad', + unreadCount: 111, + }; + NewsTests.node = new News.MenuNode(News.MenuNodeType.Feed, 6, menuData); +}); + + +/** + * Empty menu tests + */ +test('Empty menu should have certain variables', function(){ + equal(NewsTests.menu._children.length, 0); + equal(NewsTests.menu._class, 'feed_menu'); + equal(NewsTests.menu._parent, false); + equal(NewsTests.menu.getSize(), 0); +}); + + +test('Empty menu dom should have certain dom elements', function(){ + equal(NewsTests.$menuContainer.length, 1); + ok(NewsTests.$menuDomElem.hasClass('feed_menu')); + equal(NewsTests.$menuDomElem.children().length, 0); +}); + + +/** + * Find node tests + */ +test('Finding a folder node should succeed', function(){ + var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 1); + ok(node !== undefined); +}); + + +test('Finding a nested folder node should succeed', function(){ + var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 2); + ok(node !== undefined); +}); + + +test('Finding a folder node that doesnt exist should fail', function(){ + var node = NewsTests.popMenu._findNode(News.MenuNodeType.Folder, 10); + ok(node === undefined); +}); + + +test('Finding a feed node should succeed', function(){ + var node = NewsTests.popMenu._findNode(News.MenuNodeType.Feed, 4); + ok(node !== undefined); +}); + + +test('Finding a feed node that doesnt exist should fail', function(){ + var node = NewsTests.popMenu._findNode(News.MenuNodeType.Feed, 10); + ok(node === undefined); +}); + + +/** + * Adding nodes test + */ +test('Adding a node should set children and parent correctly', function(){ + NewsTests.menu._addChildNode(NewsTests.node); + equal(NewsTests.node._parent, NewsTests.menu); + ok(NewsTests.menu._children.indexOf(NewsTests.node) !== -1); + equal(NewsTests.menu.getSize(), 1); +}); + + +/** + * Creating nodes tests + */ +test('Adding a new node should create the correct dom', function(){ + NewsTests.menu.createNode(News.MenuNodeType.Folder, 0, NewsTests.node); + equal(NewsTests.$menuDomElem.children().length, 1); +}); + + +/** + * Removing nodes tests + */ +test('Removing a feed node should remove the correct dom', function(){ + equal(NewsTests.$popMenuDomElem.children().length, 3); + + var child = NewsTests.popMenu.removeNode(News.MenuNodeType.Feed, 2); + ok(child !== undefined); + + // top length should stay the same + equal(NewsTests.$popMenuDomElem.children().length, 3); + equal(NewsTests.popMenu._children.length, 3); + // but size should have been reduced by 1 + equal(NewsTests.popMenu.getSize(), 5); + +}); + +test('Removing a non existent node should not change anything', function(){ + var child = NewsTests.popMenu.removeNode(News.MenuNodeType.Feed, 12); + ok(child === undefined); + + // top length should stay the same + equal(NewsTests.$popMenuDomElem.children().length, 3); + equal(NewsTests.popMenu._children.length, 3); + equal(NewsTests.popMenu.getSize(), 6); + +}); + +test('Removing a parent node should remove its children', function(){ + var child = NewsTests.popMenu.removeNode(News.MenuNodeType.Folder, 1); + ok(child !== undefined); + + // top length should stay the same + equal(NewsTests.$popMenuDomElem.children().length, 2); + equal(NewsTests.popMenu._children.length, 2); + equal(NewsTests.popMenu.getSize(), 2); + +});
\ No newline at end of file diff --git a/tests/js/qunit/jquery-1.8.0.min.js b/tests/js/qunit/jquery-1.8.0.min.js new file mode 100644 index 000000000..f121291c4 --- /dev/null +++ b/tests/js/qunit/jquery-1.8.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v@1.8.0 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bX(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bV.length;while(e--){b=bV[e]+c;if(b in a)return b}return d}function bY(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function bZ(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bY(c)&&(e[f]=p._data(c,"olddisplay",cb(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b$(a,b,c){var d=bO.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function b_(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bU[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bU[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bU[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bU[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bU[e]+"Width"))||0));return f}function ca(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bP.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+b_(a,b,c||(f?"border":"content"),e)+"px"}function cb(a){if(bR[a])return bR[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bR[a]=c,c}function ch(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||cd.test(a)?d(a,e):ch(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ch(a+"["+e+"]",b[e],c,d);else d(a,b)}function cy(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cz(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cu;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cz(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cz(a,c,d,e,"*",g)),h}function cA(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cB(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cC(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cK(){try{return new a.XMLHttpRequest}catch(b){}}function cL(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cT(){return setTimeout(function(){cM=b},0),cM=p.now()}function cU(a,b){p.each(b,function(b,c){var d=(cS[b]||[]).concat(cS["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cV(a,b,c){var d,e=0,f=0,g=cR.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cM||cT(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cM||cT(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cW(k,j.opts.specialEasing);for(;e<g;e++){d=cR[e].call(j,a,k,j.opts);if(d)return d}return cU(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cW(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cX(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bY(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cb(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cO.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cY(a,b,c,d,e){return new cY.prototype.init(a,b,c,d,e)}function cZ(a,b){var c,d={height:a},e=0;for(;e<4;e+=2-b)c=bU[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function c_(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=r.test(" ")?/^[\s\xA0]+|[\s\xA0]+$/g:/^\s+|\s+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.0",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":a.toString().replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||f.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete"||e.readyState!=="loading"&&e.addEventListener)setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){p.isFunction(c)&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return typeof a=="object"?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length||!d)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c |