      1 /*
      2  * $ URIs @VERSION
      3  *
      4  * Copyright (c) 2008,2009 Jeni Tennison
      5  * Licensed under the MIT (MIT-LICENSE.txt)
      6  *
      7  */
      8 /**
      9  * @fileOverview $ URIs
     10  * @author <a href="mailto:jeni@jenitennison.com">Jeni Tennison</a>
     11  * @copyright (c) 2008,2009 Jeni Tennison
     12  * @license MIT license (MIT-LICENSE.txt)
     13  * @version 1.0
     14  */
     15 /**
     16  * @class
     17  * @name jQuery
     18  * @exports $ as jQuery
     19  * @description rdfQuery is a <a href="http://jquery.com/">jQuery</a> plugin. The only fields and methods listed here are those that come as part of the rdfQuery library.
     20  */
     21 (function ($) {
     22
     23   var
     24     mem = {},
     25     uriRegex = /^(([a-z][\-a-z0-9+\.]*):)?(\/\/([^\/?#]+))?([^?#]*)?(\?([^#]*))?(#(.*))?$/i,
     26     docURI,
     27
     28     parseURI = function (u) {
     29       var m = u.match(uriRegex);
     30       if (m === null) {
     31         throw "Malformed URI: " + u;
     32       }
     33       return {
     34         scheme: m[1] ? m[2].toLowerCase() : undefined,
     35         authority: m[3] ? m[4] : undefined,
     36         path: m[5] || '',
     37         query: m[6] ? m[7] : undefined,
     38         fragment: m[8] ? m[9] : undefined
     39       };
     40     },
     41
     42     removeDotSegments = function (u) {
     43       var r = '', m = [];
     44       if (/\./.test(u)) {
     45         while (u !== undefined && u !== '') {
     46           if (u === '.' || u === '..') {
     47             u = '';
     48           } else if (/^\.\.\//.test(u)) { // starts with ../
     49             u = u.substring(3);
     50           } else if (/^\.\//.test(u)) { // starts with ./
     51             u = u.substring(2);
     52           } else if (/^\/\.(\/|$)/.test(u)) { // starts with /./ or consists of /.
     53             u = '/' + u.substring(3);
     54           } else if (/^\/\.\.(\/|$)/.test(u)) { // starts with /../ or consists of /..
     55             u = '/' + u.substring(4);
     56             r = r.replace(/\/?[^\/]+$/, '');
     57           } else {
     58             m = u.match(/^(\/?[^\/]*)(\/.*)?$/);
     59             u = m[2];
     60             r = r + m[1];
     61           }
     62         }
     63         return r;
     64       } else {
     65         return u;
     66       }
     67     },
     68
     69     merge = function (b, r) {
     70       if (b.authority !== '' && (b.path === undefined || b.path === '')) {
     71         return '/' + r;
     72       } else {
     73         return b.path.replace(/[^\/]+$/, '') + r;
     74       }
     75     };
     76
     77   /**
     78    * Creates a new jQuery.uri object. This should be invoked as a method rather than constructed using new.
     79    * @class Represents a URI
     80    * @param {String} [relative='']
     81    * @param {String|jQuery.uri} [base] Defaults to the base URI of the page
     82    * @returns {jQuery.uri} The new jQuery.uri object.
     83    * @example uri = jQuery.uri('/my/file.html');
     84    */
     85   $.uri = function (relative, base) {
     86     var uri;
     87     relative = relative || '';
     88     if (mem[relative]) {
     89       return mem[relative];
     90     }
     91     base = base || $.uri.base();
     92     if (typeof base === 'string') {
     93       base = $.uri.absolute(base);
     94     }
     95     uri = new $.uri.fn.init(relative, base);
     96     if (mem[uri]) {
     97       return mem[uri];
     98     } else {
     99       mem[uri] = uri;
    100       return uri;
    101     }
    102   };
    103
    104   $.uri.fn = $.uri.prototype = {
    105     /**
    106      * The scheme used in the URI
    107      * @type String
    108      */
    109     scheme: undefined,
    110     /**
    111      * The authority used in the URI
    112      * @type String
    113      */
    114     authority: undefined,
    115     /**
    116      * The path used in the URI
    117      * @type String
    118      */
    119     path: undefined,
    120     /**
    121      * The query part of the URI
    122      * @type String
    123      */
    124     query: undefined,
    125     /**
    126      * The fragment part of the URI
    127      * @type String
    128      */
    129     fragment: undefined,
    130
    131     init: function (relative, base) {
    132       var r = {};
    133       base = base || {};
    134       $.extend(this, parseURI(relative));
    135       if (this.scheme === undefined) {
    136         this.scheme = base.scheme;
    137         if (this.authority !== undefined) {
    138           this.path = removeDotSegments(this.path);
    139         } else {
    140           this.authority = base.authority;
    141           if (this.path === '') {
    142             this.path = base.path;
    143             if (this.query === undefined) {
    144               this.query = base.query;
    145             }
    146           } else {
    147             if (!/^\//.test(this.path)) {
    148               this.path = merge(base, this.path);
    149             }
    150             this.path = removeDotSegments(this.path);
    151           }
    152         }
    153       }
    154       if (this.scheme === undefined) {
    155         throw "Malformed URI: URI is not an absolute URI and no base supplied: " + relative;
    156       }
    157       return this;
    158     },
    159
    160     /**
    161      * Resolves a relative URI relative to this URI
    162      * @param {String} relative
    163      * @returns jQuery.uri
    164      */
    165     resolve: function (relative) {
    166       return $.uri(relative, this);
    167     },
    168
    169     /**
    170      * Creates a relative URI giving the path from this URI to the absolute URI passed as a parameter
    171      * @param {String|jQuery.uri} absolute
    172      * @returns String
    173      */
    174     relative: function (absolute) {
    175       var aPath, bPath, i = 0, j, resultPath = [], result = '';
    176       if (typeof absolute === 'string') {
    177         absolute = $.uri(absolute, {});
    178       }
    179       if (absolute.scheme !== this.scheme ||
    180           absolute.authority !== this.authority) {
    181         return absolute.toString();
    182       }
    183       if (absolute.path !== this.path) {
    184         aPath = absolute.path.split('/');
    185         bPath = this.path.split('/');
    186         if (aPath[1] !== bPath[1]) {
    187           result = absolute.path;
    188         } else {
    189           while (aPath[i] === bPath[i]) {
    190             i += 1;
    191           }
    192           j = i;
    193           for (; i < bPath.length - 1; i += 1) {
    194             resultPath.push('..');
    195           }
    196           for (; j < aPath.length; j += 1) {
    197             resultPath.push(aPath[j]);
    198           }
    199           result = resultPath.join('/');
    200         }
    201         result = absolute.query === undefined ? result : result + '?' + absolute.query;
    202         result = absolute.fragment === undefined ? result : result + '#' + absolute.fragment;
    203         return result;
    204       }
    205       if (absolute.query !== undefined && absolute.query !== this.query) {
    206         return '?' + absolute.query + (absolute.fragment === undefined ? '' : '#' + absolute.fragment);
    207       }
    208       if (absolute.fragment !== undefined && absolute.fragment !== this.fragment) {
    209         return '#' + absolute.fragment;
    210       }
    211       return '';
    212     },
    213
    214     /**
    215      * Returns the URI as an absolute string
    216      * @returns String
    217      */
    218     toString: function () {
    219       var result = '';
    220       if (this._string) {
    221         return this._string;
    222       } else {
    223         result = this.scheme === undefined ? result : (result + this.scheme + ':');
    224         result = this.authority === undefined ? result : (result + '//' + this.authority);
    225         result = result + this.path;
    226         result = this.query === undefined ? result : (result + '?' + this.query);
    227         result = this.fragment === undefined ? result : (result + '#' + this.fragment);
    228         this._string = result;
    229         return result;
    230       }
    231     }
    232
    233   };
    234
    235   $.uri.fn.init.prototype = $.uri.fn;
    236
    237   /**
    238    * Creates a {@link jQuery.uri} from a known-to-be-absolute URI
    239    * @param {String}
    240    * @returns {jQuery.uri}
    241    */
    242   $.uri.absolute = function (uri) {
    243     return $.uri(uri, {});
    244   };
    245
    246   /**
    247    * Creates a {@link jQuery.uri} from a relative URI and an optional base URI
    248    * @returns {jQuery.uri}
    249    * @see jQuery.uri
    250    */
    251   $.uri.resolve = function (relative, base) {
    252     return $.uri(relative, base);
    253   };
    254
    255   /**
    256    * Creates a string giving the relative path from a base URI to an absolute URI
    257    * @param {String} absolute
    258    * @param {String} base
    259    * @returns {String}
    260    */
    261   $.uri.relative = function (absolute, base) {
    262     return $.uri(base, {}).relative(absolute);
    263   };
    264
    265   /**
    266    * Returns the base URI of the page
    267    * @returns {jQuery.uri}
    268    */
    269   $.uri.base = function () {
    270     return $(document).base();
    271   };
    272
    273   /**
    274    * Returns the base URI in scope for the first selected element
    275    * @methodOf jQuery#
    276    * @name jQuery#base
    277    * @returns {jQuery.uri}
    278    * @example baseURI = $('img').base();
    279    */
    280   $.fn.base = function () {
    281     var base = $(this).parents().andSelf().find('base').attr('href'),
    282       doc = $(this)[0].ownerDocument || document,
    283       docURI = $.uri.absolute(doc.location === null ? document.location.href : doc.location.href);
    284     return base === undefined ? docURI : $.uri(base, docURI);
    285   };
    286
    287 })(jQuery);
    288