mtrpcic / pathjs Goto Github PK
View Code? Open in Web Editor NEWSimple, lightweight routing for web browsers
Simple, lightweight routing for web browsers
Hello,
see there were past issues with ie9 that are now closed. However I am trying to load the demo pages (http://mtrpcic.github.io/pathjs/) in ie9 and clicking on the left nav and nothing happens. When I try the to run it in ieTester and try ie9 , 8 and even ie7, I get errors on line 180 char 21. Object expected.
Can someone confirm that IE is still supported? If so is there something special that needs to be done to get it to work?
-ps- I have a POc that I am building the paths work great in ff, chrome and safari its only IE not working. in IE when the user clicks on a button to go from the login page I reroutre through a success path, then to the workspace path. in all browser it works. in ie the log in button just loops back on to it self.
here is my path code
Path.map("#/login").to(function(){
brite.display("Login","#pageBody");
});
Path.map("#/success").to(function(){
//simulate time to login
loggedIn = true;
$('#pageBody').empty();
location.hash = '#/workspace';
});
Path.map("#/error").to(function(){
alert("A Login Error has Occured!");
});
Path.map("#/workspace").to(function(){
checkAuth();
brite.display("MainView","#pageBody");
});
Path.map("#/bulk001").to(function(){
checkAuth();
});
Path.map("#/disconnect").to(function(){
$('#pageBody').empty();
var loggedIn = false;
var $workspace = false;
location.hash = '#/login';
});
Path.root("#/login");
Path.rescue(notFound);
$(document).ready(function() {
Path.listen();
});
When using IE10, the examples don't work. I have been debugging it, and noticed that the Path variable is undefined.
I get the following error when I attempt to run the tests in ie8
Webpage error details
User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322)
Timestamp: Wed, 2 Jan 2013 23:20:02 UTC
Message: Object expected
Line: 180
Char: 21
Code: 0
URI: /path.js
path.min.js is missing ;
at the end. This produces js error if you combine it with other js scripts in one file.
In the readme file, the root is set as such:
Path.root = "#/posts";
but for the root to work properly (and auto update), shouldn't it be set like this given the object? (otherwise Path.routes.root = null):
Path.root("#/posts");
After upgrading the NuGet to 0.8.4.1, PathJs could not find the path "#/".
The bug lies on 64:
var re = /\/?([^\/]+)/;
it should be
var re = /\/?([^\/]*)/;
NOTE: The "+" seems to work when its a "*".
Great and super simple library.
Any examples available on how to create a path mapping for a url with a query string.
Example URL:
http://localhost:3000/#!/rooms?_=1308513473427&page=2
I'm trying to create a mapping that then returns 2
This does not appear to be taking:
Path.map("#/rooms?:id").to(function(){
});
thanks
Your example at http://mtrpcic.github.io/pathjs/hashtag_basic.html does not entirely work under Chrome, version "28.0.1500.72 m", on Windows (7). Specifically the content does not get updated in the right hand pane when click on links in the left hand pane (the backbutton does however work)
I'm using PathJS's HTML5 pushState capability in an application. I want to be able to trigger actions not only when the user explicitly clicks on a link/form element, but also when the user goes to that page. For example: If the user goes to example.com/do/something, that should be the same as if they went to example.com and clicked a link that triggered "do/something." This is working for me in Chrome, but not Safari, Firefox, or Opera. Even if this is not the intended behavior, it is an inconsistency.
Is this a problem with PathJS or the implementation of the History API? I feel like it must be the former, since Backbone.js can do what I'm trying to do, right?
Thanks,
Gerard
Running into a strange problem trying to match certain url patterns
Path.map('/test(/:id1)(/:id2)(/:id3)(/:id4)(/:id5)').to(function(){
console.log( this.params );
});
Path.history.listen(true);
If I do a pushState of a pattern of /test/0/0/0 it works.
However, /test/0/1/0 doesn't.
If I do /test/0/a/0 it also works. In fact, any number !== 1 works.
/test/0/10/0 works, etc.
I'm having to use multiple :id values because there's a nested array returned from an XHR request when the app initializes and the url structure is the pattern of indexes used to reach into the array to obtain data.
On a side note, being able to do some more advanced regex-style url matching would be very useful. What I have in mind is the route matching that's used in the node.js Express framework.
var routes = [
"#/home",
"#/obstacles",
"#/obstacles/:id"
];
Path.map(routes[2]).to(function(){
app.route(this.path, this.params["id"]);
});
When looping through an array of routes, firefox - firebug throws a
Any reason why this is happening?
Strangely, the default root path action is not being called even though I place a console.log() call before that after line 188.
I have no errors con console and I don't know where to debug, it's strange. If I navigate to other routes and come back to the root one, it works, but not on first attempt.
Here's my code:
addRoute('#/home', $('#panel-home'));
addRoute('#/filosofia', $('#panel-philosophy'));
addRoute('#/servicios', $('#panel-services'));
addRoute('#/seminarios-y-talleres', $('#panel-workshops'));
addRoute('#/sobre-edith-lara', $('#panel-about'));
addRoute('#/contacto', $('#panel-contact'));
function addRoute(route, $element) {
Path
.map(route)
.to(function(){
$element.addClass('active');
})
.exit(function(){
$element.removeClass('active');
});
}
// Routing init.
Path.root("#/home");
Path.listen();
Path.js version 0.8.4
Error: Function.prototype.apply: argument is null or undefined
Possible fix: Line 180, remove null parameter:
result = Path.routes.defined[this.path].do_enter[i].apply(this);
After change works in IE8, IE9, Chrome 20, FF13 on Windows.
I have a route defined as
Path.map("#!/clients/:client/:campaign").to(mainFunc).exit(exitFunc);
If I go to something like this
#!/clients/geico/caveman
The exit event will never fire because its searching for #!/clients/geico/caveman
but only #!/clients/:client/:campaign
is around.
I have a web app (http://github.com/kdonald/graceworks) that is using pathjs client-side routing (hash fragments variety not push state). It is a multi-page mobile app. A back button is declared on each child page and when clicked we call window.history.back().
When testing in Chrome or another modern browser, everything works fine and in accordance with path.js documentation. For example, when you load the index page, the root route (#/) is fired. From there, when you activate links, other routes are fired as expected e.g (#/messages, #/messages/1, #/messages/1/parts/1)
However, when I wrap the web app's assets in a Phonegap/Cordova IOS project (native hybrid), I'm seeing strange behavior when invoking a back button on a child page of the root index page. Specifically, the back button on the child page, which invokes window.history.back(), does not work (nothing happens). Strangely, if I drill down 2-levels, for example, down from #/ to #/messages/ to #/messages/1 and back up to #/messages, the back button works fine. Once I try to back up to the root level (#/), the back button stops working completely.
So it seems something related to Path's root route implementation and the native IOS/Phonegap UiWebView is not playing together nicely. As an experiment, I tried Backbone's router as alternative. It seems to work fine with no issues, even backing up to the root index page.
You can see a running example of the strange behavior by cloning: http://github.com/kdonald/graceworks and then wrapping it in a Apache Cordova project as described here: http://docs.phonegap.com/en/1.8.1/guide_getting-started_ios_index.md.html#Getting%20Started%20with%20iOS.
You can see a Backbone example that works fully by cloning: https://github.com/ccoenraets/backbone-jquerymobile and wrapping it in a Apache Cordova project.
I also tried another routing framework (page.js) to see if it would work. Here's a issue tracking the results there: visionmedia/page.js#18.
So in summary, I'm unable to get pathjs to work properly as a client-side routing framework in a native IOS environment with Phonegap on a UIWebView. It nearly works flawlessly, but going back to the first page recorded in history doesn't work and once that is attempted back behavior doesn't work again until the app is restarted.
As a side note, I noticed a difference between Backbone's router and the PathJS router: backbone has you register a root route as "" and does not append any fragment to the URL when it is fired. PathJS has you note a specific route e.g #/ that should be the root route, and when the root page is loaded the fragment portion of the URL is updated (e.g. #/ is appended).
cc @brianleroux
Hi,
I'm trying to fix an issue, but I'm a little bit lost and maybe you thought about this already.
When you want to open a Path.js link in a new tab you can do it rightclicking in the link and selecting "Open In New Tab" in the Browser, but it's not working clicking on the link with the mousewheel at windows or doing Click + command on Mac OS X.
Do you know why is it happening?
Best regards!
Hi,
sorry for using an "issue" like this but can't find any contact info. How are you supposed to handle form posts? Can't find any route setup that will listen on POSTs.
//Daniel
After implementing pathjs on a site and seeing the rescue method being called for all paths, I checked the tests and they all fail in IE7.
When I map a URL to callback function, the params that are passed to the callback are URL-encoded in IE and Chrome. For example, "Hello%20World" remains "Hello%20World". But in Firefox, the param is not URL-encoded, it's "Hello World". I have to do a test like this:
var needsEncoding = decodeURIComponent(params['sentiment']) == params['sentiment'];
to figure out whether the param is encoded or not (I use it to build an AJAX URL). This seems to a problem with how Firefox handles spaces in URLs but it'd be nice if Path.js handled encoding consistently across all browsers.
When I've a path mapping like
Path.map("#/tab/:tabName(/:subTabName)(/#/params/:parameters)")
The partition method returns an array of three
["#/tab/:tabName",
"#/tab/:tabName/:subTabName",
"#/tab/:tabName/:subTabName/#/params/:parameters"
]
This is obviously missing one other possible route, which is
"#/tab/:tabName/#/params/:parameters"
That means when I have multiple optional parts specified, It does not consider scenarios where one or more of the initial parts being omitted.
Hello!
If I load a page with no hash, Path.root
is applied properly. However, hitting the back button produces the 404 error in Path.rescue
.
For reference, I can reproduce this problem by downloading the "advanced routing" example, loading the page, and then hitting the back button.
I'd expect this to once again show the default, or not go anywhere, since there is no path to be applied (we've went "back" to the default again).
I've worked around this by adding something into rescue
, but it's a bit clunky and annoying:
if( location.href.indexOf('#') < 0 ) {
// not a 404
Path.dispatch( Path.routes.root );
}
else {
// 404 handling code here
}
I'd consider this pretty low priority since there is a workaround, but also something that probably should be handled by Path.
Cheers,
Would there be a way to use pathJS with HTML5's pushState to keep the URLs clean? Thoughts?
Sorry, I know this is not the right place to post a question. I'm trying to use path.js in a project and I'm wondering how I can trigger a route, in other words navigate to a location programmatically, not using an HTML link.
Is calling Path.dispatch(hash) the way to do it? It seems to work (the route is mapped and the callback called) except that the location bar isn't updated. Could you help please?
There is currently no way to temporarily skip firing the event when navigating to a path. I have some code in my page that updates the hash manually via the results from an ajax call. This causes PathJS to fire AGAIN because the hash changed, which causes my code to update the hash, etc...
Since normal request are case insensitive, shouldn't the match also be case insensitive?
Easy fix:
In the match function, change
if (slice === compare) {
to
if (slice.toLowerCase() === compare.toLowerCase()) {
When attempting to load a site where Path is listening and a route is defined that is using a parameter in an optional part, like "#/projects(/:query)", the browser tab crashes, and with chrome at least, it mentions a script was using too much memory on the page. Am I making a mistake or is it Path?
Hey. Sorry, this is logged as an 'issue' not sure how to do it as a request.
Could you add a TypeScript definition file.
The wiki state that when running in HTML5 mode, there is no support for root route.
However there are scenarios when my web app is running at http://domain.com/app/
instead of http://domain.com/
Without the a way to define root route, when the html5 mode fallback to hash mode for browser like IE9, calling Path.history.pushState({}, '', '/app/route');
will update url to http://domain.com/app/#/app/route
, this is undesirable.
Is there a simple workaround for such issue?
It would be very useful to allow the exit function to halt execution in the same fashion the enter function can halt execution. For example, if the user is currently on a form view editing an entity, then leaves that view without saving, the exit function could be used to prompt the user to verify that they want to discard their changes before proceeding to the next route. This scenario makes more sense to me than using an enter function for that purpose because I can co-locate the code that defines the route and the code that verifies discarding changes.
I'm having trouble with routes that are deeper than 2 layers.
For example, i want
site.com/users
site.com/users/friends
site.com/users/friends/friend-3
Is it possible to have users/friends inherit the enter / exit functions from user?
Any ideas?
The test included with the script fails on Android 2.3.3. I compared the Expected and Actual strings and the first two tokens, F[enter] and F[action], are not present in the Actual string.
This test confirms a problem I had where functions were not executed when browsing to the root of the webapp with an Android 2.3.3 device.
Documentation shows support for IE7 but the test page does not work.
http://mtrpcic.github.com/pathjs/hashtag_basic.html
http://mtrpcic.github.com/pathjs/html5_basic.html
this doesn't seem to fall back to hash routes in IE9
Hello!
Thanks for this awesome lib. It's working wonderfully with my knockout.js code base.
However, I'm running into a little snag with Bootstrap subnav menus, which also use the #hashtag syntax to activate in-page bookmarks (i.e. scroll the browser down the page).
I've figured out how to filter these out from the errors generated in Path.rescue
(by using this.current
to check against the subnav hashtags). I've also discovered that I can even make a preemptive strike with something like:
Path.map("#subnavOption").to( function(){} ).enter( function(){return false;} );
However, the bookmarks still modify the URL, of course, which in turn causes routing issues when the page is refreshed or the back/forward buttons are used (since the Pathjs routes are disrupted in this way).
If a solution already exists, sorry for taking up some of your precious time. I did give the docs and source a good perusal, as well as the open issues.
If not, I was thinking that based on the above, I could probably solve it by utilizing a combination of jQuery code and the enter()
function like so:
// all anchor tags beginning with # inside a .subnav
var $bookmarks = $('.subnav a[href^=#]');
function _target( href ) {
return ( href.match(/^#([a-zA-Z0-9_-]+)$/) || [] ) [1];
}
$bookmarks.each(function() {
var $this = $(this);
// disable Path processing
Path.map( $this.attr('href') ).to( function() {} ).enter( function() { return false; } );
// create our own bookmark scrolling
$this.click(function(e) {
e.preventDefault();
var target = _target( $(this).attr('href') );
// probably only works if $(target) has position: relative/absolute
// should probably also pad this a bit so the line isn't directly at the top
$(this).scrollTo( $(target).offset().top );
});
});
However, this would have to occur before the Path.listen() code is run, I presume?
Am I missing anything more obvious or elegant to prevent these bookmarks from contaminating the URL history?
Hey Mike,
Thanks for puting this together. I am using it on a site where I want to have Google Analytics attached to each 'page'. It was of course very simple with the AoP components, though I had to call GA slightly differently.
_gaq.push(['_trackPageview', document.location.href])
instead of:
_gaq.push(['_trackPageview'])
Then I just added an on enter block to handle the logging. I think GA is a common enough thing to use, that it might be worthwhile to include some simple instructions like this in the markdown.
Thanks Mike!
Jeff
This would help DRY out some code so that someone doesn't have to duplicate route maps.
For example ( this is how ExpressJS does it on the server side ):
Path.map("#/venues/:sortorder?").to(function{
// Then we can do stuff like fn(this.params['sortorder'] || 'default');
});
I would happily fork it and submit the changes to make this work, however my javascript-fu is weak. Looking at the code, I couldn't tell how easily this could be accomplished. So this is just a feature request.
Discovered this issue on OS X Leopard with Safari 5.0.5. The bug occurs as long as any other network traffic is active on the page (common with Facebook or Google Analytics API). Here's an in-depth description of the issue and a JQuery work around. I'm going to use almost the same work around in my site (regrettably) rather than modify PathJS (0.8.3). Hope this info is useful and we can come up with a better solution in PathJS.
Having access to the params hash inside the enter callback would be awesome. I don't think it is possible to access this currently. Correct?
In some previous documentation it seemed like there a default function you could set if no paths matched. I want to use this but it seems to be missing in the current version. I tried using rescue for this but it doesn't work in the same way (doesn't set the window location)
Is there any way to apply a default function to all paths?
Maybe one way to do this is to include the same wildcard functionality as in rails routes using *
Path.map("/*path")
hi.
thanx for nice work.
how i can programmatically change a hash param?
for example url=http://test.com/#/Home/Index/25/26/27
i want change 25 to 100 programmatically.
thanx
On http://mtrpcic.github.com/pathjs/html5_basic.html there is an instruction to view the source of the page to see what's going on. That won't work in Chrome after clicking on any of push state links, eg Users.
View source in Chrome opens a new tab to a view source url, for example:
view-source:http://mtrpcic.github.com/users
This does a request for http://mtrpcic.github.com/users
, then shows the source of the GitHub 404 page.
The path
/(:page_1)(/)(:page_2)/
Should match
/
/link/
/link/link/
but doesn't.
Is this a bug or a limitation.
Is there any way to trigger a hashchange without a click?
I want to execute a function if the url matches the defined wildcard structure. For example, I want to run alert("hello world") if the url matches any of these: http://example.com/foo/x, http://example.com/foo/y, http://example.com/foo/z. I don't want to write this code for every route. Is there something like
Path.map("#/foo/*").to(function() {
alert("hello world");
});
?
Thanks
I have a route defined as "#/search/templates/:term".
When I navigate to "#/search/templates/t" I get a 'NotFound' call, but when I navigate to "#/search/templates/tt" I correctly land in my handler.
This is my setup:
Path.map("#/new").to(CT.ShowNew).enter([CT.ResetNav]).exit(CT.HideNew);
Path.map("#/search/templates/:term").to(CT.ExecuteSearchTemplates).enter([CT.ResetNav, CT.ShowSearch, CT.ShowSearchTemplates]).exit(CT.HideSearch);
Path.map("#/search/templates").to(CT.ShowSearchTemplates).enter([CT.ResetNav, CT.ShowSearch]).exit(CT.HideSearch);
Path.map("#/search/users").to(CT.ShowSearchUsers).enter([CT.ResetNav, CT.ShowSearch]).exit(CT.HideSearch);
Path.map("#/search/groups").to(CT.ShowSearchGroups).enter([CT.ResetNav, CT.ShowSearch]).exit(CT.HideSearch);
Path.map("#/search").to(CT.ShowSearchTemplates).enter([CT.ResetNav, CT.ShowSearch]).exit(CT.HideSearch);
Path.root("#/search");
Path.rescue(CT.NotFound);
And this is how i'm setting the url:
$("#search-templates-field").on("change", function()
{
window.location.href = "#/search/templates/" + $(this).val();
});
I Agree that its a fair assumption, but I had to write a workaround for this for my scenario.
The simple scenario is that my tabs are hierarchical in naming.
I'm attaching the workaround i currently use in the match function. I know it is not the best code, but it works.
It'd be great if you could support this by default.
'match': function (path, parameterize) {
var params = {}, route = null, possible_routes, slice, i, j, compare;
for (route in Path.routes.defined) {
if (route !== null && route !== undefined) {
route = Path.routes.defined[route];
possible_routes = route.partition();
for (j = 0; j < possible_routes.length; j++) {
slice = possible_routes[j];
compare = path;
if (slice.search(/:/) > 0) {
for (i = 0; i < slice.split("/").length; i++) {
if ((i < compare.split("/").length) && (slice.split("/")[i].charAt(0) === ":")) {
params[slice.split('/')[i].replace(/:/, '')] = compare.split("/")[i];
compare = compare.replace(compare.split("/")[i], slice.split("/")[i]);
}
}
}
if (slice === compare) {
if (parameterize) {
route.params = params;
}
return route;
}
}
}
}
if (parameterize) {
var maxMatchedRoute = null, maxMatches = 0,
arr2 = path.split('/');
for (route in Path.routes.defined) {
if (route !== null && route !== undefined) {
var arr1 = route.split('/');
if (arr2.length < arr1.length) {
continue;
}
var len = arr2.length;
var matches = 0;
for ( var i = 0; i < len; i++) {
var ele1 = arr1[i], ele2 = arr2[i]
if (typeof ele1 !== "undefined"
&& typeof ele2 !== "undefined"
&& ele1 === ele2) {
matches++;
}
}
if (matches > maxMatches) {
maxMatches = matches;
maxMatchedRoute = route;
}
}
}
if (maxMatches) {
var pathArray = maxMatchedRoute.split('/');
var i = 0, last = null;
for (i = maxMatches; i < pathArray.length; i++) {
var slice = pathArray[i];
if (slice.charAt(0) !== ':') {
return null;
}
last = slice.substr(1);
params[last] = arr2[i];
}
while (i < arr2.length) {
params[last] += '/' + arr2[i];
i++;
}
Path.routes.defined[maxMatchedRoute].params = params;
}
return Path.routes.defined[maxMatchedRoute];
}
return null;
}
Thanks,
Sujay
This may be out of your hands, but I'm using Path for an app that's designed to be used on mobile devices and I'm running into an odd issue with mobile Safari on iOS 5.
I have my root set with Path.root("#/home")
If I navigate to my site foo.com, I get taken to foo.com/#/home. Everything is gravy. However, if I navigate to a new page and then use the browser back button, I get taken back to foo.com without the hash at the end. It seems that the hash isn't getting written to the history. This works on other normal browsers. However, I was encountering the exact same bug on normal Safari for Mac. The fix seemed to be binding an empty function to the window.onunload event forcing the page to refresh every time the page is reloaded.
window.onunload = function(){};
This fixes the problem for desktop Safari and mobile Safari for iOS 4, but in 5, the problem remains.
Wondering if there's a potential fix to be made in Path to compensate for this or if the problem is too deep in Safari to fix.
Thanks for your help!
When using the HTML5 history mode, like in the "HTML5 Basics" example at http://mtrpcic.github.com/pathjs/html5_basic.html,
the initial page load also triggers a Path dispatch. I realise that in a lot of cases this is desirable, but I feel there should be a way to disable this.
A common use case for Path is using it to catch links out and replace them with ajax requests that replace partial content: The initial page is rendered fully and every subsequent click on a link fetches just the content that is new.
However, if you use Path in HTML5-mode, it also triggers an AJAX request for the first request, essentially causing duplicate work. Of course there are ways to hack around this, but it seems to me there should be a more elegant way to solve this.
I have given a simple example below. On the first visit of /pages/test, it says "loading..." and fires off an XHR to /partials/test. This is unnecessary, as the content of /pages/test already contains what it needs prerendered by the server.
Path.map("/pages/:page").to(function(){
$("#content").html("loading...");
$.ajax({
url: "/partials/"+this.params["page"],
timeout: 2000,
success: function(data) {
$("#content").html(data)
}
});
})
$(document).ready(function(){
Path.history.listen();
$("a").click(function(event){
event.preventDefault();
Path.history.pushState({}, "", $(this).attr("href"));
});
})
In Chrome when I load any of the example URLs I get a nasty in the console and the demo will not function...
Refused to execute script from 'https://raw.github.com/mtrpcic/pathjs/master/path.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
This is very important feature for bulding routes map dynamicly from array. I propose
'core': {
'route': function (path) {
this.path = path;
this.context = this,
this.action = null;
this.do_enter = [];
this.do_exit = null;
this.params = {};
Path.routes.defined[path] = this;
}
Path.core.route.prototype = {
'to': function (fn, context) {
this.action = fn;
this.context = context;
return this;
},
Path.routes.defined[this.path].action.apply(this.context, [this.params]);
And you can define route handler as Path.map('"#route").to(function(){}, context)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.