mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-04 15:09:16 +02:00
updated polymer example, added urljs (no implemented)
This commit is contained in:
parent
8f06e86d9c
commit
150b6b6050
10 changed files with 2635 additions and 4 deletions
1527
examples/polymer/epub-reader.html
Normal file
1527
examples/polymer/epub-reader.html
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
||||||
<script src="../../../build/epub.min.js"></script>
|
<script src="../../../build/epub.min.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<!-- <script type="text/javascript">
|
||||||
//-- Setups
|
//-- Setups
|
||||||
</script>
|
</script> -->
|
||||||
|
|
||||||
<polymer-element name="epub-js" attributes="src chapter width height restore spreads">
|
<polymer-element name="epub-js" attributes="src chapter width height restore spreads">
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<script src="../../libs/polymer/polymer.min.js"></script>
|
<script src="../../libs/polymer/polymer.min.js"></script>
|
||||||
|
|
||||||
<link rel="import" href="epub-reader/epub-reader.html">
|
<!-- // <script src="../../build/epub.min.js"></script> -->
|
||||||
|
|
||||||
|
<!-- <link rel="import" href="epub-reader/epub-reader.html"> -->
|
||||||
|
<link rel="import" href="epub-reader.html">
|
||||||
|
|
||||||
<link rel="stylesheet" href="../../demo/css/normalize.css">
|
<link rel="stylesheet" href="../../demo/css/normalize.css">
|
||||||
<style>
|
<style>
|
||||||
|
|
2
examples/polymer/vulcanize/.gitignore
vendored
Executable file
2
examples/polymer/vulcanize/.gitignore
vendored
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
output.html
|
||||||
|
node_modules
|
86
examples/polymer/vulcanize/README.md
Executable file
86
examples/polymer/vulcanize/README.md
Executable file
|
@ -0,0 +1,86 @@
|
||||||
|
# Vulcan
|
||||||
|
|
||||||
|
### Concatenate a set of Web Components into one file
|
||||||
|
|
||||||
|
>Named for the [Vulcanization](http://en.wikipedia.org/wiki/Vulcanization) process that turns polymers into more durable
|
||||||
|
materials.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
- Install the node dependencies with `npm install`
|
||||||
|
- Depends on [cheerio](https://github.com/MatthewMueller/cheerio) and [nopt](https://github.com/isaacs/nopt)
|
||||||
|
- Give some input html files with the `--input` or `-i` flags
|
||||||
|
- Input html should have `<link rel="import">` tags
|
||||||
|
- Specify an output html file with `--output` or `-o`
|
||||||
|
- Defaults to `output.html` in the current directory
|
||||||
|
- URL paths are adjusted for the new output location automatically (execpt ones set in Javascript)
|
||||||
|
- Once finished, link the final output html into your app page with `<link rel="import">`.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Say we have three html files: `index.html`, `x-app.html`, and `x-dep.html`.
|
||||||
|
|
||||||
|
index.html:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="import" href="app.html">
|
||||||
|
<x-app></x-app>
|
||||||
|
```
|
||||||
|
|
||||||
|
app.html:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="import" href="path/to/x-dep.html">
|
||||||
|
<polymer-element name="x-app">
|
||||||
|
<template>
|
||||||
|
<x-dep></x-dep>
|
||||||
|
</template>
|
||||||
|
<script>Polymer('x-app')</script>
|
||||||
|
</polymer-element>
|
||||||
|
```
|
||||||
|
|
||||||
|
x-dep.html:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<polymer-element name="x-dep">
|
||||||
|
<template>
|
||||||
|
<img src="x-dep-icon.jpg">
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer('x-dep');
|
||||||
|
</script>
|
||||||
|
</polymer-element>
|
||||||
|
```
|
||||||
|
|
||||||
|
Running vulcan on `index.html`, and specifying `build.html` as the output:
|
||||||
|
|
||||||
|
node vulcan.js -i index.html -o build.html
|
||||||
|
|
||||||
|
Will result in `build.html` that appears as so:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<polymer-element name="x-dep" assetpath="path/to/">
|
||||||
|
<template>
|
||||||
|
<img src="path/to/x-dep-icon.jpg">
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer('x-dep');
|
||||||
|
</script>
|
||||||
|
</polymer-element>
|
||||||
|
<polymer-element name="x-app" assetpath="">
|
||||||
|
<template>
|
||||||
|
<x-dep></x-dep>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer('x-app');
|
||||||
|
</script>
|
||||||
|
</polymer-element>
|
||||||
|
```
|
||||||
|
|
||||||
|
To use this, make `build.html` the only import in `index.html`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="import" href="build.html">
|
||||||
|
<x-app></x-app>
|
||||||
|
```
|
18
examples/polymer/vulcanize/package.json
Executable file
18
examples/polymer/vulcanize/package.json
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "vulcanize",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Concat all the components into one output file, with dependencies in the proper order",
|
||||||
|
"main": "vulcan.js",
|
||||||
|
"dependencies": {
|
||||||
|
"cheerio": "~0.11.0",
|
||||||
|
"nopt": "~2.1.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": "",
|
||||||
|
"author": "",
|
||||||
|
"license": "BSD",
|
||||||
|
"readmeFilename": "README.md"
|
||||||
|
}
|
183
examples/polymer/vulcanize/vulcan.js
Executable file
183
examples/polymer/vulcanize/vulcan.js
Executable file
|
@ -0,0 +1,183 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var cheerio = require('cheerio');
|
||||||
|
var nopt = require('nopt');
|
||||||
|
|
||||||
|
var options = nopt(
|
||||||
|
{
|
||||||
|
'output': path,
|
||||||
|
'input': [path, Array],
|
||||||
|
'verbose': Boolean
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'o': ['--output'],
|
||||||
|
'i': ['--input'],
|
||||||
|
'v': ['--verbose']
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!options.input) {
|
||||||
|
console.error('No input files given');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.output) {
|
||||||
|
console.warn('Default output to output.html');
|
||||||
|
options.output = path.resolve('output.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputDir = path.dirname(options.output);
|
||||||
|
|
||||||
|
var IMPORTS = 'link[rel="import"][href]';
|
||||||
|
var ELEMENTS = 'polymer-element';
|
||||||
|
var URL_ATTR = ['href', 'src', 'action', 'style'];
|
||||||
|
var URL_ATTR_SEL = '[' + URL_ATTR.join('],[') + ']';
|
||||||
|
var ABS_URL = /(^data:)|(^http[s]?:)|(^\/)/;
|
||||||
|
var URL = /url\([^)]*\)/g;
|
||||||
|
var URL_TEMPLATE = '{{.*}}';
|
||||||
|
|
||||||
|
function concatElement(dir, output, e) {
|
||||||
|
e = resolveElementPaths(dir, output, e);
|
||||||
|
buffer.push(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveElementPaths(input, output, element) {
|
||||||
|
var $ = cheerio.load(element);
|
||||||
|
resolvePaths(input, output, $);
|
||||||
|
return $.html(ELEMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePaths(input, output, $) {
|
||||||
|
// resolve attributes
|
||||||
|
$(URL_ATTR_SEL).each(function() {
|
||||||
|
var val;
|
||||||
|
URL_ATTR.forEach(function(a) {
|
||||||
|
if (val = this.attr(a)) {
|
||||||
|
if (val.search(URL_TEMPLATE) < 0) {
|
||||||
|
if (a === 'style') {
|
||||||
|
this.attr(a, rewriteURL(input, output, val));
|
||||||
|
} else {
|
||||||
|
this.attr(a, rewriteRelPath(input, output, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
// resolve style elements
|
||||||
|
$('style').each(function() {
|
||||||
|
var val = this.html();
|
||||||
|
this.html(rewriteURL(input, output, val));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewriteRelPath(inputPath, outputPath, rel) {
|
||||||
|
if (ABS_URL.test(rel)) {
|
||||||
|
return rel;
|
||||||
|
}
|
||||||
|
var abs = path.resolve(inputPath, rel);
|
||||||
|
return path.relative(outputPath, abs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewriteURL(inputPath, outputPath, cssText) {
|
||||||
|
return cssText.replace(URL, function(match) {
|
||||||
|
var path = match.replace(/["']/g, "").slice(4, -1);
|
||||||
|
path = rewriteRelPath(inputPath, outputPath, path);
|
||||||
|
return 'url(' + path + ')';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDocument(docname) {
|
||||||
|
if (options.verbose) {
|
||||||
|
console.log('Reading:', docname);
|
||||||
|
}
|
||||||
|
var content = fs.readFileSync(docname, 'utf8');
|
||||||
|
return cheerio.load(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractImports($, dir) {
|
||||||
|
var hrefs = $(IMPORTS).map(function(){ return this.attr('href') });
|
||||||
|
return hrefs.map(function(h) { return path.resolve(dir, h) });
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractScripts($, assetPath) {
|
||||||
|
var scripts = $.root().children('script');
|
||||||
|
|
||||||
|
scripts.each(function(){
|
||||||
|
var src = this.attr('src');
|
||||||
|
|
||||||
|
if(src) {
|
||||||
|
this.attr('src', path.join(assetPath, src));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return scripts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractElements($, assetPath) {
|
||||||
|
return $(ELEMENTS).map(function(i, e){ this.attr('assetpath', assetPath); return $.html(e) });
|
||||||
|
}
|
||||||
|
|
||||||
|
function concat(filename) {
|
||||||
|
if (!read[filename]) {
|
||||||
|
read[filename] = true;
|
||||||
|
var $ = readDocument(filename);
|
||||||
|
var dir = path.dirname(filename);
|
||||||
|
var assetPath = path.relative(outputDir, dir);
|
||||||
|
var links = extractImports($, dir);
|
||||||
|
resolve(filename, links);
|
||||||
|
|
||||||
|
var scripts = extractScripts($, assetPath);
|
||||||
|
|
||||||
|
scripts.each(function(){
|
||||||
|
buffer.push($.html(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var es = extractElements($, assetPath);
|
||||||
|
es.forEach(concatElement.bind(this, dir, outputDir));
|
||||||
|
} else {
|
||||||
|
if (options.verbose) {
|
||||||
|
console.log('Dependency deduplicated');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve(inName, inDependencies) {
|
||||||
|
if (inDependencies.length > 0) {
|
||||||
|
if (options.verbose) {
|
||||||
|
console.log('Dependencies:', inDependencies);
|
||||||
|
}
|
||||||
|
inDependencies.forEach(concat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// monkey patch addResolvePath for build
|
||||||
|
var monkeyPatch = function(proto, element) {
|
||||||
|
var assetPath = element.getAttribute('assetpath');
|
||||||
|
var url = HTMLImports.getDocumentUrl(element.ownerDocument) || '';
|
||||||
|
if (url) {
|
||||||
|
var parts = url.split('/');
|
||||||
|
parts.pop();
|
||||||
|
if (assetPath) {
|
||||||
|
parts.push(assetPath);
|
||||||
|
}
|
||||||
|
parts.push('');
|
||||||
|
url = parts.join('/');
|
||||||
|
}
|
||||||
|
proto.resolvePath = function(path) {
|
||||||
|
return url + path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var buffer = [
|
||||||
|
'<!-- Monkey Patch addResolvePath to use assetpath -->',
|
||||||
|
'<script>Polymer.addResolvePath = ' + monkeyPatch + '</script>'
|
||||||
|
];
|
||||||
|
var read = {};
|
||||||
|
|
||||||
|
options.input.forEach(concat);
|
||||||
|
|
||||||
|
if (buffer.length) {
|
||||||
|
fs.writeFileSync(options.output, buffer.join('\n'), 'utf8');
|
||||||
|
}
|
140
libs/urljs/README.md
Executable file
140
libs/urljs/README.md
Executable file
|
@ -0,0 +1,140 @@
|
||||||
|
URL.js
|
||||||
|
======
|
||||||
|
|
||||||
|
**An API for working with URLs in JavaScript.**
|
||||||
|
URL.js can be used in both **server-side** and **client-side** JavaScript environments,
|
||||||
|
it has **no dependencies** on any other libraries, and is easy to use for common URL-related tasks.
|
||||||
|
|
||||||
|
Oh and since I built this to use on [TipTheWeb](http://tiptheweb.org/),
|
||||||
|
you should [**tip this project**](http://tiptheweb.org/tip/?link=https://github.com/ericf/urljs) if you find it useful! :-D
|
||||||
|
|
||||||
|
Design & Approach
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
I had some very specific URL-related programming tasks I needed to do:
|
||||||
|
validate and normalize user input of URLs and URL-like strings within the browser,
|
||||||
|
and resolve URLs against each other on the server (in a YQL table to be specific).
|
||||||
|
Both of these tasks require a very good URL parser, so URL.js centers around parsing.
|
||||||
|
The design of the API and features of URL.js center around these four main concepts:
|
||||||
|
|
||||||
|
* Parsing
|
||||||
|
* Normalization
|
||||||
|
* Resolving
|
||||||
|
* Mutating/Building
|
||||||
|
|
||||||
|
**`URL` is both a namespace for utility methods and a constructor/factory to create instances of URL Objects.**
|
||||||
|
|
||||||
|
The static utility methods make it convenient when you just want to work with Strings since they return Strings.
|
||||||
|
When you want to retain a reference to a parsed URL you can easily create a URL instance;
|
||||||
|
these instances have useful methods, most serve as both an accessor/mutator to a specific part of the URL.
|
||||||
|
|
||||||
|
**Currently URL.js only works with HTTP URLs**, albiet the most popular type of URL;
|
||||||
|
I have plans to extend the functionality to include support [for all URL schemes](http://www.w3.org/Addressing/URL/url-spec.txt).
|
||||||
|
Internal to the library is the distiction between absolute and relative URLs.
|
||||||
|
Absolute URLs are ones which contain a scheme or are scheme-relative, and contain a host.
|
||||||
|
Relative URLs have slightly looser contraints but the relavence is maintained, either host- or path- relative.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
**`URL` is both a namespace for utility methods and a constructor/factory to create instances of URL Objects.**
|
||||||
|
|
||||||
|
### Using Static Utilites
|
||||||
|
|
||||||
|
There are two static methods: `normalize` and `resolve`
|
||||||
|
|
||||||
|
#### `URL.normalize`:
|
||||||
|
|
||||||
|
Takes in a dirty URL and makes it nice and clean.
|
||||||
|
|
||||||
|
URL.normalize('Http://Example.com'); // 'http://example.com/'
|
||||||
|
URL.normalize('Http://Example.com?foo=#bar'); // 'http://example.com/?foo#bar'
|
||||||
|
|
||||||
|
This should be suffient to serve the use-case of want to clean up URLs,
|
||||||
|
especially if were inputted by a user.
|
||||||
|
|
||||||
|
#### `URL.resolve`:
|
||||||
|
|
||||||
|
Given a base URL, this will resolve another URL against it; this method is inspired by what browsers do.
|
||||||
|
Normalizing is part of resolving, so a normalized and resolved URL `String` is returned.
|
||||||
|
|
||||||
|
URL.resolve('http://example.com/foo/bar', 'baz/index.html'); // 'http://example.com/foo/baz/index.html'
|
||||||
|
URL.resolve('https://example.com/foo/, '//example.com/bar.css'); // 'https://example.com/bar.css'
|
||||||
|
URL.resolve('http://example.com/foo/bar/zee/', '../../crazy#whoa'); // 'http://example.com/foo/crazy#whoa'
|
||||||
|
|
||||||
|
Resolving URLs is a pain in the ass, trust me, you don’t want to have to do this by hand.
|
||||||
|
The implementation of `resolve` is using all parts of this library’s API to pull it off.
|
||||||
|
|
||||||
|
### Using URL Instances
|
||||||
|
|
||||||
|
The `URL` `Object` is also a constructor/factory for creating instances of `URL`s.
|
||||||
|
When creating an instance, **the `new` keyword is optional**.
|
||||||
|
|
||||||
|
var url = URL('http://www.example.com');
|
||||||
|
|
||||||
|
// Accessor/Mutator Methods
|
||||||
|
|
||||||
|
url.scheme(); // 'http'
|
||||||
|
url.userInfo(); // undefined
|
||||||
|
url.host(); // 'www.example.com'
|
||||||
|
url.port(); // undefined
|
||||||
|
url.path(); // '/'
|
||||||
|
url.query(); // undefined
|
||||||
|
url.queryString(); // ''
|
||||||
|
url.fragment(); // undefined
|
||||||
|
|
||||||
|
// Convenience Methods
|
||||||
|
|
||||||
|
url.original(); // 'http://www.example.com'
|
||||||
|
url.isValid(); // true
|
||||||
|
url.isAbsolute(); // true
|
||||||
|
url.isRelative(); // false
|
||||||
|
url.isHostRelative(); // false
|
||||||
|
url.type(); // 'absolute' === URL.ABSOLUTE
|
||||||
|
url.domain(); // 'example.com'
|
||||||
|
url.authority(); // 'www.example.com'
|
||||||
|
|
||||||
|
// Output Methods
|
||||||
|
|
||||||
|
url.toString(); // 'http://www.example.com'
|
||||||
|
url.resolve('/foo/').toString(); // 'http://www.example.com/foo/'
|
||||||
|
|
||||||
|
**Yeah, `URL` instances are packed full of useful URL-ly jazz!**
|
||||||
|
|
||||||
|
Here are a few more “complex” examples of what you can do with mutation, chaining, building, and resolving:
|
||||||
|
|
||||||
|
// switch the scheme, resolve a path with a fragment, and navigate to it
|
||||||
|
window.location = URL(window.location.toString()).scheme('https').resolve('/about/#people').toString();
|
||||||
|
|
||||||
|
// turn 'http://example.com' -> 'http://example.com/?foo=bar#baz'
|
||||||
|
URL('http://example.com').query([['foo', 'bar']]).fragment('baz');
|
||||||
|
|
||||||
|
// build up a URL to: http://tiptheweb.org/tip/?link=https://github.com/ericf/urljs
|
||||||
|
URL()
|
||||||
|
.scheme('http')
|
||||||
|
.host('tiptheweb.org')
|
||||||
|
.path('/tip/')
|
||||||
|
.query([['link', 'https://github.com/ericf/urljs']]);
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
Copyright (c) 2011 Eric Ferraiuolo (http://eric.ferraiuolo.name/)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
7
libs/urljs/url-min.js
vendored
Executable file
7
libs/urljs/url-min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
666
libs/urljs/url.js
Executable file
666
libs/urljs/url.js
Executable file
|
@ -0,0 +1,666 @@
|
||||||
|
/*!
|
||||||
|
* URL.js
|
||||||
|
*
|
||||||
|
* Copyright 2011 Eric Ferraiuolo
|
||||||
|
* https://github.com/ericf/urljs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL constructor and utility.
|
||||||
|
* Provides support for validating whether something is a URL,
|
||||||
|
* formats and cleans up URL-like inputs into something nice and pretty,
|
||||||
|
* ability to resolve one URL against another and returned the formatted result,
|
||||||
|
* and is a convenient API for working with URL Objects and the various parts of URLs.
|
||||||
|
*
|
||||||
|
* @constructor URL
|
||||||
|
* @param {String | URL} url - the URL String to parse or URL instance to copy
|
||||||
|
* @return {URL} url - instance of a URL all nice and parsed
|
||||||
|
*/
|
||||||
|
var URL = function () {
|
||||||
|
|
||||||
|
var u = this;
|
||||||
|
|
||||||
|
if ( ! (u && u.hasOwnProperty && (u instanceof URL))) {
|
||||||
|
u = new URL();
|
||||||
|
}
|
||||||
|
|
||||||
|
return u._init.apply(u, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
var ABSOLUTE = 'absolute',
|
||||||
|
RELATIVE = 'relative',
|
||||||
|
|
||||||
|
HTTP = 'http',
|
||||||
|
HTTPS = 'https',
|
||||||
|
COLON = ':',
|
||||||
|
SLASH_SLASH = '//',
|
||||||
|
AT = '@',
|
||||||
|
DOT = '.',
|
||||||
|
SLASH = '/',
|
||||||
|
DOT_DOT = '..',
|
||||||
|
DOT_DOT_SLASH = '../',
|
||||||
|
QUESTION = '?',
|
||||||
|
EQUALS = '=',
|
||||||
|
AMP = '&',
|
||||||
|
HASH = '#',
|
||||||
|
EMPTY_STRING = '',
|
||||||
|
|
||||||
|
TYPE = 'type',
|
||||||
|
SCHEME = 'scheme',
|
||||||
|
USER_INFO = 'userInfo',
|
||||||
|
HOST = 'host',
|
||||||
|
PORT = 'port',
|
||||||
|
PATH = 'path',
|
||||||
|
QUERY = 'query',
|
||||||
|
FRAGMENT = 'fragment',
|
||||||
|
|
||||||
|
URL_TYPE_REGEX = /^(?:(https?:\/\/|\/\/)|(\/|\?|#)|[^;:@=\.\s])/i,
|
||||||
|
URL_ABSOLUTE_REGEX = /^(?:(https?):\/\/|\/\/)(?:([^:@\s]+:?[^:@\s]+?)@)?((?:[^;:@=\/\?\.\s]+\.)+[A-Za-z0-9\-]{2,})(?::(\d+))?(?=\/|\?|#|$)([^\?#]+)?(?:\?([^#]+))?(?:#(.+))?/i,
|
||||||
|
URL_RELATIVE_REGEX = /^([^\?#]+)?(?:\?([^#]+))?(?:#(.+))?/i,
|
||||||
|
|
||||||
|
OBJECT = 'object',
|
||||||
|
STRING = 'string',
|
||||||
|
TRIM_REGEX = /^\s+|\s+$/g,
|
||||||
|
|
||||||
|
trim, isObject, isString;
|
||||||
|
|
||||||
|
|
||||||
|
// *** Utilities *** //
|
||||||
|
|
||||||
|
trim = String.prototype.trim ? function (s) {
|
||||||
|
return ( s && s.trim ? s.trim() : s );
|
||||||
|
} : function (s) {
|
||||||
|
try {
|
||||||
|
return s.replace(TRIM_REGEX, EMPTY_STRING);
|
||||||
|
} catch (e) { return s; }
|
||||||
|
};
|
||||||
|
|
||||||
|
isObject = function (o) {
|
||||||
|
return ( o && typeof o === OBJECT );
|
||||||
|
};
|
||||||
|
|
||||||
|
isString = function (o) {
|
||||||
|
return typeof o === STRING;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// *** Static *** //
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
URL.ABSOLUTE = ABSOLUTE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
URL.RELATIVE = RELATIVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
URL.normalize = function (url) {
|
||||||
|
return new URL(url).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a resolved URL String using the baseUrl to resolve the url against.
|
||||||
|
* This attempts to resolve URLs like a browser would on a web page.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @method resolve
|
||||||
|
* @param {String | URL} baseUrl - the URL String, or URL instance as the resolving base
|
||||||
|
* @param {String | URL} url - the URL String, or URL instance to resolve
|
||||||
|
* @return {String} resolvedUrl - a resolved URL String
|
||||||
|
*/
|
||||||
|
URL.resolve = function (baseUrl, url) {
|
||||||
|
return new URL(baseUrl).resolve(url).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// *** Prototype *** //
|
||||||
|
|
||||||
|
URL.prototype = {
|
||||||
|
|
||||||
|
// *** Lifecycle Methods *** //
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new URL instance, or re-initializes an existing one.
|
||||||
|
* The URL constructor delegates to this method to do the initializing,
|
||||||
|
* and the mutator instance methods call this to re-initialize when something changes.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @method _init
|
||||||
|
* @param {String | URL} url - the URL String, or URL instance
|
||||||
|
* @return {URL} url - instance of a URL all nice and parsed/re-parsed
|
||||||
|
*/
|
||||||
|
_init : function (url) {
|
||||||
|
|
||||||
|
this.constructor = URL;
|
||||||
|
|
||||||
|
url = isString(url) ? url : url instanceof URL ? url.toString() : null;
|
||||||
|
|
||||||
|
this._original = url;
|
||||||
|
this._url = {};
|
||||||
|
this._isValid = this._parse(url);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
// *** Object Methods *** //
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the formatted URL String.
|
||||||
|
* Overridden Object toString method to do something useful.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method toString
|
||||||
|
* @return {String} url - formatted URL string
|
||||||
|
*/
|
||||||
|
toString : function () {
|
||||||
|
|
||||||
|
var url = this._url,
|
||||||
|
urlParts = [],
|
||||||
|
type = url[TYPE],
|
||||||
|
scheme = url[SCHEME],
|
||||||
|
path = url[PATH],
|
||||||
|
query = url[QUERY],
|
||||||
|
fragment = url[FRAGMENT];
|
||||||
|
|
||||||
|
if (type === ABSOLUTE) {
|
||||||
|
urlParts.push(
|
||||||
|
scheme ? (scheme + COLON + SLASH_SLASH) : SLASH_SLASH,
|
||||||
|
this.authority()
|
||||||
|
);
|
||||||
|
if (path && path.indexOf(SLASH) !== 0) { // this should maybe go in _set
|
||||||
|
path = SLASH + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
urlParts.push(
|
||||||
|
path,
|
||||||
|
query ? (QUESTION + this.queryString()) : EMPTY_STRING,
|
||||||
|
fragment ? (HASH + fragment) : EMPTY_STRING
|
||||||
|
);
|
||||||
|
|
||||||
|
return urlParts.join(EMPTY_STRING);
|
||||||
|
},
|
||||||
|
|
||||||
|
// *** Accessor/Mutator Methods *** //
|
||||||
|
|
||||||
|
original : function () {
|
||||||
|
return this._original;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether parsing from initialization or re-initialization produced something valid.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method isValid
|
||||||
|
* @return {Boolean} valid - whether the URL is valid
|
||||||
|
*/
|
||||||
|
isValid : function () {
|
||||||
|
return this._isValid;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL is absolute if it has a scheme or is scheme-relative (//).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method isAbsolute
|
||||||
|
* @return {Boolean} absolute - whether the URL is absolute
|
||||||
|
*/
|
||||||
|
isAbsolute : function () {
|
||||||
|
return this._url[TYPE] === ABSOLUTE;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL is relative if it host or path relative, i.e. doesn't contain a host.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method isRelative
|
||||||
|
* @return {Boolean} relative - whether the URL is relative
|
||||||
|
*/
|
||||||
|
isRelative : function () {
|
||||||
|
return this._url[TYPE] === RELATIVE;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL is host relative if it's relative and the path begins with '/'.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method isHostRelative
|
||||||
|
* @return {Boolean} hostRelative - whether the URL is host-relative
|
||||||
|
*/
|
||||||
|
isHostRelative : function () {
|
||||||
|
var path = this._url[PATH];
|
||||||
|
return ( this.isRelative() && path && path.indexOf(SLASH) === 0 );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the URL, either: URL.ABSOLUTE or URL.RELATIVE.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method type
|
||||||
|
* @return {String} type - the type of the URL: URL.ABSOLUTE or URL.RELATIVE
|
||||||
|
*/
|
||||||
|
type : function () {
|
||||||
|
return this._url[TYPE];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the scheme of the URL.
|
||||||
|
* If URL is determined to be absolute (i.e. contains a host) and no scheme is provided,
|
||||||
|
* the scheme will default to http.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method scheme
|
||||||
|
* @param {String} scheme - Optional scheme to set on the URL
|
||||||
|
* @return {String | URL} the URL scheme or the URL instance
|
||||||
|
*/
|
||||||
|
scheme : function (scheme) {
|
||||||
|
return ( arguments.length ? this._set(SCHEME, scheme) : this._url[SCHEME] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or set the user info of the URL.
|
||||||
|
* The user info can optionally contain a password and is only valid for absolute URLs.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method userInfo
|
||||||
|
* @param {String} userInfo - Optional userInfo to set on the URL
|
||||||
|
* @return {String | URL} the URL userInfo or the URL instance
|
||||||
|
*/
|
||||||
|
userInfo : function (userInfo) {
|
||||||
|
return ( arguments.length ? this._set(USER_INFO, userInfo) : this._url[USER_INFO] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the host of the URL.
|
||||||
|
* The host name, if set, must be something valid otherwise the URL will become invalid.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method host
|
||||||
|
* @param {String} host - Optional host to set on the URL
|
||||||
|
* @return {String | URL} the URL host or the URL instance
|
||||||
|
*/
|
||||||
|
host : function (host) {
|
||||||
|
return ( arguments.length ? this._set(HOST, host) : this._url[HOST] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL's domain, where the domain is the TLD and SLD of the host.
|
||||||
|
* e.g. foo.example.com -> example.com
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method domain
|
||||||
|
* @return {String} domain - the URL domain
|
||||||
|
*/
|
||||||
|
domain : function () {
|
||||||
|
var host = this._url[HOST];
|
||||||
|
return ( host ? host.split(DOT).slice(-2).join(DOT) : undefined );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the port of the URL.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method port
|
||||||
|
* @param {Number} port - Optional port to set on the URL
|
||||||
|
* @return {Number | URL} the URL port or the URL instance
|
||||||
|
*/
|
||||||
|
port : function (port) {
|
||||||
|
return ( arguments.length ? this._set(PORT, port) : this._url[PORT] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL's authority which is the userInfo, host, and port combined.
|
||||||
|
* This only makes sense for absolute URLs
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method authority
|
||||||
|
* @return {String} authority - the URL's authority (userInfo, host, and port)
|
||||||
|
*/
|
||||||
|
authority : function () {
|
||||||
|
|
||||||
|
var url = this._url,
|
||||||
|
userInfo = url[USER_INFO],
|
||||||
|
host = url[HOST],
|
||||||
|
port = url[PORT];
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
userInfo ? (userInfo + AT) : EMPTY_STRING,
|
||||||
|
host,
|
||||||
|
port ? (COLON + port) : EMPTY_STRING,
|
||||||
|
|
||||||
|
].join(EMPTY_STRING);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the path of the URL.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method path
|
||||||
|
* @param {String} path - Optional path to set on the URL
|
||||||
|
* @return {String | URL} the URL path or the URL instance
|
||||||
|
*/
|
||||||
|
path : function (path) {
|
||||||
|
return ( arguments.length ? this._set(PATH, path) : this._url[PATH] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the query of the URL.
|
||||||
|
* This takes or returns the parsed query as an Array of Arrays.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method query
|
||||||
|
* @param {Array} query - Optional query to set on the URL
|
||||||
|
* @return {Array | URL} the URL query or the URL instance
|
||||||
|
*/
|
||||||
|
query : function (query) {
|
||||||
|
return ( arguments.length ? this._set(QUERY, query) : this._url[QUERY] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the query of the URL.
|
||||||
|
* This takes or returns the query as a String; doesn't include the '?'
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method queryString
|
||||||
|
* @param {String} queryString - Optional queryString to set on the URL
|
||||||
|
* @return {String | URL} the URL queryString or the URL instance
|
||||||
|
*/
|
||||||
|
queryString : function (queryString) {
|
||||||
|
|
||||||
|
// parse and set queryString
|
||||||
|
if (arguments.length) {
|
||||||
|
return this._set(QUERY, this._parseQuery(queryString));
|
||||||
|
}
|
||||||
|
|
||||||
|
queryString = EMPTY_STRING;
|
||||||
|
|
||||||
|
var query = this._url[QUERY],
|
||||||
|
i, len;
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
for (i = 0, len = query.length; i < len; i++) {
|
||||||
|
queryString += query[i].join(EQUALS);
|
||||||
|
if (i < len - 1) {
|
||||||
|
queryString += AMP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryString;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns or sets the fragment on the URL.
|
||||||
|
* The fragment does not contain the '#'.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method fragment
|
||||||
|
* @param {String} fragment - Optional fragment to set on the URL
|
||||||
|
* @return {String | URL} the URL fragment or the URL instance
|
||||||
|
*/
|
||||||
|
fragment : function (fragment) {
|
||||||
|
return ( arguments.length ? this._set(FRAGMENT, fragment) : this._url[FRAGMENT] );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new, resolved URL instance using this as the baseUrl.
|
||||||
|
* The URL passed in will be resolved against the baseUrl.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method resolve
|
||||||
|
* @param {String | URL} url - the URL String, or URL instance to resolve
|
||||||
|
* @return {URL} url - a resolved URL instance
|
||||||
|
*/
|
||||||
|
resolve : function (url) {
|
||||||
|
|
||||||
|
url = (url instanceof URL) ? url : new URL(url);
|
||||||
|
|
||||||
|
var resolved, path;
|
||||||
|
|
||||||
|
if ( ! (this.isValid() && url.isValid())) { return this; } // not sure what to do???
|
||||||
|
|
||||||
|
// the easy way
|
||||||
|
if (url.isAbsolute()) {
|
||||||
|
return ( this.isAbsolute() ? url.scheme() ? url : new URL(url).scheme(this.scheme()) : url );
|
||||||
|
}
|
||||||
|
|
||||||
|
// the hard way
|
||||||
|
resolved = new URL(this.isAbsolute() ? this : null);
|
||||||
|
|
||||||
|
if (url.path()) {
|
||||||
|
|
||||||
|
if (url.isHostRelative() || ! this.path()) {
|
||||||
|
path = url.path();
|
||||||
|
} else {
|
||||||
|
path = this.path().substring(0, this.path().lastIndexOf(SLASH) + 1) + url.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved.path(this._normalizePath(path)).query(url.query()).fragment(url.fragment());
|
||||||
|
|
||||||
|
} else if (url.query()) {
|
||||||
|
resolved.query(url.query()).fragment(url.fragment());
|
||||||
|
} else if (url.fragment()) {
|
||||||
|
resolved.fragment(url.fragment());
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new, reduced relative URL instance using this as the baseUrl.
|
||||||
|
* The URL passed in will be compared to the baseUrl with the goal of
|
||||||
|
* returning a reduced-down URL to one that’s relative to the base (this).
|
||||||
|
* This method is basically the opposite of resolve.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @method reduce
|
||||||
|
* @param {String | URL} url - the URL String, or URL instance to resolve
|
||||||
|
* @return {URL} url - the reduced URL instance
|
||||||
|
*/
|
||||||
|
reduce : function (url) {
|
||||||
|
|
||||||
|
url = (url instanceof URL) ? url : new URL(url);
|
||||||
|
|
||||||
|
var reduced = this.resolve(url);
|
||||||
|
|
||||||
|
if (this.isAbsolute() && reduced.isAbsolute()) {
|
||||||
|
if (reduced.scheme() === this.scheme() && reduced.authority() === this.authority()) {
|
||||||
|
reduced.scheme(null).userInfo(null).host(null).port(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reduced;
|
||||||
|
},
|
||||||
|
|
||||||
|
// *** Private Methods *** //
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a URL into usable parts.
|
||||||
|
* Reasonable defaults are applied to parts of the URL which weren't present in the input,
|
||||||
|
* e.g. 'http://example.com' -> { type: 'absolute', scheme: 'http', host: 'example.com', path: '/' }
|
||||||
|
* If nothing or a falsy value is returned, the URL wasn't something valid.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method _parse
|
||||||
|
* @param {String} url - the URL string to parse
|
||||||
|
* @param {String} type - Optional type to seed parsing: URL.ABSOLUTE or URL.RELATIVE
|
||||||
|
* @return {Boolean} parsed - whether or not the URL string was parsed
|
||||||
|
*/
|
||||||
|
_parse : function (url, type) {
|
||||||
|
|
||||||
|
// make sure we have a good string
|
||||||
|
url = trim(url);
|
||||||
|
if ( ! (isString(url) && url.length > 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var urlParts, parsed;
|
||||||
|
|
||||||
|
// figure out type, absolute or relative, or quit
|
||||||
|
if ( ! type) {
|
||||||
|
type = url.match(URL_TYPE_REGEX);
|
||||||
|
type = type ? type[1] ? ABSOLUTE : type[2] ? RELATIVE : null : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case ABSOLUTE:
|
||||||
|
urlParts = url.match(URL_ABSOLUTE_REGEX);
|
||||||
|
if (urlParts) {
|
||||||
|
parsed = {};
|
||||||
|
parsed[TYPE] = ABSOLUTE;
|
||||||
|
parsed[SCHEME] = urlParts[1] ? urlParts[1].toLowerCase() : undefined;
|
||||||
|
parsed[USER_INFO] = urlParts[2];
|
||||||
|
parsed[HOST] = urlParts[3].toLowerCase();
|
||||||
|
parsed[PORT] = urlParts[4] ? parseInt(urlParts[4], 10) : undefined;
|
||||||
|
parsed[PATH] = urlParts[5] || SLASH;
|
||||||
|
parsed[QUERY] = this._parseQuery(urlParts[6]);
|
||||||
|
parsed[FRAGMENT] = urlParts[7];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RELATIVE:
|
||||||
|
urlParts = url.match(URL_RELATIVE_REGEX);
|
||||||
|
if (urlParts) {
|
||||||
|
parsed = {};
|
||||||
|
parsed[TYPE] = RELATIVE;
|
||||||
|
parsed[PATH] = urlParts[1];
|
||||||
|
parsed[QUERY] = this._parseQuery(urlParts[2]);
|
||||||
|
parsed[FRAGMENT] = urlParts[3];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// try to parse as absolute, if that fails then as relative
|
||||||
|
default:
|
||||||
|
return ( this._parse(url, ABSOLUTE) || this._parse(url, RELATIVE) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed) {
|
||||||
|
this._url = parsed;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to parse a URL query string into an array of arrays.
|
||||||
|
* Order of the query paramerters is maintained, an example structure would be:
|
||||||
|
* queryString: 'foo=bar&baz' -> [['foo', 'bar'], ['baz']]
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method _parseQuery
|
||||||
|
* @param {String} queryString - the query string to parse, should not include '?'
|
||||||
|
* @return {Array} parsedQuery - array of arrays representing the query parameters and values
|
||||||
|
*/
|
||||||
|
_parseQuery : function (queryString) {
|
||||||
|
|
||||||
|
if ( ! isString(queryString)) { return; }
|
||||||
|
|
||||||
|
queryString = trim(queryString);
|
||||||
|
|
||||||
|
var query = [],
|
||||||
|
queryParts = queryString.split(AMP),
|
||||||
|
queryPart, i, len;
|
||||||
|
|
||||||
|
for (i = 0, len = queryParts.length; i < len; i++) {
|
||||||
|
if (queryParts[i]) {
|
||||||
|
queryPart = queryParts[i].split(EQUALS);
|
||||||
|
query.push(queryPart[1] ? queryPart : [queryPart[0]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for mutators to set a new URL-part value.
|
||||||
|
* After the URL-part is updated, the URL will be toString'd and re-parsed.
|
||||||
|
* This is a brute, but will make sure the URL stays in sync and is re-validated.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method _set
|
||||||
|
* @param {String} urlPart - the _url Object member String name
|
||||||
|
* @param {Object} val - the new value for the URL-part, mixed type
|
||||||
|
* @return {URL} this - returns this URL instance, chainable
|
||||||
|
*/
|
||||||
|
_set : function (urlPart, val) {
|
||||||
|
|
||||||
|
this._url[urlPart] = val;
|
||||||
|
|
||||||
|
if (val && (
|
||||||
|
urlPart === SCHEME ||
|
||||||
|
urlPart === USER_INFO ||
|
||||||
|
urlPart === HOST ||
|
||||||
|
urlPart === PORT )){
|
||||||
|
this._url[TYPE] = ABSOLUTE; // temp, set this to help clue parsing
|
||||||
|
}
|
||||||
|
if ( ! val && urlPart === HOST) {
|
||||||
|
this._url[TYPE] = RELATIVE; // temp, no host means relative
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isValid = this._parse(this.toString());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a normalized path String, by removing ../'s.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @method _normalizePath
|
||||||
|
* @param {String} path — the path String to normalize
|
||||||
|
* @return {String} normalizedPath — the normalized path String
|
||||||
|
*/
|
||||||
|
_normalizePath : function (path) {
|
||||||
|
|
||||||
|
var pathParts, pathPart, pathStack, normalizedPath, i, len;
|
||||||
|
|
||||||
|
if (path.indexOf(DOT_DOT_SLASH) > -1) {
|
||||||
|
|
||||||
|
pathParts = path.split(SLASH);
|
||||||
|
pathStack = [];
|
||||||
|
|
||||||
|
for ( i = 0, len = pathParts.length; i < len; i++ ) {
|
||||||
|
pathPart = pathParts[i];
|
||||||
|
if (pathPart === DOT_DOT) {
|
||||||
|
pathStack.pop();
|
||||||
|
} else if (pathPart) {
|
||||||
|
pathStack.push(pathPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedPath = pathStack.join(SLASH);
|
||||||
|
|
||||||
|
// prepend slash if needed
|
||||||
|
if (path[0] === SLASH) {
|
||||||
|
normalizedPath = SLASH + normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append slash if needed
|
||||||
|
if (path[path.length - 1] === SLASH && normalizedPath.length > 1) {
|
||||||
|
normalizedPath += SLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
normalizedPath = path;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
Loading…
Add table
Add a link
Reference in a new issue