Add lamassu-admin-elm to this repo (#185)
This commit is contained in:
parent
5ee7e40872
commit
f4fc9d6328
134 changed files with 28171 additions and 83 deletions
|
|
@ -1,3 +0,0 @@
|
||||||
[ignore]
|
|
||||||
|
|
||||||
[include]
|
|
||||||
66
.jscsrc
66
.jscsrc
|
|
@ -1,66 +0,0 @@
|
||||||
{
|
|
||||||
"requireCurlyBraces": [
|
|
||||||
"for",
|
|
||||||
"while",
|
|
||||||
"do",
|
|
||||||
"try",
|
|
||||||
"catch"
|
|
||||||
],
|
|
||||||
"requireOperatorBeforeLineBreak": true,
|
|
||||||
"requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties",
|
|
||||||
"maximumLineLength": {
|
|
||||||
"value": 80,
|
|
||||||
"allowComments": true,
|
|
||||||
"allowRegex": true
|
|
||||||
},
|
|
||||||
"validateIndentation": 2,
|
|
||||||
"validateQuoteMarks": "'",
|
|
||||||
|
|
||||||
"disallowMultipleLineStrings": true,
|
|
||||||
"disallowMixedSpacesAndTabs": true,
|
|
||||||
"disallowTrailingWhitespace": true,
|
|
||||||
"disallowSpaceAfterPrefixUnaryOperators": true,
|
|
||||||
"disallowMultipleVarDecl": true,
|
|
||||||
|
|
||||||
"requireSpaceAfterKeywords": [
|
|
||||||
"if",
|
|
||||||
"else",
|
|
||||||
"for",
|
|
||||||
"while",
|
|
||||||
"do",
|
|
||||||
"switch",
|
|
||||||
"return",
|
|
||||||
"try",
|
|
||||||
"catch"
|
|
||||||
],
|
|
||||||
"requireSpaceBeforeBinaryOperators": [
|
|
||||||
"=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
|
|
||||||
"&=", "|=", "^=", "+=",
|
|
||||||
|
|
||||||
"+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
|
|
||||||
"|", "^", "&&", "||", "===", "==", ">=",
|
|
||||||
"<=", "<", ">", "!=", "!=="
|
|
||||||
],
|
|
||||||
"requireSpaceAfterBinaryOperators": true,
|
|
||||||
"requireSpacesInConditionalExpression": true,
|
|
||||||
"requireSpaceBeforeBlockStatements": true,
|
|
||||||
"requireLineFeedAtFileEnd": true,
|
|
||||||
"requireSpacesInFunctionExpression": {
|
|
||||||
"beforeOpeningCurlyBrace": true
|
|
||||||
},
|
|
||||||
"disallowSpacesInAnonymousFunctionExpression": {
|
|
||||||
"beforeOpeningRoundBrace": true
|
|
||||||
},
|
|
||||||
"disallowSpacesInsideObjectBrackets": "all",
|
|
||||||
"disallowSpacesInsideArrayBrackets": "all",
|
|
||||||
"disallowSpacesInsideParentheses": true,
|
|
||||||
|
|
||||||
|
|
||||||
"validateJSDoc": {
|
|
||||||
"checkParamNames": true,
|
|
||||||
"requireParamTypes": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"disallowMultipleLineBreaks": true,
|
|
||||||
"disallowNewlineBeforeBlockStatements": true
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"trailing": false,
|
|
||||||
"node": true,
|
|
||||||
"unused": "last-param",
|
|
||||||
"globalstrict": true
|
|
||||||
}
|
|
||||||
8
lamassu-admin-elm/.gitignore
vendored
Normal file
8
lamassu-admin-elm/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
node_modules
|
||||||
|
elm-stuff
|
||||||
|
|
||||||
|
build/styles.css
|
||||||
|
build/elm.js
|
||||||
|
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
28
lamassu-admin-elm/README.md
Normal file
28
lamassu-admin-elm/README.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
# lamassu-admin
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Start the hot-reloading webpack dev server:
|
||||||
|
|
||||||
|
npm start
|
||||||
|
|
||||||
|
Navigate to <http://localhost:8080>.
|
||||||
|
|
||||||
|
Any changes you make to your files (.elm, .js, .css, etc.) will trigger
|
||||||
|
a hot reload.
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
When you're ready to deploy:
|
||||||
|
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
This will create a `dist` folder:
|
||||||
|
|
||||||
|
.
|
||||||
|
├── dist
|
||||||
|
│ ├── index.html
|
||||||
|
│ ├── 5df766af1ced8ff1fe0a.css
|
||||||
|
│ └── 5df766af1ced8ff1fe0a.js
|
||||||
|
|
||||||
24
lamassu-admin-elm/UNLICENSE
Normal file
24
lamassu-admin-elm/UNLICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org>
|
||||||
18
lamassu-admin-elm/build/bower.json
Normal file
18
lamassu-admin-elm/build/bower.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "lamassu-admin-elm",
|
||||||
|
"homepage": "https://github.com/lamassu/lamassu-admin-elm",
|
||||||
|
"authors": [
|
||||||
|
"Josh Harvey <josh@lamassu.is>"
|
||||||
|
],
|
||||||
|
"description": "",
|
||||||
|
"main": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"private": true,
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
}
|
||||||
27
lamassu-admin-elm/build/bower_components/gridism/.bower.json
vendored
Normal file
27
lamassu-admin-elm/build/bower_components/gridism/.bower.json
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "gridism",
|
||||||
|
"version": "0.2.2",
|
||||||
|
"author": "Coby Chapple",
|
||||||
|
"homepage": "http://cobyism.com/gridism",
|
||||||
|
"main": "./gridism.css",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/cobyism/gridism.git"
|
||||||
|
},
|
||||||
|
"ignore": [
|
||||||
|
"shapeshifter/",
|
||||||
|
"**/*.yml",
|
||||||
|
"**/*.html"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"_release": "0.2.2",
|
||||||
|
"_resolution": {
|
||||||
|
"type": "version",
|
||||||
|
"tag": "0.2.2",
|
||||||
|
"commit": "490be0b6813d701dcc35a82b0bcc8f639e5ad63f"
|
||||||
|
},
|
||||||
|
"_source": "https://github.com/cobyism/gridism.git",
|
||||||
|
"_target": "^0.2.2",
|
||||||
|
"_originalSource": "gridism",
|
||||||
|
"_direct": true
|
||||||
|
}
|
||||||
19
lamassu-admin-elm/build/bower_components/gridism/LICENSE
vendored
Normal file
19
lamassu-admin-elm/build/bower_components/gridism/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2013 Coby Chapple.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the 'Software'), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
80
lamassu-admin-elm/build/bower_components/gridism/README.md
vendored
Normal file
80
lamassu-admin-elm/build/bower_components/gridism/README.md
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Gridism
|
||||||
|
|
||||||
|
A simple responsive CSS grid. [View the demo →](http://cobyism.com/gridism/)
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
### My process
|
||||||
|
|
||||||
|
When I design web layouts, my thought process usually goes something like this:
|
||||||
|
|
||||||
|
> Alright, in this section, I want a bit that’s one third of the section’s width,
|
||||||
|
> and then next to that I want another bit that’s two thirds of the sections’s width.
|
||||||
|
> Now, in the next section…
|
||||||
|
|
||||||
|
I don’t think in 12 or 16 column grids. Instead, my mental model basically just consists of the page being divided up into multiple full-width vertical sections, and each vertical section being divided up into simple fractions of the section width.
|
||||||
|
|
||||||
|
### Existing grid frameworks
|
||||||
|
|
||||||
|
Most frameworks I’ve used don’t match that thought process *at all*. I usually have to:
|
||||||
|
|
||||||
|
1. Remember how many columns are in the grid for the particular framework I’m using.
|
||||||
|
1. Decide how I want to divide up this particular section’s content.
|
||||||
|
1. Mentally do the conversion from what I want to see (one quarter + three quarters, for example) into the number of columns I need for the grid I’m using.
|
||||||
|
1. Remember the class naming structure for the framework I’m using. Is it `.span3`, `.grid_3`, `.col-3`, or something else altogether?
|
||||||
|
1. Deal with other hassles like clearing floats, messing with column padding to have the gutters look right, indicating which elements are the first in a row, and so forth.
|
||||||
|
|
||||||
|
Only the second step should be necessary.
|
||||||
|
|
||||||
|
### Gridism’s Goals
|
||||||
|
|
||||||
|
I couldn’t find a framework that matched this mental model of how I work, so I started hacking on Gridism with the following goals:
|
||||||
|
|
||||||
|
- Class names should be memorable and self-evident.
|
||||||
|
- Gutters and basic content padding should be taken care of.
|
||||||
|
- Clearing floats should be done automatically.
|
||||||
|
- Wrapped grid sections should be independant of vertical page sections.
|
||||||
|
- Frequently required utility classes should be provided.
|
||||||
|
- Common patterns for Responsive Design™ should be built-in.
|
||||||
|
|
||||||
|
I hope you find that this project is living up to those goals. If not, please [create an issue](https://github.com/cobyism/gridism/issues/new) and let me know.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### 1. Get the files
|
||||||
|
|
||||||
|
The easiest way to use Gridism in your project is via the [Bower](http://twitter.github.com/bower) package manager.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bower install gridism
|
||||||
|
```
|
||||||
|
|
||||||
|
Elsewise, [download the zip folder](https://github.com/cobyism/gridism/archive/gh-pages.zip), extract it, and copy `gridism.css` into your project’s folder. Boom. Done.
|
||||||
|
|
||||||
|
### 2. Link the stylesheet
|
||||||
|
|
||||||
|
Add the following stylesheet to your HTML’s `<head>` section:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="stylesheet" href="bower_components/gridism/gridism.css">
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** If you didn’t install using Bower, you need to adjust the path of CSS file to match your file structure.
|
||||||
|
|
||||||
|
### 3. Viewport scale
|
||||||
|
|
||||||
|
Add the following meta tag to your HTML’s `<head>` section:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
```
|
||||||
|
|
||||||
|
Without this meta tag, mobiles and tablets might load your page as a scaled-down version of the desktop size, instead of resizing the content to match the device’s actual viewport width.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
I’d :heart: to receive contributions to this project. It doesn’t matter if it’s just a typo, or if you’re proposing an overhaul of the entire project—I’ll gladly take a look at your changes. Fork at will! :grinning:.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Go nuts. See [LICENSE](https://github.com/cobyism/gridism/blob/gh-pages/LICENSE) (MIT).
|
||||||
17
lamassu-admin-elm/build/bower_components/gridism/bower.json
vendored
Normal file
17
lamassu-admin-elm/build/bower_components/gridism/bower.json
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "gridism",
|
||||||
|
"version": "0.2.1",
|
||||||
|
"author": "Coby Chapple",
|
||||||
|
"homepage": "http://cobyism.com/gridism",
|
||||||
|
"main": "./gridism.css",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/cobyism/gridism.git"
|
||||||
|
},
|
||||||
|
"ignore": [
|
||||||
|
"shapeshifter/",
|
||||||
|
"**/*.yml",
|
||||||
|
"**/*.html"
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
132
lamassu-admin-elm/build/bower_components/gridism/gridism.css
vendored
Normal file
132
lamassu-admin-elm/build/bower_components/gridism/gridism.css
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Gridism
|
||||||
|
* A simple, responsive, and handy CSS grid by @cobyism
|
||||||
|
* https://github.com/cobyism/gridism
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Preserve some sanity */
|
||||||
|
.grid,
|
||||||
|
.unit {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up some rules to govern the grid */
|
||||||
|
.grid {
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.grid .unit {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This ensures the outer gutters are equal to the (doubled) inner gutters. */
|
||||||
|
.grid .unit:first-child { padding-left: 20px; }
|
||||||
|
.grid .unit:last-child { padding-right: 20px; }
|
||||||
|
|
||||||
|
/* Nested grids already have padding though, so let's nuke it */
|
||||||
|
.unit .unit:first-child { padding-left: 0; }
|
||||||
|
.unit .unit:last-child { padding-right: 0; }
|
||||||
|
.unit .grid:first-child > .unit { padding-top: 0; }
|
||||||
|
.unit .grid:last-child > .unit { padding-bottom: 0; }
|
||||||
|
|
||||||
|
/* Let people nuke the gutters/padding completely in a couple of ways */
|
||||||
|
.no-gutters .unit,
|
||||||
|
.unit.no-gutters {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapping at a maximum width is optional */
|
||||||
|
.wrap .grid,
|
||||||
|
.grid.wrap {
|
||||||
|
max-width: 978px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Width classes also have shorthand versions numbered as fractions
|
||||||
|
* For example: for a grid unit 1/3 (one third) of the parent width,
|
||||||
|
* simply apply class="w-1-3" to the element. */
|
||||||
|
.grid .whole, .grid .w-1-1 { width: 100%; }
|
||||||
|
.grid .half, .grid .w-1-2 { width: 50%; }
|
||||||
|
.grid .one-third, .grid .w-1-3 { width: 33.3332%; }
|
||||||
|
.grid .two-thirds, .grid .w-2-3 { width: 66.6665%; }
|
||||||
|
.grid .one-quarter,
|
||||||
|
.grid .one-fourth, .grid .w-1-4 { width: 25%; }
|
||||||
|
.grid .three-quarters,
|
||||||
|
.grid .three-fourths, .grid .w-3-4 { width: 75%; }
|
||||||
|
.grid .one-fifth, .grid .w-1-5 { width: 20%; }
|
||||||
|
.grid .two-fifths, .grid .w-2-5 { width: 40%; }
|
||||||
|
.grid .three-fifths, .grid .w-3-5 { width: 60%; }
|
||||||
|
.grid .four-fifths, .grid .w-4-5 { width: 80%; }
|
||||||
|
.grid .golden-small, .grid .w-g-s { width: 38.2716%; } /* Golden section: smaller piece */
|
||||||
|
.grid .golden-large, .grid .w-g-l { width: 61.7283%; } /* Golden section: larger piece */
|
||||||
|
|
||||||
|
/* Clearfix after every .grid */
|
||||||
|
.grid {
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
.grid:before, .grid:after {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.grid:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Utility classes */
|
||||||
|
.align-center { text-align: center; }
|
||||||
|
.align-left { text-align: left; }
|
||||||
|
.align-right { text-align: right; }
|
||||||
|
.pull-left { float: left; }
|
||||||
|
.pull-right { float: right; }
|
||||||
|
|
||||||
|
/* A property for a better rendering of images in units: in
|
||||||
|
this way bigger pictures are just resized if the unit
|
||||||
|
becomes smaller */
|
||||||
|
.unit img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide elements using this class by default */
|
||||||
|
.only-on-mobiles {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Stuff */
|
||||||
|
@media screen and (max-width: 568px) {
|
||||||
|
/* Stack anything that isn't full-width on smaller screens
|
||||||
|
and doesn't provide the no-stacking-on-mobiles class */
|
||||||
|
.grid:not(.no-stacking-on-mobiles) > .unit {
|
||||||
|
width: 100% !important;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
.unit .grid .unit {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sometimes, you just want to be different on small screens */
|
||||||
|
.center-on-mobiles {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
.hide-on-mobiles {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.only-on-mobiles {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand the wrap a bit further on larger screens */
|
||||||
|
@media screen and (min-width: 1180px) {
|
||||||
|
.wider .grid,
|
||||||
|
.grid.wider {
|
||||||
|
max-width: 1180px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
lamassu-admin-elm/build/bower_components/qr-code/.bower.json
vendored
Normal file
40
lamassu-admin-elm/build/bower_components/qr-code/.bower.json
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"name": "qr-code",
|
||||||
|
"version": "0.1.8",
|
||||||
|
"homepage": "https://github.com/educastellano/qr-code",
|
||||||
|
"authors": [
|
||||||
|
"Eduard Castellano <educastellano08@gmail.com>"
|
||||||
|
],
|
||||||
|
"description": "Web Component for generating QR codes",
|
||||||
|
"main": "src/qr-code.js",
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"qrcode",
|
||||||
|
"qr-code",
|
||||||
|
"webcomponent",
|
||||||
|
"customelement",
|
||||||
|
"web-components"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests",
|
||||||
|
"demo"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"qrjs": "~0.1.2"
|
||||||
|
},
|
||||||
|
"_release": "0.1.8",
|
||||||
|
"_resolution": {
|
||||||
|
"type": "version",
|
||||||
|
"tag": "v0.1.8",
|
||||||
|
"commit": "28a413834c62d8ec7f5b3f3005fe2ee78e47e647"
|
||||||
|
},
|
||||||
|
"_source": "https://github.com/educastellano/qr-code.git",
|
||||||
|
"_target": "^0.1.8",
|
||||||
|
"_originalSource": "webcomponent-qr-code",
|
||||||
|
"_direct": true
|
||||||
|
}
|
||||||
94
lamassu-admin-elm/build/bower_components/qr-code/README.md
vendored
Normal file
94
lamassu-admin-elm/build/bower_components/qr-code/README.md
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
# <qr-code>
|
||||||
|
|
||||||
|
Web Component for generating QR Codes, using (a [fork](https://github.com/educastellano/qr.js) of) [qr.js](https://github.com/lifthrasiir/qr.js) lib.
|
||||||
|
|
||||||
|
> Maintained by [Eduard Castellano](https://github.com/educastellano).
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
> [Check it live](http://educastellano.github.io/qr-code/demo).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* **NPM and Browserify** ([polyfill](https://github.com/WebComponents/webcomponentsjs) and the component):
|
||||||
|
|
||||||
|
Install:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install webcomponents.js
|
||||||
|
npm install webcomponent-qr-code
|
||||||
|
```
|
||||||
|
|
||||||
|
Import:
|
||||||
|
|
||||||
|
```js
|
||||||
|
require('webcomponents.js');
|
||||||
|
require('webcomponent-qr-code');
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Bower** ([polyfill](https://github.com/WebComponents/webcomponentsjs), [qr.js](https://github.com/educastellano/qr.js) and the component):
|
||||||
|
|
||||||
|
Install:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bower install webcomponentsjs
|
||||||
|
bower install webcomponent-qr-code
|
||||||
|
```
|
||||||
|
|
||||||
|
Import:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||||
|
<script src="bower_components/qrjs/qr.js"></script>
|
||||||
|
<script src="bower_components/webcomponent-qr-code/src/qr-code.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
> You can also import the component with [HTML Imports](http://w3c.github.io/webcomponents/spec/imports/), but you still need to import the polyfill and the qr.js lib separately:
|
||||||
|
>
|
||||||
|
> ```html
|
||||||
|
> <link rel="import" href="bower_components/webcomponent-qr-code/src/qr-code.html">
|
||||||
|
> ```
|
||||||
|
|
||||||
|
* **Start using it!**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<qr-code data="hello world!"></qr-code>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
Attribute | Options | Default | Description
|
||||||
|
--- | --- | --- | ---
|
||||||
|
`data` | *string* | `null` | The information encoded by the QR code.
|
||||||
|
`format` | `png`, `html`, `svg` | `png` | Format of the QR code rendered inside the component.
|
||||||
|
`modulesize` | *int* | `5` | Size of the modules in *pixels*.
|
||||||
|
`margin` | *int* | `4` | Margin of the QR code in *modules*.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork it!
|
||||||
|
2. Create your feature branch: `git checkout -b my-new-feature`
|
||||||
|
3. Commit your changes: `git commit -m 'Add some feature'`
|
||||||
|
4. Push to the branch: `git push origin my-new-feature`
|
||||||
|
5. Submit a pull request :D
|
||||||
|
|
||||||
|
## History
|
||||||
|
|
||||||
|
* v0.1.7 April 11, 2015
|
||||||
|
* Support for SVG
|
||||||
|
* v0.1.6 April 10, 2015
|
||||||
|
* Default attributes
|
||||||
|
* qr.js removed and used as a dependency
|
||||||
|
* Available in NPM
|
||||||
|
* v0.1.1 March 31, 2015
|
||||||
|
* Framework-agnostic webcomponent (no use of Polymer)
|
||||||
|
* Available in Bower
|
||||||
|
* v0.0.1 September 18, 2013
|
||||||
|
* Started project using [boilerplate-element](https://github.com/customelements/boilerplate-element)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT License](http://opensource.org/licenses/MIT)
|
||||||
30
lamassu-admin-elm/build/bower_components/qr-code/bower.json
vendored
Normal file
30
lamassu-admin-elm/build/bower_components/qr-code/bower.json
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "qr-code",
|
||||||
|
"version": "0.1.7",
|
||||||
|
"homepage": "https://github.com/educastellano/qr-code",
|
||||||
|
"authors": [
|
||||||
|
"Eduard Castellano <educastellano08@gmail.com>"
|
||||||
|
],
|
||||||
|
"description": "Web Component for generating QR codes",
|
||||||
|
"main": "src/qr-code.js",
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"qrcode",
|
||||||
|
"qr-code",
|
||||||
|
"webcomponent",
|
||||||
|
"customelement",
|
||||||
|
"web-components"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests",
|
||||||
|
"demo"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"qrjs": "~0.1.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
lamassu-admin-elm/build/bower_components/qr-code/index.html
vendored
Normal file
10
lamassu-admin-elm/build/bower_components/qr-code/index.html
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title><qr-code></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="demo">Demo here</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1
lamassu-admin-elm/build/bower_components/qr-code/index.js
vendored
Normal file
1
lamassu-admin-elm/build/bower_components/qr-code/index.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
require('./src/qr-code.js')
|
||||||
29
lamassu-admin-elm/build/bower_components/qr-code/package.json
vendored
Normal file
29
lamassu-admin-elm/build/bower_components/qr-code/package.json
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "webcomponent-qr-code",
|
||||||
|
"version": "0.1.8",
|
||||||
|
"description": "Web Component for generating QR codes",
|
||||||
|
"main": "qr-code.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/educastellano/qr-code.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"qrcode",
|
||||||
|
"qr-code",
|
||||||
|
"webcomponent",
|
||||||
|
"custom-element"
|
||||||
|
],
|
||||||
|
"author": "Eduard Castellano",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/educastellano/qr-code/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/educastellano/qr-code",
|
||||||
|
"dependencies": {
|
||||||
|
"qrjs": "^0.1.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
56
lamassu-admin-elm/build/bower_components/qr-code/src/polymer/qr-code.html
vendored
Normal file
56
lamassu-admin-elm/build/bower_components/qr-code/src/polymer/qr-code.html
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<polymer-element name="qr-code"
|
||||||
|
attributes="data format modulesize margin">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer('qr-code', {
|
||||||
|
|
||||||
|
format: 'png',
|
||||||
|
|
||||||
|
dataChanged: function () {
|
||||||
|
this.generate();
|
||||||
|
},
|
||||||
|
|
||||||
|
generate: function () {
|
||||||
|
var options = {
|
||||||
|
modulesize: this.modulesize,
|
||||||
|
margin: this.margin === 0 ? -1 : this.margin
|
||||||
|
};
|
||||||
|
if (this.format === 'png') {
|
||||||
|
this.generatePNG(options);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.generateHTML(options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
generatePNG: function (options) {
|
||||||
|
var img;
|
||||||
|
try {
|
||||||
|
img = document.createElement('img');
|
||||||
|
img.src = QRCode.generatePNG(this.data, options);
|
||||||
|
this.clear();
|
||||||
|
this.appendChild(img);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log('no canvas support');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
generateHTML: function (options) {
|
||||||
|
var div = QRCode.generateHTML(this.data, options);
|
||||||
|
this.clear();
|
||||||
|
this.appendChild(div);
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: function () {
|
||||||
|
var i;
|
||||||
|
for (i=0; i<this.children.length; i++) {
|
||||||
|
this.children[i].parentNode.removeChild(this.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</polymer-element>
|
||||||
1
lamassu-admin-elm/build/bower_components/qr-code/src/qr-code.html
vendored
Normal file
1
lamassu-admin-elm/build/bower_components/qr-code/src/qr-code.html
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<script src="qr-code.js"></script>
|
||||||
144
lamassu-admin-elm/build/bower_components/qr-code/src/qr-code.js
vendored
Normal file
144
lamassu-admin-elm/build/bower_components/qr-code/src/qr-code.js
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
(function(definition) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
define(['QRCode'], definition);
|
||||||
|
} else if (typeof module === 'object' && module.exports) {
|
||||||
|
var QRCode = require('qrjs');
|
||||||
|
module.exports = definition(QRCode);
|
||||||
|
} else {
|
||||||
|
definition(window.QRCode);
|
||||||
|
}
|
||||||
|
})(function(QRCode) {
|
||||||
|
//
|
||||||
|
// Prototype
|
||||||
|
//
|
||||||
|
var proto = Object.create(HTMLElement.prototype, {
|
||||||
|
//
|
||||||
|
// Attributes
|
||||||
|
//
|
||||||
|
attrs: {
|
||||||
|
value: {
|
||||||
|
data: null,
|
||||||
|
format: 'png',
|
||||||
|
modulesize: 5,
|
||||||
|
margin: 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defineAttributes: {
|
||||||
|
value: function () {
|
||||||
|
var attrs = Object.keys(this.attrs),
|
||||||
|
attr;
|
||||||
|
for (var i=0; i<attrs.length; i++) {
|
||||||
|
attr = attrs[i];
|
||||||
|
(function (attr) {
|
||||||
|
Object.defineProperty(this, attr, {
|
||||||
|
get: function () {
|
||||||
|
var value = this.getAttribute(attr);
|
||||||
|
return value === null ? this.attrs[attr] : value;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this.setAttribute(attr, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}.bind(this))(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// LifeCycle Callbacks
|
||||||
|
//
|
||||||
|
createdCallback: {
|
||||||
|
value: function () {
|
||||||
|
this.createShadowRoot();
|
||||||
|
this.defineAttributes();
|
||||||
|
this.generate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
attributeChangedCallback: {
|
||||||
|
value: function (attrName, oldVal, newVal) {
|
||||||
|
var fn = this[attrName+'Changed'];
|
||||||
|
if (fn && typeof fn === 'function') {
|
||||||
|
fn.call(this, oldVal, newVal);
|
||||||
|
}
|
||||||
|
this.generate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Methods
|
||||||
|
//
|
||||||
|
getOptions: {
|
||||||
|
value: function () {
|
||||||
|
var modulesize = this.modulesize,
|
||||||
|
margin = this.margin;
|
||||||
|
return {
|
||||||
|
modulesize: modulesize !== null ? parseInt(modulesize) : modulesize,
|
||||||
|
margin: margin !== null ? parseInt(margin) : margin
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
generate: {
|
||||||
|
value: function () {
|
||||||
|
if (this.data !== null) {
|
||||||
|
if (this.format === 'png') {
|
||||||
|
this.generatePNG();
|
||||||
|
}
|
||||||
|
else if (this.format === 'html') {
|
||||||
|
this.generateHTML();
|
||||||
|
}
|
||||||
|
else if (this.format === 'svg') {
|
||||||
|
this.generateSVG();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.shadowRoot.innerHTML = '<div>qr-code: '+ this.format +' not supported!</div>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.shadowRoot.innerHTML = '<div>qr-code: no data!</div>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
generatePNG: {
|
||||||
|
value: function () {
|
||||||
|
try {
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.src = QRCode.generatePNG(this.data, this.getOptions());
|
||||||
|
this.clear();
|
||||||
|
this.shadowRoot.appendChild(img);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.shadowRoot.innerHTML = '<div>qr-code: no canvas support!</div>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
generateHTML: {
|
||||||
|
value: function () {
|
||||||
|
var div = QRCode.generateHTML(this.data, this.getOptions());
|
||||||
|
this.clear();
|
||||||
|
this.shadowRoot.appendChild(div);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
generateSVG: {
|
||||||
|
value: function () {
|
||||||
|
var div = QRCode.generateSVG(this.data, this.getOptions());
|
||||||
|
this.clear();
|
||||||
|
this.shadowRoot.appendChild(div);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear: {
|
||||||
|
value: function () {
|
||||||
|
while (this.shadowRoot.lastChild) {
|
||||||
|
this.shadowRoot.removeChild(this.shadowRoot.lastChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//
|
||||||
|
// Register
|
||||||
|
//
|
||||||
|
document.registerElement('qr-code', {
|
||||||
|
prototype: proto
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
31
lamassu-admin-elm/build/bower_components/qrcodejs/.bower.json
vendored
Normal file
31
lamassu-admin-elm/build/bower_components/qrcodejs/.bower.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "qrcodejs",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"homepage": "https://github.com/CatTail/qrcodejs",
|
||||||
|
"authors": [
|
||||||
|
"davidshimjs ssm0123@gmail.com"
|
||||||
|
],
|
||||||
|
"description": "Cross-browser QRCode generator for javascript",
|
||||||
|
"main": "qrcode.js",
|
||||||
|
"keywords": [
|
||||||
|
"qrcode"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
],
|
||||||
|
"_release": "0.1.0",
|
||||||
|
"_resolution": {
|
||||||
|
"type": "version",
|
||||||
|
"tag": "v0.1.0",
|
||||||
|
"commit": "71340740270b3c9d797ecaa7d7a75af36037217d"
|
||||||
|
},
|
||||||
|
"_source": "https://github.com/CatTail/qrcodejs.git",
|
||||||
|
"_target": "^0.1.0",
|
||||||
|
"_originalSource": "qrcodejs",
|
||||||
|
"_direct": true
|
||||||
|
}
|
||||||
14
lamassu-admin-elm/build/bower_components/qrcodejs/LICENSE
vendored
Normal file
14
lamassu-admin-elm/build/bower_components/qrcodejs/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
---------------------
|
||||||
|
Copyright (c) 2012 davidshimjs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge,
|
||||||
|
to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction,
|
||||||
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
43
lamassu-admin-elm/build/bower_components/qrcodejs/README.md
vendored
Normal file
43
lamassu-admin-elm/build/bower_components/qrcodejs/README.md
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# QRCode.js
|
||||||
|
QRCode.js is javascript library for making QRCode. QRCode.js supports Cross-browser with HTML5 Canvas and table tag in DOM.
|
||||||
|
QRCode.js has no dependencies.
|
||||||
|
|
||||||
|
## Basic Usages
|
||||||
|
```
|
||||||
|
<div id="qrcode"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
new QRCode(document.getElementById("qrcode"), "http://jindo.dev.naver.com/collie");
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
or with some options
|
||||||
|
|
||||||
|
```
|
||||||
|
var qrcode = new QRCode("test", {
|
||||||
|
text: "http://jindo.dev.naver.com/collie",
|
||||||
|
width: 128,
|
||||||
|
height: 128,
|
||||||
|
colorDark : "#000000",
|
||||||
|
colorLight : "#ffffff",
|
||||||
|
correctLevel : QRCode.CorrectLevel.H
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
and you can use some methods
|
||||||
|
|
||||||
|
```
|
||||||
|
qrcode.clear(); // clear the code.
|
||||||
|
qrcode.makeCode("http://naver.com"); // make another code.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Browser Compatibility
|
||||||
|
IE6~10, Chrome, Firefox, Safari, Opera, Mobile Safari, Android, Windows Mobile, ETC.
|
||||||
|
|
||||||
|
## License
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
twitter @davidshimjs
|
||||||
|
|
||||||
|
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||||
|
|
||||||
21
lamassu-admin-elm/build/bower_components/qrcodejs/bower.json
vendored
Normal file
21
lamassu-admin-elm/build/bower_components/qrcodejs/bower.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "qrcodejs",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"homepage": "https://github.com/CatTail/qrcodejs",
|
||||||
|
"authors": [
|
||||||
|
"davidshimjs ssm0123@gmail.com"
|
||||||
|
],
|
||||||
|
"description": "Cross-browser QRCode generator for javascript",
|
||||||
|
"main": "qrcode.js",
|
||||||
|
"keywords": [
|
||||||
|
"qrcode"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
}
|
||||||
44
lamassu-admin-elm/build/bower_components/qrcodejs/index.html
vendored
Normal file
44
lamassu-admin-elm/build/bower_components/qrcodejs/index.html
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
|
||||||
|
<head>
|
||||||
|
<title>Cross-Browser QRCode generator for Javascript</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
|
||||||
|
<script type="text/javascript" src="jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="qrcode.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<input id="text" type="text" value="http://jindo.dev.naver.com/collie" style="width:80%" /><br />
|
||||||
|
<div id="qrcode" style="width:100px; height:100px; margin-top:15px;"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var qrcode = new QRCode(document.getElementById("qrcode"), {
|
||||||
|
width : 100,
|
||||||
|
height : 100
|
||||||
|
});
|
||||||
|
|
||||||
|
function makeCode () {
|
||||||
|
var elText = document.getElementById("text");
|
||||||
|
|
||||||
|
if (!elText.value) {
|
||||||
|
alert("Input a text");
|
||||||
|
elText.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qrcode.makeCode(elText.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
makeCode();
|
||||||
|
|
||||||
|
$("#text").
|
||||||
|
on("blur", function () {
|
||||||
|
makeCode();
|
||||||
|
}).
|
||||||
|
on("keydown", function (e) {
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
makeCode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
37
lamassu-admin-elm/build/bower_components/qrcodejs/index.svg
vendored
Normal file
37
lamassu-admin-elm/build/bower_components/qrcodejs/index.svg
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" standalone="yes"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-50 0 200 100">
|
||||||
|
<g id="qrcode"/>
|
||||||
|
<foreignObject x="-50" y="0" width="100" height="100">
|
||||||
|
<body xmlns="http://www.w3.org/1999/xhtml" style="padding:0; margin:0">
|
||||||
|
<div style="padding:inherit; margin:inherit; height:100%">
|
||||||
|
<textarea id="text" style="height:100%; width:100%; position:absolute; margin:inherit; padding:inherit">james</textarea>
|
||||||
|
</div>
|
||||||
|
<script type="application/ecmascript" src="qrcode.js"></script>
|
||||||
|
<script type="application/ecmascript">
|
||||||
|
var elem = document.getElementById("qrcode");
|
||||||
|
var qrcode = new QRCode(elem, {
|
||||||
|
width : 100,
|
||||||
|
height : 100
|
||||||
|
});
|
||||||
|
|
||||||
|
function makeCode () {
|
||||||
|
var elText = document.getElementById("text");
|
||||||
|
|
||||||
|
if (elText.value === "") {
|
||||||
|
//alert("Input a text");
|
||||||
|
//elText.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qrcode.makeCode(elText.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
makeCode();
|
||||||
|
|
||||||
|
document.getElementById("text").onkeyup = function (e) {
|
||||||
|
makeCode();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</foreignObject>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
2
lamassu-admin-elm/build/bower_components/qrcodejs/jquery.min.js
vendored
Normal file
2
lamassu-admin-elm/build/bower_components/qrcodejs/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
609
lamassu-admin-elm/build/bower_components/qrcodejs/qrcode.js
vendored
Normal file
609
lamassu-admin-elm/build/bower_components/qrcodejs/qrcode.js
vendored
Normal file
|
|
@ -0,0 +1,609 @@
|
||||||
|
/**
|
||||||
|
* @fileoverview
|
||||||
|
* - Using the 'QRCode for Javascript library'
|
||||||
|
* - Fixed dataset of 'QRCode for Javascript library' for support full-spec.
|
||||||
|
* - this library has no dependencies.
|
||||||
|
*
|
||||||
|
* @author davidshimjs
|
||||||
|
* @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a>
|
||||||
|
* @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a>
|
||||||
|
*/
|
||||||
|
var QRCode;
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
// QRCode for JavaScript
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Kazuhiko Arase
|
||||||
|
//
|
||||||
|
// URL: http://www.d-project.com/
|
||||||
|
//
|
||||||
|
// Licensed under the MIT license:
|
||||||
|
// http://www.opensource.org/licenses/mit-license.php
|
||||||
|
//
|
||||||
|
// The word "QR Code" is registered trademark of
|
||||||
|
// DENSO WAVE INCORPORATED
|
||||||
|
// http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
function QR8bitByte(data) {
|
||||||
|
this.mode = QRMode.MODE_8BIT_BYTE;
|
||||||
|
this.data = data;
|
||||||
|
this.parsedData = [];
|
||||||
|
|
||||||
|
// Added to support UTF-8 Characters
|
||||||
|
for (var i = 0, l = this.data.length; i < l; i++) {
|
||||||
|
var byteArray = [];
|
||||||
|
var code = this.data.charCodeAt(i);
|
||||||
|
|
||||||
|
if (code > 0x10000) {
|
||||||
|
byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
|
||||||
|
byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
|
||||||
|
byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
|
||||||
|
byteArray[3] = 0x80 | (code & 0x3F);
|
||||||
|
} else if (code > 0x800) {
|
||||||
|
byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
|
||||||
|
byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
|
||||||
|
byteArray[2] = 0x80 | (code & 0x3F);
|
||||||
|
} else if (code > 0x80) {
|
||||||
|
byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
|
||||||
|
byteArray[1] = 0x80 | (code & 0x3F);
|
||||||
|
} else {
|
||||||
|
byteArray[0] = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parsedData.push(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parsedData = Array.prototype.concat.apply([], this.parsedData);
|
||||||
|
|
||||||
|
if (this.parsedData.length != this.data.length) {
|
||||||
|
this.parsedData.unshift(191);
|
||||||
|
this.parsedData.unshift(187);
|
||||||
|
this.parsedData.unshift(239);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QR8bitByte.prototype = {
|
||||||
|
getLength: function (buffer) {
|
||||||
|
return this.parsedData.length;
|
||||||
|
},
|
||||||
|
write: function (buffer) {
|
||||||
|
for (var i = 0, l = this.parsedData.length; i < l; i++) {
|
||||||
|
buffer.put(this.parsedData[i], 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function QRCodeModel(typeNumber, errorCorrectLevel) {
|
||||||
|
this.typeNumber = typeNumber;
|
||||||
|
this.errorCorrectLevel = errorCorrectLevel;
|
||||||
|
this.modules = null;
|
||||||
|
this.moduleCount = 0;
|
||||||
|
this.dataCache = null;
|
||||||
|
this.dataList = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);}
|
||||||
|
return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row<this.moduleCount;row++){this.modules[row]=new Array(this.moduleCount);for(var col=0;col<this.moduleCount;col++){this.modules[row][col]=null;}}
|
||||||
|
this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(test,maskPattern);if(this.typeNumber>=7){this.setupTypeNumber(test);}
|
||||||
|
if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);}
|
||||||
|
this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}
|
||||||
|
return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row<this.modules.length;row++){var y=row*cs;for(var col=0;col<this.modules[row].length;col++){var x=col*cs;var dark=this.modules[row][col];if(dark){qr_mc.beginFill(0,100);qr_mc.moveTo(x,y);qr_mc.lineTo(x+cs,y);qr_mc.lineTo(x+cs,y+cs);qr_mc.lineTo(x,y+cs);qr_mc.endFill();}}}
|
||||||
|
return qr_mc;},setupTimingPattern:function(){for(var r=8;r<this.moduleCount-8;r++){if(this.modules[r][6]!=null){continue;}
|
||||||
|
this.modules[r][6]=(r%2==0);}
|
||||||
|
for(var c=8;c<this.moduleCount-8;c++){if(this.modules[6][c]!=null){continue;}
|
||||||
|
this.modules[6][c]=(c%2==0);}},setupPositionAdjustPattern:function(){var pos=QRUtil.getPatternPosition(this.typeNumber);for(var i=0;i<pos.length;i++){for(var j=0;j<pos.length;j++){var row=pos[i];var col=pos[j];if(this.modules[row][col]!=null){continue;}
|
||||||
|
for(var r=-2;r<=2;r++){for(var c=-2;c<=2;c++){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}}}},setupTypeNumber:function(test){var bits=QRUtil.getBCHTypeNumber(this.typeNumber);for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;}
|
||||||
|
for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}}
|
||||||
|
for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}}
|
||||||
|
this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}
|
||||||
|
var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;}
|
||||||
|
this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}}
|
||||||
|
row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;i<dataList.length;i++){var data=dataList[i];buffer.put(data.mode,4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.mode,typeNumber));data.write(buffer);}
|
||||||
|
var totalDataCount=0;for(var i=0;i<rsBlocks.length;i++){totalDataCount+=rsBlocks[i].dataCount;}
|
||||||
|
if(buffer.getLengthInBits()>totalDataCount*8){throw new Error("code length overflow. ("
|
||||||
|
+buffer.getLengthInBits()
|
||||||
|
+">"
|
||||||
|
+totalDataCount*8
|
||||||
|
+")");}
|
||||||
|
if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}
|
||||||
|
while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}
|
||||||
|
while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}
|
||||||
|
buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}
|
||||||
|
buffer.put(QRCodeModel.PAD1,8);}
|
||||||
|
return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r++){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i++){dcdata[r][i]=0xff&buffer.buffer[i+offset];}
|
||||||
|
offset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=new QRPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i++){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.get(modIndex):0;}}
|
||||||
|
var totalCodeCount=0;for(var i=0;i<rsBlocks.length;i++){totalCodeCount+=rsBlocks[i].totalCount;}
|
||||||
|
var data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<dcdata[r].length){data[index++]=dcdata[r][i];}}}
|
||||||
|
for(var i=0;i<maxEcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<ecdata[r].length){data[index++]=ecdata[r][i];}}}
|
||||||
|
return data;};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0),G18:(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0),G15_MASK:(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1),getBCHTypeInfo:function(data){var d=data<<10;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)>=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));}
|
||||||
|
return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));}
|
||||||
|
return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;}
|
||||||
|
return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i<errorCorrectLength;i++){a=a.multiply(new QRPolynomial([1,QRMath.gexp(i)],0));}
|
||||||
|
return a;},getLengthInBits:function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error("mode:"+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error("mode:"+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error("mode:"+mode);}}else{throw new Error("type:"+type);}},getLostPoint:function(qrCode){var moduleCount=qrCode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount;col++){var sameCount=0;var dark=qrCode.isDark(row,col);for(var r=-1;r<=1;r++){if(row+r<0||moduleCount<=row+r){continue;}
|
||||||
|
for(var c=-1;c<=1;c++){if(col+c<0||moduleCount<=col+c){continue;}
|
||||||
|
if(r==0&&c==0){continue;}
|
||||||
|
if(dark==qrCode.isDark(row+r,col+c)){sameCount++;}}}
|
||||||
|
if(sameCount>5){lostPoint+=(3+sameCount-5);}}}
|
||||||
|
for(var row=0;row<moduleCount-1;row++){for(var col=0;col<moduleCount-1;col++){var count=0;if(qrCode.isDark(row,col))count++;if(qrCode.isDark(row+1,col))count++;if(qrCode.isDark(row,col+1))count++;if(qrCode.isDark(row+1,col+1))count++;if(count==0||count==4){lostPoint+=3;}}}
|
||||||
|
for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount-6;col++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row,col+1)&&qrCode.isDark(row,col+2)&&qrCode.isDark(row,col+3)&&qrCode.isDark(row,col+4)&&!qrCode.isDark(row,col+5)&&qrCode.isDark(row,col+6)){lostPoint+=40;}}}
|
||||||
|
for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount-6;row++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row+1,col)&&qrCode.isDark(row+2,col)&&qrCode.isDark(row+3,col)&&qrCode.isDark(row+4,col)&&!qrCode.isDark(row+5,col)&&qrCode.isDark(row+6,col)){lostPoint+=40;}}}
|
||||||
|
var darkCount=0;for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount;row++){if(qrCode.isDark(row,col)){darkCount++;}}}
|
||||||
|
var ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;}};var QRMath={glog:function(n){if(n<1){throw new Error("glog("+n+")");}
|
||||||
|
return QRMath.LOG_TABLE[n];},gexp:function(n){while(n<0){n+=255;}
|
||||||
|
while(n>=256){n-=255;}
|
||||||
|
return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<<i;}
|
||||||
|
for(var i=8;i<256;i++){QRMath.EXP_TABLE[i]=QRMath.EXP_TABLE[i-4]^QRMath.EXP_TABLE[i-5]^QRMath.EXP_TABLE[i-6]^QRMath.EXP_TABLE[i-8];}
|
||||||
|
for(var i=0;i<255;i++){QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]]=i;}
|
||||||
|
function QRPolynomial(num,shift){if(num.length==undefined){throw new Error(num.length+"/"+shift);}
|
||||||
|
var offset=0;while(offset<num.length&&num[offset]==0){offset++;}
|
||||||
|
this.num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i++){this.num[i]=num[i+offset];}}
|
||||||
|
QRPolynomial.prototype={get:function(index){return this.num[index];},getLength:function(){return this.num.length;},multiply:function(e){var num=new Array(this.getLength()+e.getLength()-1);for(var i=0;i<this.getLength();i++){for(var j=0;j<e.getLength();j++){num[i+j]^=QRMath.gexp(QRMath.glog(this.get(i))+QRMath.glog(e.get(j)));}}
|
||||||
|
return new QRPolynomial(num,0);},mod:function(e){if(this.getLength()-e.getLength()<0){return this;}
|
||||||
|
var ratio=QRMath.glog(this.get(0))-QRMath.glog(e.get(0));var num=new Array(this.getLength());for(var i=0;i<this.getLength();i++){num[i]=this.get(i);}
|
||||||
|
for(var i=0;i<e.getLength();i++){num[i]^=QRMath.gexp(QRMath.glog(e.get(i))+ratio);}
|
||||||
|
return new QRPolynomial(num,0).mod(e);}};function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this.dataCount=dataCount;}
|
||||||
|
QRRSBlock.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];QRRSBlock.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=QRRSBlock.getRsBlockTable(typeNumber,errorCorrectLevel);if(rsBlock==undefined){throw new Error("bad rs block @ typeNumber:"+typeNumber+"/errorCorrectLevel:"+errorCorrectLevel);}
|
||||||
|
var length=rsBlock.length/3;var list=[];for(var i=0;i<length;i++){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j++){list.push(new QRRSBlock(totalCount,dataCount));}}
|
||||||
|
return list;};QRRSBlock.getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};function QRBitBuffer(){this.buffer=[];this.length=0;}
|
||||||
|
QRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i<length;i++){this.putBit(((num>>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);}
|
||||||
|
if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));}
|
||||||
|
this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];
|
||||||
|
|
||||||
|
function _isSupportCanvas() {
|
||||||
|
return typeof CanvasRenderingContext2D != "undefined";
|
||||||
|
}
|
||||||
|
|
||||||
|
// android 2.x doesn't support Data-URI spec
|
||||||
|
function _getAndroid() {
|
||||||
|
var android = false;
|
||||||
|
var sAgent = navigator.userAgent;
|
||||||
|
|
||||||
|
if (/android/i.test(sAgent)) { // android
|
||||||
|
android = true;
|
||||||
|
aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i);
|
||||||
|
|
||||||
|
if (aMat && aMat[1]) {
|
||||||
|
android = parseFloat(aMat[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return android;
|
||||||
|
}
|
||||||
|
|
||||||
|
var svgDrawer = (function() {
|
||||||
|
|
||||||
|
var Drawing = function (el, htOption) {
|
||||||
|
this._el = el;
|
||||||
|
this._htOption = htOption;
|
||||||
|
};
|
||||||
|
|
||||||
|
Drawing.prototype.draw = function (oQRCode) {
|
||||||
|
var _htOption = this._htOption;
|
||||||
|
var _el = this._el;
|
||||||
|
var nCount = oQRCode.getModuleCount();
|
||||||
|
var nWidth = Math.floor(_htOption.width / nCount);
|
||||||
|
var nHeight = Math.floor(_htOption.height / nCount);
|
||||||
|
|
||||||
|
this.clear();
|
||||||
|
|
||||||
|
function makeSVG(tag, attrs) {
|
||||||
|
var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||||
|
for (var k in attrs)
|
||||||
|
if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight});
|
||||||
|
svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||||
|
_el.appendChild(svg);
|
||||||
|
|
||||||
|
svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"}));
|
||||||
|
|
||||||
|
for (var row = 0; row < nCount; row++) {
|
||||||
|
for (var col = 0; col < nCount; col++) {
|
||||||
|
if (oQRCode.isDark(row, col)) {
|
||||||
|
var child = makeSVG("use", {"x": String(row), "y": String(col)});
|
||||||
|
child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template")
|
||||||
|
svg.appendChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Drawing.prototype.clear = function () {
|
||||||
|
while (this._el.hasChildNodes())
|
||||||
|
this._el.removeChild(this._el.lastChild);
|
||||||
|
};
|
||||||
|
return Drawing;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var useSVG = document.documentElement.tagName.toLowerCase() === "svg";
|
||||||
|
|
||||||
|
// Drawing in DOM by using Table tag
|
||||||
|
var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {
|
||||||
|
var Drawing = function (el, htOption) {
|
||||||
|
this._el = el;
|
||||||
|
this._htOption = htOption;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the QRCode
|
||||||
|
*
|
||||||
|
* @param {QRCode} oQRCode
|
||||||
|
*/
|
||||||
|
Drawing.prototype.draw = function (oQRCode) {
|
||||||
|
var _htOption = this._htOption;
|
||||||
|
var _el = this._el;
|
||||||
|
var nCount = oQRCode.getModuleCount();
|
||||||
|
var nWidth = Math.floor(_htOption.width / nCount);
|
||||||
|
var nHeight = Math.floor(_htOption.height / nCount);
|
||||||
|
var aHTML = ['<table style="border:0;border-collapse:collapse;">'];
|
||||||
|
|
||||||
|
for (var row = 0; row < nCount; row++) {
|
||||||
|
aHTML.push('<tr>');
|
||||||
|
|
||||||
|
for (var col = 0; col < nCount; col++) {
|
||||||
|
aHTML.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' + nWidth + 'px;height:' + nHeight + 'px;background-color:' + (oQRCode.isDark(row, col) ? _htOption.colorDark : _htOption.colorLight) + ';"></td>');
|
||||||
|
}
|
||||||
|
|
||||||
|
aHTML.push('</tr>');
|
||||||
|
}
|
||||||
|
|
||||||
|
aHTML.push('</table>');
|
||||||
|
_el.innerHTML = aHTML.join('');
|
||||||
|
|
||||||
|
// Fix the margin values as real size.
|
||||||
|
var elTable = _el.childNodes[0];
|
||||||
|
var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;
|
||||||
|
var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
|
||||||
|
|
||||||
|
if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
|
||||||
|
elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the QRCode
|
||||||
|
*/
|
||||||
|
Drawing.prototype.clear = function () {
|
||||||
|
this._el.innerHTML = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
return Drawing;
|
||||||
|
})() : (function () { // Drawing in Canvas
|
||||||
|
function _onMakeImage() {
|
||||||
|
this._elImage.src = this._elCanvas.toDataURL("image/png");
|
||||||
|
this._elImage.style.display = "block";
|
||||||
|
this._elCanvas.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android 2.1 bug workaround
|
||||||
|
// http://code.google.com/p/android/issues/detail?id=5141
|
||||||
|
if (this._android && this._android <= 2.1) {
|
||||||
|
var factor = 1 / window.devicePixelRatio;
|
||||||
|
var drawImage = CanvasRenderingContext2D.prototype.drawImage;
|
||||||
|
CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||||
|
if (("nodeName" in image) && /img/i.test(image.nodeName)) {
|
||||||
|
for (var i = arguments.length - 1; i >= 1; i--) {
|
||||||
|
arguments[i] = arguments[i] * factor;
|
||||||
|
}
|
||||||
|
} else if (typeof dw == "undefined") {
|
||||||
|
arguments[1] *= factor;
|
||||||
|
arguments[2] *= factor;
|
||||||
|
arguments[3] *= factor;
|
||||||
|
arguments[4] *= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawImage.apply(this, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the user's browser supports Data URI or not
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Function} fSuccess Occurs if it supports Data URI
|
||||||
|
* @param {Function} fFail Occurs if it doesn't support Data URI
|
||||||
|
*/
|
||||||
|
function _safeSetDataURI(fSuccess, fFail) {
|
||||||
|
var self = this;
|
||||||
|
self._fFail = fFail;
|
||||||
|
self._fSuccess = fSuccess;
|
||||||
|
|
||||||
|
// Check it just once
|
||||||
|
if (self._bSupportDataURI === null) {
|
||||||
|
var el = document.createElement("img");
|
||||||
|
var fOnError = function() {
|
||||||
|
self._bSupportDataURI = false;
|
||||||
|
|
||||||
|
if (self._fFail) {
|
||||||
|
_fFail.call(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var fOnSuccess = function() {
|
||||||
|
self._bSupportDataURI = true;
|
||||||
|
|
||||||
|
if (self._fSuccess) {
|
||||||
|
self._fSuccess.call(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
el.onabort = fOnError;
|
||||||
|
el.onerror = fOnError;
|
||||||
|
el.onload = fOnSuccess;
|
||||||
|
el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data.
|
||||||
|
return;
|
||||||
|
} else if (self._bSupportDataURI === true && self._fSuccess) {
|
||||||
|
self._fSuccess.call(self);
|
||||||
|
} else if (self._bSupportDataURI === false && self._fFail) {
|
||||||
|
self._fFail.call(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawing QRCode by using canvas
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {HTMLElement} el
|
||||||
|
* @param {Object} htOption QRCode Options
|
||||||
|
*/
|
||||||
|
var Drawing = function (el, htOption) {
|
||||||
|
this._bIsPainted = false;
|
||||||
|
this._android = _getAndroid();
|
||||||
|
|
||||||
|
this._htOption = htOption;
|
||||||
|
this._elCanvas = document.createElement("canvas");
|
||||||
|
this._elCanvas.width = htOption.width;
|
||||||
|
this._elCanvas.height = htOption.height;
|
||||||
|
el.appendChild(this._elCanvas);
|
||||||
|
this._el = el;
|
||||||
|
this._oContext = this._elCanvas.getContext("2d");
|
||||||
|
this._bIsPainted = false;
|
||||||
|
this._elImage = document.createElement("img");
|
||||||
|
this._elImage.alt = "Scan me!";
|
||||||
|
this._elImage.style.display = "none";
|
||||||
|
this._el.appendChild(this._elImage);
|
||||||
|
this._bSupportDataURI = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the QRCode
|
||||||
|
*
|
||||||
|
* @param {QRCode} oQRCode
|
||||||
|
*/
|
||||||
|
Drawing.prototype.draw = function (oQRCode) {
|
||||||
|
var _elImage = this._elImage;
|
||||||
|
var _oContext = this._oContext;
|
||||||
|
var _htOption = this._htOption;
|
||||||
|
|
||||||
|
var nCount = oQRCode.getModuleCount();
|
||||||
|
var nWidth = _htOption.width / nCount;
|
||||||
|
var nHeight = _htOption.height / nCount;
|
||||||
|
var nRoundedWidth = Math.round(nWidth);
|
||||||
|
var nRoundedHeight = Math.round(nHeight);
|
||||||
|
|
||||||
|
_elImage.style.display = "none";
|
||||||
|
this.clear();
|
||||||
|
|
||||||
|
for (var row = 0; row < nCount; row++) {
|
||||||
|
for (var col = 0; col < nCount; col++) {
|
||||||
|
var bIsDark = oQRCode.isDark(row, col);
|
||||||
|
var nLeft = col * nWidth;
|
||||||
|
var nTop = row * nHeight;
|
||||||
|
_oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
|
||||||
|
_oContext.lineWidth = 1;
|
||||||
|
_oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
|
||||||
|
_oContext.fillRect(nLeft, nTop, nWidth, nHeight);
|
||||||
|
|
||||||
|
// 안티 앨리어싱 방지 처리
|
||||||
|
_oContext.strokeRect(
|
||||||
|
Math.floor(nLeft) + 0.5,
|
||||||
|
Math.floor(nTop) + 0.5,
|
||||||
|
nRoundedWidth,
|
||||||
|
nRoundedHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
_oContext.strokeRect(
|
||||||
|
Math.ceil(nLeft) - 0.5,
|
||||||
|
Math.ceil(nTop) - 0.5,
|
||||||
|
nRoundedWidth,
|
||||||
|
nRoundedHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._bIsPainted = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the image from Canvas if the browser supports Data URI.
|
||||||
|
*/
|
||||||
|
Drawing.prototype.makeImage = function () {
|
||||||
|
if (this._bIsPainted) {
|
||||||
|
_safeSetDataURI.call(this, _onMakeImage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the QRCode is painted or not
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
Drawing.prototype.isPainted = function () {
|
||||||
|
return this._bIsPainted;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the QRCode
|
||||||
|
*/
|
||||||
|
Drawing.prototype.clear = function () {
|
||||||
|
this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);
|
||||||
|
this._bIsPainted = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Number} nNumber
|
||||||
|
*/
|
||||||
|
Drawing.prototype.round = function (nNumber) {
|
||||||
|
if (!nNumber) {
|
||||||
|
return nNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.floor(nNumber * 1000) / 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Drawing;
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type by string length
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {String} sText
|
||||||
|
* @param {Number} nCorrectLevel
|
||||||
|
* @return {Number} type
|
||||||
|
*/
|
||||||
|
function _getTypeNumber(sText, nCorrectLevel) {
|
||||||
|
var nType = 1;
|
||||||
|
var length = _getUTF8Length(sText);
|
||||||
|
|
||||||
|
for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
|
||||||
|
var nLimit = 0;
|
||||||
|
|
||||||
|
switch (nCorrectLevel) {
|
||||||
|
case QRErrorCorrectLevel.L :
|
||||||
|
nLimit = QRCodeLimitLength[i][0];
|
||||||
|
break;
|
||||||
|
case QRErrorCorrectLevel.M :
|
||||||
|
nLimit = QRCodeLimitLength[i][1];
|
||||||
|
break;
|
||||||
|
case QRErrorCorrectLevel.Q :
|
||||||
|
nLimit = QRCodeLimitLength[i][2];
|
||||||
|
break;
|
||||||
|
case QRErrorCorrectLevel.H :
|
||||||
|
nLimit = QRCodeLimitLength[i][3];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length <= nLimit) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
nType++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nType > QRCodeLimitLength.length) {
|
||||||
|
throw new Error("Too long data");
|
||||||
|
}
|
||||||
|
|
||||||
|
return nType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getUTF8Length(sText) {
|
||||||
|
var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
|
||||||
|
return replacedText.length + (replacedText.length != sText ? 3 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class QRCode
|
||||||
|
* @constructor
|
||||||
|
* @example
|
||||||
|
* new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie");
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var oQRCode = new QRCode("test", {
|
||||||
|
* text : "http://naver.com",
|
||||||
|
* width : 128,
|
||||||
|
* height : 128
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* oQRCode.clear(); // Clear the QRCode.
|
||||||
|
* oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement|String} el target element or 'id' attribute of element.
|
||||||
|
* @param {Object|String} vOption
|
||||||
|
* @param {String} vOption.text QRCode link data
|
||||||
|
* @param {Number} [vOption.width=256]
|
||||||
|
* @param {Number} [vOption.height=256]
|
||||||
|
* @param {String} [vOption.colorDark="#000000"]
|
||||||
|
* @param {String} [vOption.colorLight="#ffffff"]
|
||||||
|
* @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H]
|
||||||
|
*/
|
||||||
|
QRCode = function (el, vOption) {
|
||||||
|
this._htOption = {
|
||||||
|
width : 256,
|
||||||
|
height : 256,
|
||||||
|
typeNumber : 4,
|
||||||
|
colorDark : "#000000",
|
||||||
|
colorLight : "#ffffff",
|
||||||
|
correctLevel : QRErrorCorrectLevel.H
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof vOption === 'string') {
|
||||||
|
vOption = {
|
||||||
|
text : vOption
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrites options
|
||||||
|
if (vOption) {
|
||||||
|
for (var i in vOption) {
|
||||||
|
this._htOption[i] = vOption[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof el == "string") {
|
||||||
|
el = document.getElementById(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._android = _getAndroid();
|
||||||
|
this._el = el;
|
||||||
|
this._oQRCode = null;
|
||||||
|
this._oDrawing = new Drawing(this._el, this._htOption);
|
||||||
|
|
||||||
|
if (this._htOption.text) {
|
||||||
|
this.makeCode(this._htOption.text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the QRCode
|
||||||
|
*
|
||||||
|
* @param {String} sText link data
|
||||||
|
*/
|
||||||
|
QRCode.prototype.makeCode = function (sText) {
|
||||||
|
this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);
|
||||||
|
this._oQRCode.addData(sText);
|
||||||
|
this._oQRCode.make();
|
||||||
|
this._el.title = sText;
|
||||||
|
this._oDrawing.draw(this._oQRCode);
|
||||||
|
this.makeImage();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the Image from Canvas element
|
||||||
|
* - It occurs automatically
|
||||||
|
* - Android below 3 doesn't support Data-URI spec.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
QRCode.prototype.makeImage = function () {
|
||||||
|
if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) {
|
||||||
|
this._oDrawing.makeImage();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the QRCode
|
||||||
|
*/
|
||||||
|
QRCode.prototype.clear = function () {
|
||||||
|
this._oDrawing.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name QRCode.CorrectLevel
|
||||||
|
*/
|
||||||
|
QRCode.CorrectLevel = QRErrorCorrectLevel;
|
||||||
|
})();
|
||||||
1
lamassu-admin-elm/build/bower_components/qrcodejs/qrcode.min.js
vendored
Normal file
1
lamassu-admin-elm/build/bower_components/qrcodejs/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
47
lamassu-admin-elm/build/bower_components/qrious/.bower.json
vendored
Normal file
47
lamassu-admin-elm/build/bower_components/qrious/.bower.json
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"name": "qrious",
|
||||||
|
"version": "2.0.2",
|
||||||
|
"description": "Library for QR code generation using canvas",
|
||||||
|
"homepage": "https://github.com/neocotic/qrious",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alasdair Mercer",
|
||||||
|
"email": "mercer.alasdair@gmail.com",
|
||||||
|
"homepage": "http://neocotic.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"code",
|
||||||
|
"encode",
|
||||||
|
"canvas",
|
||||||
|
"image"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/neocotic/qrious.git"
|
||||||
|
},
|
||||||
|
"main": "dist/umd/qrious.js",
|
||||||
|
"ignore": [
|
||||||
|
"src/",
|
||||||
|
".*",
|
||||||
|
"AUTHORS.md",
|
||||||
|
"CHANGES.md",
|
||||||
|
"CONTRIBUTING.md",
|
||||||
|
"demo.html",
|
||||||
|
"Gruntfile.js",
|
||||||
|
"package.json",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"_release": "2.0.2",
|
||||||
|
"_resolution": {
|
||||||
|
"type": "version",
|
||||||
|
"tag": "2.0.2",
|
||||||
|
"commit": "1ffd092e97ab3ba212fad21ab865eb1754155296"
|
||||||
|
},
|
||||||
|
"_source": "https://github.com/neocotic/qrious.git",
|
||||||
|
"_target": "^2.0.2",
|
||||||
|
"_originalSource": "qrious",
|
||||||
|
"_direct": true
|
||||||
|
}
|
||||||
16
lamassu-admin-elm/build/bower_components/qrious/LICENSE.md
vendored
Normal file
16
lamassu-admin-elm/build/bower_components/qrious/LICENSE.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
QRious
|
||||||
|
Copyright (C) 2016 Alasdair Mercer
|
||||||
|
Copyright (C) 2010 Tom Zerucha
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
37
lamassu-admin-elm/build/bower_components/qrious/bower.json
vendored
Normal file
37
lamassu-admin-elm/build/bower_components/qrious/bower.json
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "qrious",
|
||||||
|
"version": "2.0.2",
|
||||||
|
"description": "Library for QR code generation using canvas",
|
||||||
|
"homepage": "https://github.com/neocotic/qrious",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alasdair Mercer",
|
||||||
|
"email": "mercer.alasdair@gmail.com",
|
||||||
|
"homepage": "http://neocotic.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"code",
|
||||||
|
"encode",
|
||||||
|
"canvas",
|
||||||
|
"image"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/neocotic/qrious.git"
|
||||||
|
},
|
||||||
|
"main": "dist/umd/qrious.js",
|
||||||
|
"ignore": [
|
||||||
|
"src/",
|
||||||
|
".*",
|
||||||
|
"AUTHORS.md",
|
||||||
|
"CHANGES.md",
|
||||||
|
"CONTRIBUTING.md",
|
||||||
|
"demo.html",
|
||||||
|
"Gruntfile.js",
|
||||||
|
"package.json",
|
||||||
|
"README.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
36
lamassu-admin-elm/build/bower_components/qrjs/.bower.json
vendored
Normal file
36
lamassu-admin-elm/build/bower_components/qrjs/.bower.json
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name": "qrjs",
|
||||||
|
"main": "qr.js",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"homepage": "https://github.com/educastellano/qr.js",
|
||||||
|
"authors": [
|
||||||
|
"Kang Seonghoon <kang.seonghoon@mearie.org>",
|
||||||
|
"Eduard Castellano <educastellano08@gmail.com>"
|
||||||
|
],
|
||||||
|
"description": "QR code generator in Javascript",
|
||||||
|
"moduleType": [
|
||||||
|
"globals"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"qr.js",
|
||||||
|
"qrcode"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
],
|
||||||
|
"_release": "0.1.2",
|
||||||
|
"_resolution": {
|
||||||
|
"type": "version",
|
||||||
|
"tag": "v0.1.2",
|
||||||
|
"commit": "dbfa732cb309195a51a656b021f309d354154e04"
|
||||||
|
},
|
||||||
|
"_source": "https://github.com/educastellano/qr.js.git",
|
||||||
|
"_target": "~0.1.2",
|
||||||
|
"_originalSource": "qrjs"
|
||||||
|
}
|
||||||
8
lamassu-admin-elm/build/bower_components/qrjs/README.md
vendored
Normal file
8
lamassu-admin-elm/build/bower_components/qrjs/README.md
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# qr.js: QR code generator in pure Javascript (2011)
|
||||||
|
|
||||||
|
This is a fairly standalone script for producing QR code on the fly.
|
||||||
|
Originally developed for my own interest, the code is fully commented and well-structured.
|
||||||
|
The code is in the public domain (or to be exact, [Creative Commons Zero](https://creativecommons.org/publicdomain/zero/1.0/)),
|
||||||
|
and you can use it for absolutely any purpose.
|
||||||
|
|
||||||
|
See also a [node.js module based on qr.js](https://github.com/shesek/qruri), packaged by Nadav Ivgi.
|
||||||
27
lamassu-admin-elm/build/bower_components/qrjs/bower.json
vendored
Normal file
27
lamassu-admin-elm/build/bower_components/qrjs/bower.json
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "qrjs",
|
||||||
|
"main": "qr.js",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"homepage": "https://github.com/educastellano/qr.js",
|
||||||
|
"authors": [
|
||||||
|
"Kang Seonghoon <kang.seonghoon@mearie.org>",
|
||||||
|
"Eduard Castellano <educastellano08@gmail.com>"
|
||||||
|
],
|
||||||
|
"description": "QR code generator in Javascript",
|
||||||
|
"moduleType": [
|
||||||
|
"globals"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"qr.js",
|
||||||
|
"qrcode"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
}
|
||||||
24
lamassu-admin-elm/build/bower_components/qrjs/package.json
vendored
Normal file
24
lamassu-admin-elm/build/bower_components/qrjs/package.json
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "qrjs",
|
||||||
|
"version": "0.1.1",
|
||||||
|
"description": "QR code generator in Javascript",
|
||||||
|
"main": "qr.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/educastellano/qr.js.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"qr",
|
||||||
|
"qr.js",
|
||||||
|
"qrcode"
|
||||||
|
],
|
||||||
|
"author": "Kang Seonghoon <kang.seonghoon@mearie.org>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/educastellano/qr.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/educastellano/qr.js"
|
||||||
|
}
|
||||||
804
lamassu-admin-elm/build/bower_components/qrjs/qr.js
vendored
Normal file
804
lamassu-admin-elm/build/bower_components/qrjs/qr.js
vendored
Normal file
|
|
@ -0,0 +1,804 @@
|
||||||
|
/* qr.js -- QR code generator in Javascript (revision 2011-01-19)
|
||||||
|
* Written by Kang Seonghoon <public+qrjs@mearie.org>.
|
||||||
|
*
|
||||||
|
* This source code is in the public domain; if your jurisdiction does not
|
||||||
|
* recognize the public domain the terms of Creative Commons CC0 license
|
||||||
|
* apply. In the other words, you can always do what you want.
|
||||||
|
*/
|
||||||
|
(function(root, name, definition) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
define([], definition);
|
||||||
|
} else if (typeof module === 'object' && module.exports) {
|
||||||
|
module.exports = definition();
|
||||||
|
} else {
|
||||||
|
root[name] = definition();
|
||||||
|
}
|
||||||
|
})(this, 'QRCode', function() {
|
||||||
|
/* Quick overview: QR code composed of 2D array of modules (a rectangular
|
||||||
|
* area that conveys one bit of information); some modules are fixed to help
|
||||||
|
* the recognition of the code, and remaining data modules are further divided
|
||||||
|
* into 8-bit code words which are augumented by Reed-Solomon error correcting
|
||||||
|
* codes (ECC). There could be multiple ECCs, in the case the code is so large
|
||||||
|
* that it is helpful to split the raw data into several chunks.
|
||||||
|
*
|
||||||
|
* The number of modules is determined by the code's "version", ranging from 1
|
||||||
|
* (21x21) to 40 (177x177). How many ECC bits are used is determined by the
|
||||||
|
* ECC level (L/M/Q/H). The number and size (and thus the order of generator
|
||||||
|
* polynomial) of ECCs depend to the version and ECC level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// per-version information (cf. JIS X 0510:2004 pp. 30--36, 71)
|
||||||
|
//
|
||||||
|
// [0]: the degree of generator polynomial by ECC levels
|
||||||
|
// [1]: # of code blocks by ECC levels
|
||||||
|
// [2]: left-top positions of alignment patterns
|
||||||
|
//
|
||||||
|
// the number in this table (in particular, [0]) does not exactly match with
|
||||||
|
// the numbers in the specficiation. see augumenteccs below for the reason.
|
||||||
|
var VERSIONS = [
|
||||||
|
null,
|
||||||
|
[[10, 7,17,13], [ 1, 1, 1, 1], []],
|
||||||
|
[[16,10,28,22], [ 1, 1, 1, 1], [4,16]],
|
||||||
|
[[26,15,22,18], [ 1, 1, 2, 2], [4,20]],
|
||||||
|
[[18,20,16,26], [ 2, 1, 4, 2], [4,24]],
|
||||||
|
[[24,26,22,18], [ 2, 1, 4, 4], [4,28]],
|
||||||
|
[[16,18,28,24], [ 4, 2, 4, 4], [4,32]],
|
||||||
|
[[18,20,26,18], [ 4, 2, 5, 6], [4,20,36]],
|
||||||
|
[[22,24,26,22], [ 4, 2, 6, 6], [4,22,40]],
|
||||||
|
[[22,30,24,20], [ 5, 2, 8, 8], [4,24,44]],
|
||||||
|
[[26,18,28,24], [ 5, 4, 8, 8], [4,26,48]],
|
||||||
|
[[30,20,24,28], [ 5, 4,11, 8], [4,28,52]],
|
||||||
|
[[22,24,28,26], [ 8, 4,11,10], [4,30,56]],
|
||||||
|
[[22,26,22,24], [ 9, 4,16,12], [4,32,60]],
|
||||||
|
[[24,30,24,20], [ 9, 4,16,16], [4,24,44,64]],
|
||||||
|
[[24,22,24,30], [10, 6,18,12], [4,24,46,68]],
|
||||||
|
[[28,24,30,24], [10, 6,16,17], [4,24,48,72]],
|
||||||
|
[[28,28,28,28], [11, 6,19,16], [4,28,52,76]],
|
||||||
|
[[26,30,28,28], [13, 6,21,18], [4,28,54,80]],
|
||||||
|
[[26,28,26,26], [14, 7,25,21], [4,28,56,84]],
|
||||||
|
[[26,28,28,30], [16, 8,25,20], [4,32,60,88]],
|
||||||
|
[[26,28,30,28], [17, 8,25,23], [4,26,48,70,92]],
|
||||||
|
[[28,28,24,30], [17, 9,34,23], [4,24,48,72,96]],
|
||||||
|
[[28,30,30,30], [18, 9,30,25], [4,28,52,76,100]],
|
||||||
|
[[28,30,30,30], [20,10,32,27], [4,26,52,78,104]],
|
||||||
|
[[28,26,30,30], [21,12,35,29], [4,30,56,82,108]],
|
||||||
|
[[28,28,30,28], [23,12,37,34], [4,28,56,84,112]],
|
||||||
|
[[28,30,30,30], [25,12,40,34], [4,32,60,88,116]],
|
||||||
|
[[28,30,30,30], [26,13,42,35], [4,24,48,72,96,120]],
|
||||||
|
[[28,30,30,30], [28,14,45,38], [4,28,52,76,100,124]],
|
||||||
|
[[28,30,30,30], [29,15,48,40], [4,24,50,76,102,128]],
|
||||||
|
[[28,30,30,30], [31,16,51,43], [4,28,54,80,106,132]],
|
||||||
|
[[28,30,30,30], [33,17,54,45], [4,32,58,84,110,136]],
|
||||||
|
[[28,30,30,30], [35,18,57,48], [4,28,56,84,112,140]],
|
||||||
|
[[28,30,30,30], [37,19,60,51], [4,32,60,88,116,144]],
|
||||||
|
[[28,30,30,30], [38,19,63,53], [4,28,52,76,100,124,148]],
|
||||||
|
[[28,30,30,30], [40,20,66,56], [4,22,48,74,100,126,152]],
|
||||||
|
[[28,30,30,30], [43,21,70,59], [4,26,52,78,104,130,156]],
|
||||||
|
[[28,30,30,30], [45,22,74,62], [4,30,56,82,108,134,160]],
|
||||||
|
[[28,30,30,30], [47,24,77,65], [4,24,52,80,108,136,164]],
|
||||||
|
[[28,30,30,30], [49,25,81,68], [4,28,56,84,112,140,168]]];
|
||||||
|
|
||||||
|
// mode constants (cf. Table 2 in JIS X 0510:2004 p. 16)
|
||||||
|
var MODE_TERMINATOR = 0;
|
||||||
|
var MODE_NUMERIC = 1, MODE_ALPHANUMERIC = 2, MODE_OCTET = 4, MODE_KANJI = 8;
|
||||||
|
|
||||||
|
// validation regexps
|
||||||
|
var NUMERIC_REGEXP = /^\d*$/;
|
||||||
|
var ALPHANUMERIC_REGEXP = /^[A-Za-z0-9 $%*+\-./:]*$/;
|
||||||
|
var ALPHANUMERIC_OUT_REGEXP = /^[A-Z0-9 $%*+\-./:]*$/;
|
||||||
|
|
||||||
|
// ECC levels (cf. Table 22 in JIS X 0510:2004 p. 45)
|
||||||
|
var ECCLEVEL_L = 1, ECCLEVEL_M = 0, ECCLEVEL_Q = 3, ECCLEVEL_H = 2;
|
||||||
|
|
||||||
|
// GF(2^8)-to-integer mapping with a reducing polynomial x^8+x^4+x^3+x^2+1
|
||||||
|
// invariant: GF256_MAP[GF256_INVMAP[i]] == i for all i in [1,256)
|
||||||
|
var GF256_MAP = [], GF256_INVMAP = [-1];
|
||||||
|
for (var i = 0, v = 1; i < 255; ++i) {
|
||||||
|
GF256_MAP.push(v);
|
||||||
|
GF256_INVMAP[v] = i;
|
||||||
|
v = (v * 2) ^ (v >= 128 ? 0x11d : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generator polynomials up to degree 30
|
||||||
|
// (should match with polynomials in JIS X 0510:2004 Appendix A)
|
||||||
|
//
|
||||||
|
// generator polynomial of degree K is product of (x-\alpha^0), (x-\alpha^1),
|
||||||
|
// ..., (x-\alpha^(K-1)). by convention, we omit the K-th coefficient (always 1)
|
||||||
|
// from the result; also other coefficients are written in terms of the exponent
|
||||||
|
// to \alpha to avoid the redundant calculation. (see also calculateecc below.)
|
||||||
|
var GF256_GENPOLY = [[]];
|
||||||
|
for (var i = 0; i < 30; ++i) {
|
||||||
|
var prevpoly = GF256_GENPOLY[i], poly = [];
|
||||||
|
for (var j = 0; j <= i; ++j) {
|
||||||
|
var a = (j < i ? GF256_MAP[prevpoly[j]] : 0);
|
||||||
|
var b = GF256_MAP[(i + (prevpoly[j-1] || 0)) % 255];
|
||||||
|
poly.push(GF256_INVMAP[a ^ b]);
|
||||||
|
}
|
||||||
|
GF256_GENPOLY.push(poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
// alphanumeric character mapping (cf. Table 5 in JIS X 0510:2004 p. 19)
|
||||||
|
var ALPHANUMERIC_MAP = {};
|
||||||
|
for (var i = 0; i < 45; ++i) {
|
||||||
|
ALPHANUMERIC_MAP['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.charAt(i)] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mask functions in terms of row # and column #
|
||||||
|
// (cf. Table 20 in JIS X 0510:2004 p. 42)
|
||||||
|
var MASKFUNCS = [
|
||||||
|
function(i,j) { return (i+j) % 2 == 0; },
|
||||||
|
function(i,j) { return i % 2 == 0; },
|
||||||
|
function(i,j) { return j % 3 == 0; },
|
||||||
|
function(i,j) { return (i+j) % 3 == 0; },
|
||||||
|
function(i,j) { return (((i/2)|0) + ((j/3)|0)) % 2 == 0; },
|
||||||
|
function(i,j) { return (i*j) % 2 + (i*j) % 3 == 0; },
|
||||||
|
function(i,j) { return ((i*j) % 2 + (i*j) % 3) % 2 == 0; },
|
||||||
|
function(i,j) { return ((i+j) % 2 + (i*j) % 3) % 2 == 0; }];
|
||||||
|
|
||||||
|
// returns true when the version information has to be embeded.
|
||||||
|
var needsverinfo = function(ver) { return ver > 6; };
|
||||||
|
|
||||||
|
// returns the size of entire QR code for given version.
|
||||||
|
var getsizebyver = function(ver) { return 4 * ver + 17; };
|
||||||
|
|
||||||
|
// returns the number of bits available for code words in this version.
|
||||||
|
var nfullbits = function(ver) {
|
||||||
|
/*
|
||||||
|
* |<--------------- n --------------->|
|
||||||
|
* | |<----- n-17 ---->| |
|
||||||
|
* +-------+ ///+-------+ ----
|
||||||
|
* | | ///| | ^
|
||||||
|
* | 9x9 | @@@@@ ///| 9x8 | |
|
||||||
|
* | | # # # @5x5@ # # # | | |
|
||||||
|
* +-------+ @@@@@ +-------+ |
|
||||||
|
* # ---|
|
||||||
|
* ^ |
|
||||||
|
* # |
|
||||||
|
* @@@@@ @@@@@ @@@@@ | n
|
||||||
|
* @5x5@ @5x5@ @5x5@ n-17
|
||||||
|
* @@@@@ @@@@@ @@@@@ | |
|
||||||
|
* # | |
|
||||||
|
* ////// v |
|
||||||
|
* //////# ---|
|
||||||
|
* +-------+ @@@@@ @@@@@ |
|
||||||
|
* | | @5x5@ @5x5@ |
|
||||||
|
* | 8x9 | @@@@@ @@@@@ |
|
||||||
|
* | | v
|
||||||
|
* +-------+ ----
|
||||||
|
*
|
||||||
|
* when the entire code has n^2 modules and there are m^2-3 alignment
|
||||||
|
* patterns, we have:
|
||||||
|
* - 225 (= 9x9 + 9x8 + 8x9) modules for finder patterns and
|
||||||
|
* format information;
|
||||||
|
* - 2n-34 (= 2(n-17)) modules for timing patterns;
|
||||||
|
* - 36 (= 3x6 + 6x3) modules for version information, if any;
|
||||||
|
* - 25m^2-75 (= (m^2-3)(5x5)) modules for alignment patterns
|
||||||
|
* if any, but 10m-20 (= 2(m-2)x5) of them overlaps with
|
||||||
|
* timing patterns.
|
||||||
|
*/
|
||||||
|
var v = VERSIONS[ver];
|
||||||
|
var nbits = 16*ver*ver + 128*ver + 64; // finder, timing and format info.
|
||||||
|
if (needsverinfo(ver)) nbits -= 36; // version information
|
||||||
|
if (v[2].length) { // alignment patterns
|
||||||
|
nbits -= 25 * v[2].length * v[2].length - 10 * v[2].length - 55;
|
||||||
|
}
|
||||||
|
return nbits;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the number of bits available for data portions (i.e. excludes ECC
|
||||||
|
// bits but includes mode and length bits) in this version and ECC level.
|
||||||
|
var ndatabits = function(ver, ecclevel) {
|
||||||
|
var nbits = nfullbits(ver) & ~7; // no sub-octet code words
|
||||||
|
var v = VERSIONS[ver];
|
||||||
|
nbits -= 8 * v[0][ecclevel] * v[1][ecclevel]; // ecc bits
|
||||||
|
return nbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the number of bits required for the length of data.
|
||||||
|
// (cf. Table 3 in JIS X 0510:2004 p. 16)
|
||||||
|
var ndatalenbits = function(ver, mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_NUMERIC: return (ver < 10 ? 10 : ver < 27 ? 12 : 14);
|
||||||
|
case MODE_ALPHANUMERIC: return (ver < 10 ? 9 : ver < 27 ? 11 : 13);
|
||||||
|
case MODE_OCTET: return (ver < 10 ? 8 : 16);
|
||||||
|
case MODE_KANJI: return (ver < 10 ? 8 : ver < 27 ? 10 : 12);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the maximum length of data possible in given configuration.
|
||||||
|
var getmaxdatalen = function(ver, mode, ecclevel) {
|
||||||
|
var nbits = ndatabits(ver, ecclevel) - 4 - ndatalenbits(ver, mode); // 4 for mode bits
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_NUMERIC:
|
||||||
|
return ((nbits/10) | 0) * 3 + (nbits%10 < 4 ? 0 : nbits%10 < 7 ? 1 : 2);
|
||||||
|
case MODE_ALPHANUMERIC:
|
||||||
|
return ((nbits/11) | 0) * 2 + (nbits%11 < 6 ? 0 : 1);
|
||||||
|
case MODE_OCTET:
|
||||||
|
return (nbits/8) | 0;
|
||||||
|
case MODE_KANJI:
|
||||||
|
return (nbits/13) | 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// checks if the given data can be encoded in given mode, and returns
|
||||||
|
// the converted data for the further processing if possible. otherwise
|
||||||
|
// returns null.
|
||||||
|
//
|
||||||
|
// this function does not check the length of data; it is a duty of
|
||||||
|
// encode function below (as it depends on the version and ECC level too).
|
||||||
|
var validatedata = function(mode, data) {
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_NUMERIC:
|
||||||
|
if (!data.match(NUMERIC_REGEXP)) return null;
|
||||||
|
return data;
|
||||||
|
|
||||||
|
case MODE_ALPHANUMERIC:
|
||||||
|
if (!data.match(ALPHANUMERIC_REGEXP)) return null;
|
||||||
|
return data.toUpperCase();
|
||||||
|
|
||||||
|
case MODE_OCTET:
|
||||||
|
if (typeof data === 'string') { // encode as utf-8 string
|
||||||
|
var newdata = [];
|
||||||
|
for (var i = 0; i < data.length; ++i) {
|
||||||
|
var ch = data.charCodeAt(i);
|
||||||
|
if (ch < 0x80) {
|
||||||
|
newdata.push(ch);
|
||||||
|
} else if (ch < 0x800) {
|
||||||
|
newdata.push(0xc0 | (ch >> 6),
|
||||||
|
0x80 | (ch & 0x3f));
|
||||||
|
} else if (ch < 0x10000) {
|
||||||
|
newdata.push(0xe0 | (ch >> 12),
|
||||||
|
0x80 | ((ch >> 6) & 0x3f),
|
||||||
|
0x80 | (ch & 0x3f));
|
||||||
|
} else {
|
||||||
|
newdata.push(0xf0 | (ch >> 18),
|
||||||
|
0x80 | ((ch >> 12) & 0x3f),
|
||||||
|
0x80 | ((ch >> 6) & 0x3f),
|
||||||
|
0x80 | (ch & 0x3f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newdata;
|
||||||
|
} else {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the code words (sans ECC bits) for given data and configurations.
|
||||||
|
// requires data to be preprocessed by validatedata. no length check is
|
||||||
|
// performed, and everything has to be checked before calling this function.
|
||||||
|
var encode = function(ver, mode, data, maxbuflen) {
|
||||||
|
var buf = [];
|
||||||
|
var bits = 0, remaining = 8;
|
||||||
|
var datalen = data.length;
|
||||||
|
|
||||||
|
// this function is intentionally no-op when n=0.
|
||||||
|
var pack = function(x, n) {
|
||||||
|
if (n >= remaining) {
|
||||||
|
buf.push(bits | (x >> (n -= remaining)));
|
||||||
|
while (n >= 8) buf.push((x >> (n -= 8)) & 255);
|
||||||
|
bits = 0;
|
||||||
|
remaining = 8;
|
||||||
|
}
|
||||||
|
if (n > 0) bits |= (x & ((1 << n) - 1)) << (remaining -= n);
|
||||||
|
};
|
||||||
|
|
||||||
|
var nlenbits = ndatalenbits(ver, mode);
|
||||||
|
pack(mode, 4);
|
||||||
|
pack(datalen, nlenbits);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_NUMERIC:
|
||||||
|
for (var i = 2; i < datalen; i += 3) {
|
||||||
|
pack(parseInt(data.substring(i-2,i+1), 10), 10);
|
||||||
|
}
|
||||||
|
pack(parseInt(data.substring(i-2), 10), [0,4,7][datalen%3]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_ALPHANUMERIC:
|
||||||
|
for (var i = 1; i < datalen; i += 2) {
|
||||||
|
pack(ALPHANUMERIC_MAP[data.charAt(i-1)] * 45 +
|
||||||
|
ALPHANUMERIC_MAP[data.charAt(i)], 11);
|
||||||
|
}
|
||||||
|
if (datalen % 2 == 1) {
|
||||||
|
pack(ALPHANUMERIC_MAP[data.charAt(i-1)], 6);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_OCTET:
|
||||||
|
for (var i = 0; i < datalen; ++i) {
|
||||||
|
pack(data[i], 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
// final bits. it is possible that adding terminator causes the buffer
|
||||||
|
// to overflow, but then the buffer truncated to the maximum size will
|
||||||
|
// be valid as the truncated terminator mode bits and padding is
|
||||||
|
// identical in appearance (cf. JIS X 0510:2004 sec 8.4.8).
|
||||||
|
pack(MODE_TERMINATOR, 4);
|
||||||
|
if (remaining < 8) buf.push(bits);
|
||||||
|
|
||||||
|
// the padding to fill up the remaining space. we should not add any
|
||||||
|
// words when the overflow already occurred.
|
||||||
|
while (buf.length + 1 < maxbuflen) buf.push(0xec, 0x11);
|
||||||
|
if (buf.length < maxbuflen) buf.push(0xec);
|
||||||
|
return buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
// calculates ECC code words for given code words and generator polynomial.
|
||||||
|
//
|
||||||
|
// this is quite similar to CRC calculation as both Reed-Solomon and CRC use
|
||||||
|
// the certain kind of cyclic codes, which is effectively the division of
|
||||||
|
// zero-augumented polynomial by the generator polynomial. the only difference
|
||||||
|
// is that Reed-Solomon uses GF(2^8), instead of CRC's GF(2), and Reed-Solomon
|
||||||
|
// uses the different generator polynomial than CRC's.
|
||||||
|
var calculateecc = function(poly, genpoly) {
|
||||||
|
var modulus = poly.slice(0);
|
||||||
|
var polylen = poly.length, genpolylen = genpoly.length;
|
||||||
|
for (var i = 0; i < genpolylen; ++i) modulus.push(0);
|
||||||
|
for (var i = 0; i < polylen; ) {
|
||||||
|
var quotient = GF256_INVMAP[modulus[i++]];
|
||||||
|
if (quotient >= 0) {
|
||||||
|
for (var j = 0; j < genpolylen; ++j) {
|
||||||
|
modulus[i+j] ^= GF256_MAP[(quotient + genpoly[j]) % 255];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modulus.slice(polylen);
|
||||||
|
};
|
||||||
|
|
||||||
|
// auguments ECC code words to given code words. the resulting words are
|
||||||
|
// ready to be encoded in the matrix.
|
||||||
|
//
|
||||||
|
// the much of actual augumenting procedure follows JIS X 0510:2004 sec 8.7.
|
||||||
|
// the code is simplified using the fact that the size of each code & ECC
|
||||||
|
// blocks is almost same; for example, when we have 4 blocks and 46 data words
|
||||||
|
// the number of code words in those blocks are 11, 11, 12, 12 respectively.
|
||||||
|
var augumenteccs = function(poly, nblocks, genpoly) {
|
||||||
|
var subsizes = [];
|
||||||
|
var subsize = (poly.length / nblocks) | 0, subsize0 = 0;
|
||||||
|
var pivot = nblocks - poly.length % nblocks;
|
||||||
|
for (var i = 0; i < pivot; ++i) {
|
||||||
|
subsizes.push(subsize0);
|
||||||
|
subsize0 += subsize;
|
||||||
|
}
|
||||||
|
for (var i = pivot; i < nblocks; ++i) {
|
||||||
|
subsizes.push(subsize0);
|
||||||
|
subsize0 += subsize+1;
|
||||||
|
}
|
||||||
|
subsizes.push(subsize0);
|
||||||
|
|
||||||
|
var eccs = [];
|
||||||
|
for (var i = 0; i < nblocks; ++i) {
|
||||||
|
eccs.push(calculateecc(poly.slice(subsizes[i], subsizes[i+1]), genpoly));
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = [];
|
||||||
|
var nitemsperblock = (poly.length / nblocks) | 0;
|
||||||
|
for (var i = 0; i < nitemsperblock; ++i) {
|
||||||
|
for (var j = 0; j < nblocks; ++j) {
|
||||||
|
result.push(poly[subsizes[j] + i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var j = pivot; j < nblocks; ++j) {
|
||||||
|
result.push(poly[subsizes[j+1] - 1]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < genpoly.length; ++i) {
|
||||||
|
for (var j = 0; j < nblocks; ++j) {
|
||||||
|
result.push(eccs[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// auguments BCH(p+q,q) code to the polynomial over GF(2), given the proper
|
||||||
|
// genpoly. the both input and output are in binary numbers, and unlike
|
||||||
|
// calculateecc genpoly should include the 1 bit for the highest degree.
|
||||||
|
//
|
||||||
|
// actual polynomials used for this procedure are as follows:
|
||||||
|
// - p=10, q=5, genpoly=x^10+x^8+x^5+x^4+x^2+x+1 (JIS X 0510:2004 Appendix C)
|
||||||
|
// - p=18, q=6, genpoly=x^12+x^11+x^10+x^9+x^8+x^5+x^2+1 (ibid. Appendix D)
|
||||||
|
var augumentbch = function(poly, p, genpoly, q) {
|
||||||
|
var modulus = poly << q;
|
||||||
|
for (var i = p - 1; i >= 0; --i) {
|
||||||
|
if ((modulus >> (q+i)) & 1) modulus ^= genpoly << i;
|
||||||
|
}
|
||||||
|
return (poly << q) | modulus;
|
||||||
|
};
|
||||||
|
|
||||||
|
// creates the base matrix for given version. it returns two matrices, one of
|
||||||
|
// them is the actual one and the another represents the "reserved" portion
|
||||||
|
// (e.g. finder and timing patterns) of the matrix.
|
||||||
|
//
|
||||||
|
// some entries in the matrix may be undefined, rather than 0 or 1. this is
|
||||||
|
// intentional (no initialization needed!), and putdata below will fill
|
||||||
|
// the remaining ones.
|
||||||
|
var makebasematrix = function(ver) {
|
||||||
|
var v = VERSIONS[ver], n = getsizebyver(ver);
|
||||||
|
var matrix = [], reserved = [];
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
matrix.push([]);
|
||||||
|
reserved.push([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var blit = function(y, x, h, w, bits) {
|
||||||
|
for (var i = 0; i < h; ++i) {
|
||||||
|
for (var j = 0; j < w; ++j) {
|
||||||
|
matrix[y+i][x+j] = (bits[i] >> j) & 1;
|
||||||
|
reserved[y+i][x+j] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// finder patterns and a part of timing patterns
|
||||||
|
// will also mark the format information area (not yet written) as reserved.
|
||||||
|
blit(0, 0, 9, 9, [0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x17f, 0x00, 0x40]);
|
||||||
|
blit(n-8, 0, 8, 9, [0x100, 0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x7f]);
|
||||||
|
blit(0, n-8, 9, 8, [0xfe, 0x82, 0xba, 0xba, 0xba, 0x82, 0xfe, 0x00, 0x00]);
|
||||||
|
|
||||||
|
// the rest of timing patterns
|
||||||
|
for (var i = 9; i < n-8; ++i) {
|
||||||
|
matrix[6][i] = matrix[i][6] = ~i & 1;
|
||||||
|
reserved[6][i] = reserved[i][6] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// alignment patterns
|
||||||
|
var aligns = v[2], m = aligns.length;
|
||||||
|
for (var i = 0; i < m; ++i) {
|
||||||
|
var minj = (i==0 || i==m-1 ? 1 : 0), maxj = (i==0 ? m-1 : m);
|
||||||
|
for (var j = minj; j < maxj; ++j) {
|
||||||
|
blit(aligns[i], aligns[j], 5, 5, [0x1f, 0x11, 0x15, 0x11, 0x1f]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// version information
|
||||||
|
if (needsverinfo(ver)) {
|
||||||
|
var code = augumentbch(ver, 6, 0x1f25, 12);
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 0; i < 6; ++i) {
|
||||||
|
for (var j = 0; j < 3; ++j) {
|
||||||
|
matrix[i][(n-11)+j] = matrix[(n-11)+j][i] = (code >> k++) & 1;
|
||||||
|
reserved[i][(n-11)+j] = reserved[(n-11)+j][i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {matrix: matrix, reserved: reserved};
|
||||||
|
};
|
||||||
|
|
||||||
|
// fills the data portion (i.e. unmarked in reserved) of the matrix with given
|
||||||
|
// code words. the size of code words should be no more than available bits,
|
||||||
|
// and remaining bits are padded to 0 (cf. JIS X 0510:2004 sec 8.7.3).
|
||||||
|
var putdata = function(matrix, reserved, buf) {
|
||||||
|
var n = matrix.length;
|
||||||
|
var k = 0, dir = -1;
|
||||||
|
for (var i = n-1; i >= 0; i -= 2) {
|
||||||
|
if (i == 6) --i; // skip the entire timing pattern column
|
||||||
|
var jj = (dir < 0 ? n-1 : 0);
|
||||||
|
for (var j = 0; j < n; ++j) {
|
||||||
|
for (var ii = i; ii > i-2; --ii) {
|
||||||
|
if (!reserved[jj][ii]) {
|
||||||
|
// may overflow, but (undefined >> x)
|
||||||
|
// is 0 so it will auto-pad to zero.
|
||||||
|
matrix[jj][ii] = (buf[k >> 3] >> (~k&7)) & 1;
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jj += dir;
|
||||||
|
}
|
||||||
|
dir = -dir;
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
// XOR-masks the data portion of the matrix. repeating the call with the same
|
||||||
|
// arguments will revert the prior call (convenient in the matrix evaluation).
|
||||||
|
var maskdata = function(matrix, reserved, mask) {
|
||||||
|
var maskf = MASKFUNCS[mask];
|
||||||
|
var n = matrix.length;
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
for (var j = 0; j < n; ++j) {
|
||||||
|
if (!reserved[i][j]) matrix[i][j] ^= maskf(i,j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// puts the format information.
|
||||||
|
var putformatinfo = function(matrix, reserved, ecclevel, mask) {
|
||||||
|
var n = matrix.length;
|
||||||
|
var code = augumentbch((ecclevel << 3) | mask, 5, 0x537, 10) ^ 0x5412;
|
||||||
|
for (var i = 0; i < 15; ++i) {
|
||||||
|
var r = [0,1,2,3,4,5,7,8,n-7,n-6,n-5,n-4,n-3,n-2,n-1][i];
|
||||||
|
var c = [n-1,n-2,n-3,n-4,n-5,n-6,n-7,n-8,7,5,4,3,2,1,0][i];
|
||||||
|
matrix[r][8] = matrix[8][c] = (code >> i) & 1;
|
||||||
|
// we don't have to mark those bits reserved; always done
|
||||||
|
// in makebasematrix above.
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
// evaluates the resulting matrix and returns the score (lower is better).
|
||||||
|
// (cf. JIS X 0510:2004 sec 8.8.2)
|
||||||
|
//
|
||||||
|
// the evaluation procedure tries to avoid the problematic patterns naturally
|
||||||
|
// occuring from the original matrix. for example, it penaltizes the patterns
|
||||||
|
// which just look like the finder pattern which will confuse the decoder.
|
||||||
|
// we choose the mask which results in the lowest score among 8 possible ones.
|
||||||
|
//
|
||||||
|
// note: zxing seems to use the same procedure and in many cases its choice
|
||||||
|
// agrees to ours, but sometimes it does not. practically it doesn't matter.
|
||||||
|
var evaluatematrix = function(matrix) {
|
||||||
|
// N1+(k-5) points for each consecutive row of k same-colored modules,
|
||||||
|
// where k >= 5. no overlapping row counts.
|
||||||
|
var PENALTY_CONSECUTIVE = 3;
|
||||||
|
// N2 points for each 2x2 block of same-colored modules.
|
||||||
|
// overlapping block does count.
|
||||||
|
var PENALTY_TWOBYTWO = 3;
|
||||||
|
// N3 points for each pattern with >4W:1B:1W:3B:1W:1B or
|
||||||
|
// 1B:1W:3B:1W:1B:>4W, or their multiples (e.g. highly unlikely,
|
||||||
|
// but 13W:3B:3W:9B:3W:3B counts).
|
||||||
|
var PENALTY_FINDERLIKE = 40;
|
||||||
|
// N4*k points for every (5*k)% deviation from 50% black density.
|
||||||
|
// i.e. k=1 for 55~60% and 40~45%, k=2 for 60~65% and 35~40%, etc.
|
||||||
|
var PENALTY_DENSITY = 10;
|
||||||
|
|
||||||
|
var evaluategroup = function(groups) { // assumes [W,B,W,B,W,...,B,W]
|
||||||
|
var score = 0;
|
||||||
|
for (var i = 0; i < groups.length; ++i) {
|
||||||
|
if (groups[i] >= 5) score += PENALTY_CONSECUTIVE + (groups[i]-5);
|
||||||
|
}
|
||||||
|
for (var i = 5; i < groups.length; i += 2) {
|
||||||
|
var p = groups[i];
|
||||||
|
if (groups[i-1] == p && groups[i-2] == 3*p && groups[i-3] == p &&
|
||||||
|
groups[i-4] == p && (groups[i-5] >= 4*p || groups[i+1] >= 4*p)) {
|
||||||
|
// this part differs from zxing...
|
||||||
|
score += PENALTY_FINDERLIKE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
};
|
||||||
|
|
||||||
|
var n = matrix.length;
|
||||||
|
var score = 0, nblacks = 0;
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
var row = matrix[i];
|
||||||
|
var groups;
|
||||||
|
|
||||||
|
// evaluate the current row
|
||||||
|
groups = [0]; // the first empty group of white
|
||||||
|
for (var j = 0; j < n; ) {
|
||||||
|
var k;
|
||||||
|
for (k = 0; j < n && row[j]; ++k) ++j;
|
||||||
|
groups.push(k);
|
||||||
|
for (k = 0; j < n && !row[j]; ++k) ++j;
|
||||||
|
groups.push(k);
|
||||||
|
}
|
||||||
|
score += evaluategroup(groups);
|
||||||
|
|
||||||
|
// evaluate the current column
|
||||||
|
groups = [0];
|
||||||
|
for (var j = 0; j < n; ) {
|
||||||
|
var k;
|
||||||
|
for (k = 0; j < n && matrix[j][i]; ++k) ++j;
|
||||||
|
groups.push(k);
|
||||||
|
for (k = 0; j < n && !matrix[j][i]; ++k) ++j;
|
||||||
|
groups.push(k);
|
||||||
|
}
|
||||||
|
score += evaluategroup(groups);
|
||||||
|
|
||||||
|
// check the 2x2 box and calculate the density
|
||||||
|
var nextrow = matrix[i+1] || [];
|
||||||
|
nblacks += row[0];
|
||||||
|
for (var j = 1; j < n; ++j) {
|
||||||
|
var p = row[j];
|
||||||
|
nblacks += p;
|
||||||
|
// at least comparison with next row should be strict...
|
||||||
|
if (row[j-1] == p && nextrow[j] === p && nextrow[j-1] === p) {
|
||||||
|
score += PENALTY_TWOBYTWO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
score += PENALTY_DENSITY * ((Math.abs(nblacks / n / n - 0.5) / 0.05) | 0);
|
||||||
|
return score;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the fully encoded QR code matrix which contains given data.
|
||||||
|
// it also chooses the best mask automatically when mask is -1.
|
||||||
|
var generate = function(data, ver, mode, ecclevel, mask) {
|
||||||
|
var v = VERSIONS[ver];
|
||||||
|
var buf = encode(ver, mode, data, ndatabits(ver, ecclevel) >> 3);
|
||||||
|
buf = augumenteccs(buf, v[1][ecclevel], GF256_GENPOLY[v[0][ecclevel]]);
|
||||||
|
|
||||||
|
var result = makebasematrix(ver);
|
||||||
|
var matrix = result.matrix, reserved = result.reserved;
|
||||||
|
putdata(matrix, reserved, buf);
|
||||||
|
|
||||||
|
if (mask < 0) {
|
||||||
|
// find the best mask
|
||||||
|
maskdata(matrix, reserved, 0);
|
||||||
|
putformatinfo(matrix, reserved, ecclevel, 0);
|
||||||
|
var bestmask = 0, bestscore = evaluatematrix(matrix);
|
||||||
|
maskdata(matrix, reserved, 0);
|
||||||
|
for (mask = 1; mask < 8; ++mask) {
|
||||||
|
maskdata(matrix, reserved, mask);
|
||||||
|
putformatinfo(matrix, reserved, ecclevel, mask);
|
||||||
|
var score = evaluatematrix(matrix);
|
||||||
|
if (bestscore > score) {
|
||||||
|
bestscore = score;
|
||||||
|
bestmask = mask;
|
||||||
|
}
|
||||||
|
maskdata(matrix, reserved, mask);
|
||||||
|
}
|
||||||
|
mask = bestmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
maskdata(matrix, reserved, mask);
|
||||||
|
putformatinfo(matrix, reserved, ecclevel, mask);
|
||||||
|
return matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
// the public interface is trivial; the options available are as follows:
|
||||||
|
//
|
||||||
|
// - version: an integer in [1,40]. when omitted (or -1) the smallest possible
|
||||||
|
// version is chosen.
|
||||||
|
// - mode: one of 'numeric', 'alphanumeric', 'octet'. when omitted the smallest
|
||||||
|
// possible mode is chosen.
|
||||||
|
// - ecclevel: one of 'L', 'M', 'Q', 'H'. defaults to 'L'.
|
||||||
|
// - mask: an integer in [0,7]. when omitted (or -1) the best mask is chosen.
|
||||||
|
//
|
||||||
|
// for generate{HTML,PNG}:
|
||||||
|
//
|
||||||
|
// - modulesize: a number. this is a size of each modules in pixels, and
|
||||||
|
// defaults to 5px.
|
||||||
|
// - margin: a number. this is a size of margin in *modules*, and defaults to
|
||||||
|
// 4 (white modules). the specficiation mandates the margin no less than 4
|
||||||
|
// modules, so it is better not to alter this value unless you know what
|
||||||
|
// you're doing.
|
||||||
|
var QRCode = {
|
||||||
|
'generate': function(data, options) {
|
||||||
|
var MODES = {'numeric': MODE_NUMERIC, 'alphanumeric': MODE_ALPHANUMERIC,
|
||||||
|
'octet': MODE_OCTET};
|
||||||
|
var ECCLEVELS = {'L': ECCLEVEL_L, 'M': ECCLEVEL_M, 'Q': ECCLEVEL_Q,
|
||||||
|
'H': ECCLEVEL_H};
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
var ver = options.version || -1;
|
||||||
|
var ecclevel = ECCLEVELS[(options.ecclevel || 'L').toUpperCase()];
|
||||||
|
var mode = options.mode ? MODES[options.mode.toLowerCase()] : -1;
|
||||||
|
var mask = 'mask' in options ? options.mask : -1;
|
||||||
|
|
||||||
|
if (mode < 0) {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
if (data.match(NUMERIC_REGEXP)) {
|
||||||
|
mode = MODE_NUMERIC;
|
||||||
|
} else if (data.match(ALPHANUMERIC_OUT_REGEXP)) {
|
||||||
|
// while encode supports case-insensitive
|
||||||
|
// encoding, we restrict the data to be
|
||||||
|
// uppercased when auto-selecting the mode.
|
||||||
|
mode = MODE_ALPHANUMERIC;
|
||||||
|
} else {
|
||||||
|
mode = MODE_OCTET;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mode = MODE_OCTET;
|
||||||
|
}
|
||||||
|
} else if (!(mode == MODE_NUMERIC || mode == MODE_ALPHANUMERIC ||
|
||||||
|
mode == MODE_OCTET)) {
|
||||||
|
throw 'invalid or unsupported mode';
|
||||||
|
}
|
||||||
|
|
||||||
|
data = validatedata(mode, data);
|
||||||
|
if (data === null) throw 'invalid data format';
|
||||||
|
|
||||||
|
if (ecclevel < 0 || ecclevel > 3) throw 'invalid ECC level';
|
||||||
|
|
||||||
|
if (ver < 0) {
|
||||||
|
for (ver = 1; ver <= 40; ++ver) {
|
||||||
|
if (data.length <= getmaxdatalen(ver, mode, ecclevel)) break;
|
||||||
|
}
|
||||||
|
if (ver > 40) throw 'too large data';
|
||||||
|
} else if (ver < 1 || ver > 40) {
|
||||||
|
throw 'invalid version';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask != -1 && (mask < 0 || mask > 8)) throw 'invalid mask';
|
||||||
|
|
||||||
|
return generate(data, ver, mode, ecclevel, mask);
|
||||||
|
},
|
||||||
|
|
||||||
|
'generateHTML': function(data, options) {
|
||||||
|
options = options || {};
|
||||||
|
var matrix = QRCode['generate'](data, options);
|
||||||
|
var modsize = Math.max(options.modulesize || 5, 0.5);
|
||||||
|
var margin = Math.max(options.margin !== null ? options.margin : 4, 0.0);
|
||||||
|
|
||||||
|
var e = document.createElement('div');
|
||||||
|
var n = matrix.length;
|
||||||
|
var html = ['<table border="0" cellspacing="0" cellpadding="0" style="border:' +
|
||||||
|
modsize*margin + 'px solid #fff;background:#fff">'];
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
html.push('<tr>');
|
||||||
|
for (var j = 0; j < n; ++j) {
|
||||||
|
html.push('<td style="width:' + modsize + 'px;height:' + modsize + 'px' +
|
||||||
|
(matrix[i][j] ? ';background:#000' : '') + '"></td>');
|
||||||
|
}
|
||||||
|
html.push('</tr>');
|
||||||
|
}
|
||||||
|
e.className = 'qrcode';
|
||||||
|
e.innerHTML = html.join('') + '</table>';
|
||||||
|
return e;
|
||||||
|
},
|
||||||
|
|
||||||
|
'generateSVG': function(data, options) {
|
||||||
|
options = options || {};
|
||||||
|
var matrix = QRCode['generate'](data, options);
|
||||||
|
var n = matrix.length;
|
||||||
|
var modsize = Math.max(options.modulesize || 5, 0.5);
|
||||||
|
var margin = Math.max(options.margin !== null ? options.margin : 4, 0.0);
|
||||||
|
var size = modsize * (n + 2 * margin);
|
||||||
|
|
||||||
|
var common = ' class= "fg"'+' width="'+modsize+'" height="'+modsize+'"/>';
|
||||||
|
|
||||||
|
var e = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||||
|
e.setAttribute('viewBox', '0 0 '+size+' '+size);
|
||||||
|
e.setAttribute('style', 'shape-rendering:crispEdges');
|
||||||
|
if (options.modulesize) {
|
||||||
|
e.setAttribute('width', size);
|
||||||
|
e.setAttribute('height', size);
|
||||||
|
}
|
||||||
|
|
||||||
|
var svg = [
|
||||||
|
'<style scoped>.bg{fill:#FFF}.fg{fill:#000}</style>',
|
||||||
|
'<rect class="bg" x="0" y="0"',
|
||||||
|
'width="'+size+'" height="'+size+'"/>',
|
||||||
|
];
|
||||||
|
|
||||||
|
var yo = margin * modsize;
|
||||||
|
for (var y = 0; y < n; ++y) {
|
||||||
|
var xo = margin * modsize;
|
||||||
|
for (var x = 0; x < n; ++x) {
|
||||||
|
if (matrix[y][x])
|
||||||
|
svg.push('<rect x="'+xo+'" y="'+yo+'"', common);
|
||||||
|
xo += modsize;
|
||||||
|
}
|
||||||
|
yo += modsize;
|
||||||
|
}
|
||||||
|
e.innerHTML = svg.join('');
|
||||||
|
return e;
|
||||||
|
},
|
||||||
|
|
||||||
|
'generatePNG': function(data, options) {
|
||||||
|
options = options || {};
|
||||||
|
var matrix = QRCode['generate'](data, options);
|
||||||
|
var modsize = Math.max(options.modulesize || 5, 0.5);
|
||||||
|
var margin = Math.max(options.margin !== null ? options.margin : 4, 0.0);
|
||||||
|
var n = matrix.length;
|
||||||
|
var size = modsize * (n + 2 * margin);
|
||||||
|
|
||||||
|
var canvas = document.createElement('canvas'), context;
|
||||||
|
canvas.width = canvas.height = size;
|
||||||
|
context = canvas.getContext('2d');
|
||||||
|
if (!context) throw 'canvas support is needed for PNG output';
|
||||||
|
|
||||||
|
context.fillStyle = '#fff';
|
||||||
|
context.fillRect(0, 0, size, size);
|
||||||
|
context.fillStyle = '#000';
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
for (var j = 0; j < n; ++j) {
|
||||||
|
if (matrix[i][j]) {
|
||||||
|
context.fillRect(modsize * (margin + j),
|
||||||
|
modsize * (margin + i),
|
||||||
|
modsize, modsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//context.fillText('evaluation: ' + evaluatematrix(matrix), 10, 10);
|
||||||
|
return canvas.toDataURL();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return QRCode;
|
||||||
|
});
|
||||||
31
lamassu-admin-elm/build/bower_components/webcomponentsjs/.bower.json
vendored
Normal file
31
lamassu-admin-elm/build/bower_components/webcomponentsjs/.bower.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "webcomponentsjs",
|
||||||
|
"main": "webcomponents.js",
|
||||||
|
"version": "0.7.22",
|
||||||
|
"homepage": "http://webcomponents.org",
|
||||||
|
"authors": [
|
||||||
|
"The Polymer Authors"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/webcomponents/webcomponentsjs.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"webcomponents"
|
||||||
|
],
|
||||||
|
"license": "BSD",
|
||||||
|
"ignore": [],
|
||||||
|
"devDependencies": {
|
||||||
|
"web-component-tester": "^4.0.1"
|
||||||
|
},
|
||||||
|
"_release": "0.7.22",
|
||||||
|
"_resolution": {
|
||||||
|
"type": "version",
|
||||||
|
"tag": "v0.7.22",
|
||||||
|
"commit": "50f9751f8e638301603aebb33ba9f1e90d2b0d32"
|
||||||
|
},
|
||||||
|
"_source": "https://github.com/Polymer/webcomponentsjs.git",
|
||||||
|
"_target": "^0.7.22",
|
||||||
|
"_originalSource": "webcomponentsjs",
|
||||||
|
"_direct": true
|
||||||
|
}
|
||||||
1029
lamassu-admin-elm/build/bower_components/webcomponentsjs/CustomElements.js
vendored
Normal file
1029
lamassu-admin-elm/build/bower_components/webcomponentsjs/CustomElements.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
11
lamassu-admin-elm/build/bower_components/webcomponentsjs/CustomElements.min.js
vendored
Normal file
11
lamassu-admin-elm/build/bower_components/webcomponentsjs/CustomElements.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1157
lamassu-admin-elm/build/bower_components/webcomponentsjs/HTMLImports.js
vendored
Normal file
1157
lamassu-admin-elm/build/bower_components/webcomponentsjs/HTMLImports.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
11
lamassu-admin-elm/build/bower_components/webcomponentsjs/HTMLImports.min.js
vendored
Normal file
11
lamassu-admin-elm/build/bower_components/webcomponentsjs/HTMLImports.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
350
lamassu-admin-elm/build/bower_components/webcomponentsjs/MutationObserver.js
vendored
Normal file
350
lamassu-admin-elm/build/bower_components/webcomponentsjs/MutationObserver.js
vendored
Normal file
|
|
@ -0,0 +1,350 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||||
|
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
|
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||||
|
* Code distributed by Google as part of the polymer project is also
|
||||||
|
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
// @version 0.7.22
|
||||||
|
if (typeof WeakMap === "undefined") {
|
||||||
|
(function() {
|
||||||
|
var defineProperty = Object.defineProperty;
|
||||||
|
var counter = Date.now() % 1e9;
|
||||||
|
var WeakMap = function() {
|
||||||
|
this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
|
||||||
|
};
|
||||||
|
WeakMap.prototype = {
|
||||||
|
set: function(key, value) {
|
||||||
|
var entry = key[this.name];
|
||||||
|
if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {
|
||||||
|
value: [ key, value ],
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
get: function(key) {
|
||||||
|
var entry;
|
||||||
|
return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
|
||||||
|
},
|
||||||
|
"delete": function(key) {
|
||||||
|
var entry = key[this.name];
|
||||||
|
if (!entry || entry[0] !== key) return false;
|
||||||
|
entry[0] = entry[1] = undefined;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
has: function(key) {
|
||||||
|
var entry = key[this.name];
|
||||||
|
if (!entry) return false;
|
||||||
|
return entry[0] === key;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.WeakMap = WeakMap;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
(function(global) {
|
||||||
|
if (global.JsMutationObserver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var registrationsTable = new WeakMap();
|
||||||
|
var setImmediate;
|
||||||
|
if (/Trident|Edge/.test(navigator.userAgent)) {
|
||||||
|
setImmediate = setTimeout;
|
||||||
|
} else if (window.setImmediate) {
|
||||||
|
setImmediate = window.setImmediate;
|
||||||
|
} else {
|
||||||
|
var setImmediateQueue = [];
|
||||||
|
var sentinel = String(Math.random());
|
||||||
|
window.addEventListener("message", function(e) {
|
||||||
|
if (e.data === sentinel) {
|
||||||
|
var queue = setImmediateQueue;
|
||||||
|
setImmediateQueue = [];
|
||||||
|
queue.forEach(function(func) {
|
||||||
|
func();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setImmediate = function(func) {
|
||||||
|
setImmediateQueue.push(func);
|
||||||
|
window.postMessage(sentinel, "*");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var isScheduled = false;
|
||||||
|
var scheduledObservers = [];
|
||||||
|
function scheduleCallback(observer) {
|
||||||
|
scheduledObservers.push(observer);
|
||||||
|
if (!isScheduled) {
|
||||||
|
isScheduled = true;
|
||||||
|
setImmediate(dispatchCallbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function wrapIfNeeded(node) {
|
||||||
|
return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
|
||||||
|
}
|
||||||
|
function dispatchCallbacks() {
|
||||||
|
isScheduled = false;
|
||||||
|
var observers = scheduledObservers;
|
||||||
|
scheduledObservers = [];
|
||||||
|
observers.sort(function(o1, o2) {
|
||||||
|
return o1.uid_ - o2.uid_;
|
||||||
|
});
|
||||||
|
var anyNonEmpty = false;
|
||||||
|
observers.forEach(function(observer) {
|
||||||
|
var queue = observer.takeRecords();
|
||||||
|
removeTransientObserversFor(observer);
|
||||||
|
if (queue.length) {
|
||||||
|
observer.callback_(queue, observer);
|
||||||
|
anyNonEmpty = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (anyNonEmpty) dispatchCallbacks();
|
||||||
|
}
|
||||||
|
function removeTransientObserversFor(observer) {
|
||||||
|
observer.nodes_.forEach(function(node) {
|
||||||
|
var registrations = registrationsTable.get(node);
|
||||||
|
if (!registrations) return;
|
||||||
|
registrations.forEach(function(registration) {
|
||||||
|
if (registration.observer === observer) registration.removeTransientObservers();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function forEachAncestorAndObserverEnqueueRecord(target, callback) {
|
||||||
|
for (var node = target; node; node = node.parentNode) {
|
||||||
|
var registrations = registrationsTable.get(node);
|
||||||
|
if (registrations) {
|
||||||
|
for (var j = 0; j < registrations.length; j++) {
|
||||||
|
var registration = registrations[j];
|
||||||
|
var options = registration.options;
|
||||||
|
if (node !== target && !options.subtree) continue;
|
||||||
|
var record = callback(options);
|
||||||
|
if (record) registration.enqueue(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var uidCounter = 0;
|
||||||
|
function JsMutationObserver(callback) {
|
||||||
|
this.callback_ = callback;
|
||||||
|
this.nodes_ = [];
|
||||||
|
this.records_ = [];
|
||||||
|
this.uid_ = ++uidCounter;
|
||||||
|
}
|
||||||
|
JsMutationObserver.prototype = {
|
||||||
|
observe: function(target, options) {
|
||||||
|
target = wrapIfNeeded(target);
|
||||||
|
if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {
|
||||||
|
throw new SyntaxError();
|
||||||
|
}
|
||||||
|
var registrations = registrationsTable.get(target);
|
||||||
|
if (!registrations) registrationsTable.set(target, registrations = []);
|
||||||
|
var registration;
|
||||||
|
for (var i = 0; i < registrations.length; i++) {
|
||||||
|
if (registrations[i].observer === this) {
|
||||||
|
registration = registrations[i];
|
||||||
|
registration.removeListeners();
|
||||||
|
registration.options = options;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!registration) {
|
||||||
|
registration = new Registration(this, target, options);
|
||||||
|
registrations.push(registration);
|
||||||
|
this.nodes_.push(target);
|
||||||
|
}
|
||||||
|
registration.addListeners();
|
||||||
|
},
|
||||||
|
disconnect: function() {
|
||||||
|
this.nodes_.forEach(function(node) {
|
||||||
|
var registrations = registrationsTable.get(node);
|
||||||
|
for (var i = 0; i < registrations.length; i++) {
|
||||||
|
var registration = registrations[i];
|
||||||
|
if (registration.observer === this) {
|
||||||
|
registration.removeListeners();
|
||||||
|
registrations.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
this.records_ = [];
|
||||||
|
},
|
||||||
|
takeRecords: function() {
|
||||||
|
var copyOfRecords = this.records_;
|
||||||
|
this.records_ = [];
|
||||||
|
return copyOfRecords;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function MutationRecord(type, target) {
|
||||||
|
this.type = type;
|
||||||
|
this.target = target;
|
||||||
|
this.addedNodes = [];
|
||||||
|
this.removedNodes = [];
|
||||||
|
this.previousSibling = null;
|
||||||
|
this.nextSibling = null;
|
||||||
|
this.attributeName = null;
|
||||||
|
this.attributeNamespace = null;
|
||||||
|
this.oldValue = null;
|
||||||
|
}
|
||||||
|
function copyMutationRecord(original) {
|
||||||
|
var record = new MutationRecord(original.type, original.target);
|
||||||
|
record.addedNodes = original.addedNodes.slice();
|
||||||
|
record.removedNodes = original.removedNodes.slice();
|
||||||
|
record.previousSibling = original.previousSibling;
|
||||||
|
record.nextSibling = original.nextSibling;
|
||||||
|
record.attributeName = original.attributeName;
|
||||||
|
record.attributeNamespace = original.attributeNamespace;
|
||||||
|
record.oldValue = original.oldValue;
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
var currentRecord, recordWithOldValue;
|
||||||
|
function getRecord(type, target) {
|
||||||
|
return currentRecord = new MutationRecord(type, target);
|
||||||
|
}
|
||||||
|
function getRecordWithOldValue(oldValue) {
|
||||||
|
if (recordWithOldValue) return recordWithOldValue;
|
||||||
|
recordWithOldValue = copyMutationRecord(currentRecord);
|
||||||
|
recordWithOldValue.oldValue = oldValue;
|
||||||
|
return recordWithOldValue;
|
||||||
|
}
|
||||||
|
function clearRecords() {
|
||||||
|
currentRecord = recordWithOldValue = undefined;
|
||||||
|
}
|
||||||
|
function recordRepresentsCurrentMutation(record) {
|
||||||
|
return record === recordWithOldValue || record === currentRecord;
|
||||||
|
}
|
||||||
|
function selectRecord(lastRecord, newRecord) {
|
||||||
|
if (lastRecord === newRecord) return lastRecord;
|
||||||
|
if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function Registration(observer, target, options) {
|
||||||
|
this.observer = observer;
|
||||||
|
this.target = target;
|
||||||
|
this.options = options;
|
||||||
|
this.transientObservedNodes = [];
|
||||||
|
}
|
||||||
|
Registration.prototype = {
|
||||||
|
enqueue: function(record) {
|
||||||
|
var records = this.observer.records_;
|
||||||
|
var length = records.length;
|
||||||
|
if (records.length > 0) {
|
||||||
|
var lastRecord = records[length - 1];
|
||||||
|
var recordToReplaceLast = selectRecord(lastRecord, record);
|
||||||
|
if (recordToReplaceLast) {
|
||||||
|
records[length - 1] = recordToReplaceLast;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scheduleCallback(this.observer);
|
||||||
|
}
|
||||||
|
records[length] = record;
|
||||||
|
},
|
||||||
|
addListeners: function() {
|
||||||
|
this.addListeners_(this.target);
|
||||||
|
},
|
||||||
|
addListeners_: function(node) {
|
||||||
|
var options = this.options;
|
||||||
|
if (options.attributes) node.addEventListener("DOMAttrModified", this, true);
|
||||||
|
if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true);
|
||||||
|
if (options.childList) node.addEventListener("DOMNodeInserted", this, true);
|
||||||
|
if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true);
|
||||||
|
},
|
||||||
|
removeListeners: function() {
|
||||||
|
this.removeListeners_(this.target);
|
||||||
|
},
|
||||||
|
removeListeners_: function(node) {
|
||||||
|
var options = this.options;
|
||||||
|
if (options.attributes) node.removeEventListener("DOMAttrModified", this, true);
|
||||||
|
if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true);
|
||||||
|
if (options.childList) node.removeEventListener("DOMNodeInserted", this, true);
|
||||||
|
if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true);
|
||||||
|
},
|
||||||
|
addTransientObserver: function(node) {
|
||||||
|
if (node === this.target) return;
|
||||||
|
this.addListeners_(node);
|
||||||
|
this.transientObservedNodes.push(node);
|
||||||
|
var registrations = registrationsTable.get(node);
|
||||||
|
if (!registrations) registrationsTable.set(node, registrations = []);
|
||||||
|
registrations.push(this);
|
||||||
|
},
|
||||||
|
removeTransientObservers: function() {
|
||||||
|
var transientObservedNodes = this.transientObservedNodes;
|
||||||
|
this.transientObservedNodes = [];
|
||||||
|
transientObservedNodes.forEach(function(node) {
|
||||||
|
this.removeListeners_(node);
|
||||||
|
var registrations = registrationsTable.get(node);
|
||||||
|
for (var i = 0; i < registrations.length; i++) {
|
||||||
|
if (registrations[i] === this) {
|
||||||
|
registrations.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
handleEvent: function(e) {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
switch (e.type) {
|
||||||
|
case "DOMAttrModified":
|
||||||
|
var name = e.attrName;
|
||||||
|
var namespace = e.relatedNode.namespaceURI;
|
||||||
|
var target = e.target;
|
||||||
|
var record = new getRecord("attributes", target);
|
||||||
|
record.attributeName = name;
|
||||||
|
record.attributeNamespace = namespace;
|
||||||
|
var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
|
||||||
|
forEachAncestorAndObserverEnqueueRecord(target, function(options) {
|
||||||
|
if (!options.attributes) return;
|
||||||
|
if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
|
||||||
|
return record;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "DOMCharacterDataModified":
|
||||||
|
var target = e.target;
|
||||||
|
var record = getRecord("characterData", target);
|
||||||
|
var oldValue = e.prevValue;
|
||||||
|
forEachAncestorAndObserverEnqueueRecord(target, function(options) {
|
||||||
|
if (!options.characterData) return;
|
||||||
|
if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);
|
||||||
|
return record;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "DOMNodeRemoved":
|
||||||
|
this.addTransientObserver(e.target);
|
||||||
|
|
||||||
|
case "DOMNodeInserted":
|
||||||
|
var changedNode = e.target;
|
||||||
|
var addedNodes, removedNodes;
|
||||||
|
if (e.type === "DOMNodeInserted") {
|
||||||
|
addedNodes = [ changedNode ];
|
||||||
|
removedNodes = [];
|
||||||
|
} else {
|
||||||
|
addedNodes = [];
|
||||||
|
removedNodes = [ changedNode ];
|
||||||
|
}
|
||||||
|
var previousSibling = changedNode.previousSibling;
|
||||||
|
var nextSibling = changedNode.nextSibling;
|
||||||
|
var record = getRecord("childList", e.target.parentNode);
|
||||||
|
record.addedNodes = addedNodes;
|
||||||
|
record.removedNodes = removedNodes;
|
||||||
|
record.previousSibling = previousSibling;
|
||||||
|
record.nextSibling = nextSibling;
|
||||||
|
forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {
|
||||||
|
if (!options.childList) return;
|
||||||
|
return record;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
clearRecords();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
global.JsMutationObserver = JsMutationObserver;
|
||||||
|
if (!global.MutationObserver) {
|
||||||
|
global.MutationObserver = JsMutationObserver;
|
||||||
|
JsMutationObserver._isPolyfilled = true;
|
||||||
|
}
|
||||||
|
})(self);
|
||||||
11
lamassu-admin-elm/build/bower_components/webcomponentsjs/MutationObserver.min.js
vendored
Normal file
11
lamassu-admin-elm/build/bower_components/webcomponentsjs/MutationObserver.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
155
lamassu-admin-elm/build/bower_components/webcomponentsjs/README.md
vendored
Normal file
155
lamassu-admin-elm/build/bower_components/webcomponentsjs/README.md
vendored
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
webcomponents.js
|
||||||
|
================
|
||||||
|
|
||||||
|
[](https://gitter.im/webcomponents/webcomponentsjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
A suite of polyfills supporting the [Web Components](http://webcomponents.org) specs:
|
||||||
|
|
||||||
|
**Custom Elements**: allows authors to define their own custom tags ([spec](https://w3c.github.io/webcomponents/spec/custom/)).
|
||||||
|
|
||||||
|
**HTML Imports**: a way to include and reuse HTML documents via other HTML documents ([spec](https://w3c.github.io/webcomponents/spec/imports/)).
|
||||||
|
|
||||||
|
**Shadow DOM**: provides encapsulation by hiding DOM subtrees under shadow roots ([spec](https://w3c.github.io/webcomponents/spec/shadow/)).
|
||||||
|
|
||||||
|
This also folds in polyfills for `MutationObserver` and `WeakMap`.
|
||||||
|
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
Pre-built (concatenated & minified) versions of the polyfills are maintained in the [tagged versions](https://github.com/webcomponents/webcomponentsjs/releases) of this repo. There are two variants:
|
||||||
|
|
||||||
|
`webcomponents.js` includes all of the polyfills.
|
||||||
|
|
||||||
|
`webcomponents-lite.js` includes all polyfills except for shadow DOM.
|
||||||
|
|
||||||
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
Our polyfills are intended to work in the latest versions of evergreen browsers. See below
|
||||||
|
for our complete browser support matrix:
|
||||||
|
|
||||||
|
| Polyfill | IE10 | IE11+ | Chrome* | Firefox* | Safari 7+* | Chrome Android* | Mobile Safari* |
|
||||||
|
| ---------- |:----:|:-----:|:-------:|:--------:|:----------:|:---------------:|:--------------:|
|
||||||
|
| Custom Elements | ~ | ✓ | ✓ | ✓ | ✓ | ✓| ✓ |
|
||||||
|
| HTML Imports | ~ | ✓ | ✓ | ✓ | ✓| ✓| ✓ |
|
||||||
|
| Shadow DOM | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| Templates | ✓ | ✓ | ✓ | ✓| ✓ | ✓ | ✓ |
|
||||||
|
|
||||||
|
|
||||||
|
*Indicates the current version of the browser
|
||||||
|
|
||||||
|
~Indicates support may be flaky. If using Custom Elements or HTML Imports with Shadow DOM,
|
||||||
|
you will get the non-flaky Mutation Observer polyfill that Shadow DOM includes.
|
||||||
|
|
||||||
|
The polyfills may work in older browsers, however require additional polyfills (such as classList)
|
||||||
|
to be used. We cannot guarantee support for browsers outside of our compatibility matrix.
|
||||||
|
|
||||||
|
|
||||||
|
### Manually Building
|
||||||
|
|
||||||
|
If you wish to build the polyfills yourself, you'll need `node` and `gulp` on your system:
|
||||||
|
|
||||||
|
* install [node.js](http://nodejs.org/) using the instructions on their website
|
||||||
|
* use `npm` to install [gulp.js](http://gulpjs.com/): `npm install -g gulp`
|
||||||
|
|
||||||
|
Now you are ready to build the polyfills with:
|
||||||
|
|
||||||
|
# install dependencies
|
||||||
|
npm install
|
||||||
|
# build
|
||||||
|
gulp build
|
||||||
|
|
||||||
|
The builds will be placed into the `dist/` directory.
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
See the [contributing guide](CONTRIBUTING.md)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Everything in this repository is BSD style license unless otherwise specified.
|
||||||
|
|
||||||
|
Copyright (c) 2015 The Polymer Authors. All rights reserved.
|
||||||
|
|
||||||
|
## Helper utilities
|
||||||
|
|
||||||
|
### `WebComponentsReady`
|
||||||
|
|
||||||
|
Under native HTML Imports, `<script>` tags in the main document block the loading of such imports. This is to ensure the imports have loaded and any registered elements in them have been upgraded.
|
||||||
|
|
||||||
|
The webcomponents.js and webcomponents-lite.js polyfills parse element definitions and handle their upgrade asynchronously. If prematurely fetching the element from the DOM before it has an opportunity to upgrade, you'll be working with an `HTMLUnknownElement`.
|
||||||
|
|
||||||
|
For these situations (or when you need an approximate replacement for the Polymer 0.5 `polymer-ready` behavior), you can use the `WebComponentsReady` event as a signal before interacting with the element. The criteria for this event to fire is all Custom Elements with definitions registered by the time HTML Imports available at load time have loaded have upgraded.
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.addEventListener('WebComponentsReady', function(e) {
|
||||||
|
// imports are loaded and elements have been registered
|
||||||
|
console.log('Components are ready');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
|
* [Limited CSS encapsulation](#encapsulation)
|
||||||
|
* [Element wrapping / unwrapping limitations](#wrapping)
|
||||||
|
* [Custom element's constructor property is unreliable](#constructor)
|
||||||
|
* [Contenteditable elements do not trigger MutationObserver](#contentedit)
|
||||||
|
* [ShadowCSS: :host-context(...):host(...) doesn't work](#hostcontext)
|
||||||
|
* [ShadowCSS: :host(.zot:not(.bar:nth-child(2))) doesn't work](#nestedparens)
|
||||||
|
* [HTML imports: document.currentScript doesn't work as expected](#currentscript)
|
||||||
|
* [execCommand isn't supported under Shadow DOM](#execcommand)
|
||||||
|
|
||||||
|
### Limited CSS encapsulation <a id="encapsulation"></a>
|
||||||
|
Under native Shadow DOM, CSS selectors cannot cross the shadow boundary. This means document level styles don't apply to shadow roots, and styles defined within a shadow root don't apply outside of that shadow root. [Several selectors](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/) are provided to be able to deal with the shadow boundary.
|
||||||
|
|
||||||
|
The Shadow DOM polyfill can't prevent document styles from leaking into shadow roots. It can, however, encapsulate styles within shadow roots to some extent. This behavior isn't automatically emulated by the Shadow DOM polyfill, but it can be achieved by manually using the included ShadowCSS shim:
|
||||||
|
|
||||||
|
```
|
||||||
|
WebComponents.ShadowCSS.shimStyling( shadowRoot, scope );
|
||||||
|
```
|
||||||
|
|
||||||
|
... where `shadowRoot` is the shadow root of a DOM element, and `scope` is the name of the scope used to prefix the selectors. This removes all `<style>` elements from the shadow root, rewrites it rules using the given scope and reinserts the style as a document level stylesheet. Note that the `:host` and `:host-context` pseudo classes are also rewritten.
|
||||||
|
|
||||||
|
For a full explanation on the implementation and both the possibilities and the limitations of ShadowCSS please view the documentation in the [ShadowCSS source](src/ShadowCSS/ShadowCSS.js).
|
||||||
|
|
||||||
|
### Element wrapping / unwrapping limitations <a id="wrapping"></a>
|
||||||
|
The Shadow DOM polyfill is implemented by [wrapping](http://webcomponents.org/polyfills/shadow-dom/#wrappers) DOM elements whenever possible. It does this by wrapping methods like `document.querySelector` to return wrapped DOM elements. This has a few caveats:
|
||||||
|
* Not _everything_ can be wrapped. For example, elements like `document`, `window`, `document.body`, `document.fullscreenElement` and others are non-configurable and thus cannot be overridden.
|
||||||
|
* Wrappers don't support [live NodeLists](https://developer.mozilla.org/en-US/docs/Web/API/NodeList#A_sometimes-live_collection) like `HTMLElement.childNodes` and `HTMLFormElement.elements`. All NodeLists are snapshotted upon read. See [#217](https://github.com/webcomponents/webcomponentsjs/issues/217) for an explanation.
|
||||||
|
|
||||||
|
In order to work around these limitations the polyfill provides the `ShadowDOMPolyfill.wrap` and `ShadowDOMPolyfill.unwrap` methods to respectively wrap and unwrap DOM elements manually.
|
||||||
|
|
||||||
|
### Custom element's constructor property is unreliable <a id="constructor"></a>
|
||||||
|
See [#215](https://github.com/webcomponents/webcomponentsjs/issues/215) for background.
|
||||||
|
|
||||||
|
In Safari and IE, instances of Custom Elements have a `constructor` property of `HTMLUnknownElementConstructor` and `HTMLUnknownElement`, respectively. It's unsafe to rely on this property for checking element types.
|
||||||
|
|
||||||
|
It's worth noting that `customElement.__proto__.__proto__.constructor` is `HTMLElementPrototype` and that the prototype chain isn't modified by the polyfills(onto `ElementPrototype`, etc.)
|
||||||
|
|
||||||
|
### Contenteditable elements do not trigger MutationObserver <a id="contentedit"></a>
|
||||||
|
Using the MutationObserver polyfill, it isn't possible to monitor mutations of an element marked `contenteditable`.
|
||||||
|
See [the mailing list](https://groups.google.com/forum/#!msg/polymer-dev/LHdtRVXXVsA/v1sGoiTYWUkJ)
|
||||||
|
|
||||||
|
### ShadowCSS: :host-context(...):host(...) doesn't work <a id="hostcontext"></a>
|
||||||
|
See [#16](https://github.com/webcomponents/webcomponentsjs/issues/16) for background.
|
||||||
|
|
||||||
|
Under the shadow DOM polyfill, rules like:
|
||||||
|
```
|
||||||
|
:host-context(.foo):host(.bar) {...}
|
||||||
|
```
|
||||||
|
don't work, despite working under native Shadow DOM. The solution is to use `polyfill-next-selector` like:
|
||||||
|
|
||||||
|
```
|
||||||
|
polyfill-next-selector { content: '.foo :host.bar, :host.foo.bar'; }
|
||||||
|
```
|
||||||
|
|
||||||
|
### ShadowCSS: :host(.zot:not(.bar:nth-child(2))) doesn't work <a id="nestedparens"></a>
|
||||||
|
ShadowCSS `:host()` rules can only have (at most) 1-level of nested parentheses in its argument selector under ShadowCSS. For example, `:host(.zot)` and `:host(.zot:not(.bar))` both work, but `:host(.zot:not(.bar:nth-child(2)))` does not.
|
||||||
|
|
||||||
|
### HTML imports: document.currentScript doesn't work as expected <a id="currentscript"></a>
|
||||||
|
In native HTML Imports, document.currentScript.ownerDocument references the import document itself. In the polyfill use document._currentScript.ownerDocument (note the underscore).
|
||||||
|
|
||||||
|
### execCommand and contenteditable isn't supported under Shadow DOM <a id="execcommand"></a>
|
||||||
|
See [#212](https://github.com/webcomponents/webcomponentsjs/issues/212)
|
||||||
|
|
||||||
|
`execCommand`, and `contenteditable` aren't supported under the ShadowDOM polyfill, with commands that insert or remove nodes being especially prone to failure.
|
||||||
4493
lamassu-admin-elm/build/bower_components/webcomponentsjs/ShadowDOM.js
vendored
Normal file
4493
lamassu-admin-elm/build/bower_components/webcomponentsjs/ShadowDOM.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
13
lamassu-admin-elm/build/bower_components/webcomponentsjs/ShadowDOM.min.js
vendored
Normal file
13
lamassu-admin-elm/build/bower_components/webcomponentsjs/ShadowDOM.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
lamassu-admin-elm/build/bower_components/webcomponentsjs/bower.json
vendored
Normal file
21
lamassu-admin-elm/build/bower_components/webcomponentsjs/bower.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "webcomponentsjs",
|
||||||
|
"main": "webcomponents.js",
|
||||||
|
"version": "0.7.22",
|
||||||
|
"homepage": "http://webcomponents.org",
|
||||||
|
"authors": [
|
||||||
|
"The Polymer Authors"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/webcomponents/webcomponentsjs.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"webcomponents"
|
||||||
|
],
|
||||||
|
"license": "BSD",
|
||||||
|
"ignore": [],
|
||||||
|
"devDependencies": {
|
||||||
|
"web-component-tester": "^4.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
31
lamassu-admin-elm/build/bower_components/webcomponentsjs/package.json
vendored
Normal file
31
lamassu-admin-elm/build/bower_components/webcomponentsjs/package.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "webcomponents.js",
|
||||||
|
"version": "0.7.22",
|
||||||
|
"description": "webcomponents.js",
|
||||||
|
"main": "webcomponents.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "tests"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/webcomponents/webcomponentsjs.git"
|
||||||
|
},
|
||||||
|
"author": "The Polymer Authors",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/webcomponents/webcomponentsjs/issues"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "wct"
|
||||||
|
},
|
||||||
|
"homepage": "http://webcomponents.org",
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "^3.8.8",
|
||||||
|
"gulp-audit": "^1.0.0",
|
||||||
|
"gulp-concat": "^2.4.1",
|
||||||
|
"gulp-header": "^1.1.1",
|
||||||
|
"gulp-uglify": "^1.0.1",
|
||||||
|
"run-sequence": "^1.0.1",
|
||||||
|
"web-component-tester": "^4.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
2505
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents-lite.js
vendored
Normal file
2505
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents-lite.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
12
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents-lite.min.js
vendored
Normal file
12
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents-lite.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7206
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents.js
vendored
Normal file
7206
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
14
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents.min.js
vendored
Normal file
14
lamassu-admin-elm/build/bower_components/webcomponentsjs/webcomponents.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
lamassu-admin-elm/build/favicon.ico
Normal file
BIN
lamassu-admin-elm/build/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
23
lamassu-admin-elm/build/index.html
Normal file
23
lamassu-admin-elm/build/index.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<base href="/">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||||
|
<script src="bower_components/qrjs/qr.js"></script>
|
||||||
|
<script src="bower_components/qr-code/src/qr-code.js"></script>
|
||||||
|
<script src="elm.js"></script>
|
||||||
|
<script>
|
||||||
|
Elm.Main.fullscreen()
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" href="bower_components/gridism/gridism.css">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<style>
|
||||||
|
@keyframes fadein {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
3
lamassu-admin-elm/cli.txt
Normal file
3
lamassu-admin-elm/cli.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
ls src/Css/* | entr elm-css src/Stylesheets.elm
|
||||||
|
find src | entr elm-make src/Main.elm --output ../lamassu-server/public/elm.js
|
||||||
|
find src | entr elm-make src/Lamassu.elm --output ../lamassu-server/public/lamassu-elm.js
|
||||||
37
lamassu-admin-elm/elm-package.json
Normal file
37
lamassu-admin-elm/elm-package.json
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"summary": "helpful summary of your project, less than 80 characters",
|
||||||
|
"repository": "https://github.com/user/project.git",
|
||||||
|
"license": "Unlicense",
|
||||||
|
"source-directories": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exposed-modules": [],
|
||||||
|
"dependencies": {
|
||||||
|
"NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0",
|
||||||
|
"arturopala/elm-monocle": "1.3.1 <= v < 2.0.0",
|
||||||
|
"elm-community/json-extra": "2.0.0 <= v < 3.0.0",
|
||||||
|
"elm-community/maybe-extra": "4.0.0 <= v < 5.0.0",
|
||||||
|
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||||
|
"elm-lang/html": "2.0.0 <= v < 3.0.0",
|
||||||
|
"elm-lang/http": "1.0.0 <= v < 2.0.0",
|
||||||
|
"elm-lang/keyboard": "1.0.1 <= v < 2.0.0",
|
||||||
|
"elm-lang/navigation": "2.0.1 <= v < 3.0.0",
|
||||||
|
"elm-lang/virtual-dom": "2.0.0 <= v < 3.0.0",
|
||||||
|
"elm-lang/websocket": "1.0.2 <= v < 2.0.0",
|
||||||
|
"evancz/elm-markdown": "3.0.1 <= v < 4.0.0",
|
||||||
|
"evancz/url-parser": "2.0.1 <= v < 3.0.0",
|
||||||
|
"ggb/numeral-elm": "1.2.3 <= v < 2.0.0",
|
||||||
|
"justinmimbs/elm-date-extra": "2.0.2 <= v < 3.0.0",
|
||||||
|
"krisajenkins/remotedata": "4.0.0 <= v < 5.0.0",
|
||||||
|
"lukewestby/elm-http-builder": "5.1.0 <= v < 6.0.0",
|
||||||
|
"pablohirafuji/elm-qrcode": "1.0.1 <= v < 2.0.0",
|
||||||
|
"rluiten/stringdistance": "1.0.3 <= v < 2.0.0",
|
||||||
|
"rtfeldman/elm-css": "10.0.0 <= v < 11.0.0",
|
||||||
|
"rtfeldman/elm-css-helpers": "2.1.0 <= v < 3.0.0",
|
||||||
|
"rtfeldman/elm-css-util": "1.0.2 <= v < 2.0.0",
|
||||||
|
"rtfeldman/elm-validate": "1.1.3 <= v < 2.0.0",
|
||||||
|
"tripokey/elm-fuzzy": "5.0.3 <= v < 6.0.0"
|
||||||
|
},
|
||||||
|
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||||
|
}
|
||||||
164
lamassu-admin-elm/src/Account.elm
Normal file
164
lamassu-admin-elm/src/Account.elm
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
module Account exposing (..)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Events exposing (..)
|
||||||
|
import Html.Keyed
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Http
|
||||||
|
import HttpBuilder exposing (..)
|
||||||
|
import AccountTypes exposing (..)
|
||||||
|
import AccountDecoder exposing (..)
|
||||||
|
import AccountEncoder exposing (..)
|
||||||
|
import FieldSet.Types
|
||||||
|
import FieldSet.State
|
||||||
|
import FieldSet.View
|
||||||
|
import Css.Admin exposing (..)
|
||||||
|
import Css.Classes
|
||||||
|
import Process
|
||||||
|
import Time exposing (second)
|
||||||
|
import Task
|
||||||
|
|
||||||
|
|
||||||
|
type alias SubModel =
|
||||||
|
{ status : SavingStatus
|
||||||
|
, account : Account
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
RemoteData.WebData SubModel
|
||||||
|
|
||||||
|
|
||||||
|
type SavingStatus
|
||||||
|
= Saving
|
||||||
|
| Saved
|
||||||
|
| Editing
|
||||||
|
| NotSaving
|
||||||
|
|
||||||
|
|
||||||
|
toModel : SavingStatus -> Account -> SubModel
|
||||||
|
toModel status account =
|
||||||
|
{ status = status, account = account }
|
||||||
|
|
||||||
|
|
||||||
|
getForm : String -> Cmd Msg
|
||||||
|
getForm code =
|
||||||
|
get ("/api/account/" ++ code)
|
||||||
|
|> withExpect (Http.expectJson accountDecoder)
|
||||||
|
|> send (Result.map (toModel NotSaving) >> RemoteData.fromResult)
|
||||||
|
|> Cmd.map Load
|
||||||
|
|
||||||
|
|
||||||
|
postForm : Account -> Cmd Msg
|
||||||
|
postForm account =
|
||||||
|
post "/api/account"
|
||||||
|
|> withJsonBody (encodeAccount account)
|
||||||
|
|> withExpect (Http.expectJson accountDecoder)
|
||||||
|
|> send (Result.map (toModel Saved) >> RemoteData.fromResult)
|
||||||
|
|> Cmd.map Load
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
RemoteData.NotAsked
|
||||||
|
|
||||||
|
|
||||||
|
load : String -> ( Model, Cmd Msg )
|
||||||
|
load code =
|
||||||
|
( RemoteData.Loading, getForm code )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- UPDATE
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Load Model
|
||||||
|
| Submit
|
||||||
|
| FieldSetMsg FieldSet.Types.Msg
|
||||||
|
| HideSaveIndication
|
||||||
|
|
||||||
|
|
||||||
|
saveUpdate : SubModel -> ( SubModel, Cmd Msg )
|
||||||
|
saveUpdate model =
|
||||||
|
let
|
||||||
|
cmd =
|
||||||
|
if (model.status == Saved) then
|
||||||
|
Process.sleep (2 * second)
|
||||||
|
|> Task.perform (\_ -> HideSaveIndication)
|
||||||
|
else
|
||||||
|
Cmd.none
|
||||||
|
in
|
||||||
|
model ! [ cmd ]
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg webModel =
|
||||||
|
case msg of
|
||||||
|
Load newModel ->
|
||||||
|
RemoteData.update saveUpdate newModel
|
||||||
|
|
||||||
|
Submit ->
|
||||||
|
RemoteData.update (\model -> model ! [ postForm model.account ]) webModel
|
||||||
|
|
||||||
|
HideSaveIndication ->
|
||||||
|
RemoteData.update (\model -> { model | status = NotSaving } ! []) webModel
|
||||||
|
|
||||||
|
FieldSetMsg fieldSetMsg ->
|
||||||
|
let
|
||||||
|
updateFields model =
|
||||||
|
FieldSet.State.update fieldSetMsg model.account.fields
|
||||||
|
|
||||||
|
newAccount account fields =
|
||||||
|
{ account | fields = fields }
|
||||||
|
|
||||||
|
toModel model fieldsUpdate =
|
||||||
|
{ model
|
||||||
|
| account =
|
||||||
|
newAccount model.account
|
||||||
|
(Tuple.first fieldsUpdate)
|
||||||
|
}
|
||||||
|
! [ Cmd.map FieldSetMsg (Tuple.second fieldsUpdate) ]
|
||||||
|
|
||||||
|
mapper model =
|
||||||
|
updateFields model
|
||||||
|
|> (toModel model)
|
||||||
|
in
|
||||||
|
RemoteData.update mapper webModel
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view webModel =
|
||||||
|
case webModel of
|
||||||
|
NotAsked ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
div [] [ text "Loading..." ]
|
||||||
|
|
||||||
|
Failure err ->
|
||||||
|
div [] [ text (toString err) ]
|
||||||
|
|
||||||
|
Success model ->
|
||||||
|
let
|
||||||
|
fieldSetView =
|
||||||
|
Html.Keyed.node "div" [] [ ( model.account.code, (Html.map FieldSetMsg (FieldSet.View.view model.account.fields)) ) ]
|
||||||
|
|
||||||
|
statusString =
|
||||||
|
case model.status of
|
||||||
|
Saved ->
|
||||||
|
"Saved"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
""
|
||||||
|
in
|
||||||
|
div []
|
||||||
|
[ div [ class [ Css.Classes.SectionLabel ] ] [ text model.account.display ]
|
||||||
|
, form [ id model.account.code ]
|
||||||
|
[ fieldSetView
|
||||||
|
, div [ class [ Css.Classes.ButtonRow ] ]
|
||||||
|
[ div [ onClick Submit, class [ Css.Classes.Button ] ] [ text "Submit" ]
|
||||||
|
, div [] [ text statusString ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
22
lamassu-admin-elm/src/AccountDecoder.elm
Normal file
22
lamassu-admin-elm/src/AccountDecoder.elm
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
module AccountDecoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Decode exposing (..)
|
||||||
|
import FieldSet.Rest exposing (..)
|
||||||
|
import AccountTypes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
accountDecoder : Decoder Account
|
||||||
|
accountDecoder =
|
||||||
|
map3 Account
|
||||||
|
(field "code" string)
|
||||||
|
(field "display" string)
|
||||||
|
(field "fields" (list fieldDecoder))
|
||||||
|
|
||||||
|
|
||||||
|
type alias AccountResult =
|
||||||
|
Result String Account
|
||||||
|
|
||||||
|
|
||||||
|
decodeAccount : String -> AccountResult
|
||||||
|
decodeAccount string =
|
||||||
|
decodeString accountDecoder string
|
||||||
15
lamassu-admin-elm/src/AccountEncoder.elm
Normal file
15
lamassu-admin-elm/src/AccountEncoder.elm
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
module AccountEncoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Encode exposing (..)
|
||||||
|
import AccountTypes exposing (..)
|
||||||
|
import List
|
||||||
|
import FieldSet.Rest exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
encodeAccount : Account -> Value
|
||||||
|
encodeAccount account =
|
||||||
|
Json.Encode.object
|
||||||
|
[ ( "code", string account.code )
|
||||||
|
, ( "display", string account.display )
|
||||||
|
, ( "fields", list (List.filterMap encodeField account.fields) )
|
||||||
|
]
|
||||||
10
lamassu-admin-elm/src/AccountTypes.elm
Normal file
10
lamassu-admin-elm/src/AccountTypes.elm
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
module AccountTypes exposing (..)
|
||||||
|
|
||||||
|
import FieldSet.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Account =
|
||||||
|
{ code : String
|
||||||
|
, display : String
|
||||||
|
, fields : List Field
|
||||||
|
}
|
||||||
16
lamassu-admin-elm/src/AccountsDecoder.elm
Normal file
16
lamassu-admin-elm/src/AccountsDecoder.elm
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
module AccountsDecoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Decode exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
accountDecoder : Decoder ( String, String )
|
||||||
|
accountDecoder =
|
||||||
|
map2 (,)
|
||||||
|
(field "code" string)
|
||||||
|
(field "display" string)
|
||||||
|
|
||||||
|
|
||||||
|
accountsDecoder : Decoder (List ( String, String ))
|
||||||
|
accountsDecoder =
|
||||||
|
map identity
|
||||||
|
(field "accounts" (list accountDecoder))
|
||||||
8
lamassu-admin-elm/src/BasicTypes.elm
Normal file
8
lamassu-admin-elm/src/BasicTypes.elm
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
module BasicTypes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type SavingStatus
|
||||||
|
= Saving
|
||||||
|
| Saved
|
||||||
|
| Editing
|
||||||
|
| NotSaving
|
||||||
45
lamassu-admin-elm/src/ClientServerWebsocket.elm
Normal file
45
lamassu-admin-elm/src/ClientServerWebsocket.elm
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
module ClientServerWebsocket exposing (..)
|
||||||
|
|
||||||
|
-- Elm might not be the best platform for this kind of thing
|
||||||
|
-- Hard to do a global lookup table
|
||||||
|
-- Might be easiest to just use HTTP for this for now
|
||||||
|
-- No need to prematurely optimize and go against the flow
|
||||||
|
|
||||||
|
import WebSocket
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= OK
|
||||||
|
| Timeout
|
||||||
|
|
||||||
|
|
||||||
|
type alias Client =
|
||||||
|
Sub Msg
|
||||||
|
|
||||||
|
|
||||||
|
init : String -> Client
|
||||||
|
init url =
|
||||||
|
let
|
||||||
|
sub =
|
||||||
|
WebSocket.listen url parsePacket
|
||||||
|
in
|
||||||
|
sub
|
||||||
|
|
||||||
|
|
||||||
|
request : Client -> String -> String -> Cmd Msg
|
||||||
|
request client url payload =
|
||||||
|
let
|
||||||
|
cmd =
|
||||||
|
Cmd.map (respond client) (WebSocket.send url payload)
|
||||||
|
in
|
||||||
|
cmd
|
||||||
|
|
||||||
|
|
||||||
|
parsePacket : String -> Msg
|
||||||
|
parsePacket packet =
|
||||||
|
OK
|
||||||
|
|
||||||
|
|
||||||
|
respond : client -> (a -> Msg)
|
||||||
|
respond client =
|
||||||
|
(\_ -> OK)
|
||||||
77
lamassu-admin-elm/src/Common/Customer/Decoder.elm
Normal file
77
lamassu-admin-elm/src/Common/Customer/Decoder.elm
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
module Common.Customer.Decoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Decode exposing (..)
|
||||||
|
import Json.Decode.Extra exposing (date, fromResult)
|
||||||
|
import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded)
|
||||||
|
import Common.Customer.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
customersDecoder : Decoder (List Customer)
|
||||||
|
customersDecoder =
|
||||||
|
field "customers" (list customerDecoder)
|
||||||
|
|
||||||
|
|
||||||
|
mapAuthorizedTypes : String -> Decoder Authorized
|
||||||
|
mapAuthorizedTypes s =
|
||||||
|
case s of
|
||||||
|
"blocked" ->
|
||||||
|
succeed Blocked
|
||||||
|
|
||||||
|
"verified" ->
|
||||||
|
succeed Verified
|
||||||
|
|
||||||
|
"automatic" ->
|
||||||
|
succeed Automatic
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
fail ("No such type " ++ s)
|
||||||
|
|
||||||
|
|
||||||
|
authorizedDecoder : Decoder Authorized
|
||||||
|
authorizedDecoder =
|
||||||
|
string
|
||||||
|
|> andThen mapAuthorizedTypes
|
||||||
|
|
||||||
|
|
||||||
|
idCardDataDecoder : Decoder IdCardData
|
||||||
|
idCardDataDecoder =
|
||||||
|
decode IdCardData
|
||||||
|
|> required "uid" string
|
||||||
|
|
||||||
|
customerDecoder : Decoder Customer
|
||||||
|
customerDecoder =
|
||||||
|
decode Customer
|
||||||
|
|> required "id" string
|
||||||
|
|> required "name" (nullable string)
|
||||||
|
|> required "phone" (nullable string)
|
||||||
|
|> required "phoneAt" (nullable date)
|
||||||
|
|> required "smsOverride" authorizedDecoder
|
||||||
|
|> required "smsOverrideByName" (nullable string)
|
||||||
|
|> required "smsOverrideAt" (nullable date)
|
||||||
|
|> required "created" date
|
||||||
|
|> required "status" (nullable string)
|
||||||
|
|> required "authorizedOverride" authorizedDecoder
|
||||||
|
|> required "authorizedOverrideByName" (nullable string)
|
||||||
|
|> required "authorizedOverrideAt" (nullable date)
|
||||||
|
|> required "authorizedAt" (nullable date)
|
||||||
|
|> required "idCardData" (nullable idCardDataDecoder)
|
||||||
|
|> required "idCardDataOverride" authorizedDecoder
|
||||||
|
|> required "idCardDataOverrideByName" (nullable string)
|
||||||
|
|> required "idCardDataOverrideAt" (nullable date)
|
||||||
|
|> required "idCardDataAt" (nullable date)
|
||||||
|
|> required "idCardPhotoPath" (nullable string)
|
||||||
|
|> required "idCardPhotoOverride" authorizedDecoder
|
||||||
|
|> required "idCardPhotoOverrideByName" (nullable string)
|
||||||
|
|> required "idCardPhotoOverrideAt" (nullable date)
|
||||||
|
|> required "idCardPhotoAt" (nullable date)
|
||||||
|
|> required "sanctions" (nullable bool)
|
||||||
|
|> required "sanctionsOverride" authorizedDecoder
|
||||||
|
|> required "sanctionsOverrideByName" (nullable string)
|
||||||
|
|> required "sanctionsOverrideAt" (nullable date)
|
||||||
|
|> required "sanctionsAt" (nullable date)
|
||||||
|
|> required "frontCameraPath" (nullable string)
|
||||||
|
|> required "frontCameraOverride" authorizedDecoder
|
||||||
|
|> required "frontCameraOverrideByName" (nullable string)
|
||||||
|
|> required "frontCameraOverrideAt" (nullable date)
|
||||||
|
|> required "frontCameraAt" (nullable date)
|
||||||
|
|> required "dailyVolume" (nullable string)
|
||||||
67
lamassu-admin-elm/src/Common/Customer/Types.elm
Normal file
67
lamassu-admin-elm/src/Common/Customer/Types.elm
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
module Common.Customer.Types exposing (..)
|
||||||
|
|
||||||
|
import Date exposing (Date)
|
||||||
|
|
||||||
|
|
||||||
|
type Authorized
|
||||||
|
= Automatic
|
||||||
|
| Blocked
|
||||||
|
| Verified
|
||||||
|
|
||||||
|
|
||||||
|
type alias Customers =
|
||||||
|
List Customer
|
||||||
|
|
||||||
|
|
||||||
|
type alias IdCardData =
|
||||||
|
{ uid : String }
|
||||||
|
|
||||||
|
type alias Customer =
|
||||||
|
{ id : String
|
||||||
|
, name : Maybe String
|
||||||
|
, phone : Maybe String
|
||||||
|
, phoneAt : Maybe Date
|
||||||
|
, smsOverride : Authorized
|
||||||
|
, smsOverrideByName : Maybe String
|
||||||
|
, smsOverrideAt : Maybe Date
|
||||||
|
, created : Date
|
||||||
|
, status : Maybe String
|
||||||
|
, authorizedOverride : Authorized
|
||||||
|
, authorizedOverrideByName : Maybe String
|
||||||
|
, authorizedOverrideAt : Maybe Date
|
||||||
|
, authorizedAt : Maybe Date
|
||||||
|
, idCardData : Maybe IdCardData
|
||||||
|
, idCardDataOverride : Authorized
|
||||||
|
, idCardDataOverrideByName : Maybe String
|
||||||
|
, idCardDataOverrideAt : Maybe Date
|
||||||
|
, idCardDataAt : Maybe Date
|
||||||
|
, idCardPhotoPath : Maybe String
|
||||||
|
, idCardPhotoOverride : Authorized
|
||||||
|
, idCardPhotoOverrideByName : Maybe String
|
||||||
|
, idCardPhotoOverrideAt : Maybe Date
|
||||||
|
, idCardPhotoAt : Maybe Date
|
||||||
|
, sanctions : Maybe Bool
|
||||||
|
, sanctionsOverride : Authorized
|
||||||
|
, sanctionsOverrideByName : Maybe String
|
||||||
|
, sanctionsOverrideAt : Maybe Date
|
||||||
|
, sanctionsAt : Maybe Date
|
||||||
|
, frontCameraPath : Maybe String
|
||||||
|
, frontCameraOverride : Authorized
|
||||||
|
, frontCameraOverrideByName : Maybe String
|
||||||
|
, frontCameraOverrideAt : Maybe Date
|
||||||
|
, frontCameraAt : Maybe Date
|
||||||
|
, dailyVolume : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
authorizedToString : Authorized -> String
|
||||||
|
authorizedToString model =
|
||||||
|
case model of
|
||||||
|
Verified ->
|
||||||
|
"verified"
|
||||||
|
|
||||||
|
Blocked ->
|
||||||
|
"blocked"
|
||||||
|
|
||||||
|
Automatic ->
|
||||||
|
"automatic"
|
||||||
55
lamassu-admin-elm/src/Common/Logs/Decoder.elm
Normal file
55
lamassu-admin-elm/src/Common/Logs/Decoder.elm
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
module Common.Logs.Decoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Decode exposing (..)
|
||||||
|
import Json.Decode.Extra exposing (date, fromResult)
|
||||||
|
import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded)
|
||||||
|
import Common.Logs.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
logsDecoder : Decoder Logs
|
||||||
|
logsDecoder =
|
||||||
|
decode Logs
|
||||||
|
|> required "logs" (list logDecoder)
|
||||||
|
|> required "currentMachine" machineDecoder
|
||||||
|
|
||||||
|
|
||||||
|
logDecoder : Decoder Log
|
||||||
|
logDecoder =
|
||||||
|
decode Log
|
||||||
|
|> required "id" string
|
||||||
|
|> required "timestamp" date
|
||||||
|
|> required "logLevel" string
|
||||||
|
|> required "message" string
|
||||||
|
|
||||||
|
|
||||||
|
supportLogsDecoder : Decoder SupportLogs
|
||||||
|
supportLogsDecoder =
|
||||||
|
field "supportLogs" (list supportLogDecoder)
|
||||||
|
|
||||||
|
|
||||||
|
latestLogSnapshotDecoder : Decoder SupportLogSnapshot
|
||||||
|
latestLogSnapshotDecoder =
|
||||||
|
decode SupportLogSnapshot
|
||||||
|
|> required "deviceId" string
|
||||||
|
|> required "timestamp" date
|
||||||
|
|
||||||
|
|
||||||
|
supportLogDecoder : Decoder SupportLog
|
||||||
|
supportLogDecoder =
|
||||||
|
decode SupportLog
|
||||||
|
|> required "id" string
|
||||||
|
|> required "deviceId" string
|
||||||
|
|> required "timestamp" date
|
||||||
|
|> required "name" string
|
||||||
|
|
||||||
|
|
||||||
|
machinesDecoder : Decoder Machines
|
||||||
|
machinesDecoder =
|
||||||
|
field "machines" (list machineDecoder)
|
||||||
|
|
||||||
|
|
||||||
|
machineDecoder : Decoder Machine
|
||||||
|
machineDecoder =
|
||||||
|
decode Machine
|
||||||
|
|> required "deviceId" string
|
||||||
|
|> required "name" string
|
||||||
43
lamassu-admin-elm/src/Common/Logs/Types.elm
Normal file
43
lamassu-admin-elm/src/Common/Logs/Types.elm
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
module Common.Logs.Types exposing (..)
|
||||||
|
|
||||||
|
import Date exposing (Date)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Machine =
|
||||||
|
{ deviceId : String
|
||||||
|
, name : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Machines =
|
||||||
|
List Machine
|
||||||
|
|
||||||
|
|
||||||
|
type alias Log =
|
||||||
|
{ id : String
|
||||||
|
, timestamp : Date
|
||||||
|
, logLevel : String
|
||||||
|
, message : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias SupportLogSnapshot =
|
||||||
|
{ deviceId : String
|
||||||
|
, timestamp : Date
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias SupportLog =
|
||||||
|
{ id : String
|
||||||
|
, deviceId : String
|
||||||
|
, timestamp : Date
|
||||||
|
, name : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias SupportLogs =
|
||||||
|
List SupportLog
|
||||||
|
|
||||||
|
|
||||||
|
type alias Logs =
|
||||||
|
{ logs : List Log, currentMachine : Machine }
|
||||||
54
lamassu-admin-elm/src/Common/TransactionTypes.elm
Normal file
54
lamassu-admin-elm/src/Common/TransactionTypes.elm
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
module Common.TransactionTypes exposing (..)
|
||||||
|
|
||||||
|
import Date exposing (Date)
|
||||||
|
|
||||||
|
type CryptoCode
|
||||||
|
= BTC
|
||||||
|
| BCH
|
||||||
|
| ETH
|
||||||
|
| ZEC
|
||||||
|
| DASH
|
||||||
|
| LTC
|
||||||
|
|
||||||
|
|
||||||
|
type alias CashInTxRec =
|
||||||
|
{ id : String
|
||||||
|
, machineName : String
|
||||||
|
, toAddress : String
|
||||||
|
, cryptoAtoms : Int
|
||||||
|
, cryptoCode : CryptoCode
|
||||||
|
, fiat : Float
|
||||||
|
, fiatCode : String
|
||||||
|
, txHash : Maybe String
|
||||||
|
, phone : Maybe String
|
||||||
|
, error : Maybe String
|
||||||
|
, operatorCompleted : Bool
|
||||||
|
, send : Bool
|
||||||
|
, sendConfirmed : Bool
|
||||||
|
, expired : Bool
|
||||||
|
, created : Date
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias CashOutTxRec =
|
||||||
|
{ id : String
|
||||||
|
, machineName : String
|
||||||
|
, toAddress : String
|
||||||
|
, cryptoAtoms : Int
|
||||||
|
, cryptoCode : CryptoCode
|
||||||
|
, fiat : Float
|
||||||
|
, fiatCode : String
|
||||||
|
, status : String
|
||||||
|
, dispense : Bool
|
||||||
|
, notified : Bool
|
||||||
|
, redeemed : Bool
|
||||||
|
, phone : Maybe String
|
||||||
|
, error : Maybe String
|
||||||
|
, created : Date
|
||||||
|
, confirmed : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Tx
|
||||||
|
= CashInTx CashInTxRec
|
||||||
|
| CashOutTx CashOutTxRec
|
||||||
1855
lamassu-admin-elm/src/Config.elm
Normal file
1855
lamassu-admin-elm/src/Config.elm
Normal file
File diff suppressed because it is too large
Load diff
305
lamassu-admin-elm/src/ConfigDecoder.elm
Normal file
305
lamassu-admin-elm/src/ConfigDecoder.elm
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
module ConfigDecoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Decode exposing (..)
|
||||||
|
import ConfigTypes exposing (..)
|
||||||
|
import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded, custom)
|
||||||
|
import BasicTypes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
fieldValueTypeDecoder : String -> Decoder FieldValue
|
||||||
|
fieldValueTypeDecoder fieldType =
|
||||||
|
case fieldType of
|
||||||
|
"string" ->
|
||||||
|
map FieldStringValue (field "value" string)
|
||||||
|
|
||||||
|
"percentage" ->
|
||||||
|
map FieldPercentageValue (field "value" float)
|
||||||
|
|
||||||
|
"integer" ->
|
||||||
|
map FieldIntegerValue (field "value" int)
|
||||||
|
|
||||||
|
"decimal" ->
|
||||||
|
map FieldDecimalValue (field "value" float)
|
||||||
|
|
||||||
|
"onOff" ->
|
||||||
|
map FieldOnOffValue (field "value" bool)
|
||||||
|
|
||||||
|
"account" ->
|
||||||
|
map FieldFiatCurrencyValue (field "value" string)
|
||||||
|
|
||||||
|
"fiatCurrency" ->
|
||||||
|
map FieldFiatCurrencyValue (field "value" string)
|
||||||
|
|
||||||
|
"cryptoCurrency" ->
|
||||||
|
map FieldCryptoCurrencyValue (field "value" (list string))
|
||||||
|
|
||||||
|
"language" ->
|
||||||
|
map FieldLanguageValue (field "value" (list string))
|
||||||
|
|
||||||
|
"country" ->
|
||||||
|
map FieldCountryValue (field "value" string)
|
||||||
|
|
||||||
|
"textarea" ->
|
||||||
|
map FieldTextAreaValue (field "value" string)
|
||||||
|
|
||||||
|
"markdown" ->
|
||||||
|
map FieldMarkdownValue (field "value" string)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
fail ("Unsupported field type: " ++ fieldType)
|
||||||
|
|
||||||
|
|
||||||
|
fieldValueDecoder : Decoder FieldValue
|
||||||
|
fieldValueDecoder =
|
||||||
|
(field "fieldType" string) |> andThen fieldValueTypeDecoder
|
||||||
|
|
||||||
|
|
||||||
|
fieldScopeDecoder : Decoder FieldScope
|
||||||
|
fieldScopeDecoder =
|
||||||
|
map2 FieldScope
|
||||||
|
(field "crypto" cryptoDecoder)
|
||||||
|
(field "machine" machineDecoder)
|
||||||
|
|
||||||
|
|
||||||
|
nullOr : Decoder a -> Decoder (Maybe a)
|
||||||
|
nullOr decoder =
|
||||||
|
oneOf
|
||||||
|
[ null Nothing
|
||||||
|
, map Just decoder
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
fieldLocatorDecoder : Decoder FieldLocator
|
||||||
|
fieldLocatorDecoder =
|
||||||
|
map4 FieldLocator
|
||||||
|
(field "fieldScope" fieldScopeDecoder)
|
||||||
|
(field "code" string)
|
||||||
|
((field "fieldType" string) |> andThen fieldTypeDecoder)
|
||||||
|
(field "fieldClass" (nullOr string))
|
||||||
|
|
||||||
|
|
||||||
|
fieldDecoder : Decoder Field
|
||||||
|
fieldDecoder =
|
||||||
|
map5 Field
|
||||||
|
(field "fieldLocator" fieldLocatorDecoder)
|
||||||
|
(field "fieldValue" fieldValueDecoder)
|
||||||
|
(field "fieldEnabledIfAny" (list string))
|
||||||
|
(field "fieldEnabledIfAll" (list string))
|
||||||
|
(succeed True)
|
||||||
|
|
||||||
|
|
||||||
|
string2machine : String -> Machine
|
||||||
|
string2machine s =
|
||||||
|
if s == "global" then
|
||||||
|
GlobalMachine
|
||||||
|
else
|
||||||
|
MachineId s
|
||||||
|
|
||||||
|
|
||||||
|
machineDecoder : Decoder Machine
|
||||||
|
machineDecoder =
|
||||||
|
map string2machine string
|
||||||
|
|
||||||
|
|
||||||
|
cryptoDecoder : Decoder Crypto
|
||||||
|
cryptoDecoder =
|
||||||
|
map stringToCrypto string
|
||||||
|
|
||||||
|
|
||||||
|
displayRecDecoder : Decoder DisplayRec
|
||||||
|
displayRecDecoder =
|
||||||
|
map2 DisplayRec
|
||||||
|
(field "code" string)
|
||||||
|
(field "display" string)
|
||||||
|
|
||||||
|
|
||||||
|
machineDisplayDecoder : Decoder MachineDisplay
|
||||||
|
machineDisplayDecoder =
|
||||||
|
map2 MachineDisplay
|
||||||
|
(field "machine" machineDecoder)
|
||||||
|
(field "display" string)
|
||||||
|
|
||||||
|
|
||||||
|
cryptoDisplayDecoder : Decoder CryptoDisplay
|
||||||
|
cryptoDisplayDecoder =
|
||||||
|
map2 CryptoDisplay
|
||||||
|
(field "crypto" cryptoDecoder)
|
||||||
|
(field "display" string)
|
||||||
|
|
||||||
|
|
||||||
|
stringToConfigScope : String -> Decoder ConfigScope
|
||||||
|
stringToConfigScope s =
|
||||||
|
case s of
|
||||||
|
"global" ->
|
||||||
|
succeed Global
|
||||||
|
|
||||||
|
"specific" ->
|
||||||
|
succeed Specific
|
||||||
|
|
||||||
|
"both" ->
|
||||||
|
succeed Both
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
fail ("No such ConfigScope " ++ s)
|
||||||
|
|
||||||
|
|
||||||
|
basicFieldTypeDecoder : String -> Decoder FieldType
|
||||||
|
basicFieldTypeDecoder s =
|
||||||
|
case s of
|
||||||
|
"string" ->
|
||||||
|
succeed FieldStringType
|
||||||
|
|
||||||
|
"percentage" ->
|
||||||
|
succeed FieldPercentageType
|
||||||
|
|
||||||
|
"integer" ->
|
||||||
|
succeed FieldIntegerType
|
||||||
|
|
||||||
|
"decimal" ->
|
||||||
|
succeed FieldDecimalType
|
||||||
|
|
||||||
|
"onOff" ->
|
||||||
|
succeed FieldOnOffType
|
||||||
|
|
||||||
|
"account" ->
|
||||||
|
succeed FieldAccountType
|
||||||
|
|
||||||
|
"fiatCurrency" ->
|
||||||
|
succeed FieldFiatCurrencyType
|
||||||
|
|
||||||
|
"cryptoCurrency" ->
|
||||||
|
succeed FieldCryptoCurrencyType
|
||||||
|
|
||||||
|
"language" ->
|
||||||
|
succeed FieldLanguageType
|
||||||
|
|
||||||
|
"country" ->
|
||||||
|
succeed FieldCountryType
|
||||||
|
|
||||||
|
"textarea" ->
|
||||||
|
succeed FieldTextAreaType
|
||||||
|
|
||||||
|
"markdown" ->
|
||||||
|
succeed FieldMarkdownType
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
fail ("No such FieldType " ++ s)
|
||||||
|
|
||||||
|
|
||||||
|
configScopeDecoder : Decoder ConfigScope
|
||||||
|
configScopeDecoder =
|
||||||
|
string
|
||||||
|
|> andThen stringToConfigScope
|
||||||
|
|
||||||
|
|
||||||
|
fieldTypeDecoder : String -> Decoder FieldType
|
||||||
|
fieldTypeDecoder fieldType =
|
||||||
|
basicFieldTypeDecoder fieldType
|
||||||
|
|
||||||
|
|
||||||
|
fieldValidatorDecode : String -> Decoder FieldValidator
|
||||||
|
fieldValidatorDecode code =
|
||||||
|
case code of
|
||||||
|
"min" ->
|
||||||
|
map FieldMin (field "min" int)
|
||||||
|
|
||||||
|
"max" ->
|
||||||
|
map FieldMax (field "max" int)
|
||||||
|
|
||||||
|
"required" ->
|
||||||
|
succeed FieldRequired
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
fail ("Unsupported fieldValidator: " ++ code)
|
||||||
|
|
||||||
|
|
||||||
|
fieldValidatorDecoder : Decoder FieldValidator
|
||||||
|
fieldValidatorDecoder =
|
||||||
|
(field "code" string)
|
||||||
|
|> andThen fieldValidatorDecode
|
||||||
|
|
||||||
|
|
||||||
|
displayTopDecoderHelper : Maybe Int -> Decoder DisplayTop
|
||||||
|
displayTopDecoderHelper maybeDisplayTopCount =
|
||||||
|
case maybeDisplayTopCount of
|
||||||
|
Nothing ->
|
||||||
|
(maybe <| (field "displayTop" string))
|
||||||
|
|> map (DisplayTopSolo << (Maybe.withDefault ""))
|
||||||
|
|
||||||
|
Just 0 ->
|
||||||
|
succeed DisplayTopNone
|
||||||
|
|
||||||
|
Just 1 ->
|
||||||
|
succeed DisplayTopNone
|
||||||
|
|
||||||
|
Just x ->
|
||||||
|
map (DisplayTopLeader x) (field "displayTop" string)
|
||||||
|
|
||||||
|
|
||||||
|
displayTopDecoder : Decoder DisplayTop
|
||||||
|
displayTopDecoder =
|
||||||
|
(maybe <| (field "displayTopCount" int))
|
||||||
|
|> andThen displayTopDecoderHelper
|
||||||
|
|
||||||
|
|
||||||
|
fieldDescriptorDecoder : Decoder FieldDescriptor
|
||||||
|
fieldDescriptorDecoder =
|
||||||
|
decode FieldDescriptor
|
||||||
|
|> required "code" string
|
||||||
|
|> required "cryptoScope" configScopeDecoder
|
||||||
|
|> required "machineScope" configScopeDecoder
|
||||||
|
|> custom displayTopDecoder
|
||||||
|
|> required "displayBottom" string
|
||||||
|
|> custom (maybe (field "displayCount" int))
|
||||||
|
|> custom (field "fieldType" string |> andThen fieldTypeDecoder)
|
||||||
|
|> custom (field "fieldValidation" <| list fieldValidatorDecoder)
|
||||||
|
|> required "fieldClass" (nullable string)
|
||||||
|
|> required "fieldEnabledIfAny" (list string)
|
||||||
|
|> required "fieldEnabledIfAll" (list string)
|
||||||
|
|> optional "readOnly" bool False
|
||||||
|
|
||||||
|
|
||||||
|
configSchemaDecoder : Decoder ConfigSchema
|
||||||
|
configSchemaDecoder =
|
||||||
|
map5 ConfigSchema
|
||||||
|
(field "code" string)
|
||||||
|
(field "display" string)
|
||||||
|
(field "cryptoScope" configScopeDecoder)
|
||||||
|
(field "machineScope" configScopeDecoder)
|
||||||
|
(field "entries" (list fieldDescriptorDecoder))
|
||||||
|
|
||||||
|
|
||||||
|
configGroupDecoder : Decoder ConfigGroup
|
||||||
|
configGroupDecoder =
|
||||||
|
map4 ConfigGroup
|
||||||
|
(field "schema" configSchemaDecoder)
|
||||||
|
(field "values" (list fieldDecoder))
|
||||||
|
(field "selectedCryptos" (list string))
|
||||||
|
(field "data" configDataDecoder)
|
||||||
|
|
||||||
|
|
||||||
|
accountRecDecoder : Decoder AccountRec
|
||||||
|
accountRecDecoder =
|
||||||
|
oneOf
|
||||||
|
[ map4 AccountRec
|
||||||
|
(field "code" string)
|
||||||
|
(field "display" string)
|
||||||
|
(field "class" string)
|
||||||
|
(field "cryptos" (map Just (list cryptoDecoder)))
|
||||||
|
, map4 AccountRec
|
||||||
|
(field "code" string)
|
||||||
|
(field "display" string)
|
||||||
|
(field "class" string)
|
||||||
|
(succeed Nothing)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
configDataDecoder : Decoder ConfigData
|
||||||
|
configDataDecoder =
|
||||||
|
map6 ConfigData
|
||||||
|
(field "cryptoCurrencies" (list cryptoDisplayDecoder))
|
||||||
|
(field "currencies" (list displayRecDecoder))
|
||||||
|
(field "languages" (list displayRecDecoder))
|
||||||
|
(field "countries" (list displayRecDecoder))
|
||||||
|
(field "accounts" (list accountRecDecoder))
|
||||||
|
(field "machines" (list machineDisplayDecoder))
|
||||||
187
lamassu-admin-elm/src/ConfigEncoder.elm
Normal file
187
lamassu-admin-elm/src/ConfigEncoder.elm
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
module ConfigEncoder exposing (..)
|
||||||
|
|
||||||
|
import Json.Encode exposing (..)
|
||||||
|
import List
|
||||||
|
import ConfigTypes exposing (..)
|
||||||
|
import BasicTypes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
encodeFieldValueObject : String -> Value -> Value
|
||||||
|
encodeFieldValueObject fieldTypeStr value =
|
||||||
|
object [ ( "fieldType", string fieldTypeStr ), ( "value", value ) ]
|
||||||
|
|
||||||
|
|
||||||
|
encodeFieldValue : FieldValue -> Value
|
||||||
|
encodeFieldValue fieldValue =
|
||||||
|
case fieldValue of
|
||||||
|
FieldStringValue value ->
|
||||||
|
encodeFieldValueObject "string" (string value)
|
||||||
|
|
||||||
|
FieldPercentageValue value ->
|
||||||
|
encodeFieldValueObject "percentage" (float value)
|
||||||
|
|
||||||
|
FieldIntegerValue value ->
|
||||||
|
encodeFieldValueObject "integer" (int value)
|
||||||
|
|
||||||
|
FieldDecimalValue value ->
|
||||||
|
encodeFieldValueObject "decimal" (float value)
|
||||||
|
|
||||||
|
FieldOnOffValue value ->
|
||||||
|
encodeFieldValueObject "onOff" (bool value)
|
||||||
|
|
||||||
|
FieldAccountValue value ->
|
||||||
|
encodeFieldValueObject "account" (string value)
|
||||||
|
|
||||||
|
FieldFiatCurrencyValue value ->
|
||||||
|
encodeFieldValueObject "fiatCurrency" (string value)
|
||||||
|
|
||||||
|
FieldCryptoCurrencyValue value ->
|
||||||
|
encodeFieldValueObject "cryptoCurrency" (list (List.map string value))
|
||||||
|
|
||||||
|
FieldLanguageValue value ->
|
||||||
|
encodeFieldValueObject "language" (list (List.map string value))
|
||||||
|
|
||||||
|
FieldCountryValue value ->
|
||||||
|
encodeFieldValueObject "country" (string value)
|
||||||
|
|
||||||
|
FieldTextAreaValue value ->
|
||||||
|
encodeFieldValueObject "textarea" (string value)
|
||||||
|
|
||||||
|
FieldMarkdownValue value ->
|
||||||
|
encodeFieldValueObject "markdown" (string value)
|
||||||
|
|
||||||
|
|
||||||
|
encodeCrypto : Crypto -> Value
|
||||||
|
encodeCrypto crypto =
|
||||||
|
case crypto of
|
||||||
|
CryptoCode cryptoCode ->
|
||||||
|
string cryptoCode
|
||||||
|
|
||||||
|
GlobalCrypto ->
|
||||||
|
string "global"
|
||||||
|
|
||||||
|
|
||||||
|
encodeMachine : Machine -> Value
|
||||||
|
encodeMachine machine =
|
||||||
|
case machine of
|
||||||
|
MachineId machineId ->
|
||||||
|
string machineId
|
||||||
|
|
||||||
|
GlobalMachine ->
|
||||||
|
string "global"
|
||||||
|
|
||||||
|
|
||||||
|
encodeFieldScope : FieldScope -> Value
|
||||||
|
encodeFieldScope fieldScope =
|
||||||
|
Json.Encode.object
|
||||||
|
[ ( "crypto", encodeCrypto fieldScope.crypto )
|
||||||
|
, ( "machine", encodeMachine fieldScope.machine )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
fieldTypeEncoder : FieldType -> Value
|
||||||
|
fieldTypeEncoder fieldType =
|
||||||
|
case fieldType of
|
||||||
|
FieldStringType ->
|
||||||
|
string "string"
|
||||||
|
|
||||||
|
FieldPercentageType ->
|
||||||
|
string "percentage"
|
||||||
|
|
||||||
|
FieldIntegerType ->
|
||||||
|
string "integer"
|
||||||
|
|
||||||
|
FieldDecimalType ->
|
||||||
|
string "decimal"
|
||||||
|
|
||||||
|
FieldOnOffType ->
|
||||||
|
string "onOff"
|
||||||
|
|
||||||
|
FieldAccountType ->
|
||||||
|
string "account"
|
||||||
|
|
||||||
|
FieldFiatCurrencyType ->
|
||||||
|
string "fiatCurrency"
|
||||||
|
|
||||||
|
FieldCryptoCurrencyType ->
|
||||||
|
string "cryptoCurrency"
|
||||||
|
|
||||||
|
FieldLanguageType ->
|
||||||
|
string "language"
|
||||||
|
|
||||||
|
FieldCountryType ->
|
||||||
|
string "country"
|
||||||
|
|
||||||
|
FieldTextAreaType ->
|
||||||
|
string "textarea"
|
||||||
|
|
||||||
|
FieldMarkdownType ->
|
||||||
|
string "markdown"
|
||||||
|
|
||||||
|
|
||||||
|
maybeString : Maybe String -> Value
|
||||||
|
maybeString maybeString =
|
||||||
|
case maybeString of
|
||||||
|
Nothing ->
|
||||||
|
null
|
||||||
|
|
||||||
|
Just s ->
|
||||||
|
string s
|
||||||
|
|
||||||
|
|
||||||
|
encodeFieldLocator : FieldLocator -> Value
|
||||||
|
encodeFieldLocator fieldLocator =
|
||||||
|
Json.Encode.object
|
||||||
|
[ ( "fieldScope", encodeFieldScope fieldLocator.fieldScope )
|
||||||
|
, ( "code", string fieldLocator.code )
|
||||||
|
, ( "fieldType", fieldTypeEncoder fieldLocator.fieldType )
|
||||||
|
, ( "fieldClass", maybeString fieldLocator.fieldClass )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
encodeFieldResult : FieldInstance -> Maybe Value
|
||||||
|
encodeFieldResult fieldInstance =
|
||||||
|
let
|
||||||
|
encode value =
|
||||||
|
Json.Encode.object
|
||||||
|
[ ( "fieldLocator", encodeFieldLocator fieldInstance.fieldLocator )
|
||||||
|
, ( "fieldValue", value )
|
||||||
|
]
|
||||||
|
|
||||||
|
dirtyEncode fieldHolder =
|
||||||
|
case fieldHolder of
|
||||||
|
ParsingError fieldValue ->
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
ValidationError fieldValue ->
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
FieldOk fieldValue ->
|
||||||
|
if (fieldInstance.loadedFieldHolder == fieldHolder) then
|
||||||
|
Nothing
|
||||||
|
else
|
||||||
|
Just <| encode <| encodeFieldValue fieldValue
|
||||||
|
|
||||||
|
FieldEmpty ->
|
||||||
|
if (fieldInstance.loadedFieldHolder == fieldHolder) then
|
||||||
|
Nothing
|
||||||
|
else
|
||||||
|
Just <| encode null
|
||||||
|
in
|
||||||
|
dirtyEncode fieldInstance.fieldHolder
|
||||||
|
|
||||||
|
|
||||||
|
encodeResults : String -> List FieldInstance -> Maybe Value
|
||||||
|
encodeResults configGroupCode fieldInstances =
|
||||||
|
let
|
||||||
|
results =
|
||||||
|
List.filterMap encodeFieldResult fieldInstances
|
||||||
|
in
|
||||||
|
if List.isEmpty results then
|
||||||
|
Nothing
|
||||||
|
else
|
||||||
|
Json.Encode.object
|
||||||
|
[ ( "groupCode", string configGroupCode )
|
||||||
|
, ( "values", list (List.filterMap encodeFieldResult fieldInstances) )
|
||||||
|
]
|
||||||
|
|> Just
|
||||||
495
lamassu-admin-elm/src/ConfigTypes.elm
Normal file
495
lamassu-admin-elm/src/ConfigTypes.elm
Normal file
|
|
@ -0,0 +1,495 @@
|
||||||
|
module ConfigTypes exposing (..)
|
||||||
|
|
||||||
|
import String
|
||||||
|
import Selectize
|
||||||
|
|
||||||
|
|
||||||
|
type alias DisplayRec =
|
||||||
|
{ code : String
|
||||||
|
, display : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Machine
|
||||||
|
= MachineId String
|
||||||
|
| GlobalMachine
|
||||||
|
|
||||||
|
|
||||||
|
type alias MachineDisplay =
|
||||||
|
{ machine : Machine
|
||||||
|
, display : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type ConfigScope
|
||||||
|
= Global
|
||||||
|
| Specific
|
||||||
|
| Both
|
||||||
|
|
||||||
|
|
||||||
|
type FieldHolder
|
||||||
|
= ParsingError String
|
||||||
|
| ValidationError String
|
||||||
|
| FieldOk FieldValue
|
||||||
|
| FieldEmpty
|
||||||
|
|
||||||
|
|
||||||
|
type alias FieldScope =
|
||||||
|
{ crypto : Crypto
|
||||||
|
, machine : Machine
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias FieldLocator =
|
||||||
|
{ fieldScope : FieldScope
|
||||||
|
, code : String
|
||||||
|
, fieldType : FieldType
|
||||||
|
, fieldClass : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type FieldComponent
|
||||||
|
= InputBoxComponent
|
||||||
|
| TextAreaComponent
|
||||||
|
| SelectizeComponent Selectize.State
|
||||||
|
|
||||||
|
|
||||||
|
type alias FieldInstance =
|
||||||
|
{ fieldLocator : FieldLocator
|
||||||
|
, component : FieldComponent
|
||||||
|
, fieldHolder : FieldHolder
|
||||||
|
, loadedFieldHolder : FieldHolder
|
||||||
|
, fieldValidation : List FieldValidator
|
||||||
|
, fieldEnabledIfAny : List String
|
||||||
|
, fieldEnabledIfAll : List String
|
||||||
|
, readOnly : Bool
|
||||||
|
, inScope : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ResolvedFieldInstance =
|
||||||
|
{ fieldLocator : FieldLocator
|
||||||
|
, fieldValue : Maybe FieldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Field =
|
||||||
|
{ fieldLocator : FieldLocator
|
||||||
|
, fieldValue : FieldValue
|
||||||
|
, fieldEnabledIfAny : List String
|
||||||
|
, fieldEnabledIfAll : List String
|
||||||
|
, inScope : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias FieldMeta =
|
||||||
|
{ fieldLocator : FieldLocator
|
||||||
|
, fieldEnabledIfAny : List String
|
||||||
|
, fieldEnabledIfAll : List String
|
||||||
|
, inScope : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type FieldType
|
||||||
|
= FieldStringType
|
||||||
|
| FieldPercentageType
|
||||||
|
| FieldIntegerType
|
||||||
|
| FieldDecimalType
|
||||||
|
| FieldOnOffType
|
||||||
|
| FieldAccountType
|
||||||
|
| FieldFiatCurrencyType
|
||||||
|
| FieldCryptoCurrencyType
|
||||||
|
| FieldLanguageType
|
||||||
|
| FieldCountryType
|
||||||
|
| FieldTextAreaType
|
||||||
|
| FieldMarkdownType
|
||||||
|
|
||||||
|
|
||||||
|
type FieldValue
|
||||||
|
= FieldStringValue String
|
||||||
|
| FieldPercentageValue Float
|
||||||
|
| FieldIntegerValue Int
|
||||||
|
| FieldDecimalValue Float
|
||||||
|
| FieldOnOffValue Bool
|
||||||
|
| FieldAccountValue String
|
||||||
|
| FieldFiatCurrencyValue String
|
||||||
|
| FieldCryptoCurrencyValue (List String)
|
||||||
|
| FieldLanguageValue (List String)
|
||||||
|
| FieldCountryValue String
|
||||||
|
| FieldTextAreaValue String
|
||||||
|
| FieldMarkdownValue String
|
||||||
|
|
||||||
|
|
||||||
|
type FieldValidator
|
||||||
|
= FieldMin Int
|
||||||
|
| FieldMax Int
|
||||||
|
| FieldRequired
|
||||||
|
|
||||||
|
|
||||||
|
type DisplayTop
|
||||||
|
= DisplayTopLeader Int String
|
||||||
|
| DisplayTopSolo String
|
||||||
|
| DisplayTopNone
|
||||||
|
|
||||||
|
|
||||||
|
type alias FieldDescriptor =
|
||||||
|
{ code : String
|
||||||
|
, cryptoScope : ConfigScope
|
||||||
|
, machineScope : ConfigScope
|
||||||
|
, displayTop : DisplayTop
|
||||||
|
, displayBottom : String
|
||||||
|
, displayCount : Maybe Int
|
||||||
|
, fieldType : FieldType
|
||||||
|
, fieldValidation : List FieldValidator
|
||||||
|
, fieldClass : Maybe String
|
||||||
|
, fieldEnabledIfAny : List String
|
||||||
|
, fieldEnabledIfAll : List String
|
||||||
|
, readOnly : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ConfigSchema =
|
||||||
|
{ code : String
|
||||||
|
, display : String
|
||||||
|
, cryptoScope : ConfigScope
|
||||||
|
, machineScope : ConfigScope
|
||||||
|
, entries : List FieldDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ConfigGroup =
|
||||||
|
{ schema : ConfigSchema
|
||||||
|
, values : List Field
|
||||||
|
, selectedCryptos : List String
|
||||||
|
, data : ConfigData
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias AccountRec =
|
||||||
|
{ code : String
|
||||||
|
, display : String
|
||||||
|
, class : String
|
||||||
|
, cryptos : Maybe (List Crypto)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
accountRecToDisplayRec : AccountRec -> DisplayRec
|
||||||
|
accountRecToDisplayRec accountRec =
|
||||||
|
{ code = accountRec.code
|
||||||
|
, display = accountRec.display
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ConfigData =
|
||||||
|
{ cryptoCurrencies : List CryptoDisplay
|
||||||
|
, currencies : List DisplayRec
|
||||||
|
, languages : List DisplayRec
|
||||||
|
, countries : List DisplayRec
|
||||||
|
, accounts : List AccountRec
|
||||||
|
, machines : List MachineDisplay
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias FieldCollection =
|
||||||
|
{ fields : List Field
|
||||||
|
, fieldInstances : List FieldInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initFieldCollection : FieldCollection
|
||||||
|
initFieldCollection =
|
||||||
|
{ fields = []
|
||||||
|
, fieldInstances = []
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
globalCryptoDisplay : CryptoDisplay
|
||||||
|
globalCryptoDisplay =
|
||||||
|
{ crypto = GlobalCrypto
|
||||||
|
, display = "Global"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
globalMachineDisplay : MachineDisplay
|
||||||
|
globalMachineDisplay =
|
||||||
|
{ machine = GlobalMachine
|
||||||
|
, display = "Global"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fieldValueToDisplay : FieldValue -> String
|
||||||
|
fieldValueToDisplay fieldValue =
|
||||||
|
case fieldValue of
|
||||||
|
FieldOnOffValue v ->
|
||||||
|
if v then
|
||||||
|
"On"
|
||||||
|
else
|
||||||
|
"Off"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
fieldValueToString fieldValue
|
||||||
|
|
||||||
|
|
||||||
|
fieldValueToString : FieldValue -> String
|
||||||
|
fieldValueToString fieldValue =
|
||||||
|
case fieldValue of
|
||||||
|
FieldStringValue v ->
|
||||||
|
v
|
||||||
|
|
||||||
|
FieldPercentageValue v ->
|
||||||
|
toString v
|
||||||
|
|
||||||
|
FieldIntegerValue v ->
|
||||||
|
toString v
|
||||||
|
|
||||||
|
FieldDecimalValue v ->
|
||||||
|
toString v
|
||||||
|
|
||||||
|
FieldOnOffValue v ->
|
||||||
|
if v then
|
||||||
|
"on"
|
||||||
|
else
|
||||||
|
"off"
|
||||||
|
|
||||||
|
FieldAccountValue v ->
|
||||||
|
v
|
||||||
|
|
||||||
|
FieldFiatCurrencyValue v ->
|
||||||
|
v
|
||||||
|
|
||||||
|
FieldCryptoCurrencyValue v ->
|
||||||
|
String.join "," v
|
||||||
|
|
||||||
|
FieldLanguageValue v ->
|
||||||
|
String.join "," v
|
||||||
|
|
||||||
|
FieldCountryValue v ->
|
||||||
|
v
|
||||||
|
|
||||||
|
FieldTextAreaValue v ->
|
||||||
|
v
|
||||||
|
|
||||||
|
FieldMarkdownValue v ->
|
||||||
|
v
|
||||||
|
|
||||||
|
|
||||||
|
machineToString : Machine -> String
|
||||||
|
machineToString machine =
|
||||||
|
case machine of
|
||||||
|
GlobalMachine ->
|
||||||
|
"global"
|
||||||
|
|
||||||
|
MachineId machineId ->
|
||||||
|
machineId
|
||||||
|
|
||||||
|
|
||||||
|
listMachines : ConfigGroup -> List MachineDisplay
|
||||||
|
listMachines configGroup =
|
||||||
|
case configGroup.schema.machineScope of
|
||||||
|
Specific ->
|
||||||
|
configGroup.data.machines
|
||||||
|
|
||||||
|
Global ->
|
||||||
|
[ globalMachineDisplay ]
|
||||||
|
|
||||||
|
Both ->
|
||||||
|
globalMachineDisplay :: configGroup.data.machines
|
||||||
|
|
||||||
|
|
||||||
|
isCrypto : String -> CryptoDisplay -> Bool
|
||||||
|
isCrypto cryptoString cryptoDisplay =
|
||||||
|
case cryptoDisplay.crypto of
|
||||||
|
GlobalCrypto ->
|
||||||
|
cryptoString == "global"
|
||||||
|
|
||||||
|
CryptoCode string ->
|
||||||
|
cryptoString == string
|
||||||
|
|
||||||
|
|
||||||
|
lookupCryptoDisplay : List CryptoDisplay -> String -> Maybe CryptoDisplay
|
||||||
|
lookupCryptoDisplay cryptoDisplays cryptoString =
|
||||||
|
List.filter (isCrypto cryptoString) cryptoDisplays
|
||||||
|
|> List.head
|
||||||
|
|
||||||
|
|
||||||
|
fieldHolderToCryptoStrings : FieldHolder -> List String
|
||||||
|
fieldHolderToCryptoStrings fieldHolder =
|
||||||
|
case fieldHolder of
|
||||||
|
FieldOk fieldValue ->
|
||||||
|
case fieldValue of
|
||||||
|
FieldCryptoCurrencyValue cryptoStrings ->
|
||||||
|
cryptoStrings
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
allCryptos : List CryptoDisplay -> ConfigScope -> List String -> List CryptoDisplay
|
||||||
|
allCryptos cryptoDisplays cryptoScope cryptoStrings =
|
||||||
|
let
|
||||||
|
allSpecificCryptos =
|
||||||
|
List.filterMap (lookupCryptoDisplay cryptoDisplays) cryptoStrings
|
||||||
|
in
|
||||||
|
case cryptoScope of
|
||||||
|
Global ->
|
||||||
|
[ globalCryptoDisplay ]
|
||||||
|
|
||||||
|
Specific ->
|
||||||
|
allSpecificCryptos
|
||||||
|
|
||||||
|
Both ->
|
||||||
|
globalCryptoDisplay :: allSpecificCryptos
|
||||||
|
|
||||||
|
|
||||||
|
listCryptos : ConfigGroup -> List CryptoDisplay
|
||||||
|
listCryptos configGroup =
|
||||||
|
case configGroup.schema.cryptoScope of
|
||||||
|
Specific ->
|
||||||
|
configGroup.data.cryptoCurrencies
|
||||||
|
|
||||||
|
Global ->
|
||||||
|
[ globalCryptoDisplay ]
|
||||||
|
|
||||||
|
Both ->
|
||||||
|
globalCryptoDisplay :: configGroup.data.cryptoCurrencies
|
||||||
|
|
||||||
|
|
||||||
|
fieldScopes : ConfigGroup -> List FieldScope
|
||||||
|
fieldScopes configGroup =
|
||||||
|
let
|
||||||
|
machines =
|
||||||
|
List.map .machine (listMachines configGroup)
|
||||||
|
|
||||||
|
cryptos =
|
||||||
|
List.map .crypto (listCryptos configGroup)
|
||||||
|
|
||||||
|
cryptoScopes crypto =
|
||||||
|
List.map (\machine -> { machine = machine, crypto = crypto }) machines
|
||||||
|
in
|
||||||
|
List.concatMap cryptoScopes cryptos
|
||||||
|
|
||||||
|
|
||||||
|
stringToCrypto : String -> Crypto
|
||||||
|
stringToCrypto string =
|
||||||
|
case string of
|
||||||
|
"global" ->
|
||||||
|
GlobalCrypto
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
CryptoCode string
|
||||||
|
|
||||||
|
|
||||||
|
fieldHolderToMaybe : FieldHolder -> Maybe FieldValue
|
||||||
|
fieldHolderToMaybe fieldHolder =
|
||||||
|
case fieldHolder of
|
||||||
|
FieldOk fieldValue ->
|
||||||
|
Just fieldValue
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
|
||||||
|
resultToFieldHolder : Result String FieldValue -> FieldHolder
|
||||||
|
resultToFieldHolder result =
|
||||||
|
case result of
|
||||||
|
Ok fieldValue ->
|
||||||
|
FieldOk fieldValue
|
||||||
|
|
||||||
|
Err s ->
|
||||||
|
ParsingError s
|
||||||
|
|
||||||
|
|
||||||
|
stringToFieldHolder : FieldType -> String -> FieldHolder
|
||||||
|
stringToFieldHolder fieldType s =
|
||||||
|
if (String.isEmpty s) then
|
||||||
|
FieldEmpty
|
||||||
|
else
|
||||||
|
case fieldType of
|
||||||
|
FieldStringType ->
|
||||||
|
FieldOk (FieldStringValue s)
|
||||||
|
|
||||||
|
FieldPercentageType ->
|
||||||
|
String.toFloat s
|
||||||
|
|> Result.map FieldPercentageValue
|
||||||
|
|> resultToFieldHolder
|
||||||
|
|
||||||
|
FieldIntegerType ->
|
||||||
|
String.toInt s
|
||||||
|
|> Result.map FieldIntegerValue
|
||||||
|
|> resultToFieldHolder
|
||||||
|
|
||||||
|
FieldDecimalType ->
|
||||||
|
String.toFloat s
|
||||||
|
|> Result.map FieldDecimalValue
|
||||||
|
|> resultToFieldHolder
|
||||||
|
|
||||||
|
FieldOnOffType ->
|
||||||
|
case s of
|
||||||
|
"on" ->
|
||||||
|
FieldOk (FieldOnOffValue True)
|
||||||
|
|
||||||
|
"off" ->
|
||||||
|
FieldOk (FieldOnOffValue False)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
ParsingError ("Unsupported value for OnOff: " ++ s)
|
||||||
|
|
||||||
|
FieldAccountType ->
|
||||||
|
FieldOk (FieldAccountValue s)
|
||||||
|
|
||||||
|
FieldFiatCurrencyType ->
|
||||||
|
FieldOk (FieldFiatCurrencyValue s)
|
||||||
|
|
||||||
|
FieldCryptoCurrencyType ->
|
||||||
|
FieldOk (FieldCryptoCurrencyValue [ s ])
|
||||||
|
|
||||||
|
FieldLanguageType ->
|
||||||
|
FieldOk (FieldLanguageValue [ s ])
|
||||||
|
|
||||||
|
FieldCountryType ->
|
||||||
|
FieldOk (FieldCountryValue s)
|
||||||
|
|
||||||
|
FieldTextAreaType ->
|
||||||
|
FieldOk (FieldTextAreaValue s)
|
||||||
|
|
||||||
|
FieldMarkdownType ->
|
||||||
|
FieldOk (FieldMarkdownValue s)
|
||||||
|
|
||||||
|
|
||||||
|
groupMember : ConfigGroup -> String -> Bool
|
||||||
|
groupMember configGroup fieldCode =
|
||||||
|
List.any (.code >> ((==) fieldCode)) configGroup.schema.entries
|
||||||
|
|
||||||
|
|
||||||
|
fieldHolderMap : a -> (FieldValue -> a) -> FieldHolder -> a
|
||||||
|
fieldHolderMap default mapper fieldHolder =
|
||||||
|
case fieldHolder of
|
||||||
|
FieldOk v ->
|
||||||
|
mapper v
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
default
|
||||||
|
|
||||||
|
|
||||||
|
type Crypto
|
||||||
|
= CryptoCode String
|
||||||
|
| GlobalCrypto
|
||||||
|
|
||||||
|
|
||||||
|
type alias CryptoDisplay =
|
||||||
|
{ crypto : Crypto
|
||||||
|
, display : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cryptoToString : Crypto -> String
|
||||||
|
cryptoToString crypto =
|
||||||
|
case crypto of
|
||||||
|
GlobalCrypto ->
|
||||||
|
"global"
|
||||||
|
|
||||||
|
CryptoCode code ->
|
||||||
|
code
|
||||||
62
lamassu-admin-elm/src/CoreTypes.elm
Normal file
62
lamassu-admin-elm/src/CoreTypes.elm
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
module CoreTypes
|
||||||
|
exposing
|
||||||
|
( Msg(..)
|
||||||
|
, Category(..)
|
||||||
|
, Route(..)
|
||||||
|
)
|
||||||
|
|
||||||
|
import Navigation
|
||||||
|
import Pair
|
||||||
|
import Account
|
||||||
|
import Config
|
||||||
|
import MaintenanceMachines.Types
|
||||||
|
import MaintenanceFunding.Types
|
||||||
|
import Transaction.Types
|
||||||
|
import Transactions
|
||||||
|
import Customers.Types
|
||||||
|
import Customer.Types
|
||||||
|
import Logs.Types
|
||||||
|
import SupportLogs.Types
|
||||||
|
import StatusTypes
|
||||||
|
|
||||||
|
|
||||||
|
type Category
|
||||||
|
= AccountCat
|
||||||
|
| MachineSettingsCat
|
||||||
|
| GlobalSettingsCat
|
||||||
|
| MaintenanceCat
|
||||||
|
|
||||||
|
|
||||||
|
type Route
|
||||||
|
= AccountRoute String
|
||||||
|
| PairRoute
|
||||||
|
| ConfigRoute String (Maybe String)
|
||||||
|
| TransactionsRoute
|
||||||
|
| TransactionRoute String
|
||||||
|
| CustomersRoute
|
||||||
|
| CustomerRoute String
|
||||||
|
| LogsRoute (Maybe String)
|
||||||
|
| SupportLogsRoute (Maybe String)
|
||||||
|
| MaintenanceMachinesRoute
|
||||||
|
| MaintenanceFundingRoute (Maybe String)
|
||||||
|
| NotFoundRoute
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= AccountMsg Account.Msg
|
||||||
|
| PairMsg Pair.Msg
|
||||||
|
| ConfigMsg Config.Msg
|
||||||
|
| MaintenanceMachinesMsg MaintenanceMachines.Types.Msg
|
||||||
|
| MaintenanceFundingMsg MaintenanceFunding.Types.Msg
|
||||||
|
| TransactionsMsg Transactions.Msg
|
||||||
|
| TransactionMsg Transaction.Types.Msg
|
||||||
|
| CustomersMsg Customers.Types.Msg
|
||||||
|
| CustomerMsg Customer.Types.Msg
|
||||||
|
| LogsMsg Logs.Types.Msg
|
||||||
|
| SupportLogsMsg SupportLogs.Types.Msg
|
||||||
|
| LoadAccounts (List ( String, String ))
|
||||||
|
| LoadStatus StatusTypes.WebStatus
|
||||||
|
| NewUrl String
|
||||||
|
| UrlChange Navigation.Location
|
||||||
|
| Interval
|
||||||
|
| WebSocketMsg String
|
||||||
35
lamassu-admin-elm/src/Css/Admin.elm
Normal file
35
lamassu-admin-elm/src/Css/Admin.elm
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
module Css.Admin exposing (className, class, classList, id)
|
||||||
|
|
||||||
|
import Css.Helpers
|
||||||
|
import Html
|
||||||
|
import Html.CssHelpers
|
||||||
|
|
||||||
|
|
||||||
|
name : String
|
||||||
|
name =
|
||||||
|
"lamassuAdmin"
|
||||||
|
|
||||||
|
|
||||||
|
helpers : Html.CssHelpers.Namespace String class id msg
|
||||||
|
helpers =
|
||||||
|
Html.CssHelpers.withNamespace name
|
||||||
|
|
||||||
|
|
||||||
|
className : class -> String
|
||||||
|
className class =
|
||||||
|
Css.Helpers.identifierToString name class
|
||||||
|
|
||||||
|
|
||||||
|
class : List class -> Html.Attribute msg
|
||||||
|
class =
|
||||||
|
helpers.class
|
||||||
|
|
||||||
|
|
||||||
|
classList : List ( class, Bool ) -> Html.Attribute msg
|
||||||
|
classList =
|
||||||
|
helpers.classList
|
||||||
|
|
||||||
|
|
||||||
|
id : id -> Html.Attribute msg
|
||||||
|
id =
|
||||||
|
helpers.id
|
||||||
83
lamassu-admin-elm/src/Css/Classes.elm
Normal file
83
lamassu-admin-elm/src/Css/Classes.elm
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
module Css.Classes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type CssClasses
|
||||||
|
= Layout
|
||||||
|
| Main
|
||||||
|
| PaneWrapper
|
||||||
|
| LeftPane
|
||||||
|
| ContentPane
|
||||||
|
| NavBar
|
||||||
|
| MainLeft
|
||||||
|
| MainRight
|
||||||
|
| NavBarItemActive
|
||||||
|
| NavBarCategoryContainer
|
||||||
|
| NavBarCategory
|
||||||
|
| NavBarRoute
|
||||||
|
| Container
|
||||||
|
| Content
|
||||||
|
| CryptoTabs
|
||||||
|
| CryptoTab
|
||||||
|
| CryptoTabsActive
|
||||||
|
| SectionLabel
|
||||||
|
| ConfigTable
|
||||||
|
| ConfigTableGlobalRow
|
||||||
|
| ConfigContainer
|
||||||
|
| TopDisplay
|
||||||
|
| BottomDisplay
|
||||||
|
| MultiDisplay
|
||||||
|
| ShortCell
|
||||||
|
| MediumCell
|
||||||
|
| LongCell
|
||||||
|
| TextCell
|
||||||
|
| FormRow
|
||||||
|
| Button
|
||||||
|
| ButtonRow
|
||||||
|
| Active
|
||||||
|
| BasicInput
|
||||||
|
| BasicInputDisabled
|
||||||
|
| BasicInputReadOnly
|
||||||
|
| CellDisabled
|
||||||
|
| NoInput
|
||||||
|
| Component
|
||||||
|
| FocusedComponent
|
||||||
|
| InvalidComponent
|
||||||
|
| TableButton
|
||||||
|
| Fail
|
||||||
|
| Success
|
||||||
|
| StatusBar
|
||||||
|
| InvalidGroup
|
||||||
|
| NumberColumn
|
||||||
|
| DirectionColumn
|
||||||
|
| TruncatedColumn
|
||||||
|
| DateColumn
|
||||||
|
| TxTable
|
||||||
|
| InputContainer
|
||||||
|
| UnitDisplay
|
||||||
|
| EmptyTable
|
||||||
|
| Saving
|
||||||
|
| Enabled
|
||||||
|
| Disabled
|
||||||
|
| TxId
|
||||||
|
| TxDate
|
||||||
|
| TxMachine
|
||||||
|
| TxAmount
|
||||||
|
| TxFiat
|
||||||
|
| TxCrypto
|
||||||
|
| TxPhone
|
||||||
|
| TxAddress
|
||||||
|
| TxCancelled
|
||||||
|
| QrCode
|
||||||
|
| CashOut
|
||||||
|
| CashIn
|
||||||
|
| ReadOnly
|
||||||
|
| CryptoAddress
|
||||||
|
| BalanceSection
|
||||||
|
| Textarea
|
||||||
|
| SelectizeAccount
|
||||||
|
| SelectizeFiatCurrency
|
||||||
|
| SelectizeCryptoCurrency
|
||||||
|
| SelectizeLanguage
|
||||||
|
| SelectizeCountry
|
||||||
|
| SelectizeOnOff
|
||||||
72
lamassu-admin-elm/src/Css/ColorSchemes.elm
Normal file
72
lamassu-admin-elm/src/Css/ColorSchemes.elm
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
module Css.ColorSchemes exposing (..)
|
||||||
|
|
||||||
|
import Css exposing (..)
|
||||||
|
import Css.LocalColors as Colors
|
||||||
|
import Css.Classes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type alias ColorScheme =
|
||||||
|
{ bg : Color
|
||||||
|
, fg : Color
|
||||||
|
, bgHover : Color
|
||||||
|
, fgActive : Color
|
||||||
|
, bgActive : Color
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
darkGreyScheme : ColorScheme
|
||||||
|
darkGreyScheme =
|
||||||
|
{ bg = Colors.darkGrey
|
||||||
|
, fg = Colors.sandstone
|
||||||
|
, bgHover = Colors.darkerGrey
|
||||||
|
, fgActive = Colors.amazonite
|
||||||
|
, bgActive = Colors.darkerGrey
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
darkerGreyScheme : ColorScheme
|
||||||
|
darkerGreyScheme =
|
||||||
|
{ bg = Colors.darkerGrey
|
||||||
|
, fg = Colors.sandstone
|
||||||
|
, bgHover = Colors.darkerGrey
|
||||||
|
, fgActive = Colors.amazonite
|
||||||
|
, bgActive = Colors.darkerGrey
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lightGreyScheme : ColorScheme
|
||||||
|
lightGreyScheme =
|
||||||
|
{ bg = Colors.darkerLightGrey
|
||||||
|
, fg = Colors.sandstone
|
||||||
|
, bgHover = Colors.lighterLightGrey
|
||||||
|
, fgActive = Colors.sandstone
|
||||||
|
, bgActive = Colors.lightGrey
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cobaltScheme : ColorScheme
|
||||||
|
cobaltScheme =
|
||||||
|
{ bg = Colors.cobalt
|
||||||
|
, fg = Colors.white
|
||||||
|
, bgHover = Colors.darkCobalt
|
||||||
|
, fgActive = Colors.amazonite
|
||||||
|
, bgActive = Colors.darkCobalt
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
colorize : ColorScheme -> Style
|
||||||
|
colorize scheme =
|
||||||
|
batch
|
||||||
|
[ color scheme.fg
|
||||||
|
, fontWeight bold
|
||||||
|
, cursor pointer
|
||||||
|
, backgroundColor scheme.bg
|
||||||
|
, hover
|
||||||
|
[ backgroundColor scheme.bgHover
|
||||||
|
]
|
||||||
|
, active [ color scheme.fgActive ]
|
||||||
|
, withClass Active
|
||||||
|
[ color scheme.fgActive
|
||||||
|
, backgroundColor scheme.bgActive
|
||||||
|
]
|
||||||
|
]
|
||||||
68
lamassu-admin-elm/src/Css/LocalColors.elm
Normal file
68
lamassu-admin-elm/src/Css/LocalColors.elm
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
module Css.LocalColors exposing (..)
|
||||||
|
|
||||||
|
import Css exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
cobalt : Color
|
||||||
|
cobalt =
|
||||||
|
hex "004062"
|
||||||
|
|
||||||
|
|
||||||
|
darkCobalt : Color
|
||||||
|
darkCobalt =
|
||||||
|
hex "042c47"
|
||||||
|
|
||||||
|
|
||||||
|
amazonite : Color
|
||||||
|
amazonite =
|
||||||
|
hex "37e8d7"
|
||||||
|
|
||||||
|
|
||||||
|
white : Color
|
||||||
|
white =
|
||||||
|
hex "ffffff"
|
||||||
|
|
||||||
|
|
||||||
|
sandstone : Color
|
||||||
|
sandstone =
|
||||||
|
hex "5f5f56"
|
||||||
|
|
||||||
|
|
||||||
|
lightGrey : Color
|
||||||
|
lightGrey =
|
||||||
|
hex "f6f6f4"
|
||||||
|
|
||||||
|
|
||||||
|
lighterLightGrey : Color
|
||||||
|
lighterLightGrey =
|
||||||
|
hex "fcfcfa"
|
||||||
|
|
||||||
|
|
||||||
|
darkerLightGrey : Color
|
||||||
|
darkerLightGrey =
|
||||||
|
hex "E6E6E3"
|
||||||
|
|
||||||
|
|
||||||
|
darkGrey : Color
|
||||||
|
darkGrey =
|
||||||
|
hex "2d2d2d"
|
||||||
|
|
||||||
|
|
||||||
|
darkerGrey : Color
|
||||||
|
darkerGrey =
|
||||||
|
hex "282828"
|
||||||
|
|
||||||
|
|
||||||
|
red : Color
|
||||||
|
red =
|
||||||
|
hex "eb6b6e"
|
||||||
|
|
||||||
|
|
||||||
|
lightRed : Color
|
||||||
|
lightRed =
|
||||||
|
hex "efd1d2"
|
||||||
|
|
||||||
|
|
||||||
|
disabledGrey : Color
|
||||||
|
disabledGrey =
|
||||||
|
hex "757575"
|
||||||
523
lamassu-admin-elm/src/Css/Main.elm
Normal file
523
lamassu-admin-elm/src/Css/Main.elm
Normal file
|
|
@ -0,0 +1,523 @@
|
||||||
|
module Css.Main exposing (..)
|
||||||
|
|
||||||
|
import Css exposing (..)
|
||||||
|
import Css.Elements
|
||||||
|
exposing
|
||||||
|
( body
|
||||||
|
, li
|
||||||
|
, a
|
||||||
|
, div
|
||||||
|
, td
|
||||||
|
, th
|
||||||
|
, tr
|
||||||
|
, thead
|
||||||
|
, tbody
|
||||||
|
, input
|
||||||
|
, button
|
||||||
|
, label
|
||||||
|
, p
|
||||||
|
, svg
|
||||||
|
, h2
|
||||||
|
)
|
||||||
|
import Css.Namespace exposing (namespace)
|
||||||
|
import Css.LocalColors as Colors
|
||||||
|
import Css.ColorSchemes exposing (..)
|
||||||
|
import Css.Classes exposing (..)
|
||||||
|
import Css.Selectize
|
||||||
|
|
||||||
|
|
||||||
|
type CssIds
|
||||||
|
= Page
|
||||||
|
|
||||||
|
|
||||||
|
mainBackgroundColor : Color
|
||||||
|
mainBackgroundColor =
|
||||||
|
Colors.lightGrey
|
||||||
|
|
||||||
|
|
||||||
|
contentBackgroundColor : Color
|
||||||
|
contentBackgroundColor =
|
||||||
|
Colors.white
|
||||||
|
|
||||||
|
|
||||||
|
navBackgroundColor : Color
|
||||||
|
navBackgroundColor =
|
||||||
|
Colors.darkGrey
|
||||||
|
|
||||||
|
|
||||||
|
navItemActiveBackgroundColor : Color
|
||||||
|
navItemActiveBackgroundColor =
|
||||||
|
Colors.darkerGrey
|
||||||
|
|
||||||
|
|
||||||
|
navItemActiveColor : Color
|
||||||
|
navItemActiveColor =
|
||||||
|
Colors.amazonite
|
||||||
|
|
||||||
|
|
||||||
|
navItemColor : Color
|
||||||
|
navItemColor =
|
||||||
|
Colors.sandstone
|
||||||
|
|
||||||
|
|
||||||
|
cryptoTabsBackgroundColor : Color
|
||||||
|
cryptoTabsBackgroundColor =
|
||||||
|
Colors.cobalt
|
||||||
|
|
||||||
|
|
||||||
|
cryptoTabsHoverBackgroundColor : Color
|
||||||
|
cryptoTabsHoverBackgroundColor =
|
||||||
|
Colors.darkCobalt
|
||||||
|
|
||||||
|
|
||||||
|
cryptoTabsColor : Color
|
||||||
|
cryptoTabsColor =
|
||||||
|
Colors.white
|
||||||
|
|
||||||
|
|
||||||
|
cryptoTabsActiveColor : Color
|
||||||
|
cryptoTabsActiveColor =
|
||||||
|
Colors.amazonite
|
||||||
|
|
||||||
|
|
||||||
|
cobaltBG : Color
|
||||||
|
cobaltBG =
|
||||||
|
Colors.cobalt
|
||||||
|
|
||||||
|
|
||||||
|
cobaltHoverBG : Color
|
||||||
|
cobaltHoverBG =
|
||||||
|
Colors.darkCobalt
|
||||||
|
|
||||||
|
|
||||||
|
cobaltColor : Color
|
||||||
|
cobaltColor =
|
||||||
|
Colors.white
|
||||||
|
|
||||||
|
|
||||||
|
cobaltActiveColor : Color
|
||||||
|
cobaltActiveColor =
|
||||||
|
Colors.amazonite
|
||||||
|
|
||||||
|
|
||||||
|
codeFonts : List String
|
||||||
|
codeFonts =
|
||||||
|
[ "Inconsolata", "monospace" ]
|
||||||
|
|
||||||
|
|
||||||
|
css : Stylesheet
|
||||||
|
css =
|
||||||
|
(stylesheet << namespace "lamassuAdmin")
|
||||||
|
[ body
|
||||||
|
[ fontFamilies [ "Nunito", "sans-serif" ]
|
||||||
|
, margin zero
|
||||||
|
]
|
||||||
|
, p
|
||||||
|
[ margin zero ]
|
||||||
|
, class QrCode
|
||||||
|
[ backgroundColor Colors.lightGrey
|
||||||
|
, padding (px 10)
|
||||||
|
, marginBottom (px 20)
|
||||||
|
, borderRadius (px 6)
|
||||||
|
, descendants
|
||||||
|
[ svg
|
||||||
|
[ height (px 400)
|
||||||
|
, width (px 400)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class Layout
|
||||||
|
[]
|
||||||
|
, class Main
|
||||||
|
[ displayFlex
|
||||||
|
, marginBottom (px 40)
|
||||||
|
]
|
||||||
|
, class PaneWrapper
|
||||||
|
[ displayFlex
|
||||||
|
]
|
||||||
|
, class LeftPane
|
||||||
|
[ minWidth (px 270)
|
||||||
|
]
|
||||||
|
, class ContentPane
|
||||||
|
[ maxHeight (pct 100)
|
||||||
|
]
|
||||||
|
, class StatusBar
|
||||||
|
[ position fixed
|
||||||
|
, bottom zero
|
||||||
|
, padding2 (px 10) (px 20)
|
||||||
|
, backgroundColor Colors.sandstone
|
||||||
|
, color Colors.white
|
||||||
|
, width (pct 100)
|
||||||
|
]
|
||||||
|
, class CashOut
|
||||||
|
[ backgroundColor Colors.lightGrey
|
||||||
|
]
|
||||||
|
, class FormRow
|
||||||
|
[ margin2 (px 20) zero
|
||||||
|
, firstChild
|
||||||
|
[ margin zero
|
||||||
|
]
|
||||||
|
, descendants
|
||||||
|
[ label
|
||||||
|
[ fontSize (px 11)
|
||||||
|
, fontWeight bold
|
||||||
|
, children
|
||||||
|
[ div
|
||||||
|
[ margin3 zero zero (px 5)
|
||||||
|
, color Colors.sandstone
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, input
|
||||||
|
[ border zero
|
||||||
|
, backgroundColor Colors.white
|
||||||
|
, borderRadius (px 3)
|
||||||
|
, padding (px 6)
|
||||||
|
, textAlign left
|
||||||
|
, fontFamilies codeFonts
|
||||||
|
, fontSize (px 14)
|
||||||
|
, fontWeight (int 600)
|
||||||
|
, width (pct 90)
|
||||||
|
, property "outline" "none"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class ButtonRow
|
||||||
|
[ textAlign right ]
|
||||||
|
, class Button
|
||||||
|
[ colorize cobaltScheme
|
||||||
|
, padding2 (px 10) (px 15)
|
||||||
|
, display inlineBlock
|
||||||
|
, borderRadius (px 5)
|
||||||
|
, withClass Disabled
|
||||||
|
[ backgroundColor Colors.darkerLightGrey
|
||||||
|
, color Colors.white
|
||||||
|
, cursor default
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class MainLeft
|
||||||
|
[ backgroundColor navBackgroundColor
|
||||||
|
, height (pct 100)
|
||||||
|
]
|
||||||
|
, class MainRight
|
||||||
|
[ backgroundColor mainBackgroundColor
|
||||||
|
, height (pct 100)
|
||||||
|
]
|
||||||
|
, class Content
|
||||||
|
[ margin (px 20)
|
||||||
|
, backgroundColor contentBackgroundColor
|
||||||
|
, borderRadius (px 5)
|
||||||
|
]
|
||||||
|
, class Container
|
||||||
|
[ padding (px 30)
|
||||||
|
, backgroundColor Colors.lightGrey
|
||||||
|
, borderRadius4 (px 0) (px 5) (px 5) (px 5)
|
||||||
|
, width (em 30)
|
||||||
|
]
|
||||||
|
, class CryptoAddress
|
||||||
|
[ fontFamilies codeFonts ]
|
||||||
|
, class BalanceSection
|
||||||
|
[ marginTop (em 2)
|
||||||
|
, descendants
|
||||||
|
[ h2
|
||||||
|
[ fontSize (em 1.2)
|
||||||
|
, marginBottom (em 0.2)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class Textarea
|
||||||
|
[ width (pct 100)
|
||||||
|
, border (px 0)
|
||||||
|
, backgroundColor transparent
|
||||||
|
]
|
||||||
|
, class CryptoTabs
|
||||||
|
[ displayFlex
|
||||||
|
, children
|
||||||
|
[ class CryptoTab
|
||||||
|
[ padding2 (px 10) (px 15)
|
||||||
|
, colorize lightGreyScheme
|
||||||
|
, textDecoration none
|
||||||
|
, firstChild
|
||||||
|
[ borderRadius4 (px 5) (px 0) (px 0) (px 0)
|
||||||
|
]
|
||||||
|
, lastChild
|
||||||
|
[ borderRadius4 (px 0) (px 5) (px 0) (px 0)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class SectionLabel
|
||||||
|
[ fontWeight bold
|
||||||
|
, fontSize (px 30)
|
||||||
|
, marginBottom (px 10)
|
||||||
|
]
|
||||||
|
, class ConfigContainer
|
||||||
|
[ padding2 (px 20) (px 60)
|
||||||
|
, borderRadius4 (px 0) (px 7) (px 7) (px 7)
|
||||||
|
, backgroundColor mainBackgroundColor
|
||||||
|
, margin3 zero zero (px 10)
|
||||||
|
, property "animation" "fadein 0.8s"
|
||||||
|
, overflow hidden
|
||||||
|
, minHeight (em 15)
|
||||||
|
, minWidth (em 20)
|
||||||
|
]
|
||||||
|
, class NoInput
|
||||||
|
[ fontFamilies codeFonts
|
||||||
|
, color Colors.sandstone
|
||||||
|
, fontWeight normal
|
||||||
|
, textAlign left |> important
|
||||||
|
]
|
||||||
|
, class TxTable
|
||||||
|
[ borderRadius (px 7)
|
||||||
|
, margin2 (px 20) zero
|
||||||
|
, property "border-collapse" "collapse"
|
||||||
|
, fontSize (px 14)
|
||||||
|
, width (pct 100)
|
||||||
|
, backgroundColor Colors.white
|
||||||
|
, descendants
|
||||||
|
[ a
|
||||||
|
[ textDecoration none
|
||||||
|
, color Colors.sandstone
|
||||||
|
, borderBottom3 (px 1) solid Colors.amazonite
|
||||||
|
]
|
||||||
|
, class NumberColumn
|
||||||
|
[ textAlign right
|
||||||
|
, width (em 10)
|
||||||
|
]
|
||||||
|
, class DirectionColumn
|
||||||
|
[ textAlign left
|
||||||
|
, fontWeight bold
|
||||||
|
, fontSize (pct 90)
|
||||||
|
]
|
||||||
|
, class TxCancelled
|
||||||
|
[ backgroundColor Colors.lightRed ]
|
||||||
|
, tbody
|
||||||
|
[ fontFamilies codeFonts
|
||||||
|
, color Colors.sandstone
|
||||||
|
, descendants
|
||||||
|
[ td
|
||||||
|
[ padding2 (px 2) (px 14)
|
||||||
|
, borderBottom3 (px 1) solid Colors.lightGrey
|
||||||
|
, whiteSpace noWrap
|
||||||
|
]
|
||||||
|
, class TruncatedColumn
|
||||||
|
[ maxWidth zero
|
||||||
|
, overflow hidden
|
||||||
|
, width (px 300)
|
||||||
|
, textOverflow ellipsis
|
||||||
|
]
|
||||||
|
, class TxDate [ width (em 10) ]
|
||||||
|
, class TxAddress
|
||||||
|
[ width (em 25)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, thead
|
||||||
|
[ fontSize (px 14)
|
||||||
|
, textAlign center
|
||||||
|
, color Colors.sandstone
|
||||||
|
, descendants
|
||||||
|
[ td
|
||||||
|
[ borderBottom3 (px 2) solid Colors.lightGrey
|
||||||
|
, padding (px 5)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class EmptyTable
|
||||||
|
[ fontSize (px 20)
|
||||||
|
, fontWeight normal
|
||||||
|
]
|
||||||
|
, class ConfigTable
|
||||||
|
[ fontSize (px 14)
|
||||||
|
, fontWeight bold
|
||||||
|
, borderRadius (px 7)
|
||||||
|
, margin2 (px 20) zero
|
||||||
|
, property "border-collapse" "collapse"
|
||||||
|
, descendants
|
||||||
|
[ class Css.Selectize.SelectizeContainer
|
||||||
|
[ Css.Selectize.component
|
||||||
|
, border3 (px 2) solid Colors.darkerLightGrey
|
||||||
|
, borderRadius (px 3)
|
||||||
|
]
|
||||||
|
, class InputContainer
|
||||||
|
[ displayFlex
|
||||||
|
, property "justify-content" "flex-end"
|
||||||
|
, border3 (px 2) solid Colors.darkerLightGrey
|
||||||
|
, borderRadius (px 3)
|
||||||
|
]
|
||||||
|
, class UnitDisplay
|
||||||
|
[ backgroundColor Colors.darkerLightGrey
|
||||||
|
, color Colors.sandstone
|
||||||
|
, padding2 zero (px 5)
|
||||||
|
, fontWeight (int 700)
|
||||||
|
, fontSize (pct 80)
|
||||||
|
, lineHeight (px 25)
|
||||||
|
, cursor default
|
||||||
|
, fontFamilies [ "Nunito", "sans-serif" ]
|
||||||
|
]
|
||||||
|
, input
|
||||||
|
[ border zero
|
||||||
|
, borderRadius (px 3)
|
||||||
|
, padding (px 6)
|
||||||
|
, textAlign right
|
||||||
|
, width (pct 100)
|
||||||
|
, fontFamilies codeFonts
|
||||||
|
, fontWeight (int 600)
|
||||||
|
, fontSize (px 14)
|
||||||
|
, outline none
|
||||||
|
, backgroundColor Colors.white
|
||||||
|
]
|
||||||
|
, class CellDisabled
|
||||||
|
[ property "background" "repeating-linear-gradient(45deg,#dfdfdc,#dfdfdc 2px,#e6e6e3 5px)"
|
||||||
|
]
|
||||||
|
, class BasicInput
|
||||||
|
[ pseudoElement "placeholder"
|
||||||
|
[ color Colors.amazonite
|
||||||
|
, opacity (num 1)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class BasicInputDisabled
|
||||||
|
[ height (px 25)
|
||||||
|
, lineHeight (px 25)
|
||||||
|
, fontSize (px 14)
|
||||||
|
, fontWeight (int 500)
|
||||||
|
, color Colors.sandstone
|
||||||
|
, opacity (num 0.7)
|
||||||
|
, textAlign left
|
||||||
|
, padding2 zero (em 1)
|
||||||
|
, property "background" "repeating-linear-gradient(45deg,#dfdfdc,#dfdfdc 2px,#e6e6e3 5px)"
|
||||||
|
]
|
||||||
|
, class ReadOnly
|
||||||
|
[ lineHeight (px 25)
|
||||||
|
, backgroundColor Colors.lightGrey
|
||||||
|
, fontFamilies codeFonts
|
||||||
|
, fontSize (px 14)
|
||||||
|
, fontWeight (int 600)
|
||||||
|
, color Colors.sandstone
|
||||||
|
, cursor default
|
||||||
|
, children
|
||||||
|
[ class BasicInputReadOnly
|
||||||
|
[ padding2 zero (px 5)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, td
|
||||||
|
[ padding2 (px 3) (px 4)
|
||||||
|
, textAlign center
|
||||||
|
, verticalAlign middle
|
||||||
|
, width (em 5)
|
||||||
|
]
|
||||||
|
, class Component
|
||||||
|
[ borderRadius (px 3)
|
||||||
|
, border3 (px 2) solid Colors.lightGrey
|
||||||
|
, backgroundColor Colors.white
|
||||||
|
]
|
||||||
|
, class FocusedComponent
|
||||||
|
[ children
|
||||||
|
[ class InputContainer
|
||||||
|
[ borderColor Colors.amazonite ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class InvalidComponent
|
||||||
|
[ children
|
||||||
|
[ class InputContainer [ borderColor Colors.red ]
|
||||||
|
, class Css.Selectize.SelectizeContainer [ borderColor Colors.red ]
|
||||||
|
]
|
||||||
|
, descendants
|
||||||
|
[ input
|
||||||
|
[ color Colors.red
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, tbody
|
||||||
|
[ descendants
|
||||||
|
[ td
|
||||||
|
[ textAlign right
|
||||||
|
, whiteSpace noWrap
|
||||||
|
]
|
||||||
|
, td
|
||||||
|
[ firstChild
|
||||||
|
[ fontWeight normal
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, thead
|
||||||
|
[ fontWeight bold
|
||||||
|
, textAlign left
|
||||||
|
]
|
||||||
|
, class MultiDisplay
|
||||||
|
[ backgroundColor Colors.darkerLightGrey
|
||||||
|
, borderLeft3 (px 3) solid Colors.lightGrey
|
||||||
|
, borderRight3 (px 3) solid Colors.lightGrey
|
||||||
|
, borderRadius (px 3)
|
||||||
|
]
|
||||||
|
, th
|
||||||
|
[ padding2 (px 3) (px 4)
|
||||||
|
, textAlign center
|
||||||
|
]
|
||||||
|
, class ConfigTableGlobalRow
|
||||||
|
[ descendants
|
||||||
|
[ td
|
||||||
|
[ firstChild
|
||||||
|
[ fontWeight bold
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class TextCell
|
||||||
|
[ textAlign left ]
|
||||||
|
, class ShortCell
|
||||||
|
[ minWidth (em 5) ]
|
||||||
|
, class MediumCell
|
||||||
|
[ minWidth (em 10) ]
|
||||||
|
, class LongCell
|
||||||
|
[ minWidth (em 20) ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class Saving
|
||||||
|
[ fontSize (px 18)
|
||||||
|
, fontWeight normal
|
||||||
|
, textAlign right
|
||||||
|
]
|
||||||
|
, class NavBar
|
||||||
|
[ margin zero
|
||||||
|
, padding4 zero zero (px 110) zero
|
||||||
|
, backgroundColor Colors.darkGrey
|
||||||
|
, fontSize (px 18)
|
||||||
|
, width (em 15)
|
||||||
|
, maxWidth (em 15)
|
||||||
|
, minWidth (em 15)
|
||||||
|
, height (pct 100)
|
||||||
|
, descendants
|
||||||
|
[ class NavBarRoute
|
||||||
|
[ height (px 60)
|
||||||
|
, display block
|
||||||
|
, lineHeight (px 60)
|
||||||
|
, padding2 (px 0) (px 20)
|
||||||
|
, colorize darkGreyScheme
|
||||||
|
]
|
||||||
|
, class NavBarCategory
|
||||||
|
[ height (px 60)
|
||||||
|
, display block
|
||||||
|
, lineHeight (px 60)
|
||||||
|
, padding2 (px 0) (px 20)
|
||||||
|
, colorize darkGreyScheme
|
||||||
|
]
|
||||||
|
, class InvalidGroup
|
||||||
|
[ color Colors.red |> important ]
|
||||||
|
, class NavBarCategoryContainer
|
||||||
|
[ descendants
|
||||||
|
[ class NavBarRoute
|
||||||
|
[ colorize darkGreyScheme
|
||||||
|
, padding4 zero (px 20) zero (px 30)
|
||||||
|
, fontWeight (int 500)
|
||||||
|
, property "animation" "fadein 0.8s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
164
lamassu-admin-elm/src/Css/Selectize.elm
Normal file
164
lamassu-admin-elm/src/Css/Selectize.elm
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
module Css.Selectize exposing (..)
|
||||||
|
|
||||||
|
import Css exposing (..)
|
||||||
|
import Css.LocalColors as Colors
|
||||||
|
import Selectize
|
||||||
|
import Css.Admin exposing (className)
|
||||||
|
import Css.Elements exposing (input)
|
||||||
|
import Css.Classes as C
|
||||||
|
|
||||||
|
codeFonts : List String
|
||||||
|
codeFonts =
|
||||||
|
[ "Inconsolata", "monospace" ]
|
||||||
|
|
||||||
|
|
||||||
|
component : Style
|
||||||
|
component =
|
||||||
|
batch
|
||||||
|
[ borderRadius (px 3)
|
||||||
|
, position relative
|
||||||
|
, margin zero
|
||||||
|
, descendants
|
||||||
|
[ class NoOptions
|
||||||
|
[ backgroundColor Colors.lighterLightGrey
|
||||||
|
, fontSize (px 14)
|
||||||
|
, fontWeight (int 500)
|
||||||
|
, color Colors.sandstone
|
||||||
|
, padding (px 5)
|
||||||
|
, textAlign center
|
||||||
|
, cursor default
|
||||||
|
, property "-webkit-user-select" "none"
|
||||||
|
]
|
||||||
|
, class SelectBox
|
||||||
|
[ displayFlex
|
||||||
|
, alignItems center
|
||||||
|
, padding2 zero (px 5)
|
||||||
|
, property "background-color" "inherit"
|
||||||
|
, width (px 60)
|
||||||
|
]
|
||||||
|
, class BoxContainer
|
||||||
|
[ position absolute
|
||||||
|
, property "z-index" "100"
|
||||||
|
, left (px -3)
|
||||||
|
, backgroundColor Colors.white
|
||||||
|
, textAlign left
|
||||||
|
, fontWeight (int 500)
|
||||||
|
, fontSize (pct 80)
|
||||||
|
, borderRadius (px 3)
|
||||||
|
, backgroundColor Colors.white
|
||||||
|
, border3 (px 2) solid Colors.darkerLightGrey
|
||||||
|
, borderTop zero
|
||||||
|
, color Colors.sandstone
|
||||||
|
, width (em 15)
|
||||||
|
, cursor pointer
|
||||||
|
, padding (px 5)
|
||||||
|
]
|
||||||
|
, class BoxItems
|
||||||
|
[]
|
||||||
|
, class BoxItemActive
|
||||||
|
[ color Colors.cobalt
|
||||||
|
, fontWeight (int 900)
|
||||||
|
]
|
||||||
|
, class BoxItem
|
||||||
|
[ padding2 (px 3) (px 6)
|
||||||
|
, overflow hidden
|
||||||
|
, textOverflow ellipsis
|
||||||
|
]
|
||||||
|
, class Info
|
||||||
|
[ padding2 (px 3) (px 6)
|
||||||
|
, color Colors.darkGrey
|
||||||
|
]
|
||||||
|
, class MultiItemContainer
|
||||||
|
[ descendants
|
||||||
|
[ class SelectedItem
|
||||||
|
[ backgroundColor Colors.cobalt
|
||||||
|
, color Colors.white
|
||||||
|
, padding (px 2)
|
||||||
|
, margin2 zero (px 1)
|
||||||
|
, fontFamilies codeFonts
|
||||||
|
, fontSize (pct 70)
|
||||||
|
, fontWeight normal
|
||||||
|
, borderRadius (px 3)
|
||||||
|
]
|
||||||
|
, class FallbackItem
|
||||||
|
[ backgroundColor Colors.amazonite
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class SingleItemContainer
|
||||||
|
[ descendants
|
||||||
|
[ class SelectedItem
|
||||||
|
[ fontFamilies codeFonts
|
||||||
|
, fontSize (px 14)
|
||||||
|
, padding zero
|
||||||
|
, borderRadius zero
|
||||||
|
]
|
||||||
|
, class FallbackItem
|
||||||
|
[ color Colors.sandstone
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class C.SelectizeLanguage
|
||||||
|
[ descendants
|
||||||
|
[ class SelectBox
|
||||||
|
[ width (px 140)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, class C.SelectizeCryptoCurrency
|
||||||
|
[ descendants
|
||||||
|
[ class SelectBox
|
||||||
|
[ width (px 150)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, input
|
||||||
|
[ textAlign left
|
||||||
|
, property "background-color" "inherit"
|
||||||
|
, padding2 (px 6) (px 2)
|
||||||
|
, width (em 6)
|
||||||
|
, cursor default
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
type Class
|
||||||
|
= SelectizeContainer
|
||||||
|
| SelectBox
|
||||||
|
| BoxItems
|
||||||
|
| BoxItem
|
||||||
|
| BoxItemActive
|
||||||
|
| SelectedItems
|
||||||
|
| FallbackItems
|
||||||
|
| FallbackItem
|
||||||
|
| SelectedItem
|
||||||
|
| InputEditing
|
||||||
|
| SingleItemContainer
|
||||||
|
| MultiItemContainer
|
||||||
|
| BoxContainer
|
||||||
|
| Info
|
||||||
|
| InfoNoMatches
|
||||||
|
| NoOptions
|
||||||
|
| Disabled
|
||||||
|
|
||||||
|
|
||||||
|
classes : Selectize.HtmlClasses
|
||||||
|
classes =
|
||||||
|
{ container = className SelectizeContainer
|
||||||
|
, singleItemContainer = className SingleItemContainer
|
||||||
|
, multiItemContainer = className MultiItemContainer
|
||||||
|
, selectBox = className SelectBox
|
||||||
|
, selectedItems = className SelectedItems
|
||||||
|
, fallbackItems = className FallbackItems
|
||||||
|
, fallbackItem = className FallbackItem
|
||||||
|
, selectedItem = className SelectedItem
|
||||||
|
, boxContainer = className BoxContainer
|
||||||
|
, boxItems = className BoxItems
|
||||||
|
, boxItem = className BoxItem
|
||||||
|
, boxItemActive = className BoxItemActive
|
||||||
|
, info = className Info
|
||||||
|
, infoNoMatches = className InfoNoMatches
|
||||||
|
, inputEditing = className InputEditing
|
||||||
|
, noOptions = className NoOptions
|
||||||
|
}
|
||||||
24
lamassu-admin-elm/src/Customer/Rest.elm
Normal file
24
lamassu-admin-elm/src/Customer/Rest.elm
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
module Customer.Rest exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Http
|
||||||
|
import HttpBuilder exposing (..)
|
||||||
|
import Common.Customer.Decoder exposing (customerDecoder)
|
||||||
|
import Common.Customer.Types exposing (..)
|
||||||
|
import Customer.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
patchCustomer : String -> String -> Authorized -> Cmd Msg
|
||||||
|
patchCustomer id field value =
|
||||||
|
patch ("/api/customer/" ++ id ++ "?" ++ field ++ "=" ++ authorizedToString value)
|
||||||
|
|> withExpect (Http.expectJson customerDecoder)
|
||||||
|
|> send RemoteData.fromResult
|
||||||
|
|> Cmd.map Load
|
||||||
|
|
||||||
|
|
||||||
|
getCustomer : String -> Cmd Msg
|
||||||
|
getCustomer id =
|
||||||
|
get ("/api/customer/" ++ id)
|
||||||
|
|> withExpect (Http.expectJson customerDecoder)
|
||||||
|
|> send RemoteData.fromResult
|
||||||
|
|> Cmd.map Load
|
||||||
25
lamassu-admin-elm/src/Customer/State.elm
Normal file
25
lamassu-admin-elm/src/Customer/State.elm
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
module Customer.State exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Customer.Rest exposing (..)
|
||||||
|
import Customer.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
NotAsked
|
||||||
|
|
||||||
|
|
||||||
|
load : String -> ( Model, Cmd Msg )
|
||||||
|
load id =
|
||||||
|
( Loading, getCustomer id )
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Load loadedModel ->
|
||||||
|
loadedModel ! []
|
||||||
|
|
||||||
|
PatchCustomer id fieldName value ->
|
||||||
|
model ! [ patchCustomer id fieldName value ]
|
||||||
13
lamassu-admin-elm/src/Customer/Types.elm
Normal file
13
lamassu-admin-elm/src/Customer/Types.elm
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
module Customer.Types exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Common.Customer.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
RemoteData.WebData Customer
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Load Model
|
||||||
|
| PatchCustomer String String Authorized
|
||||||
197
lamassu-admin-elm/src/Customer/View.elm
Normal file
197
lamassu-admin-elm/src/Customer/View.elm
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
module Customer.View exposing (..)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (..)
|
||||||
|
import Html.Events exposing (onClick)
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Css.Admin as CSSAdmin exposing (..)
|
||||||
|
import Css.Classes as C
|
||||||
|
import Common.Customer.Types exposing (..)
|
||||||
|
import Customer.Types exposing (..)
|
||||||
|
import Date exposing (..)
|
||||||
|
import Date.Extra exposing (toFormattedString)
|
||||||
|
|
||||||
|
|
||||||
|
customerActions : String -> Authorized -> Html Msg
|
||||||
|
customerActions id authorizedOverride =
|
||||||
|
case authorizedOverride of
|
||||||
|
Blocked ->
|
||||||
|
button [ onClick (PatchCustomer id "authorizedOverride" Verified) ] [ text "Unblock" ]
|
||||||
|
|
||||||
|
Verified ->
|
||||||
|
button [ onClick (PatchCustomer id "authorizedOverride" Blocked) ] [ text "Block" ]
|
||||||
|
|
||||||
|
Automatic ->
|
||||||
|
button [ onClick (PatchCustomer id "authorizedOverride" Blocked) ] [ text "Block" ]
|
||||||
|
|
||||||
|
|
||||||
|
formatDate : Maybe Date -> String
|
||||||
|
formatDate date =
|
||||||
|
case date of
|
||||||
|
Just date ->
|
||||||
|
toFormattedString "yyyy-MM-dd HH:mm" date
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
""
|
||||||
|
|
||||||
|
|
||||||
|
maybeText : Maybe String -> Html Msg
|
||||||
|
maybeText maybeString =
|
||||||
|
text (Maybe.withDefault "" maybeString)
|
||||||
|
|
||||||
|
|
||||||
|
actions : String -> String -> Authorized -> Html Msg
|
||||||
|
actions id fieldKey checkedValue =
|
||||||
|
(div []
|
||||||
|
[ div []
|
||||||
|
[ radio fieldKey checkedValue Automatic (PatchCustomer id fieldKey Automatic)
|
||||||
|
, radio fieldKey checkedValue Blocked (PatchCustomer id fieldKey Blocked)
|
||||||
|
, radio fieldKey checkedValue Verified (PatchCustomer id fieldKey Verified)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
radio : String -> Authorized -> Authorized -> msg -> Html msg
|
||||||
|
radio inputName checkedValue value msg =
|
||||||
|
label
|
||||||
|
[ style [ ( "padding", "5px" ) ] ]
|
||||||
|
[ input [ checked (checkedValue == value), type_ "radio", name inputName, onClick msg ] []
|
||||||
|
, text (authorizedToString value)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
verifyStatus : Maybe a -> Authorized -> Html Msg
|
||||||
|
verifyStatus complianceType fieldOverride =
|
||||||
|
if fieldOverride == Verified || (complianceType /= Nothing && fieldOverride == Automatic) then
|
||||||
|
text "Verified"
|
||||||
|
else
|
||||||
|
text "Unverified"
|
||||||
|
|
||||||
|
|
||||||
|
customerView : Customer -> Html Msg
|
||||||
|
customerView customer =
|
||||||
|
div []
|
||||||
|
[ h1 [] [ text "Customer Details" ]
|
||||||
|
, table [ CSSAdmin.class [ C.TxTable ] ]
|
||||||
|
[ tbody []
|
||||||
|
[ tr []
|
||||||
|
[ td [] [ text "Customer ID" ]
|
||||||
|
, td [] [ text customer.id ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Name" ]
|
||||||
|
, td [] [ maybeText customer.name ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Phone" ]
|
||||||
|
, td [] [ maybeText customer.phone ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Completed phone at" ]
|
||||||
|
, td [] [ text (formatDate customer.phoneAt) ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Created" ]
|
||||||
|
, td [] [ text (toFormattedString "yyyy-MM-dd HH:mm" customer.created) ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Block Customer" ]
|
||||||
|
, td []
|
||||||
|
[ customerActions customer.id customer.authorizedOverride ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Authorized at " ]
|
||||||
|
, td [] [ text (formatDate customer.authorizedAt) ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Daily Volume " ]
|
||||||
|
, td [] [ maybeText customer.dailyVolume ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, h2 [] [ text "Compliance types" ]
|
||||||
|
, table [ CSSAdmin.class [ C.TxTable ] ]
|
||||||
|
[ thead []
|
||||||
|
[ tr []
|
||||||
|
[ td [] [ text "Name" ]
|
||||||
|
, td [] [ text "Date" ]
|
||||||
|
, td [] [ text "Verify Status" ]
|
||||||
|
, td [] [ text "Override Status" ]
|
||||||
|
, td [] [ text "User who overrode" ]
|
||||||
|
, td [] [ text "Actions" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, tbody []
|
||||||
|
[ tr []
|
||||||
|
[ td [] [ text "SMS" ]
|
||||||
|
, td [] [ text (formatDate customer.phoneAt) ]
|
||||||
|
, td [] [ verifyStatus customer.phone customer.smsOverride ]
|
||||||
|
, td [] [ text (authorizedToString customer.smsOverride) ]
|
||||||
|
, td [] [ maybeText customer.smsOverrideByName ]
|
||||||
|
, td [] [ actions customer.id "smsOverride" customer.smsOverride ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "ID Card Data" ]
|
||||||
|
, td [] [ text (formatDate customer.idCardDataAt) ]
|
||||||
|
, td [] [ verifyStatus customer.idCardData customer.idCardDataOverride ]
|
||||||
|
, td [] [ text (authorizedToString customer.idCardDataOverride) ]
|
||||||
|
, td [] [ maybeText customer.idCardDataOverrideByName ]
|
||||||
|
, td [] [ actions customer.id "idCardDataOverride" customer.idCardDataOverride ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "ID Card Photo" ]
|
||||||
|
, td [] [ text (formatDate customer.idCardPhotoAt) ]
|
||||||
|
, td [] [ verifyStatus customer.idCardPhotoPath customer.idCardPhotoOverride ]
|
||||||
|
, td [] [ text (authorizedToString customer.idCardPhotoOverride) ]
|
||||||
|
, td [] [ maybeText customer.idCardPhotoOverrideByName ]
|
||||||
|
, td [] [ actions customer.id "idCardPhotoOverride" customer.idCardPhotoOverride ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Front Facing Camera" ]
|
||||||
|
, td [] [ text (formatDate customer.frontCameraAt) ]
|
||||||
|
, td [] [ verifyStatus customer.frontCameraPath customer.frontCameraOverride ]
|
||||||
|
, td [] [ text (authorizedToString customer.frontCameraOverride) ]
|
||||||
|
, td [] [ maybeText customer.frontCameraOverrideByName ]
|
||||||
|
, td [] [ actions customer.id "frontCameraOverride" customer.frontCameraOverride ]
|
||||||
|
]
|
||||||
|
, tr []
|
||||||
|
[ td [] [ text "Sanctions Check" ]
|
||||||
|
, td [] [ text (formatDate customer.sanctionsAt) ]
|
||||||
|
, td [] [ verifyStatus customer.sanctions customer.sanctionsOverride ]
|
||||||
|
, td [] [ text (authorizedToString customer.sanctionsOverride) ]
|
||||||
|
, td [] [ maybeText customer.sanctionsOverrideByName ]
|
||||||
|
, td [] [ actions customer.id "sanctionsOverride" customer.sanctionsOverride ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, h2 [] [ text "ID Card Photo" ]
|
||||||
|
, case customer.idCardPhotoPath of
|
||||||
|
Nothing ->
|
||||||
|
text "N/A"
|
||||||
|
|
||||||
|
Just idCardPhotoPath ->
|
||||||
|
div []
|
||||||
|
[ img
|
||||||
|
[ src ("/id-card-photo/" ++ idCardPhotoPath)
|
||||||
|
, height 200
|
||||||
|
, alt "N/A"
|
||||||
|
] []
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
case model of
|
||||||
|
NotAsked ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
div [] [ text "Loading..." ]
|
||||||
|
|
||||||
|
Failure err ->
|
||||||
|
div [] [ text (toString err) ]
|
||||||
|
|
||||||
|
Success customer ->
|
||||||
|
div [] [ customerView customer ]
|
||||||
15
lamassu-admin-elm/src/Customers/Rest.elm
Normal file
15
lamassu-admin-elm/src/Customers/Rest.elm
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
module Customers.Rest exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Http
|
||||||
|
import HttpBuilder exposing (..)
|
||||||
|
import Common.Customer.Decoder exposing (customersDecoder)
|
||||||
|
import Customers.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
getCustomers : Cmd Msg
|
||||||
|
getCustomers =
|
||||||
|
get ("/api/customers")
|
||||||
|
|> withExpect (Http.expectJson customersDecoder)
|
||||||
|
|> send RemoteData.fromResult
|
||||||
|
|> Cmd.map Load
|
||||||
27
lamassu-admin-elm/src/Customers/State.elm
Normal file
27
lamassu-admin-elm/src/Customers/State.elm
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
module Customers.State exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Customers.Rest exposing (..)
|
||||||
|
import Customers.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
NotAsked
|
||||||
|
|
||||||
|
|
||||||
|
loadCmd : Cmd Msg
|
||||||
|
loadCmd =
|
||||||
|
getCustomers
|
||||||
|
|
||||||
|
|
||||||
|
load : ( Model, Cmd Msg )
|
||||||
|
load =
|
||||||
|
( Loading, loadCmd )
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Load loadedModel ->
|
||||||
|
loadedModel ! []
|
||||||
12
lamassu-admin-elm/src/Customers/Types.elm
Normal file
12
lamassu-admin-elm/src/Customers/Types.elm
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
module Customers.Types exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Common.Customer.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
RemoteData.WebData Customers
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Load Model
|
||||||
70
lamassu-admin-elm/src/Customers/View.elm
Normal file
70
lamassu-admin-elm/src/Customers/View.elm
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
module Customers.View exposing (..)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (colspan, href)
|
||||||
|
import Css.Admin exposing (..)
|
||||||
|
import Css.Classes as C
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import List
|
||||||
|
import Common.Customer.Types exposing (..)
|
||||||
|
import Customers.Types exposing (..)
|
||||||
|
import Date.Extra exposing (toFormattedString)
|
||||||
|
|
||||||
|
|
||||||
|
customerLink : String -> Html Msg
|
||||||
|
customerLink id =
|
||||||
|
a [ href ("/#customer/" ++ id) ] [ text (String.left 8 id) ]
|
||||||
|
|
||||||
|
|
||||||
|
maybeText : Maybe String -> Html Msg
|
||||||
|
maybeText maybeString =
|
||||||
|
text (Maybe.withDefault "" maybeString)
|
||||||
|
|
||||||
|
|
||||||
|
rowView : Customer -> Html Msg
|
||||||
|
rowView customer =
|
||||||
|
tr [ class [] ]
|
||||||
|
[ td [] [ customerLink customer.id ]
|
||||||
|
, td [] [ text (toFormattedString "yyyy-MM-dd HH:mm" customer.created) ]
|
||||||
|
, td [] [ maybeText customer.phone ]
|
||||||
|
, td [] [ maybeText customer.name ]
|
||||||
|
, td [] [ maybeText customer.status ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
tableView : Customers -> Html Msg
|
||||||
|
tableView customers =
|
||||||
|
if List.isEmpty customers then
|
||||||
|
div [] [ text "No customers yet." ]
|
||||||
|
else
|
||||||
|
div []
|
||||||
|
[ h1 [] [ text "Customers" ]
|
||||||
|
, table [ class [ C.TxTable ] ]
|
||||||
|
[ thead []
|
||||||
|
[ tr []
|
||||||
|
[ td [] [ text "Id" ]
|
||||||
|
, td [] [ text "Created" ]
|
||||||
|
, td [] [ text "Phone" ]
|
||||||
|
, td [] [ text "Name" ]
|
||||||
|
, td [] [ text "Status" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, tbody [] (List.map rowView customers)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
case model of
|
||||||
|
NotAsked ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
div [] [ text "Loading..." ]
|
||||||
|
|
||||||
|
Failure err ->
|
||||||
|
div [] [ text (toString err) ]
|
||||||
|
|
||||||
|
Success customers ->
|
||||||
|
div [] [ tableView customers ]
|
||||||
95
lamassu-admin-elm/src/FieldSet/Rest.elm
Normal file
95
lamassu-admin-elm/src/FieldSet/Rest.elm
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
module FieldSet.Rest exposing (..)
|
||||||
|
|
||||||
|
import Json.Decode as D
|
||||||
|
import Json.Encode as E
|
||||||
|
import FieldSet.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
fieldPasswordDecoder : Bool -> FieldValue
|
||||||
|
fieldPasswordDecoder present =
|
||||||
|
if present then
|
||||||
|
FieldPassword PasswordHidden
|
||||||
|
else
|
||||||
|
FieldPassword PasswordEmpty
|
||||||
|
|
||||||
|
|
||||||
|
badInt : D.Decoder Int
|
||||||
|
badInt =
|
||||||
|
D.oneOf [ D.int ]
|
||||||
|
|
||||||
|
|
||||||
|
fieldValueDecoder : String -> D.Decoder FieldValue
|
||||||
|
fieldValueDecoder fieldType =
|
||||||
|
case fieldType of
|
||||||
|
"string" ->
|
||||||
|
D.map FieldString D.string
|
||||||
|
|
||||||
|
"password" ->
|
||||||
|
D.map fieldPasswordDecoder D.bool
|
||||||
|
|
||||||
|
"integer" ->
|
||||||
|
D.map FieldInteger badInt
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
D.fail ("Unsupported field type: " ++ fieldType)
|
||||||
|
|
||||||
|
|
||||||
|
fieldDecoder : D.Decoder Field
|
||||||
|
fieldDecoder =
|
||||||
|
(D.field "fieldType" D.string)
|
||||||
|
|> D.andThen
|
||||||
|
(\fieldType ->
|
||||||
|
D.map6 Field
|
||||||
|
(D.field "code" D.string)
|
||||||
|
(D.field "display" D.string)
|
||||||
|
(D.oneOf [ D.field "placeholder" D.string, D.succeed "" ])
|
||||||
|
(D.field "required" D.bool)
|
||||||
|
(D.field "value" (fieldValueDecoder fieldType))
|
||||||
|
(D.field "value" (fieldValueDecoder fieldType))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
encodeFieldValue : FieldValue -> E.Value
|
||||||
|
encodeFieldValue fieldValue =
|
||||||
|
case fieldValue of
|
||||||
|
FieldString value ->
|
||||||
|
E.string value
|
||||||
|
|
||||||
|
FieldPassword value ->
|
||||||
|
case value of
|
||||||
|
Password s ->
|
||||||
|
E.string s
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
E.null
|
||||||
|
|
||||||
|
FieldInteger value ->
|
||||||
|
E.int value
|
||||||
|
|
||||||
|
|
||||||
|
maybeString : Maybe String -> E.Value
|
||||||
|
maybeString maybeString =
|
||||||
|
case maybeString of
|
||||||
|
Nothing ->
|
||||||
|
E.null
|
||||||
|
|
||||||
|
Just s ->
|
||||||
|
E.string s
|
||||||
|
|
||||||
|
|
||||||
|
encodeField : Field -> Maybe E.Value
|
||||||
|
encodeField field =
|
||||||
|
if isDirty field then
|
||||||
|
Just
|
||||||
|
(E.object
|
||||||
|
[ ( "code", E.string field.code )
|
||||||
|
, ( "value", encodeFieldValue field.value )
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
|
||||||
|
isDirty : Field -> Bool
|
||||||
|
isDirty field =
|
||||||
|
field.value /= field.loadedValue
|
||||||
23
lamassu-admin-elm/src/FieldSet/State.elm
Normal file
23
lamassu-admin-elm/src/FieldSet/State.elm
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
module FieldSet.State exposing (update)
|
||||||
|
|
||||||
|
import FieldSet.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
updateField : String -> String -> Field -> Field
|
||||||
|
updateField fieldCode fieldValueString field =
|
||||||
|
if .code field == fieldCode then
|
||||||
|
{ field | value = updateFieldValue fieldValueString field.value }
|
||||||
|
else
|
||||||
|
field
|
||||||
|
|
||||||
|
|
||||||
|
updateFieldSet : String -> String -> List Field -> List Field
|
||||||
|
updateFieldSet fieldCode fieldValueString fields =
|
||||||
|
List.map (updateField fieldCode fieldValueString) fields
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Input fieldCode valueString ->
|
||||||
|
updateFieldSet fieldCode valueString model ! []
|
||||||
44
lamassu-admin-elm/src/FieldSet/Types.elm
Normal file
44
lamassu-admin-elm/src/FieldSet/Types.elm
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
module FieldSet.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
List Field
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Input String String
|
||||||
|
|
||||||
|
|
||||||
|
type alias Field =
|
||||||
|
{ code : String
|
||||||
|
, display : String
|
||||||
|
, placeholder : String
|
||||||
|
, required : Bool
|
||||||
|
, value : FieldValue
|
||||||
|
, loadedValue : FieldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type FieldPasswordType
|
||||||
|
= Password String
|
||||||
|
| PasswordEmpty
|
||||||
|
| PasswordHidden
|
||||||
|
|
||||||
|
|
||||||
|
type FieldValue
|
||||||
|
= FieldString String
|
||||||
|
| FieldPassword FieldPasswordType
|
||||||
|
| FieldInteger Int
|
||||||
|
|
||||||
|
|
||||||
|
updateFieldValue : String -> FieldValue -> FieldValue
|
||||||
|
updateFieldValue stringValue oldFieldValue =
|
||||||
|
case oldFieldValue of
|
||||||
|
FieldString _ ->
|
||||||
|
FieldString stringValue
|
||||||
|
|
||||||
|
FieldPassword _ ->
|
||||||
|
FieldPassword (Password stringValue)
|
||||||
|
|
||||||
|
FieldInteger oldValue ->
|
||||||
|
FieldInteger <| Result.withDefault oldValue <| String.toInt stringValue
|
||||||
52
lamassu-admin-elm/src/FieldSet/View.elm
Normal file
52
lamassu-admin-elm/src/FieldSet/View.elm
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
module FieldSet.View exposing (view)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes as HA exposing (defaultValue, name, type_, placeholder)
|
||||||
|
import Html.Events exposing (..)
|
||||||
|
import FieldSet.Types exposing (..)
|
||||||
|
import List
|
||||||
|
import Css.Admin exposing (..)
|
||||||
|
import Css.Classes as C
|
||||||
|
|
||||||
|
|
||||||
|
fieldComponent : Field -> Html Msg
|
||||||
|
fieldComponent field =
|
||||||
|
let
|
||||||
|
inputEl =
|
||||||
|
case field.value of
|
||||||
|
FieldString string ->
|
||||||
|
input
|
||||||
|
[ onInput (Input field.code), placeholder field.placeholder, defaultValue string ]
|
||||||
|
[]
|
||||||
|
|
||||||
|
FieldPassword pass ->
|
||||||
|
case pass of
|
||||||
|
PasswordEmpty ->
|
||||||
|
input
|
||||||
|
[ onInput (Input field.code), name field.code, type_ "password" ]
|
||||||
|
[]
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
input
|
||||||
|
[ onInput (Input field.code), name field.code, type_ "password", placeholder "••• Field is set •••" ]
|
||||||
|
[]
|
||||||
|
|
||||||
|
FieldInteger int ->
|
||||||
|
input
|
||||||
|
[ onInput (Input field.code), type_ "number", defaultValue (toString int) ]
|
||||||
|
[]
|
||||||
|
in
|
||||||
|
label []
|
||||||
|
[ div [] [ text field.display ]
|
||||||
|
, inputEl
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
fieldView : Field -> Html Msg
|
||||||
|
fieldView field =
|
||||||
|
div [ class [ C.FormRow ] ] [ fieldComponent field ]
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div [ class [ C.ConfigContainer ] ] (List.map fieldView model)
|
||||||
48
lamassu-admin-elm/src/FuzzyMatch.elm
Normal file
48
lamassu-admin-elm/src/FuzzyMatch.elm
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
module FuzzyMatch exposing (match)
|
||||||
|
|
||||||
|
import String
|
||||||
|
import Fuzzy
|
||||||
|
import Tuple
|
||||||
|
|
||||||
|
|
||||||
|
clean : String -> String
|
||||||
|
clean s =
|
||||||
|
String.trim s
|
||||||
|
|> String.toLower
|
||||||
|
|
||||||
|
|
||||||
|
type alias DisplayRec =
|
||||||
|
{ code : String
|
||||||
|
, display : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
score : String -> Int -> DisplayRec -> ( ( Int, Int ), DisplayRec )
|
||||||
|
score needle index hay =
|
||||||
|
let
|
||||||
|
match keyword =
|
||||||
|
Fuzzy.match [] [] needle keyword
|
||||||
|
|> .score
|
||||||
|
|
||||||
|
score =
|
||||||
|
List.map match ((String.split " " (clean hay.display)) ++ [ clean hay.code, clean hay.display ])
|
||||||
|
|> List.minimum
|
||||||
|
|> Maybe.withDefault
|
||||||
|
10000
|
||||||
|
in
|
||||||
|
( ( score, index ), hay )
|
||||||
|
|
||||||
|
|
||||||
|
match : String -> List DisplayRec -> List DisplayRec
|
||||||
|
match rawString list =
|
||||||
|
let
|
||||||
|
s =
|
||||||
|
clean rawString
|
||||||
|
in
|
||||||
|
if String.isEmpty s then
|
||||||
|
list
|
||||||
|
else
|
||||||
|
List.indexedMap (score s) list
|
||||||
|
|> List.sortBy Tuple.first
|
||||||
|
|> List.filter (((>) 1100) << Tuple.first << Tuple.first)
|
||||||
|
|> List.map Tuple.second
|
||||||
153
lamassu-admin-elm/src/Lamassu.elm
Normal file
153
lamassu-admin-elm/src/Lamassu.elm
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
module Main exposing (..)
|
||||||
|
|
||||||
|
import Html exposing (Html, Attribute, a, div, hr, input, span, text, map)
|
||||||
|
import Html.Attributes exposing (class)
|
||||||
|
import Navigation
|
||||||
|
import SupportLogs.Types
|
||||||
|
import SupportLogs.State
|
||||||
|
import SupportLogs.View
|
||||||
|
import UrlParser exposing ((</>), s, string, top, parseHash)
|
||||||
|
import Navigation exposing (newUrl, Location)
|
||||||
|
import StatusTypes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type Category
|
||||||
|
= AccountCat
|
||||||
|
| MachineSettingsCat
|
||||||
|
| GlobalSettingsCat
|
||||||
|
| MaintenanceCat
|
||||||
|
|
||||||
|
|
||||||
|
type Route
|
||||||
|
= SupportLogsRoute (Maybe String)
|
||||||
|
| NotFoundRoute
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= SupportLogsMsg SupportLogs.Types.Msg
|
||||||
|
| UrlChange Navigation.Location
|
||||||
|
|
||||||
|
|
||||||
|
main : Program Never Model Msg
|
||||||
|
main =
|
||||||
|
Navigation.program UrlChange
|
||||||
|
{ init = init
|
||||||
|
, update = update
|
||||||
|
, view = view
|
||||||
|
, subscriptions = subscriptions
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- URL PARSERS
|
||||||
|
|
||||||
|
|
||||||
|
parseRoute : UrlParser.Parser (Route -> a) a
|
||||||
|
parseRoute =
|
||||||
|
UrlParser.oneOf
|
||||||
|
[ UrlParser.map (\id -> SupportLogsRoute (Just id)) (s "support_logs" </> string)
|
||||||
|
, UrlParser.map (SupportLogsRoute Nothing) (s "support_logs")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- MODEL
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ location : Location
|
||||||
|
, supportLogs : SupportLogs.Types.Model
|
||||||
|
, status : Maybe StatusRec
|
||||||
|
, err : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init : Location -> ( Model, Cmd Msg )
|
||||||
|
init location =
|
||||||
|
let
|
||||||
|
model =
|
||||||
|
{ location = location
|
||||||
|
, supportLogs = SupportLogs.State.init
|
||||||
|
, status = Nothing
|
||||||
|
, err = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
( newModel, newCmd ) =
|
||||||
|
urlUpdate location model
|
||||||
|
in
|
||||||
|
newModel ! [ newCmd ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- UPDATE
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
SupportLogsMsg supportLogsMsg ->
|
||||||
|
let
|
||||||
|
( supportLogsModel, cmd ) =
|
||||||
|
SupportLogs.State.update supportLogsMsg model.supportLogs
|
||||||
|
in
|
||||||
|
{ model | supportLogs = supportLogsModel } ! [ Cmd.map SupportLogsMsg cmd ]
|
||||||
|
|
||||||
|
UrlChange location ->
|
||||||
|
urlUpdate location model
|
||||||
|
|
||||||
|
|
||||||
|
content : Model -> Route -> Html Msg
|
||||||
|
content model route =
|
||||||
|
case route of
|
||||||
|
SupportLogsRoute _ ->
|
||||||
|
map SupportLogsMsg (SupportLogs.View.view model.supportLogs)
|
||||||
|
|
||||||
|
NotFoundRoute ->
|
||||||
|
div [] [ text ("No such route") ]
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
let
|
||||||
|
route =
|
||||||
|
Maybe.withDefault NotFoundRoute (parseHash parseRoute model.location)
|
||||||
|
|
||||||
|
invalidConfigGroups =
|
||||||
|
Maybe.map .invalidConfigGroups model.status
|
||||||
|
|> Maybe.withDefault []
|
||||||
|
in
|
||||||
|
div [ class "lamassuAdminLayout" ]
|
||||||
|
[ div
|
||||||
|
[ class "lamassuAdminMain" ]
|
||||||
|
[ div [ class "lamassuAdminContent" ]
|
||||||
|
[ content model route ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
urlUpdate : Location -> Model -> ( Model, Cmd Msg )
|
||||||
|
urlUpdate location model =
|
||||||
|
let
|
||||||
|
route =
|
||||||
|
Maybe.withDefault NotFoundRoute (parseHash parseRoute location)
|
||||||
|
in
|
||||||
|
case route of
|
||||||
|
SupportLogsRoute maybeId ->
|
||||||
|
let
|
||||||
|
( supportLogsModel, cmd ) =
|
||||||
|
SupportLogs.State.load maybeId
|
||||||
|
in
|
||||||
|
{ model | location = location, supportLogs = supportLogsModel } ! [ Cmd.map SupportLogsMsg cmd ]
|
||||||
|
|
||||||
|
NotFoundRoute ->
|
||||||
|
{ model | location = location } ! []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- SUBSCRIPTIONS
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Model -> Sub Msg
|
||||||
|
subscriptions model =
|
||||||
|
Sub.batch
|
||||||
|
[]
|
||||||
22
lamassu-admin-elm/src/LamassuAdminServerClient.elm
Normal file
22
lamassu-admin-elm/src/LamassuAdminServerClient.elm
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
module ClientServerWebsocket exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import HttpBuilder exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
-- Fetch stuff: different configurations for starters
|
||||||
|
|
||||||
|
|
||||||
|
type alias NewsResponse =
|
||||||
|
()
|
||||||
|
|
||||||
|
|
||||||
|
type alias Msg =
|
||||||
|
NewsResponse (WebData News)
|
||||||
|
|
||||||
|
|
||||||
|
getNews : Cmd Msg
|
||||||
|
getNews =
|
||||||
|
Http.get decodeNews "/news"
|
||||||
|
|> RemoteData.asCmd
|
||||||
|
|> Cmd.map NewsResponse
|
||||||
29
lamassu-admin-elm/src/Logs/Rest.elm
Normal file
29
lamassu-admin-elm/src/Logs/Rest.elm
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
module Logs.Rest exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Http
|
||||||
|
import HttpBuilder exposing (..)
|
||||||
|
import Common.Logs.Decoder exposing (logsDecoder, machinesDecoder, latestLogSnapshotDecoder)
|
||||||
|
import Logs.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
getLogs : Maybe String -> Cmd Msg
|
||||||
|
getLogs maybeId =
|
||||||
|
Http.get ("/api/logs/" ++ (Maybe.withDefault "" maybeId)) logsDecoder
|
||||||
|
|> RemoteData.sendRequest
|
||||||
|
|> Cmd.map LoadLogs
|
||||||
|
|
||||||
|
|
||||||
|
getMachines : Cmd Msg
|
||||||
|
getMachines =
|
||||||
|
Http.get "/api/machines/" machinesDecoder
|
||||||
|
|> RemoteData.sendRequest
|
||||||
|
|> Cmd.map LoadMachines
|
||||||
|
|
||||||
|
|
||||||
|
shareLogs : String -> Cmd Msg
|
||||||
|
shareLogs id =
|
||||||
|
post ("/api/support_logs?deviceId=" ++ id)
|
||||||
|
|> withExpect (Http.expectJson latestLogSnapshotDecoder)
|
||||||
|
|> send RemoteData.fromResult
|
||||||
|
|> Cmd.map LoadSupportLog
|
||||||
42
lamassu-admin-elm/src/Logs/State.elm
Normal file
42
lamassu-admin-elm/src/Logs/State.elm
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
module Logs.State exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Logs.Rest exposing (..)
|
||||||
|
import Logs.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
{ logs = NotAsked, machines = NotAsked, latestLogSnapshot = NotAsked }
|
||||||
|
|
||||||
|
|
||||||
|
load : Maybe String -> ( Model, Cmd Msg )
|
||||||
|
load maybeId =
|
||||||
|
( { logs = Loading, machines = Loading, latestLogSnapshot = NotAsked }, getData maybeId )
|
||||||
|
|
||||||
|
|
||||||
|
getData : Maybe String -> Cmd Msg
|
||||||
|
getData maybeId =
|
||||||
|
Cmd.batch [ getLogs maybeId, getMachines ]
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
LoadLogs response ->
|
||||||
|
( { model | logs = response }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
LoadMachines response ->
|
||||||
|
( { model | machines = response }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
ShareLogs machine ->
|
||||||
|
model ! [ shareLogs machine.deviceId ]
|
||||||
|
|
||||||
|
LoadSupportLog supportLog ->
|
||||||
|
( { model | latestLogSnapshot = supportLog }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
18
lamassu-admin-elm/src/Logs/Types.elm
Normal file
18
lamassu-admin-elm/src/Logs/Types.elm
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
module Logs.Types exposing (..)
|
||||||
|
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import Common.Logs.Types exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ logs : WebData Logs
|
||||||
|
, machines : WebData Machines
|
||||||
|
, latestLogSnapshot : WebData SupportLogSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= LoadLogs (WebData Logs)
|
||||||
|
| LoadMachines (WebData Machines)
|
||||||
|
| ShareLogs Machine
|
||||||
|
| LoadSupportLog (WebData SupportLogSnapshot)
|
||||||
149
lamassu-admin-elm/src/Logs/View.elm
Normal file
149
lamassu-admin-elm/src/Logs/View.elm
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
module Logs.View exposing (..)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (href)
|
||||||
|
import Html.Events exposing (onClick)
|
||||||
|
import Css.Admin exposing (..)
|
||||||
|
import Css.Classes as C
|
||||||
|
import RemoteData exposing (..)
|
||||||
|
import List
|
||||||
|
import Common.Logs.Types exposing (..)
|
||||||
|
import Logs.Types exposing (..)
|
||||||
|
import Date exposing (..)
|
||||||
|
import Date.Extra exposing (toFormattedString)
|
||||||
|
|
||||||
|
|
||||||
|
machineLink : Machine -> Html Msg
|
||||||
|
machineLink machine =
|
||||||
|
a [ href ("/#logs/" ++ machine.deviceId) ] [ text machine.name ]
|
||||||
|
|
||||||
|
|
||||||
|
logsActions : Logs -> Html Msg
|
||||||
|
logsActions logs =
|
||||||
|
button [ onClick (ShareLogs logs.currentMachine) ] [ text "Share log snapshot" ]
|
||||||
|
|
||||||
|
|
||||||
|
formatDate : Date -> String
|
||||||
|
formatDate date =
|
||||||
|
toFormattedString "yyyy-MM-dd HH:mm" date
|
||||||
|
|
||||||
|
|
||||||
|
rowView : Log -> Html Msg
|
||||||
|
rowView log =
|
||||||
|
tr [ class [] ]
|
||||||
|
[ td [] [ text (formatDate log.timestamp) ]
|
||||||
|
, td [] [ text log.logLevel ]
|
||||||
|
, td [] [ text log.message ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
machineRowView : Machine -> Html Msg
|
||||||
|
machineRowView machine =
|
||||||
|
tr [ class [] ]
|
||||||
|
[ td [] [ machineLink machine ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
machineItemView : Machine -> Html Msg
|
||||||
|
machineItemView machine =
|
||||||
|
li [] [ machineLink machine ]
|
||||||
|
|
||||||
|
|
||||||
|
machinesView : Machines -> Html Msg
|
||||||
|
machinesView machines =
|
||||||
|
if List.isEmpty machines then
|
||||||
|
div [ class [ C.EmptyTable ] ] [ text "No paired machines." ]
|
||||||
|
else
|
||||||
|
div []
|
||||||
|
[ div [ class [ C.TxTable ] ]
|
||||||
|
[ ul [] (List.map machineItemView machines)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
machines : Model -> Html Msg
|
||||||
|
machines model =
|
||||||
|
case model.machines of
|
||||||
|
NotAsked ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
div [] [ text "Loading machines ..." ]
|
||||||
|
|
||||||
|
Failure err ->
|
||||||
|
div [] [ text (toString err) ]
|
||||||
|
|
||||||
|
Success machines ->
|
||||||
|
div [] [ machinesView machines ]
|
||||||
|
|
||||||
|
|
||||||
|
latestLogSnapshot : Model -> Html Msg
|
||||||
|
latestLogSnapshot model =
|
||||||
|
case model.latestLogSnapshot of
|
||||||
|
NotAsked ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Failure err ->
|
||||||
|
div [] [ text (toString err) ]
|
||||||
|
|
||||||
|
Success latestLogSnapshot ->
|
||||||
|
h4 [] [ text "✓ Saved latest snapshot" ]
|
||||||
|
|
||||||
|
|
||||||
|
logsView : Logs -> Html Msg
|
||||||
|
logsView logs =
|
||||||
|
if List.isEmpty logs.logs then
|
||||||
|
div [] [ text "No logs yet." ]
|
||||||
|
else
|
||||||
|
div []
|
||||||
|
[ logsActions logs
|
||||||
|
, table [ class [ C.TxTable ] ]
|
||||||
|
[ thead []
|
||||||
|
[ tr []
|
||||||
|
[ td [] [ text "Date" ]
|
||||||
|
, td [] [ text "Level" ]
|
||||||
|
, td [] [ text "Message" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, tbody [] (List.map rowView logs.logs)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
logs : Model -> Html Msg
|
||||||
|
logs model =
|
||||||
|
case model.logs of
|
||||||
|
NotAsked ->
|
||||||
|
div [] []
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
div [] [ text "Loading logs..." ]
|
||||||
|
|
||||||
|
Failure err ->
|
||||||
|
div [] [ text (toString err) ]
|
||||||
|
|
||||||
|
Success logs ->
|
||||||
|
div []
|
||||||
|
[ logsView logs
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div []
|
||||||
|
[ h1 [] [ text "Latest Logs" ]
|
||||||
|
, div [ class [ C.PaneWrapper ] ]
|
||||||
|
[ div [ class [ C.LeftPane ] ]
|
||||||
|
[ h2 [] [ text "Machines" ]
|
||||||
|
, machines model
|
||||||
|
]
|
||||||
|
, div [ class [ C.ContentPane ] ]
|
||||||
|
[ h2 [] [ text "Logs" ]
|
||||||
|
, latestLogSnapshot model
|
||||||
|
, logs model
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue