From: pho Date: Sat, 3 Nov 2007 07:08:06 +0000 (+0900) Subject: Wrote more... X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Rakka.git;a=commitdiff_plain;h=e0da4e15d6a4053be720bddf62ae755f1f63ec3b Wrote more... darcs-hash:20071103070806-62b54-ed5f1c92485dd877c7d6db85f57dda713513aef2.gz --- diff --git a/.boring b/.boring index d833803..e7f247d 100644 --- a/.boring +++ b/.boring @@ -57,5 +57,5 @@ ^repos(/|$) ^Rakka/Resource/JavaScript\.hs$ -^js/jquery- -^js/yuicompressor\.jar$ +^js/yuicompressor- +^js/packed\.js$ diff --git a/Rakka.cabal b/Rakka.cabal index 47c87a1..82bb773 100644 --- a/Rakka.cabal +++ b/Rakka.cabal @@ -38,6 +38,12 @@ Extra-Source-Files: Rakka.buildinfo.in configure configure.ac + js/Makefile + js/base.js + js/editPage.js + js/jquery-1.2.1.js + js/jquery-dom.js + js/screen.js Executable: diff --git a/Rakka/Resource/PageEntity.hs b/Rakka/Resource/PageEntity.hs index 3c00612..32a4a61 100644 --- a/Rakka/Resource/PageEntity.hs +++ b/Rakka/Resource/PageEntity.hs @@ -37,7 +37,7 @@ fallbackPageEntity env path , resGet = Just $ handleGet env (toPageName path) , resHead = Nothing , resPost = Nothing - , resPut = Nothing + , resPut = Just $ handlePut env (toPageName path) , resDelete = Nothing } where @@ -269,3 +269,10 @@ notFoundToXHTML env ) ) ) ) -<< pageNotFound + + +handlePut :: Environment -> PageName -> Resource () +handlePut env name + = do xml <- input defaultLimit + setContentType $ read "text/xml" + output xml diff --git a/js/Makefile b/js/Makefile index d7e9959..689deee 100644 --- a/js/Makefile +++ b/js/Makefile @@ -1,34 +1,31 @@ +JQUERY_SOURCE = jquery-1.2.1.js +COMPRESSOR = yuicompressor-2.2.4.jar + SOURCES = \ - jquery-1.2.1.js \ + $(JQUERY_SOURCE) \ jquery-dom.js \ base.js \ editPage.js \ + screen.js \ $(NULL) - -build: ../Rakka/Resource/JavaScript.hs +COMPRESS = java -jar $(COMPRESSOR) --type js --charset UTF-8 -../Rakka/Resource/JavaScript.hs: $(SOURCES) yuicompressor.jar - cat $(SOURCES) > tmp.js - java -jar yuicompressor.jar --type js --charset UTF-8 -o tmp.packed.js --warn tmp.js - lucu-implant-file -o $@ -m Rakka.Resource.JavaScript -t text/javascript tmp.packed.js - rm tmp.js tmp.packed.js +build: ../Rakka/Resource/JavaScript.hs -jquery-dom.js: - @echo "Warning: jquery-dom.js is missing. Trying to download it..." - wget http://mg.to/files/jquery-dom.js +packed.js: $(SOURCES) $(COMPRESSOR) +# cat $(SOURCES) > $@ + cat $(SOURCES) | $(COMPRESS) --warn -o $@ -jquery-%.js: - @echo "Error: $@ has to be placed on this directory." - @echo " See http://jquery.com/" - @exit 1 +../Rakka/Resource/JavaScript.hs: packed.js + lucu-implant-file -o $@ -m Rakka.Resource.JavaScript -t text/javascript packed.js clean: - rm -f ../Rakka/Resource/JavaScript.hs + rm -f ../Rakka/Resource/JavaScript.hs packed.js $(JQUERY_PACKED) yuicompressor.jar: diff --git a/js/editPage.js b/js/editPage.js index 49b021b..e14b383 100644 --- a/js/editPage.js +++ b/js/editPage.js @@ -1,99 +1,131 @@ Rakka.editPage = function (baseURI, pageName) { - var $body = $("div.body"); - - $body.text("Loading... please wait."); + var $area = Rakka.switchScreen(); + $area.text("Loading... please wait."); // XML 版のページを取得する。 $.ajax({ url : baseURI + pageName + ".xml", success: function (pageXml) { - var $page = $(pageXml).find("page"); - var oldRevision = $page.attr("revision"); - var defaultType = $page.attr("isBinary") == "yes" ? "binary" - : $page.attr("type") == "text/x-rakka" ? "rakka" - : $page.attr("type") == "text/css" ? "css" - : "unknown" - ; - var source = $page.find("textData").text(); - Rakka.displayPageEditor($body, pageName, oldRevision, defaultType, source); - }, + var $page = $(pageXml).find("page"); + var oldRevision = $page.attr("revision"); + var defaultType + = $page.attr("isBinary") == "yes" ? "binary" + : $page.attr("type") == "text/x-rakka" ? "rakka" + : $page.attr("type") == "text/css" ? "css" + : "unknown" + ; + var source = $page.find("textData").text(); + Rakka.displayPageEditor(baseURI, pageName, oldRevision, defaultType, source); + }, error : function (req) { - if (req.status == 404) { - Rakka.displayPageEditor($body, pageName, null, "rakka", null); - } - else { - $body.text("Error: " + req.status + " " + req.statusText); - } - } - }); + if (req.status == 404) { + Rakka.displayPageEditor(baseURI, pageName, null, "rakka", null); + } + else { + $area.text("Error: " + req.status + " " + req.statusText); + } + } + }); }; -Rakka.displayPageEditor = function ($place, pageName, oldRevision, defaultType, source) { - $place.empty(); +Rakka.displayPageEditor = function (baseURI, pageName, oldRevision, defaultType, source) { + var $area = Rakka.switchScreen(); + $area.empty(); - $place.append($.H1({}, "Edit page")); + $area.append($.H1({}, "Edit page")); var fldPageName - = $.INPUT({type : "text", value: pageName}); + = $.INPUT({type : "text", value: pageName}); var btnTypeRakka - = $.INPUT({type : "radio", - name : "type", - checked: (defaultType == "rakka" ? "checked" : "")}); + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "rakka" ? "checked" : "")}); var btnTypeCSS - = $.INPUT({type : "radio", - name : "type", - checked: (defaultType == "css" ? "checked" : "")}); + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "css" ? "checked" : "")}); var btnTypeBinary - = $.INPUT({type : "radio", - name : "type", - checked: (defaultType == "binary" ? "checked" : "")}); + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "binary" ? "checked" : "")}); var fldRakkaSource - = $.TEXTAREA({}, (defaultType == "rakka" && source != null ? source : "")); + = $.TEXTAREA({}, (defaultType == "rakka" && source != null ? source : "")); var fldCSSSource - = $.TEXTAREA({}, (defaultType == "css" && source != null ? source : "")); + = $.TEXTAREA({}, (defaultType == "css" && source != null ? source : "")); var fldUploadFile - = $.INPUT({type: "file"}); + = $.INPUT({type: "file"}); var trContent - = $.TR({}, - $.TH({}), - $.TD({}) - ); + = $.TR({}, + $.TH({}), + $.TD({}) + ); var btnPreview - = $.INPUT({type: "button", value: "Preview page"}); + = $.INPUT({type: "button", value: "Preview page"}); + + $(btnPreview).click(function () { + throw new Error("FIXME: not implemented yet"); + }); var btnSubmit - = $.INPUT({type: "button", value: "Submit page"}); + = $.INPUT({type: "button", value: "Submit page"}); + + $(btnSubmit).click(function () { + if (btnTypeRakka.checked) { + Rakka.submitTextPage( + baseURI, + pageName, + oldRevision, + fldPageName.value, + "text/x-rakka", + fldRakkaSource.value); + } + else if (btnTypeCSS.checked) { + Rakka.submitTextPage( + baseURI, + pageName, + oldRevision, + fldPageName.value, + "text/css", + fldCSSSource.value); + } + else if (btnTypeBinary.checked) { + Rakka.submitBinaryPage( + baseURI, + pageName, + oldRevision, + fldPageName.value, + fldUploadFile.value); + } + }); var btnDelete - = $.INPUT({type: "button", value: "Delete this page"}); + = $.INPUT({type: "button", value: "Delete this page"}); + $(btnDelete).click(function () { + throw new Error("FIXME: not implemented yet"); + }); + var updateTRContent = function () { if (btnTypeRakka.checked) { $(trContent).find("th").text("Wiki source"); $(trContent).find("td").empty().append(fldRakkaSource); - $(trContent).show(); } else if (btnTypeCSS.checked) { $(trContent).find("th").text("CSS source"); $(trContent).find("td").empty().append(fldCSSSource); - $(trContent).show(); } else if (btnTypeBinary.checked) { $(trContent).find("th").text("File"); $(trContent).find("td").empty().append(fldUploadFile); - $(trContent).show(); - } - else { - $(trContent).hide(); } }; $(btnTypeRakka ).change(updateTRContent); @@ -102,49 +134,91 @@ Rakka.displayPageEditor = function ($place, pageName, oldRevision, defaultType, updateTRContent(); var pageEditor - = $.TABLE({className: "pageEditor"}, - $.TBODY({}, - $.TR({}, - $.TH({}, "Page name"), - $.TD({}, fldPageName) - ), - $.TR({}, - $.TH({}, "Page type"), - $.TD({}, - $.UL({}, - $.LI({}, - $.LABEL({}, - btnTypeRakka, - "Wiki page" - ) - ), - $.LI({}, - $.LABEL({}, - btnTypeCSS, - "Style sheet" - ) - ), - $.LI({}, - $.LABEL({}, - btnTypeBinary, - "Binary file" - ) - ) - ) - ) - ), - trContent, - $.TR({}, - $.TH({}), - $.TD({}, btnPreview, btnSubmit, btnDelete) - ) - ) - ); + = $.TABLE({className: "pageEditor"}, + $.TBODY({}, + $.TR({}, + $.TH({}, "Page name"), + $.TD({}, fldPageName) + ), + $.TR({}, + $.TH({}, "Page type"), + $.TD({}, + $.UL({}, + $.LI({}, + $.LABEL({}, + btnTypeRakka, + "Wiki page" + ) + ), + $.LI({}, + $.LABEL({}, + btnTypeCSS, + "Style sheet" + ) + ), + $.LI({}, + $.LABEL({}, + btnTypeBinary, + "Binary file" + ) + ) + ) + ) + ), + trContent, + $.TR({}, + $.TH({}), + $.TD({}, btnPreview, btnSubmit, btnDelete) + ) + ) + ); if (oldRevision == null || oldRevision == 0) { // 削除不可 $(btnDelete).hide(); } - $place.append(pageEditor); + $area.append(pageEditor); +}; + +Rakka.submitTextPage = function (baseURI, pageName, oldRevision, givenPageName, mimeType, text) { + var doc = document.implementation.createDocument( + "http://cielonegro.org/schema/Rakka/Page/1.0", "page", null); + + var page = doc.documentElement; + + if (oldRevision != null) { + // ページ書換時 + var updateInfo = doc.createElement("updateInfo"); + updateInfo.setAttribute("oldRevision", oldRevision); + + if (pageName != givenPageName) { + var move = doc.createElement("move"); + move.setAttribute("from", pageName); + updateInfo.appendChild(move); + } + + page.appendChild(updateInfo); + } + + if (0) { + // redirection + } + else { + page.setAttribute("type", mimeType); + + var textData = doc.createElement("textData"); + textData.appendChild( + doc.createTextNode(text)); + + page.appendChild(textData); + } + + $.ajax({ + type : "PUT", + url : baseURI + encodeURI(givenPageName), + contentType: "text/xml", + data : doc, + processData: false + }); }; diff --git a/js/jquery-1.2.1.js b/js/jquery-1.2.1.js new file mode 100644 index 0000000..244638c --- /dev/null +++ b/js/jquery-1.2.1.js @@ -0,0 +1,2992 @@ +(function(){ +/* + * jQuery 1.2.1 - New Wave Javascript + * + * Copyright (c) 2007 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2007-09-16 23:42:06 -0400 (Sun, 16 Sep 2007) $ + * $Rev: 3353 $ + */ + +// Map over jQuery in case of overwrite +if ( typeof jQuery != "undefined" ) + var _jQuery = jQuery; + +var jQuery = window.jQuery = function(selector, context) { + // If the context is a namespace object, return a new object + return this instanceof jQuery ? + this.init(selector, context) : + new jQuery(selector, context); +}; + +// Map over the $ in case of overwrite +if ( typeof $ != "undefined" ) + var _$ = $; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +jQuery.fn = jQuery.prototype = { + init: function(selector, context) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle HTML strings + if ( typeof selector == "string" ) { + var m = quickExpr.exec(selector); + if ( m && (m[1] || !context) ) { + // HANDLE: $(html) -> $(array) + if ( m[1] ) + selector = jQuery.clean( [ m[1] ], context ); + + // HANDLE: $("#id") + else { + var tmp = document.getElementById( m[3] ); + if ( tmp ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( tmp.id != m[3] ) + return jQuery().find( selector ); + else { + this[0] = tmp; + this.length = 1; + return this; + } + else + selector = []; + } + + // HANDLE: $(expr) + } else + return new jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction(selector) ) + return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( selector ); + + return this.setArray( + // HANDLE: $(array) + selector.constructor == Array && selector || + + // HANDLE: $(arraylike) + // Watch for when an array-like object is passed as the selector + (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + + // HANDLE: $(*) + [ selector ] ); + }, + + jquery: "1.2.1", + + size: function() { + return this.length; + }, + + length: 0, + + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[num]; + }, + + pushStack: function( a ) { + var ret = jQuery(a); + ret.prevObject = this; + return ret; + }, + + setArray: function( a ) { + this.length = 0; + Array.prototype.push.apply( this, a ); + return this; + }, + + each: function( fn, args ) { + return jQuery.each( this, fn, args ); + }, + + index: function( obj ) { + var pos = -1; + this.each(function(i){ + if ( this == obj ) pos = i; + }); + return pos; + }, + + attr: function( key, value, type ) { + var obj = key; + + // Look for the case where we're accessing a style value + if ( key.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined; + else { + obj = {}; + obj[ key ] = value; + } + + // Check to see if we're setting style values + return this.each(function(index){ + // Set all the styles + for ( var prop in obj ) + jQuery.attr( + type ? this.style : this, + prop, jQuery.prop(this, obj[prop], type, index, prop) + ); + }); + }, + + css: function( key, value ) { + return this.attr( key, value, "curCSS" ); + }, + + text: function(e) { + if ( typeof e != "object" && e != null ) + return this.empty().append( document.createTextNode( e ) ); + + var t = ""; + jQuery.each( e || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + t += this.nodeType != 1 ? + this.nodeValue : jQuery.fn.text([ this ]); + }); + }); + return t; + }, + + wrapAll: function(html) { + if ( this[0] ) + // The elements to wrap the target around + jQuery(html, this[0].ownerDocument) + .clone() + .insertBefore(this[0]) + .map(function(){ + var elem = this; + while ( elem.firstChild ) + elem = elem.firstChild; + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function(html) { + return this.each(function(){ + jQuery(this).contents().wrapAll(html); + }); + }, + + wrap: function(html) { + return this.each(function(){ + jQuery(this).wrapAll(html); + }); + }, + + append: function() { + return this.domManip(arguments, true, 1, function(a){ + this.appendChild( a ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, -1, function(a){ + this.insertBefore( a, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, 1, function(a){ + this.parentNode.insertBefore( a, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, -1, function(a){ + this.parentNode.insertBefore( a, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery([]); + }, + + find: function(t) { + var data = jQuery.map(this, function(a){ return jQuery.find(t,a); }); + return this.pushStack( /[^+>] [^+>]/.test( t ) || t.indexOf("..") > -1 ? + jQuery.unique( data ) : data ); + }, + + clone: function(events) { + // Do the clone + var ret = this.map(function(){ + return this.outerHTML ? jQuery(this.outerHTML)[0] : this.cloneNode(true); + }); + + // Need to set the expando to null on the cloned set if it exists + // removeData doesn't work here, IE removes it from the original as well + // this is primarily for IE but the data expando shouldn't be copied over in any browser + var clone = ret.find("*").andSelf().each(function(){ + if ( this[ expando ] != undefined ) + this[ expando ] = null; + }); + + // Copy the events from the original to the clone + if (events === true) + this.find("*").andSelf().each(function(i) { + var events = jQuery.data(this, "events"); + for ( var type in events ) + for ( var handler in events[type] ) + jQuery.event.add(clone[i], type, events[type][handler], events[type][handler].data); + }); + + // Return the cloned set + return ret; + }, + + filter: function(t) { + return this.pushStack( + jQuery.isFunction( t ) && + jQuery.grep(this, function(el, index){ + return t.apply(el, [index]); + }) || + + jQuery.multiFilter(t,this) ); + }, + + not: function(t) { + return this.pushStack( + t.constructor == String && + jQuery.multiFilter(t, this, true) || + + jQuery.grep(this, function(a) { + return ( t.constructor == Array || t.jquery ) + ? jQuery.inArray( a, t ) < 0 + : a != t; + }) + ); + }, + + add: function(t) { + return this.pushStack( jQuery.merge( + this.get(), + t.constructor == String ? + jQuery(t).get() : + t.length != undefined && (!t.nodeName || jQuery.nodeName(t, "form")) ? + t : [t] ) + ); + }, + + is: function(expr) { + return expr ? jQuery.multiFilter(expr,this).length > 0 : false; + }, + + hasClass: function(expr) { + return this.is("." + expr); + }, + + val: function( val ) { + if ( val == undefined ) { + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName(elem, "select") ) { + var index = elem.selectedIndex, + a = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[i]; + if ( option.selected ) { + // Get the specifc value for the option + var val = jQuery.browser.msie && !option.attributes["value"].specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return val; + + // Multi-Selects return an array + a.push(val); + } + } + + return a; + + // Everything else, we just grab the value + } else + return this[0].value.replace(/\r/g, ""); + } + } else + return this.each(function(){ + if ( val.constructor == Array && /radio|checkbox/.test(this.type) ) + this.checked = (jQuery.inArray(this.value, val) >= 0 || + jQuery.inArray(this.name, val) >= 0); + else if ( jQuery.nodeName(this, "select") ) { + var tmp = val.constructor == Array ? val : [val]; + + jQuery("option", this).each(function(){ + this.selected = (jQuery.inArray(this.value, tmp) >= 0 || + jQuery.inArray(this.text, tmp) >= 0); + }); + + if ( !tmp.length ) + this.selectedIndex = -1; + } else + this.value = val; + }); + }, + + html: function( val ) { + return val == undefined ? + ( this.length ? this[0].innerHTML : null ) : + this.empty().append( val ); + }, + + replaceWith: function( val ) { + return this.after( val ).remove(); + }, + + eq: function(i){ + return this.slice(i, i+1); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function(fn) { + return this.pushStack(jQuery.map( this, function(elem,i){ + return fn.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function(args, table, dir, fn) { + var clone = this.length > 1, a; + + return this.each(function(){ + if ( !a ) { + a = jQuery.clean(args, this.ownerDocument); + if ( dir < 0 ) + a.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody")); + + jQuery.each( a, function(){ + var elem = clone ? this.cloneNode(true) : this; + if ( !evalScript(0, elem) ) + fn.call( obj, elem ); + }); + }); + } +}; + +function evalScript(i, elem){ + var script = jQuery.nodeName(elem, "script"); + + if ( script ) { + if ( elem.src ) + jQuery.ajax({ url: elem.src, async: false, dataType: "script" }); + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild(elem); + + } else if ( elem.nodeType == 1 ) + jQuery("script", elem).each(evalScript); + + return script; +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + } + + // extend jQuery itself if only one argument is passed + if ( al == 1 ) { + target = this; + a = 0; + } + + var prop; + + for ( ; a < al; a++ ) + // Only deal with non-null/undefined values + if ( (prop = arguments[a]) != null ) + // Extend the base object + for ( var i in prop ) { + // Prevent never-ending loop + if ( target == prop[i] ) + continue; + + // Recurse if we're merging object values + if ( deep && typeof prop[i] == 'object' && target[i] ) + jQuery.extend( target[i], prop[i] ); + + // Don't bring in undefined values + else if ( prop[i] != undefined ) + target[i] = prop[i]; + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, win = {}; + +jQuery.extend({ + noConflict: function(deep) { + window.$ = _$; + if ( deep ) + window.jQuery = _jQuery; + return jQuery; + }, + + // This may seem like some crazy code, but trust me when I say that this + // is the only cross-browser way to do this. --John + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a XML document + isXMLDoc: function(elem) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + // Evaluates Async. in Safari 2 :-( + globalEval: function( data ) { + data = jQuery.trim( data ); + if ( data ) { + if ( window.execScript ) + window.execScript( data ); + else if ( jQuery.browser.safari ) + // safari doesn't provide a synchronous global eval + window.setTimeout( data, 0 ); + else + eval.call( window, data ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? win : elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? jQuery.cache[ id ][ name ] : id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? win : elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + for ( name in jQuery.cache[ id ] ) break; + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( obj, fn, args ) { + if ( args ) { + if ( obj.length == undefined ) + for ( var i in obj ) + fn.apply( obj[i], args ); + else + for ( var i = 0, ol = obj.length; i < ol; i++ ) + if ( fn.apply( obj[i], args ) === false ) break; + + // A special, fast, case for the most common use of each + } else { + if ( obj.length == undefined ) + for ( var i in obj ) + fn.call( obj[i], i, obj[i] ); + else + for ( var i = 0, ol = obj.length, val = obj[0]; + i < ol && fn.call(val,i,val) !== false; val = obj[++i] ){} + } + + return obj; + }, + + prop: function(elem, value, type, index, prop){ + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, [index] ); + + // exclude the following css properties to add px + var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, c ){ + jQuery.each( (c || "").split(/\s+/), function(i, cur){ + if ( !jQuery.className.has( elem.className, cur ) ) + elem.className += ( elem.className ? " " : "" ) + cur; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, c ){ + elem.className = c != undefined ? + jQuery.grep( elem.className.split(/\s+/), function(cur){ + return !jQuery.className.has( c, cur ); + }).join(" ") : ""; + }, + + // internal only, use is(".class") + has: function( t, c ) { + return jQuery.inArray( c, (t.className || t).toString().split(/\s+/) ) > -1; + } + }, + + swap: function(e,o,f) { + for ( var i in o ) { + e.style["old"+i] = e.style[i]; + e.style[i] = o[i]; + } + f.apply( e, [] ); + for ( var i in o ) + e.style[i] = e.style["old"+i]; + }, + + css: function(e,p) { + if ( p == "height" || p == "width" ) { + var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; + + jQuery.each( d, function(){ + old["padding" + this] = 0; + old["border" + this + "Width"] = 0; + }); + + jQuery.swap( e, old, function() { + if ( jQuery(e).is(':visible') ) { + oHeight = e.offsetHeight; + oWidth = e.offsetWidth; + } else { + e = jQuery(e.cloneNode(true)) + .find(":radio").removeAttr("checked").end() + .css({ + visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0" + }).appendTo(e.parentNode)[0]; + + var parPos = jQuery.css(e.parentNode,"position") || "static"; + if ( parPos == "static" ) + e.parentNode.style.position = "relative"; + + oHeight = e.clientHeight; + oWidth = e.clientWidth; + + if ( parPos == "static" ) + e.parentNode.style.position = "static"; + + e.parentNode.removeChild(e); + } + }); + + return p == "height" ? oHeight : oWidth; + } + + return jQuery.curCSS( e, p ); + }, + + curCSS: function(elem, prop, force) { + var ret, stack = [], swap = []; + + // A helper method for determining if an element's values are broken + function color(a){ + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle(a,null); + return !ret || ret.getPropertyValue("color") == ""; + } + + if (prop == "opacity" && jQuery.browser.msie) { + ret = jQuery.attr(elem.style, "opacity"); + return ret == "" ? "1" : ret; + } + + if (prop.match(/float/i)) + prop = styleFloat; + + if (!force && elem.style[prop]) + ret = elem.style[prop]; + + else if (document.defaultView && document.defaultView.getComputedStyle) { + + if (prop.match(/float/i)) + prop = "float"; + + prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); + var cur = document.defaultView.getComputedStyle(elem, null); + + if ( cur && !color(elem) ) + ret = cur.getPropertyValue(prop); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( a = 0; a < stack.length; a++ ) + if ( color(stack[a]) ) { + swap[a] = stack[a].style.display; + stack[a].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = prop == "display" && swap[stack.length-1] != null ? + "none" : + document.defaultView.getComputedStyle(elem,null).getPropertyValue(prop) || ""; + + // Finally, revert the display styles back + for ( a = 0; a < swap.length; a++ ) + if ( swap[a] != null ) + stack[a].style.display = swap[a]; + } + + if ( prop == "opacity" && ret == "" ) + ret = "1"; + + } else if (elem.currentStyle) { + var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}); + ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test(ret) && /^\d/.test(ret) ) { + var style = elem.style.left; + var runtimeStyle = elem.runtimeStyle.left; + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function(a, doc) { + var r = []; + doc = doc || document; + + jQuery.each( a, function(i,arg){ + if ( !arg ) return; + + if ( arg.constructor == Number ) + arg = arg.toString(); + + // Convert html string into DOM nodes + if ( typeof arg == "string" ) { + // Fix "XHTML"-style tags in all browsers + arg = arg.replace(/(<(\w+)[^>]*?)\/>/g, function(m, all, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i)? m : all+">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var s = jQuery.trim(arg).toLowerCase(), div = doc.createElement("div"), tb = []; + + var wrap = + // option or optgroup + !s.indexOf("", ""] || + + !s.indexOf("", ""] || + + s.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [1, "", "
"] || + + !s.indexOf("", ""] || + + // matched above + (!s.indexOf("", ""] || + + !s.indexOf("", ""] || + + // IE can't serialize and