├── public
├── api
│ ├── StubResponses
│ ├── resources.json
│ └── dashboard
│ │ ├── 1.json
│ │ └── 2.json
├── css
│ └── style.css
├── index.html
└── lib
│ └── css3tips
│ └── css3-tips.css
├── .bowerrc
├── src
├── page
│ ├── apps
│ │ ├── AppsPage.html
│ │ ├── AppsPage.ts
│ │ └── AppsPage.js
│ ├── IPage.d.ts
│ ├── dashboard
│ │ ├── DashboardPage.less
│ │ ├── DashboardPage.html
│ │ ├── DashboardPage.ts
│ │ └── DashboardPage.js
│ ├── home
│ │ ├── HomePage.html
│ │ ├── HomePage.less
│ │ ├── HomePage.ts
│ │ └── HomePage.js
│ └── error
│ │ ├── ErrorPage.html
│ │ ├── ErrorPage.ts
│ │ └── ErrorPage.js
├── parts
│ ├── header-nav
│ │ ├── HeaderNav.html
│ │ ├── HeaderNav.less
│ │ ├── HeaderNav.js
│ │ └── HeaderNav.ts
│ ├── widget
│ │ ├── Widget.html
│ │ ├── Widget.ts
│ │ ├── Widget.js
│ │ ├── Widget.less
│ │ ├── WidgetHolder.ts
│ │ ├── WidgetHolder.js
│ │ └── WidgetHolder.less
│ ├── side-nav
│ │ ├── SideNav.html
│ │ ├── SideNav.ts
│ │ ├── SideNav.js
│ │ └── SideNav.less
│ ├── MenuItem.js
│ ├── MenuItem.ts
│ └── directory-tree
│ │ ├── DirectoryTree.less
│ │ ├── DirectoryTree.html
│ │ ├── DirectoryTree.js
│ │ └── DirectoryTree.ts
├── references.d.ts
├── package.json
├── tsd.json
├── webpack.config.js
├── Application.ts
└── Application.js
├── init.sh
├── .gitignore
├── package.json
├── dashboard.iml
├── bower.json
├── README.md
└── server.js
/public/api/StubResponses:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "public/lib"
3 | }
--------------------------------------------------------------------------------
/src/page/apps/AppsPage.html:
--------------------------------------------------------------------------------
1 |
{{title}}
2 |
--------------------------------------------------------------------------------
/src/page/IPage.d.ts:
--------------------------------------------------------------------------------
1 | interface IPage{
2 | title:string;
3 | component:string;
4 | icon?:string;
5 | }
--------------------------------------------------------------------------------
/src/page/dashboard/DashboardPage.less:
--------------------------------------------------------------------------------
1 | .dashboard-page{
2 | .control{
3 | margin: 0 10px;
4 | }
5 | }
--------------------------------------------------------------------------------
/src/page/home/HomePage.html:
--------------------------------------------------------------------------------
1 | {{title}}
2 |
--------------------------------------------------------------------------------
/init.sh:
--------------------------------------------------------------------------------
1 | npm install
2 | bower install
3 |
4 | pushd src
5 | npm install
6 | tsd reinstall
7 | webpack
8 | popd
9 |
--------------------------------------------------------------------------------
/src/page/home/HomePage.less:
--------------------------------------------------------------------------------
1 | .home-page{
2 | dl{
3 | dt{
4 | span{
5 | min-width: 6em;
6 | display: inline-block;
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/page/error/ErrorPage.html:
--------------------------------------------------------------------------------
1 | {{code}}
2 | {{message}}
3 | back
--------------------------------------------------------------------------------
/src/parts/header-nav/HeaderNav.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | {{$root.pages[$root.page].title}}
10 |
11 |
--------------------------------------------------------------------------------
/src/parts/header-nav/HeaderNav.less:
--------------------------------------------------------------------------------
1 | header-nav{
2 | display:block;
3 | background:#2b3d51;
4 | color: #ccc;
5 |
6 | .btn{
7 | &:hover{
8 | color:white;
9 | }
10 | }
11 |
12 | ul{
13 | margin:0;
14 | padding:0;
15 | list-style:none;
16 | }
17 | }
--------------------------------------------------------------------------------
/src/parts/widget/Widget.html:
--------------------------------------------------------------------------------
1 |
4 |
5 | body
6 |
7 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /node_modules
3 | /src/node_modules
4 | /src/typings
5 | /public/lib/jquery
6 | /public/lib/knockout
7 | /public/lib/knockout.punches
8 | /public/lib/knockout-else
9 | /public/lib/knockout-es5
10 | /public/lib/bootstrap
11 | /public/lib/fontawesome
12 | /public/lib/gridster
13 | /public/lib/jquery-ui
14 | /public/js/bundle.js
--------------------------------------------------------------------------------
/src/page/dashboard/DashboardPage.html:
--------------------------------------------------------------------------------
1 | {{title}}
2 |
3 | {{#if: message}}
4 |
{{message}}
5 | {{/if}}
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/public/api/resources.json:
--------------------------------------------------------------------------------
1 | {
2 | "disks":[
3 | {
4 | "filesystem": "/dev/vda1",
5 | "used":33505,
6 | "available": 436789
7 | },
8 | {
9 | "filesystem": "/dev/vdb",
10 | "used":188160,
11 | "available": 78187440
12 | }
13 | ],
14 | "memory":{
15 | "used":311800,
16 | "free":708616
17 | },
18 | "swap":{
19 | "used":123456,
20 | "free":2064376
21 | }
22 | }
--------------------------------------------------------------------------------
/src/references.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 |
5 | interface KnockoutStatic{
6 | punches:any;
7 | track:any;
8 | }
9 | interface JQuery{
10 | gridster:any;
11 | }
12 |
13 | declare var KnockoutElse:{
14 | init:any;
15 | };
16 |
17 | /*
18 | declare class Router{
19 | addRoute:any;
20 | errors:any;
21 | run:any;
22 | }
23 | */
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node server"
7 | },
8 | "dependencies": {
9 | "body-parser": "~1.8.1",
10 | "cookie-parser": "~1.3.3",
11 | "debug": "~2.0.0",
12 | "express": "~4.9.0",
13 | "jade": "~1.6.0",
14 | "morgan": "~1.3.0",
15 | "serve-favicon": "~2.1.3"
16 | },
17 | "devDependencies": {
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/parts/side-nav/SideNav.html:
--------------------------------------------------------------------------------
1 |
2 | {{#foreach menu}}
3 | -
4 | {{#if: $parent.isShown}}
5 | {{label}}
6 | {{/if}}
7 | {{#else}}
8 |
9 | {{/else}}
10 |
11 | {{/foreach}}
12 |
--------------------------------------------------------------------------------
/dashboard.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "ignore": [
6 | "**/.*",
7 | "node_modules",
8 | "bower_components",
9 | "public/js/lib",
10 | "test",
11 | "tests"
12 | ],
13 | "dependencies": {
14 | "bootstrap": "~3.2.0",
15 | "jquery": "~2.1.1",
16 | "fontawesome": "~4.2.0",
17 | "knockout": "~3.2.0",
18 | "knockout.punches": "~0.5.0",
19 | "knockout-es5": "*",
20 | "knockout-else": "~1.0.11",
21 | "jquery-ui": "~1.11.2",
22 | "gridster": "~0.5.6"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/parts/MenuItem.js:
--------------------------------------------------------------------------------
1 | ///
2 | var MenuItem = (function () {
3 | function MenuItem(arg1, arg2, arg3) {
4 | if (typeof arg1 == "string") {
5 | this.label = arg1;
6 | this.icon = arg2;
7 | this.href = arg3;
8 | }
9 | else {
10 | this.label = arg1.title;
11 | this.icon = arg1.icon;
12 | this.href = arg2;
13 | }
14 | ko.track(this);
15 | }
16 | return MenuItem;
17 | })();
18 | module.exports = MenuItem;
19 |
--------------------------------------------------------------------------------
/src/parts/header-nav/HeaderNav.js:
--------------------------------------------------------------------------------
1 | var HeaderNav = (function () {
2 | function HeaderNav(sideNav) {
3 | this.sideNav = sideNav;
4 | ko.track(this);
5 | }
6 | return HeaderNav;
7 | })();
8 | require('./HeaderNav.less');
9 | ko.components.register('header-nav', {
10 | template: require('./HeaderNav.html'),
11 | viewModel: {
12 | createViewModel: function (params, componentInfo) {
13 | return params instanceof HeaderNav ? params : ko.unwrap(params.option);
14 | }
15 | }
16 | });
17 | module.exports = HeaderNav;
18 |
--------------------------------------------------------------------------------
/public/api/dashboard/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "First",
3 | "widgets": [
4 | {"type": "text","data": "A","size_x": 1,"size_y":1,"col":1,"row":1},
5 | {"type": "text","data": "B","size_x": 1,"size_y":1,"col":2,"row":1},
6 | {"type": "text","data": "C","size_x": 1,"size_y":1,"col":3,"row":1},
7 | {"type": "text","data": "D","size_x": 1,"size_y":3,"col":4,"row":1},
8 | {"type": "text","data": "E","size_x": 1,"size_y":1,"col":1,"row":2},
9 | {"type": "text","data": "F","size_x": 1,"size_y":1,"col":2,"row":2},
10 | {"type": "text","data": "G","size_x": 3,"size_y":1,"col":1,"row":3}
11 | ]
12 | }
--------------------------------------------------------------------------------
/public/api/dashboard/2.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Second",
3 | "widgets": [
4 | {"type": "text","data": "1","size_x": 1,"size_y":1,"col":1,"row":1},
5 | {"type": "text","data": "2","size_x": 1,"size_y":1,"col":2,"row":1},
6 | {"type": "text","data": "3","size_x": 1,"size_y":2,"col":3,"row":1},
7 | {"type": "text","data": "4","size_x": 1,"size_y":3,"col":4,"row":1},
8 | {"type": "text","data": "5","size_x": 1,"size_y":1,"col":1,"row":2},
9 | {"type": "text","data": "6","size_x": 1,"size_y":1,"col":2,"row":2},
10 | {"type": "text","data": "7","size_x": 3,"size_y":1,"col":1,"row":3}
11 | ]
12 | }
--------------------------------------------------------------------------------
/src/page/apps/AppsPage.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | class AppsPage implements IPage{
4 | public title ="Apps";
5 | public component="apps-page";
6 | public icon = "bookmark-o";
7 |
8 | constructor(
9 | ){
10 | ko.track(this);
11 | }
12 | }
13 | export = AppsPage;
14 |
15 |
16 | //require('./AppsPage.less');
17 | ko.components.register('apps-page',{
18 | template: require('./AppsPage.html'),
19 | viewModel:{
20 | createViewModel(params, componentInfo){
21 | return params instanceof AppsPage ? params : params.option;
22 | }
23 | }
24 | });
25 |
26 |
--------------------------------------------------------------------------------
/src/parts/header-nav/HeaderNav.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import MenuItem = require('../MenuItem');
3 | import SideNav = require('../side-nav/SideNav');
4 |
5 | class HeaderNav{
6 | constructor(
7 | private sideNav:SideNav
8 | ){
9 | ko.track(this);
10 | }
11 | }
12 | export = HeaderNav;
13 |
14 | require('./HeaderNav.less');
15 | ko.components.register('header-nav',{
16 | template: require('./HeaderNav.html'),
17 | viewModel:{
18 | createViewModel(params, componentInfo){
19 | return params instanceof HeaderNav ? params : ko.unwrap(params.option);
20 | }
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashbord_client",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "webpack.config.js",
6 | "author": "MKGaru",
7 | "license": "MIT",
8 | "dependencies": {
9 | "css-loader": "^0.9.0",
10 | "file-loader": "^0.8.1",
11 | "html-loader": "^0.2.3",
12 | "html5-history-api": "^4.1.15",
13 | "imports-loader": "^0.6.3",
14 | "jquery": "^2.1.1",
15 | "less": "^1.7.5",
16 | "less-loader": "^0.7.7",
17 | "page": "^1.3.7",
18 | "style-loader": "^0.8.1",
19 | "sugar": "^1.4.1",
20 | "url-loader": "^0.5.5",
21 | "webpack": "^1.4.10"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/parts/MenuItem.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | class MenuItem{
4 | public label:string;
5 | public icon:string;
6 | public href:string;
7 |
8 | constructor(page:IPage,href:string);
9 | constructor(label:string, icon: string, href: string);
10 | constructor(arg1,arg2,arg3?)
11 | {
12 | if(typeof arg1 =="string"){
13 | this.label = arg1;
14 | this.icon = arg2;
15 | this.href = arg3;
16 | }else{
17 | this.label = (arg1).title;
18 | this.icon = (arg1).icon;
19 | this.href = arg2;
20 | }
21 | ko.track(this);
22 | }
23 | }
24 |
25 | export = MenuItem;
--------------------------------------------------------------------------------
/src/parts/side-nav/SideNav.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import MenuItem = require('../MenuItem');
3 |
4 | class SideNav{
5 | public isShown = true;
6 | constructor(
7 | public menu:MenuItem[]
8 | ){
9 | ko.track(this);
10 | }
11 |
12 | public toggle(){
13 | this.isShown = !this.isShown;
14 | }
15 | }
16 | export = SideNav;
17 |
18 | require('./SideNav.less');
19 | ko.components.register('side-nav',{
20 | template: require('./SideNav.html'),
21 | viewModel:{
22 | createViewModel(params, componentInfo){
23 | return params instanceof SideNav ? params : ko.unwrap(params.option);
24 | }
25 | }
26 | });
27 |
28 |
--------------------------------------------------------------------------------
/public/css/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body{
3 | height:100%;
4 | margin:0;
5 | padding:0;
6 | font-family: "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", "Meiryo", "MS Pゴシック", "MS P Gothic", sans-serif;
7 | }
8 | body{
9 | padding-top:30px;
10 | overflow:hidden;
11 | }
12 | body>header-nav{
13 | margin-top:-30px;
14 | height:30px;
15 | }
16 | body>side-nav{
17 | float:left;
18 | height: 100%;
19 | }
20 | body>.contents{
21 | margin-left:15em;
22 | transition: margin-left 250ms;
23 | padding:1em;
24 | height: 100%;
25 | overflow: auto;
26 | }
27 | body>.contents.wide{
28 | margin-left:3em;
29 | }
30 |
31 | body>.contents>h1{
32 | margin:0;
33 | }
--------------------------------------------------------------------------------
/src/page/apps/AppsPage.js:
--------------------------------------------------------------------------------
1 | ///
2 | var AppsPage = (function () {
3 | function AppsPage() {
4 | this.title = "Apps";
5 | this.component = "apps-page";
6 | this.icon = "bookmark-o";
7 | ko.track(this);
8 | }
9 | return AppsPage;
10 | })();
11 | //require('./AppsPage.less');
12 | ko.components.register('apps-page', {
13 | template: require('./AppsPage.html'),
14 | viewModel: {
15 | createViewModel: function (params, componentInfo) {
16 | return params instanceof AppsPage ? params : params.option;
17 | }
18 | }
19 | });
20 | module.exports = AppsPage;
21 |
--------------------------------------------------------------------------------
/src/page/error/ErrorPage.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | class ErrorPage implements IPage{
4 | public title ="Error";
5 | public component ="error-page";
6 | public icon = "warning";
7 |
8 | public code:number=500;
9 | public message:string = '';
10 |
11 | constructor(
12 | ){
13 | ko.track(this);
14 | }
15 | }
16 | export = ErrorPage;
17 |
18 | //require('./ErrorPage.less');
19 | ko.components.register('error-page',{
20 | template: require('./ErrorPage.html'),
21 | viewModel:{
22 | createViewModel(params, componentInfo){
23 | return params instanceof ErrorPage ? params : params.option;
24 | }
25 | }
26 | });
27 |
28 |
--------------------------------------------------------------------------------
/src/parts/directory-tree/DirectoryTree.less:
--------------------------------------------------------------------------------
1 | directory-tree{
2 | display:block;
3 | directory-tree {
4 | margin-left: -2em;
5 | }
6 | ul.fa-ul{
7 | margin-left:2em;
8 | li{
9 | span.name{
10 | display:inline-block;
11 | color:darkgreen;
12 | margin-right:1em;
13 | user-select:none;
14 | -webkit-user-select:none;
15 | &:hover{
16 | text-decoration: underline;
17 | }
18 | }
19 | span.description{
20 | color: #aaa;
21 | }
22 |
23 | .fa-folder,
24 | .fa-folder-open-o{
25 | color: darkorange;
26 | &~span.name{
27 | color: blue;
28 | cursor:pointer;
29 | }
30 | }
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/parts/side-nav/SideNav.js:
--------------------------------------------------------------------------------
1 | var SideNav = (function () {
2 | function SideNav(menu) {
3 | this.menu = menu;
4 | this.isShown = true;
5 | ko.track(this);
6 | }
7 | SideNav.prototype.toggle = function () {
8 | this.isShown = !this.isShown;
9 | };
10 | return SideNav;
11 | })();
12 | require('./SideNav.less');
13 | ko.components.register('side-nav', {
14 | template: require('./SideNav.html'),
15 | viewModel: {
16 | createViewModel: function (params, componentInfo) {
17 | return params instanceof SideNav ? params : ko.unwrap(params.option);
18 | }
19 | }
20 | });
21 | module.exports = SideNav;
22 |
--------------------------------------------------------------------------------
/src/parts/widget/Widget.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | class Widget{
4 | private element:Element;
5 | constructor(
6 | public title
7 | ){
8 | ko.track(this);
9 | }
10 | public link(element:Element){
11 | this.element = element;
12 | //$(element).draggable();
13 | }
14 | }
15 | export = Widget;
16 |
17 | require('./Widget.less');
18 | ko.components.register('widget',{
19 | template: require('./Widget.html'),
20 | viewModel:{
21 | createViewModel(params, componentInfo){
22 | var vm:Widget = params instanceof Widget ? params : ko.utils.unwrapObservable(params.option);
23 | vm.link(componentInfo.element);
24 | return vm;
25 | }
26 | }
27 | });
28 |
--------------------------------------------------------------------------------
/src/parts/directory-tree/DirectoryTree.html:
--------------------------------------------------------------------------------
1 |
2 | -
3 |
4 | {{name}}
5 | [{{description}}]
6 |
7 | -
8 |
9 | -
10 | {{#if: $data.sub}}
11 |
12 | {{/if}}
13 | {{#else}}
14 |
15 | {{name}}
16 | [{{description}}]
17 | {{/else}}
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/tsd.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v4",
3 | "repo": "borisyankov/DefinitelyTyped",
4 | "ref": "master",
5 | "path": "typings",
6 | "bundle": "typings/tsd.d.ts",
7 | "installed": {
8 | "sugar/sugar.d.ts": {
9 | "commit": "bd9a1922e44ddf35953587a92c5caf4242bf6ea5"
10 | },
11 | "jquery/jquery.d.ts": {
12 | "commit": "bd9a1922e44ddf35953587a92c5caf4242bf6ea5"
13 | },
14 | "knockout/knockout.d.ts": {
15 | "commit": "7be40b2a8aca2288fe7011cd24959718756a5664"
16 | },
17 | "jqueryui/jqueryui.d.ts": {
18 | "commit": "0202fa011287e4f8394f01edc6681442dbdeaf51"
19 | },
20 | "node/node.d.ts": {
21 | "commit": "5e8ac2341f100202415ff39d8f79875b439ac677"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/parts/directory-tree/DirectoryTree.js:
--------------------------------------------------------------------------------
1 | var DirectoryTree = (function () {
2 | function DirectoryTree(name, description, sub) {
3 | this.name = name;
4 | this.description = description;
5 | this.sub = sub;
6 | this.isOpened = true;
7 | ko.track(this);
8 | }
9 | return DirectoryTree;
10 | })();
11 | require('./DirectoryTree.less');
12 | ko.components.register('directory-tree', {
13 | template: require('./DirectoryTree.html'),
14 | viewModel: {
15 | createViewModel: function (params, componentInfo) {
16 | return params instanceof DirectoryTree ? params : ko.unwrap(params.option);
17 | }
18 | }
19 | });
20 | module.exports = DirectoryTree;
21 |
--------------------------------------------------------------------------------
/src/page/error/ErrorPage.js:
--------------------------------------------------------------------------------
1 | ///
2 | var ErrorPage = (function () {
3 | function ErrorPage() {
4 | this.title = "Error";
5 | this.component = "error-page";
6 | this.icon = "warning";
7 | this.code = 500;
8 | this.message = '';
9 | ko.track(this);
10 | }
11 | return ErrorPage;
12 | })();
13 | //require('./ErrorPage.less');
14 | ko.components.register('error-page', {
15 | template: require('./ErrorPage.html'),
16 | viewModel: {
17 | createViewModel: function (params, componentInfo) {
18 | return params instanceof ErrorPage ? params : params.option;
19 | }
20 | }
21 | });
22 | module.exports = ErrorPage;
23 |
--------------------------------------------------------------------------------
/src/parts/directory-tree/DirectoryTree.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import MenuItem = require('../MenuItem');
3 | import SideNav = require('../directory-tree/DirectoryTree');
4 |
5 | class DirectoryTree{
6 | public isOpened = true;
7 | constructor(
8 | public name:string,
9 | public description:string,
10 | public sub: {name:string;description:string}[]
11 | ){
12 | ko.track(this);
13 | }
14 | }
15 | export = DirectoryTree;
16 |
17 | require('./DirectoryTree.less');
18 | ko.components.register('directory-tree',{
19 | template: require('./DirectoryTree.html'),
20 | viewModel:{
21 | createViewModel(params, componentInfo){
22 | return params instanceof DirectoryTree ? params : ko.unwrap(params.option);
23 | }
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ko-spa-example
2 | ==============
3 |
4 | Typescript( knockout + punches + es5 ) and LESS and WebPack
5 | ------------
6 |
7 |
8 | [WebPack]
9 |
10 | - knockout.js (ver 3.2 with component)
11 | - with knockout.punches
12 | - with kunockout.es5
13 | - and more
14 |
15 |
16 | Demo
17 | ------
18 | Legacy: http://mkgaru.github.io/ko_spa_example/6b7d9d9/
19 | Current: http://mkgaru.github.io/ko_spa_example/63d449f/ (Github's Demo can't page reload. maby 404)
20 |
21 | Usage
22 | ------
23 |
24 | $ git clone https://github.com/MKGaru/ko-spa-example.git
25 | $ cd ko-spa-example
26 | $ sh init.sh #init npm , bower , tsd and webpack
27 | $ npm start #run demo server
28 |
29 | and, access to http://localhost:5000/
30 |
--------------------------------------------------------------------------------
/src/parts/widget/Widget.js:
--------------------------------------------------------------------------------
1 | ///
2 | var Widget = (function () {
3 | function Widget(title) {
4 | this.title = title;
5 | ko.track(this);
6 | }
7 | Widget.prototype.link = function (element) {
8 | this.element = element;
9 | //$(element).draggable();
10 | };
11 | return Widget;
12 | })();
13 | require('./Widget.less');
14 | ko.components.register('widget', {
15 | template: require('./Widget.html'),
16 | viewModel: {
17 | createViewModel: function (params, componentInfo) {
18 | var vm = params instanceof Widget ? params : ko.utils.unwrapObservable(params.option);
19 | vm.link(componentInfo.element);
20 | return vm;
21 | }
22 | }
23 | });
24 | module.exports = Widget;
25 |
--------------------------------------------------------------------------------
/src/parts/widget/Widget.less:
--------------------------------------------------------------------------------
1 | widget{
2 | display:block;
3 | background:white;
4 | border:solid 1px #ccc;
5 | box-shadow: 2px 2px 2px #ddd;
6 | margin: 0 2px 2px 0;
7 | position: relative;
8 |
9 | &>header{
10 | cursor:move;
11 | }
12 | &>div{
13 |
14 | }
15 | &>footer{
16 | position: absolute;
17 | bottom: 0;
18 | left: 0;
19 | right: 0;
20 | }
21 |
22 |
23 | .data-col(@i) when(@i>0){
24 | &[data-col="@{i}"] {
25 | left: 10 + (@i - 1) *(250 + 10*2px);
26 | }
27 | .data-col(@i - 1);
28 | }
29 | .data-col(5);
30 |
31 | .data-row(@i) when(@i>0){
32 | &[data-row="@{i}"] {
33 | top: 10 + (@i - 1) *(250 + 10*2px);
34 | }
35 | .data-row(@i - 1);
36 | }
37 | .data-row(25);
38 |
39 | .data-sizey(@i) when(@i>0){
40 | &[data-sizey="@{i}"] {
41 | height: -10*2 + @i *(250 + 10*2px);
42 | }
43 | .data-sizey(@i - 1);
44 | }
45 | .data-sizey(24);
46 |
47 | .data-sizex(@i) when(@i>0){
48 | &[data-sizex="@{i}"] {
49 | width: -10*2 + @i *(250 + 10*2px);
50 | }
51 | .data-sizex(@i - 1);
52 | }
53 | .data-sizex(4);
54 | }
55 |
--------------------------------------------------------------------------------
/src/parts/side-nav/SideNav.less:
--------------------------------------------------------------------------------
1 | side-nav{
2 | display:block;
3 | height:100%;
4 | background: #e6e9ee;
5 | ul{
6 | list-style:none;
7 | padding:0;
8 | margin:0;
9 | width: 15em;
10 | transition: width 250ms;
11 | &.off{
12 | width: 3em;
13 | }
14 | li{
15 | transition: background 500ms;
16 | a{
17 | display:block;
18 | color: #777;
19 | padding: 0.7em;
20 | font-size: 1.15em;
21 | white-space: nowrap;
22 |
23 | &:link,
24 | &:visited{
25 | color: #777;
26 | }
27 | }
28 | &:hover{
29 | background: #eeeeee;
30 | a {
31 | color:#222;
32 | text-decoration: none;
33 | }
34 | }
35 | &.active{
36 | background: #4697ce;
37 | transition: background 100ms ease-out;
38 | a{
39 | color: white;
40 | text-decoration: non;
41 | }
42 | &:after{ /* caret <| */
43 | content: "";
44 | display: block;
45 | width: 0;
46 | height: 0;
47 | border: 0.85em solid transparent;
48 | border-right: 0.85em solid white;
49 | position: relative;
50 | float: right;
51 | top: -2.3em;
52 | pointer-events: none;
53 | }
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dashboard
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 |
8 |
9 | var app = express();
10 |
11 | // view engine setup
12 |
13 | // uncomment after placing your favicon in /public
14 | //app.use(favicon(__dirname + '/public/favicon.ico'));
15 | app.use(logger('dev'));
16 | app.use(bodyParser.json());
17 | app.use(bodyParser.urlencoded({ extended: false }));
18 | app.use(cookieParser());
19 | app.use(express.static(path.join(__dirname, 'public')));
20 |
21 | app.all('/*', function(req, res){
22 | res.sendFile(path.join(__dirname,'public/index.html'));
23 | });
24 |
25 | // catch 404 and forward to error handler
26 | app.use(function(req, res, next) {
27 | var err = new Error('Not Found');
28 | err.status = 404;
29 | next(err);
30 | });
31 |
32 | // error handlers
33 |
34 | // development error handler
35 | // will print stacktrace
36 | if (app.get('env') === 'development') {
37 | app.use(function(err, req, res, next) {
38 | res.status(err.status || 500);
39 | res.send(err);
40 | });
41 | }
42 |
43 | // production error handler
44 | // no stacktraces leaked to user
45 | app.use(function(err, req, res, next) {
46 | res.status(err.status || 500);
47 | res.send(err);
48 | });
49 |
50 | app.listen(5000);
--------------------------------------------------------------------------------
/src/parts/widget/WidgetHolder.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import Widget = require('./Widget');
3 |
4 | class WidgetHolder{
5 | private element:Element;
6 | public gridster:any;
7 | constructor(
8 | public widgets:{widget:Widget;size_x:number;size_y:number;row:number;col:number;}[]
9 | ){
10 | ko.track(this);
11 | }
12 |
13 | public link(element:Element){
14 | var holder = this;
15 | this.element = element;
16 |
17 | this.gridster = $(this.element).gridster({
18 | widget_margins: [10, 10],
19 | widget_base_dimensions: [250, 250],
20 | widget_selector: 'widget',
21 | auto_init:true,
22 | autogenerate_stylesheet:false,
23 | resize: {
24 | enabled: true,
25 | handle_append_to:'footer'
26 | },
27 | draggable:{
28 | items: 'widget',
29 | handle: 'header'
30 | }
31 | }).data('gridster');
32 |
33 |
34 | this.widgets.forEach((widget,i)=>{
35 | holder.gridster.add_widget('',
36 | widget.size_x,
37 | widget.size_y,
38 | widget.col,
39 | widget.row
40 | )
41 | });
42 | }
43 | }
44 | export = WidgetHolder;
45 |
46 | require('./WidgetHolder.less');
47 | ko.components.register('widget-holder',{
48 | template: '',
49 | viewModel:{
50 | createViewModel(params, componentInfo){
51 | var vm:WidgetHolder = params instanceof WidgetHolder ? params : ko.unwrap(params.option);
52 | vm.link(componentInfo.element);
53 | return vm;
54 | }
55 | }
56 | });
57 |
--------------------------------------------------------------------------------
/src/parts/widget/WidgetHolder.js:
--------------------------------------------------------------------------------
1 | var WidgetHolder = (function () {
2 | function WidgetHolder(widgets) {
3 | this.widgets = widgets;
4 | ko.track(this);
5 | }
6 | WidgetHolder.prototype.link = function (element) {
7 | var holder = this;
8 | this.element = element;
9 | this.gridster = $(this.element).gridster({
10 | widget_margins: [10, 10],
11 | widget_base_dimensions: [250, 250],
12 | widget_selector: 'widget',
13 | auto_init: true,
14 | autogenerate_stylesheet: false,
15 | resize: {
16 | enabled: true,
17 | handle_append_to: 'footer'
18 | },
19 | draggable: {
20 | items: 'widget',
21 | handle: 'header'
22 | }
23 | }).data('gridster');
24 | this.widgets.forEach(function (widget, i) {
25 | holder.gridster.add_widget('', widget.size_x, widget.size_y, widget.col, widget.row);
26 | });
27 | };
28 | return WidgetHolder;
29 | })();
30 | require('./WidgetHolder.less');
31 | ko.components.register('widget-holder', {
32 | template: '',
33 | viewModel: {
34 | createViewModel: function (params, componentInfo) {
35 | var vm = params instanceof WidgetHolder ? params : ko.unwrap(params.option);
36 | vm.link(componentInfo.element);
37 | return vm;
38 | }
39 | }
40 | });
41 | module.exports = WidgetHolder;
42 |
--------------------------------------------------------------------------------
/src/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: 'Application',
6 | output: {
7 | filename: '../public/js/bundle.js'
8 | },
9 | module: {
10 | loaders: [
11 | { test: /\.less$/, loader: 'style!css!less' },
12 | { test: /\.html$/, loader: 'html' },
13 | { test: /\.svg$/, loader: 'url-loader?mimetype=image/svg+xml' }
14 | /*
15 | { test: /\.woff$/, loader: 'url-loader?mimetype=application/font-woff' },
16 | { test: /\.eot$/, loader: 'url-loader?mimetype=application/font-woff' },
17 | { test: /\.ttf$/, loader: 'url-loader?mimetype=application/font-woff' },
18 | { test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&minetype=application/font-woff" },
19 | { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?mimetype=application/font-woff" }
20 | */
21 | ]
22 | },
23 | resolve: {
24 | root: [
25 | // We want roots to resolve the app code:
26 | path.resolve('.'),
27 | // and the bower components:
28 | path.resolve('../public/lib')
29 | ],
30 | alias: {
31 | /*
32 | // This one first to match just the entrypoint module.
33 | // We only need this because the module name doesn't match the file name.
34 | myApp$: 'myApp/app',
35 | // This one maps all our modules called 'myApp.something' to the app/js
36 | // directory
37 | myApp: path.resolve('app', 'js'),
38 | // This is also needed because the module name doesn't match the file name
39 | // but we don't need to locate the file because it is a bower component
40 | // with a file name the same as the directory (component) name:
41 | // bower_components/angular-route/angular-route
42 | ngRoute$: 'angular-route'
43 | */
44 | }
45 | },
46 | plugins:[
47 | new webpack.ResolverPlugin(
48 | new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("../bower.json", ["main"])
49 | )
50 | ]
51 | };
--------------------------------------------------------------------------------
/src/page/dashboard/DashboardPage.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import Widget = require('../../parts/widget/Widget');
4 | import WidgetHolder = require('../../parts/widget/WidgetHolder');
5 |
6 | class DashboardPage implements IPage{
7 | public title:string = undefined;
8 | public icon = "tachometer";
9 | public component = "dashboard-page";
10 |
11 | public id:string=undefined;
12 | public widgetHolder:WidgetHolder = undefined;
13 |
14 | public message=undefined;
15 | constructor(){
16 | ko.track(this);
17 | }
18 |
19 | public load(id:string){
20 | this.id = id;
21 | var base = $("base").attr("href");
22 | var endpoint = "{base}api/dashboard/{id}.json".assign({base:base,id:id});
23 | var dashboard = this;
24 |
25 | return $.getJSON(endpoint)
26 | .done(function(data){
27 | //DEMO GithubPageでのテストデモ用に、localstorageから復帰するよ。
28 | var restore = localStorage.getItem(endpoint);
29 | if(restore){
30 | data = JSON.parse(restore);
31 | }
32 | //~ forDEMO
33 |
34 | dashboard.title = data.title;
35 | dashboard.widgetHolder = new WidgetHolder(data.widgets.map(widget=>({
36 | widget: new Widget(widget.data),
37 | size_x:widget.size_x,
38 | size_y:widget.size_y,
39 | col:widget.col,
40 | row:widget.row
41 | })))
42 | })
43 | }
44 | private save(){
45 | var widgetHolder = this.widgetHolder;
46 | var serialized = {
47 | title: this.title,
48 | widgets:[]
49 | };
50 | serialized.widgets = widgetHolder.gridster.serialize().map((widgetLayout,index)=>({
51 | type:"text",
52 | data: widgetHolder.widgets[index].widget.title,
53 | size_x:widgetLayout.size_x,
54 | size_y:widgetLayout.size_y,
55 | col:widgetLayout.col,
56 | row:widgetLayout.row
57 | }));
58 |
59 | var base = $("base").attr("href");
60 | var endpoint = "{base}api/dashboard/{id}.json".assign({base:base,id:this.id});
61 |
62 | //GithubPageでのテストデモ用に、localstorageに退避するよ
63 | localStorage.setItem(endpoint,JSON.stringify(serialized));
64 |
65 | this.message="Save success.";
66 |
67 | /*
68 | $.ajax({
69 | type: "post",
70 | url:endpoint,
71 | data: JSON.stringify(serialized),
72 | contentType: 'application/json'
73 | }).done(function(){
74 |
75 | }).fail(function(){
76 |
77 | });
78 | */
79 |
80 | }
81 | }
82 | export = DashboardPage;
83 |
84 | require('./DashboardPage.less');
85 | ko.components.register('dashboard-page',{
86 | template: require('./DashboardPage.html'),
87 | viewModel:{
88 | createViewModel(params, componentInfo){
89 | return params instanceof DashboardPage ? params : params.option;
90 | }
91 | }
92 | });
93 |
94 |
--------------------------------------------------------------------------------
/src/Application.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import SideNav = require('parts/side-nav/SideNav');
3 | import HeaderNav = require('parts/header-nav/HeaderNav');
4 | import MenuItem = require('parts/MenuItem');
5 |
6 | import Widget = require('parts/widget/Widget');
7 |
8 | import AppsPage = require('page/apps/AppsPage');
9 | import DashboardPage =require('page/dashboard/DashboardPage');
10 | import HomePage = require('page/home/HomePage');
11 | import ErrorPage = require('page/error/ErrorPage');
12 |
13 | require('sugar'); //http://sugarjs.com/api
14 | require('html5-history-api'); //https://github.com/devote/HTML5-History-API
15 | var page = require('page'); //https://github.com/visionmedia/page.js
16 |
17 | class Application{
18 | public sideNav:SideNav;
19 | public headerNav:HeaderNav;
20 |
21 | public pages:{[name:string]:IPage};
22 | public page="home";
23 | public href="";
24 |
25 | constructor(){
26 | // Init Page VMs
27 | var pages = this.pages ={
28 | 'home': new HomePage(),
29 | 'apps': new AppsPage(),
30 | 'dashboard': undefined, //Dynamic Gen
31 | 'error': new ErrorPage()
32 | };
33 | ko.track(pages);
34 |
35 | // Init Common Parts VM
36 | this.sideNav = new SideNav(
37 | [
38 | new MenuItem(pages.home, ''),
39 | new MenuItem('1stDashboard','tachometer','dashboard/1'),
40 | new MenuItem('2ndDashboard','tachometer','dashboard/2'),
41 | new MenuItem(pages.apps, 'app'),
42 | new MenuItem('ErrorSample','warning','hogehoge')
43 | ]
44 | );
45 | this.headerNav = new HeaderNav(
46 | this.sideNav
47 | );
48 |
49 | ko.track(this);
50 | }
51 | }
52 | export=Application;
53 |
54 | class ApplicationRouter{
55 | constructor(
56 | private app:Application
57 | ){
58 | page.base($("base").attr("href"));
59 |
60 | page('*',(ctx,next)=>{
61 | app.href = ctx.pathname.substr(1);
62 | next();
63 | });
64 | page('', (ctx,next)=>{app.page='home'});
65 | page('dashboard/:id', (ctx,next)=>{
66 | var dashboardPage = new DashboardPage();
67 | dashboardPage.load(ctx.params.id)
68 | .done(data=>{
69 | app.pages['dashboard'] = dashboardPage;
70 | app.page='dashboard';
71 | })
72 | .fail(err=>{
73 | next();
74 | });
75 | });
76 | page('app',(ctx,next)=>{app.page='apps'});
77 | page('*',(ctx,next)=>{
78 | var errorPage = (app.pages['error']);
79 | errorPage.code = 404;
80 | errorPage.message = "Route Not Found";
81 | app.page='error';
82 | });
83 | page();
84 | }
85 | }
86 |
87 | KnockoutElse.init(); // knockout-else : https://github.com/brianmhunt/knockout-else
88 | ko.punches.enableAll(); // knockout-punches : https://github.com/mbest/knockout.punches
89 |
90 |
91 | $(function(){
92 | var app = new Application();
93 | //window['app'] = app; //for Console Debug.
94 | new ApplicationRouter(app);
95 | ko.applyBindings(app,$('html')[0]);
96 | });
97 |
98 |
--------------------------------------------------------------------------------
/src/page/home/HomePage.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import DirectoryTree = require('../../parts/directory-tree/DirectoryTree');
4 |
5 | class HomePage implements IPage{
6 | public title = "DirTree";
7 | public component= "home-page";
8 | public icon = "folder";
9 |
10 |
11 | public resources:any =null;
12 | constructor(
13 | ){
14 | ko.track(this);
15 | }
16 |
17 | public dir = new DirectoryTree("/","",[
18 | new DirectoryTree("public","Public Web Dir",[
19 | new DirectoryTree("api","Stub Response Service",[
20 | {name:"resources.json",description:"Stub Server Status Response"}
21 | ]),
22 | new DirectoryTree("css","Application CSS Files",[
23 | {name:"style.css",description:"Common CSS File"}
24 | ]),
25 | new DirectoryTree("js","Application JavaScript Files",[
26 | {name:"bundle.js",description:"(Application and Library) Generated by WebPack"}
27 | ]),
28 | new DirectoryTree("lib","Dependence library (without Webpack)",[
29 | ]),
30 | {name:"index.html",description:"Common SPA base page."}
31 | ]),
32 | new DirectoryTree("src","Application Build Src",[
33 | new DirectoryTree("node_modules","Build and dependent library",[
34 | ]),
35 | new DirectoryTree("page","Contents of SPA",[
36 | new DirectoryTree("foo","Some page component",[
37 | {name:"FooPage.html",description:"HTML of Page"},
38 | {name:"FooPage.less",description:"Style of Page (option)"},
39 | {name:"FooPage.ts", description:"Script of Page (ViewModel(implements IPage) , component register , style append)"},
40 | ]),
41 | new DirectoryTree("bar","Some page component",[
42 | {name:"BarPage.html",description:"HTML of Page"},
43 | {name:"BarPage.ts", description:"Script of Page (ViewModel(implements IPage) , component register , style append)"},
44 | ]),
45 | {name:"IPage.d.ts",description:"Page interface define"},
46 | ]),
47 | new DirectoryTree("parts","Custom element component",[
48 | new DirectoryTree("baz","Some component",[
49 | {name:"Baz.html",description:"Component Template"},
50 | {name:"Baz.less",description:"Style of Component (option)"},
51 | {name:"Baz.ts", description:"Script of Component (ViewModel , component register , style append)"},
52 | ]),
53 | ]),
54 | new DirectoryTree("typings","Typescript Definitely Typed(by tsd)",[
55 | ]),
56 | {name:"Application.ts",description:"Application Main"},
57 | {name:"package.json",description:"npm package meta"},
58 | {name:"references.d.ts",description:"Typescript Definitely Reference"},
59 | {name:"tsd.json",description:"Typescript Definitely Typed meta"},
60 | {name:"webpack.config.js",description:"WebPack build config"}
61 | ])
62 | ]);
63 |
64 | }
65 | export = HomePage;
66 |
67 |
68 | require('./HomePage.less');
69 | ko.components.register('home-page',{
70 | template: require('./HomePage.html'),
71 | viewModel:{
72 | createViewModel(params, componentInfo){
73 | return params instanceof HomePage ? params : params.option;
74 | }
75 | }
76 | });
77 |
78 |
--------------------------------------------------------------------------------
/src/page/dashboard/DashboardPage.js:
--------------------------------------------------------------------------------
1 | ///
2 | var Widget = require('../../parts/widget/Widget');
3 | var WidgetHolder = require('../../parts/widget/WidgetHolder');
4 | var DashboardPage = (function () {
5 | function DashboardPage() {
6 | this.title = undefined;
7 | this.icon = "tachometer";
8 | this.component = "dashboard-page";
9 | this.id = undefined;
10 | this.widgetHolder = undefined;
11 | this.message = undefined;
12 | ko.track(this);
13 | }
14 | DashboardPage.prototype.load = function (id) {
15 | this.id = id;
16 | var base = $("base").attr("href");
17 | var endpoint = "{base}api/dashboard/{id}.json".assign({ base: base, id: id });
18 | var dashboard = this;
19 | return $.getJSON(endpoint).done(function (data) {
20 | //DEMO GithubPageでのテストデモ用に、localstorageから復帰するよ。
21 | var restore = localStorage.getItem(endpoint);
22 | if (restore) {
23 | data = JSON.parse(restore);
24 | }
25 | //~ forDEMO
26 | dashboard.title = data.title;
27 | dashboard.widgetHolder = new WidgetHolder(data.widgets.map(function (widget) { return ({
28 | widget: new Widget(widget.data),
29 | size_x: widget.size_x,
30 | size_y: widget.size_y,
31 | col: widget.col,
32 | row: widget.row
33 | }); }));
34 | });
35 | };
36 | DashboardPage.prototype.save = function () {
37 | var widgetHolder = this.widgetHolder;
38 | var serialized = {
39 | title: this.title,
40 | widgets: []
41 | };
42 | serialized.widgets = widgetHolder.gridster.serialize().map(function (widgetLayout, index) { return ({
43 | type: "text",
44 | data: widgetHolder.widgets[index].widget.title,
45 | size_x: widgetLayout.size_x,
46 | size_y: widgetLayout.size_y,
47 | col: widgetLayout.col,
48 | row: widgetLayout.row
49 | }); });
50 | var base = $("base").attr("href");
51 | var endpoint = "{base}api/dashboard/{id}.json".assign({ base: base, id: this.id });
52 | //GithubPageでのテストデモ用に、localstorageに退避するよ
53 | localStorage.setItem(endpoint, JSON.stringify(serialized));
54 | this.message = "Save success.";
55 | /*
56 | $.ajax({
57 | type: "post",
58 | url:endpoint,
59 | data: JSON.stringify(serialized),
60 | contentType: 'application/json'
61 | }).done(function(){
62 |
63 | }).fail(function(){
64 |
65 | });
66 | */
67 | };
68 | return DashboardPage;
69 | })();
70 | require('./DashboardPage.less');
71 | ko.components.register('dashboard-page', {
72 | template: require('./DashboardPage.html'),
73 | viewModel: {
74 | createViewModel: function (params, componentInfo) {
75 | return params instanceof DashboardPage ? params : params.option;
76 | }
77 | }
78 | });
79 | module.exports = DashboardPage;
80 |
--------------------------------------------------------------------------------
/src/Application.js:
--------------------------------------------------------------------------------
1 | ///
2 | var SideNav = require('parts/side-nav/SideNav');
3 | var HeaderNav = require('parts/header-nav/HeaderNav');
4 | var MenuItem = require('parts/MenuItem');
5 | var AppsPage = require('page/apps/AppsPage');
6 | var DashboardPage = require('page/dashboard/DashboardPage');
7 | var HomePage = require('page/home/HomePage');
8 | var ErrorPage = require('page/error/ErrorPage');
9 | require('sugar'); //http://sugarjs.com/api
10 | require('html5-history-api'); //https://github.com/devote/HTML5-History-API
11 | var page = require('page'); //https://github.com/visionmedia/page.js
12 | var Application = (function () {
13 | function Application() {
14 | this.page = "home";
15 | this.href = "";
16 | // Init Page VMs
17 | var pages = this.pages = {
18 | 'home': new HomePage(),
19 | 'apps': new AppsPage(),
20 | 'dashboard': undefined,
21 | 'error': new ErrorPage()
22 | };
23 | ko.track(pages);
24 | // Init Common Parts VM
25 | this.sideNav = new SideNav([
26 | new MenuItem(pages.home, ''),
27 | new MenuItem('1stDashboard', 'tachometer', 'dashboard/1'),
28 | new MenuItem('2ndDashboard', 'tachometer', 'dashboard/2'),
29 | new MenuItem(pages.apps, 'app'),
30 | new MenuItem('ErrorSample', 'warning', 'hogehoge')
31 | ]);
32 | this.headerNav = new HeaderNav(this.sideNav);
33 | ko.track(this);
34 | }
35 | return Application;
36 | })();
37 | var ApplicationRouter = (function () {
38 | function ApplicationRouter(app) {
39 | this.app = app;
40 | page.base($("base").attr("href"));
41 | page('*', function (ctx, next) {
42 | app.href = ctx.pathname.substr(1);
43 | next();
44 | });
45 | page('', function (ctx, next) {
46 | app.page = 'home';
47 | });
48 | page('dashboard/:id', function (ctx, next) {
49 | var dashboardPage = new DashboardPage();
50 | dashboardPage.load(ctx.params.id).done(function (data) {
51 | app.pages['dashboard'] = dashboardPage;
52 | app.page = 'dashboard';
53 | }).fail(function (err) {
54 | next();
55 | });
56 | });
57 | page('app', function (ctx, next) {
58 | app.page = 'apps';
59 | });
60 | page('*', function (ctx, next) {
61 | var errorPage = app.pages['error'];
62 | errorPage.code = 404;
63 | errorPage.message = "Route Not Found";
64 | app.page = 'error';
65 | });
66 | page();
67 | }
68 | return ApplicationRouter;
69 | })();
70 | KnockoutElse.init(); // knockout-else : https://github.com/brianmhunt/knockout-else
71 | ko.punches.enableAll(); // knockout-punches : https://github.com/mbest/knockout.punches
72 | $(function () {
73 | var app = new Application();
74 | //window['app'] = app; //for Console Debug.
75 | new ApplicationRouter(app);
76 | ko.applyBindings(app, $('html')[0]);
77 | });
78 | module.exports = Application;
79 |
--------------------------------------------------------------------------------
/src/parts/widget/WidgetHolder.less:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | base File:
4 | ! gridster.js - v0.5.6 - 2014-09-25
5 | * http://gridster.net/
6 | * Copyright (c) 2014 ducksboard; Licensed MIT */
7 |
8 | .transition (@transition) {
9 | -webkit-transition: @transition;
10 | -moz-transition: @transition;
11 | -ms-transition: @transition;
12 | -o-transition: @transition;
13 | transition: @transition;
14 | }
15 |
16 | widget-holder{
17 | display:block;
18 | position:relative;
19 | &>*{
20 | margin: 0 auto;
21 | .transition(~"height .4s, width .4s");
22 | &:not(.dragging){
23 | .transition(~"top .4s, left .4s, height .4s, width .4s");
24 | }
25 | }
26 | .gs-w {
27 | z-index: 2;
28 | position: absolute;
29 | }
30 | .preview-holder {
31 | z-index: 1;
32 | position: absolute;
33 | background-color: #ccc;
34 | border-color: #ccc;
35 | opacity: 0.3;
36 | }
37 | .player-revert {
38 | z-index: 10!important;
39 | .transition(~"left .3s, top .3s !important");
40 | }
41 | .dragging,
42 | .resizing {
43 | z-index: 10!important;
44 | .transition(~"all 0s !important");
45 | }
46 |
47 | .ready{
48 | .gs-w:not(.preview-holder) {
49 | .transition(~"opacity .3s, left .3s, top .3s");
50 | }
51 | .gs-w:not(.preview-holder),
52 | .resize-preview-holder {
53 | .transition(~"opacity .3s, left .3s, top .3s, width .3s, height .3s");
54 | }
55 | }
56 |
57 |
58 | .gs-resize-handle {
59 | position: absolute;
60 | z-index: 1;
61 | }
62 |
63 | .gs-resize-handle-both {
64 | width: 20px;
65 | height: 20px;
66 | bottom: -8px;
67 | right: -8px;
68 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
69 | background-position: top left;
70 | background-repeat: no-repeat;
71 | cursor: se-resize;
72 | z-index: 20;
73 | }
74 |
75 | .gs-resize-handle-x {
76 | top: 0;
77 | bottom: 13px;
78 | right: -5px;
79 | width: 10px;
80 | cursor: e-resize;
81 | }
82 |
83 | .gs-resize-handle-y {
84 | left: 0;
85 | right: 13px;
86 | bottom: -5px;
87 | height: 10px;
88 | cursor: s-resize;
89 | }
90 |
91 | .gs-w:hover .gs-resize-handle,
92 | .resizing .gs-resize-handle {
93 | opacity: 1;
94 | }
95 |
96 | .gs-resize-handle,
97 | .gs-w.dragging .gs-resize-handle {
98 | opacity: 0;
99 | }
100 |
101 | .gs-resize-disabled .gs-resize-handle {
102 | display: none!important;
103 | }
104 |
105 | [data-max-sizex="1"] .gs-resize-handle-x,
106 | [data-max-sizey="1"] .gs-resize-handle-y,
107 | [data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle {
108 | display: none !important;
109 | }
110 |
111 | /* Uncomment this if you set helper : "clone" in draggable options */
112 | /*.gridster .player {
113 | opacity:0;
114 | }
115 | */
116 | }
117 |
--------------------------------------------------------------------------------
/src/page/home/HomePage.js:
--------------------------------------------------------------------------------
1 | ///
2 | var DirectoryTree = require('../../parts/directory-tree/DirectoryTree');
3 | var HomePage = (function () {
4 | function HomePage() {
5 | this.title = "DirTree";
6 | this.component = "home-page";
7 | this.icon = "folder";
8 | this.resources = null;
9 | this.dir = new DirectoryTree("/", "", [
10 | new DirectoryTree("public", "Public Web Dir", [
11 | new DirectoryTree("api", "Stub Response Service", [
12 | { name: "resources.json", description: "Stub Server Status Response" }
13 | ]),
14 | new DirectoryTree("css", "Application CSS Files", [
15 | { name: "style.css", description: "Common CSS File" }
16 | ]),
17 | new DirectoryTree("js", "Application JavaScript Files", [
18 | { name: "bundle.js", description: "(Application and Library) Generated by WebPack" }
19 | ]),
20 | new DirectoryTree("lib", "Dependence library (without Webpack)", [
21 | ]),
22 | { name: "index.html", description: "Common SPA base page." }
23 | ]),
24 | new DirectoryTree("src", "Application Build Src", [
25 | new DirectoryTree("node_modules", "Build and dependent library", [
26 | ]),
27 | new DirectoryTree("page", "Contents of SPA", [
28 | new DirectoryTree("foo", "Some page component", [
29 | { name: "FooPage.html", description: "HTML of Page" },
30 | { name: "FooPage.less", description: "Style of Page (option)" },
31 | { name: "FooPage.ts", description: "Script of Page (ViewModel(implements IPage) , component register , style append)" },
32 | ]),
33 | new DirectoryTree("bar", "Some page component", [
34 | { name: "BarPage.html", description: "HTML of Page" },
35 | { name: "BarPage.ts", description: "Script of Page (ViewModel(implements IPage) , component register , style append)" },
36 | ]),
37 | { name: "IPage.d.ts", description: "Page interface define" },
38 | ]),
39 | new DirectoryTree("parts", "Custom element component", [
40 | new DirectoryTree("baz", "Some component", [
41 | { name: "Baz.html", description: "Component Template" },
42 | { name: "Baz.less", description: "Style of Component (option)" },
43 | { name: "Baz.ts", description: "Script of Component (ViewModel , component register , style append)" },
44 | ]),
45 | ]),
46 | new DirectoryTree("typings", "Typescript Definitely Typed(by tsd)", [
47 | ]),
48 | { name: "Application.ts", description: "Application Main" },
49 | { name: "package.json", description: "npm package meta" },
50 | { name: "references.d.ts", description: "Typescript Definitely Reference" },
51 | { name: "tsd.json", description: "Typescript Definitely Typed meta" },
52 | { name: "webpack.config.js", description: "WebPack build config" }
53 | ])
54 | ]);
55 | ko.track(this);
56 | }
57 | return HomePage;
58 | })();
59 | require('./HomePage.less');
60 | ko.components.register('home-page', {
61 | template: require('./HomePage.html'),
62 | viewModel: {
63 | createViewModel: function (params, componentInfo) {
64 | return params instanceof HomePage ? params : params.option;
65 | }
66 | }
67 | });
68 | module.exports = HomePage;
69 |
--------------------------------------------------------------------------------
/public/lib/css3tips/css3-tips.css:
--------------------------------------------------------------------------------
1 | /**
2 | * CSS3 Tips v1.0.1
3 | *
4 | * A stylesheet for creating tooltips without using anything other than CSS3.
5 | *
6 | * created by c.bavota
7 | * released under GPL v2
8 | *
9 | * March 21st, 2014
10 | */
11 | [data-tips] {
12 | position: relative;
13 | text-decoration: none;
14 | }
15 |
16 | [data-tips]:after,
17 | [data-tips]:before {
18 | position: absolute;
19 | z-index: 100;
20 | opacity: 0;
21 | }
22 |
23 | [data-tips]:after {
24 | content: attr(data-tips);
25 | height: 25px;
26 | line-height: 25px;
27 | padding: 0 10px;
28 | font-size: 12px;
29 | text-align: center;
30 | color: #fff;
31 | background: #222;
32 | border-radius: 5px;
33 | text-shadow: 0 0 5px #000;
34 | -moz-box-shadow: 0 0 5px rgba(0,0,0,0.3);
35 | -webkit-box-shadow: 0 0 5px rgba(0,0,0,0.3);
36 | box-shadow: 0 0 5px rgba(0,0,0,0.3);
37 | white-space: nowrap;
38 | -moz-box-sizing: border-box;
39 | -webkit-box-sizing: border-box;
40 | box-sizing: border-box;
41 | }
42 |
43 | [data-tips]:before {
44 | content: "";
45 | width: 0;
46 | height: 0;
47 | border-width: 6px;
48 | border-style: solid;
49 | }
50 |
51 | [data-tips]:hover:after,
52 | [data-tips]:hover:before {
53 | opacity: 1;
54 | }
55 |
56 | /* Top tips */
57 | [data-tips].top-tip:after,
58 | [data-tips].top-tip:before {
59 | -webkit-transition: bottom 0.25s ease-in-out, opacity 0.25s ease-in-out;
60 | -moz-transition: bottom 0.25s ease-in-out, opacity 0.25s ease-in-out;
61 | transition: bottom 0.25s ease-in-out, opacity 0.25s ease-in-out;
62 | bottom: 90%;
63 | left: -9999px;
64 | margin-bottom: 12px;
65 | }
66 |
67 | [data-tips].top-tip:before {
68 | border-color: #222 transparent transparent transparent;
69 | margin-bottom: 0;
70 | }
71 |
72 | [data-tips].top-tip:hover:after,
73 | [data-tips].top-tip:hover:before {
74 | bottom: 100%;
75 | left: 0;
76 | }
77 |
78 | [data-tips].top-tip:hover:before {
79 | left: 15px;
80 | }
81 |
82 | /* Bottom tip */
83 | [data-tips].bottom-tip:after,
84 | [data-tips].bottom-tip:before {
85 | -webkit-transition: top 0.25s ease-in-out, opacity 0.25s ease-in-out;
86 | -moz-transition: top 0.25s ease-in-out, opacity 0.25s ease-in-out;
87 | transition: top 0.25s ease-in-out, opacity 0.25s ease-in-out;
88 | top: 90%;
89 | left: -9999px;
90 | margin-top: 12px;
91 | }
92 |
93 | [data-tips].bottom-tip:before {
94 | border-color: transparent transparent #222 transparent;
95 | margin-top: 0;
96 | }
97 |
98 | [data-tips].bottom-tip:hover:after,
99 | [data-tips].bottom-tip:hover:before {
100 | top: 100%;
101 | left: 0;
102 | }
103 |
104 | [data-tips].bottom-tip:hover:before {
105 | left: 15px;
106 | }
107 |
108 | /* Right tip */
109 | [data-tips].right-tip:after,
110 | [data-tips].right-tip:before {
111 | -webkit-transition: left 0.25s ease-in-out, opacity 0.25s ease-in-out;
112 | -moz-transition: left 0.25s ease-in-out, opacity 0.25s ease-in-out;
113 | transition: left 0.25s ease-in-out, opacity 0.25s ease-in-out;
114 | top: -9999px;
115 | left: 96%;
116 | margin-left: 12px;
117 | }
118 |
119 | [data-tips].right-tip:before {
120 | border-color: transparent #222 transparent transparent;
121 | margin-left: 0;
122 | }
123 |
124 | [data-tips].right-tip:hover:after,
125 | [data-tips].right-tip:hover:before {
126 | left: 100%;
127 | top: 0;
128 | }
129 |
130 | [data-tips].right-tip:hover:before {
131 | top: 7px;
132 | }
133 |
134 | /* Left tip */
135 | [data-tips].left-tip:after,
136 | [data-tips].left-tip:before {
137 | -webkit-transition: right 0.25s ease-in-out, opacity 0.25s ease-in-out;
138 | -moz-transition: right 0.25s ease-in-out, opacity 0.25s ease-in-out;
139 | transition: right 0.25s ease-in-out, opacity 0.25s ease-in-out;
140 | top: -9999px;
141 | right: 96%;
142 | margin-right: 12px;
143 | }
144 |
145 | [data-tips].left-tip:before {
146 | border-color: transparent transparent transparent #222;
147 | margin-right: 0;
148 | }
149 |
150 | [data-tips].left-tip:hover:after,
151 | [data-tips].left-tip:hover:before {
152 | right: 100%;
153 | top: 0;
154 | }
155 |
156 | [data-tips].left-tip:hover:before {
157 | top: 7px;
158 | }
--------------------------------------------------------------------------------