finnsson / pagerjs Goto Github PK
View Code? Open in Web Editor NEWThe Single Page Application Framework for KnockoutJS
Home Page: http://pagerjs.com/
License: MIT License
The Single Page Application Framework for KnockoutJS
Home Page: http://pagerjs.com/
License: MIT License
Something like pager.start("id") would be nice!
A page should be able to access the information in the current route - changing a view-model.
Sending parts of the fragment identifier to variables in the view-model is possible using
params
.
<div data-bind="page: {id: 'search', params: {'name', 'fromdate'}}">
<span data-bind="text: name"></span> (<span data-bind="text: fromdate"></span>)
</div>
where name
and fromdate
with be bound by the parameters name
and fromdate
.
An example route for the example above could look like
example.com/#search/tv?name=samsung&fromdate=20121010
or if HTML5 history is used
example.com/search/tv?name=samsung&fromdate=20121010
When a child page is removed and later a page with the same page is added the newly added child page should be visible.
<div data-bind="page: {id: 'admin'}"></div>
<!-- The page below match anything except 'admin' -->
<div data-bind="page: {id: '?'}"></div>
IE8 throws an error due to Date.now not existing.
Should have
if (!Date.now) {
Date.now = function() {
return new Date().valueOf();
};
}
At the head of pager.js
Is it just me or does the demo not work in IE7? I can go to different hashes, but the content on the page is not reflected.
<div data-bind="page: {id: 'lazyLoremCached', sourceOnShow: 'lorem.html .content', sourceCache: true}"></div>
<ul class="nav nav-tabs" data-bind="foreach: $page.children">
<li data-bind="css: {active: isVisible}"><a data-bind="text: $data.getValue().title, page-href: getId()"></a></li>
</ul>
<div data-bind="page: {id: 'Slagsmålsklubben', title: 'Slagsmålsklubben', sourceOnShow: 'https://embed.spotify.com/?uri=spotify:album:66KBDVJnA6c0DjHeSZYaHb', frame: 'iframe'}" class="hero-unit">
<iframe width="300" height="380" frameborder="0" allowtransparency="true"></iframe>
</div>
<div data-bind="page: {id: 'Binärpilot', title: 'Binärpilot', sourceOnShow: 'https://embed.spotify.com/?uri=spotify:album:67LKycg4jAoC06kZgjvbNd', frame: 'iframe'}" class="hero-unit">
<iframe width="300" height="380" frameborder="0" allowtransparency="true"></iframe>
</div>
<div id="start" data-bind="page: {id: 'start'}">
<a href="#user/fry">Go to Fry</a>
</div>
<div id="user" data-bind="page: {id: 'user'}">
<div id="fry" data-bind="page: {id: 'fry'}">Fry</div>
</div>
An example would be validation.
If validation fails, you do not want the transition to be performed.
It would be nice if the items that are passed to the event include the current page and the page the user is attempting to navigate to.
If this is the navigate to backlog item then please ignore.
<div>
<div data-bind="page: {id: 'bar'}">Bar</div>
<!-- Foo is displayed -->
<div data-bind="page: {id: 'start'}">Foo</div>
</div>
<div data-bind="page: {id: 'start'}">
<!-- This will update href to #start/bender -->
<a data-bind="page-href: 'bender'">Bender</a>
<!-- This will update href to #admin/login -->
<a data-bind="page-href: '../admin/login'">Admin Login</a>
<div data-bind="page: {id: 'bender'}">Bender!</div>
</div>
<div data-bind="page: {id: 'admin'}">
<div data-bind="page: {id: 'login'}">Login</div>
</div>
Based on the total path of the page the binding calculates an absolute href.
<div data-bind="page: {id: 'start'}">
<a href="#user/leela">Go to Leela</a>
</div>
<div data-bind="page: {id: '?'}">
Misc:
<div data-bind="page: {id: 'leela'}">
Leela
</div>
</div>
In running the demo from a local server using the following procedure:
cd
into demo dir of repo (fork) clonepython -m SimpleHTTPServer
http://localhost:8000/#guards
All pages seem to work fine except http://localhost:8000/#recapitulation
which renders sections weird
Compared to correct rendering on your server http://oscar.finnsson.nu/pagerjs/demo/#recapitulation
In playing with demo page Lazy Load External Content (on a local server since online demo is currently out of sync with repo content (e.g., missing CSS class linenums
)), despite having CSS classes prettyprint linenums
, line numbers are not shown. If I manually run prettyPrint()
in the console it works right. If I add page
property callback source: prettyPrint()
, it also doesn't work. Using an instrumented callback in source
, it looks like refresh of the page triggers calling the callback twice which seems like another bug? Is this a known limitation / working-as-designed / user error?
An example application of using pager.js together with History.js can be found in boilerplate
.
Current (0a1f5b0bc15f4731345e88920a64093c63b4a335
) pager.js
causes
Uncaught TypeError: Object #<Object> has no method 'start'
for standard initialization code, while dist/pager.min.js
works (this was somewhat difficult to track down). I prefer to use pager without requirejs
.
The knockoutjs mapping plugin and ko.toJS function doesn't work. I was able to figure out that it is trying to convert the property added to the object by pagerjs and eventually causing javascript to run out of memory and throw an error.
<!-- x and y are now available as observables, but only in the view (not the view-model) -->
<div data-bind="page: {id: 'foo', vars: ['x','y']}">
<span data-bind="text: x"></span>
<span data-bind="text: x"></span>
</div>
This is useful for effects that has nothing to do with the view-model.
When doing pager.start(id) the pager.Href.hash is not applied to the new window.location. I don't know about the rest of the start methods.
Two new bindings should be created.
page-hash for normal hash handling and page-href5 for html5 history.
The current page-href should be either one - depending on configuration (pager.useHTML5history)
my mistake completely. works as intended.
Don
have a great day
Since pager is not responsible for listening on the location it is possible to
circumvent the routing using the router used. Just do not use pager.start
.
In order to facilitate programming in the large it is useful to be able to extract views as separate components.
These views should not be forced to be stored as html-fragments or be loaded with jQuery.
Thus a way to inject custom views should be possible. This is done using the source
- or
sourceOnShow
-properties. Just supply a method instead of a string!
These properties takes a method that should take a pager.Page
as first argument, a callback, and return nothing.
<div data-bind="page: {id: 'zoidberg', sourceOnShow: requireView('character/zoidberg')}" />
where
window.requireView = function(viewModule) {
return function(page, callback) {
require([viewModule], function(viewString) {
$(page.element).html(viewString);
callback();
});
};
};
if
// file: character/zoidberg.js
define(function() {
return '<h1>Zoidberg</h1>';
});
Firstly, thanks for your job, it's good idea and implementation.
I'm trying to implement following scenario:
in the main page only one "navigation node"
<div data-bind='page: {id: '?', sourceOnShow: '{1}.html'}'><div>
each loaded element have own navigation... for example into modal view.
Problems:
Maybe it's wrong way, but looks like it's should work.
thanks.
First, thanks for creating a really nice library!
It would be nice to have access to the Page object when dynamically fetching viewmodels in "withOnShow". I modified the source for withOnShow to pass "this", just like you are currently doing for sourceOnShow:
I replaced
572 - }, this));
572 + }, this), this);
This allow me to retrieve specific data for my views based on the route, eg
http://domain.name.com/order/56
<div data-bind="page: {id: '?', withOnShow: MyNamespace.Order.GetModel()}"></div>
MyNamespace.Order = {
GetModel: function () {
return function (callback, page) {
$.getJSON('/api/orders/' + page.currentId, function (data) {
var viewModel = new MyNamespace.Order.ViewModel(data);
callback(viewModel);
});
};
}
};
Off course, ability to use wildcards would be even better, to say something like:
<div data-bind="page: {id: '?', withOnShow: MyNamespace.Order.GetModel({1})}"></div>
But I don't think this is an easy addition? However, I hope you will consider adding the page parameter as described above.
I noticed when I open a tab and paste a URL (e.g., http://oscar.finnsson.nu/pagerjs/demo/#guards) it doesn't fully render -- only the header and footer show -- until I reload the page (tried on Firefox 15 and Chrome 22 on OS X). Is this expected behavior?
<div data-bind="page: {id: 'start'}">
<a href="#user/fry">Go to Fry</a>
</div>
<div data-bind="page: {id: 'user'}">
User:
<!-- {1} will be replaced with whatever matched the wildcard -->
<div data-bind="page: {id: '?', sourceOnShow: 'user/{1}.html'}">
</div>
</div>
The effects zoom, flip, fade and slide.
<a href="some/other/url">Go to some/other/url.html</a>
<div data-bind="page: {id: '?', deep: true, sourceOnShow: '{?}.html'}>
</div>
<div data-bind="page: {id: 'user', with: user}">
<!-- Here name is user.name -->
<div data-bind="text: name"></div>
</div>
<div data-bind="page: {id:'start'}">
<a href="#foo">Go to foo</a>
</div>
<div data-bind="page: {id: 'foo'}">
Foo. Go to <a href="#start">start</a>
</div>
If a page-href-binding is feed with a page-instance the URL to the page is automatically calculated.
<!-- An iframe will be created inside the div -->
<div data-bind="page: {id: 'user', frame: 'iframe', source: 'user.html'}"></div>
<!-- The iframe specified will be used -->
<div data-bind="page: {id: 'fry', frame: 'iframe', source: 'fry.html'}">
<iframe sandbox=""></iframe>
</div>
<div data-bind="page: {id: 'lazyLorem', sourceOnShow: 'lorem.html .content'}"></div>
sourceOnShow
tells the page to load the content when the page is displayed.
<div data-bind="page: {id: 'foo'}">
<div>
<span data-bind="page-child: 'name'"/>
<span data-bind="page-child: 'age'"/>
</div>
</div>
Now name
and age
are available in the Page
-instance under the elementChildren
-observable, e.g. this.elementChildren().name()
and this.elementChildren().age()
.
<div data-bind="page: {id: 'lorem', source: 'lorem.html .content', sourceLoaded: loremIsLoaded}"></div>
The source can contain a selector (see .content
above) in order to extract a fragment on the site.
In the example above loremIsLoaded
is a function that is triggered after lorem.html
is loaded.
Guards are methods that are run before the page navigation takes place and
that can stop the navigation from displaying a certain page.
Use the property guard: someMethod
do apply the guard. The method
takes three parameters: page, route and callback. If the callback is called
the navigation takes place - otherwise it is stopped.
<div data-bind="page: {id: 'admin', guard: isLoggedIn}">
This page is only accessible if the user is logged in.
</div>
where
isLoggedIn: function(page, route, callback) {
if(viewModel.loggedIn()) {
callback();
} else {
window.location.href = "login";
}
}
Use cases are login, validating steps in state machines, etc.
The reason the guard takes a callback as third argument is simply because the guard might be async - accessing
a webserver for login details or asking if a valid shopping card exists etc.
It is possible to create custom widgets that jack into the pager-system.
The page
-binding (pager.Page
-class) is possible to extend at multiple points.
One custom widget (page-accordion-item
) is already implemented.
<div data-bind="page: {id: 'employee'}">
<div data-bind="page-accordion-item: {id: 'zoidberg'}">
<a href="#employee/zoidberg">Dog</a>
<div>Zoidberg Information</div>
</div>
<div data-bind="page-accordion-item: {id: 'hermes'}">
<a href="#employee/hermes">Cat</a>
<div>Hermes Information</div>
</div>
</div>
pager.js should at the moment not depend on underscore.js since most things can be solved with jQuery.
<div data-bind="page: {id: 'user', withOnShow: someMethod('someMethod')}"></div>
someMethod
must return a function that takes a callback that takes a view model.
E.g.
function requireVM(module) {
return function(callback) {
require([module], function(mod) {
callback(mod.getVM());
});
};
}
<div data-bind="page: {id: 'lazyLoremCached5seconds', sourceOnShow: 'lorem.html .content', sourceCache: 5}"></div>
sourceCache
can specify the amount of seconds the external content should be cached.
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.