TrochaJS
It’s a standalone javascript library that describe route listing. Ideal for client-side route management (SPAs and XHR/Ajax async request) and NodeJS route declaration.
see our Hello World code example to lear more.
What it does
print clean routes for your javascript projects and even help <your favorite>
(framework/set of libraries) to describe your app routes.
What it does not
handle route/view for your app nor framework.
See vanilla implementation or Angular 1.X implementation.
98 - Why this library exist
Ugly code example
theRoute = "https://my.domain.com.co/product/" +
myProduct.id +
"/buy" +
"?quantity=" +
sell.quantity;
theRoute = "https://my.domain.com.co/product/"+
myProduct.id+
"/buy"+
"?quantity="+
sell.quantity
Nice target code example
theRoute = myRoutes.product.buy.path( {
product_id: myProduct.id,
query: {quantity: sell.quantity}
});
theRoute = myRoutes.product.buy.path
product_id: myProduct.id
query: quantity: sell.quantity
This library take inspiration from Ruby on Rails routing system, where you describe the routes via a simple name tree and call those routes via dinamic function naming, preventing use of string in views and controllers.
99 - Contributing
You can help me with this documentation editing/translating here, or reporting issues here, or improve the source code here.
100 - Basics
101 - Intro to Trocha JS
Get a copy of the library via npm
npm i trocha
Insert the library within your page
<body>
...Your page tags
<script src="https://<aCDN>/trocha/0.2.0/dist/trocha_library.min.js"></script>
...Your other scripts
</body>
Or via ES6 modules
import {Trocha} from 'trocha'
import {Trocha} from 'trocha'
Now define routes
var myRoutes = new Trocha({
routes:{
hello:{
$id: "name"
}
}
});
myRoutes = new Trocha
routes:
hello:
$id: "name"
finally print the routes
console.log(myroutes.hello.path());
console.log(myroutes.hello.path({name: "World"}));
console.log myroutes.hello.path()
console.log myroutes.hello.path name: "World"
This will print:
/hello/:name
/hello/World
Welcome to Trocha JS routes engine, the main goal of this library is to prevent use of annoing/unmantenible strings in sources(JS) and markup(HTML) files of your big projects.
This library does not depend of any other library/framework but can be integrated in those (React/Vue/Angular/Vanilla for example), also can be used on node and any mayor browser.
102 - Defining routes
You can define routes tree with a simple JSON when initialize or after that with a method, please see Best practices and Type of routes for depper explanation
Via JSON constructor
const myRoutes = new Trocha( {
routes: {
index: {
$hide: true
},
contact: {},
hello: {
$id: "name"
},
crud: {
$type: Trocha.RESOURCE,
$id: "crud_id"
},
faq: "/FrequentlyAskedQuestions"
}
});
myRoutes = new Trocha
routes:
index:
$hide: true
contact: {}
hello:
$id: "name"
crud:
$type: Trocha.RESOURCE
$id: "crud_id"
faq: "/FrequentlyAskedQuestions"
This should generate:
# an empty string return index
/contact
/hello/:name
/crud # get = list
/crud/new # get = view for create
/crud/:crud_id # get = show
/crud/:crud_id/edit # get = view for update
/FrequentlyAskedQuestions # via myRoutes.faq
This is the recomended way to define your routes tree, when create your trocha object simply add a routes
object tree.
Note the $
prefix this is used to separate trocha especific inputs of route names, this can be change see Route definition parameters.
Via method
let myRoutes = new Trocha();
myRoutes._newRoute({
name: "hello",
id: "name"
});
myRoutes._newAlias({
name: "faq",
alias: "/FrequentlyAskedQuestions"
});
myRoutes = new Trocha()
myRoutes._newRoute
name: "hello"
id: "name"
myRoutes._newAlias
name: "faq"
alias: "/FrequentlyAskedQuestions"
This should generate:
/hello/:name
/FrequentlyAskedQuestions # via myRoutes.faq
This route definition mode can be used in any part of the code, also is usefull to change a route definition.
Avoid this way, please see Best practices for depper explanation.
103 - Printing routes
See 101’s Via JSON constructor this is a continue of this example
myRoutes.index.path();
myRoutes.contact.path();
myRoutes.hello.path({name:"World"});
myRoutes.crud.list.path();
myRoutes.crud.new.path();
myRoutes.crud.show.path({
crud_id:"ASD",
query:{guest:"true"}
});
myRoutes.crud.edit.path();
myRoutes.faq.path();
myRoutes.index.path()
myRoutes.contact.path()
myRoutes.hello.path name: "World"
myRoutes.crud.list.path()
myRoutes.crud.new.path()
myRoutes.crud.show.path
crud_id: "ASD"
query: guest: "true"
myRoutes.crud.edit.path()
myRoutes.faq.path()
This should generate:
# Empty string
/contact
/hello/World
/crud # get = list
/crud/new # get = view for create
/crud/ASD?guest=true # get = show
/crud/:crud_id/edit # get = view for update
/FrequentlyAskedQuestions # via myRoutes.faq
To print any of your routes simply use path()
function at the end of the route.
See Route printing parameters
200 - API
201 - Type of routes
There are 4 type of routes (see Constants):
Route
const myRoutes = new Trocha( {
routes: {
person: {
$id: "name",
$hide: true,
attributes: {}
}
}
});
//OR
let myRoutes = new Trocha();
myRoutes._newRoute( {
name: "person",
hide: true,
id: "name"
});
myRoutes.person._newRoute( {
name: "attributes"
});
myRoutes = new Trocha
routes:
person:
$id: "name"
$hide: true
attributes: {}
#OR
myRoutes = new Trocha()
myRoutes._newRoute
name: "person"
hide: true
id: "name"
myRoutes.person._newRoute name: "attributes"
This should generate:
/:name
/:name/attributes
The simplest and base for any other type, it represent: <name>/[:<id>]
(id
is optional).
- Can be create by an empty object
<name>: {}
, no type is require. - Can be parent of any type of route.
- Can be a mute route via
$hide: true
.
Resource
const myRoutes = new Trocha( {
routes: {
products: {
$type: Trocha.RESOURCE,
$id: "product_id"
}
}
});
//OR
let myRoutes = new Trocha();
myRoutes._newResource( {
name: "products",
id: "product_id"
});
myRoutes = new Trocha
routes:
products:
$type: Trocha.RESOURCE
$id: "product_id"
#OR
myRoutes = new Trocha()
myRoutes._newResource
name: "products",
id: "product_id"
This should generate:
/products # list of
/products/new
/products/:product_id # show of
/products/:product_id/edit
Is a configurable set of routes, ideal for CRUD routes:
- It require an
ID
- The default routes are (useful for views POV):
list(): <name>
new(): <name>/new
show({id}): <name>/:<id>
edit({id}): <name>/:<id>/edit
This kind of routes is useful also for RESTful request
Custom resource
apiResource = new Trocha.$RESOURCE; // Note the $, this is an object not the String
delete apiResource.new;
delete apiResource.edit;
delete apiResource.show;
apiResource.list = {$id: false}; // Override/Remove $hide: true
apiResource.create = {$hide: true, $id: false, $method: Trocha.POST};
apiResource.read = {$hide: true};
apiResource.update = {$hide: true, $method: Trocha.PATCH};
apiResource.delete = {$hide: true, $method: Trocha.DELETE};
serverRoutes = new Trocha( {
domain: 'https://myRESTfulAPI.net.co',
post: '.json',
alwaysPost: true,
alwaysUrl: true,
// customSelector: 'ñ',
routes: {
products: {
$type: Trocha.RESOURCE, // Note this is String
$id: 'product_id'
$resource: apiResource
}
}
});
apiResource = new Trocha.$RESOURCE # Note the $, this is an object not a String
delete apiResource.new
delete apiResource.edit
delete apiResource.show
apiResource.list = {$id: false} # Override $hide: true
apiResource.create = {$hide: true, $id: false, $method: Trocha.POST}
apiResource.read = {$hide: true}
apiResource.update = {$hide: true, $method: Trocha.PATCH}
apiResource.delete = {$hide: true, $method: Trocha.DELETE}
serverRoutes = new Trocha
domain: 'https://myRESTfulAPI.net.co'
post: '.json'
alwaysPost: true
alwaysUrl: true
# customSelector: 'ñ'
routes:
products:
$type: Trocha.RESOURCE # Note this is String (whitout the $ prefix)
$id: 'product_id'
$resource: apiResource
This should generate:
https://myRESTfulAPI.net.co/products/list.json # list with method get
https://myRESTfulAPI.net.co/products.json # create with method post
https://myRESTfulAPI.net.co/products/:product_id.json # read with method get
https://myRESTfulAPI.net.co/products/:product_id.json # update with method patch
https://myRESTfulAPI.net.co/products/:product_id.json # delete with method delete
You can create your customs resources, ideal for RESTful apis (see Best practices, Methods and Constants )
When you’re defining your trocha object add a resource
object, it will be use has reference for any resource within this trocha object.
- You can copy and modify default resource at
Trocha.$RESOURCE
or with customSelector atserverRoutes.ñRESOURCE
Scope
const myRoutes = new Trocha( {
routes: {
language: {
$type: Trocha.SCOPE,
id: "language_id",
dashboard: {}
}
}
});
//OR
let myRoutes = new Trocha();
myRoutes._newScope({name: "language", id: "language_id"});
myRoutes.language._newRoute({name: "dashboard"});
console.log(myRoutes.language.dashboard.path({language_id: 'esBO'}));
console.log(myRoutes.dashboard.path());
myRoutes = new Trocha
routes:
language:
$type: Trocha.SCOPE
id: "language_id"
dashboard: {}
#OR
myRoutes = new Trocha()
myRoutes._newScope name: "language", id: "language_id"
myRoutes.language._newRoute name: "dashboard"
console.log myRoutes.language.dashboard.path language_id: 'esBO'
console.log myRoutes.dashboard.path()
This should print:
/esBO/dashboard
/dashboard
Is an optional level of the route tree.
- It require an
ID
- It by default inits with
justId: true
- Does not offer
path()
. - generate the same child tree for the parent
- Can be parent of any kind of other routes.
Alias
const cdns = new Trocha( {
routes: {
// This is a cool vanilla views/routing system more @ http://mtrpcic.net/pathjs/
pathjs: "https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js"
images: {
$type: Trocha.ALIAS,
$alias: "https://cdn.mydomain.io/images",
$id: "image_token",
desktop: 'full_size_for_desktop'
}
}
});
//OR
let cdns = new Trocha();
cdns._newAlias( {
name: "pathjs",
alias: "https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js"
});
cdns._newAlias( {
name: "images",
alias: "https://cdn.mydomain.io/images",
$id: "image_token"
});
cdns.images._newAlias({
name: "desktop",
alias: "full_size_for_desktop"
})
console.log(cdns.pathjs.path());
console.log(cdns.images.path({image_token: 'car.jpg'}));
console.log(cdns.images.desktop.path({query:{colour:'mono'}}));
cdns = new Trocha
routes:
# This is a cool vanilla views/routing system more @ http://mtrpcic.net/pathjs/
pathjs: 'https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js'
images:
$type: Trocha.ALIAS
$alias: 'https://cdn.mydomain.io/images'
$id: 'image_token'
desktop: 'full_size_for_desktop'
#OR
cdns = new Trocha()
cdns._newAlias
name: 'pathjs'
alias: 'https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js'
cdns._newAlias
name: 'images'
$id: 'image_token'
alias: 'https://cdn.mydomain.io/images'
cdns.images._newAlias
name: 'desktop'
alias: 'full_size_for_desktop'
console.log cdns.pathjs.path()
console.log cdns.images.path image_token: 'car.jpg'
console.log cdns.images.desktop.path query: colour:'mono'
This should print:
https://cdn.rawgit.com/mtrpcic/pathjs/master/path.min.js
https://cdn.mydomain.io/images/car.jpg
https://cdn.mydomain.io/images/:image_token/full_size_for_desktop?colour=mono
This type of route can render an specific string independent of the name, it’s usefull to print cdns and very long and isolated paths
- It can be created by an string in the constructor.
- Can be parent of any kind of other routes.
You can also use alias like a obfuscation/minification option for magle childs
202 - Constants
console.log(Trocha.GET);
console.log Trocha.GET
This should print:
GET
The Trocha class also offers a set of useful constants, to call those constants simply write Trocha.<CONST_NAME>
or within the module include import {Trocha, GET, ROUTE, $RESOURCE} from 'trocha'
.
Route types names
const ROUTES = new Trocha({
routes:{
route_a: {
$type: Trocha.ROUTE // Not necesary
},
route_b: {},
scope: {
$type: Trocha.SCOPE
},
resource: {
$type: Trocha.RESOURCE
},
alias: { // if alias don't have child, should be use the alias string directly
$type: Trocha.ALIAS,
$alias: "theAlias"
}
}
});
ROUTES = new Trocha
routes:
route_a:
$type: Trocha.ROUTE # Not necesary
route_b: {}
scope:
$type: Trocha.SCOPE
resource:
$type: Trocha.RESOURCE
alias: # if alias don't have child, should be use the alias string directly
$type: Trocha.ALIAS
$alias: "theAlias"
There are 4 type of routes implemented in trocha but only 2 route type names normally is needed to be use:
Trocha.SCOPE
Trocha.RESOURCE
Trocha.ALIAS
Trocha.ROUTE
The other 2 can be defined via:
- Routes are the default type need no
$type
- Alias can be initialized via a simple String
See Type of routes.
HTTP request methods names
const ROUTES = {
SERVER: new Trocha({
domain: 'https://myRESTfulAPI.net.co',
alwaysUrl: true,
routes:{
users: {
login: {
$method: Trocha.PATCH
}
}
}
});
};
ROUTES.SERVER = new Trocha
domain: 'https://myRESTfulAPI.net.co'
alwaysUrl: true
routes:
users:
login:
$method: Trocha.PATCH
This should generate:
users.login:
url: https://myRESTfulAPI.net.co/users/login
method: PATCH
You can use this in Angular 1.X xhr calls, for example:
// some Angular 1.X code
data.user = {
username: $scope.data.user.toLowerCase(),
password: $scope.data.password
};
$http({
url: ROUTES.SERVER.users.login.path(),
method: ROUTES.SERVER.users.login.$method,
data: data
} ).then( (response) => {
// Your amazing login success code
}, (response) => {
// Your amazing login fail code
});
# some Angular 1.X code
data.user =
username: $scope.data.user.toLowerCase()
password: $scope.data.password
$http
url: ROUTES.SERVER.users.login.path()
method: ROUTES.SERVER.users.login.$method
data: data
.then (response) ->
# Your amazing login success code
, (response) ->
# Your amazing login fail code
There are 9 HTTP request methods names implemented in trocha:
Trocha.GET
Trocha.POST
Trocha.PATCH
Trocha.DELETE
Trocha.HEAD
Trocha.PUT
Trocha.CONNECT
Trocha.OPTIONS
Trocha.TRACE
Those names are usefull when you’re using the route object to point a RESTful server see Angular 1.X implentation
You can set/get the method name of any of your routes via the $method
param/attribute.
Remember the objective of trocha is to avoid the use of repetitive or unmantenable Strings
- For any Route or Alias default $method is
GET
- Scopes and Resource base routes has no $method
- It’s interacting with customSelector so
<customSelector>method
to set and get this attribute
Resource base object
var myResource = Trocha.$RESOURCE
const ROUTES = new Trocha({customSelector: 'TC_'})
var myOtherResource = ROUTES.TC_RESOURCE
myResource = Trocha.$RESOURCE
ROUTES = new Trocha customSelector: 'TC_'
myOtherResource = ROUTES.TC_RESOURCE
This should generate:
{
"myResource": {
"$id": "id",
"edit": {},
"list": {
"$hide": true,
"$id": false
},
"new": {
"$id": false
},
"show": {
"$hide": true
}
},
"myOtherResource": {
"TC_id": "id",
"edit": {},
"list": {
"TC_hide": true,
"TC_id": false
},
"new": {
"TC_id": false
},
"show": {
"TC_hide": true
}
}}
Trocha.$RESOURCE
This routes tree (object like the routes: {...}
you do) define how any resource will be created within this trocha object, you can modify this object if you want to create Custom resources
- It’s interacting with customSelector so
<customSelector>RESOURCE
to get this object
203 - Route definition parameters
When you’re creating your trocha object you can set some basic parameters so when a route need to be printed it will do with more or less content if you like.
Routes & its parameters
myRoutes = new Trocha( {
routes: {
home: {}, // A simple route
The: { // It's supports many levels of hierarchy
quick: {
brown: {
fox: {
jumps: {
over: {
the: {
lazy: {
dog: {}}}}}}}}}, // that's why I prefer coffeescript ;)
people: {
$id: "name",
update: {
$hide: true, // The "update" will be hidden
$method: Trocha.PATCH // This can be part of a (custom) resource ;)
}
},
ninja: { // see 300 - Real World applications > Advance ID handling
$id: "ninja_shadow",
$justId: true,
flying_shuriken: {
$parentId: false,
$id: 'shuriken_id'
},
silent_knife: { // note it does the same as Previous example, but more presise
ninja_shadow: false,
$id: 'knife_id'
}
}
}
});
console.log(myRoutes.home.path());
console.log(myRoutes.The.quick.brown.path());
console.log(myRoutes.The.quick.brown.fox.jumps.over.the.lazy.dog.path());
console.log(myRoutes.people.update.path());
console.log(myRoutes.people.update.$method);
console.log(myRoutes.ninja.path());
console.log(myRoutes.ninja.flying_shuriken.path({shuriken_id: 'the·distracting·one'}));
console.log(myRoutes.ninja.silent_knife.path({knife_id: 'the·killer·one'}));
myRoutes = new Trocha
routes:
home: {} # A simple route
The: # It's supports many levels of hierarchy
quick:
brown:
fox:
jumps:
over:
the:
lazy:
dog: {} # that's why I prefer coffeescript ;)
people:
$id: "name"
update:
$hide: true # The "update" will be hidden
$method: Trocha.PATCH # This can be part of a (custom) resource ;)
ninja: # see 300 - Real World applications > Advance ID handling
$id: "ninja_shadow"
$justId: true
flying_shuriken:
$parentId: false
$id: 'shuriken_id'
silent_knife: # note it does the same as Previous example, but more presise
ninja_shadow: false
$id: 'knife_id'
console.log myRoutes.home.path()
console.log myRoutes.The.quick.brown.path()
console.log myRoutes.The.quick.brown.fox.jumps.over.the.lazy.dog.path()
console.log myRoutes.people.update.path()
console.log myRoutes.people.update.$method
console.log myRoutes.ninja.path()
console.log myRoutes.ninja.flying_shuriken.path shuriken_id: 'the·distracting·one'
console.log myRoutes.ninja.silent_knife.path knife_id: 'the·killer·one'
This should print:
/home
/people/:name
PATCH
/:ninja_shadow
/flying_shuriken/the·distracting·one
/silent_knife/the·killer·one
/The/quick/brown
/The/quick/brown/fox/jumps/over/the/lazy/dog
routes
is an optional(but recomended) object that define the entire routes tree of your trocha object.
A trivial example: routes:{<name>:{...route parameters...}, <name>:"<alias>"}
This routes tree can have has many routes child of any type has you like.
If you want a route with a reserved name like
/$id/
or/$name/
please see $ and customSelectorNote the selector
$
($hide:
for example) is only used when you create the routes via JSON constructor, if you want to use the Method creation ignore the selector (usehide:
instead)
Each route type suport diferent parameters, here a list on how to use:
route | resource | scope | alias | Type | What does | |
---|---|---|---|---|---|---|
$name (*) | Mandatory | Mandatory | Mandatory | Mandatory | String | the name of this part of the path |
$alias (*) | NA | NA | NA | Mandatory | String | An String that replace the name |
$id | Optional | Mandatory | NA | NA | String | A modificable ID_name see Best practices |
$method | Optional | NA | NA | NA | String | Define wich method will be used when requested this path |
$hide | Optional | NA | NA | NA | Bool(True) | If true hide the actual name of this part of the path (ideal for indexs) |
$justId | Optional | Optional | Optional | NA | Bool(True) | Same as $hide but needs $id |
$parent_id | Optional | Optional | Optional | NA | Bool(False) | If false the parent id will be absent, can be Override in path() |
<Id> | Optional | Optional | Optional | NA | Bool(False) | If false the id will be absent, can be Override in path() |
Note if $hide
or $justId
are false will do nothing, same goes to $parent_id
or \<Id\>
if true
(*) Also note name
and alias
are only used when the route is defined vía method
Domain & Always Url
serverRoutes = new Trocha( {
domain: 'https://mydomain.net.co',
alwaysUrl: true,
routes: {
home: {}
}
});
console.log(serverRoutes.home.path());
serverRoutes = new Trocha
domain: 'https://mydomain.net.co'
alwaysUrl: true
routes: home: {}
console.log serverRoutes.home.path()
This should print:
https://mydomain.net.co/home
You can set the domain of your routes via domain
constructor attribute and choice if you want to always print with alwaysUrl
, if you want to print the domain just fewer times see url printing parameter.
This is very usefull when you’re defining routes for a RESTful server.
Prefix & postfix string
templateRoutes = new Trocha( {
pre: '/templates', // note the /
post: '-myH45H.html',
alwaysPost: true,
routes: {
home: {}
}
});
console.log(templateRoutes.home.path());
console.log(templateRoutes.home.path({post: false}));
console.log(templateRoutes.home.path({pre: true}));
console.log(templateRoutes.home.path({ext: true})); // only if alwaysPost is not set
templateRoutes = new Trocha
pre: '/templates' # note the /
post: '-myH45H.html'
alwaysPost: true
routes: home: {}
console.log templateRoutes.home.path()
console.log templateRoutes.home.path post: false
console.log templateRoutes.home.path pre: true
console.log templateRoutes.home.path ext: true # only if alwaysPost is not set
This should print:
/home-myH45H.html
/home
/templates/home-myH45H.html
/templates/home-myH45H.html
You can add Strings at the begining or end your path if you needed, for example if you need add an extention like .html
to all your routes simply add as a contructor attribute post: ".html", alwaysPost: true,
pre
andpost
Strings within the constructor object will be the defaults Strings for the entire routes tree.- Those Strings does not compute any level(
/
) so if you need it this must especify. - Those Strings only compute once, example:
<pre>/my/long/route<post>
- You can the the raw Strings of your Trocha object via
$alwaysPost
,$post
and$pre
attributes - If
alwaysPost
is not set, you can print thepre
orpost
String within the path function{pre:true,post:true}
- You can overide
alwaysPost
within the path function{post:false}
see Route printing parameters for furter explanation
idMode
serverRoutes = new Trocha( {
idMode: Trocha.BRACKETS,
routes: {
hello: {
$id: 'name'
}
}
});
console.log(serverRoutes.hello.path());
serverRoutes = new Trocha
idMode: Trocha.BRACKETS,
routes: hello:
$id: 'name'
console.log serverRoutes.hello.path()
This should print:
https://mydomain.net.co/hello/{name}
# Normally is
# https://mydomain.net.co/hello/:name
You can choice the id mode of your routes via idMode
constructor attribute.
idMode
can be:
Trocha.BRACKETS
will render: /{id}
.
Trocha.COLON
will render: /:id
, this is the default behavior.
This is useful for not so standard framework/libraries.
$ & customSelector
myRoutes = new Trocha( {
customSelector: 'TRCH',
routes: {
hello: {
TRCHid: 'name',
TRCHmethod: Trocha.GET,
$id: {}
}
}
});
console.log(myRoutes.hello.path({ name: "World" }));
console.log(myRoutes.hello.TRCHid);
console.log(myRoutes.hello.$id);
console.log(myRoutes.hello.TRCHmethod);
console.log(myRoutes.hello.$id.path());
myRoutes = new Trocha
customSelector: 'TRCH'
routes:
hello:
TRCHid: 'name'
TRCHmethod: Trocha.GET
$id: {}
console.log myRoutes.hello.path {name: 'World'}
console.log myRoutes.hello.TRCHid
console.log myRoutes.hello.$id
console.log myRoutes.hello.TRCHmethod
console.log myRoutes.hello.$id.path()
This should print:
/hello/World
name
Object {... trocha route object ...}
GET
/hello/:name/$id
If you have a route like this /asd/$id/qwe
you will notice you can’t directly set an $id
route name, thats because by default the JSON constructor use $
as a prefix to reserved names.
If you need to use it anyway, you can overide the selector, simply add customSelector: 'TRCH'
to your inicializer object.
separator
LOCALES = new Trocha({
separator: Trocha.DOT,
// firstSeparator: true,
routes: {
store: { product: { info: { price: { discount: {} } } } }
}
});
console.log(LOCALES.store.product.info.price.discount.path());
LOCALES = new Trocha
separator: Trocha.DOT
# firstSeparator: true
routes:
store: product: info: price: discount: {}
console.log LOCALES.store.product.info.price.discount.path()
This should print:
store.product.info.price.discount
You can use Trocha also to declare attributes list (I.E. Localization engines). Using separator
will change this /asd/:asd_id/qwe
to asd.:asd_id.qwe
or \asd\:asd_id\qwe
.
If you need the first separator to be (or not) present you can toggle with firstSeparator: <Boolean>
.
Available separators are:
Trocha.SLASH
default, it’s/
, firstSeparator enableTrocha.BACK_SLASH
it’s\
, firstSeparator enableTrocha.DOT
it’s.
, firstSeparator disable by default
204 - Route printing parameters
myRoutes = new Trocha( {
pre: '/templates', // note the /
post: '-myH45H.html',
domain: 'https://mydomain.net.co',
routes: {
town: {
$id: 'town_name',
house: {
$id: 'address'
}
}
}
});
console.log(myRoutes.town.path());
console.log(myRoutes.town.path({url: true})); //only if alwaysUrl is not set
console.log(myRoutes.town.path({pre: true}));
console.log(myRoutes.town.path({post: true})); //only if alwaysPost is not set
console.log(myRoutes.town.path({ext: true}));
console.log(myRoutes.town.path({hide: true}));
console.log(myRoutes.town.path({query: {description: true, pictures: 4}}));
console.log(myRoutes.town.path({fragment: 'references'}));
console.log(myRoutes.town.house.path({parentId: false}));
console.log(myRoutes.town.house.path({id: false}));
console.log(myRoutes.town.house.path({
town_name: 'Sydney_NSW',
address: 'P._Sherman_42_wallaby_way'
}));
myRoutes = new Trocha
pre: '/templates' # note the /
post: '-myH45H.html'
domain: 'https://mydomain.net.co'
routes:
town:
$id: 'town_name'
house:
$id: 'address'
console.log myRoutes.town.path()
console.log myRoutes.town.path url: true # only if alwaysUrl is not set
console.log myRoutes.town.path pre: true
console.log myRoutes.town.path post: true # only if alwaysPost is not set
console.log myRoutes.town.path ext: true
console.log myRoutes.town.path hide: true
console.log myRoutes.town.path
query:
description: true
pictures: 4
console.log myRoutes.town.path fragment: 'references'
console.log myRoutes.town.house.path parentId: false
console.log myRoutes.town.house.path id: false
console.log myRoutes.town.house.path
town_name: 'Sydney_NSW'
address: 'P._Sherman_42_wallaby_way'
This should print:
/town/:town_name
https://mydomain.net.co/town/:town_name
/templates/town/:town_name
/town/:town_name-myH45H.html
/templates/town/:town_name-myH45H.html
/:town_name
/town/:town_name?description=true&pictures=4
/town/:town_name#references
/town/house/:address
/town/:town_name/house
/town/Sydney_NSW/house/P._Sherman_42_wallaby_way
After you define your routes the next think you wanna do is print those routes, to do that simply use the path({args})
at the end of your desire route.
Parameters:
url: true
print domain if alwaysUrl is not set.pre: true
print prefix.post: <Boolean>
ifpost: true
print the postfix, ifpost: false
(note justfalse
notundefined
nornull
nor0
) will ignore alwaysPost route param.ext: true
(extended) print prefix and postfix.hide: true
Hide the last name of the path, if an id is setted it will appears anyway.parentId: false
Hide the parent route id.id: false
Hide the route last id, also note the last/
is skip.<someId>: <String>|false
ifString
set the value of some id of the route, iffalse
skip this id path (remove/:someId
).query: {<attribute>:<value>}
Print a define query?<attribute>=<value>&...
.fragment: <String>
Print the fragment#<value>
.
205 - Methods & attributes
When you create your own trocha object it offers a tree of routes objects where most of object offer a variety of methods/attributes. here the explanation what it does.
Attributes have the default prefix $
to change see $ & custom selector.
$name
myRoutes = new Trocha( {
routes: {
country: {
state: {
city: {
town: {}}}}
}
});
console.log(myRoutes.country.$name);
console.log(myRoutes.country.state.$name);
console.log(myRoutes.country.state.city.town.$name);
myRoutes = new Trocha
routes:
country:
state:
city:
town: {}
console.log myRoutes.country.$name
console.log myRoutes.country.state.$name
console.log myRoutes.country.state.city.town.$name
This should print:
country
state
town
<selector>name
Is a String, last child of the route.
$as
myRoutes = new Trocha( {
routes: {
country: {
state: {
city: {
town: {}}}}
}
});
console.log(myRoutes.country.$as);
console.log(myRoutes.country.state.$as);
console.log(myRoutes.country.state.city.town.$as);
myRoutes = new Trocha
routes:
country:
state:
city:
town: {}
console.log myRoutes.country.$as
console.log myRoutes.country.state.$as
console.log myRoutes.country.state.city.town.$as
This should print:
country
country_state
country_state_city_town
<selector>as
Is a String, concatenate parent names and it self. (to easy identify the route).
This attribute is really useful if you want to declare controllers for your route handler like Angular.
$method
serverRoutes = new Trocha( {
routes: {
students: {
$method: Trocha.GET,
create: { $method: Trocha.POST}}
}
});
console.log(serverRoutes.students.$method);
console.log(serverRoutes.students.create.$method);
myRoutes = new Trocha
routes:
students:
$method: Trocha.GET
create: $method: Trocha.POST
console.log myRoutes.students.$method
console.log myRoutes.students.create.$method
This should print:
GET
POST
<selector>method
Is a String, the desired method of this route. See Constants methods names on how to set this String.
This attribute is really useful if you want to make XHR (ajax) calls, see JQuery example.
Methods
path
<route>.path({args})
See Route printing parameters.
_new<Route type>
let myRoutes = new Trocha();
myRoutes._newRoute({
name: "person",
// Optionals
id: "name",
hide: true,
method: Trocha.PUT
});
myRoutes._newScope({
name: "language",
// Optionals
id: "lng"
});
myRoutes._newResource({
name: "products",
id: "product_id",
// Optionals
resource: {
show: {},
list: {
$hide: true
}
}
});
myRoutes._newAlias({
name: "faq",
alias: "FrequentlyAskedQuestions"
});
myRoutes = new Trocha()
myRoutes._newRoute {
name: "person"
# Optionals
id: "name"
hide: true
method: Trocha.PUT
}
myRoutes._newScope {
name: "language"
# Optionals
id: "lng"
}
myRoutes._newResource {
name: "products"
id: "product_id"
# Optionals
resource:
show: {}
list:
$hide: true
}
myRoutes._newAlias {
name: "faq"
alias: "FrequentlyAskedQuestions"
}
This methods helps to create new child routes.
<route>._newRoute({args})
<route>._newResource({args})
: you can set a custom resource but you need to prefix with selector see Custom-resource<route>._newScope({args})
<route>._newAlias({args})
Avoid this way, please see Best practices for depper explanation.
300 - Real World applications
Note the main goal of this library is to declare routes, not to handle.
When to use
- When your web project implement extense Client-side routing.
- When your project make calls to a RESTful server.
- When your project is NodeJS server side rendered.
When do not use
- When your project is server side rendered(PHP, Java, ASP, RoR), use backend framework route system instead.
- When you are looking ONLY for a client side route handler, like Angular or pathjs
Alternativeto TrochaJS
- Server-side RoR Routes. This system is the inspiration of this library.
- Client-side RoR, generates javascript file that defines all Rails named routes as javascript helpers js-routes. Note this compile entire routes.rb tree.
- Client-side ASP.NET MVC or WebForms routes from JavaScript RouteJs.
Advance ID handling
/reports
/reports/123
/reports/tables
/reports/tables/321
myRoutes = new Trocha( {
routes: {
reports: {
$id: 'report_id',
tables: {
show: {$hide: true},
$id: 'table_id',
// Next (any of two)lines makes the best solution
// parentId: false // OR
// report_id: false
}}
}
});
myRoutes = new Trocha
routes:
reports:
$id: 'report_id'
tables:
show: $hide: true
$id: 'table_id'
# Next (any of two)lines makes the best solution
# parentId: false # OR
# report_id: false
You can get this with:
console.log myRoutes.reports.path({report_id: false})
console.log myRoutes.reports.path({report_id: ''}) // equal to previous
console.log myRoutes.reports.path({report_id: 123})
console.log myRoutes.reports.path({report_id: 'tables'}) // may be not the best idea
console.log myRoutes.reports.tables.path({parentId: false, table_id: false}) // :(
console.log myRoutes.reports.tables.show.path({report_id: false})
console.log myRoutes.reports.tables.show.path({parentId: false})
// if parentId defined in contructor (best idea)
console.log myRoutes.reports.tables.show.path()
console.log myRoutes.reports.tables.path(table_id: 321)
console.log myRoutes.reports.path report_id = false
console.log myRoutes.reports.path report_id = '' # equal to previous
console.log myRoutes.reports.path report_id = 123
console.log myRoutes.reports.path report_id = 'tables' # may be not the best idea
console.log myRoutes.reports.tables.path parentId: false, table_id: false # :(
console.log myRoutes.reports.tables.show.path report_id = false
console.log myRoutes.reports.tables.show.path parentId: false
# if `(parentId or report_id): false` defined in contructor (best idea)
console.log myRoutes.reports.tables.show.path()
console.log myRoutes.reports.tables.path table_id: 321
You can get this with:
/reports
/reports
/reports/123
/reports/tables # :(
/reports/tables # :(
/reports/tables/:table_id
/reports/tables/:table_id
/reports/tables # :)
/reports/tables/321 # :)
See the requested routes:
In some cases is useful to set the parentId: false
or \<Id\>: false
in the contructor for DRY code
301 - Best practices
ñ00 Never point to master
BAD idea
<script src="https://cdn.rawgit.com/DFOXpro/trocha/master/dist/Trocha.min.js"></script>
GOOD idea
<script src="https://cdn.rawgit.com/DFOXpro/trocha/0.1.3/dist/Trocha.min.js"></script>
Wherever you use this library never point to master branch, use always an especific version of the library.
WHY?
Any change between versions (releases, revision, etc) may change the behavior of this library.
ñ01 Prefer JSON constructor
BAD idea
let myRoutes = new Trocha();
myRoutes._newRoute({args...});
...
myRoutes = new Trocha()
myRoutes._newRoute {args...}
...
GOOD idea
const myRoutes = new Trocha({
routes: {... my routes ...}
});
myRoutes = new Trocha
routes: {... my routes ...}
Always use the JSON constructor to declarate the routes tree, avoid the creation methods.
WHY?
- When using the creation methods your route can’t be const and may be override later on.
- Using the creation methods you can ending with routes declarations in the entire project.
- Using the JSON contructor you can declare in just one place (file?) all your routes.
ñ02 Use const
BAD idea
let myRoutes = new Trocha({
routes: {... my routes ...}
});
myRoutes = new Trocha
routes: {... my routes ...}
...
GOOD idea
const myRoutes = new Trocha({
routes: {... my routes ...}
});
const myRoutes = new Trocha {... my routes ...} # for CS2
# for coffeescript vanilla :(
__myRoutes = {... my routes ...}
`const myRoutes = new Trocha({
routes: __myRoutes
});
`
delete __myRoutes
Use variable type const
WHY?
- This is a well supported ES6 feature (even IE11 support this).
- This prevent later on override.
ñ03 Use diferent trocha objects to diferent route scopes
BAD idea
const myRoutes = new Trocha({
routes: {
client routes ...
serverA routes ...
serverB routes ...
}
});
myRoutes = new Trocha
routes:
client routes ...
serverA routes ...
serverB routes ...
GOOD idea
const clientRoutes = new Trocha({
pre: '/the/templates/route',
post: '_the_hash_and_ext.html',
routes: {... client routes ...}
});
const serverARoutes = new Trocha({
domain: 'https://api.serverA.net.co/',
alwaysUrl: true,
routes: {... serverA routes ...}
});
const serverBRoutes = new Trocha({
domain: 'https://api.serverB.net.co/',
alwaysUrl: true,
routes: {... serverB routes ...}
});
clientRoutes = new Trocha {
pre: '/the/templates/route'
post: '_the_hash_and_ext.html'
routes: {... client routes ...}
serverARoutes = new Trocha {
domain: 'https://api.serverA.net.co/'
alwaysUrl: true
routes: {... serverA routes ...}
serverBRoutes = new Trocha {
domain: 'https://api.serverB.net.co/'
alwaysUrl: true
routes: {... serverB routes ...}
If your project access to RESTful apis declare a trocha object per server, also use an exclusive object for client views
WHY?
- Its more clean for the apis or cdns or views route trees
- Most cases views routes are diferent of api routes
- Even more you can create some security holes showing all your api routes in the view
ñ04 If posible use Trocha for(with) async cdns
BAD idea
loadAsyncCDN('www.myCDN.io/min.js');
loadAsyncCDN 'www.myCDN.io/min.js'
GOOD idea
myCDN = new Trocha({routes: min: 'www.myCDN.io/min.js'});
loadAsyncCDN(myCDN.min);
myCDN = new Trocha routes: min: 'www.myCDN.io/min.js'
loadAsyncCDN myCDN.min
If you use async libraries or technologies like AMD use trocha to point the cdn url
WHY?
- Its cleaner
- Can be used like Dependency Injection if you wanna, ideal for dev/test/production environment swap
302 - Vanilla
const handleRoute = (event) => {
// Your awesome route handle
};
const replaceHref = () => {
Array.prototype.forEach.call(document.getElementsByTagName("a"), (link) => {
if(link.dataset.href){
link.href = eval(
"clientRoutes." +
link.dataset.href
).path(
link.dataset.path ? JSON.parse(link.dataset.path) : {}
);
link.onclick = handleRoute
}
});
};
window.onload = () => {
replaceHref();
}
handleRoute = (event) ->
# Your awesome route handle
replaceHref = ->
Array.prototype.forEach.call document.getElementsByTagName("a"), (link) ->
if link.dataset.href
link.href = eval(
"clientRoutes." + link.dataset.href
).path(
`link.dataset.path ? JSON.parse(link.dataset.path) : {}`
)
link.onclick = handleRoute
window.onload = ->
replaceHref()
If you want to use this library with Vanilla JS(my fav framework ;)) I recomend you to use pathjs to route handle. SEE TRIVIAL EXAMPLE HERE
In this example we write the links <a href >
via onload function
303 - JQuery
const succcesAction = (msg) => {
// Your awesome XHR success handler
};
const doJqueryXHR = (route, path, data) => {
return $.ajax({
method: route.$method,
url: route.path(path),
data: data
})
};
doJqueryXHR(serverRoutes.posts.show,{args},{data}).done(succcesAction);
succcesAction = (msg) ->
# Your awesome XHR success handler
doJqueryXHR = (route, path, data) ->
$.ajax
method: route.$method
url: route.path path
data: data
doJqueryXHR(serverRoutes.posts.show,{args},{data}).done succcesAction
In this example we use an ajax helper that include the route, the path parameters and the data it will send if any.
304 - Angular 1.X
The directive where we include trocha to our Angular project views via
<a thref="ROUTE">...
app.directive( 'thref', () => {// Trocha href
return {
restrict: 'A',
link: ($scope, elements, attrs) => {
route = ROUTES.CLIENT;
attrs.thref.split('.').forEach((r) => {
route = route[r];
if(!route) throw "Invalid thref route"
});
if(attrs.tpath)
try {
attrs.tpath = JSON.parse(attrs.tpath)
} catch(error){
console.error('Invalid tpath JSON', error)
}
if("string" == typeof route)
elements[0].href = route; // @TODO in future release this will be obsolete
else elements[0].href = '#!' + route.path(attrs.tpath)// default hashprefix since 1.6
}
}
});
app.directive 'thref', () ->
restrict: 'A'
link: ($s, elements, attrs) ->
route = _routes.client
attrs.thref.split('.').forEach (r) ->
route = route[r]
if !route
throw "Invalid thref route"
if attrs.tpath
try
attrs.tpath = JSON.parse attrs.tpath
catch error
console.error 'Invalid tpath JSON', error
if "string" == typeof route
elements[0].href = route # @TODO in future release this will be obsolete
else
elements[0].href = '#!' + route.path attrs.tpath # default hashprefix since 1.6
<a thref="trochaJSDocs">click here</a>
<a thref="users.list">Show users list</a>
The factory where we include trocha XHR helper to our Angular project
app.factory('$trocha', [
'$http',
($http) => {
var $trocha = new Trocha;
$Trocha.CLIENT = ROUTES.CLIENT;
$Trocha.SERVER = ROUTES.SERVER;
$Trocha.xhr = (route, path, data) => {
let args = {
url: route.path(path),
method: route.$method
}
if(data) args.data = data;
return $http(args);
}
return $trocha;
}
]);
app.factory '$trocha', [
'$http',
($http) ->
$trocha = new Trocha;
$Trocha.CLIENT = ROUTES.CLIENT
$Trocha.SERVER = ROUTES.SERVER
$Trocha.xhr = (route, path, data) ->
args =
url: route.path path
method: route.$method
args.data = data if data
$http args
$trocha
]
The ngRoute config
app.config([
'$routeProvider'
($routeProvider) => {
$routeProvider.when(ROUTES.CLIENT.the.client.route.path(), {
templateUrl: ROUTES.CLIENT.the.client.route.path({ext: true}),
controller: ROUTES.CLIENT.the.client.route.$as
})
}
]);
app.config [
'$routeProvider'
($routeProvider) ->
$routeProvider.when ROUTES.CLIENT.the.client.route.path(),
templateUrl: ROUTES.CLIENT.the.client.route.path {ext: true}
controller: ROUTES.CLIENT.the.client.route.$as
]
The controller implementation
app.controller(ROUTES.CLIENT.the.client.route.$as, [
'$scope', '$trocha', function($scope, $trocha) {
$scope.data = {
routes: $Trocha.CLIENT
};
$Trocha.xhr($Trocha.SERVER.the.server.route, {path args...}, {data...})
.then(xhrSuccess, xhrFail);
}
]);
app.controller ROUTES.CLIENT.the.client.route.$as, [
'$scope', '$trocha', ($scope, $trocha) ->
$scope.data =
routes: $Trocha.CLIENT
$Trocha.xhr $Trocha.SERVER.the.server.route, {path args...}, {data...}
.then xhrSuccess, xhrFail
]
In this trivial example we use use the $http Angular service to make XHR request and ngRoute to handle routes and templates.
Note various things:
- We have diferent objects for client routes and server routes.
- To print the routes in the view we integrate just the client routes in the directive.
- To naming the controller we use the
$as
attribute of the route.
305 - Node
WIP :(
400 - Errors
401 - Route definition errors
402 - Route printing errors
403 - Trobleshoting
404 - Known bugs
- An empty route like
/
will return blank “ - Alias ignore parent and does not support child routes
418 - HTCPCP
Parce gracias por leerse toda esta documentación, ojalá un día nos tomemos un café con aguapanela.
419 - I’m a Fox
Any comment please tellme via email: dfoxpro at gmail
420 - Enhance Your Calm
Twitter:
You can tag this project via #trochajs, or my self via @dfoxpro
Licence
This project (the library and this documentation) is under Mozilla’s MPLv2.0
Mozilla Public License, version 2.0
1. Definitions
1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.
1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution.
1.3. “Contribution” means Covered Software of a particular Contributor.
1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.
1.5. “Incompatible With Secondary Licenses” means
that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or
that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License.
1.6. “Executable Form” means any form of the work other than Source Code Form.
1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.
1.8. “License” means this document.
1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.
1.10. “Modifications” means any of the following:
any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or
any new file in Source Code Form that contains any Covered Software.
1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.
1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.
1.13. “Source Code Form” means the form of the work preferred for making modifications.
1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and
under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.
2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.
2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:
for any code that a Contributor has removed from Covered Software; or
for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or
under Patent Claims infringed by Covered Software in the absence of its Contributions.
This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).
2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).
2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form.
3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then:
such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and
You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).
3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.
4.
Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.
6.
Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer.
7.
Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.
8.
Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims.
9.
Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.
10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.
10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.
Exhibit
Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.