- NodeJs 6.1.0
- Chimp.js
- Chrome (60+)
Lark is a tiny MVC framework which is written in ES5, it doesn't have any dependencies on other javascript libraries. It provides an easy to write components and use dependecny injection to manage componenent dependencies. More information on how to create components is provided below.
If you haven't used node version manager NVM, recommend to install it, so you can switch different node version for different projects easily. After the installation, 6.1.0 has been tested and is working. Please report issues if the version doesn't work for you. To use a version, for example 6.1.0
nvm install 6.1.0
Check the version 6.1.0 with
node -v
You can install NVM with Homebrew
brew update
brew install nvm
mkdir ~/.nvm
nano ~/.bash_profile
Install library
[sudo] npm install -g chimp
[sudo] npm install
Then run gulp watch to try out the app is via the built-in server: (http://localhost:9000/demo/)
gulp watch
- src //source code
- app //demo application
- asssets //demo application assets (bootstrap.css, video, images etc.)
- lark //framework file
- demo
- partials //page partials (footer libs, header libs etc.)
index.html //demo page
- features //End to end test features
- _support //supporting code, use for different test components
helper.js //helper class
- components //source code of test components
- features //test features and scenrios
- gulp
- tasks //Gulp build task, (gulp release)
config.js //gulp tasks configuration (source and destination paths)
- output //test log
.editorconfig //IDE default configuration, it is for Intellij EditorConfig plugin
test.config.js //Tes global configuration for server and envirnment
chimp.conf.js //ChimpJs configuration
It uses dependency injection technique to manage the dependency. This project is using the gulp build-app
build-lark
to concat source files together, the source file order is config in gulp/config.js
.
It instantiates a html tempalte once per item from a collection or an array. Each instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
<ul>
<li data-js-repeat="task in tasks" >
<p>{{task.name}}</p>
</li>
</ul>
After rendering
<ul>
<li data-js-repeat="task in tasks" >
<p>task A</p>
</li>
<li data-js-repeat="task in tasks" >
<p>task B</p>
</li>
<li data-js-repeat="task in tasks" >
<p>task C</p>
</li>
</ul>
Component template
<data-component-country>
<h3>{{country.name}}</h3>
<p>{{country.intro}}</p>
</data-component-country>
<div data-js-repeat="country in countries" data-component-country data-country="country"></div>
The element is shown or hidden based on the {{expression}} of the data-js-show
or data-js-hide
attribute onto the element.
<form data-js-show="isOpened">...</form>
If $scope.isOpened is true
show the form
<form data-js-hide="isClosed">...</form>
If $scope.isClosed is true
hide the form
It removes or recreates the DOM element based on the {{expression}} of data-js-if
attribute onto the element.
<form data-js-if="isOpened">...</form>
If $scope.isOpened is true
add the form element, otherwise remove the form element
It provides custom behaviour for element itself. The list of the behaviours
data-js-click, data-js-dblclick, data-js-mousedown, data-js-mouseup, data-js-mouseover, data-js-mouseout, data-js-mousemove, data-js-mouseenter, data-js-mouseleave, data-js-keydown, data-js-keyup, data-js-keypress, data-js-submit, data-js-focus, data-js-blur, data-js-copy, data-js-cut, data-js-paste
Example
<button type="button" data-js-click="removeMe()">Delete</button>
It provides click behaviour, on click this delete button, it will execute $scope.removeMe()
method.
It uses for the form interaction elements, binds the textinput, textarea or select to a property defined in the corresponding scope model. It Binds the view into the scope model, which otherelements such as input, textarea or select require.
<input class="form-control" data-js-model="currentTask.name" placeholder="Name" id="taskName"/>
Scope model
$scope.currentTask.name
It creates the collection of all component templates before setting up components
A template has type="text/x-lark-template"
id
is in the reference in the component. A template can be used for different component models
For example
<script type="text/x-lark-template" id="component-new-task-template" >
<button type="button" class="btn btn-primary" data-js-click="create()">Create</button>
</script>
templateId equals component-new-task-template
lark.addComponent('newTask', [function() {
return function () {
return {
scope: {},
templateId: "component-new-task-template",
link: (function ($scope, $element) {
})
}
}
}]);
It provides the method lark.$refresh.loop()
to scanner the whole scope tree, validate the binding properties and update the view. it is the same to call $scope.$update()
. It uses for the situation when you want to manually update the view. In the future, it will provides the ability to update particular part of the scope tree.
Normally, you use a service to manage data used for different components or talk to the web server.
For example a taskService
lark.addService('taskService', ['HttpService', function (HttpService) {
var service = {};
var _tasks = [];
service.list = function() {
_tasks = HttpService.fetchTasks()
...
return _tasks;
};
service.update = function(candidate) { };
service.add = function(candidate) { };
service.get = function(candidate) { };
service.remove = function(candidate) {};
return service;
}]);
The component template element has type="text/x-lark-template"
for the script
tag or (TODO)data-type="text/x-lark-template"
for custom tag (<div data-type="text/x-lark-template" >
) For example
<script type="text/x-lark-template" id="component-task-list-template">
<div class="container">
<div data-js-repeat="task in tasks" data-task-avatar data-task="task" style="margin-bottom: 20px;"></div>
</div>
</script>
A component template can be shared with different controller. For this project, it is using gulp build-template
task to concat all templates into single file dist/app/templates.html
, which is included in the demo page with using ssi <!--#include virtual="app/templates.html" -->
A component controller controls the presentation logic. On components set up, it gets a new instance of the Scope object. An example
lark.addComponent('componentName', ['ServiceName', function (ServiceName) {
return function () {
return {
scope: { }, //configurable object
template: '', //view template
link: (function ($scope, $element) {}) //controller
}
}
}]);
The scope
parameter is a collection of Strings, it is optional, it collects optional properties in the component $scope object. You can use it to get and set the data between sharing scope components or set the configurable options for the component.
Get and set the value between components like the parent and the child component. The value is the property of the parent $scope. For example
Parent and child component templates
<div data-parent-component >
<div data-child-component data-parent-name="name" >
{{parentName}}
</div>
</div>
Parent component
lark.addComponent('parentComponent', [function () {
return function () {
return {
link: (function ($scope, $element) {
$scope.parentName = "radish";
})
}
}
}]);
Child component
lark.addComponent('childComponent', [function () {
return function () {
return {
scope: {
parentName: "="
},
link: (function ($scope, $element) {
console.log($scope.parentName); //Radish
})
}
}
}]);
Get the value of the component scope
<div data-featured-panel data-colour="dark" class="{{panelClass}}">
...
</div>
Example
lark.addComponent('featuredPanel', [function () {
return function () {
return {
scope: {
colour: "="
},
link: (function ($scope, $element) {
if($scope.colour == "dark") {
$scope.panelClass = "dark-panel";
}
})
}
}
}]);
After initialisation, the rendered view is
<div data-featured-panel data-colour="dark" class="dark-panel">
...
</div>
The project uses nodejs ssi
library to control server side include, the gulp task gulp build-template
will set the sitePathValue
and make partials ready in dist folder, for example the dist/demo/index.html
<!--#set var="sitePath" value="<%=sitePathValue%>" -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Lark demo</title>
<!--#include virtual="demo/partials/head-libs.html" -->
</head>
<body>
<div class="container" id="mainContainer">
application code
</div>
<!--#include virtual="app/templates.html" -->
<!--#include virtual="demo/partials/footer-libs.html" -->
</body>
</html>
This project simply uses gulp task to manage the source code dependency, gulp build-lark
and gulp build-app
. Those two tasks will concat the source files into dist/lark.js
and dist/app/app.js
, they register in demo/partials/footer-libs.html
It uses Chimp.js to develop test case. Before run the test locally, you should start the local server by gulp serve
or gulp watch
The configuration file is test.config.js
which has the global configuration and chimp.conf.js
which has the default configuration.
Add @watch
tag in a feature or scenario, then run chimp --watch
, you should see your chrome browser pops up
Run chimp
in terminal to run all test cases
The project follows the git-flow methodology, uses semver version numbers and JSPM and Bower for distribution. Releases are created by merging develop
to master
, building the release code and tagging the master
branch with a version number.
First, check the latest develop branch is release-ready:
$ git checkout develop
$ git pull
$ git push
Then merge the release-ready code to master
$ git checkout master
$ git pull
$ git merge develop
$ git commit
Then, while still on master
, the process of building, updating version numbers and tagging the release can be done using gulp release
. By default gulp release
will increment the bugfix version, it supports --bump
options are major
, minor
, and patch
but the major and minor versions can be incremented using the --bump
flag, for example:
gulp release --bump patch
Finally, push new release to remote master branch and push new release tag to remote master branch.
git push
git push --tags
Fix scope destroy doesn't handle empty scope for js-repeat component Add router component to control router
Test framework uses Chimp.js
Release uses gulp release package
Demo application uses Bootstrap
Expression service uses Lodash template expression