init
32
.editorconfig
Normal file
@ -0,0 +1,32 @@
|
||||
; http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.txt]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[*.m]
|
||||
indent_size = 4
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
||||
[*.{js,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
180
.gitignore
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Archives template
|
||||
# It's better to unpack these files and commit the raw source because
|
||||
# git has its own built in compression methods.
|
||||
*.7z
|
||||
*.jar
|
||||
*.rar
|
||||
*.zip
|
||||
*.gz
|
||||
*.bzip
|
||||
*.bz2
|
||||
*.xz
|
||||
*.lzma
|
||||
*.cab
|
||||
|
||||
#packing-only formats
|
||||
*.iso
|
||||
*.tar
|
||||
|
||||
#package management formats
|
||||
*.dmg
|
||||
*.xpi
|
||||
*.gem
|
||||
*.egg
|
||||
*.deb
|
||||
*.rpm
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
### Windows template
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
### OSX template
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
### Node template
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
||||
node_modules
|
||||
bower_components
|
||||
|
||||
### VisualStudioCode template
|
||||
.settings
|
||||
|
||||
### Xcode template
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
|
||||
## Other
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
dist
|
46
.jscsrc
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleVarDecl": "exceptUndefined",
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowQuotedKeysInObjects": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": true,
|
||||
"disallowSpacesInFunction": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"maximumLineLength": 160,
|
||||
"requireCamelCaseOrUpperCaseIdentifiers": false,
|
||||
"requireCapitalizedComments": true,
|
||||
"requireCapitalizedConstructors": true,
|
||||
"requireCurlyBraces": true,
|
||||
"requireSpaceAfterKeywords": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"switch",
|
||||
"case",
|
||||
"return",
|
||||
"try",
|
||||
"catch",
|
||||
"typeof"
|
||||
],
|
||||
"requireSpaceAfterLineComment": true,
|
||||
"requireSpaceAfterBinaryOperators": true,
|
||||
"requireSpaceBeforeBinaryOperators": true,
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireSpaceBeforeObjectValues": true,
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"requireTrailingComma": false,
|
||||
"requireEarlyReturn": false,
|
||||
"validateIndentation": 2,
|
||||
"validateLineBreaks": "LF",
|
||||
"validateQuoteMarks": "'"
|
||||
}
|
37
.jshintrc
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"predef": [
|
||||
"Promise",
|
||||
"$"
|
||||
],
|
||||
"globals": {
|
||||
"$": false,
|
||||
"MicroEvent": false
|
||||
},
|
||||
"node":true,
|
||||
"browser": true,
|
||||
"boss": true,
|
||||
"curly": true,
|
||||
"debug": false,
|
||||
"devel": true,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": false,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": false,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": true,
|
||||
"strict": false,
|
||||
"white": false,
|
||||
"eqnull": true,
|
||||
"esnext": true,
|
||||
"unused": true,
|
||||
"supernew":true
|
||||
}
|
90
app.js
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Created by Martin on 08/02/2016.
|
||||
*/
|
||||
'use strict';
|
||||
var express = require('express');
|
||||
var path = require('path');
|
||||
var http = require('http');
|
||||
var ejs = require('ejs');
|
||||
var morgan = require('morgan');
|
||||
var cookieparser = require('cookie-parser');
|
||||
var session = require('express-session');
|
||||
var methodoverride = require('method-override');
|
||||
var bodyparser = require('body-parser');
|
||||
var errorhandler = require('errorhandler');
|
||||
var log4js = require('log4js');
|
||||
var logger = log4js.getLogger();
|
||||
|
||||
|
||||
var WebSocketServer = require('websocket').server;
|
||||
|
||||
var EventEmitter = require('events');
|
||||
var busEmitter = new EventEmitter();
|
||||
|
||||
var apn = require('apn');
|
||||
|
||||
require('sugar-date');
|
||||
|
||||
var isProduction = false;
|
||||
|
||||
|
||||
var mdotApi = require('./lib/mdot/api.js');
|
||||
|
||||
|
||||
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
isProduction = true;
|
||||
}
|
||||
|
||||
logger.warn('isProduction:', isProduction);
|
||||
|
||||
var app = express();
|
||||
|
||||
app.set('port', process.env.PORT || 4545);
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
app.use(morgan('combined'));
|
||||
app.use(cookieparser('your secret here'));
|
||||
app.use(session({
|
||||
secret: '1234567890QWERTY', resave: false, saveUninitialized: false
|
||||
}));
|
||||
/* 'default', 'short', 'tiny', 'dev' */
|
||||
app.use(methodoverride());
|
||||
|
||||
app.use(bodyparser.urlencoded({extended: false}));
|
||||
|
||||
// Parse application/json
|
||||
app.use(bodyparser.json());
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
|
||||
next();
|
||||
});
|
||||
|
||||
// Run npm start --production to use dist
|
||||
var staticDir = isProduction ? 'dist' : 'app';
|
||||
|
||||
app.use(express.static(path.join(__dirname, staticDir)));
|
||||
app.use(errorhandler({dumpExceptions: true, showStack: true}));
|
||||
|
||||
|
||||
// Events and sockets
|
||||
|
||||
function originIsAllowed(origin) {
|
||||
// Put logic here to detect whether the specified origin is allowed.
|
||||
return true;
|
||||
}
|
||||
|
||||
// glue routes
|
||||
mdotApi(app);
|
||||
|
||||
//app.get('/api/mdot/:id', mDot.getData);
|
||||
|
||||
app.listen(3010, function() {
|
||||
logger.info('Express listening on 3010');
|
||||
|
||||
});
|
276
app/css/app.css
Normal file
@ -0,0 +1,276 @@
|
||||
body {
|
||||
font-family: Ubuntu, "Helvetica Neue", Helvetica, arial, sans-serif;
|
||||
background-color: #004c6d;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#weatherIcon {
|
||||
margin-left:25%;
|
||||
margin-right:25%;
|
||||
height:70px;
|
||||
width:70px;
|
||||
|
||||
}
|
||||
|
||||
#lightR, #projR { color: red !important; }
|
||||
|
||||
#lightG, #projG { color: green !important; }
|
||||
|
||||
#lightB, #projB { color: blue !important; }
|
||||
|
||||
#lightW, #projW { background-color: #aabbcc; }
|
||||
|
||||
.lightBG, .heatingBG, .projectorBG {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/*.lightBG {
|
||||
background-color: rgba(255, 255, 0, 0.3);
|
||||
}
|
||||
|
||||
.heatingBG {
|
||||
background-color: rgba(255, 0, 255, 0.3);
|
||||
}
|
||||
|
||||
.projectorBG {
|
||||
background-color: rgba(0, 255, 255, 0.3);
|
||||
}*/
|
||||
|
||||
.mui-panel {
|
||||
background-color: #015579;
|
||||
}
|
||||
|
||||
.h105 {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.mdHeading {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mui--text-title {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.item_content {
|
||||
height: 100px;
|
||||
/* border: 1px solid grey;*/
|
||||
min-height: 100px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item_content a.title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.item_content div.body, .item_content div.site, .item_content div.tags {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #313131;
|
||||
}
|
||||
|
||||
.time, .date, .temp {
|
||||
font-family: 'Ubuntu Condensed', sans-serif;
|
||||
font-size: 80px;
|
||||
color: #bad649;
|
||||
}
|
||||
|
||||
.time span.hour:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 35px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.temp::after {
|
||||
content: "°c";
|
||||
}
|
||||
|
||||
.item_content div.tags {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.noConnection {
|
||||
color: rgb(244, 150, 26);
|
||||
}
|
||||
|
||||
#caltext {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Smartphones (portrait and landscape) ----------- */
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
|
||||
/* Styles */
|
||||
.time, .date, .temp {
|
||||
font-family: 'Ubuntu Condensed', sans-serif;
|
||||
font-size: 33px;
|
||||
/*color: #ff0000;*/
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 50px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.time span.hour:after {
|
||||
content: "\a";
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.temp {
|
||||
font-size: 70px;
|
||||
}
|
||||
|
||||
.temp::after {
|
||||
content: "°";
|
||||
}
|
||||
|
||||
.wd-we {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.mo {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
.mo.mo-1, .mo.mo-10 {
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
.mo.mo-2 {
|
||||
font-size: 65%;
|
||||
}
|
||||
|
||||
.mo.mo-8 {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.mo.mo-9 {
|
||||
font-size: 55%;
|
||||
}
|
||||
|
||||
.mo.mo-11, .mo.mo-12 {
|
||||
font-size: 60%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Smartphones (landscape) ----------- */
|
||||
@media only screen and (min-width: 321px) {
|
||||
/* Styles */
|
||||
}
|
||||
|
||||
/* Smartphones (portrait) ----------- */
|
||||
@media only screen and (max-width: 320px) {
|
||||
/* Styles */
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin: 25px auto 0;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner > div {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-color: rgb(244, 150, 26);
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
}
|
||||
|
||||
.spinner .bounce1 {
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.spinner .bounce2 {
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
}
|
||||
40% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
color: #e5f7fd;
|
||||
}
|
||||
|
||||
.material-icons.md-18 { font-size: 18px; }
|
||||
|
||||
.material-icons.md-24 { font-size: 24px; }
|
||||
|
||||
.material-icons.md-36 { font-size: 36px; }
|
||||
|
||||
.material-icons.md-48 { font-size: 48px; }
|
||||
|
||||
.material-icons.md-100 { font-size: 100px; }
|
||||
|
||||
/* Rules for using icons as black on a light background. */
|
||||
.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); }
|
||||
|
||||
.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); }
|
||||
|
||||
/* Rules for using icons as white on a dark background. */
|
||||
.material-icons.md-light { color: rgba(255, 255, 255, 1); }
|
||||
|
||||
.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); }
|
||||
|
||||
.material-icons.md-bulb {
|
||||
content: ""
|
||||
}
|
||||
|
||||
/*
|
||||
fan : toys
|
||||
|
||||
<i class="material-icons"></i>
|
||||
|
||||
|
||||
bulb : lightbulb_outline
|
||||
<i class="material-icons"></i>
|
||||
|
||||
calendar: event_note
|
||||
<i class="material-icons"></i>
|
||||
|
||||
projector: cast
|
||||
<i class="material-icons"></i>
|
||||
|
||||
*/
|
||||
|
||||
.md-display {
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s, visibility 0.3s;
|
||||
|
||||
}
|
||||
|
||||
.lostConnection {
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.3s, visibility 0.3s;
|
||||
}
|
15
app/css/material-icons.css
Normal file
@ -0,0 +1,15 @@
|
||||
.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
1912
app/css/mui.css
Normal file
1912
app/css/mui.custom.css
Normal file
1
app/css/mui.min.css
vendored
Normal file
BIN
app/fav/android-chrome-144x144.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
app/fav/android-chrome-36x36.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
app/fav/android-chrome-48x48.png
Normal file
After Width: | Height: | Size: 767 B |
BIN
app/fav/android-chrome-72x72.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/fav/android-chrome-96x96.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/fav/apple-icon-57x57-precomposed.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
app/fav/apple-icon-60x60-precomposed.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
app/fav/apple-icon-72x72-precomposed.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
app/fav/apple-touch-icon-114x114.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/fav/apple-touch-icon-120x120.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/fav/apple-touch-icon-144x144.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/apple-touch-icon-152x152.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/apple-touch-icon-180x180.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
app/fav/apple-touch-icon-57x57.png
Normal file
After Width: | Height: | Size: 875 B |
BIN
app/fav/apple-touch-icon-60x60.png
Normal file
After Width: | Height: | Size: 924 B |
BIN
app/fav/apple-touch-icon-72x72.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/fav/apple-touch-icon-76x76.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/fav/apple-touch-icon-precomposed.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/fav/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
12
app/fav/browserconfig.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/fav/mstile-70x70.png"/>
|
||||
<square150x150logo src="/fav/mstile-150x150.png"/>
|
||||
<square310x310logo src="/fav/mstile-310x310.png"/>
|
||||
<wide310x150logo src="/fav/mstile-310x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
BIN
app/fav/censis-opengraph-image.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
app/fav/favicon-16x16.png
Normal file
After Width: | Height: | Size: 401 B |
BIN
app/fav/favicon-32x32.png
Normal file
After Width: | Height: | Size: 564 B |
BIN
app/fav/favicon-96x96.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/fav/favicon.ico
Normal file
After Width: | Height: | Size: 7.2 KiB |
43
app/fav/manifest.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "Censis Smart Office ",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/fav\/android-chrome-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": 0.75
|
||||
},
|
||||
{
|
||||
"src": "\/fav\/android-chrome-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": 1
|
||||
},
|
||||
{
|
||||
"src": "\/fav\/android-chrome-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": 1.5
|
||||
},
|
||||
{
|
||||
"src": "\/fav\/android-chrome-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": 2
|
||||
},
|
||||
{
|
||||
"src": "\/fav\/android-chrome-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": 3
|
||||
},
|
||||
{
|
||||
"src": "\/fav\/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": 4
|
||||
}
|
||||
],
|
||||
"display": "standalone",
|
||||
"orientation": "portrait"
|
||||
}
|
BIN
app/fav/mstile-144x144.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/mstile-150x150.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/fav/mstile-310x150.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/fav/mstile-310x310.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/fav/mstile-70x70.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
46
app/fav/safari-pinned-tab.svg
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="991.000000pt" height="991.000000pt" viewBox="0 0 991.000000 991.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,991.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M7465 9503 c-480 -60 -867 -422 -967 -903 -28 -132 -21 -345 16 -517
|
||||
40 -184 56 -315 56 -460 0 -146 -15 -244 -54 -347 -36 -96 -38 -98 -89 -80
|
||||
-71 25 -267 73 -372 90 -219 35 -551 33 -774 -5 -973 -169 -1752 -917 -1945
|
||||
-1871 -14 -67 -27 -124 -30 -127 -9 -9 -162 19 -235 43 -168 56 -304 137 -577
|
||||
345 -209 157 -328 222 -489 266 -93 25 -114 27 -290 27 -207 0 -253 -8 -420
|
||||
-73 -270 -104 -514 -347 -624 -623 -113 -281 -105 -620 20 -887 113 -241 291
|
||||
-426 524 -541 311 -154 673 -157 985 -9 107 51 172 95 328 226 311 258 558
|
||||
392 752 405 l44 3 17 -70 c115 -492 361 -914 725 -1247 354 -324 795 -530
|
||||
1294 -604 80 -12 177 -17 320 -17 222 0 346 14 545 58 254 57 407 0 493 -183
|
||||
25 -52 27 -68 27 -177 -1 -119 -1 -121 -49 -245 -66 -173 -86 -263 -93 -410
|
||||
-21 -494 279 -940 743 -1106 352 -126 754 -67 1054 156 84 62 205 187 259 269
|
||||
62 91 126 231 157 341 38 140 45 372 14 520 -96 469 -473 820 -950 886 -179
|
||||
25 -223 35 -297 69 -85 39 -159 105 -199 177 -27 49 -29 61 -29 158 0 95 3
|
||||
110 27 156 15 28 70 102 123 165 239 281 410 611 500 963 57 223 70 332 70
|
||||
596 0 264 -13 373 -70 595 -115 448 -379 885 -712 1179 -57 50 -103 95 -103
|
||||
100 0 19 92 136 150 189 119 110 264 194 490 282 80 31 176 69 215 86 333 142
|
||||
568 418 656 770 29 120 36 325 15 448 -84 482 -453 849 -931 926 -82 14 -245
|
||||
18 -320 8z m-879 -2369 c179 -72 362 -175 526 -296 l67 -49 -23 -52 c-78 -176
|
||||
-73 -421 13 -642 17 -45 63 -137 103 -205 210 -367 298 -727 268 -1103 -53
|
||||
-664 -433 -1233 -1019 -1527 -295 -148 -564 -207 -891 -197 -233 7 -398 39
|
||||
-600 114 -449 168 -823 510 -1029 943 -42 89 -123 311 -116 318 2 2 44 -11 95
|
||||
-28 199 -66 403 -188 797 -477 211 -155 338 -226 497 -278 766 -251 1582 242
|
||||
1721 1041 20 113 19 336 0 450 -95 545 -532 983 -1079 1081 -125 22 -354 22
|
||||
-470 -1 -279 -54 -482 -162 -716 -377 -330 -304 -539 -447 -753 -514 -117 -37
|
||||
-118 -37 -101 33 82 320 239 603 467 839 161 167 310 274 522 379 232 113 430
|
||||
166 690 184 357 24 460 45 614 125 111 57 194 125 255 209 26 36 54 66 60 66
|
||||
7 0 52 -16 102 -36z m-701 -1448 c90 -24 232 -98 307 -160 122 -101 217 -251
|
||||
259 -411 28 -105 30 -279 4 -380 -91 -359 -405 -608 -770 -608 -123 0 -231 25
|
||||
-350 83 -165 80 -284 199 -364 363 -54 109 -72 180 -78 308 -11 224 60 417
|
||||
215 581 109 116 254 198 407 232 87 19 283 15 370 -8z m-2044 -463 c-10 -56
|
||||
-15 -144 -14 -313 0 -211 3 -246 25 -348 l24 -114 -30 6 c-106 20 -209 26
|
||||
-353 20 l-162 -6 -6 24 c-31 139 -44 479 -25 664 6 65 13 120 13 120 1 1 114
|
||||
5 252 9 137 3 252 8 254 11 2 2 12 4 21 4 15 0 15 -6 1 -77z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/gfx/100.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/gfx/105.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
app/gfx/128.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
app/gfx/censis_logo_white.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
app/gfx/icons/Cellular Network.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/gfx/icons/Chance of Storm.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Clock.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Cloud Lighting.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Cloud.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/gfx/icons/Coffee Maker.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/gfx/icons/Downpour.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Electric Teapot.png
Normal file
After Width: | Height: | Size: 1015 B |
BIN
app/gfx/icons/Fog Day.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/gfx/icons/Fog Night.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/gfx/icons/Full Moon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Hail.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
app/gfx/icons/Heavy Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Icy.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/gfx/icons/Idea.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Intense Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Light Automation.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Light Off.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Light Rain 2.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Light Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Light Snow.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
app/gfx/icons/Lightning Bolt.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/gfx/icons/Moderate Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/No Rain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Partly Cloudy Day.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Partly Cloudy Night.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Partly Cloudy Rain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Rain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Sleet.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Snow Storm.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Snow.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/gfx/icons/Storm.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Sun.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/gfx/icons/TV On.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/gfx/icons/Temperature Outside.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/gfx/icons/Thermometer Automation.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Torrential Rain.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Wet.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Winter.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/gfx/icons/air-conditioner.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/gfx/icons/av-receiver.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/gfx/icons/bright-moon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/calendar.png
Normal file
After Width: | Height: | Size: 894 B |
BIN
app/gfx/icons/fan.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/globe-bulb.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/gfx/icons/video-projector.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
16
app/gfx/light-bulb-vector-png-light-bulb-10.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<path d="M256,32c77.313,0,140,62.688,140,140c0,76.125-45.875,85-54.5,168c0,7.75-6.25,14-14,14h-143c-7.75,0-14-6.25-14-14h-0.031
|
||||
C161.875,257,116,248.125,116,172C116,94.688,178.688,32,256,32 M326,368c7.75,0,14,6.25,14,14s-6.25,14-14,14H186
|
||||
c-7.75,0-14-6.25-14-14s6.25-14,14-14H326 M326,410c7.75,0,14,6.25,14,14s-6.25,14-14,14H186c-7.75,0-14-6.25-14-14s6.25-14,14-14
|
||||
H326 M312,452c0,15.469-12.531,28-28,28h-56c-15.469,0-28-12.531-28-28H312 M256,0C161.156,0,84,77.156,84,172
|
||||
c0,47.625,15.563,74.969,29.25,99.125c11.625,20.438,21.688,38.156,25.281,71.094c0.344,7.313,2.438,14.188,5.844,20.219
|
||||
C141.563,368.375,140,375,140,382c0,7.563,1.813,14.688,5.063,21c-3.25,6.313-5.063,13.438-5.063,21
|
||||
c0,19.719,12.469,36.563,29.938,43.094C176.625,492.906,200.125,512,228,512h56c27.875,0,51.375-19.094,58.063-44.906
|
||||
C359.531,460.563,372,443.719,372,424c0-7.563-1.844-14.688-5.094-21c3.25-6.313,5.094-13.438,5.094-21
|
||||
c0-7-1.563-13.625-4.375-19.531c3.406-6.063,5.469-12.969,5.813-20.281c3.625-32.906,13.656-50.594,25.281-71.063
|
||||
C412.438,247,428,219.625,428,172C428,77.156,350.844,0,256,0L256,0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/gfx/projector.gif
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
app/gfx/projector.png
Normal file
After Width: | Height: | Size: 31 KiB |
318
app/index.html
Normal file
@ -0,0 +1,318 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Console</title>
|
||||
<!-- build:fonts -->
|
||||
<link rel="stylesheet"
|
||||
href="http://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700"
|
||||
type="text/css">
|
||||
<link href='https://fonts.googleapis.com/css?family=Ubuntu+Condensed'
|
||||
rel='stylesheet' type='text/css'>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
||||
rel="stylesheet">
|
||||
<!-- endbuild -->
|
||||
<!-- build:css -->
|
||||
<link href="css/mui.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="css/app.css" rel="stylesheet" type="text/css"/>
|
||||
<!-- endbuild -->
|
||||
<link rel="apple-touch-icon" sizes="57x57"
|
||||
href="/fav/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60"
|
||||
href="/fav/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72"
|
||||
href="/fav/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76"
|
||||
href="/fav/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114"
|
||||
href="/fav/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120"
|
||||
href="/fav/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144"
|
||||
href="/fav/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152"
|
||||
href="/fav/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180"
|
||||
href="/fav/apple-touch-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" href="/fav/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="/fav/android-chrome-192x192.png"
|
||||
sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="/fav/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="/fav/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="/fav/manifest.json">
|
||||
<link rel="mask-icon" href="/fav/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<link rel="shortcut icon" href="/fav/favicon.ico">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="msapplication-TileImage" content="/fav/mstile-144x144.png">
|
||||
<meta name="msapplication-config" content="/fav/browserconfig.xml">
|
||||
<meta name="theme-color" content="#00aeef">
|
||||
</head>
|
||||
<body class="mui--no-user-select">
|
||||
<div id="iosTaskbar" style="height:25px;display:none;"></div>
|
||||
<div class="mui-container">
|
||||
<div class="mui-panel" style="display: ;">
|
||||
<div class="mui-row mui--text-center">
|
||||
<img src="gfx/censis_logo_white.png">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="noSocket" style="display: none;">
|
||||
<div class="mui-row">
|
||||
<div
|
||||
class="mui--text-body2 mui--text-center noConnection">Lost connection to server. Waiting for connection
|
||||
</div>
|
||||
<div id='longWait' class="spinner" style="display: none;">
|
||||
<div class="bounce1"></div>
|
||||
<div class="bounce2"></div>
|
||||
<div class="bounce3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="noDevice" style="display: none;">
|
||||
<div class="mui-row">
|
||||
<div
|
||||
class="mui--text-body2 mui--text-center noConnection">We are having problems connecting to one or more of the devices. Please restart them and wait for them to reconnect.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="clock">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 ">
|
||||
<div id="time" class="mui--text-center time">12:34</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div id="date" class="mui--text-center date">14 April<br>2016</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div id="weather" class="mui--text-center date">
|
||||
<div id="weatherIcon">
|
||||
<canvas id="icon1" width="210" height="210"
|
||||
style="max-width: 70px; max-height:70px"></canvas>
|
||||
</div>
|
||||
<div class="mui--text-center" id="weatherText"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="extender" style="display: none;">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-12 mui--text-center">
|
||||
<div class="mui--text-title ">
|
||||
Extend meeting
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-12 mui--text-center">
|
||||
<button id="extend05" class="mui-btn mui-btn--fab">5</button>
|
||||
<button id="extend10" class="mui-btn mui-btn--fab">10</button>
|
||||
<button id="extend15" class="mui-btn mui-btn--fab">15</button>
|
||||
<button id="extend30" class="mui-btn mui-btn--fab">30</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="calendar" style="display: none;">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 mui--text-center"><span
|
||||
class="material-icons md-100"></span></div>
|
||||
<div class="mui-col-xs-8 item_content">
|
||||
<div class="mui-row ">
|
||||
<div class="mui--text-title "><a class='title'
|
||||
href="#">Meeting room</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row">
|
||||
<div id="caltext"></div>
|
||||
<div id="extendInfo" class="mui--text-subhead mui--text-accent"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="front-light" class="md-display">
|
||||
<div class="mui-panel">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 mui--text-center"><span
|
||||
class="material-icons md-100"></span></div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div class="mui-row mui--text-center">
|
||||
<div class="mui--text-title mui--text-center"><a class='title'
|
||||
href="#">Front light</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row mui--text-center">
|
||||
<button id="frontLightOn" class="mui-btn mui-btn--primary lightOn">On
|
||||
</button>
|
||||
<button id="frontLightOff" class="mui-btn mui-btn--danger lightOff"
|
||||
style="display: none;">Off
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 mui--text-center" id="auxFront"
|
||||
style="display:none;">
|
||||
<div>
|
||||
<button class="mui-btn mui-btn--small mui-btn--accent lightUp"
|
||||
id="frontUp">BRIGHTER
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="mui-btn mui-btn--small mui-btn--accent lightDown"
|
||||
id="frontDown">DARKER
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="mui-panel" id="middle-light">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 mui--text-center"><i class="material-icons md-100"></i></div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div class="mui-row">
|
||||
<div class="mui--text-title mui--text-center"><a class='title'
|
||||
href="#">Middle light</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row mui--text-center">
|
||||
<button id="middleLightOn"
|
||||
class="mui-btn mui-btn--primary">On
|
||||
</button>
|
||||
<button id="middleLightOff" class="mui-btn mui-btn--danger"
|
||||
style="display: none;">Off
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="mui-panel" id="back-light">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 mui--text-center"><i
|
||||
class="material-icons md-100"></i></div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div class="mui-row">
|
||||
<div class="mui--text-title mui--text-center"><a class='title'
|
||||
href="#">Back light</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row mui--text-center">
|
||||
<button id="backLightOn" class="mui-btn mui-btn--primary lightOn">On
|
||||
</button>
|
||||
<button id="backLightOff" class="mui-btn mui-btn--danger lightOff"
|
||||
style="display: none;">Off
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 mui--text-center" id="auxBack"
|
||||
style="display: none;">
|
||||
<div>
|
||||
<button class="mui-btn mui-btn--small mui-btn--accent lightUp"
|
||||
id="backUp">BRIGHTER
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="mui-btn mui-btn--small mui-btn--accent lightDown"
|
||||
id="backDown">DARKER
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="heating-panel" style="display: none ;">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 mui--text-center"><i
|
||||
class="material-icons md-100"></i>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div class="mui-row">
|
||||
<div class="mui--text-title mui--text-center"><a class='title'
|
||||
href="#">Fan</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row mui--text-center">
|
||||
<button id="heatingOn" class="mui-btn mui-btn--primary">On
|
||||
</button>
|
||||
<button id="heatingOff" class="mui-btn mui-btn--danger"
|
||||
style="display: none;">Off
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 mui--text-center">
|
||||
<div id="curTemp" class="temp"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-panel" id="projector-panel" style="display:;">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-xs-4 mui--text-center"><i
|
||||
class="material-icons md-100"></i></div>
|
||||
<div class="mui-col-xs-4 item_content">
|
||||
<div class="mui-row">
|
||||
<div class="mui--text-title mui--text-center"><a class='title'
|
||||
href="#">Projector</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-row mui--text-center">
|
||||
<button id="projectorOn" class="mui-btn mui-btn--primary">On
|
||||
</button>
|
||||
<button id="projectorOff" class="mui-btn mui-btn--danger"
|
||||
style="display: none;">Off
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-4 mui--text-center" id="auxProjector"
|
||||
style="display:none;">
|
||||
<div>
|
||||
<button class="mui-btn mui-btn--small mui-btn--accent"
|
||||
id="projectorHDMI">HDMI
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="mui-btn mui-btn--small mui-btn--accent"
|
||||
id="projectorVGA">VGA
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="mui-panel">
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-md-3"><span id="lightR">---</span></div>
|
||||
<div class="mui-col-md-3"><span id="lightG">---</span></div>
|
||||
<div class="mui-col-md-3"><span id="lightB">---</span></div>
|
||||
<div class="mui-col-md-3"><span id="lightW">---</span></div>
|
||||
</div>
|
||||
<div class="mui-row">
|
||||
<div class="mui-col-md-3"><span id="projR">---</span></div>
|
||||
<div class="mui-col-md-3"><span id="projG">---</span></div>
|
||||
<div class="mui-col-md-3"><span id="projB">---</span></div>
|
||||
<div class="mui-col-md-3"><span id="projW">---</span></div>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
<script src="cordova.js"></script>
|
||||
<!-- build:vendor -->
|
||||
<script src="lib/mui.js"></script>
|
||||
<script src="lib/jquery.js"
|
||||
integrity="sha256-laXWtGydpwqJ8JA+X9x2miwmaiKhn8tVmOVEigRNtP4="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="lib/chroma.js"></script>
|
||||
|
||||
<script src="lib/underscore.js"></script>
|
||||
<script src="lib/backbone.js"></script>
|
||||
<!--<script src="lib/sugar-date.js"></script>-->
|
||||
<script src="lib/sugar-full.min.js"></script>
|
||||
<script src="lib/skycons.js"></script>
|
||||
<script src="lib/microevent.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js -->
|
||||
<script src="js/sowebsocket.js"></script>
|
||||
<script src="js/colours.js"></script>
|
||||
|
||||
<script src="js/parts/clock.js"></script>
|
||||
<script src="js/parts/meetings.js"></script>
|
||||
<script src="js/parts/lights.js"></script>
|
||||
<script src="js/parts/projector.js"></script>
|
||||
<script src="js/appv3.js"></script>
|
||||
</body>
|
||||
<!-- endbuild -->
|
||||
</html>
|
403
app/js/mdot.js
Normal file
@ -0,0 +1,403 @@
|
||||
'use strict';
|
||||
/* global Backbone, _, $ */
|
||||
/* global mainview */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
|
||||
(function($) {
|
||||
|
||||
var mqttConfig = {
|
||||
orgId: 'qz0da4',
|
||||
userName: 'a-qz0da4-dfwwdkmkzr',
|
||||
appKey: '9txJEf3Cjy7hkSOvkv',
|
||||
prefix: 'iot-2/type/mDot/id/'
|
||||
};
|
||||
|
||||
var sendAuthentication = function(xhr) {
|
||||
var user = 'a-qz0da4-dfwwdkmkzr'; // Your actual username
|
||||
var pass = '9txJEf3Cjy7hkSOvkv'; // Your actual password
|
||||
var token = user.concat(':', pass);
|
||||
xhr.setRequestHeader('Authorization', ('Basic '.concat(btoa(token))));
|
||||
|
||||
console.log('Auth:', ('Basic '.concat(btoa(token))));
|
||||
};
|
||||
|
||||
var EventsModel = Backbone.Model.extend({
|
||||
initialize: function() {
|
||||
_.bindAll(this, 'processAdded');
|
||||
this.on('all',function(d) {
|
||||
console.log('model:all',d);
|
||||
this.temporal = {low: 0,high: 0};
|
||||
});
|
||||
|
||||
this.on('add',function() {
|
||||
this.processAdded();
|
||||
});
|
||||
|
||||
},
|
||||
processAdded: function() {
|
||||
console.log('Model:ProcessAdded');
|
||||
|
||||
var tempCollection = new Backbone.Collection();
|
||||
|
||||
_.invoke(DeviceCollection.toArray(), 'destroy');
|
||||
|
||||
|
||||
this.temporal = {low: 0,high: 0};
|
||||
|
||||
_(this.get('events')).each(function(i) {
|
||||
i.evt.decoded = this.decoder(i.evt.data);
|
||||
i.evt.dateTime = this.dateTime(i.timestamp.$date);
|
||||
|
||||
if (this.temporal.low === 0 || this.temporal.low > i.timestamp.$date) {
|
||||
this.temporal.low = i.timestamp.$date;
|
||||
}
|
||||
|
||||
if (this.temporal.high === 0 || this.temporal.high < i.timestamp.$date) {
|
||||
this.temporal.high = i.timestamp.$date;
|
||||
}
|
||||
|
||||
tempCollection.add({dt: i.evt.dateTime.dateTime,lux: i.evt.decoded.light, temp: i.evt.decoded.temp, co2: i.evt.decoded.co2, humid: i.evt.decoded.humid, noise: i.evt.decoded.noise});
|
||||
}, this);
|
||||
|
||||
DeviceCollection.temporal = this.temporal;
|
||||
|
||||
DeviceCollection.models = tempCollection.models;
|
||||
DeviceCollection.trigger('update');
|
||||
console.log('temporal:', this.temporal);
|
||||
},
|
||||
decoder: function(data) {
|
||||
var _obj = {};
|
||||
var _data = window.atob(data).split('');
|
||||
|
||||
var bytes = _data.map(i => i.charCodeAt());
|
||||
|
||||
_obj.light = parseInt('0x' + ('0' + bytes[0]).substr(-2) + ('0' + bytes[1]).substr(-2));
|
||||
_obj.co2 = parseInt(_data[2] + _data[3] + _data[4] + _data[5] + _data[6], 10);
|
||||
_obj.temp = (parseInt(_data[7] + _data[8] + _data[9] + _data[10] + _data[11], 10) - 1000) / 10;
|
||||
_obj.humid = (parseInt(_data[12] + _data[13] + _data[14] + _data[15] + _data[16], 10) / 10);
|
||||
_obj.noise = parseInt('0x' + ('0' + bytes[17]).substr(-2) + ('0' + bytes[18]).substr(-2));
|
||||
_obj.binData = bytes;
|
||||
return _obj;
|
||||
},
|
||||
dateTime: function($date) {
|
||||
var dateTime = new Date.create($date);
|
||||
var date = dateTime.format('{yyyy}-{MM}-{dd}');
|
||||
var time = dateTime.format('{HH}:{mm}:{ss}');
|
||||
return {dateTime: dateTime.format('{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'), date: date, time: time};
|
||||
}
|
||||
});
|
||||
|
||||
var mDotCollection = Backbone.Collection.extend({
|
||||
model: EventsModel,
|
||||
url: 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/',
|
||||
initialize: function() {
|
||||
this.on('all',function(d) {
|
||||
console.log('Collection:all',d);
|
||||
|
||||
});
|
||||
this.on('update', function() {
|
||||
// Console.log('Collection:update',this);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var ItemView = Backbone.View.extend({
|
||||
tagName: 'div', className: 'item mui-container', initialize: function() {
|
||||
this.template = _.template($('#item-template').html());
|
||||
console.log('ItemView:Init');
|
||||
// This.render();
|
||||
}, render: function() {
|
||||
console.log('ItemView:Render');
|
||||
_(this.model.events).each(function(i) {
|
||||
this.$el.append(this.template({item: i}));
|
||||
}, this);
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var MDOT = Backbone.View.extend({
|
||||
model: EventsModel, el: $('#output'),
|
||||
|
||||
events: {
|
||||
'click button#refresh': 'refresh'
|
||||
}, initialize: function() {
|
||||
_.bindAll(this, 'render', 'refresh', 'update');
|
||||
this.collection.bind('change reset add remove', this.render, this);
|
||||
|
||||
this.template = _.template($('#list-template').html());
|
||||
this.render();
|
||||
}, refresh: function() {
|
||||
|
||||
}, update: function() {
|
||||
console.log('MDOT:update');
|
||||
this.collection.each(function(model) {
|
||||
|
||||
// Var events = model.get('events');
|
||||
// var e = new ItemView({model: model.toJSON()});
|
||||
});
|
||||
|
||||
}, render: function() {
|
||||
console.log('MDOT:render');
|
||||
var that = this;
|
||||
this.$el.empty();
|
||||
this.collection.each(function(model) {
|
||||
var events = model.get('events');
|
||||
var e = new ItemView({model: model.toJSON()}).render().el;
|
||||
|
||||
console.log('render:done:');
|
||||
that.$el.append(e);
|
||||
|
||||
});
|
||||
console.log('bah');
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var MainModel = Backbone.Model.extend({});
|
||||
|
||||
var MainView = Backbone.View.extend({
|
||||
el: $('#main'),
|
||||
template: _.template($('#main-template').html()),
|
||||
events: {
|
||||
'change select#device': 'changeDevice',
|
||||
'click button#refresh': 'updateDevice',
|
||||
'change input#from': 'changeDate',
|
||||
'change input#to': 'changeDate',
|
||||
submit: function(event) {}
|
||||
|
||||
},
|
||||
initialize: function() {
|
||||
_.bindAll(this, 'render','changeDevice', 'updateDevice');
|
||||
|
||||
this.model.on('change',this.updateDevice);
|
||||
console.log('MainView:', this);
|
||||
this.render();
|
||||
},
|
||||
render: function() {
|
||||
$(this.el).html(this.template());
|
||||
return this;
|
||||
},changeDate: function(elm) {
|
||||
console.log('ChangeDate', elm);
|
||||
|
||||
if (Number.isNaN(elm.currentTarget.valueAsNumber)) {
|
||||
this.model.unset(elm.currentTarget.id);
|
||||
} else {
|
||||
this.model.set(elm.currentTarget.id, elm.currentTarget.valueAsNumber);
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
changeDevice: function() {
|
||||
var newDevice;
|
||||
console.log('MainView:ChangeDevice');
|
||||
newDevice = this.$el.find('#device')[0].value;
|
||||
|
||||
this.model.set('device', newDevice);
|
||||
},
|
||||
updateDevice: function() {
|
||||
var fetchObj = {beforeSend: sendAuthentication};
|
||||
var rangeObj = {start: null, end: null};
|
||||
console.log('MainView:Updatedevice');
|
||||
console.log(this.model);
|
||||
if (this.model.has('from') && this.model.has('to')) {
|
||||
rangeObj.start = this.model.get('from');
|
||||
rangeObj.end = this.model.get('to');
|
||||
fetchObj.data = $.param(rangeObj);
|
||||
console.log(fetchObj.data);
|
||||
}
|
||||
if (this.model.has('device')) {
|
||||
// FetchObj.data = $.param({key:'"'+ this.model.get('device') + '"'});
|
||||
// this.collection.url = 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/' + this.model.get('device');
|
||||
this.collection.url = '/api/mdot/' + this.model.get('device');
|
||||
// this.collection.url = 'http://127.0.0.1:5984/mdot/_design/getDevice/_view/getDevice';
|
||||
this.collection.fetch(fetchObj);
|
||||
} else {
|
||||
console.error('Nothing to get!');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var GraphView = Backbone.View.extend({
|
||||
el: $('#graph'),
|
||||
template: _.template($('#graph-template').html()),
|
||||
initialize: function() {
|
||||
this.modes = ['','lux','temp','co2','humid','noise'];
|
||||
this.mode = 0;
|
||||
this.xmlns = 'http://www.w3.org/2000/svg';
|
||||
|
||||
console.log('GraphView!');
|
||||
_.bindAll(this, 'render', 'changeMode', 'updateGraph');
|
||||
this.collection.on('update',function(d) {
|
||||
if (this.mode > 0) {
|
||||
this.updateGraph();
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.render();
|
||||
},
|
||||
events: {
|
||||
'change select#displaymode': 'changeMode'
|
||||
},
|
||||
render: function() {
|
||||
$(this.el).html(this.template());
|
||||
this.$line = $(this.el).find('#line');
|
||||
this.$maxY = $(this.el).find('#maxY');
|
||||
this.$datapoints = $(this.el).find('#datapoints');
|
||||
this.$baseline = $(this.el).find('#baseline');
|
||||
|
||||
return this;
|
||||
},
|
||||
changeMode: function() {
|
||||
this.mode = this.$el.find('#displaymode')[0].value;
|
||||
this.updateGraph();
|
||||
console.log('new mode:', this.mode);
|
||||
|
||||
},
|
||||
updateGraph: function() {
|
||||
|
||||
var calcArray;
|
||||
var startX;
|
||||
var xstep;
|
||||
var scale;
|
||||
let ceiling, ceilingLimit;
|
||||
let points = [];
|
||||
let data = [];
|
||||
let circle, title;
|
||||
let getMode = this.modes[this.mode];
|
||||
var occupied;
|
||||
|
||||
_(this.collection.models).each(function(i) {
|
||||
// Console.log(i);
|
||||
points.push(i.get(getMode));
|
||||
data.push(i.get('dt') + ' / ' + i.get(getMode));
|
||||
}, this);
|
||||
|
||||
ceiling = points.reduce(function(p, v) {
|
||||
return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v));
|
||||
});
|
||||
|
||||
ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 10) * 10);
|
||||
if (ceilingLimit > 1000) {
|
||||
ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 50) * 50);
|
||||
}
|
||||
|
||||
this.$datapoints.empty();
|
||||
this.$baseline.empty();
|
||||
|
||||
scale = 124 / ceilingLimit;
|
||||
// Var xstep = (280 - 46) / 100;
|
||||
xstep = 2.34;
|
||||
startX = 46 + (100 - points.length) * xstep;
|
||||
calcArray = [];
|
||||
|
||||
for (var x = 0;x < points.length;x++) {
|
||||
calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (136 - ((points[x]) * scale)).toFixed(2));
|
||||
|
||||
circle = document.createElementNS(this.xmlns,'circle');
|
||||
title = document.createElementNS(this.xmlns,'title');
|
||||
|
||||
if (parseInt(this.mode) === 5) {
|
||||
occupied = (points[x] > 920) ? 'purple' : 'red';
|
||||
} else if (parseInt(this.mode) === 3) {
|
||||
occupied = (points[x] > 579) ? 'purple' : 'red';
|
||||
} else {
|
||||
occupied = 'red';
|
||||
}
|
||||
|
||||
circle.setAttributeNS(null,'fill',occupied);
|
||||
circle.setAttributeNS(null,'cx',(startX + (x * xstep)).toFixed(2).toString());
|
||||
circle.setAttributeNS(null,'cy',(136 - ((points[x]) * scale)).toFixed(2).toString());
|
||||
circle.setAttributeNS(null,'r','2');
|
||||
circle.setAttributeNS(null,'stroke-width','1');
|
||||
|
||||
title.textContent = data[x];
|
||||
|
||||
circle.appendChild(title);
|
||||
|
||||
this.$datapoints[0].appendChild(circle);
|
||||
}
|
||||
|
||||
console.log('This.mode = ', this.mode);
|
||||
if (parseInt(this.mode) === 3 || parseInt(this.mode) === 5) {
|
||||
var avgLine = (parseInt(this.mode) === 3) ? 526 : 852;
|
||||
|
||||
var bline = document.createElementNS(this.xmlns,'line');
|
||||
bline.setAttributeNS(null,'x1',46);
|
||||
bline.setAttributeNS(null,'y1',(136 - (avgLine * scale)).toFixed(2).toString());
|
||||
bline.setAttributeNS(null,'x2',280);
|
||||
bline.setAttributeNS(null,'y2',(136 - (avgLine * scale)).toFixed(2).toString());
|
||||
|
||||
bline.setAttributeNS(null,'stroke','#00ff00');
|
||||
bline.setAttributeNS(null,'stroke-width','1');
|
||||
|
||||
this.$baseline[0].appendChild(bline);
|
||||
|
||||
|
||||
|
||||
bline = document.createElementNS(this.xmlns,'line');
|
||||
bline.setAttributeNS(null,'x1',46);
|
||||
bline.setAttributeNS(null,'y1',(136 - (4884 * scale)).toFixed(2).toString());
|
||||
bline.setAttributeNS(null,'x2',280);
|
||||
bline.setAttributeNS(null,'y2',(136 - (4884 * scale)).toFixed(2).toString());
|
||||
|
||||
bline.setAttributeNS(null,'stroke','#00ff55');
|
||||
bline.setAttributeNS(null,'stroke-width','1');
|
||||
this.$baseline[0].appendChild(bline);
|
||||
}
|
||||
|
||||
if (parseInt(this.mode) === 3) {
|
||||
var bline = document.createElementNS(this.xmlns,'line');
|
||||
bline.setAttributeNS(null,'x1',46);
|
||||
bline.setAttributeNS(null,'y1',(136 - (632 * scale)).toFixed(2).toString());
|
||||
bline.setAttributeNS(null,'x2',280);
|
||||
bline.setAttributeNS(null,'y2',(136 - (632 * scale)).toFixed(2).toString());
|
||||
|
||||
bline.setAttributeNS(null,'stroke','yellow');
|
||||
bline.setAttributeNS(null,'stroke-width','1');
|
||||
|
||||
this.$baseline[0].appendChild(bline);
|
||||
|
||||
var bline = document.createElementNS(this.xmlns,'line');
|
||||
bline.setAttributeNS(null,'x1',46);
|
||||
bline.setAttributeNS(null,'y1',(136 - (1045 * scale)).toFixed(2).toString());
|
||||
bline.setAttributeNS(null,'x2',280);
|
||||
bline.setAttributeNS(null,'y2',(136 - (1045 * scale)).toFixed(2).toString());
|
||||
|
||||
bline.setAttributeNS(null,'stroke','red');
|
||||
bline.setAttributeNS(null,'stroke-width','1');
|
||||
|
||||
this.$baseline[0].appendChild(bline);
|
||||
|
||||
}
|
||||
|
||||
|
||||
this.$line[0].setAttribute('points',calcArray.join(' '));
|
||||
|
||||
this.$maxY[0].textContent = ceilingLimit;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var DeviceCollection = new Backbone.Collection;
|
||||
|
||||
var mdotCollection = new mDotCollection();
|
||||
|
||||
var mainSettings = new MainModel();
|
||||
var mainview = new MainView({collection: mdotCollection, model: mainSettings});
|
||||
|
||||
var mdot = new MDOT({collection: mdotCollection});
|
||||
|
||||
var grapher = new GraphView({collection: DeviceCollection});
|
||||
|
||||
})(jQuery);
|
1920
app/lib/backbone.js
Normal file
61
app/lib/base64.js
Normal file
@ -0,0 +1,61 @@
|
||||
;(function () {
|
||||
|
||||
var object = typeof exports != 'undefined' ? exports : self; // #8: web workers
|
||||
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
|
||||
function InvalidCharacterError(message) {
|
||||
this.message = message;
|
||||
}
|
||||
InvalidCharacterError.prototype = new Error;
|
||||
InvalidCharacterError.prototype.name = 'InvalidCharacterError';
|
||||
|
||||
// encoder
|
||||
// [https://gist.github.com/999166] by [https://github.com/nignag]
|
||||
object.btoa || (
|
||||
object.btoa = function (input) {
|
||||
var str = String(input);
|
||||
for (
|
||||
// initialize result and counter
|
||||
var block, charCode, idx = 0, map = chars, output = '';
|
||||
// if the next str index does not exist:
|
||||
// change the mapping table to "="
|
||||
// check if d has no fractional digits
|
||||
str.charAt(idx | 0) || (map = '=', idx % 1);
|
||||
// "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
|
||||
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
|
||||
) {
|
||||
charCode = str.charCodeAt(idx += 3/4);
|
||||
if (charCode > 0xFF) {
|
||||
throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
|
||||
}
|
||||
block = block << 8 | charCode;
|
||||
}
|
||||
return output;
|
||||
});
|
||||
|
||||
// decoder
|
||||
// [https://gist.github.com/1020396] by [https://github.com/atk]
|
||||
object.atob || (
|
||||
object.atob = function (input) {
|
||||
var str = String(input).replace(/=+$/, '');
|
||||
if (str.length % 4 == 1) {
|
||||
throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
|
||||
}
|
||||
for (
|
||||
// initialize result and counters
|
||||
var bc = 0, bs, buffer, idx = 0, output = '';
|
||||
// get next character
|
||||
buffer = str.charAt(idx++);
|
||||
// character found in table? initialize bit storage and add its ascii value;
|
||||
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
|
||||
// and if not first of each 4 characters,
|
||||
// convert the first 8 bits to one ascii character
|
||||
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
|
||||
) {
|
||||
// try to find character in table (0-63, not found => -1)
|
||||
buffer = chars.indexOf(buffer);
|
||||
}
|
||||
return output;
|
||||
});
|
||||
|
||||
}());
|