Skip to content

Commit

Permalink
new simplified URI class
Browse files Browse the repository at this point in the history
  • Loading branch information
anutron committed Mar 25, 2009
1 parent 3797b31 commit 6c7e047
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 102 deletions.
36 changes: 30 additions & 6 deletions Docs/Native/URI.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Pass a *string* to the URI subclass and it will extend it, returning a new strin

### Syntax

var myURI = new URI(['http://www.test.com:8383/the/path.html?query=value#anchor']);
var myURI = new URI(['http://user:password@www.test.com:8383/the/path.html?query=value#anchor']);

### Returns

Expand All @@ -34,6 +34,28 @@ Returns an regular *string* without the URI extensions.

* (*string*) the unaltered url.

URI Method: validate {#URI:validate}
------------------------------------

Validates the URI.

### Syntax

myURI.validate([parts, regex]);

### Arguments

1. parts - (*array*; optional) An array of parts (*scheme*, *domain*, etc) that must be present for the URI to be valid. By default this is set to *scheme* and *host* but you could, for example, require only *path* to validate a relative URI.
2. regex - (*RegExp*; optional) A regular expression to validate against the url. By default this expression is the standard URL scheme.

### Example

myURI.validate(['path']); //validate relative url

### Note

The validation parts are only checked to verify that they are defined. This means that other parts may also be defined. The example above ensures that *path* is defined, but doesn't ensure that, for example, *domain* isn't.

URI Method: set {#URI:set}
--------------------------

Expand All @@ -49,7 +71,7 @@ Set's a portion of the URI to the specified value.

### Example

myURI.set('protocol', 'https');
myURI.set('scheme', 'https');
myURI.set('domain', 'www.foo.com');
//etc.

Expand All @@ -59,7 +81,9 @@ Set's a portion of the URI to the specified value.

### Valid parts

* protocol - (*string*) 'http', 'https', 'ftp', etc.
* scheme - (*string*) 'http', 'https', 'ftp', etc.
* user - (*string*) the username portion of the credentials
* password - (*string*) the password portion of the credentials
* domain - (*string*) 'www.example.com', 'exmaple.com', 'subdomain.example.com', etc.
* port - (*string* or *integer*) 80, 8080, etc.
* path - (*string*) '/directory/file.html'
Expand All @@ -78,7 +102,7 @@ Returns the current value for the specified portion of the URI.

### Example

myURI.get('protocol'); //returns "http", for example
myURI.get('scheme'); //returns "http", for example
myURI.get('domain'); //returns "www.example.com", for example

### Returns
Expand All @@ -87,7 +111,7 @@ Returns the current value for the specified portion of the URI.

### Valid parts

* protocol - (returns *string*) 'http', 'https', 'ftp', etc.
* scheme - (returns *string*) 'http', 'https', 'ftp', etc.
* domain - (returns *string*) 'www.example.com', 'exmaple.com', 'subdomain.example.com', etc.
* port - (returns *string*) 80, 8080, etc.
* path - (returns *string*) '/directory/file.html'
Expand Down Expand Up @@ -158,7 +182,7 @@ Loads the url into the document location.
Method Translations
===================

All the URI parts ('protocol', 'domain', 'port', 'query', and 'hash') have corresponding *get<Part>* methods. So you can call *myURI.get('domain')* or *myURI.getDomain()*. The same is true of *set* - you can call *myURI.set('domain', 'www.foo.com')* or *myURI.setDomain('www.foo.com')*. The *set/get(part)* method is the prefered method.
All the URI parts ('scheme', 'domain', 'port', 'query', and 'hash') have corresponding *get<Part>* methods. So you can call *myURI.get('domain')* or *myURI.getDomain()*. The same is true of *set* - you can call *myURI.set('domain', 'www.foo.com')* or *myURI.setDomain('www.foo.com')*. The *set/get(part)* method is the prefered method.

String Method: parseQueryString {#String:parseQueryString}
----------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ MooTools Plugins and Enhancements Repository
* Compat for Clientcide
* Switch to feature detection instead of engine detection
* update all the Element.Forms methods to getters/setters; tidy them up a bit
* Update calls to .position to use .setPosition

### StyleGuide

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Lang.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ Script: MooTools.Lang.js

var cascaded;

MooTools.lang = new new Class({
MooTools.lang = new Events();

Implements: Events,
$extend(MooTools.lang, {

setLanguage: function(lang){
if (!data.languages[lang]) return;
Expand Down
137 changes: 51 additions & 86 deletions Source/Native/URI.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,32 @@ String.implement({
return $chk(set.split('=')[1]);
}).join('&');
}

});

var URI = new Class({

Implements: Options,

options: {
regex: /^(?:(\w+):\/\/)?(?:(?:(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]+)?(?::(\d*))?)?([^#?]*)(?:\?([^#]*))?(?:#(.*))?$/,
parts: ['full', 'scheme', 'user', 'password', 'host', 'port', 'path', 'query', 'fragment'],
schemes: ['https','ftp','file','rtsp','mms'],
required: ['scheme', 'host'],
wrappers: {
scheme: function(s) { return s ? s += '://' : '' },
password: function(s) { return s ? ':' + s : '' },
port: function(s) { return s ? ':' + s : ''},
query: function(s) { return s ? '?' + s : ''},
fragment: function(s) { return s ? '#' + s : ''}
}
},

initialize: function(uri, options){
this.setOptions(options);
this.value = uri || document.location.href || '';
},

toString: function(){
return this.value;
},
Expand All @@ -45,38 +66,59 @@ var URI = new Class({
return this.value;
},

validate: function(regex, parts){
parts = parts || this.parts;
validate: function(parts, regex){
parts = parts || this.options.parts;
var bits = this.parse(regex, parts);
return parts.every(function(part) {
var valid = parts.every(function(part) {
return !!bits[part];
});
return valid && (this.schemes.contains(bits.scheme) || !bits.scheme);
},

parse: function(regex, parts) {
regex = regex || this.regex;
parts = parts || this.parts;
regex = regex || this.options.regex;
parts = parts || this.options.parts;
var bits = this.value.match(regex).associate(parts);
delete bits.full;
return bits;
},

set: function(part, value){
if (part == "data") return this.setData(value);
var bits = this.parse();
bits[part] = value;
this.combine(bits);
return this;
},

get: function(part){
if (part == "data") return this.getData();
return this.parse()[part];
},

getData: function(key){
var qs = this.get('query');
if (!$chk(qs)) return key ? null : {};
var obj = decodeURI(qs).parseQueryString(false, false);
return key ? obj[key] : obj;
},

setData: function(values, merge){
var merged = merge ? $merge(this.getData(), values) : values;
var newQuery = '';
for (key in merged) newQuery += encodeURIComponent(key) + '=' + encodeURIComponent(merged[key]) + '&';
return this.set('query', newQuery.substring(0, newQuery.length-1));
},

clearData: function(){
this.set('query', '');
},

combine: function(bits){
bits = bits || this.parse();
var result = '';
$each(bits, function(value, key) {
var wrapped = this.wrappers[key] ? this.wrappers[key](value) : value;
var wrapped = this.options.wrappers[key] ? this.options.wrappers[key](value) : value;
result += wrapped ? wrapped : '';
}, this);
this.value = result;
Expand All @@ -91,86 +133,9 @@ var URI = new Class({

(function(){

//HTTP: protocol, user, password, hostname, port, directory, pathname, file, search, hash
//MAILTO: email, username, hostname, headers, subject, body
URI.URL = new Class({

Extends: URI,

wrappers: {
protocol: function(s) { return s ? s += '://' : s },
password: function(s) { return s ? ':' + s : s },
port: function(s) { return s ? ':' + s : s},
query: function(s) { return s ? '?' + s : s},
fragment: function(s) { return s ? '#' + s : s}
},

initialize: function(uri){
this.value = uri || document.location.href || '';
this.regex = URI.URL.regex;
this.parts = URI.URL.parts;
},

parse: function(){
return this.parent(URI.URL.regex, URI.URL.parts);
},

validate: function(regex, parts){
return this.parent(regex || this.regex, parts || ['protocol', 'host']);
},

set: function(part, value){
switch(part) {
case 'data': return this.setData(value);
case 'directory': return this.setDirectory(value);
}
return this.parent(part, value);
},

get: function(part){
switch(part) {
case 'data': return this.getData();
case 'directory': return this.getDirectory();
}
return this.parent(part);
},

getData: function(key){
var qs = this.get('query');
if (!$chk(qs)) return key ? null : {};
var obj = decodeURI(qs).parseQueryString(false, false);
return key ? obj[key] : obj;
},

getDirectory: function() {
var bits = this.get('path').split('/');
bits.pop();
return bits.join('/');
},

setDirectory: function(dir){
return this.set('path', dir + '/' + this.get('path').split('/').getLast());
},

setData: function(values, merge){
var merged = merge ? $merge(this.getData(), values) : values;
var newQuery = '';
for (key in merged) newQuery += encodeURIComponent(key) + '=' + encodeURIComponent(merged[key]) + '&';
return this.set('query', newQuery.substring(0, newQuery.length-1));
},

clearData: function(){
this.set('query', '');
}

});

URI.URL.regex = /^(?:(\w+):\/\/)?(?:(?:(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]+)?(?::(\d*))?)?([^#?]*)(?:\?([^#]*))?(?:#(.*))?$/;
URI.URL.parts = ['full', 'protocol', 'user', 'password', 'host', 'port', 'path', 'query', 'fragment'];

var methods = {};

URI.URL.parts.each(function(part){
new URI().options.parts.each(function(part){

methods['get' + part.capitalize()] = function(){
return this.get(part);
Expand All @@ -182,6 +147,6 @@ var URI = new Class({

});

URI.URL.implement(methods);
URI.implement(methods);

})();
16 changes: 8 additions & 8 deletions Specs/Native/URI.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,47 +38,47 @@ License:
describe('URL.get(\'host\')', {

'should get the domain of a url': function(){
value_of(new URI.URL(url.toString()).get('host')).should_be('www.test.com');
value_of(new URI(url.toString()).get('host')).should_be('www.test.com');
}

});

describe('URL.getData', {

'should get the query string values from a url': function(){
value_of(new URI.URL(url.toString()).getData()['query']).should_be('value');
value_of(new URI(url.toString()).getData()['query']).should_be('value');
},

'should get the query string value from a url': function(){
value_of(new URI.URL(url.toString()).getData('query')).should_be('value');
value_of(new URI(url.toString()).getData('query')).should_be('value');
}

});

describe('URI.get(\'domain\')', {

'should get the protocol from a url': function(){
value_of(new URI.URL(url.toString()).get('protocol')).should_be('http');
'should get the scheme from a url': function(){
value_of(new URI(url.toString()).get('scheme')).should_be('http');
}

});

describe('URI.get(\'port\')', {

'should get the port from a url': function(){
value_of(new URI.URL(url.toString()).get('port')).should_be('8383');
value_of(new URI(url.toString()).get('port')).should_be('8383');
}

});

describe('URI.setData', {

'should set query string values': function(){
value_of(new URI.URL('www.test.com').setData({a: 'b'}).toString()).should_be('www.test.com?a=b');
value_of(new URI('www.test.com').setData({a: 'b'}).toString()).should_be('www.test.com?a=b');
},

'should merge url query string values': function(){
value_of(new URI.URL('www.test.com?x=y&a=b').setData({a: 'c'}, true).toString()).should_be('www.test.com?x=y&a=c');
value_of(new URI('www.test.com?x=y&a=b').setData({a: 'c'}, true).toString()).should_be('www.test.com?x=y&a=c');
}

});
Expand Down

0 comments on commit 6c7e047

Please sign in to comment.