Node.js datasource plugin for freeboard.io with socket.io namespaces and rooms.
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>NodeJSToFreeboardIO</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.eclipsesource.jshint.ui.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.nodeclipse.ui.NodeNature</nature>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,3 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//datasources/plugin_node.js=UTF-8
|
||||
encoding/plugin_node_sample_server.js=UTF-8
|
60
README.md
|
@ -1,4 +1,58 @@
|
|||
plugins
|
||||
=======
|
||||
freeboard.io-node.js
|
||||
=========
|
||||
|
||||
Plugins for Freeboard.io
|
||||
This is a datasource plugin to connect freeboard.io dashboards to real-time node.js servers.
|
||||
|
||||
- Subscribe to real-time events using WebSockets (Sockets.io)
|
||||
- Listen for events from different servers
|
||||
- Restrict events from only certain [namespaces or rooms](http://socket.io/docs/rooms-and-namespaces/)
|
||||
|
||||
Installation
|
||||
--------------
|
||||
|
||||
1. Place the file ```/datasources/plugin_node.js``` in ```/js/freeboard/plugins``` of your freeboard.io installation.
|
||||
|
||||
2. Edit your freeboard.io main HTML file and add the plugin to the header:
|
||||
|
||||
```js
|
||||
<script type="text/javascript">
|
||||
head.js(
|
||||
...
|
||||
"/js/freeboard/plugins/plugin_node.js",
|
||||
```
|
||||
|
||||
Testing
|
||||
--------------
|
||||
|
||||
You can test this plugin by running the node.js **sample server** in your terminal:
|
||||
|
||||
```js
|
||||
node plugin_node_sample_server.js
|
||||
```
|
||||
|
||||
Open the **sample freeboard.io client** with your browser:
|
||||
|
||||
```js
|
||||
/plugin_node_sample_client.html
|
||||
```
|
||||
|
||||
Requirements
|
||||
--------------
|
||||
|
||||
To run the sample server make sure you have following dependencies installed:
|
||||
|
||||
1. [Node.js](http://nodejs.org)
|
||||
2. [Socket.io](http://socket.io)
|
||||
|
||||
|
||||
Screenshots
|
||||
--------------
|
||||
|
||||
In this screenshot, you can see the sample server and dashboard running with multiple clients and receiving data in real-time.
|
||||
|
||||

|
||||
|
||||
License
|
||||
----
|
||||
|
||||
MIT
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
/* Set scrolling behaviour here */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
background: #7e7;
|
||||
}
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
div.CodeMirror-overwrite div.CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; }
|
||||
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3 {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actuall scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
padding-bottom: 30px;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
padding-bottom: 30px;
|
||||
margin-bottom: -32px;
|
||||
display: inline-block;
|
||||
/* Hack to make IE7 behave */
|
||||
*zoom:1;
|
||||
*display:inline;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-wrap .CodeMirror-scroll {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
|
||||
.CodeMirror span { *vertical-align: text-bottom; }
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/*! gridster.js - v0.1.0 - 2013-06-14 - * http://gridster.net/ - Copyright (c) 2013 ducksboard; Licensed MIT */
|
||||
.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s;-moz-transition:height .4s;-o-transition:height .4s;-ms-transition:height .4s;transition:height .4s}.gridster .gs_w{z-index:2;position:absolute}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}
|
|
@ -0,0 +1,163 @@
|
|||
// ┌────────────────────────────────────────────────────────────────────┐ \\
|
||||
// │ freeboard.io-node.js │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Copyright © 2014 Hugo Sequeira (https://github.com/hugocore) │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Licensed under the MIT license. │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Freeboard datasource plugin for node.js and socket.io. │ \\
|
||||
// └────────────────────────────────────────────────────────────────────┘ \\
|
||||
|
||||
(function() {
|
||||
|
||||
var nodeJSDatasource = function(settings, updateCallback) {
|
||||
|
||||
var self = this;
|
||||
var currentSettings = settings;
|
||||
var url;
|
||||
var socket;
|
||||
var newMessageCallback;
|
||||
|
||||
function onNewMessageHandler(message) {
|
||||
|
||||
console.debug("Message received %s", message);
|
||||
|
||||
var objdata = JSON.parse(message);
|
||||
|
||||
if (typeof objdata == "object") {
|
||||
updateCallback(objdata);
|
||||
} else {
|
||||
updateCallback(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function joinRoom(roomName, roomEvent) {
|
||||
// Sends request to join the new room
|
||||
// (handle event on server-side)
|
||||
self.socket.emit(roomEvent, roomName);
|
||||
console.info("Joining room '%s' with event '%s'", roomName, roomEvent);
|
||||
}
|
||||
|
||||
function connectToServer(url, rooms) {
|
||||
// Establish connection with server
|
||||
self.url = url;
|
||||
self.socket = io.connect(self.url);
|
||||
|
||||
// Join the rooms
|
||||
self.socket.on('connect', function() {
|
||||
|
||||
console.info("Connecting to Node.js at: %s", self.url);
|
||||
|
||||
// Join the rooms
|
||||
_.each(rooms, function(roomConfig) {
|
||||
var roomName = roomConfig.roomName;
|
||||
var roomEvent = roomConfig.roomEvent;
|
||||
|
||||
if (!_.isUndefined(roomName) && !_.isUndefined(roomEvent)) {
|
||||
joinRoom(roomName, roomEvent);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
self.socket.on('connect_error', function(object) {
|
||||
console.error("It was not possible to connect to Node.js at: %s", self.url);
|
||||
});
|
||||
|
||||
self.socket.on('reconnect_error', function(object) {
|
||||
console.error("Still was not possible to re-connect to Node.js at: %s", self.url);
|
||||
});
|
||||
|
||||
self.socket.on('reconnect_failed', function(object) {
|
||||
console.error("Stopping re-connecting to Node.js at: %s", self.url);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function disconnecFromServer() {
|
||||
// Disconnect any older socket
|
||||
if (self.socket) {
|
||||
self.socket.disconnect();
|
||||
console.info("Disconnected from Node.js: %s", self.url);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDataSource() {
|
||||
|
||||
console.info("Subscribing to event: %s", currentSettings.eventName);
|
||||
|
||||
// Reset connection to server
|
||||
disconnecFromServer();
|
||||
connectToServer(currentSettings.url, currentSettings.rooms);
|
||||
|
||||
// Subscribe to the events
|
||||
var newEventName = currentSettings.eventName;
|
||||
self.newMessageCallback = onNewMessageHandler;
|
||||
self.socket.on(newEventName, function(message) {
|
||||
self.newMessageCallback(message);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
initializeDataSource();
|
||||
|
||||
this.updateNow = function() {
|
||||
// Just seat back, relax and wait for incoming events
|
||||
return;
|
||||
};
|
||||
|
||||
this.onDispose = function() {
|
||||
// Stop responding to messages
|
||||
self.newMessageCallback = function(message) {
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
this.onSettingsChanged = function(newSettings) {
|
||||
currentSettings = newSettings;
|
||||
initializeDataSource();
|
||||
};
|
||||
};
|
||||
|
||||
freeboard
|
||||
.loadDatasourcePlugin({
|
||||
type_name : "node_js",
|
||||
display_name : "Node.js (Socket.io)",
|
||||
description : "A real-time stream datasource from node.js servers using socket.io.",
|
||||
external_scripts : [ "https://cdn.socket.io/socket.io-1.0.6.js" ],
|
||||
settings : [
|
||||
{
|
||||
name : "url",
|
||||
display_name : "Server URL",
|
||||
description : "(Optional) In case you are using custom namespaces, add the name of the namespace (e.g. chat) at the end of your URL.<br>For example: http://localhost/chat",
|
||||
type : "text"
|
||||
},
|
||||
{
|
||||
name : "eventName",
|
||||
display_name : "Events",
|
||||
description : "The name of the events you want this datasource to subscribe to.",
|
||||
type : "text"
|
||||
},
|
||||
{
|
||||
name : "rooms",
|
||||
display_name : "(Optional) Rooms",
|
||||
description : "In case you are using rooms, specify the name of the rooms you want to join. Otherwise, leave this empty.",
|
||||
type : "array",
|
||||
settings : [ {
|
||||
name : "roomName",
|
||||
display_name : "Room name",
|
||||
type : "text"
|
||||
}, {
|
||||
name : "roomEvent",
|
||||
display_name : "Name of the event to join the room",
|
||||
type : "text"
|
||||
} ]
|
||||
} ],
|
||||
newInstance : function(settings, newInstanceCallback,
|
||||
updateCallback) {
|
||||
newInstanceCallback(new nodeJSDatasource(settings,
|
||||
updateCallback));
|
||||
}
|
||||
});
|
||||
}());
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
docco --css docco-fb.css ./../examples/plugin_example.js --output ./
|
|
@ -0,0 +1,630 @@
|
|||
/*--------------------- Typography ----------------------------*/
|
||||
|
||||
@import url(http://fonts.googleapis.com/css?family=Montserrat);
|
||||
|
||||
@font-face
|
||||
{
|
||||
font-family : 'aller-light';
|
||||
src : url('public/fonts/aller-light.eot');
|
||||
src : url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), url('public/fonts/aller-light.woff') format('woff'), url('public/fonts/aller-light.ttf') format('truetype');
|
||||
font-weight : normal;
|
||||
font-style : normal;
|
||||
}
|
||||
|
||||
@font-face
|
||||
{
|
||||
font-family : 'aller-bold';
|
||||
src : url('public/fonts/aller-bold.eot');
|
||||
src : url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), url('public/fonts/aller-bold.woff') format('woff'), url('public/fonts/aller-bold.ttf') format('truetype');
|
||||
font-weight : normal;
|
||||
font-style : normal;
|
||||
}
|
||||
|
||||
@font-face
|
||||
{
|
||||
font-family : 'novecento-bold';
|
||||
src : url('public/fonts/novecento-bold.eot');
|
||||
src : url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'), url('public/fonts/novecento-bold.woff') format('woff'), url('public/fonts/novecento-bold.ttf') format('truetype');
|
||||
font-weight : normal;
|
||||
font-style : normal;
|
||||
}
|
||||
|
||||
/*--------------------- Layout ----------------------------*/
|
||||
html
|
||||
{
|
||||
height : 100%;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
font-family : "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size : 14px;
|
||||
line-height : 18px;
|
||||
color : #30404f;
|
||||
margin : 0;
|
||||
padding : 0;
|
||||
height : 100%;
|
||||
}
|
||||
|
||||
#container
|
||||
{
|
||||
min-height : 100%;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
color : #000;
|
||||
}
|
||||
|
||||
b, strong
|
||||
{
|
||||
font-weight : 400;
|
||||
color : #fff;
|
||||
}
|
||||
|
||||
p, ul, ol
|
||||
{
|
||||
margin : 15px 0 0px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6
|
||||
{
|
||||
font-family : montserrat, sans-serif;
|
||||
color : #fff;
|
||||
line-height : 1em;
|
||||
font-weight : normal;
|
||||
text-transform : uppercase;
|
||||
margin : 30px 0 15px 0;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
margin-top : 40px;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
border : 0;
|
||||
background : 1px solid #ddd;
|
||||
height : 1px;
|
||||
margin : 20px 0;
|
||||
}
|
||||
|
||||
pre, tt, code
|
||||
{
|
||||
font-size : 12px;
|
||||
line-height : 16px;
|
||||
font-family : Menlo, Monaco, Consolas, "Lucida Console", monospace;
|
||||
margin : 0;
|
||||
padding : 0;
|
||||
}
|
||||
|
||||
.annotation
|
||||
{
|
||||
color: #A5A5A5;
|
||||
font-weight : 200;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.annotation pre
|
||||
{
|
||||
display : block;
|
||||
margin : 0;
|
||||
padding : 7px 10px;
|
||||
background : #fcfcfc;
|
||||
-moz-box-shadow : inset 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
-webkit-box-shadow : inset 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
box-shadow : inset 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
overflow-x : auto;
|
||||
}
|
||||
|
||||
.annotation pre code
|
||||
{
|
||||
border : 0;
|
||||
padding : 0;
|
||||
background : transparent;
|
||||
}
|
||||
|
||||
blockquote
|
||||
{
|
||||
border-left : 5px solid #ccc;
|
||||
margin : 0;
|
||||
padding : 1px 0 1px 1em;
|
||||
}
|
||||
|
||||
.sections blockquote p
|
||||
{
|
||||
font-family : Menlo, Consolas, Monaco, monospace;
|
||||
font-size : 12px;
|
||||
line-height : 16px;
|
||||
color : #999;
|
||||
margin : 10px 0 0;
|
||||
white-space : pre-wrap;
|
||||
}
|
||||
|
||||
ul.sections
|
||||
{
|
||||
list-style : none;
|
||||
padding : 0 0 5px 0;;
|
||||
margin : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Force border-box so that % widths fit the parent
|
||||
container without overlap because of margin/padding.
|
||||
|
||||
More Info : http://www.quirksmode.org/css/box.html
|
||||
*/
|
||||
ul.sections > li > div
|
||||
{
|
||||
-moz-box-sizing : border-box; /* firefox */
|
||||
-ms-box-sizing : border-box; /* ie */
|
||||
-webkit-box-sizing : border-box; /* webkit */
|
||||
-khtml-box-sizing : border-box; /* konqueror */
|
||||
box-sizing : border-box; /* css3 */
|
||||
}
|
||||
|
||||
/*---------------------- Jump Page -----------------------------*/
|
||||
#jump_to, #jump_page
|
||||
{
|
||||
margin : 0;
|
||||
background : white;
|
||||
-webkit-box-shadow : 0 0 25px #777;
|
||||
-moz-box-shadow : 0 0 25px #777;
|
||||
-webkit-border-bottom-left-radius : 5px;
|
||||
-moz-border-radius-bottomleft : 5px;
|
||||
font : 16px Arial;
|
||||
cursor : pointer;
|
||||
text-align : right;
|
||||
list-style : none;
|
||||
}
|
||||
|
||||
#jump_to a
|
||||
{
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
#jump_to a.large
|
||||
{
|
||||
display : none;
|
||||
}
|
||||
|
||||
#jump_to a.small
|
||||
{
|
||||
font-size : 22px;
|
||||
font-weight : bold;
|
||||
color : #676767;
|
||||
}
|
||||
|
||||
#jump_to, #jump_wrapper
|
||||
{
|
||||
position : fixed;
|
||||
right : 0;
|
||||
top : 0;
|
||||
padding : 10px 15px;
|
||||
margin : 0;
|
||||
}
|
||||
|
||||
#jump_wrapper
|
||||
{
|
||||
display : none;
|
||||
padding : 0;
|
||||
}
|
||||
|
||||
#jump_to:hover #jump_wrapper
|
||||
{
|
||||
display : block;
|
||||
}
|
||||
|
||||
#jump_page
|
||||
{
|
||||
padding : 5px 0 3px;
|
||||
margin : 0 0 25px 25px;
|
||||
}
|
||||
|
||||
#jump_page .source
|
||||
{
|
||||
display : block;
|
||||
padding : 15px;
|
||||
text-decoration : none;
|
||||
border-top : 1px solid #eee;
|
||||
}
|
||||
|
||||
#jump_page .source:hover
|
||||
{
|
||||
background : #f5f5ff;
|
||||
}
|
||||
|
||||
#jump_page .source:first-child
|
||||
{
|
||||
}
|
||||
|
||||
/*---------------------- Low resolutions (> 320px) ---------------------*/
|
||||
@media only screen and (min-width: 320px)
|
||||
{
|
||||
.pilwrap
|
||||
{
|
||||
display : none;
|
||||
}
|
||||
|
||||
ul.sections > li > div
|
||||
{
|
||||
display : block;
|
||||
padding : 5px 10px 0 10px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol
|
||||
{
|
||||
padding-left : 30px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content
|
||||
{
|
||||
background : #f5f5ff;
|
||||
overflow-x : auto;
|
||||
-webkit-box-shadow : inset 0 0 5px #e5e5ee;
|
||||
box-shadow : inset 0 0 5px #e5e5ee;
|
||||
border : 1px solid #dedede;
|
||||
margin : 5px 10px 5px 10px;
|
||||
padding-bottom : 5px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation pre
|
||||
{
|
||||
margin : 7px 0 7px;
|
||||
padding-left : 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation p tt, .annotation code
|
||||
{
|
||||
background : #f8f8ff;
|
||||
border : 1px solid #dedede;
|
||||
font-size : 12px;
|
||||
padding : 0 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 481px) ---------------------*/
|
||||
@media only screen and (min-width: 481px)
|
||||
{
|
||||
#container
|
||||
{
|
||||
position : relative;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
background-color : #f9f9f9;
|
||||
font-size : 15px;
|
||||
line-height : 21px;
|
||||
}
|
||||
|
||||
pre, tt, code
|
||||
{
|
||||
line-height : 18px;
|
||||
}
|
||||
|
||||
p, ul, ol
|
||||
{
|
||||
margin : 0 0 15px;
|
||||
}
|
||||
|
||||
#jump_to
|
||||
{
|
||||
padding : 5px 10px;
|
||||
}
|
||||
|
||||
#jump_wrapper
|
||||
{
|
||||
padding : 0;
|
||||
}
|
||||
|
||||
#jump_to, #jump_page
|
||||
{
|
||||
font : 10px Arial;
|
||||
text-transform : uppercase;
|
||||
}
|
||||
|
||||
#jump_page .source
|
||||
{
|
||||
padding : 5px 10px;
|
||||
}
|
||||
|
||||
#jump_to a.large
|
||||
{
|
||||
display : inline-block;
|
||||
}
|
||||
|
||||
#jump_to a.small
|
||||
{
|
||||
display : none;
|
||||
}
|
||||
|
||||
#background
|
||||
{
|
||||
position : absolute;
|
||||
top : 0;
|
||||
bottom : 0;
|
||||
width : 350px;
|
||||
background : #313131;
|
||||
border-right : 1px solid #e5e5ee;
|
||||
z-index : -1;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol
|
||||
{
|
||||
padding-left : 40px;
|
||||
}
|
||||
|
||||
ul.sections > li
|
||||
{
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
ul.sections > li > div
|
||||
{
|
||||
display : inline-block;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation
|
||||
{
|
||||
max-width : 350px;
|
||||
min-width : 350px;
|
||||
min-height : 5px;
|
||||
padding : 13px;
|
||||
overflow-x : hidden;
|
||||
white-space : normal;
|
||||
vertical-align : top;
|
||||
text-align : left;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation pre
|
||||
{
|
||||
margin : 15px 0 15px;
|
||||
padding-left : 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content
|
||||
{
|
||||
padding : 13px;
|
||||
vertical-align : top;
|
||||
background : #f9f9f9;
|
||||
border : none;
|
||||
-webkit-box-shadow : none;
|
||||
box-shadow : none;
|
||||
}
|
||||
|
||||
.pilwrap
|
||||
{
|
||||
position : relative;
|
||||
display : inline;
|
||||
}
|
||||
|
||||
.pilcrow
|
||||
{
|
||||
font : 12px Arial;
|
||||
text-decoration : none;
|
||||
color : #454545;
|
||||
position : absolute;
|
||||
top : 3px;
|
||||
left : -20px;
|
||||
padding : 1px 2px;
|
||||
opacity : 0;
|
||||
-webkit-transition : opacity 0.2s linear;
|
||||
}
|
||||
|
||||
.for-h1 .pilcrow
|
||||
{
|
||||
top : 47px;
|
||||
}
|
||||
|
||||
.for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow
|
||||
{
|
||||
top : 35px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation:hover .pilcrow
|
||||
{
|
||||
opacity : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 1025px) ---------------------*/
|
||||
@media only screen and (min-width: 1025px)
|
||||
{
|
||||
|
||||
body
|
||||
{
|
||||
font-size : 16px;
|
||||
line-height : 24px;
|
||||
}
|
||||
|
||||
#background
|
||||
{
|
||||
width : 525px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation
|
||||
{
|
||||
max-width : 525px;
|
||||
min-width : 525px;
|
||||
padding : 10px 25px 1px 50px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content
|
||||
{
|
||||
padding : 9px 15px 16px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- Syntax Highlighting -----------------------------*/
|
||||
|
||||
td.linenos
|
||||
{
|
||||
background-color : #f0f0f0;
|
||||
padding-right : 10px;
|
||||
}
|
||||
|
||||
span.lineno
|
||||
{
|
||||
background-color : #f0f0f0;
|
||||
padding : 0 5px 0 5px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
pre code
|
||||
{
|
||||
display : block;
|
||||
padding : 0.5em;
|
||||
color : #000;
|
||||
background : #f8f8ff
|
||||
}
|
||||
|
||||
pre .comment,
|
||||
pre .template_comment,
|
||||
pre .diff .header,
|
||||
pre .javadoc
|
||||
{
|
||||
color : #408080;
|
||||
font-style : italic
|
||||
}
|
||||
|
||||
pre .keyword,
|
||||
pre .assignment,
|
||||
pre .literal,
|
||||
pre .css .rule .keyword,
|
||||
pre .winutils,
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .subst
|
||||
{
|
||||
color : #954121;
|
||||
/*font-weight: bold*/
|
||||
}
|
||||
|
||||
pre .number,
|
||||
pre .hexcolor
|
||||
{
|
||||
color : #40a070
|
||||
}
|
||||
|
||||
pre .string,
|
||||
pre .tag .value,
|
||||
pre .phpdoc,
|
||||
pre .tex .formula
|
||||
{
|
||||
color : #219161;
|
||||
}
|
||||
|
||||
pre .title,
|
||||
pre .id
|
||||
{
|
||||
color : #19469D;
|
||||
}
|
||||
|
||||
pre .params
|
||||
{
|
||||
color : #00F;
|
||||
}
|
||||
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .subst
|
||||
{
|
||||
font-weight : normal
|
||||
}
|
||||
|
||||
pre .class .title,
|
||||
pre .haskell .label,
|
||||
pre .tex .command
|
||||
{
|
||||
color : #458;
|
||||
font-weight : bold
|
||||
}
|
||||
|
||||
pre .tag,
|
||||
pre .tag .title,
|
||||
pre .rules .property,
|
||||
pre .django .tag .keyword
|
||||
{
|
||||
color : #000080;
|
||||
font-weight : normal
|
||||
}
|
||||
|
||||
pre .attribute,
|
||||
pre .variable,
|
||||
pre .instancevar,
|
||||
pre .lisp .body
|
||||
{
|
||||
color : #008080
|
||||
}
|
||||
|
||||
pre .regexp
|
||||
{
|
||||
color : #B68
|
||||
}
|
||||
|
||||
pre .class
|
||||
{
|
||||
color : #458;
|
||||
font-weight : bold
|
||||
}
|
||||
|
||||
pre .symbol,
|
||||
pre .ruby .symbol .string,
|
||||
pre .ruby .symbol .keyword,
|
||||
pre .ruby .symbol .keymethods,
|
||||
pre .lisp .keyword,
|
||||
pre .tex .special,
|
||||
pre .input_number
|
||||
{
|
||||
color : #990073
|
||||
}
|
||||
|
||||
pre .builtin,
|
||||
pre .constructor,
|
||||
pre .built_in,
|
||||
pre .lisp .title
|
||||
{
|
||||
color : #0086b3
|
||||
}
|
||||
|
||||
pre .preprocessor,
|
||||
pre .pi,
|
||||
pre .doctype,
|
||||
pre .shebang,
|
||||
pre .cdata
|
||||
{
|
||||
color : #999;
|
||||
font-weight : bold
|
||||
}
|
||||
|
||||
pre .deletion
|
||||
{
|
||||
background : #fdd
|
||||
}
|
||||
|
||||
pre .addition
|
||||
{
|
||||
background : #dfd
|
||||
}
|
||||
|
||||
pre .diff .change
|
||||
{
|
||||
background : #0086b3
|
||||
}
|
||||
|
||||
pre .chunk
|
||||
{
|
||||
color : #aaa
|
||||
}
|
||||
|
||||
pre .tex .formula
|
||||
{
|
||||
opacity : 0.5;
|
||||
}
|
|
@ -0,0 +1,500 @@
|
|||
/*--------------------- Typography ----------------------------*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'aller-light';
|
||||
src: url('public/fonts/aller-light.eot');
|
||||
src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/aller-light.woff') format('woff'),
|
||||
url('public/fonts/aller-light.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'aller-bold';
|
||||
src: url('public/fonts/aller-bold.eot');
|
||||
src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/aller-bold.woff') format('woff'),
|
||||
url('public/fonts/aller-bold.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'novecento-bold';
|
||||
src: url('public/fonts/novecento-bold.eot');
|
||||
src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('public/fonts/novecento-bold.woff') format('woff'),
|
||||
url('public/fonts/novecento-bold.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/*--------------------- Layout ----------------------------*/
|
||||
html { height: 100%; }
|
||||
body {
|
||||
font-family: "aller-light";
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
color: #30404f;
|
||||
margin: 0; padding: 0;
|
||||
height:100%;
|
||||
}
|
||||
#container { min-height: 100%; }
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
b, strong {
|
||||
font-weight: normal;
|
||||
font-family: "aller-bold";
|
||||
}
|
||||
|
||||
p, ul, ol {
|
||||
margin: 15px 0 0px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #112233;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
font-family: "novecento-bold";
|
||||
text-transform: uppercase;
|
||||
margin: 30px 0 15px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
background: 1px solid #ddd;
|
||||
height: 1px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
pre, tt, code {
|
||||
font-size: 12px; line-height: 16px;
|
||||
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
.annotation pre {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 7px 10px;
|
||||
background: #fcfcfc;
|
||||
-moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
|
||||
overflow-x: auto;
|
||||
}
|
||||
.annotation pre code {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
blockquote {
|
||||
border-left: 5px solid #ccc;
|
||||
margin: 0;
|
||||
padding: 1px 0 1px 1em;
|
||||
}
|
||||
.sections blockquote p {
|
||||
font-family: Menlo, Consolas, Monaco, monospace;
|
||||
font-size: 12px; line-height: 16px;
|
||||
color: #999;
|
||||
margin: 10px 0 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
ul.sections {
|
||||
list-style: none;
|
||||
padding:0 0 5px 0;;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
/*
|
||||
Force border-box so that % widths fit the parent
|
||||
container without overlap because of margin/padding.
|
||||
|
||||
More Info : http://www.quirksmode.org/css/box.html
|
||||
*/
|
||||
ul.sections > li > div {
|
||||
-moz-box-sizing: border-box; /* firefox */
|
||||
-ms-box-sizing: border-box; /* ie */
|
||||
-webkit-box-sizing: border-box; /* webkit */
|
||||
-khtml-box-sizing: border-box; /* konqueror */
|
||||
box-sizing: border-box; /* css3 */
|
||||
}
|
||||
|
||||
|
||||
/*---------------------- Jump Page -----------------------------*/
|
||||
#jump_to, #jump_page {
|
||||
margin: 0;
|
||||
background: white;
|
||||
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
|
||||
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
|
||||
font: 16px Arial;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#jump_to a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#jump_to a.large {
|
||||
display: none;
|
||||
}
|
||||
#jump_to a.small {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: #676767;
|
||||
}
|
||||
|
||||
#jump_to, #jump_wrapper {
|
||||
position: fixed;
|
||||
right: 0; top: 0;
|
||||
padding: 10px 15px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#jump_wrapper {
|
||||
display: none;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#jump_to:hover #jump_wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#jump_page {
|
||||
padding: 5px 0 3px;
|
||||
margin: 0 0 25px 25px;
|
||||
}
|
||||
|
||||
#jump_page .source {
|
||||
display: block;
|
||||
padding: 15px;
|
||||
text-decoration: none;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
#jump_page .source:hover {
|
||||
background: #f5f5ff;
|
||||
}
|
||||
|
||||
#jump_page .source:first-child {
|
||||
}
|
||||
|
||||
/*---------------------- Low resolutions (> 320px) ---------------------*/
|
||||
@media only screen and (min-width: 320px) {
|
||||
.pilwrap { display: none; }
|
||||
|
||||
ul.sections > li > div {
|
||||
display: block;
|
||||
padding:5px 10px 0 10px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content {
|
||||
background: #f5f5ff;
|
||||
overflow-x:auto;
|
||||
-webkit-box-shadow: inset 0 0 5px #e5e5ee;
|
||||
box-shadow: inset 0 0 5px #e5e5ee;
|
||||
border: 1px solid #dedede;
|
||||
margin:5px 10px 5px 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation pre {
|
||||
margin: 7px 0 7px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation p tt, .annotation code {
|
||||
background: #f8f8ff;
|
||||
border: 1px solid #dedede;
|
||||
font-size: 12px;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 481px) ---------------------*/
|
||||
@media only screen and (min-width: 481px) {
|
||||
#container {
|
||||
position: relative;
|
||||
}
|
||||
body {
|
||||
background-color: #F5F5FF;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
}
|
||||
pre, tt, code {
|
||||
line-height: 18px;
|
||||
}
|
||||
p, ul, ol {
|
||||
margin: 0 0 15px;
|
||||
}
|
||||
|
||||
|
||||
#jump_to {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
#jump_to, #jump_page {
|
||||
font: 10px Arial;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#jump_page .source {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_to a.large {
|
||||
display: inline-block;
|
||||
}
|
||||
#jump_to a.small {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
width: 350px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #e5e5ee;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ul.sections > li {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
ul.sections > li > div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation {
|
||||
max-width: 350px;
|
||||
min-width: 350px;
|
||||
min-height: 5px;
|
||||
padding: 13px;
|
||||
overflow-x: hidden;
|
||||
white-space: normal;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
ul.sections > li > div.annotation pre {
|
||||
margin: 15px 0 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.content {
|
||||
padding: 13px;
|
||||
vertical-align: top;
|
||||
background: #f5f5ff;
|
||||
border: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.pilwrap {
|
||||
position: relative;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pilcrow {
|
||||
font: 12px Arial;
|
||||
text-decoration: none;
|
||||
color: #454545;
|
||||
position: absolute;
|
||||
top: 3px; left: -20px;
|
||||
padding: 1px 2px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
}
|
||||
.for-h1 .pilcrow {
|
||||
top: 47px;
|
||||
}
|
||||
.for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow {
|
||||
top: 35px;
|
||||
}
|
||||
|
||||
ul.sections > li > div.annotation:hover .pilcrow {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- (> 1025px) ---------------------*/
|
||||
@media only screen and (min-width: 1025px) {
|
||||
|
||||
body {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
#background {
|
||||
width: 525px;
|
||||
}
|
||||
ul.sections > li > div.annotation {
|
||||
max-width: 525px;
|
||||
min-width: 525px;
|
||||
padding: 10px 25px 1px 50px;
|
||||
}
|
||||
ul.sections > li > div.content {
|
||||
padding: 9px 15px 16px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------- Syntax Highlighting -----------------------------*/
|
||||
|
||||
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
|
||||
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
pre code {
|
||||
display: block; padding: 0.5em;
|
||||
color: #000;
|
||||
background: #f8f8ff
|
||||
}
|
||||
|
||||
pre .comment,
|
||||
pre .template_comment,
|
||||
pre .diff .header,
|
||||
pre .javadoc {
|
||||
color: #408080;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
pre .keyword,
|
||||
pre .assignment,
|
||||
pre .literal,
|
||||
pre .css .rule .keyword,
|
||||
pre .winutils,
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .subst {
|
||||
color: #954121;
|
||||
/*font-weight: bold*/
|
||||
}
|
||||
|
||||
pre .number,
|
||||
pre .hexcolor {
|
||||
color: #40a070
|
||||
}
|
||||
|
||||
pre .string,
|
||||
pre .tag .value,
|
||||
pre .phpdoc,
|
||||
pre .tex .formula {
|
||||
color: #219161;
|
||||
}
|
||||
|
||||
pre .title,
|
||||
pre .id {
|
||||
color: #19469D;
|
||||
}
|
||||
pre .params {
|
||||
color: #00F;
|
||||
}
|
||||
|
||||
pre .javascript .title,
|
||||
pre .lisp .title,
|
||||
pre .subst {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .class .title,
|
||||
pre .haskell .label,
|
||||
pre .tex .command {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .tag,
|
||||
pre .tag .title,
|
||||
pre .rules .property,
|
||||
pre .django .tag .keyword {
|
||||
color: #000080;
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
pre .attribute,
|
||||
pre .variable,
|
||||
pre .instancevar,
|
||||
pre .lisp .body {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
pre .regexp {
|
||||
color: #B68
|
||||
}
|
||||
|
||||
pre .class {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .symbol,
|
||||
pre .ruby .symbol .string,
|
||||
pre .ruby .symbol .keyword,
|
||||
pre .ruby .symbol .keymethods,
|
||||
pre .lisp .keyword,
|
||||
pre .tex .special,
|
||||
pre .input_number {
|
||||
color: #990073
|
||||
}
|
||||
|
||||
pre .builtin,
|
||||
pre .constructor,
|
||||
pre .built_in,
|
||||
pre .lisp .title {
|
||||
color: #0086b3
|
||||
}
|
||||
|
||||
pre .preprocessor,
|
||||
pre .pi,
|
||||
pre .doctype,
|
||||
pre .shebang,
|
||||
pre .cdata {
|
||||
color: #999;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
pre .deletion {
|
||||
background: #fdd
|
||||
}
|
||||
|
||||
pre .addition {
|
||||
background: #dfd
|
||||
}
|
||||
|
||||
pre .diff .change {
|
||||
background: #0086b3
|
||||
}
|
||||
|
||||
pre .chunk {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
pre .tex .formula {
|
||||
opacity: 0.5;
|
||||
}
|
After Width: | Height: | Size: 56 KiB |
|
@ -0,0 +1,375 @@
|
|||
/*! normalize.css v2.0.1 | MIT License | git.io/normalize */
|
||||
|
||||
/* ==========================================================================
|
||||
HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Corrects `block` display not defined in IE 8/9.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects `inline-block` display not defined in IE 8/9.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevents modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling for `hidden` attribute not present in IE 8/9.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Base
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* 1. Sets default font family to sans-serif.
|
||||
* 2. Prevents iOS text size adjust after orientation change, without disabling
|
||||
* user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Links
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses `outline` inconsistency between Chrome and other browsers.
|
||||
*/
|
||||
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Improves readability when focused and also mouse hovered in all browsers.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Typography
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses `h1` font sizes within `section` and `article` in Firefox 4+,
|
||||
* Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling not present in IE 8/9, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling not present in Safari 5 and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Corrects font family set oddly in Safari 5 and Chrome.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Improves readability of pre-formatted text in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets consistent quote types.
|
||||
*/
|
||||
|
||||
q {
|
||||
quotes: "\201C" "\201D" "\2018" "\2019";
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevents `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Removes border when inside `a` element in IE 8/9.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects overflow displayed oddly in IE 9.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Figures
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Addresses margin not present in IE 8/9 and Safari 5.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Forms
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Corrects color not being inherited in IE 8/9.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Corrects font family not being inherited in all browsers.
|
||||
* 2. Corrects font size not being inherited in all browsers.
|
||||
* 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Addresses Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
button,
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Corrects inability to style clickable `input` types in iOS.
|
||||
* 3. Improves usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Addresses box sizing set to `content-box` in IE 8/9.
|
||||
* 2. Removes excess padding in IE 8/9.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
|
||||
* 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
|
||||
* (include `-moz` to future-proof).
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes inner padding and search cancel button in Safari 5 and Chrome
|
||||
* on OS X.
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes inner padding and border in Firefox 4+.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Removes default vertical scrollbar in IE 8/9.
|
||||
* 2. Improves readability and alignment in all browsers.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto; /* 1 */
|
||||
vertical-align: top; /* 2 */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Tables
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 229 B |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 3.1 KiB |
|
@ -0,0 +1,490 @@
|
|||
// ┌────────────────────────────────────────────────────────────────────┐ \\
|
||||
// │ F R E E B O A R D │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Copyright © 2013 Jim Heising (https://github.com/jheising) │ \\
|
||||
// │ Copyright © 2013 Bug Labs, Inc. (http://buglabs.net) │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Licensed under the MIT license. │ \\
|
||||
// └────────────────────────────────────────────────────────────────────┘ \\
|
||||
|
||||
(function()
|
||||
{
|
||||
var jsonDatasource = function(settings, updateCallback)
|
||||
{
|
||||
var self = this;
|
||||
var updateTimer = null;
|
||||
var currentSettings = settings;
|
||||
|
||||
function updateRefresh(refreshTime)
|
||||
{
|
||||
if(updateTimer)
|
||||
{
|
||||
clearInterval(updateTimer);
|
||||
}
|
||||
|
||||
updateTimer = setInterval(function()
|
||||
{
|
||||
self.updateNow();
|
||||
}, refreshTime);
|
||||
}
|
||||
|
||||
updateRefresh(currentSettings.refresh * 1000);
|
||||
|
||||
this.updateNow = function()
|
||||
{
|
||||
$.ajax({
|
||||
url : currentSettings.url,
|
||||
dataType : (currentSettings.is_jsonp) ? "JSONP" : "JSON",
|
||||
beforeSend: function(xhr)
|
||||
{
|
||||
try
|
||||
{
|
||||
_.each(currentSettings.headers, function(header)
|
||||
{
|
||||
var name = header.name;
|
||||
var value = header.value;
|
||||
|
||||
if(!_.isUndefined(name) && !_.isUndefined(value))
|
||||
{
|
||||
xhr.setRequestHeader(name, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
},
|
||||
success : function(data)
|
||||
{
|
||||
updateCallback(data);
|
||||
},
|
||||
error : function(xhr, status, error)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.onDispose = function()
|
||||
{
|
||||
clearInterval(updateTimer);
|
||||
updateTimer = null;
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function(newSettings)
|
||||
{
|
||||
currentSettings = newSettings;
|
||||
updateRefresh(currentSettings.refresh * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
freeboard.loadDatasourcePlugin({
|
||||
type_name : "JSON",
|
||||
settings : [
|
||||
{
|
||||
name : "url",
|
||||
display_name: "URL",
|
||||
type : "text"
|
||||
},
|
||||
{
|
||||
name : "refresh",
|
||||
display_name : "Refresh Every",
|
||||
type : "number",
|
||||
suffix : "seconds",
|
||||
default_value: 5
|
||||
},
|
||||
{
|
||||
name : "is_jsonp",
|
||||
display_name: "Is JSONP",
|
||||
type : "boolean"
|
||||
},
|
||||
{
|
||||
name : "headers",
|
||||
display_name: "Headers",
|
||||
type : "array",
|
||||
settings : [
|
||||
{
|
||||
name : "name",
|
||||
display_name: "Name",
|
||||
type : "text"
|
||||
},
|
||||
{
|
||||
name : "value",
|
||||
display_name: "Value",
|
||||
type : "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
newInstance: function(settings, newInstanceCallback, updateCallback)
|
||||
{
|
||||
newInstanceCallback( new jsonDatasource(settings, updateCallback));
|
||||
}
|
||||
});
|
||||
|
||||
var openWeatherMapDatasource = function(settings, updateCallback)
|
||||
{
|
||||
var self = this;
|
||||
var updateTimer = null;
|
||||
var currentSettings = settings;
|
||||
|
||||
function updateRefresh(refreshTime)
|
||||
{
|
||||
if(updateTimer)
|
||||
{
|
||||
clearInterval(updateTimer);
|
||||
}
|
||||
|
||||
updateTimer = setInterval(function()
|
||||
{
|
||||
self.updateNow();
|
||||
}, refreshTime);
|
||||
}
|
||||
|
||||
function toTitleCase(str)
|
||||
{
|
||||
return str.replace(/\w\S*/g, function(txt)
|
||||
{
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
updateRefresh(currentSettings.refresh * 1000);
|
||||
|
||||
this.updateNow = function()
|
||||
{
|
||||
$.ajax({
|
||||
url : "http://api.openweathermap.org/data/2.5/weather?q=" + encodeURIComponent(currentSettings.location) + "&units=" + currentSettings.units,
|
||||
dataType : "JSONP",
|
||||
success : function(data)
|
||||
{
|
||||
// Rejigger our data into something easier to understand
|
||||
var newData = {
|
||||
place_name : data.name,
|
||||
sunrise : (new Date(data.sys.sunrise * 1000)).toLocaleTimeString(),
|
||||
sunset : (new Date(data.sys.sunset * 1000)).toLocaleTimeString(),
|
||||
conditions : toTitleCase(data.weather[0].description),
|
||||
current_temp : data.main.temp,
|
||||
high_temp : data.main.temp_max,
|
||||
low_temp : data.main.temp_min,
|
||||
pressure : data.main.pressure,
|
||||
humidity : data.main.humidity,
|
||||
wind_speed : data.wind.speed,
|
||||
wind_direction : data.wind.deg
|
||||
};
|
||||
|
||||
updateCallback(newData);
|
||||
},
|
||||
error : function(xhr, status, error)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.onDispose = function()
|
||||
{
|
||||
clearInterval(updateTimer);
|
||||
updateTimer = null;
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function(newSettings)
|
||||
{
|
||||
currentSettings = newSettings;
|
||||
self.updateNow();
|
||||
updateRefresh(currentSettings.refresh * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
freeboard.loadDatasourcePlugin({
|
||||
type_name : "openweathermap",
|
||||
display_name: "Open Weather Map API",
|
||||
settings : [
|
||||
{
|
||||
name : "location",
|
||||
display_name: "Location",
|
||||
type : "text",
|
||||
description : "Example: London, UK"
|
||||
},
|
||||
{
|
||||
name : "units",
|
||||
display_name: "Units",
|
||||
type : "option",
|
||||
default : "imperial",
|
||||
options: [
|
||||
{
|
||||
name : "Imperial",
|
||||
value: "imperial"
|
||||
},
|
||||
{
|
||||
name : "Metric",
|
||||
value: "metric"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name : "refresh",
|
||||
display_name : "Refresh Every",
|
||||
type : "number",
|
||||
suffix : "seconds",
|
||||
default_value: 5
|
||||
}
|
||||
],
|
||||
newInstance: function(settings, newInstanceCallback, updateCallback)
|
||||
{
|
||||
newInstanceCallback( new openWeatherMapDatasource(settings, updateCallback));
|
||||
}
|
||||
});
|
||||
|
||||
var dweetioDatasource = function(settings, updateCallback)
|
||||
{
|
||||
var self = this;
|
||||
var currentSettings = settings;
|
||||
|
||||
function onNewDweet(dweet)
|
||||
{
|
||||
updateCallback(dweet);
|
||||
}
|
||||
|
||||
this.updateNow = function()
|
||||
{
|
||||
dweetio.get_latest_dweet_for(currentSettings.thing_id, function(err, dweet){
|
||||
if(err)
|
||||
{
|
||||
//onNewDweet({});
|
||||
}
|
||||
else
|
||||
{
|
||||
onNewDweet(dweet[0].content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.onDispose = function()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function(newSettings)
|
||||
{
|
||||
dweetio.stop_listening();
|
||||
|
||||
currentSettings = newSettings;
|
||||
|
||||
dweetio.listen_for(currentSettings.thing_id, function(dweet)
|
||||
{
|
||||
onNewDweet(dweet.content);
|
||||
});
|
||||
}
|
||||
|
||||
self.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadDatasourcePlugin({
|
||||
"type_name" : "dweet_io",
|
||||
"display_name": "Dweet.io",
|
||||
"external_scripts" : [
|
||||
"http://dweet.io/client/dweet.io.min.js"
|
||||
],
|
||||
"settings" : [
|
||||
{
|
||||
name : "thing_id",
|
||||
display_name: "Thing Name",
|
||||
"description": "Example: salty-dog-1",
|
||||
type : "text"
|
||||
}
|
||||
],
|
||||
newInstance : function(settings, newInstanceCallback, updateCallback)
|
||||
{
|
||||
newInstanceCallback(new dweetioDatasource(settings, updateCallback));
|
||||
}
|
||||
});
|
||||
|
||||
var playbackDatasource = function(settings, updateCallback)
|
||||
{
|
||||
var self = this;
|
||||
var currentSettings = settings;
|
||||
var currentDataset = [];
|
||||
var currentIndex = 0;
|
||||
var currentTimeout;
|
||||
|
||||
function moveNext()
|
||||
{
|
||||
if(currentDataset.length > 0)
|
||||
{
|
||||
if(currentIndex < currentDataset.length)
|
||||
{
|
||||
updateCallback(currentDataset[currentIndex]);
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
if(currentIndex >= currentDataset.length && currentSettings.loop)
|
||||
{
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
if(currentIndex < currentDataset.length)
|
||||
{
|
||||
currentTimeout = setTimeout(moveNext, currentSettings.refresh * 1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
updateCallback({});
|
||||
}
|
||||
}
|
||||
|
||||
function stopTimeout()
|
||||
{
|
||||
currentDataset = [];
|
||||
currentIndex = 0;
|
||||
|
||||
if(currentTimeout)
|
||||
{
|
||||
clearTimeout(currentTimeout);
|
||||
currentTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateNow = function()
|
||||
{
|
||||
stopTimeout();
|
||||
|
||||
$.ajax({
|
||||
url : currentSettings.datafile,
|
||||
dataType : (currentSettings.is_jsonp) ? "JSONP" : "JSON",
|
||||
success : function(data)
|
||||
{
|
||||
if(_.isArray(data))
|
||||
{
|
||||
currentDataset = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDataset = [];
|
||||
}
|
||||
|
||||
currentIndex = 0;
|
||||
|
||||
moveNext();
|
||||
},
|
||||
error : function(xhr, status, error)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.onDispose = function()
|
||||
{
|
||||
stopTimeout();
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function(newSettings)
|
||||
{
|
||||
currentSettings = newSettings;
|
||||
self.updateNow();
|
||||
}
|
||||
};
|
||||
|
||||
freeboard.loadDatasourcePlugin({
|
||||
"type_name": "playback",
|
||||
"display_name": "Playback",
|
||||
"settings": [
|
||||
{
|
||||
"name": "datafile",
|
||||
"display_name": "Data File URL",
|
||||
"type": "text",
|
||||
"description": "A link to a JSON array of data."
|
||||
},
|
||||
{
|
||||
name : "is_jsonp",
|
||||
display_name: "Is JSONP",
|
||||
type : "boolean"
|
||||
},
|
||||
{
|
||||
"name": "loop",
|
||||
"display_name": "Loop",
|
||||
"type": "boolean",
|
||||
"description": "Rewind and loop when finished"
|
||||
},
|
||||
{
|
||||
"name": "refresh",
|
||||
"display_name": "Refresh Every",
|
||||
"type": "number",
|
||||
"suffix": "seconds",
|
||||
"default_value": 5
|
||||
}
|
||||
],
|
||||
newInstance: function(settings, newInstanceCallback, updateCallback)
|
||||
{
|
||||
newInstanceCallback( new playbackDatasource(settings, updateCallback));
|
||||
}
|
||||
});
|
||||
|
||||
var clockDatasource = function(settings, updateCallback)
|
||||
{
|
||||
var self = this;
|
||||
var currentSettings = settings;
|
||||
var timer;
|
||||
|
||||
function stopTimer()
|
||||
{
|
||||
if(timer)
|
||||
{
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimer()
|
||||
{
|
||||
stopTimer();
|
||||
timer = setInterval(self.updateNow, currentSettings.refresh * 1000);
|
||||
}
|
||||
|
||||
this.updateNow = function()
|
||||
{
|
||||
var date = new Date();
|
||||
|
||||
var data = {
|
||||
numeric_value : date.getTime(),
|
||||
full_string_value : date.toLocaleString(),
|
||||
date_string_value : date.toLocaleDateString(),
|
||||
time_string_value : date.toLocaleTimeString(),
|
||||
date_object : date
|
||||
};
|
||||
|
||||
updateCallback(data);
|
||||
}
|
||||
|
||||
this.onDispose = function()
|
||||
{
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function(newSettings)
|
||||
{
|
||||
currentSettings = newSettings;
|
||||
updateTimer();
|
||||
}
|
||||
|
||||
updateTimer();
|
||||
};
|
||||
|
||||
freeboard.loadDatasourcePlugin({
|
||||
"type_name": "clock",
|
||||
"display_name": "Clock",
|
||||
"settings": [
|
||||
{
|
||||
"name": "refresh",
|
||||
"display_name": "Refresh Every",
|
||||
"type": "number",
|
||||
"suffix": "seconds",
|
||||
"default_value": 1
|
||||
}
|
||||
],
|
||||
newInstance: function(settings, newInstanceCallback, updateCallback)
|
||||
{
|
||||
newInstanceCallback( new clockDatasource(settings, updateCallback));
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
|
@ -0,0 +1,861 @@
|
|||
// ┌────────────────────────────────────────────────────────────────────┐ \\
|
||||
// │ F R E E B O A R D │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Copyright © 2013 Jim Heising (https://github.com/jheising) │ \\
|
||||
// │ Copyright © 2013 Bug Labs, Inc. (http://buglabs.net) │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Licensed under the MIT license. │ \\
|
||||
// └────────────────────────────────────────────────────────────────────┘ \\
|
||||
|
||||
(function () {
|
||||
var SPARKLINE_HISTORY_LENGTH = 100;
|
||||
var valueStyle = freeboard.getStyleString("values");
|
||||
|
||||
valueStyle +=
|
||||
"overflow: hidden;" +
|
||||
"text-overflow: ellipsis;" +
|
||||
"display: inline;";
|
||||
|
||||
// Add some styles to our sheet
|
||||
freeboard.addStyle('.text-widget-unit', 'padding-left: 5px;display:inline;');
|
||||
freeboard.addStyle('.text-widget-regular-value', valueStyle + "font-size:30px;");
|
||||
freeboard.addStyle('.text-widget-big-value', valueStyle + "font-size:75px;");
|
||||
|
||||
freeboard.addStyle('.gauge-widget-wrapper', "width: 100%;text-align: center;");
|
||||
freeboard.addStyle('.gauge-widget', "width:200px;height:160px;display:inline-block;");
|
||||
|
||||
freeboard.addStyle('.sparkline', "width:100%;height: 75px;");
|
||||
freeboard.addStyle('.sparkline-inline', "width:50%;float:right;height:30px;");
|
||||
|
||||
freeboard.addStyle('.indicator-light', "border-radius:50%;width:22px;height:22px;border:2px solid #3d3d3d;margin-top:5px;float:left;background-color:#222;margin-right:10px;");
|
||||
freeboard.addStyle('.indicator-light.on', "background-color:#FFC773;box-shadow: 0px 0px 15px #FF9900;border-color:#FDF1DF;");
|
||||
freeboard.addStyle('.indicator-text', "margin-top:10px;");
|
||||
|
||||
freeboard.addStyle('div.pointer-value', "position:absolute;height:95px;margin: auto;top: 0px;bottom: 0px;width: 100%;text-align:center;");
|
||||
|
||||
function easeTransitionText(currentValue, newValue, textElement, duration) {
|
||||
if (currentValue == newValue)
|
||||
return;
|
||||
|
||||
if ($.isNumeric(newValue) && $.isNumeric(currentValue)) {
|
||||
var numParts = newValue.toString().split('.');
|
||||
var endingPrecision = 0;
|
||||
|
||||
if (numParts.length > 1) {
|
||||
endingPrecision = numParts[1].length;
|
||||
}
|
||||
|
||||
numParts = currentValue.toString().split('.');
|
||||
var startingPrecision = 0;
|
||||
|
||||
if (numParts.length > 1) {
|
||||
startingPrecision = numParts[1].length;
|
||||
}
|
||||
|
||||
jQuery({transitionValue: Number(currentValue), precisionValue: startingPrecision}).animate({transitionValue: Number(newValue), precisionValue: endingPrecision}, {
|
||||
duration: duration,
|
||||
step: function () {
|
||||
$(textElement).text(this.transitionValue.toFixed(this.precisionValue));
|
||||
},
|
||||
done: function () {
|
||||
$(textElement).text(newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$(textElement).text(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
function addValueToSparkline(element, value) {
|
||||
var values = $(element).data().values;
|
||||
|
||||
if (!values) {
|
||||
values = [];
|
||||
}
|
||||
|
||||
if (values.length >= SPARKLINE_HISTORY_LENGTH) {
|
||||
values.shift();
|
||||
}
|
||||
|
||||
//if(_.isNumber(value))
|
||||
//{
|
||||
values.push(Number(value));
|
||||
|
||||
$(element).data().values = values;
|
||||
|
||||
$(element).sparkline(values, {
|
||||
type: "line",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
fillColor: false,
|
||||
lineColor: "#FF9900",
|
||||
lineWidth: 2,
|
||||
spotRadius: 3,
|
||||
spotColor: false,
|
||||
minSpotColor: "#78AB49",
|
||||
maxSpotColor: "#78AB49",
|
||||
highlightSpotColor: "#9D3926",
|
||||
highlightLineColor: "#9D3926"
|
||||
});
|
||||
//}
|
||||
}
|
||||
|
||||
var textWidget = function (settings) {
|
||||
var self = this;
|
||||
|
||||
var currentSettings = settings;
|
||||
var titleElement = $('<h2 class="section-title"></h2>');
|
||||
var valueElement = $('<div></div>');
|
||||
var unitsElement = $('<div class="text-widget-unit"></div>');
|
||||
var sparklineElement = $('<span class="sparkline-inline"></span>');
|
||||
var currentValue;
|
||||
|
||||
this.render = function (element) {
|
||||
$(element).append(titleElement).append(valueElement).append(unitsElement).append(sparklineElement);
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
currentSettings = newSettings;
|
||||
titleElement.html((_.isUndefined(newSettings.title) ? "" : newSettings.title));
|
||||
|
||||
valueElement
|
||||
.toggleClass("text-widget-regular-value", (newSettings.size == "regular"))
|
||||
.toggleClass("text-widget-big-value", (newSettings.size == "big"));
|
||||
|
||||
unitsElement.html((_.isUndefined(newSettings.units) ? "" : newSettings.units));
|
||||
|
||||
if (newSettings.sparkline) {
|
||||
sparklineElement.show();
|
||||
}
|
||||
else {
|
||||
delete sparklineElement.data().values;
|
||||
sparklineElement.empty();
|
||||
sparklineElement.hide();
|
||||
}
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
if (settingName == "value") {
|
||||
if (currentSettings.animate) {
|
||||
easeTransitionText(currentValue, newValue, valueElement, 500);
|
||||
}
|
||||
else {
|
||||
valueElement.text(newValue);
|
||||
}
|
||||
|
||||
if (currentSettings.sparkline) {
|
||||
addValueToSparkline(sparklineElement, newValue);
|
||||
}
|
||||
|
||||
currentValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
if (currentSettings.size == "big") {
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "text_widget",
|
||||
display_name: "Text",
|
||||
settings: [
|
||||
{
|
||||
name: "title",
|
||||
display_name: "Title",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "size",
|
||||
display_name: "Size",
|
||||
type: "option",
|
||||
options: [
|
||||
{
|
||||
name: "Regular",
|
||||
value: "regular"
|
||||
},
|
||||
{
|
||||
name: "Big",
|
||||
value: "big"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
display_name: "Value",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
name: "sparkline",
|
||||
display_name: "Include Sparkline",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "animate",
|
||||
display_name: "Animate Value Changes",
|
||||
type: "boolean",
|
||||
default_value: true
|
||||
},
|
||||
{
|
||||
name: "units",
|
||||
display_name: "Units",
|
||||
type: "text"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new textWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
var gaugeID = 0;
|
||||
|
||||
var gaugeWidget = function (settings) {
|
||||
var self = this;
|
||||
|
||||
var thisGaugeID = "gauge-" + gaugeID++;
|
||||
var titleElement = $('<h2 class="section-title"></h2>');
|
||||
var gaugeElement = $('<div class="gauge-widget" id="' + thisGaugeID + '"></div>');
|
||||
|
||||
var gaugeObject;
|
||||
var rendered = false;
|
||||
|
||||
var currentSettings = settings;
|
||||
|
||||
function createGauge() {
|
||||
if (!rendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
gaugeElement.empty();
|
||||
|
||||
gaugeObject = new JustGage({
|
||||
id: thisGaugeID,
|
||||
value: (_.isUndefined(currentSettings.min_value) ? 0 : currentSettings.min_value),
|
||||
min: (_.isUndefined(currentSettings.min_value) ? 0 : currentSettings.min_value),
|
||||
max: (_.isUndefined(currentSettings.max_value) ? 0 : currentSettings.max_value),
|
||||
label: currentSettings.units,
|
||||
showInnerShadow: false,
|
||||
valueFontColor: "#d3d4d4"
|
||||
});
|
||||
}
|
||||
|
||||
this.render = function (element) {
|
||||
rendered = true;
|
||||
$(element).append(titleElement).append($('<div class="gauge-widget-wrapper"></div>').append(gaugeElement));
|
||||
createGauge();
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
if (newSettings.min_value != currentSettings.min_value || newSettings.max_value != currentSettings.max_value || newSettings.units != currentSettings.units) {
|
||||
currentSettings = newSettings;
|
||||
createGauge();
|
||||
}
|
||||
else {
|
||||
currentSettings = newSettings;
|
||||
}
|
||||
|
||||
titleElement.html(newSettings.title);
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
if (!_.isUndefined(gaugeObject)) {
|
||||
gaugeObject.refresh(Number(newValue));
|
||||
}
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
return 3;
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "gauge",
|
||||
display_name: "Gauge",
|
||||
settings: [
|
||||
{
|
||||
name: "title",
|
||||
display_name: "Title",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
display_name: "Value",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
name: "units",
|
||||
display_name: "Units",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "min_value",
|
||||
display_name: "Minimum",
|
||||
type: "text",
|
||||
default_value: 0
|
||||
},
|
||||
{
|
||||
name: "max_value",
|
||||
display_name: "Maximum",
|
||||
type: "text",
|
||||
default_value: 100
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new gaugeWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
var sparklineWidget = function (settings) {
|
||||
var self = this;
|
||||
|
||||
var titleElement = $('<h2 class="section-title"></h2>');
|
||||
var sparklineElement = $('<div class="sparkline"></div>');
|
||||
|
||||
this.render = function (element) {
|
||||
$(element).append(titleElement).append(sparklineElement);
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
titleElement.html((_.isUndefined(newSettings.title) ? "" : newSettings.title));
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
addValueToSparkline(sparklineElement, newValue);
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
return 2;
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "sparkline",
|
||||
display_name: "Sparkline",
|
||||
settings: [
|
||||
{
|
||||
name: "title",
|
||||
display_name: "Title",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
display_name: "Value",
|
||||
type: "calculated"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new sparklineWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
var pointerWidget = function (settings) {
|
||||
var self = this;
|
||||
var paper;
|
||||
var strokeWidth = 3;
|
||||
var triangle;
|
||||
var width, height;
|
||||
var currentValue = 0;
|
||||
var valueDiv = $('<div class="text-widget-big-value"></div>');
|
||||
var unitsDiv = $('<div></div>');
|
||||
|
||||
function polygonPath(points) {
|
||||
if (!points || points.length < 2)
|
||||
return [];
|
||||
var path = []; //will use path object type
|
||||
path.push(['m', points[0], points[1]]);
|
||||
for (var i = 2; i < points.length; i += 2) {
|
||||
path.push(['l', points[i], points[i + 1]]);
|
||||
}
|
||||
path.push(['z']);
|
||||
return path;
|
||||
}
|
||||
|
||||
this.render = function (element) {
|
||||
width = $(element).width();
|
||||
height = $(element).height();
|
||||
|
||||
var radius = Math.min(width, height) / 2 - strokeWidth * 2;
|
||||
|
||||
paper = Raphael($(element).get()[0], width, height);
|
||||
var circle = paper.circle(width / 2, height / 2, radius);
|
||||
circle.attr("stroke", "#FF9900");
|
||||
circle.attr("stroke-width", strokeWidth);
|
||||
|
||||
triangle = paper.path(polygonPath([width / 2, (height / 2) - radius + strokeWidth, 15, 20, -30, 0]));
|
||||
triangle.attr("stroke-width", 0);
|
||||
triangle.attr("fill", "#fff");
|
||||
|
||||
$(element).append($('<div class="pointer-value"></div>').append(valueDiv).append(unitsDiv));
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
unitsDiv.html(newSettings.units);
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
if (settingName == "direction") {
|
||||
if (!_.isUndefined(triangle)) {
|
||||
var direction = "r";
|
||||
|
||||
var oppositeCurrent = currentValue + 180;
|
||||
|
||||
if (oppositeCurrent < newValue) {
|
||||
//direction = "l";
|
||||
}
|
||||
|
||||
triangle.animate({transform: "r" + newValue + "," + (width / 2) + "," + (height / 2)}, 250, "bounce");
|
||||
}
|
||||
|
||||
currentValue = newValue;
|
||||
}
|
||||
else if (settingName == "value_text") {
|
||||
valueDiv.html(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
return 4;
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "pointer",
|
||||
display_name: "Pointer",
|
||||
settings: [
|
||||
{
|
||||
name: "direction",
|
||||
display_name: "Direction",
|
||||
type: "calculated",
|
||||
description: "In degrees"
|
||||
},
|
||||
{
|
||||
name: "value_text",
|
||||
display_name: "Value Text",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
name: "units",
|
||||
display_name: "Units",
|
||||
type: "text"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new pointerWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
var pictureWidget = function(settings)
|
||||
{
|
||||
var self = this;
|
||||
var widgetElement;
|
||||
var timer;
|
||||
var imageURL;
|
||||
|
||||
function stopTimer()
|
||||
{
|
||||
if(timer)
|
||||
{
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function updateImage()
|
||||
{
|
||||
if(widgetElement && imageURL)
|
||||
{
|
||||
var cacheBreakerURL = imageURL + (imageURL.indexOf("?") == -1 ? "?" : "&") + Date.now();
|
||||
|
||||
$(widgetElement).css({
|
||||
"background-image" : "url(" + cacheBreakerURL + ")"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.render = function(element)
|
||||
{
|
||||
$(element).css({
|
||||
width : "100%",
|
||||
height: "100%",
|
||||
"background-size" : "cover",
|
||||
"background-position" : "center"
|
||||
});
|
||||
|
||||
widgetElement = element;
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function(newSettings)
|
||||
{
|
||||
stopTimer();
|
||||
|
||||
if(newSettings.refresh && newSettings.refresh > 0)
|
||||
{
|
||||
timer = setInterval(updateImage, Number(newSettings.refresh) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function(settingName, newValue)
|
||||
{
|
||||
if(settingName == "src")
|
||||
{
|
||||
imageURL = newValue;
|
||||
}
|
||||
|
||||
updateImage();
|
||||
}
|
||||
|
||||
this.onDispose = function()
|
||||
{
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
this.getHeight = function()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "picture",
|
||||
display_name: "Picture",
|
||||
fill_size: true,
|
||||
settings: [
|
||||
{
|
||||
name: "src",
|
||||
display_name: "Image URL",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"display_name": "Refresh every",
|
||||
"name": "refresh",
|
||||
"suffix": "seconds",
|
||||
"description":"Leave blank if the image doesn't need to be refreshed"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new pictureWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
var indicatorWidget = function (settings) {
|
||||
var self = this;
|
||||
var titleElement = $('<h2 class="section-title"></h2>');
|
||||
var stateElement = $('<div class="indicator-text"></div>');
|
||||
var indicatorElement = $('<div class="indicator-light"></div>');
|
||||
var currentSettings = settings;
|
||||
var isOn = false;
|
||||
|
||||
function updateState() {
|
||||
indicatorElement.toggleClass("on", isOn);
|
||||
|
||||
if (isOn) {
|
||||
stateElement.text((_.isUndefined(currentSettings.on_text) ? "" : currentSettings.on_text));
|
||||
}
|
||||
else {
|
||||
stateElement.text((_.isUndefined(currentSettings.off_text) ? "" : currentSettings.off_text));
|
||||
}
|
||||
}
|
||||
|
||||
this.render = function (element) {
|
||||
$(element).append(titleElement).append(indicatorElement).append(stateElement);
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
currentSettings = newSettings;
|
||||
titleElement.html((_.isUndefined(newSettings.title) ? "" : newSettings.title));
|
||||
updateState();
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
if (settingName == "value") {
|
||||
isOn = Boolean(newValue);
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
return 1;
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "indicator",
|
||||
display_name: "Indicator Light",
|
||||
settings: [
|
||||
{
|
||||
name: "title",
|
||||
display_name: "Title",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
display_name: "Value",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
name: "on_text",
|
||||
display_name: "On Text",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
name: "off_text",
|
||||
display_name: "Off Text",
|
||||
type: "calculated"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new indicatorWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
freeboard.addStyle('.gm-style-cc a', "text-shadow:none;");
|
||||
|
||||
var googleMapWidget = function (settings) {
|
||||
var self = this;
|
||||
var currentSettings = settings;
|
||||
var map;
|
||||
var marker;
|
||||
var currentPosition = {};
|
||||
|
||||
function updatePosition() {
|
||||
if (map && marker && currentPosition.lat && currentPosition.lon) {
|
||||
var newLatLon = new google.maps.LatLng(currentPosition.lat, currentPosition.lon);
|
||||
marker.setPosition(newLatLon);
|
||||
map.panTo(newLatLon);
|
||||
}
|
||||
}
|
||||
|
||||
this.render = function (element) {
|
||||
function initializeMap() {
|
||||
var mapOptions = {
|
||||
zoom: 13,
|
||||
center: new google.maps.LatLng(37.235, -115.811111),
|
||||
disableDefaultUI: true,
|
||||
draggable: false,
|
||||
styles: [
|
||||
{"featureType": "water", "elementType": "geometry", "stylers": [
|
||||
{"color": "#2a2a2a"}
|
||||
]},
|
||||
{"featureType": "landscape", "elementType": "geometry", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 20}
|
||||
]},
|
||||
{"featureType": "road.highway", "elementType": "geometry.fill", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 17}
|
||||
]},
|
||||
{"featureType": "road.highway", "elementType": "geometry.stroke", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 29},
|
||||
{"weight": 0.2}
|
||||
]},
|
||||
{"featureType": "road.arterial", "elementType": "geometry", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 18}
|
||||
]},
|
||||
{"featureType": "road.local", "elementType": "geometry", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 16}
|
||||
]},
|
||||
{"featureType": "poi", "elementType": "geometry", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 21}
|
||||
]},
|
||||
{"elementType": "labels.text.stroke", "stylers": [
|
||||
{"visibility": "on"},
|
||||
{"color": "#000000"},
|
||||
{"lightness": 16}
|
||||
]},
|
||||
{"elementType": "labels.text.fill", "stylers": [
|
||||
{"saturation": 36},
|
||||
{"color": "#000000"},
|
||||
{"lightness": 40}
|
||||
]},
|
||||
{"elementType": "labels.icon", "stylers": [
|
||||
{"visibility": "off"}
|
||||
]},
|
||||
{"featureType": "transit", "elementType": "geometry", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 19}
|
||||
]},
|
||||
{"featureType": "administrative", "elementType": "geometry.fill", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 20}
|
||||
]},
|
||||
{"featureType": "administrative", "elementType": "geometry.stroke", "stylers": [
|
||||
{"color": "#000000"},
|
||||
{"lightness": 17},
|
||||
{"weight": 1.2}
|
||||
]}
|
||||
]
|
||||
};
|
||||
|
||||
map = new google.maps.Map(element, mapOptions);
|
||||
|
||||
google.maps.event.addDomListener(element, 'mouseenter', function (e) {
|
||||
e.cancelBubble = true;
|
||||
if (!map.hover) {
|
||||
map.hover = true;
|
||||
map.setOptions({zoomControl: true});
|
||||
}
|
||||
});
|
||||
|
||||
google.maps.event.addDomListener(element, 'mouseleave', function (e) {
|
||||
if (map.hover) {
|
||||
map.setOptions({zoomControl: false});
|
||||
map.hover = false;
|
||||
}
|
||||
});
|
||||
|
||||
marker = new google.maps.Marker({map: map});
|
||||
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
if (window.google && window.google.maps) {
|
||||
initializeMap();
|
||||
}
|
||||
else {
|
||||
window.gmap_initialize = initializeMap;
|
||||
head.js("https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=gmap_initialize");
|
||||
}
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
currentSettings = newSettings;
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
if (settingName == "lat") {
|
||||
currentPosition.lat = newValue;
|
||||
}
|
||||
else if (settingName == "lon") {
|
||||
currentPosition.lon = newValue;
|
||||
}
|
||||
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
return 4;
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
type_name: "google_map",
|
||||
display_name: "Google Map",
|
||||
fill_size: true,
|
||||
settings: [
|
||||
{
|
||||
name: "lat",
|
||||
display_name: "Latitude",
|
||||
type: "calculated"
|
||||
},
|
||||
{
|
||||
name: "lon",
|
||||
display_name: "Longitude",
|
||||
type: "calculated"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new googleMapWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
freeboard.addStyle('.html-widget', "white-space:normal;width:100%;height:100%");
|
||||
|
||||
var htmlWidget = function (settings) {
|
||||
var self = this;
|
||||
var htmlElement = $('<div class="html-widget"></div>');
|
||||
var currentSettings = settings;
|
||||
|
||||
this.render = function (element) {
|
||||
$(element).append(htmlElement);
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
currentSettings = newSettings;
|
||||
}
|
||||
|
||||
this.onCalculatedValueChanged = function (settingName, newValue) {
|
||||
if (settingName == "html") {
|
||||
htmlElement.html(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
}
|
||||
|
||||
this.getHeight = function () {
|
||||
return Number(currentSettings.height);
|
||||
}
|
||||
|
||||
this.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadWidgetPlugin({
|
||||
"type_name": "html",
|
||||
"display_name": "HTML",
|
||||
"fill_size": true,
|
||||
"settings": [
|
||||
{
|
||||
"name": "html",
|
||||
"display_name": "HTML",
|
||||
"type": "calculated",
|
||||
"description": "Can be literal HTML, or javascript that outputs HTML."
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"display_name": "Height Blocks",
|
||||
"type": "number",
|
||||
"default_value": 4,
|
||||
"description": "A height block is around 60 pixels"
|
||||
}
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback) {
|
||||
newInstanceCallback(new htmlWidget(settings));
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
|
@ -0,0 +1,108 @@
|
|||
var pubnubDatasource = function (settings, updateCallback) {
|
||||
var self = this;
|
||||
var currentSettings = {};
|
||||
var pubnub;
|
||||
|
||||
this.onPubNubHistory = function (envelope) {
|
||||
var messages = envelope[0];
|
||||
for (var idx in messages) {
|
||||
self.onPubNubMessage(messages[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
this.onPubNubMessage = function (message) {
|
||||
|
||||
if (_.isString(message)) {
|
||||
// Parse as JSON if it's a string
|
||||
try {
|
||||
var messageObject = JSON.parse(message);
|
||||
|
||||
if (messageObject) {
|
||||
updateCallback(messageObject);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
updateCallback(message);
|
||||
}
|
||||
}
|
||||
|
||||
this.changeChannel = function (newChannel) {
|
||||
|
||||
try {
|
||||
pubnub.unsubscribe({
|
||||
channel: currentSettings["channel"]
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
}
|
||||
|
||||
if (newChannel) {
|
||||
pubnub.subscribe({
|
||||
channel: newChannel,
|
||||
message: self.onPubNubMessage
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.closeConnection = function () {
|
||||
self.changeChannel(null);
|
||||
// TODO: Find out if there is a close function for pubnub. There isn't one documented.
|
||||
pubnub = null;
|
||||
}
|
||||
|
||||
this.updateNow = function () {
|
||||
pubnub.history({
|
||||
channel: currentSettings["channel"],
|
||||
callback: self.onPubNubHistory
|
||||
})
|
||||
}
|
||||
|
||||
this.onDispose = function () {
|
||||
self.closeConnection();
|
||||
}
|
||||
|
||||
this.onSettingsChanged = function (newSettings) {
|
||||
if (newSettings["subscribe_key"] !== currentSettings["subscribe_key"]) {
|
||||
pubnub = PUBNUB.init({
|
||||
subscribe_key: newSettings["subscribe_key"],
|
||||
ssl: true
|
||||
});
|
||||
}
|
||||
|
||||
if (newSettings["channel"] !== currentSettings["channel"]) {
|
||||
self.changeChannel(newSettings["channel"]);
|
||||
}
|
||||
|
||||
currentSettings = newSettings;
|
||||
}
|
||||
|
||||
self.onSettingsChanged(settings);
|
||||
};
|
||||
|
||||
freeboard.loadDatasourcePlugin({
|
||||
"type_name": "pubnub",
|
||||
"display_name": "PubNub",
|
||||
"external_scripts": [
|
||||
"https://cdn.pubnub.com/pubnub.min.js"
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"name": "subscribe_key",
|
||||
"display_name": "Subscribe Key",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "channel",
|
||||
"display_name": "Channel",
|
||||
"type": "text"
|
||||
},
|
||||
],
|
||||
newInstance: function (settings, newInstanceCallback, updateCallback) {
|
||||
newInstanceCallback(new pubnubDatasource(settings, updateCallback));
|
||||
}
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
/*! head.core - v1.0.2 */
|
||||
(function(n,t){"use strict";function r(n){a[a.length]=n}function k(n){var t=new RegExp(" ?\\b"+n+"\\b");c.className=c.className.replace(t,"")}function p(n,t){for(var i=0,r=n.length;i<r;i++)t.call(n,n[i],i)}function tt(){var t,e,f,o;c.className=c.className.replace(/ (w-|eq-|gt-|gte-|lt-|lte-|portrait|no-portrait|landscape|no-landscape)\d+/g,"");t=n.innerWidth||c.clientWidth;e=n.outerWidth||n.screen.width;u.screen.innerWidth=t;u.screen.outerWidth=e;r("w-"+t);p(i.screens,function(n){t>n?(i.screensCss.gt&&r("gt-"+n),i.screensCss.gte&&r("gte-"+n)):t<n?(i.screensCss.lt&&r("lt-"+n),i.screensCss.lte&&r("lte-"+n)):t===n&&(i.screensCss.lte&&r("lte-"+n),i.screensCss.eq&&r("e-q"+n),i.screensCss.gte&&r("gte-"+n))});f=n.innerHeight||c.clientHeight;o=n.outerHeight||n.screen.height;u.screen.innerHeight=f;u.screen.outerHeight=o;u.feature("portrait",f>t);u.feature("landscape",f<t)}function it(){n.clearTimeout(b);b=n.setTimeout(tt,50)}var y=n.document,rt=n.navigator,ut=n.location,c=y.documentElement,a=[],i={screens:[240,320,480,640,768,800,1024,1280,1440,1680,1920],screensCss:{gt:!0,gte:!1,lt:!0,lte:!1,eq:!1},browsers:[{ie:{min:6,max:11}}],browserCss:{gt:!0,gte:!1,lt:!0,lte:!1,eq:!0},html5:!0,page:"-page",section:"-section",head:"head"},v,u,s,w,o,h,l,d,f,g,nt,e,b;if(n.head_conf)for(v in n.head_conf)n.head_conf[v]!==t&&(i[v]=n.head_conf[v]);u=n[i.head]=function(){u.ready.apply(null,arguments)};u.feature=function(n,t,i){return n?(Object.prototype.toString.call(t)==="[object Function]"&&(t=t.call()),r((t?"":"no-")+n),u[n]=!!t,i||(k("no-"+n),k(n),u.feature()),u):(c.className+=" "+a.join(" "),a=[],u)};u.feature("js",!0);s=rt.userAgent.toLowerCase();w=/mobile|android|kindle|silk|midp|phone|(windows .+arm|touch)/.test(s);u.feature("mobile",w,!0);u.feature("desktop",!w,!0);s=/(chrome|firefox)[ \/]([\w.]+)/.exec(s)||/(iphone|ipad|ipod)(?:.*version)?[ \/]([\w.]+)/.exec(s)||/(android)(?:.*version)?[ \/]([\w.]+)/.exec(s)||/(webkit|opera)(?:.*version)?[ \/]([\w.]+)/.exec(s)||/(msie) ([\w.]+)/.exec(s)||/(trident).+rv:(\w.)+/.exec(s)||[];o=s[1];h=parseFloat(s[2]);switch(o){case"msie":case"trident":o="ie";h=y.documentMode||h;break;case"firefox":o="ff";break;case"ipod":case"ipad":case"iphone":o="ios";break;case"webkit":o="safari"}for(u.browser={name:o,version:h},u.browser[o]=!0,l=0,d=i.browsers.length;l<d;l++)for(f in i.browsers[l])if(o===f)for(r(f),g=i.browsers[l][f].min,nt=i.browsers[l][f].max,e=g;e<=nt;e++)h>e?(i.browserCss.gt&&r("gt-"+f+e),i.browserCss.gte&&r("gte-"+f+e)):h<e?(i.browserCss.lt&&r("lt-"+f+e),i.browserCss.lte&&r("lte-"+f+e)):h===e&&(i.browserCss.lte&&r("lte-"+f+e),i.browserCss.eq&&r("eq-"+f+e),i.browserCss.gte&&r("gte-"+f+e));else r("no-"+f);r(o);r(o+parseInt(h,10));i.html5&&o==="ie"&&h<9&&p("abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|progress|section|summary|time|video".split("|"),function(n){y.createElement(n)});p(ut.pathname.split("/"),function(n,u){if(this.length>2&&this[u+1]!==t)u&&r(this.slice(u,u+1).join("-").toLowerCase()+i.section);else{var f=n||"index",e=f.indexOf(".");e>0&&(f=f.substring(0,e));c.id=f.toLowerCase()+i.page;u||r("root"+i.section)}});u.screen={height:n.screen.height,width:n.screen.width};tt();b=0;n.addEventListener?n.addEventListener("resize",it,!1):n.attachEvent("onresize",it)})(window);
|
||||
/*! head.css3 - v1.0.0 */
|
||||
(function(n,t){"use strict";function a(n){for(var r in n)if(i[n[r]]!==t)return!0;return!1}function r(n){var t=n.charAt(0).toUpperCase()+n.substr(1),i=(n+" "+c.join(t+" ")+t).split(" ");return!!a(i)}var h=n.document,o=h.createElement("i"),i=o.style,s=" -o- -moz- -ms- -webkit- -khtml- ".split(" "),c="Webkit Moz O ms Khtml".split(" "),l=n.head_conf&&n.head_conf.head||"head",u=n[l],f={gradient:function(){var n="background-image:";return i.cssText=(n+s.join("gradient(linear,left top,right bottom,from(#9f9),to(#fff));"+n)+s.join("linear-gradient(left top,#eee,#fff);"+n)).slice(0,-n.length),!!i.backgroundImage},rgba:function(){return i.cssText="background-color:rgba(0,0,0,0.5)",!!i.backgroundColor},opacity:function(){return o.style.opacity===""},textshadow:function(){return i.textShadow===""},multiplebgs:function(){i.cssText="background:url(https://),url(https://),red url(https://)";var n=(i.background||"").match(/url/g);return Object.prototype.toString.call(n)==="[object Array]"&&n.length===3},boxshadow:function(){return r("boxShadow")},borderimage:function(){return r("borderImage")},borderradius:function(){return r("borderRadius")},cssreflections:function(){return r("boxReflect")},csstransforms:function(){return r("transform")},csstransitions:function(){return r("transition")},touch:function(){return"ontouchstart"in n},retina:function(){return n.devicePixelRatio>1},fontface:function(){var t=u.browser.name,n=u.browser.version;switch(t){case"ie":return n>=9;case"chrome":return n>=13;case"ff":return n>=6;case"ios":return n>=5;case"android":return!1;case"webkit":return n>=5.1;case"opera":return n>=10;default:return!1}}};for(var e in f)f[e]&&u.feature(e,f[e].call(),!0);u.feature()})(window);
|
||||
/*! head.load - v1.0.3 */
|
||||
(function(n,t){"use strict";function w(){}function u(n,t){if(n){typeof n=="object"&&(n=[].slice.call(n));for(var i=0,r=n.length;i<r;i++)t.call(n,n[i],i)}}function it(n,i){var r=Object.prototype.toString.call(i).slice(8,-1);return i!==t&&i!==null&&r===n}function s(n){return it("Function",n)}function a(n){return it("Array",n)}function et(n){var i=n.split("/"),t=i[i.length-1],r=t.indexOf("?");return r!==-1?t.substring(0,r):t}function f(n){(n=n||w,n._done)||(n(),n._done=1)}function ot(n,t,r,u){var f=typeof n=="object"?n:{test:n,success:!t?!1:a(t)?t:[t],failure:!r?!1:a(r)?r:[r],callback:u||w},e=!!f.test;return e&&!!f.success?(f.success.push(f.callback),i.load.apply(null,f.success)):e||!f.failure?u():(f.failure.push(f.callback),i.load.apply(null,f.failure)),i}function v(n){var t={},i,r;if(typeof n=="object")for(i in n)!n[i]||(t={name:i,url:n[i]});else t={name:et(n),url:n};return(r=c[t.name],r&&r.url===t.url)?r:(c[t.name]=t,t)}function y(n){n=n||c;for(var t in n)if(n.hasOwnProperty(t)&&n[t].state!==l)return!1;return!0}function st(n){n.state=ft;u(n.onpreload,function(n){n.call()})}function ht(n){n.state===t&&(n.state=nt,n.onpreload=[],rt({url:n.url,type:"cache"},function(){st(n)}))}function ct(){var n=arguments,t=n[n.length-1],r=[].slice.call(n,1),f=r[0];return(s(t)||(t=null),a(n[0]))?(n[0].push(t),i.load.apply(null,n[0]),i):(f?(u(r,function(n){s(n)||!n||ht(v(n))}),b(v(n[0]),s(f)?f:function(){i.load.apply(null,r)})):b(v(n[0])),i)}function lt(){var n=arguments,t=n[n.length-1],r={};return(s(t)||(t=null),a(n[0]))?(n[0].push(t),i.load.apply(null,n[0]),i):(u(n,function(n){n!==t&&(n=v(n),r[n.name]=n)}),u(n,function(n){n!==t&&(n=v(n),b(n,function(){y(r)&&f(t)}))}),i)}function b(n,t){if(t=t||w,n.state===l){t();return}if(n.state===tt){i.ready(n.name,t);return}if(n.state===nt){n.onpreload.push(function(){b(n,t)});return}n.state=tt;rt(n,function(){n.state=l;t();u(h[n.name],function(n){f(n)});o&&y()&&u(h.ALL,function(n){f(n)})})}function at(n){n=n||"";var t=n.split("?")[0].split(".");return t[t.length-1].toLowerCase()}function rt(t,i){function e(t){t=t||n.event;u.onload=u.onreadystatechange=u.onerror=null;i()}function o(f){f=f||n.event;(f.type==="load"||/loaded|complete/.test(u.readyState)&&(!r.documentMode||r.documentMode<9))&&(n.clearTimeout(t.errorTimeout),n.clearTimeout(t.cssTimeout),u.onload=u.onreadystatechange=u.onerror=null,i())}function s(){if(t.state!==l&&t.cssRetries<=20){for(var i=0,f=r.styleSheets.length;i<f;i++)if(r.styleSheets[i].href===u.href){o({type:"load"});return}t.cssRetries++;t.cssTimeout=n.setTimeout(s,250)}}var u,h,f;i=i||w;h=at(t.url);h==="css"?(u=r.createElement("link"),u.type="text/"+(t.type||"css"),u.rel="stylesheet",u.href=t.url,t.cssRetries=0,t.cssTimeout=n.setTimeout(s,500)):(u=r.createElement("script"),u.type="text/"+(t.type||"javascript"),u.src=t.url);u.onload=u.onreadystatechange=o;u.onerror=e;u.async=!1;u.defer=!1;t.errorTimeout=n.setTimeout(function(){e({type:"timeout"})},7e3);f=r.head||r.getElementsByTagName("head")[0];f.insertBefore(u,f.lastChild)}function vt(){for(var t,u=r.getElementsByTagName("script"),n=0,f=u.length;n<f;n++)if(t=u[n].getAttribute("data-headjs-load"),!!t){i.load(t);return}}function yt(n,t){var v,p,e;return n===r?(o?f(t):d.push(t),i):(s(n)&&(t=n,n="ALL"),a(n))?(v={},u(n,function(n){v[n]=c[n];i.ready(n,function(){y(v)&&f(t)})}),i):typeof n!="string"||!s(t)?i:(p=c[n],p&&p.state===l||n==="ALL"&&y()&&o)?(f(t),i):(e=h[n],e?e.push(t):e=h[n]=[t],i)}function e(){if(!r.body){n.clearTimeout(i.readyTimeout);i.readyTimeout=n.setTimeout(e,50);return}o||(o=!0,vt(),u(d,function(n){f(n)}))}function k(){r.addEventListener?(r.removeEventListener("DOMContentLoaded",k,!1),e()):r.readyState==="complete"&&(r.detachEvent("onreadystatechange",k),e())}var r=n.document,d=[],h={},c={},ut="async"in r.createElement("script")||"MozAppearance"in r.documentElement.style||n.opera,o,g=n.head_conf&&n.head_conf.head||"head",i=n[g]=n[g]||function(){i.ready.apply(null,arguments)},nt=1,ft=2,tt=3,l=4,p;if(r.readyState==="complete")e();else if(r.addEventListener)r.addEventListener("DOMContentLoaded",k,!1),n.addEventListener("load",e,!1);else{r.attachEvent("onreadystatechange",k);n.attachEvent("onload",e);p=!1;try{p=!n.frameElement&&r.documentElement}catch(wt){}p&&p.doScroll&&function pt(){if(!o){try{p.doScroll("left")}catch(t){n.clearTimeout(i.readyTimeout);i.readyTimeout=n.setTimeout(pt,50);return}e()}}()}i.load=i.js=ut?lt:ct;i.test=ot;i.ready=yt;i.ready(r,function(){y()&&u(h.ALL,function(n){f(n)});i.feature&&i.feature("domloaded",!0)})})(window);
|
||||
/*
|
||||
//# sourceMappingURL=head.min.js.map
|
||||
*/
|
|
@ -0,0 +1,139 @@
|
|||
(function($)
|
||||
{
|
||||
$.fn.insertAtCaret = function(text, opts)
|
||||
{
|
||||
var element = $(this).get(0);
|
||||
|
||||
if(document.selection)
|
||||
{
|
||||
element.focus();
|
||||
var orig = element.value.replace(/\r\n/g, "\n");
|
||||
var range = document.selection.createRange();
|
||||
|
||||
if(range.parentElement() != element)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
range.text = text;
|
||||
|
||||
var actual = tmp = element.value.replace(/\r\n/g, "\n");
|
||||
|
||||
for(var diff = 0; diff < orig.length; diff++)
|
||||
{
|
||||
if(orig.charAt(diff) != actual.charAt(diff)) break;
|
||||
}
|
||||
|
||||
for(var index = 0, start = 0; tmp.match(text) && (tmp = tmp.replace(text, "")) && index <= diff; index = start + text.length)
|
||||
{
|
||||
start = actual.indexOf(text, index);
|
||||
}
|
||||
}
|
||||
else if(element.selectionStart)
|
||||
{
|
||||
var start = element.selectionStart;
|
||||
var end = element.selectionEnd;
|
||||
|
||||
element.value = element.value.substr(0, start) + text + element.value.substr(end, element.value.length);
|
||||
}
|
||||
|
||||
if(start)
|
||||
{
|
||||
setCaretTo(element, start + text.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.value = text + element.value;
|
||||
}
|
||||
|
||||
$(this).change();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
$.fn.replaceTextAt = function(start, end, replacementText)
|
||||
{
|
||||
var element = $(this).get(0);
|
||||
|
||||
var wholeString = $(this).val();
|
||||
var prefix = wholeString.substr(0, start);
|
||||
var suffix = wholeString.substr(end);
|
||||
|
||||
$(this).val(prefix + replacementText + suffix);
|
||||
|
||||
var newCursorPosition = prefix.length + replacementText.length;
|
||||
|
||||
setCaretTo(element, newCursorPosition);
|
||||
|
||||
$(this).change();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
$.fn.setCaretPosition = function(start, end)
|
||||
{
|
||||
var element = $(this).get(0);
|
||||
element.focus();
|
||||
setCaretTo(element, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
$.fn.getCaretPosition = function()
|
||||
{
|
||||
var element = $(this).get(0);
|
||||
$(element).focus();
|
||||
return getCaretPosition(element);
|
||||
}
|
||||
|
||||
$.fn.getSelectedText = function()
|
||||
{
|
||||
var element = $(this).get(0);
|
||||
|
||||
// workaround for firefox because window.getSelection does not work inside inputs
|
||||
if(typeof element.selectionStart == 'number')
|
||||
{
|
||||
return $(element).val().substr(element.selectionStart, element.selectionEnd - element.selectionStart);
|
||||
}
|
||||
else if(document.getSelection)
|
||||
{
|
||||
return document.getSelection();
|
||||
}
|
||||
else if(window.getSelection)
|
||||
{
|
||||
return window.getSelection();
|
||||
}
|
||||
}
|
||||
|
||||
// privates
|
||||
function setCaretTo(element, start, end)
|
||||
{
|
||||
if(element.createTextRange)
|
||||
{
|
||||
var range = element.createTextRange();
|
||||
range.moveStart('character', start);
|
||||
range.moveEnd('character', (end || start));
|
||||
range.select();
|
||||
}
|
||||
else if(element.selectionStart)
|
||||
{
|
||||
element.focus();
|
||||
element.setSelectionRange(start, (end || start));
|
||||
}
|
||||
}
|
||||
|
||||
function getCaretPosition(element)
|
||||
{
|
||||
if(typeof element.selectionStart == 'number')
|
||||
{
|
||||
return element.selectionStart;
|
||||
}
|
||||
else if(document.selection)
|
||||
{
|
||||
var range = document.selection.createRange();
|
||||
var rangeLength = range.text.length;
|
||||
range.moveStart('character', -element.value.length);
|
||||
return range.text.length - rangeLength;
|
||||
}
|
||||
}
|
||||
})(jQuery);
|
|
@ -0,0 +1,491 @@
|
|||
/**
|
||||
* JustGage - a handy JavaScript plugin for generating and animating nice & clean dashboard gauges.
|
||||
* Copyright (c) 2012 Bojan Djuricic - pindjur(at)gmail(dot)com | http://www.madcog.com
|
||||
* Licensed under MIT.
|
||||
* Date: 31/07/2012
|
||||
* @author Bojan Djuricic (@Toorshia)
|
||||
* @version 1.0
|
||||
*
|
||||
* http://www.justgage.com
|
||||
*/
|
||||
|
||||
JustGage = function(config)
|
||||
{
|
||||
|
||||
if(!config.id)
|
||||
{
|
||||
alert("Missing id parameter for gauge!");
|
||||
return false;
|
||||
}
|
||||
if(!document.getElementById(config.id))
|
||||
{
|
||||
alert("No element with id: \"" + config.id + "\" found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// configurable parameters
|
||||
this.config = {
|
||||
// id : string
|
||||
// this is container element id
|
||||
id : config.id,
|
||||
|
||||
// value : int
|
||||
// value gauge is showing
|
||||
value : (config.value) ? config.value : 0,
|
||||
|
||||
// valueFontColor : string
|
||||
// color of label showing current value
|
||||
valueFontColor : (config.valueFontColor) ? config.valueFontColor : "#010101",
|
||||
|
||||
// min : int
|
||||
// min value
|
||||
min : (config.min) ? config.min : 0,
|
||||
|
||||
// max : int
|
||||
// max value
|
||||
max : (config.max) ? config.max : 100,
|
||||
|
||||
// showMinMax : bool
|
||||
// hide or display min and max values
|
||||
showMinMax : (config.showMinMax != null) ? config.showMinMax : true,
|
||||
|
||||
// gaugeWidthScale : float
|
||||
// width of the gauge element
|
||||
gaugeWidthScale : (config.gaugeWidthScale) ? config.gaugeWidthScale : 1.0,
|
||||
|
||||
// gaugeColor : string
|
||||
// background color of gauge element
|
||||
gaugeColor : (config.gaugeColor) ? config.gaugeColor : "#edebeb",
|
||||
|
||||
// label : string
|
||||
// text to show below value
|
||||
label : (config.label) ? config.label : "",
|
||||
|
||||
// showInnerShadow : bool
|
||||
// give gauge element small amount of inner shadow
|
||||
showInnerShadow : (config.showInnerShadow != null) ? config.showInnerShadow : true,
|
||||
|
||||
// shadowOpacity : int
|
||||
// 0 ~ 1
|
||||
shadowOpacity : (config.shadowOpacity) ? config.shadowOpacity : 0.2,
|
||||
|
||||
// shadowSize: int
|
||||
// inner shadow size
|
||||
shadowSize : (config.shadowSize) ? config.shadowSize : 5,
|
||||
|
||||
// shadowVerticalOffset : int
|
||||
// how much shadow is offset from top
|
||||
shadowVerticalOffset: (config.shadowVerticalOffset) ? config.shadowVerticalOffset : 3,
|
||||
|
||||
// levelColors : string[]
|
||||
// colors of indicator, from lower to upper, in RGB format
|
||||
levelColors : (config.levelColors) ? config.levelColors : percentColors,
|
||||
|
||||
// levelColorsGradient : bool
|
||||
// whether to use gradual color change for value, or sector-based
|
||||
levelColorsGradient : (config.levelColorsGradient != null) ? config.levelColorsGradient : true,
|
||||
|
||||
// labelFontColor : string
|
||||
// color of label showing label under value
|
||||
labelFontColor : (config.labelFontColor) ? config.labelFontColor : "#b3b3b3",
|
||||
|
||||
// startAnimationTime : int
|
||||
// length of initial animation
|
||||
startAnimationTime : (config.startAnimationTime) ? config.startAnimationTime : 700,
|
||||
|
||||
// startAnimationType : string
|
||||
// type of initial animation (linear, >, <, <>, bounce)
|
||||
startAnimationType : (config.startAnimationType) ? config.startAnimationType : ">",
|
||||
|
||||
// refreshAnimationTime : int
|
||||
// length of refresh animation
|
||||
refreshAnimationTime: (config.refreshAnimationTime) ? config.refreshAnimationTime : 700,
|
||||
|
||||
// refreshAnimationType : string
|
||||
// type of refresh animation (linear, >, <, <>, bounce)
|
||||
refreshAnimationType: (config.refreshAnimationType) ? config.refreshAnimationType : ">"
|
||||
};
|
||||
|
||||
// overflow values
|
||||
if(config.value > this.config.max) this.config.value = this.config.max;
|
||||
if(config.value < this.config.min) this.config.value = this.config.min;
|
||||
this.originalValue = config.value;
|
||||
|
||||
// canvas
|
||||
this.canvas = Raphael(this.config.id, "100%", "100%");
|
||||
|
||||
// canvas dimensions
|
||||
//var canvasW = document.getElementById(this.config.id).clientWidth;
|
||||
//var canvasH = document.getElementById(this.config.id).clientHeight;
|
||||
var canvasW = getStyle(document.getElementById(this.config.id), "width").slice(0, -2) * 1;
|
||||
var canvasH = getStyle(document.getElementById(this.config.id), "height").slice(0, -2) * 1;
|
||||
|
||||
// widget dimensions
|
||||
var widgetW, widgetH;
|
||||
if((canvasW / canvasH) > 1.25)
|
||||
{
|
||||
widgetW = 1.25 * canvasH;
|
||||
widgetH = canvasH;
|
||||
}
|
||||
else
|
||||
{
|
||||
widgetW = canvasW;
|
||||
widgetH = canvasW / 1.25;
|
||||
}
|
||||
|
||||
// delta
|
||||
var dx = (canvasW - widgetW) / 2;
|
||||
var dy = (canvasH - widgetH) / 2;
|
||||
|
||||
// value
|
||||
var valueFontSize = ((widgetH / 6.4) > 16) ? (widgetH / 6.4) : 16;
|
||||
var valueX = dx + widgetW / 2;
|
||||
var valueY = dy + widgetH / 1.4;
|
||||
|
||||
// label
|
||||
var labelFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
|
||||
var labelX = dx + widgetW / 2;
|
||||
//var labelY = dy + widgetH / 1.126760563380282;
|
||||
var labelY = valueY + valueFontSize / 2 + 6;
|
||||
|
||||
// min
|
||||
var minFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
|
||||
var minX = dx + (widgetW / 10) + (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2;
|
||||
var minY = dy + widgetH / 1.126760563380282;
|
||||
|
||||
// max
|
||||
var maxFontSize = ((widgetH / 16) > 10) ? (widgetH / 16) : 10;
|
||||
var maxX = dx + widgetW - (widgetW / 10) - (widgetW / 6.666666666666667 * this.config.gaugeWidthScale) / 2;
|
||||
var maxY = dy + widgetH / 1.126760563380282;
|
||||
|
||||
// parameters
|
||||
this.params = {
|
||||
canvasW : canvasW,
|
||||
canvasH : canvasH,
|
||||
widgetW : widgetW,
|
||||
widgetH : widgetH,
|
||||
dx : dx,
|
||||
dy : dy,
|
||||
valueFontSize: valueFontSize,
|
||||
valueX : valueX,
|
||||
valueY : valueY,
|
||||
labelFontSize: labelFontSize,
|
||||
labelX : labelX,
|
||||
labelY : labelY,
|
||||
minFontSize : minFontSize,
|
||||
minX : minX,
|
||||
minY : minY,
|
||||
maxFontSize : maxFontSize,
|
||||
maxX : maxX,
|
||||
maxY : maxY
|
||||
};
|
||||
|
||||
// pki - custom attribute for generating gauge paths
|
||||
this.canvas.customAttributes.pki = function(value, min, max, w, h, dx, dy, gws)
|
||||
{
|
||||
|
||||
var alpha = (1 - (value - min) / (max - min)) * Math.PI , Ro = w / 2 - w / 10, Ri = Ro - w / 6.666666666666667 * gws,
|
||||
|
||||
Cx = w / 2 + dx, Cy = h / 1.25 + dy,
|
||||
|
||||
Xo = w / 2 + dx + Ro * Math.cos(alpha), Yo = h - (h - Cy) + dy - Ro * Math.sin(alpha), Xi = w / 2 + dx + Ri * Math.cos(alpha), Yi = h - (h - Cy) + dy - Ri * Math.sin(alpha), path;
|
||||
|
||||
path += "M" + (Cx - Ri) + "," + Cy + " ";
|
||||
path += "L" + (Cx - Ro) + "," + Cy + " ";
|
||||
path += "A" + Ro + "," + Ro + " 0 0,1 " + Xo + "," + Yo + " ";
|
||||
path += "L" + Xi + "," + Yi + " ";
|
||||
path += "A" + Ri + "," + Ri + " 0 0,0 " + (Cx - Ri) + "," + Cy + " ";
|
||||
path += "z ";
|
||||
return { path: path };
|
||||
}
|
||||
|
||||
// gauge
|
||||
this.gauge = this.canvas.path().attr({
|
||||
"stroke": "none",
|
||||
"fill" : this.config.gaugeColor,
|
||||
pki : [this.config.max, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH,
|
||||
this.params.dx, this.params.dy, this.config.gaugeWidthScale]
|
||||
});
|
||||
this.gauge.id = this.config.id + "-gauge";
|
||||
|
||||
// level
|
||||
this.level = this.canvas.path().attr({
|
||||
"stroke": "none",
|
||||
"fill" : getColorForPercentage((this.config.value - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient),
|
||||
pki : [this.config.min, this.config.min, this.config.max, this.params.widgetW, this.params.widgetH,
|
||||
this.params.dx, this.params.dy, this.config.gaugeWidthScale]
|
||||
});
|
||||
this.level.id = this.config.id + "-level";
|
||||
|
||||
// value
|
||||
this.txtValue = this.canvas.text(this.params.valueX, this.params.valueY, this.originalValue);
|
||||
this.txtValue.attr({
|
||||
"font-size" : this.params.valueFontSize,
|
||||
"font-weight" : "bold",
|
||||
"font-family" : "Arial",
|
||||
"fill" : this.config.valueFontColor,
|
||||
"fill-opacity": "0"
|
||||
});
|
||||
this.txtValue.id = this.config.id + "-txtvalue";
|
||||
|
||||
// label
|
||||
this.txtLabel = this.canvas.text(this.params.labelX, this.params.labelY, this.config.label);
|
||||
this.txtLabel.attr({
|
||||
"font-size" : this.params.labelFontSize,
|
||||
"font-weight" : "normal",
|
||||
"font-family" : "Arial",
|
||||
"fill" : this.config.labelFontColor,
|
||||
"fill-opacity": "0"
|
||||
});
|
||||
this.txtLabel.id = this.config.id + "-txtlabel";
|
||||
|
||||
// min
|
||||
this.txtMin = this.canvas.text(this.params.minX, this.params.minY, this.config.min);
|
||||
this.txtMin.attr({
|
||||
"font-size" : this.params.minFontSize,
|
||||
"font-weight" : "normal",
|
||||
"font-family" : "Arial",
|
||||
"fill" : this.config.labelFontColor,
|
||||
"fill-opacity": (this.config.showMinMax == true) ? "1" : "0"
|
||||
});
|
||||
this.txtMin.id = this.config.id + "-txtmin";
|
||||
|
||||
// max
|
||||
this.txtMax = this.canvas.text(this.params.maxX, this.params.maxY, this.config.max);
|
||||
this.txtMax.attr({
|
||||
"font-size" : this.params.maxFontSize,
|
||||
"font-weight" : "normal",
|
||||
"font-family" : "Arial",
|
||||
"fill" : this.config.labelFontColor,
|
||||
"fill-opacity": (this.config.showMinMax == true) ? "1" : "0"
|
||||
});
|
||||
this.txtMax.id = this.config.id + "-txtmax";
|
||||
|
||||
var defs = this.canvas.canvas.childNodes[1];
|
||||
var svg = "http://www.w3.org/2000/svg";
|
||||
|
||||
|
||||
if(ie < 9)
|
||||
{
|
||||
onCreateElementNsReady(function()
|
||||
{
|
||||
this.generateShadow();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.generateShadow(svg, defs);
|
||||
}
|
||||
|
||||
// animate
|
||||
this.level.animate({pki: [this.config.value, this.config.min, this.config.max, this.params.widgetW,
|
||||
this.params.widgetH, this.params.dx, this.params.dy, this.config.gaugeWidthScale
|
||||
]}, this.config.startAnimationTime, this.config.startAnimationType);
|
||||
|
||||
this.txtValue.animate({"fill-opacity": "1"}, this.config.startAnimationTime, this.config.startAnimationType);
|
||||
this.txtLabel.animate({"fill-opacity": "1"}, this.config.startAnimationTime, this.config.startAnimationType);
|
||||
};
|
||||
|
||||
// refresh gauge level
|
||||
JustGage.prototype.refresh = function(val)
|
||||
{
|
||||
// overflow values
|
||||
originalVal = val;
|
||||
if(val > this.config.max)
|
||||
{
|
||||
val = this.config.max;
|
||||
}
|
||||
if(val < this.config.min)
|
||||
{
|
||||
val = this.config.min;
|
||||
}
|
||||
|
||||
var color = getColorForPercentage((val - this.config.min) / (this.config.max - this.config.min), this.config.levelColors, this.config.levelColorsGradient);
|
||||
this.canvas.getById(this.config.id + "-txtvalue").attr({"text": originalVal});
|
||||
this.canvas.getById(this.config.id + "-level").animate({pki : [val,
|
||||
this.config.min,
|
||||
this.config.max,
|
||||
this.params.widgetW,
|
||||
this.params.widgetH,
|
||||
this.params.dx,
|
||||
this.params.dy,
|
||||
this.config.gaugeWidthScale
|
||||
], "fill" : color}, this.config.refreshAnimationTime, this.config.refreshAnimationType);
|
||||
};
|
||||
|
||||
var percentColors = [
|
||||
"#a9d70b", "#f9c802", "#ff0000"
|
||||
]
|
||||
|
||||
JustGage.prototype.generateShadow = function(svg, defs)
|
||||
{
|
||||
// FILTER
|
||||
var gaussFilter = document.createElementNS(svg, "filter");
|
||||
gaussFilter.setAttribute("id", this.config.id + "-inner-shadow");
|
||||
defs.appendChild(gaussFilter);
|
||||
|
||||
// offset
|
||||
var feOffset = document.createElementNS(svg, "feOffset");
|
||||
feOffset.setAttribute("dx", 0);
|
||||
feOffset.setAttribute("dy", this.config.shadowVerticalOffset);
|
||||
gaussFilter.appendChild(feOffset);
|
||||
|
||||
// blur
|
||||
var feGaussianBlur = document.createElementNS(svg, "feGaussianBlur");
|
||||
feGaussianBlur.setAttribute("result", "offset-blur");
|
||||
feGaussianBlur.setAttribute("stdDeviation", this.config.shadowSize);
|
||||
gaussFilter.appendChild(feGaussianBlur);
|
||||
|
||||
// composite 1
|
||||
var feComposite1 = document.createElementNS(svg, "feComposite");
|
||||
feComposite1.setAttribute("operator", "out");
|
||||
feComposite1.setAttribute("in", "SourceGraphic");
|
||||
feComposite1.setAttribute("in2", "offset-blur");
|
||||
feComposite1.setAttribute("result", "inverse");
|
||||
gaussFilter.appendChild(feComposite1);
|
||||
|
||||
// flood
|
||||
var feFlood = document.createElementNS(svg, "feFlood");
|
||||
feFlood.setAttribute("flood-color", "black");
|
||||
feFlood.setAttribute("flood-opacity", this.config.shadowOpacity);
|
||||
feFlood.setAttribute("result", "color");
|
||||
gaussFilter.appendChild(feFlood);
|
||||
|
||||
// composite 2
|
||||
var feComposite2 = document.createElementNS(svg, "feComposite");
|
||||
feComposite2.setAttribute("operator", "in");
|
||||
feComposite2.setAttribute("in", "color");
|
||||
feComposite2.setAttribute("in2", "inverse");
|
||||
feComposite2.setAttribute("result", "shadow");
|
||||
gaussFilter.appendChild(feComposite2);
|
||||
|
||||
// composite 3
|
||||
var feComposite3 = document.createElementNS(svg, "feComposite");
|
||||
feComposite3.setAttribute("operator", "over");
|
||||
feComposite3.setAttribute("in", "shadow");
|
||||
feComposite3.setAttribute("in2", "SourceGraphic");
|
||||
gaussFilter.appendChild(feComposite3);
|
||||
|
||||
// set shadow
|
||||
if(this.config.showInnerShadow == true)
|
||||
{
|
||||
this.canvas.canvas.childNodes[2].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)");
|
||||
this.canvas.canvas.childNodes[3].setAttribute("filter", "url(#" + this.config.id + "-inner-shadow)");
|
||||
}
|
||||
}
|
||||
|
||||
var getColorForPercentage = function(pct, col, grad)
|
||||
{
|
||||
|
||||
var no = col.length;
|
||||
if(no === 1) return col[0];
|
||||
var inc = (grad) ? (1 / (no - 1)) : (1 / no);
|
||||
var colors = new Array();
|
||||
for(var i = 0; i < col.length; i++)
|
||||
{
|
||||
var percentage = (grad) ? (inc * i) : (inc * (i + 1));
|
||||
var rval = parseInt((cutHex(col[i])).substring(0, 2), 16);
|
||||
var gval = parseInt((cutHex(col[i])).substring(2, 4), 16);
|
||||
var bval = parseInt((cutHex(col[i])).substring(4, 6), 16);
|
||||
colors[i] = { pct: percentage, color: { r: rval, g: gval, b: bval } };
|
||||
}
|
||||
|
||||
if(pct == 0) return 'rgb(' + [colors[0].color.r, colors[0].color.g, colors[0].color.b].join(',') + ')';
|
||||
for(var i = 0; i < colors.length; i++)
|
||||
{
|
||||
if(pct <= colors[i].pct)
|
||||
{
|
||||
if(grad == true)
|
||||
{
|
||||
var lower = colors[i - 1];
|
||||
var upper = colors[i];
|
||||
var range = upper.pct - lower.pct;
|
||||
var rangePct = (pct - lower.pct) / range;
|
||||
var pctLower = 1 - rangePct;
|
||||
var pctUpper = rangePct;
|
||||
var color = {
|
||||
r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),
|
||||
g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),
|
||||
b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)
|
||||
};
|
||||
return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'rgb(' + [colors[i].color.r, colors[i].color.g, colors[i].color.b].join(',') + ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomInt(min, max)
|
||||
{
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function cutHex(str)
|
||||
{
|
||||
return (str.charAt(0) == "#") ? str.substring(1, 7) : str
|
||||
}
|
||||
|
||||
function getStyle(oElm, strCssRule)
|
||||
{
|
||||
var strValue = "";
|
||||
if(document.defaultView && document.defaultView.getComputedStyle)
|
||||
{
|
||||
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
|
||||
}
|
||||
else if(oElm.currentStyle)
|
||||
{
|
||||
strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1)
|
||||
{
|
||||
return p1.toUpperCase();
|
||||
});
|
||||
strValue = oElm.currentStyle[strCssRule];
|
||||
}
|
||||
return strValue;
|
||||
}
|
||||
|
||||
function onCreateElementNsReady(func)
|
||||
{
|
||||
if(document.createElementNS != undefined)
|
||||
{
|
||||
func();
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
onCreateElementNsReady(func);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// A short snippet for detecting versions of IE in JavaScript
|
||||
// without resorting to user-agent sniffing
|
||||
// ----------------------------------------------------------
|
||||
// If you're not in IE (or IE version is less than 5) then:
|
||||
// ie === undefined
|
||||
// If you're in IE (>=5) then you can determine which version:
|
||||
// ie === 7; // IE7
|
||||
// Thus, to detect IE:
|
||||
// if (ie) {}
|
||||
// And to detect the version:
|
||||
// ie === 6 // IE6
|
||||
// ie > 7 // IE8, IE9 ...
|
||||
// ie < 9 // Anything less than IE9
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// UPDATE: Now using Live NodeList idea from @jdalton
|
||||
|
||||
var ie = (function()
|
||||
{
|
||||
|
||||
var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i');
|
||||
|
||||
while(div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]);
|
||||
|
||||
return v > 4 ? v : undef;
|
||||
|
||||
}());
|
|
@ -0,0 +1,94 @@
|
|||
// Knockout JavaScript library v3.0.0
|
||||
// (c) Steven Sanderson - http://knockoutjs.com/
|
||||
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
(function() {(function(q){var y=this||(0,eval)("this"),w=y.document,K=y.navigator,u=y.jQuery,B=y.JSON;(function(q){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?q(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],q):q(y.ko={})})(function(F){function G(a,c){return null===a||typeof a in N?a===c:!1}function H(b,c,d,e){a.d[b]={init:function(b){a.a.f.set(b,L,{});return{controlsDescendantBindings:!0}},update:function(b,h,k,m,f){k=a.a.f.get(b,L);h=a.a.c(h());
|
||||
m=!d!==!h;var p=!k.ob;if(p||c||m!==k.Db)p&&(k.ob=a.a.Ya(a.e.childNodes(b),!0)),m?(p||a.e.S(b,a.a.Ya(k.ob)),a.Ta(e?e(f,h):f,b)):a.e.Z(b),k.Db=m}};a.g.Y[b]=!1;a.e.P[b]=!0}var a="undefined"!==typeof F?F:{};a.b=function(b,c){for(var d=b.split("."),e=a,g=0;g<d.length-1;g++)e=e[d[g]];e[d[d.length-1]]=c};a.s=function(a,c,d){a[c]=d};a.version="3.0.0";a.b("version",a.version);a.a=function(){function b(a,b){for(var f in a)a.hasOwnProperty(f)&&b(f,a[f])}function c(k,b){if("input"!==a.a.v(k)||!k.type||"click"!=
|
||||
b.toLowerCase())return!1;var f=k.type;return"checkbox"==f||"radio"==f}var d={},e={};d[K&&/Firefox\/2/i.test(K.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(d,function(a,b){if(b.length)for(var f=0,c=b.length;f<c;f++)e[b[f]]=a});var g={propertychange:!0},h=w&&function(){for(var a=3,b=w.createElement("div"),f=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+
|
||||
++a+"]><i></i><![endif]--\x3e",f[0];);return 4<a?a:q}();return{$a:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],n:function(a,b){for(var f=0,c=a.length;f<c;f++)b(a[f])},l:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var f=0,c=a.length;f<c;f++)if(a[f]===b)return f;return-1},Ua:function(a,b,f){for(var c=0,d=a.length;c<d;c++)if(b.call(f,a[c]))return a[c];return null},ia:function(b,c){var f=a.a.l(b,c);0<=f&&b.splice(f,1)},Va:function(b){b=
|
||||
b||[];for(var c=[],f=0,d=b.length;f<d;f++)0>a.a.l(c,b[f])&&c.push(b[f]);return c},ha:function(a,b){a=a||[];for(var f=[],c=0,d=a.length;c<d;c++)f.push(b(a[c]));return f},ga:function(a,b){a=a||[];for(var f=[],c=0,d=a.length;c<d;c++)b(a[c])&&f.push(a[c]);return f},X:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var f=0,c=b.length;f<c;f++)a.push(b[f]);return a},V:function(b,c,f){var d=a.a.l(a.a.Ha(b),c);0>d?f&&b.push(c):f||b.splice(d,1)},extend:function(a,b){if(b)for(var f in b)b.hasOwnProperty(f)&&
|
||||
(a[f]=b[f]);return a},K:b,Da:function(a,b){if(!a)return a;var f={},c;for(c in a)a.hasOwnProperty(c)&&(f[c]=b(a[c],c,a));return f},wa:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Vb:function(b){b=a.a.Q(b);for(var c=w.createElement("div"),f=0,d=b.length;f<d;f++)c.appendChild(a.L(b[f]));return c},Ya:function(b,c){for(var f=0,d=b.length,e=[];f<d;f++){var g=b[f].cloneNode(!0);e.push(c?a.L(g):g)}return e},S:function(b,c){a.a.wa(b);if(c)for(var f=0,d=c.length;f<d;f++)b.appendChild(c[f])},nb:function(b,
|
||||
c){var f=b.nodeType?[b]:b;if(0<f.length){for(var d=f[0],e=d.parentNode,g=0,n=c.length;g<n;g++)e.insertBefore(c[g],d);g=0;for(n=f.length;g<n;g++)a.removeNode(f[g])}},$:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);if(1<a.length){var f=a[0],c=a[a.length-1];for(a.length=0;f!==c;)if(a.push(f),f=f.nextSibling,!f)return;a.push(c)}}return a},qb:function(a,b){7>h?a.setAttribute("selected",b):a.selected=b},la:function(a){return null===a||a===
|
||||
q?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},ec:function(b,c){for(var f=[],d=(b||"").split(c),e=0,g=d.length;e<g;e++){var n=a.a.la(d[e]);""!==n&&f.push(n)}return f},ac:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Gb:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;
|
||||
return!!a},va:function(b){return a.a.Gb(b,b.ownerDocument.documentElement)},Ra:function(b){return!!a.a.Ua(b,a.a.va)},v:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},r:function(b,d,f){var e=h&&g[d];if(e||"undefined"==typeof u)if(e||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var s=function(a){f.call(b,a)},l="on"+d;b.attachEvent(l,s);a.a.C.ea(b,function(){b.detachEvent(l,s)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(d,
|
||||
f,!1);else{if(c(b,d)){var n=f;f=function(a,b){var f=this.checked;b&&(this.checked=!0!==b.Ab);n.call(this,a);this.checked=f}}u(b).bind(d,f)}},da:function(a,b){if(!a||!a.nodeType)throw Error("element must be a DOM node when calling triggerEvent");if("undefined"!=typeof u){var f=[];c(a,b)&&f.push({Ab:a.checked});u(a).trigger(b,f)}else if("function"==typeof w.createEvent)if("function"==typeof a.dispatchEvent)f=w.createEvent(e[b]||"HTMLEvents"),f.initEvent(b,!0,!0,y,0,0,0,0,0,!1,!1,!1,!1,0,a),a.dispatchEvent(f);
|
||||
else throw Error("The supplied element doesn't support dispatchEvent");else if("undefined"!=typeof a.fireEvent)c(a,b)&&(a.checked=!0!==a.checked),a.fireEvent("on"+b);else throw Error("Browser doesn't support triggering events");},c:function(b){return a.M(b)?b():b},Ha:function(b){return a.M(b)?b.t():b},ma:function(b,c,f){if(c){var d=/\S+/g,e=b.className.match(d)||[];a.a.n(c.match(d),function(b){a.a.V(e,b,f)});b.className=e.join(" ")}},Ma:function(b,c){var f=a.a.c(c);if(null===f||f===q)f="";var d=a.e.firstChild(b);
|
||||
!d||3!=d.nodeType||a.e.nextSibling(d)?a.e.S(b,[w.createTextNode(f)]):d.data=f;a.a.Jb(b)},pb:function(a,b){a.name=b;if(7>=h)try{a.mergeAttributes(w.createElement("<input name='"+a.name+"'/>"),!1)}catch(f){}},Jb:function(a){9<=h&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Hb:function(a){if(h){var b=a.style.width;a.style.width=0;a.style.width=b}},Zb:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var f=[],d=b;d<=c;d++)f.push(d);return f},Q:function(a){for(var b=[],c=0,d=a.length;c<
|
||||
d;c++)b.push(a[c]);return b},cc:6===h,dc:7===h,ja:h,ab:function(b,c){for(var f=a.a.Q(b.getElementsByTagName("input")).concat(a.a.Q(b.getElementsByTagName("textarea"))),d="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},e=[],g=f.length-1;0<=g;g--)d(f[g])&&e.push(f[g]);return e},Wb:function(b){return"string"==typeof b&&(b=a.a.la(b))?B&&B.parse?B.parse(b):(new Function("return "+b))():null},Na:function(b,c,f){if(!B||!B.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
|
||||
return B.stringify(a.a.c(b),c,f)},Xb:function(c,d,f){f=f||{};var e=f.params||{},g=f.includeFields||this.$a,h=c;if("object"==typeof c&&"form"===a.a.v(c))for(var h=c.action,n=g.length-1;0<=n;n--)for(var r=a.a.ab(c,g[n]),v=r.length-1;0<=v;v--)e[r[v].name]=r[v].value;d=a.a.c(d);var t=w.createElement("form");t.style.display="none";t.action=h;t.method="post";for(var E in d)c=w.createElement("input"),c.name=E,c.value=a.a.Na(a.a.c(d[E])),t.appendChild(c);b(e,function(a,b){var c=w.createElement("input");c.name=
|
||||
a;c.value=b;t.appendChild(c)});w.body.appendChild(t);f.submitter?f.submitter(t):t.submit();setTimeout(function(){t.parentNode.removeChild(t)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.n);a.b("utils.arrayFirst",a.a.Ua);a.b("utils.arrayFilter",a.a.ga);a.b("utils.arrayGetDistinctValues",a.a.Va);a.b("utils.arrayIndexOf",a.a.l);a.b("utils.arrayMap",a.a.ha);a.b("utils.arrayPushAll",a.a.X);a.b("utils.arrayRemoveItem",a.a.ia);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",
|
||||
a.a.$a);a.b("utils.getFormFields",a.a.ab);a.b("utils.peekObservable",a.a.Ha);a.b("utils.postJson",a.a.Xb);a.b("utils.parseJson",a.a.Wb);a.b("utils.registerEventHandler",a.a.r);a.b("utils.stringifyJson",a.a.Na);a.b("utils.range",a.a.Zb);a.b("utils.toggleDomNodeCssClass",a.a.ma);a.b("utils.triggerEvent",a.a.da);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.K);a.b("utils.addOrRemoveItem",a.a.V);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=function(a){var c=
|
||||
this,d=Array.prototype.slice.call(arguments);a=d.shift();return function(){return c.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});a.a.f=new function(){function a(b,h){var k=b[d];if(!k||"null"===k||!e[k]){if(!h)return q;k=b[d]="ko"+c++;e[k]={}}return e[k]}var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===q?q:e[d]},set:function(c,d,e){if(e!==q||a(c,!1)!==q)a(c,!0)[d]=e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},D:function(){return c++ +
|
||||
d}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.C=new function(){function b(b,c){var e=a.a.f.get(b,d);e===q&&c&&(e=[],a.a.f.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),m=0;m<e.length;m++)e[m](d);a.a.f.clear(d);"function"==typeof u&&"function"==typeof u.cleanData&&u.cleanData([d]);if(g[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.f.D(),e={1:!0,8:!0,9:!0},g={1:!0,9:!0};return{ea:function(a,c){if("function"!=
|
||||
typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},mb:function(c,e){var g=b(c,!1);g&&(a.a.ia(g,e),0==g.length&&a.a.f.set(c,d,q))},L:function(b){if(e[b.nodeType]&&(c(b),g[b.nodeType])){var d=[];a.a.X(d,b.getElementsByTagName("*"));for(var m=0,f=d.length;m<f;m++)c(d[m])}return b},removeNode:function(b){a.L(b);b.parentNode&&b.parentNode.removeChild(b)}}};a.L=a.a.C.L;a.removeNode=a.a.C.removeNode;a.b("cleanNode",a.L);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.C);
|
||||
a.b("utils.domNodeDisposal.addDisposeCallback",a.a.C.ea);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.C.mb);(function(){a.a.Fa=function(b){var c;if("undefined"!=typeof u)if(u.parseHTML)c=u.parseHTML(b)||[];else{if((c=u.clean([b]))&&c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&b.parentNode.removeChild(b)}}else{var d=a.a.la(b).toLowerCase();c=w.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,
|
||||
"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];b="ignored<div>"+d[1]+b+d[2]+"</div>";for("function"==typeof y.innerShiv?c.appendChild(y.innerShiv(b)):c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.Q(c.lastChild.childNodes)}return c};a.a.Ka=function(b,c){a.a.wa(b);c=a.a.c(c);if(null!==c&&c!==q)if("string"!=typeof c&&(c=c.toString()),"undefined"!=typeof u)u(b).html(c);else for(var d=a.a.Fa(c),e=0;e<d.length;e++)b.appendChild(d[e])}})();
|
||||
a.b("utils.parseHtmlFragment",a.a.Fa);a.b("utils.setHtml",a.a.Ka);a.u=function(){function b(c,e){if(c)if(8==c.nodeType){var g=a.u.jb(c.nodeValue);null!=g&&e.push({Fb:c,Tb:g})}else if(1==c.nodeType)for(var g=0,h=c.childNodes,k=h.length;g<k;g++)b(h[g],e)}var c={};return{Ca:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);
|
||||
c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},ub:function(a,b){var g=c[a];if(g===q)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return g.apply(null,b||[]),!0}finally{delete c[a]}},vb:function(c,e){var g=[];b(c,g);for(var h=0,k=g.length;h<k;h++){var m=g[h].Fb,f=[m];e&&a.a.X(f,e);a.u.ub(g[h].Tb,f);m.nodeValue="";m.parentNode&&m.parentNode.removeChild(m)}},jb:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.u);a.b("memoization.memoize",
|
||||
a.u.Ca);a.b("memoization.unmemoize",a.u.ub);a.b("memoization.parseMemoText",a.u.jb);a.b("memoization.unmemoizeDomNodeAndDescendants",a.u.vb);a.xa={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.h({read:b,write:function(a){clearTimeout(d);d=setTimeout(function(){b(a)},c)}})},notify:function(a,c){a.equalityComparer="always"==c?null:G}};var N={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.xa);a.sb=function(b,c,d){this.target=b;this.qa=c;this.Eb=d;a.s(this,"dispose",
|
||||
this.B)};a.sb.prototype.B=function(){this.Qb=!0;this.Eb()};a.ca=function(){this.F={};a.a.extend(this,a.ca.fn);a.s(this,"subscribe",this.T);a.s(this,"extend",this.extend);a.s(this,"getSubscriptionsCount",this.Lb)};var I="change";a.ca.fn={T:function(b,c,d){d=d||I;var e=new a.sb(this,c?b.bind(c):b,function(){a.a.ia(this.F[d],e)}.bind(this));this.F[d]||(this.F[d]=[]);this.F[d].push(e);return e},notifySubscribers:function(b,c){c=c||I;if(this.cb(c))try{a.i.Wa();for(var d=this.F[c].slice(0),e=0,g;g=d[e];++e)g&&
|
||||
!0!==g.Qb&&g.qa(b)}finally{a.i.end()}},cb:function(a){return this.F[a]&&this.F[a].length},Lb:function(){var b=0;a.a.K(this.F,function(a,d){b+=d.length});return b},extend:function(b){var c=this;b&&a.a.K(b,function(b,e){var g=a.xa[b];"function"==typeof g&&(c=g(c,e)||c)});return c}};a.fb=function(a){return null!=a&&"function"==typeof a.T&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.ca);a.b("isSubscribable",a.fb);a.i=function(){var b=[];return{Wa:function(a){b.push(a&&{qa:a,Za:[]})},
|
||||
end:function(){b.pop()},lb:function(c){if(!a.fb(c))throw Error("Only subscribable things can act as dependencies");if(0<b.length){var d=b[b.length-1];!d||0<=a.a.l(d.Za,c)||(d.Za.push(c),d.qa(c))}},p:function(a,d,e){try{return b.push(null),a.apply(d,e||[])}finally{b.pop()}}}}();a.q=function(b){function c(){if(0<arguments.length)return c.equalityComparer&&c.equalityComparer(d,arguments[0])||(c.O(),d=arguments[0],c.N()),this;a.i.lb(c);return d}var d=b;a.ca.call(c);c.t=function(){return d};c.N=function(){c.notifySubscribers(d)};
|
||||
c.O=function(){c.notifySubscribers(d,"beforeChange")};a.a.extend(c,a.q.fn);a.s(c,"peek",c.t);a.s(c,"valueHasMutated",c.N);a.s(c,"valueWillMutate",c.O);return c};a.q.fn={equalityComparer:G};var C=a.q.Yb="__ko_proto__";a.q.fn[C]=a.q;a.ya=function(b,c){return null===b||b===q||b[C]===q?!1:b[C]===c?!0:a.ya(b[C],c)};a.M=function(b){return a.ya(b,a.q)};a.gb=function(b){return"function"==typeof b&&b[C]===a.q||"function"==typeof b&&b[C]===a.h&&b.Nb?!0:!1};a.b("observable",a.q);a.b("isObservable",a.M);a.b("isWriteableObservable",
|
||||
a.gb);a.ba=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.q(b);a.a.extend(b,a.ba.fn);return b.extend({trackArrayChanges:!0})};a.ba.fn={remove:function(b){for(var c=this.t(),d=[],e="function"!=typeof b||a.M(b)?function(a){return a===b}:b,g=0;g<c.length;g++){var h=c[g];e(h)&&(0===d.length&&this.O(),d.push(h),c.splice(g,1),g--)}d.length&&this.N();return d},removeAll:function(b){if(b===
|
||||
q){var c=this.t(),d=c.slice(0);this.O();c.splice(0,c.length);this.N();return d}return b?this.remove(function(c){return 0<=a.a.l(b,c)}):[]},destroy:function(b){var c=this.t(),d="function"!=typeof b||a.M(b)?function(a){return a===b}:b;this.O();for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.N()},destroyAll:function(b){return b===q?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.l(b,c)}):[]},indexOf:function(b){var c=this();return a.a.l(c,b)},replace:function(a,
|
||||
c){var d=this.indexOf(a);0<=d&&(this.O(),this.t()[d]=c,this.N())}};a.a.n("pop push reverse shift sort splice unshift".split(" "),function(b){a.ba.fn[b]=function(){var a=this.t();this.O();this.Xa(a,b,arguments);a=a[b].apply(a,arguments);this.N();return a}});a.a.n(["slice"],function(b){a.ba.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.ba);var J="arrayChange";a.xa.trackArrayChanges=function(b){function c(){if(!d){d=!0;var c=b.notifySubscribers;b.notifySubscribers=
|
||||
function(a,b){b&&b!==I||++g;return c.apply(this,arguments)};var m=[].concat(b.t()||[]);e=null;b.T(function(c){c=[].concat(c||[]);if(b.cb(J)){var d;if(!e||1<g)e=a.a.ra(m,c,{sparse:!0});d=e;d.length&&b.notifySubscribers(d,J)}m=c;e=null;g=0})}}if(!b.Xa){var d=!1,e=null,g=0,h=b.T;b.T=b.subscribe=function(a,b,f){f===J&&c();return h.apply(this,arguments)};b.Xa=function(a,b,c){function p(a,b,c){h.push({status:a,value:b,index:c})}if(d&&!g){var h=[],l=a.length,n=c.length,r=0;switch(b){case "push":r=l;case "unshift":for(b=
|
||||
0;b<n;b++)p("added",c[b],r+b);break;case "pop":r=l-1;case "shift":l&&p("deleted",a[r],r);break;case "splice":b=Math.min(Math.max(0,0>c[0]?l+c[0]:c[0]),l);for(var l=1===n?l:Math.min(b+(c[1]||0),l),n=b+n-2,r=Math.max(l,n),v=2;b<r;++b,++v)b<l&&p("deleted",a[b],b),b<n&&p("added",c[v],b);break;default:return}e=h}}}};a.h=function(b,c,d){function e(){a.a.n(z,function(a){a.B()});z=[]}function g(){var a=k.throttleEvaluation;a&&0<=a?(clearTimeout(x),x=setTimeout(h,a)):h()}function h(){if(!s){if(E&&E()){if(!l){D();
|
||||
p=!0;return}}else l=!1;s=!0;try{var b=a.a.ha(z,function(a){return a.target});a.i.Wa(function(c){var d;0<=(d=a.a.l(b,c))?b[d]=q:z.push(c.T(g))});for(var d=c?n.call(c):n(),e=b.length-1;0<=e;e--)b[e]&&z.splice(e,1)[0].B();p=!0;k.equalityComparer&&k.equalityComparer(f,d)||(k.notifySubscribers(f,"beforeChange"),f=d,k.notifySubscribers(f))}finally{a.i.end(),s=!1}z.length||D()}}function k(){if(0<arguments.length){if("function"===typeof r)r.apply(c,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
|
||||
return this}p||h();a.i.lb(k);return f}function m(){return!p||0<z.length}var f,p=!1,s=!1,l=!1,n=b;n&&"object"==typeof n?(d=n,n=d.read):(d=d||{},n||(n=d.read));if("function"!=typeof n)throw Error("Pass a function that returns the value of the ko.computed");var r=d.write,v=d.disposeWhenNodeIsRemoved||d.I||null,t=d.disposeWhen||d.ua,E=t,D=e,z=[],x=null;c||(c=d.owner);k.t=function(){p||h();return f};k.Kb=function(){return z.length};k.Nb="function"===typeof d.write;k.B=function(){D()};k.aa=m;a.ca.call(k);
|
||||
a.a.extend(k,a.h.fn);a.s(k,"peek",k.t);a.s(k,"dispose",k.B);a.s(k,"isActive",k.aa);a.s(k,"getDependenciesCount",k.Kb);v&&(l=!0,v.nodeType&&(E=function(){return!a.a.va(v)||t&&t()}));!0!==d.deferEvaluation&&h();v&&m()&&(D=function(){a.a.C.mb(v,D);e()},a.a.C.ea(v,D));return k};a.Pb=function(b){return a.ya(b,a.h)};F=a.q.Yb;a.h[F]=a.q;a.h.fn={equalityComparer:G};a.h.fn[F]=a.h;a.b("dependentObservable",a.h);a.b("computed",a.h);a.b("isComputed",a.Pb);(function(){function b(a,g,h){h=h||new d;a=g(a);if("object"!=
|
||||
typeof a||null===a||a===q||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var k=a instanceof Array?[]:{};h.save(a,k);c(a,function(c){var d=g(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":k[c]=d;break;case "object":case "undefined":var p=h.get(d);k[c]=p!==q?p:b(d,g,h)}});return k}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=
|
||||
[];this.Qa=[]}a.tb=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.M(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.tb(b);return a.a.Na(b,c,d)};d.prototype={save:function(b,c){var d=a.a.l(this.keys,b);0<=d?this.Qa[d]=c:(this.keys.push(b),this.Qa.push(c))},get:function(b){b=a.a.l(this.keys,b);return 0<=b?this.Qa[b]:q}}})();a.b("toJS",a.tb);a.b("toJSON",a.toJSON);(function(){a.k={o:function(b){switch(a.a.v(b)){case "option":return!0===
|
||||
b.__ko__hasDomDataOptionValue__?a.a.f.get(b,a.d.options.Ea):7>=a.a.ja?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.k.o(b.options[b.selectedIndex]):q;default:return b.value}},na:function(b,c){switch(a.a.v(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.d.options.Ea,q);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.d.options.Ea,c),b.__ko__hasDomDataOptionValue__=
|
||||
!0,b.value="number"===typeof c?c:""}break;case "select":""===c&&(c=q);if(null===c||c===q)b.selectedIndex=-1;for(var d=b.options.length-1;0<=d;d--)if(a.k.o(b.options[d])==c){b.selectedIndex=d;break}1<b.size||-1!==b.selectedIndex||(b.selectedIndex=0);break;default:if(null===c||c===q)c="";b.value=c}}}})();a.b("selectExtensions",a.k);a.b("selectExtensions.readValue",a.k.o);a.b("selectExtensions.writeValue",a.k.na);a.g=function(){function b(b){b=a.a.la(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=
|
||||
[],d=b.match(e),k,l,n=0;if(d){d.push(",");for(var r=0,v;v=d[r];++r){var t=v.charCodeAt(0);if(44===t){if(0>=n){k&&c.push(l?{key:k,value:l.join("")}:{unknown:k});k=l=n=0;continue}}else if(58===t){if(!l)continue}else if(47===t&&r&&1<v.length)(t=d[r-1].match(g))&&!h[t[0]]&&(b=b.substr(b.indexOf(v)+1),d=b.match(e),d.push(","),r=-1,v="/");else if(40===t||123===t||91===t)++n;else if(41===t||125===t||93===t)--n;else if(!k&&!l){k=34===t||39===t?v.slice(1,-1):v;continue}l?l.push(v):l=[v]}}return c}var c=["true",
|
||||
"false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),g=/[\])"'A-Za-z0-9_$]+$/,h={"in":1,"return":1,"typeof":1},k={};return{Y:[],U:k,Ga:b,ka:function(e,f){function g(b,f){var e,r=a.getBindingHandler(b);if(r&&r.preprocess?f=r.preprocess(f,b,g):1){if(r=k[b])e=f,0<=a.a.l(c,e)?e=!1:(r=e.match(d),e=null===r?!1:r[1]?"Object("+r[1]+")"+
|
||||
r[2]:e),r=e;r&&l.push("'"+b+"':function(_z){"+e+"=_z}");n&&(f="function(){return "+f+" }");h.push("'"+b+"':"+f)}}f=f||{};var h=[],l=[],n=f.valueAccessors,r="string"===typeof e?b(e):e;a.a.n(r,function(a){g(a.key||a.unknown,a.value)});l.length&&g("_ko_property_writers","{"+l.join(",")+"}");return h.join(",")},Sb:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},oa:function(b,c,d,e,k){if(b&&a.M(b))!a.gb(b)||k&&b.t()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();
|
||||
a.b("expressionRewriting",a.g);a.b("expressionRewriting.bindingRewriteValidators",a.g.Y);a.b("expressionRewriting.parseObjectLiteral",a.g.Ga);a.b("expressionRewriting.preProcessBindings",a.g.ka);a.b("expressionRewriting._twoWayBindings",a.g.U);a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.g.ka);(function(){function b(a){return 8==a.nodeType&&h.test(g?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&k.test(g?a.text:a.nodeValue)}function d(a,
|
||||
d){for(var e=a,k=1,n=[];e=e.nextSibling;){if(c(e)&&(k--,0===k))return n;n.push(e);b(e)&&k++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var g=w&&"\x3c!--test--\x3e"===w.createComment("test").text,h=g?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,k=g?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,m={ul:!0,ol:!0};a.e={P:{},childNodes:function(a){return b(a)?
|
||||
d(a):a.childNodes},Z:function(c){if(b(c)){c=a.e.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.wa(c)},S:function(c,d){if(b(c)){a.e.Z(c);for(var e=c.nextSibling,k=0,n=d.length;k<n;k++)e.parentNode.insertBefore(d[k],e)}else a.a.S(c,d)},kb:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},eb:function(c,d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):
|
||||
c.appendChild(d):a.e.kb(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Mb:b,bc:function(a){return(a=(g?a.text:a.nodeValue).match(h))?a[1]:null},ib:function(d){if(m[a.a.v(d)]){var k=d.firstChild;if(k){do if(1===k.nodeType){var g;g=k.firstChild;var h=null;if(g){do if(h)h.push(g);else if(b(g)){var n=e(g,!0);n?g=n:h=[g]}else c(g)&&(h=[g]);while(g=
|
||||
g.nextSibling)}if(g=h)for(h=k.nextSibling,n=0;n<g.length;n++)h?d.insertBefore(g[n],h):d.appendChild(g[n])}while(k=k.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.P);a.b("virtualElements.emptyNode",a.e.Z);a.b("virtualElements.insertAfter",a.e.eb);a.b("virtualElements.prepend",a.e.kb);a.b("virtualElements.setDomNodeChildren",a.e.S);(function(){a.H=function(){this.zb={}};a.a.extend(a.H.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=
|
||||
b.getAttribute("data-bind");case 8:return a.e.Mb(b);default:return!1}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a):null},getBindingAccessors:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a,{valueAccessors:!0}):null},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.e.bc(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var g=this.zb,
|
||||
h=b+(e&&e.valueAccessors||""),k;if(!(k=g[h])){var m,f="with($context){with($data||{}){return{"+a.g.ka(b,e)+"}}}";m=new Function("$context","$element",f);k=g[h]=m}return k(c,d)}catch(p){throw p.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+p.message,p;}}});a.H.instance=new a.H})();a.b("bindingProvider",a.H);(function(){function b(a){return function(){return a}}function c(a){return a()}function d(b){return a.a.Da(a.i.p(b),function(a,c){return function(){return b()[c]}})}function e(a,
|
||||
b){return d(this.getBindings.bind(this,a,b))}function g(b,c,d){var f,e=a.e.firstChild(c),k=a.H.instance,g=k.preprocessNode;if(g){for(;f=e;)e=a.e.nextSibling(f),g.call(k,f);e=a.e.firstChild(c)}for(;f=e;)e=a.e.nextSibling(f),h(b,f,d)}function h(b,c,d){var f=!0,e=1===c.nodeType;e&&a.e.ib(c);if(e&&d||a.H.instance.nodeHasBindings(c))f=m(c,null,b,d).shouldBindDescendants;f&&!p[a.a.v(c)]&&g(b,c,!e)}function k(b){var c=[],d={},f=[];a.a.K(b,function D(e){if(!d[e]){var k=a.getBindingHandler(e);k&&(k.after&&
|
||||
(f.push(e),a.a.n(k.after,function(c){if(b[c]){if(-1!==a.a.l(f,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+f.join(", "));D(c)}}),f.pop()),c.push({key:e,bb:k}));d[e]=!0}});return c}function m(b,d,f,g){var h=a.a.f.get(b,s);if(!d){if(h)throw Error("You cannot apply bindings multiple times to the same element.");a.a.f.set(b,s,!0)}!h&&g&&a.rb(b,f);var m;if(d&&"function"!==typeof d)m=d;else{var p=a.H.instance,l=p.getBindingAccessors||e;if(d||f.A){var A=
|
||||
a.h(function(){(m=d?d(f,b):l.call(p,b,f))&&f.A&&f.A();return m},null,{I:b});m&&A.aa()||(A=null)}else m=a.i.p(l,p,[b,f])}var u;if(m){var w=A?function(a){return function(){return c(A()[a])}}:function(a){return m[a]},y=function(){return a.a.Da(A?A():m,c)};y.get=function(a){return m[a]&&c(w(a))};y.has=function(a){return a in m};g=k(m);a.a.n(g,function(c){var d=c.bb.init,e=c.bb.update,k=c.key;if(8===b.nodeType&&!a.e.P[k])throw Error("The binding '"+k+"' cannot be used with virtual elements");try{"function"==
|
||||
typeof d&&a.i.p(function(){var a=d(b,w(k),y,f.$data,f);if(a&&a.controlsDescendantBindings){if(u!==q)throw Error("Multiple bindings ("+u+" and "+k+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");u=k}}),"function"==typeof e&&a.h(function(){e(b,w(k),y,f.$data,f)},null,{I:b})}catch(g){throw g.message='Unable to process binding "'+k+": "+m[k]+'"\nMessage: '+g.message,g;}})}return{shouldBindDescendants:u===q}}function f(b){return b&&
|
||||
b instanceof a.G?b:new a.G(b)}a.d={};var p={script:!0};a.getBindingHandler=function(b){return a.d[b]};a.G=function(b,c,d,f){var e=this,k="function"==typeof b,g,h=a.h(function(){var g=k?b():b;c?(c.A&&c.A(),a.a.extend(e,c),h&&(e.A=h)):(e.$parents=[],e.$root=g,e.ko=a);e.$rawData=b;e.$data=g;d&&(e[d]=g);f&&f(e,c,g);return e.$data},null,{ua:function(){return g&&!a.a.Ra(g)},I:!0});h.aa()&&(e.A=h,h.equalityComparer=null,g=[],h.wb=function(b){g.push(b);a.a.C.ea(b,function(b){a.a.ia(g,b);g.length||(h.B(),
|
||||
e.A=h=q)})})};a.G.prototype.createChildContext=function(b,c,d){return new a.G(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)})};a.G.prototype.extend=function(b){return new a.G(this.$rawData,this,null,function(c){a.a.extend(c,"function"==typeof b?b():b)})};var s=a.a.f.D(),l=a.a.f.D();a.rb=function(b,c){if(2==arguments.length)a.a.f.set(b,l,c),c.A&&c.A.wb(b);else return a.a.f.get(b,l)};a.pa=function(b,c,d){1===b.nodeType&&
|
||||
a.e.ib(b);return m(b,c,f(d),!0)};a.xb=function(c,e,k){k=f(k);return a.pa(c,"function"===typeof e?d(e.bind(null,k,c)):a.a.Da(e,b),k)};a.Ta=function(a,b){1!==b.nodeType&&8!==b.nodeType||g(f(a),b,!0)};a.Sa=function(a,b){if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||y.document.body;h(f(a),b,!0)};a.ta=function(b){switch(b.nodeType){case 1:case 8:var c=a.rb(b);if(c)return c;if(b.parentNode)return a.ta(b.parentNode)}return q};
|
||||
a.Cb=function(b){return(b=a.ta(b))?b.$data:q};a.b("bindingHandlers",a.d);a.b("applyBindings",a.Sa);a.b("applyBindingsToDescendants",a.Ta);a.b("applyBindingAccessorsToNode",a.pa);a.b("applyBindingsToNode",a.xb);a.b("contextFor",a.ta);a.b("dataFor",a.Cb)})();var M={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.K(d,function(c,d){d=a.a.c(d);var h=!1===d||null===d||d===q;h&&b.removeAttribute(c);8>=a.a.ja&&c in M?(c=M[c],h?b.removeAttribute(c):b[c]=d):h||b.setAttribute(c,
|
||||
d.toString());"name"===c&&a.a.pb(b,h?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,c,d){function e(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):b.value}function g(){var k=b.checked,g=s?e():k;if(l&&(!m||k)){var h=a.i.p(c);f?p!==g?(k&&(a.a.V(h,g,!0),a.a.V(h,p,!1)),p=g):a.a.V(h,g,k):a.g.oa(h,d,"checked",g,!0)}}function h(){var d=a.a.c(c());b.checked=f?0<=a.a.l(d,e()):k?d:e()===d}var k="checkbox"==b.type,m="radio"==b.type;if(k||m){var f=k&&a.a.c(c())instanceof
|
||||
Array,p=f?e():q,s=m||f,l=!1;m&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.h(g,null,{I:b});a.a.r(b,"click",g);a.h(h,null,{I:b});l=!0}}};a.g.U.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());"object"==typeof d?a.a.K(d,function(c,d){d=a.a.c(d);a.a.ma(b,c,d)}):(d=String(d||""),a.a.ma(b,b.__ko__cssValue,!1),b.__ko__cssValue=d,a.a.ma(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):
|
||||
d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,g){var h=c()||{};a.a.K(h,function(k){"string"==typeof k&&a.a.r(b,k,function(b){var f,h=c()[k];if(h){try{var s=a.a.Q(arguments);e=g.$data;s.unshift(e);f=h.apply(e,s)}finally{!0!==f&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}!1===d.get(k+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={hb:function(b){return function(){var c=
|
||||
b(),d=a.a.Ha(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.J.Aa};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.J.Aa}}},init:function(b,c){return a.d.template.init(b,a.d.foreach.hb(c))},update:function(b,c,d,e,g){return a.d.template.update(b,a.d.foreach.hb(c),d,e,g)}};a.g.Y.foreach=!1;a.e.P.foreach=!0;a.d.hasfocus=
|
||||
{init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var g=b.ownerDocument;if("activeElement"in g){var f;try{f=g.activeElement}catch(h){f=g.body}e=f===b}g=c();a.g.oa(g,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var g=e.bind(null,!0),h=e.bind(null,!1);a.a.r(b,"focus",g);a.a.r(b,"focusin",g);a.a.r(b,"blur",h);a.a.r(b,"focusout",h)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),a.i.p(a.a.da,
|
||||
null,[b,d?"focusin":"focusout"]))}};a.g.U.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.g.U.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Ka(b,c())}};var L=a.a.f.D();H("if");H("ifnot",!1,!0);H("with",!0,!1,function(a,c){return a.createChildContext(c)});a.d.options={init:function(b){if("select"!==a.a.v(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,
|
||||
c,d){function e(){return a.a.ga(b.options,function(a){return a.selected})}function g(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function h(c,d){if(p.length){var f=0<=a.a.l(p,a.k.o(d[0]));a.a.qb(d[0],f);l&&!f&&a.i.p(a.a.da,null,[b,"change"])}}var k=0!=b.length&&b.multiple?b.scrollTop:null;c=a.a.c(c());var m=d.get("optionsIncludeDestroyed"),f={},p;p=b.multiple?a.a.ha(e(),a.k.o):0<=b.selectedIndex?[a.k.o(b.options[b.selectedIndex])]:[];if(c){"undefined"==typeof c.length&&(c=[c]);
|
||||
var s=a.a.ga(c,function(b){return m||b===q||null===b||!a.a.c(b._destroy)});d.has("optionsCaption")&&(c=a.a.c(d.get("optionsCaption")),null!==c&&c!==q&&s.unshift(f))}else c=[];var l=!1;c=h;d.has("optionsAfterRender")&&(c=function(b,c){h(0,c);a.i.p(d.get("optionsAfterRender"),null,[c[0],b!==f?b:q])});a.a.Ja(b,s,function(b,c,e){e.length&&(p=e[0].selected?[a.k.o(e[0])]:[],l=!0);c=w.createElement("option");b===f?(a.a.Ma(c,d.get("optionsCaption")),a.k.na(c,q)):(e=g(b,d.get("optionsValue"),b),a.k.na(c,a.a.c(e)),
|
||||
b=g(b,d.get("optionsText"),e),a.a.Ma(c,b));return[c]},null,c);(b.multiple?p.length&&e().length<p.length:p.length&&0<=b.selectedIndex?a.k.o(b.options[b.selectedIndex])!==p[0]:p.length||0<=b.selectedIndex)&&a.i.p(a.a.da,null,[b,"change"]);a.a.Hb(b);k&&20<Math.abs(k-b.scrollTop)&&(b.scrollTop=k)}};a.d.options.Ea=a.a.f.D();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.r(b,"change",function(){var e=c(),g=[];a.a.n(b.getElementsByTagName("option"),function(b){b.selected&&g.push(a.k.o(b))});
|
||||
a.g.oa(e,d,"selectedOptions",g)})},update:function(b,c){if("select"!=a.a.v(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c());d&&"number"==typeof d.length&&a.a.n(b.getElementsByTagName("option"),function(b){var c=0<=a.a.l(d,a.k.o(b));a.a.qb(b,c)})}};a.g.U.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.K(d,function(c,d){d=a.a.c(d);b.style[c]=d||""})}};a.d.submit={init:function(b,c,d,e,g){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");
|
||||
a.a.r(b,"submit",function(a){var d,e=c();try{d=e.call(g.$data,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Ma(b,c())}};a.e.P.text=!0;a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.Bb;a.a.pb(b,d)}}};a.d.uniqueName.Bb=0;a.d.value={after:["options","foreach"],init:function(b,c,d){function e(){k=!1;var e=c(),f=a.k.o(b);a.g.oa(e,d,"value",f)}var g=
|
||||
["change"],h=d.get("valueUpdate"),k=!1;h&&("string"==typeof h&&(h=[h]),a.a.X(g,h),g=a.a.Va(g));!a.a.ja||"input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.l(g,"propertychange")||(a.a.r(b,"propertychange",function(){k=!0}),a.a.r(b,"blur",function(){k&&e()}));a.a.n(g,function(c){var d=e;a.a.ac(c,"after")&&(d=function(){setTimeout(e,0)},c=c.substring(5));a.a.r(b,c,d)})},update:function(b,c){var d="select"===a.a.v(b),e=a.a.c(c()),g=a.k.o(b);
|
||||
e!==g&&(g=function(){a.k.na(b,e)},g(),d&&(e!==a.k.o(b)?a.i.p(a.a.da,null,[b,"change"]):setTimeout(g,0)))}};a.g.U.value=!0;a.d.visible={update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,g,h){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,g,h)}}})("click");a.w=function(){};a.w.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");
|
||||
};a.w.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.w.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||w;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.m.j(d)}if(1==b.nodeType||8==b.nodeType)return new a.m.W(b);throw Error("Unknown template type: "+b);};a.w.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,
|
||||
d)};a.w.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.w.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.w);a.Oa=function(){function b(b,c,d,k){b=a.g.Ga(b);for(var m=a.g.Y,f=0;f<b.length;f++){var p=b[f].key;if(m.hasOwnProperty(p)){var s=m[p];if("function"===typeof s){if(p=s(b[f].value))throw Error(p);}else if(!s)throw Error("This template engine does not support the '"+
|
||||
p+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.g.ka(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return k.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Ib:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Oa.Ub(b,c)},
|
||||
d)},Ub:function(a,g){return a.replace(c,function(a,c,d,f,e){return b(e,c,d,g)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",g)})},yb:function(b,c){return a.u.Ca(function(d,k){var m=d.nextSibling;m&&m.nodeName.toLowerCase()===c&&a.pa(m,b,k)})}}}();a.b("__tr_ambtns",a.Oa.yb);(function(){a.m={};a.m.j=function(a){this.j=a};a.m.j.prototype.text=function(){var b=a.a.v(this.j),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.j[b];var c=arguments[0];
|
||||
"innerHTML"===b?a.a.Ka(this.j,c):this.j[b]=c};var b=a.a.f.D()+"_";a.m.j.prototype.data=function(c){if(1===arguments.length)return a.a.f.get(this.j,b+c);a.a.f.set(this.j,b+c,arguments[1])};var c=a.a.f.D();a.m.W=function(a){this.j=a};a.m.W.prototype=new a.m.j;a.m.W.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.j,c)||{};b.Pa===q&&b.sa&&(b.Pa=b.sa.innerHTML);return b.Pa}a.a.f.set(this.j,c,{Pa:arguments[0]})};a.m.j.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.j,
|
||||
c)||{}).sa;a.a.f.set(this.j,c,{sa:arguments[0]})};a.b("templateSources",a.m);a.b("templateSources.domElement",a.m.j);a.b("templateSources.anonymousTemplate",a.m.W)})();(function(){function b(b,c,d){var e;for(c=a.e.nextSibling(c);b&&(e=b)!==c;)b=a.e.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var f=c[0],e=c[c.length-1],g=f.parentNode,h=a.H.instance,n=h.preprocessNode;if(n){b(f,e,function(a,b){var c=a.previousSibling,d=n.call(h,a);d&&(a===f&&(f=d[0]||b),a===e&&(e=d[d.length-1]||c))});c.length=
|
||||
0;if(!f)return;f===e?c.push(f):(c.push(f,e),a.a.$(c,g))}b(f,e,function(b){1!==b.nodeType&&8!==b.nodeType||a.Sa(d,b)});b(f,e,function(b){1!==b.nodeType&&8!==b.nodeType||a.u.vb(b,[d])});a.a.$(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,f,h,s){s=s||{};var l=b&&d(b),l=l&&l.ownerDocument,n=s.templateEngine||g;a.Oa.Ib(f,n,l);f=n.renderTemplate(f,h,s,l);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");
|
||||
l=!1;switch(e){case "replaceChildren":a.e.S(b,f);l=!0;break;case "replaceNode":a.a.nb(b,f);l=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}l&&(c(f,h),s.afterRender&&a.i.p(s.afterRender,null,[f,h.$data]));return f}var g;a.La=function(b){if(b!=q&&!(b instanceof a.w))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.Ia=function(b,c,f,h,s){f=f||{};if((f.templateEngine||g)==q)throw Error("Set a template engine before calling renderTemplate");
|
||||
s=s||"replaceChildren";if(h){var l=d(h);return a.h(function(){var g=c&&c instanceof a.G?c:new a.G(a.a.c(c)),r="function"==typeof b?b(g.$data,g):b,g=e(h,s,r,g,f);"replaceNode"==s&&(h=g,l=d(h))},null,{ua:function(){return!l||!a.a.va(l)},I:l&&"replaceNode"==s?l.parentNode:l})}return a.u.Ca(function(d){a.Ia(b,c,f,d,"replaceNode")})};a.$b=function(b,d,f,g,h){function l(a,b){c(b,r);f.afterRender&&f.afterRender(b,a)}function n(a,c){r=h.createChildContext(a,f.as,function(a){a.$index=c});var d="function"==
|
||||
typeof b?b(a,r):b;return e(null,"ignoreTargetNode",d,r,f)}var r;return a.h(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.ga(b,function(b){return f.includeDestroyed||b===q||null===b||!a.a.c(b._destroy)});a.i.p(a.a.Ja,null,[g,b,n,f,l])},null,{I:g})};var h=a.a.f.D();a.d.template={init:function(b,c){var d=a.a.c(c());"string"==typeof d||d.name?a.e.Z(b):(d=a.e.childNodes(b),d=a.a.Vb(d),(new a.m.W(b)).nodes(d));return{controlsDescendantBindings:!0}},update:function(b,c,d,e,g){c=
|
||||
a.a.c(c());d={};e=!0;var l,n=null;"string"!=typeof c&&(d=c,c=a.a.c(d.name),"if"in d&&(e=a.a.c(d["if"])),e&&"ifnot"in d&&(e=!a.a.c(d.ifnot)),l=a.a.c(d.data));"foreach"in d?n=a.$b(c||b,e&&d.foreach||[],d,b,g):e?(g="data"in d?g.createChildContext(l,d.as):g,n=a.Ia(c||b,g,d,b)):a.e.Z(b);g=n;(l=a.a.f.get(b,h))&&"function"==typeof l.B&&l.B();a.a.f.set(b,h,g&&g.aa()?g:q)}};a.g.Y.template=function(b){b=a.g.Ga(b);return 1==b.length&&b[0].unknown||a.g.Sb(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};
|
||||
a.e.P.template=!0})();a.b("setTemplateEngine",a.La);a.b("renderTemplate",a.Ia);a.a.ra=function(){function a(b,d,e,g,h){var k=Math.min,m=Math.max,f=[],p,q=b.length,l,n=d.length,r=n-q||1,v=q+n+1,t,u,w;for(p=0;p<=q;p++)for(u=t,f.push(t=[]),w=k(n,p+r),l=m(0,p-1);l<=w;l++)t[l]=l?p?b[p-1]===d[l-1]?u[l-1]:k(u[l]||v,t[l-1]||v)+1:l+1:p+1;k=[];m=[];r=[];p=q;for(l=n;p||l;)n=f[p][l]-1,l&&n===f[p][l-1]?m.push(k[k.length]={status:e,value:d[--l],index:l}):p&&n===f[p-1][l]?r.push(k[k.length]={status:g,value:b[--p],
|
||||
index:p}):(--l,--p,h.sparse||k.push({status:"retained",value:d[l]}));if(m.length&&r.length){b=10*q;var z;for(d=e=0;(h.dontLimitMoves||d<b)&&(z=m[e]);e++){for(g=0;f=r[g];g++)if(z.value===f.value){z.moved=f.index;f.moved=z.index;r.splice(g,1);d=g=0;break}d+=g}}return k.reverse()}return function(c,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};c=c||[];d=d||[];return c.length<=d.length?a(c,d,"added","deleted",e):a(d,c,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.ra);(function(){function b(b,
|
||||
c,g,h,k){var m=[],f=a.h(function(){var f=c(g,k,a.a.$(m,b))||[];0<m.length&&(a.a.nb(m,f),h&&a.i.p(h,null,[g,f,k]));m.splice(0,m.length);a.a.X(m,f)},null,{I:b,ua:function(){return!a.a.Ra(m)}});return{R:m,h:f.aa()?f:q}}var c=a.a.f.D();a.a.Ja=function(d,e,g,h,k){function m(b,c){x=s[c];t!==c&&(z[b]=x);x.za(t++);a.a.$(x.R,d);r.push(x);w.push(x)}function f(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.n(c[d].R,function(a){b(a,d,c[d].fa)})}e=e||[];h=h||{};var p=a.a.f.get(d,c)===q,s=a.a.f.get(d,c)||[],
|
||||
l=a.a.ha(s,function(a){return a.fa}),n=a.a.ra(l,e,h.dontLimitMoves),r=[],v=0,t=0,u=[],w=[];e=[];for(var z=[],l=[],x,A=0,y,B;y=n[A];A++)switch(B=y.moved,y.status){case "deleted":B===q&&(x=s[v],x.h&&x.h.B(),u.push.apply(u,a.a.$(x.R,d)),h.beforeRemove&&(e[A]=x,w.push(x)));v++;break;case "retained":m(A,v++);break;case "added":B!==q?m(A,B):(x={fa:y.value,za:a.q(t++)},r.push(x),w.push(x),p||(l[A]=x))}f(h.beforeMove,z);a.a.n(u,h.beforeRemove?a.L:a.removeNode);for(var A=0,p=a.e.firstChild(d),C;x=w[A];A++){x.R||
|
||||
a.a.extend(x,b(d,g,x.fa,k,x.za));for(v=0;n=x.R[v];p=n.nextSibling,C=n,v++)n!==p&&a.e.eb(d,n,C);!x.Ob&&k&&(k(x.fa,x.R,x.za),x.Ob=!0)}f(h.beforeRemove,e);f(h.afterMove,z);f(h.afterAdd,l);a.a.f.set(d,c,r)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Ja);a.J=function(){this.allowTemplateRewriting=!1};a.J.prototype=new a.w;a.J.prototype.renderTemplateSource=function(b){var c=(9>a.a.ja?0:b.nodes)?b.nodes():null;if(c)return a.a.Q(c.cloneNode(!0).childNodes);b=b.text();return a.a.Fa(b)};a.J.Aa=
|
||||
new a.J;a.La(a.J.Aa);a.b("nativeTemplateEngine",a.J);(function(){a.Ba=function(){var a=this.Rb=function(){if("undefined"==typeof u||!u.tmpl)return 0;try{if(0<=u.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,g){g=g||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=u.template(null,"{{ko_with $item.koBindingContext}}"+h+
|
||||
"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=u.extend({koBindingContext:e},g.templateOptions);e=u.tmpl(h,b,e);e.appendTo(w.createElement("div"));u.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){w.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(u.tmpl.tag.ko_code={open:"__.push($1 || '');"},u.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.Ba.prototype=
|
||||
new a.w;var b=new a.Ba;0<b.Rb&&a.La(b);a.b("jqueryTmplTemplateEngine",a.Ba)})()})})();})();
|
|
@ -0,0 +1,250 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>freeboard</title>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="viewport"
|
||||
content="width = device-width, initial-scale = 1, user-scalable = no" />
|
||||
<link href="css/jquery.gridster.min.css" rel="stylesheet" />
|
||||
<link href="css/styles.css" rel="stylesheet" />
|
||||
<script src="js/head.js"></script>
|
||||
<script type="text/javascript">
|
||||
head
|
||||
.js(
|
||||
"js/knockout.js",
|
||||
"js/jquery.js",
|
||||
"js/jquery-ui.js",
|
||||
"js/underscore.js",
|
||||
"js/jquery.gridster.js",
|
||||
"js/jquery.sparkline.min.js",
|
||||
"js/jquery.caret.js",
|
||||
"js/raphael.2.1.0.min.js",
|
||||
"js/justgage.1.0.1.js",
|
||||
"js/freeboard/freeboard.js",
|
||||
"js/freeboard/plugins/freeboard.datasources.js",
|
||||
"js/freeboard/plugins/freeboard.widgets.js",
|
||||
"datasources/plugin_node.js",
|
||||
// *** Load more plugins here ***
|
||||
function() {
|
||||
$(function() { //DOM Ready
|
||||
freeboard.initialize(true);
|
||||
freeboard
|
||||
.loadDashboard({
|
||||
"allow_edit": true,
|
||||
"plugins": [],
|
||||
"panes": [
|
||||
{
|
||||
"title": "Houses",
|
||||
"width": 1,
|
||||
"row": {
|
||||
"2": 1,
|
||||
"3": 1
|
||||
},
|
||||
"col": {
|
||||
"2": 1,
|
||||
"3": 1
|
||||
},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Stark - Jon",
|
||||
"size": "regular",
|
||||
"value": "datasources[\"Jon\"].value",
|
||||
"sparkline": true,
|
||||
"animate": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Lannister - Tyrion",
|
||||
"size": "regular",
|
||||
"value": "datasources[\"Tyrion\"].value",
|
||||
"sparkline": true,
|
||||
"animate": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Timezones",
|
||||
"width": 1,
|
||||
"row": {
|
||||
"3": 1
|
||||
},
|
||||
"col": {
|
||||
"3": 2
|
||||
},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Stark - Jon",
|
||||
"size": "regular",
|
||||
"value": "new Date(datasources[\"Jon\"].time_stamp).toLocaleTimeString();",
|
||||
"animate": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Lannister - Tyrion",
|
||||
"size": "regular",
|
||||
"value": "new Date(datasources[\"Tyrion\"].time_stamp).toLocaleTimeString();",
|
||||
"animate": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"datasources": [
|
||||
{
|
||||
"name": "Jon",
|
||||
"type": "node_js",
|
||||
"settings": {
|
||||
"url": "http://localhost:8989/shows",
|
||||
"eventName": "house.stark.jon",
|
||||
"rooms": [
|
||||
{
|
||||
"roomName": "got",
|
||||
"roomEvent": "subscribe"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Tyrion",
|
||||
"type": "node_js",
|
||||
"settings": {
|
||||
"url": "http://localhost:8989/shows",
|
||||
"eventName": "house.lannister.tyrion",
|
||||
"rooms": [
|
||||
{
|
||||
"roomName": "got",
|
||||
"roomEvent": "subscribe"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="board-content">
|
||||
<img id="dash-logo"
|
||||
data-bind="attr:{src: header_image}, visible:header_image()">
|
||||
<div class="gridster">
|
||||
<ul data-bind="grid: true">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<header id="main-header" data-bind="if:allow_edit">
|
||||
<div id="admin-bar">
|
||||
<div id="admin-menu">
|
||||
<div id="board-tools">
|
||||
<h1 id="board-logo" class="title bordered">freeboard</h1>
|
||||
<div id="board-actions">
|
||||
<ul class="board-toolbar vertical">
|
||||
<li data-bind="click: loadDashboardFromLocalFile"><i
|
||||
id="full-screen-icon" class="icon-folder-open icon-white"></i><label
|
||||
id="full-screen">Load Freeboard</label></li>
|
||||
<li data-bind="click: saveDashboard"><i
|
||||
class="icon-download-alt icon-white"></i><label>Save
|
||||
Freeboard</label></li>
|
||||
<li id="add-pane" data-bind="click: createPane"><i
|
||||
class="icon-plus icon-white"></i><label>Add Pane</label></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="datasources">
|
||||
<h2 class="title">DATASOURCES</h2>
|
||||
|
||||
<div class="datasource-list-container">
|
||||
<table class="table table-condensed sub-table"
|
||||
id="datasources-list" data-bind="if: datasources().length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Last Updated</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-bind="foreach: datasources">
|
||||
<tr>
|
||||
<td><span class="text-button datasource-name"
|
||||
data-bind="text: name, pluginEditor: {operation: 'edit', type: 'datasource'}"></span>
|
||||
</td>
|
||||
<td data-bind="text: last_updated"></td>
|
||||
<td>
|
||||
<ul class="board-toolbar">
|
||||
<li data-bind="click: updateNow"><i
|
||||
class="icon-refresh icon-white"></i></li>
|
||||
<li
|
||||
data-bind="pluginEditor: {operation: 'delete', type: 'datasource'}">
|
||||
<i class="icon-trash icon-white"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<span class="text-button table-operation"
|
||||
data-bind="pluginEditor: {operation: 'add', type: 'datasource'}">ADD</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="toggle-header" data-bind="click: toggleEditing">
|
||||
<i id="toggle-header-icon" class="icon-wrench icon-white"></i>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div style="display: hidden">
|
||||
<ul data-bind="template: { name: 'pane-template', foreach: panes}">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="pane-template">
|
||||
<li data-bind="pane: true">
|
||||
<header>
|
||||
<h1 data-bind="text: title"></h1>
|
||||
<ul class="board-toolbar pane-tools">
|
||||
<li data-bind="pluginEditor: {operation: 'add', type: 'widget'}">
|
||||
<i class="icon-plus icon-white"></i>
|
||||
</li>
|
||||
<li data-bind="pluginEditor: {operation: 'edit', type: 'pane'}">
|
||||
<i class="icon-wrench icon-white"></i>
|
||||
</li>
|
||||
<li data-bind="pluginEditor: {operation: 'delete', type: 'pane'}">
|
||||
<i class="icon-trash icon-white"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<section data-bind="foreach: widgets">
|
||||
<div class="sub-section" data-bind="css: 'sub-section-height-' + height()">
|
||||
<div class="widget" data-bind="widget: true, css:{fillsize:fillSize}"></div>
|
||||
<div class="sub-section-tools">
|
||||
<ul class="board-toolbar">
|
||||
<!-- ko if:$parent.widgetCanMoveUp($data) -->
|
||||
<li data-bind="click:$parent.moveWidgetUp"><i class="icon-chevron-up icon-white"></i></li>
|
||||
<!-- /ko -->
|
||||
<!-- ko if:$parent.widgetCanMoveDown($data) -->
|
||||
<li data-bind="click:$parent.moveWidgetDown"><i class="icon-chevron-down icon-white"></i></li>
|
||||
<!-- /ko -->
|
||||
<li data-bind="pluginEditor: {operation: 'edit', type: 'widget'}"><i class="icon-wrench icon-white"></i></li>
|
||||
<li data-bind="pluginEditor: {operation: 'delete', type: 'widget'}"><i class="icon-trash icon-white"></i></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</li>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,100 @@
|
|||
{
|
||||
"allow_edit": true,
|
||||
"plugins": [],
|
||||
"panes": [
|
||||
{
|
||||
"title": "Houses",
|
||||
"width": 1,
|
||||
"row": {
|
||||
"2": 1,
|
||||
"3": 1
|
||||
},
|
||||
"col": {
|
||||
"2": 1,
|
||||
"3": 1
|
||||
},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Stark - Jon",
|
||||
"size": "regular",
|
||||
"value": "datasources[\"Jon\"].value",
|
||||
"sparkline": true,
|
||||
"animate": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Lannister - Tyrion",
|
||||
"size": "regular",
|
||||
"value": "datasources[\"Tyrion\"].value",
|
||||
"sparkline": true,
|
||||
"animate": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Timezones",
|
||||
"width": 1,
|
||||
"row": {
|
||||
"3": 1
|
||||
},
|
||||
"col": {
|
||||
"3": 2
|
||||
},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Stark - Jon",
|
||||
"size": "regular",
|
||||
"value": "new Date(datasources[\"Jon\"].time_stamp).toLocaleTimeString();",
|
||||
"animate": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text_widget",
|
||||
"settings": {
|
||||
"title": "House of Lannister - Tyrion",
|
||||
"size": "regular",
|
||||
"value": "new Date(datasources[\"Tyrion\"].time_stamp).toLocaleTimeString();",
|
||||
"animate": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"datasources": [
|
||||
{
|
||||
"name": "Jon",
|
||||
"type": "node_js",
|
||||
"settings": {
|
||||
"url": "http://localhost:8989/shows",
|
||||
"eventName": "house.stark.jon",
|
||||
"rooms": [
|
||||
{
|
||||
"roomName": "got",
|
||||
"roomEvent": "subscribe"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Tyrion",
|
||||
"type": "node_js",
|
||||
"settings": {
|
||||
"url": "http://localhost:8989/shows",
|
||||
"eventName": "house.lannister.tyrion",
|
||||
"rooms": [
|
||||
{
|
||||
"roomName": "got",
|
||||
"roomEvent": "subscribe"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 118 KiB |
|
@ -0,0 +1,111 @@
|
|||
// ┌────────────────────────────────────────────────────────────────────┐ \\
|
||||
// │ freeboard.io-node.js │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Copyright © 2014 Hugo Sequeira (https://github.com/hugocore) │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Licensed under the MIT license. │ \\
|
||||
// ├────────────────────────────────────────────────────────────────────┤ \\
|
||||
// │ Simple node.js and sockets.io server to test the node.js plugin. │ \\
|
||||
// └────────────────────────────────────────────────────────────────────┘ \\
|
||||
|
||||
/*
|
||||
* Configurations and helpers
|
||||
*/
|
||||
var namespace = '/shows';
|
||||
var room = 'got';
|
||||
var refreshTimer = 1000;
|
||||
var connectionscounter = 0;
|
||||
var eventNames = ['house.stark.jon', 'house.lannister.tyrion'];
|
||||
var serverport = 8989;
|
||||
|
||||
/*
|
||||
* Project dependencies
|
||||
*/
|
||||
var io = require('socket.io')(serverport);
|
||||
|
||||
/*
|
||||
* Collects data
|
||||
*/
|
||||
|
||||
// Implement the methods to handle the new events
|
||||
function newEventCallback(eventName, message) {
|
||||
|
||||
// Construct the json object to be propagated
|
||||
var json = {
|
||||
value: message.value,
|
||||
time_stamp: message.time_stamp,
|
||||
};
|
||||
|
||||
// Invokes propagation
|
||||
propagatesEvent(eventName, JSON.stringify(json));
|
||||
}
|
||||
|
||||
// Connection to external data sources
|
||||
function connectToExternalSources() {
|
||||
|
||||
// Simulate the connection and new messages with a timer function
|
||||
setInterval(function() {
|
||||
for (var i=0; i<eventNames.length; i++) {
|
||||
|
||||
// construct message
|
||||
var oneHourInMilis = 3600000;
|
||||
var message = {
|
||||
value: Math.floor(Math.random()*101),
|
||||
time_stamp: new Date().getTime()+(i*oneHourInMilis)
|
||||
};
|
||||
|
||||
|
||||
newEventCallback(eventNames[i], message);
|
||||
|
||||
}
|
||||
}, refreshTimer);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Data propagation
|
||||
*/
|
||||
|
||||
// Propagates event through all the connected clients
|
||||
function propagatesEvent(eventName, event) {
|
||||
if (connectionscounter>0) {
|
||||
io.of(namespace).to(room).emit(eventName, event);
|
||||
console.log("New event propagated in: Namespace='%s' Room='%s' EventName='%s' Event='%s'", namespace, room, eventName, event);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle Sockets.io connections
|
||||
*/
|
||||
|
||||
// Event handlers
|
||||
io.of(namespace).on('connection', function(socket) {
|
||||
|
||||
console.log("New client connected.");
|
||||
|
||||
// Do some logic for every new connection
|
||||
connectionscounter++;
|
||||
|
||||
// On subscribe events join client to room
|
||||
socket.on('subscribe', function(room) {
|
||||
socket.join(room);
|
||||
console.log("Client joined room: " + room);
|
||||
});
|
||||
|
||||
// On disconnect events
|
||||
socket.on('disconnect', function(socket) {
|
||||
console.log("Client disconnect from rooms.");
|
||||
connectionscounter--;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function puts(message) {
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run
|
||||
*/
|
||||
console.log("Starting Node.js server with namespace='%s' and room='%s'", namespace, room);
|
||||
connectToExternalSources();
|