diff --git a/source/Ox.UI/js/Core/URL.js b/source/Ox.UI/js/Core/URL.js index 273b0938..4e958125 100644 --- a/source/Ox.UI/js/Core/URL.js +++ b/source/Ox.UI/js/Core/URL.js @@ -7,22 +7,24 @@ Ox.URL URL controller findKeys <[o]> Find keys id Find key id type Value type (like "string" or "integer") - getHash Takes a state object and normalizes its "hash" property - (o) -> State object + getHash Tests if a hash is valid + May modify the state's hash property + (state, callback) -> undefined + state State object + hash The hash to be tested + callback callback function getItem Tests if a string matches an item - (type, string, callback) -> undefined - type type + May modify the state's item property + (state, string, callback) -> undefined + state State object string The string to be tested callback callback function - id Matching item id, or empty getSpan Tests if a string matches a span - (type, item, view, string, callback) -> undefined - item The item id, or empty - view The view, or empty + May modify the state's view and span properties + (state, string, callback) -> undefined + state State object string The string to be tested callback Callback function - id Matching span id, or empty - view Matching view, or empty pages <[s]> List of pages sortKeys Sort keys for list and item views for all types typeA Sort keys for this type @@ -53,16 +55,29 @@ Ox.URL URL controller {id: 'name', type: 'string'}, {id: 'population', type: 'integer'} ], - getItem: function(type, str, callback) { - callback(/^\d+$/.test(str) ? str : ''); - }, - getSpan: function(type, item, view, str, callback) { - if (!item && (!view || view == 'map')) { - callback(str.replace(/^@/, ''), 'map'); - } else { - callback(); + getHash: function(state, callback) { + if ( + state.hash && state.hash.anchor + && state.hash.anchor.length > 1 + ) { + if (state.hash.query) { + delete state.hash.anchor; + } else { + delete state.hash; + } } }, + getItem: function(state, str, callback) { + state.item = /^\d+$/.test(str) ? str : ''; + callback(); + }, + getSpan: function(state, str, callback) { + if (!state.item && (!state.view || state.view == 'map')) { + state.view = 'map'; + state.span = str.replace(/^@/, ''); + } + callback(); + }, pages: ['about', 'faq', 'help'], sortKeys: { countries: { @@ -210,6 +225,14 @@ Ox.URL URL controller operator: '&' } }, + '/#?k=v&l=w': { + hash: { + query: [ + {key: 'k', value: 'v'}, + {key: 'l', value: 'w'} + ] + } + }, '/#a?k=v&l=w': { hash: { anchor: 'a', @@ -219,7 +242,7 @@ Ox.URL URL controller ] } }, - '/#?a=[1,2]&b=true&n=1.2&o={"k":"v"}&s1="foo"&s2=bar': { + '/#invalid?a=[1,2]&b=true&n=1.2&o={"k":"v"}&s1="foo"&s2=bar': { hash: { query: [ {key: 'a', value: [1, 2]}, @@ -261,9 +284,11 @@ Ox.URL URL controller true > !!Ox.test.url.parse('/population>0&(name=a*|name=*z)', function(o) { Ox.test(o, Ox.test.result['/population>0&(name=a*|name=*z)']); }) true + > !!Ox.test.url.parse('/#?k=v&l=w', function(o) { Ox.test(o, Ox.test.result['/#?k=v&l=w']); }) + true > !!Ox.test.url.parse('/#a?k=v&l=w', function(o) { Ox.test(o, Ox.test.result['/#a?k=v&l=w']); }) true - > !!Ox.test.url.parse('/#?a=[1,2]&b=true&n=1.2&o={"k":"v"}&s1="foo"&s2=bar', function(o) { Ox.test(o, Ox.test.result['/#?a=[1,2]&b=true&n=1.2&o={"k":"v"}&s1="foo"&s2=bar']); }) + > !!Ox.test.url.parse('/#invalid?a=[1,2]&b=true&n=1.2&o={"k":"v"}&s1="foo"&s2=bar', function(o) { Ox.test(o, Ox.test.result['/#invalid?a=[1,2]&b=true&n=1.2&o={"k":"v"}&s1="foo"&s2=bar']); }) true @*/ @@ -445,8 +470,11 @@ Ox.URL = function(options) { obj[condition.key] = condition.value; }); } - return (hash.anchor || '') - + (hash.query ? '?' + Ox.serialize(obj) : ''); + return hash.anchor || hash.query + ? '#' + hash.anchor + ( + hash.query ? '?' + Ox.serialize(obj) : '' + ) + : ''; } function constructLocation(location) { @@ -508,8 +536,9 @@ Ox.URL = function(options) { parts.push(constructFind(state.find)); } } - return '/' + Ox.filter(parts).join('/') - + (state.hash ? '#' + constructHash(state.hash) : ''); + return '/' + Ox.filter(parts).join('/') + ( + state.hash ? constructHash(state.hash) : '' + ); } function constructValue(str, key) { @@ -671,7 +700,7 @@ Ox.URL = function(options) { } if (split[1]) { Ox.forEach(Ox.unserialize(split[1], true), function(value, key) { - hash.query = (hash.query || []) + hash.query = hash.query || []; hash.query.push({ key: key, value: value @@ -718,7 +747,9 @@ Ox.URL = function(options) { // fixme: removing trailing slash makes it impossible to search for '/' var split = str.split('#'), parts = split.shift().replace(/(^\/|\/$)/g, '').split('/'), - state = split.length ? {hash: parseHash(split.join('#'))} : {}; + state = split.length && split[0].length + ? {hash: parseHash(split.join('#'))} + : {}; if (parts[0] == '') { // empty URL getHash(); @@ -745,9 +776,9 @@ Ox.URL = function(options) { parseBeyondItem(); } else { // test for item id or name - self.options.getItem(state.type, parts[0].replace(/%20/g, ' '), function(item) { - state.item = item; - if (item) { + self.options.getItem(state, parts[0].replace(/%20/g, ' '), function() { + // may have modified state.item + if (state.item) { parts.shift(); } parseBeyondItem(); @@ -808,14 +839,9 @@ Ox.URL = function(options) { } if (!state.span && /^[A-Z@]/.test(parts[0])) { // test for span id or name - self.options.getSpan(state.type, state.item, state.view, decodeValue(parts[0]), function(span, view) { - Ox.Log('Core', 'span/view', span, view) - if (span) { - if (!state.view) { - // set list or item view - state.view = view; - } - state.span = span; + self.options.getSpan(state, decodeValue(parts[0]), function() { + // may have modified state.view and state.span + if (state.span) { parts.shift(); } parseBeyondSpan(); @@ -878,7 +904,10 @@ Ox.URL = function(options) { } function getHash() { if (self.options.getHash) { - state = self.options.getHash(state); + self.options.getHash(state, function() { + // may have modified state.hash + callback(state); + }); } callback(state); }