1 /*
  2  * jQuery CURIE @VERSION
  3  * 
  4  * Copyright (c) 2008,2009 Jeni Tennison
  5  * Licensed under the MIT (MIT-LICENSE.txt)
  6  *
  7  * Depends:
  8  *  jquery.uri.js
  9  */
 10 /**
 11  * @fileOverview XML Namespace processing
 12  * @author <a href="mailto:jeni@jenitennison.com">Jeni Tennison</a>
 13  * @copyright (c) 2008,2009 Jeni Tennison
 14  * @license MIT license (MIT-LICENSE.txt)
 15  * @version 1.0
 16  * @requires jquery.uri.js
 17  */
 18 
 19 /*global jQuery */
 20 (function ($) {
 21 
 22   var 
 23     xmlNs = 'http://www.w3.org/XML/1998/namespace',
 24     xmlnsNs = 'http://www.w3.org/2000/xmlns/',
 25     
 26     xmlnsRegex = /\sxmlns(?::([^ =]+))?\s*=\s*(?:"([^"]*)"|'([^']*)')/g,
 27     
 28     ncNameChar = '[-A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF\.0-9\u00B7\u0300-\u036F\u203F-\u2040]',
 29     ncNameStartChar = '[\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029_]',
 30     ncNameRegex = new RegExp('^' + ncNameStartChar + ncNameChar + '*$');
 31     
 32 
 33 /**
 34  * Returns the namespaces declared in the scope of the first selected element, or
 35  * adds a namespace declaration to all selected elements. Pass in no parameters
 36  * to return all namespaces bindings on the first selected element. If only 
 37  * the prefix parameter is specified, this method will return the namespace
 38  * URI that is bound to the specified prefix on the first element in the selection
 39  * If the prefix and uri parameters are both specified, this method will
 40  * add the binding of the specified prefix and namespace URI to all elements
 41  * in the selection.
 42  * @methodOf jQuery#
 43  * @name jQuery#xmlns
 44  * @param {String} [prefix] Restricts the namespaces returned to only the namespace with the specified namespace prefix.
 45  * @param {String|jQuery.uri} [uri] Adds a namespace declaration to the selected elements that maps the specified prefix to the specified namespace.
 46  * @param {Object} [inherited] A map of inherited namespace bindings.
 47  * @returns {Object|jQuery.uri|jQuery}
 48  * @example 
 49  * // Retrieve all of the namespace bindings on the HTML document element
 50  * var nsMap = $('html').xmlns();
 51  * @example
 52  * // Retrieve the namespace URI mapped to the 'dc' prefix on the HTML document element
 53  * var dcNamespace = $('html').xmlns('dc');
 54  * @example
 55  * // Create a namespace declaration that binds the 'dc' prefix to the URI 'http://purl.org/dc/elements/1.1/'
 56  * $('html').xmlns('dc', 'http://purl.org/dc/elements/1.1/');
 57  */
 58   $.fn.xmlns = function (prefix, uri, inherited) {
 59     var 
 60       elem = this.eq(0),
 61       ns = elem.data('xmlns'),
 62       e = elem[0], a, p, i,
 63       decl = prefix ? 'xmlns:' + prefix : 'xmlns',
 64       value,
 65       tag, found = false;
 66     if (uri === undefined) {
 67       if (prefix === undefined) { // get the in-scope declarations on the first element
 68         if (!ns) {
 69           ns = {
 70 //            xml: $.uri(xmlNs)
 71           };
 72           if (e.attributes && e.attributes.getNamedItemNS) {
 73             for (i = 0; i < e.attributes.length; i += 1) {
 74               a = e.attributes[i];
 75               if (/^xmlns(:(.+))?$/.test(a.nodeName)) {
 76                 prefix = /^xmlns(:(.+))?$/.exec(a.nodeName)[2] || '';
 77                 value = a.nodeValue;
 78                 if (prefix === '' || (value !== '' && value !== xmlNs && value !== xmlnsNs && ncNameRegex.test(prefix) && prefix !== 'xml' && prefix !== 'xmlns')) {
 79                   ns[prefix] = $.uri(a.nodeValue);
 80                   found = true;
 81                 }
 82               }
 83             }
 84           } else {
 85             tag = /<[^>]+>/.exec(e.outerHTML);
 86             a = xmlnsRegex.exec(tag);
 87             while (a !== null) {
 88               prefix = a[1] || '';
 89               value = a[2] || a[3];
 90               if (prefix === '' || (value !== '' && value !== xmlNs && value !== xmlnsNs && ncNameRegex.test(prefix) && prefix !== 'xml' && prefix !== 'xmlns')) {
 91                 ns[prefix] = $.uri(a[2] || a[3]);
 92                 found = true;
 93               }
 94               a = xmlnsRegex.exec(tag);
 95             }
 96             xmlnsRegex.lastIndex = 0;
 97           }
 98           inherited = inherited || (e.parentNode.nodeType === 1 ? elem.parent().xmlns() : {});
 99           ns = found ? $.extend({}, inherited, ns) : inherited;
100           elem.data('xmlns', ns);
101         }
102         return ns;
103       } else if (typeof prefix === 'object') { // set the prefix mappings defined in the object
104         for (p in prefix) {
105           if (typeof prefix[p] === 'string' && ncNameRegex.test(p)) {
106             this.xmlns(p, prefix[p]);
107           }
108         }
109         this.find('*').andSelf().removeData('xmlns');
110         return this;
111       } else { // get the in-scope declaration associated with this prefix on the first element
112         if (!ns) {
113           ns = elem.xmlns();
114         }
115         return ns[prefix];
116       }
117     } else { // set
118       this.find('*').andSelf().removeData('xmlns');
119       return this.attr(decl, uri);
120     }
121   };
122 
123 /**
124  * Removes one or more XML namespace bindings from the selected elements.
125  * @methodOf jQuery#
126  * @name jQuery#removeXmlns
127  * @param {String|Object|String[]} prefix The prefix(es) of the XML namespace bindings that are to be removed from the selected elements.
128  * @returns {jQuery} The original jQuery object.
129  * @example
130  * // Remove the foaf namespace declaration from the body element:
131  * $('body').removeXmlns('foaf');
132  * @example
133  * // Remove the foo and bar namespace declarations from all h2 elements
134  * $('h2').removeXmlns(['foo', 'bar']);
135  * @example
136  * // Remove the foo and bar namespace declarations from all h2 elements
137  * var namespaces = { foo : 'http://www.example.org/foo', bar : 'http://www.example.org/bar' };
138  * $('h2').removeXmlns(namespaces);
139  */
140   $.fn.removeXmlns = function (prefix) {
141     var decl, p, i;
142     if (typeof prefix === 'object') {
143       if (prefix.length === undefined) { // assume an object representing namespaces
144         for (p in prefix) {
145           if (typeof prefix[p] === 'string') {
146             this.removeXmlns(p);
147           }
148         }
149       } else { // it's an array
150         for (i = 0; i < prefix.length; i += 1) {
151           this.removeXmlns(prefix[i]);
152         }
153       }
154     } else {
155       decl = prefix ? 'xmlns:' + prefix : 'xmlns';
156       this.removeAttr(decl);
157     }
158     this.find('*').andSelf().removeData('xmlns');
159     return this;
160   };
161 
162   $.fn.qname = function (name) {
163     var m, prefix, namespace;
164     if (name === undefined) {
165       if (this[0].outerHTML === undefined) {
166         name = this[0].nodeName.toLowerCase();
167       } else {
168         name = /<([^ >]+)/.exec(this[0].outerHTML)[1].toLowerCase();
169       }
170     }
171     if (name === '?xml:namespace') {
172       // there's a prefix on the name, but we can't get at it
173       throw "XMLinHTML: Unable to get the prefix to resolve the name of this element";
174     }
175     m = /^(([^:]+):)?([^:]+)$/.exec(name);
176     prefix = m[2] || '';
177     namespace = this.xmlns(prefix);
178     if (namespace === undefined && prefix !== '') {
179       throw "MalformedQName: The prefix " + prefix + " is not declared";
180     }
181     return {
182       namespace: namespace,
183       localPart: m[3],
184       prefix: prefix,
185       name: name
186     };
187   };
188 
189 })(jQuery);
190