$ cnpm install websitejs
Library to run a Multi-Page-Content-Website as a Single-Page-Application.
It's like a static site generator that runs in your browser.
npm install websitejs
bower install websitejs
Or use a file from the /dist
folder directly.
The website.bundle.js
build is a basic, working website with:
website.js is a framework for running multi-page content websites as a Single-Page-Application.
It handles the lifecycle and essential tasks of a multi-page website:
Using plugins and events, website.js is easy to extend and customize the above tasks.
Included plugins:
There is one special plugin: The Core Plugin.
The Core Plugin handles the flow of the website:
created(options)
, fetch the website data with getData(callback)
gotData(data)
, check data.sitemap
for urls.gotDataForUrl(url,pageData)
for every url to populate the router.navigated
,getContent(id,callback)
to fetch contentgotContent(id)
to transform contentrender(pageData)
the pagerendered(pageData)
do stuff after renderingrendered /your/url(pageData)
do stuff after rendering a specific URL.var site = new Website({
router: {
html5: false, // defaults to true, if browser supports it
base: '/example', // base url, all navigation is relative to this url
},
core: { ... } // Override the core plugin (optional)
plugins: [ // Add plugins
Website.plugins.http,
Website.plugins.firebase,
Website.plugins.markdown,
Website.plugins.render,
Website.plugins.log
],
// plugins often add more options!
})
// navigate programatically to a url
site.navigate('/page1');
// re-render current url/route
site.refresh();
site.refresh(0); // re-render current URL after all events have fired.
site.refresh(100); // re-render current URL after 100 ms.
// Content that has been fetched (useful to transform content after a `gotContent` event)
site.content[id];
// listen to website' events (see below)
site.on(eventName,function(...){
// `this` is the website instance
})
site.once(eventName,function);
site.off(eventName,function);
Events are fired roughly in the following sequence:
When creating new Website:
created(options)
gotDataForUrl(url,pageData)
gotData(data)
When navigating:
navigated(url)
gotContent(id)
- this is called for every idrender(pageData)
rendered(pageData)
renderer [url](pageData)
Note that gotContent(id)
only has the id
. Use this.content[id]
to access the content.
A plugin is an object that listens to events. Simply use eventNames as attributes. For example, the MarkdownPlugin transforms content into markdown:
var MarkdownPlugin = {
gotContent: function(id){
if(this.markdownFilter(id)){
this.content[id] = marked(this.content[id]);
}
},
// created: function(options) { /* initializes the markdownFilter */ }
// etc
};
In addition to the events, plugins allow two extra methods:
{
getData: function(callback){
// fetch your data
callback(err,data);
},
getContent: function(id,callback){
// fetch your content
callback(err,content)
}
}
The Core Plugin handles the lifecycle of the website: On navigation, fetch and render content.
So you must specify the urls of your website, and what content to fetch for every url.
To do this, getData
follows a convention:
data.sitemap
contains a map from url
to pageData
.pageData.content
is an string (contentId) or an object ({name:contentId,name:contentId}
).render(pageData)
is called with page metadata, only contentId has been replaced with actual content.You still need to provide plugins for
getData(callback)
getContent(id,callback)
render(pageData)
Site metadata (Example):
var data = {
sitemap: {
'/page1': {
title: 'Page 1',
content: 'page1.md'
},
'/page2': {
title: 'Page 2',
content: {
sidebar: 'sidebar.md',
content: 'page2.md'
}
}
}
// + other site data
}
Configure http with a content and data url:
new Website({
http: {
content: location.origin + '/example/content/',
data: location.origin + '/example/site.json',
}
})
Configure Firebase with a content and data url:
new Website({
firebase: {
content: 'https://YOURFIREBASE.firebaseio.com/content/',
data: 'https://YOURFIREBASE.firebaseio.com/data/',
}
})
Firebase is comes in two flavours: Live and REST.
The plugin automatically creates a correct URL for the REST API (i.e. append .json
).
Note: Firebase does not allow .
or /
in keys. Therefore, when saving data to firebase, you must use -dot-
and \
. When retrieving the sitemap and content, these are automatically converted back to .
and /
.
Renders pageData.content
as follows:
{#elementId: content}
: Inserts content into element with #elementIdNote: The #layout
element is always rendered first, allowing you to specify a layout first, then render blocks of content in that layout.
Example:
content = {
"layout":"sidebar-layout.html",
"sidebar":"navigation.html",
"content":"blog-about-javascript.md"
}
You can write a custom Render plugin as follows:
var MyCustomRenderer = {
render: function(pageMetadata){
// `this` is the Website instance
pageMetadata.url // route (normalized url)
// url parameters
pageMetadata.params
// content (the contentId has been replaced with actual content)
pageMetadata.content
}
}
// later:
var website = new Website(plugins: [ MyCustomRenderer ] })
// or
website.addPlugin(MyCustomRenderer)
The Markdown Plugin parses all content as Markdown.
If you want, you can specify a filter (i.e. which content id need to use Markdown?)
new Website({
// Filter using a string (content-id must contain this string)
markdown: '.md',
// Filter with a Regex
markdown: /.md$/,
// Filter with a function
//
// imagine you have the following Site metedata:
// data.markdown = ['pagea','pageb']
markdown: function(id){
return this.data.markdown.indexOf(id) >= 0;
}
})
Uses the fast and efficient doT template engine.
On gotContent
, compiles the template. On render
, renders the template with your page metadata.
If you want, you can specify a filter (see above)
new Website({
template: {
filter: '.tmpl' // string, regex or function
}
})
Caches sitemap and content in IndexedDB, WebSQL or localStorage using localForage
// live-update your site:
site.setData(data)
site.setDataForUrl(url,data)
site.setContent(id,content);
// Manually get data or content:
site.getData(callback), callback(err,data);
site.getContent(id,callback), callback(err,content);
site.getContent({name:id,name:id}), callback(err,{name:content,name:content})
0.2.0: 12/1/2015
bundle
build with everything included.0.1.0: 9/1/2015
First release. Implementation and API are probably relatively stable now.
Feel free to contribute to this project in any way. The easiest way to support this project is by giving it a star.
© 2014 - Mark Marijnissen
Copyright 2014 - 2017 © taobao.org |