App supports controlling intval with bluetooth

This commit is contained in:
mmcwilliams 2017-12-13 17:52:25 -05:00
parent 52194e0b41
commit e5207a8474
11 changed files with 354 additions and 74 deletions

View File

@ -22,8 +22,10 @@
<allow-intent href="itms:*" /> <allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" /> <allow-intent href="itms-apps:*" />
</platform> </platform>
<preference name="DisallowOverscroll" value="true" />
<preference name="StatusBarBackgroundColor" value="#212121" />
<engine name="android" spec="^6.4.0" />
<engine name="ios" spec="^4.5.4" /> <engine name="ios" spec="^4.5.4" />
<engine name="android" spec="^6.3.0" />
<plugin name="cordova-plugin-whitelist" spec="^1.3.3" /> <plugin name="cordova-plugin-whitelist" spec="^1.3.3" />
<plugin name="cordova-plugin-device" spec="^1.1.7" /> <plugin name="cordova-plugin-device" spec="^1.1.7" />
<plugin name="cordova-plugin-dialogs" spec="^1.3.4" /> <plugin name="cordova-plugin-dialogs" spec="^1.3.4" />

15
app/package-lock.json generated
View File

@ -4,15 +4,10 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"android-versions": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/android-versions/-/android-versions-1.2.1.tgz",
"integrity": "sha512-k6zlrtWbJ3tx1ZsyyJ0Bo3r6cqPA3JUnFGv7pnIaLr1XVxSi2Tcem2lg3kBebFp27v/A40tZqdlouPyakpyKrw=="
},
"cordova-android": { "cordova-android": {
"version": "6.3.0", "version": "6.4.0",
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-6.3.0.tgz", "resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-6.4.0.tgz",
"integrity": "sha1-2lQYQz0lx1pZd7QoJEu+Q30BKNI=", "integrity": "sha1-VK6NpXKKjX5e/MYXLT3MoXvH/n0=",
"requires": { "requires": {
"android-versions": "1.2.1", "android-versions": "1.2.1",
"cordova-common": "2.1.0", "cordova-common": "2.1.0",
@ -27,6 +22,10 @@
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true
}, },
"android-versions": {
"version": "1.2.1",
"bundled": true
},
"ansi": { "ansi": {
"version": "0.3.1", "version": "0.3.1",
"bundled": true "bundled": true

View File

@ -10,7 +10,7 @@
"author": "M McWilliams", "author": "M McWilliams",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cordova-android": "^6.3.0", "cordova-android": "^6.4.0",
"cordova-ios": "^4.5.4", "cordova-ios": "^4.5.4",
"cordova-plugin-ble-central": "^1.1.4", "cordova-plugin-ble-central": "^1.1.4",
"cordova-plugin-compat": "^1.2.0", "cordova-plugin-compat": "^1.2.0",
@ -30,8 +30,8 @@
} }
}, },
"platforms": [ "platforms": [
"ios", "android",
"android" "ios"
] ]
} }
} }

View File

@ -4,12 +4,15 @@
<title>INTVAL</title> <title>INTVAL</title>
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width = 320, initial-scale = 1.0, user-scalable = no"> <meta name="viewport" content="width = 320, initial-scale = 1.0, user-scalable = no, minimal-ui, viewport-fit=cover">
<link rel="stylesheet" href="static/css/codemirror.css" /> <link rel="stylesheet" href="static/css/codemirror.css" />
<link rel="stylesheet" href="static/css/monokai.css" /> <link rel="stylesheet" href="static/css/monokai.css" />
<link rel="stylesheet" href="static/css/index.css" /> <link rel="stylesheet" href="static/css/index.css" />
</head> </head>
<body> <body>
<div id="overlay">
<div id="spinner"></div>
</div>
<div id="app" class="page selected"> <div id="app" class="page selected">
<h2>INTVAL</h2> <h2>INTVAL</h2>
<div> <div>
@ -27,7 +30,7 @@
</div> </div>
<div> <div>
<div class="label">Exposure <span id="str">1/5</span></div> <div class="label">Exposure <span id="str">1/5</span></div>
<input type="number" id="exposure" value="630" min="0" oninput="setExposure();" /> <input type="number" id="exposure" value="630" min="0" onchange="setExposure();" />
<select id="scale" onchange="setExposureScale();"> <select id="scale" onchange="setExposureScale();">
<option value="ms" selected>ms</option> <option value="ms" selected>ms</option>
<option value="sec">sec</option> <option value="sec">sec</option>
@ -37,7 +40,7 @@
</div> </div>
<div> <div>
<div class="label">Delay</div> <div class="label">Delay</div>
<input type="number" id="delay" value="0" min="0" step="1" /> <input type="number" id="delay" value="0" min="0" step="1" onchange="setDelay();" />
<select id="delayScale" onchange="setDelayScale();"> <select id="delayScale" onchange="setDelayScale();">
<option value="ms" selected>ms</option> <option value="ms" selected>ms</option>
<option value="sec">sec</option> <option value="sec">sec</option>
@ -49,7 +52,7 @@
<button id="seq">START SEQUENCE</button> <button id="seq">START SEQUENCE</button>
</div> </div>
<div> <div>
<button id="frame" onclick="frame();">FRAME</button> <button id="frame" onclick="frame();">1 FRAME</button>
</div> </div>
</div> </div>
<div id="settings" class="page"> <div id="settings" class="page">
@ -62,10 +65,13 @@
<option value="33">2 Stop</option> <option value="33">2 Stop</option>
</select> </select>
</div> </div>
<div class="ble">
<h2>BLUETOOTH</h2> <h2>BLUETOOTH</h2>
<select id="bluetooth"> <select id="bluetooth">
<option>N/A</option> <option>N/A</option>
</select> </select>
</div>
<div class="ble">
<h2>WIFI</h2> <h2>WIFI</h2>
<div> <div>
<input type="text" id="ssid" placeholder="Wifi SSID" /> <input type="text" id="ssid" placeholder="Wifi SSID" />
@ -73,6 +79,7 @@
<div> <div>
<input type="password" id="password" placeholder="Wifi Password" /> <input type="password" id="password" placeholder="Wifi Password" />
</div> </div>
</div>
</div> </div>
<div id="mscript" class="page"> <div id="mscript" class="page">
<h2>MSCRIPT</h2> <h2>MSCRIPT</h2>
@ -92,6 +99,7 @@
</div> </div>
</footer> </footer>
<script src="cordova.js"></script> <script src="cordova.js"></script>
<script src="static/js/spin.min.js"></script>
<script src="static/js/codemirror.js"></script> <script src="static/js/codemirror.js"></script>
<script src="static/js/intval.core.js"></script> <script src="static/js/intval.core.js"></script>
<script src="static/js/intval.web.js"></script> <script src="static/js/intval.web.js"></script>

View File

@ -46,6 +46,12 @@ body{
.page.selected{ .page.selected{
display: block; display: block;
} }
.ble{
display: none;
}
.ble.active{
display: block;
}
h2{ h2{
font-size: 18px; font-size: 18px;
text-align: center; text-align: center;
@ -144,7 +150,8 @@ button{
padding: 5px 0; padding: 5px 0;
text-align: center; text-align: center;
} }
button:focus{ button:focus,
button.focus{
background-color: #20ce45; background-color: #20ce45;
border-color: #20ce45; border-color: #20ce45;
color: #212121; color: #212121;
@ -162,7 +169,7 @@ button:focus{
right: 10%; right: 10%;
} }
.label{ .label{
text-align: center; /*text-align: center;*/
color: #666; color: #666;
margin-top: 6px; margin-top: 6px;
margin-bottom: 9px; margin-bottom: 9px;
@ -244,3 +251,26 @@ footer > div.selected{
#compile{ #compile{
margin-top: 20px; margin-top: 20px;
} }
#seq{
margin-top: 40px;
}
#overlay{
position: fixed;
z-index: 2001;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: none;
}
#overlay.active{
display: block;
}
#spinner{
margin-top: 200px;
}

View File

@ -35,7 +35,6 @@ var app = {
// 'pause', 'resume', etc. // 'pause', 'resume', etc.
onDeviceReady: function() { onDeviceReady: function() {
mobile.init(); mobile.init();
getState();
}, },
onDeviceResume : function () { onDeviceResume : function () {
getState(); getState();

View File

@ -12,6 +12,7 @@ const STATE = {
delayScale : 'ms', delayScale : 'ms',
counter : 0 counter : 0
}; };
//functions //functions
window.frame = null; window.frame = null;
window.getState = null; window.getState = null;
@ -93,7 +94,7 @@ var setExposureScale = function () {
}; };
var setDelayScale = function () { var setDelayScale = function () {
const scale = document.getElementById('scale').value; const scale = document.getElementById('delayScale').value;
const elem = document.getElementById('delay'); const elem = document.getElementById('delay');
if (scale === 'ms') { if (scale === 'ms') {
elem.value = STATE.delay; elem.value = STATE.delay;
@ -138,6 +139,36 @@ var unsetPages = function () {
} }
}; };
var setState = function (res) {
let exposure;
let exposureScale;
let delayScale;
if (res.frame.dir !== true) {
document.getElementById('dir').checked = true;
STATE.dir = res.frame.dir;
setDirLabel(false);
}
document.getElementById('counter').value = res.counter;
STATE.counter = res.counter;
//Exposure
if (res.frame.exposure === 0) {
res.frame.exposure = BOLEX.expected;
}
STATE.exposure = res.frame.exposure;
exposure = shutter(STATE.exposure);
exposureScale = scaleAuto(STATE.exposure);
document.getElementById('str').value = exposure.str;
document.getElementById('scale').value = exposureScale;
setExposureScale();
STATE.delay = res.frame.delay;
delayScale = scaleAuto(STATE.delay);
document.getElementById('delayScale').value = delayScale;
setDelayScale();
};
var appPage = function () { var appPage = function () {
unsetPages(); unsetPages();
document.getElementById('app').classList.add('selected'); document.getElementById('app').classList.add('selected');
@ -154,6 +185,44 @@ var mscriptPage = function () {
document.getElementById('mscriptIcon').classList.add('selected'); document.getElementById('mscriptIcon').classList.add('selected');
editor.cm.refresh(); editor.cm.refresh();
}; };
var spinnerInit = function () {
const spinnerOpts = {
lines: 13 // The number of lines to draw
, length: 33 // The length of each line
, width: 11 // The line thickness
, radius: 30 // The radius of the inner circle
, scale: 0.5 // Scales overall size of the spinner
, corners: 1 // Corner roundness (0..1)
, color: '#fff' // #rgb or #rrggbb or array of colors
, opacity: 0.25 // Opacity of the lines
, rotate: 0 // The rotation offset
, direction: 1 // 1: clockwise, -1: counterclockwise
, speed: 1 // Rounds per second
, trail: 60 // Afterglow percentage
, fps: 20 // Frames per second when using setTimeout() as a fallback for CSS
, zIndex: 2e9 // The z-index (defaults to 2000000000)
, className: 'spinner' // The CSS class to assign to the spinner
, top: '50%' // Top position relative to parent
, left: '50%' // Left position relative to parent
, shadow: true // Whether to render a shadow
, hwaccel: true // Whether to use hardware acceleration
, position: 'relative' // Element positioning
};
const target = document.getElementById('spinner');
const spinner = new Spinner(spinnerOpts).spin(target);
};
var spinnerShow = function () {
const elem = document.getElementById('overlay');
if (!elem.classList.contains('active')) {
elem.classList.add('active');
}
};
var spinnerHide = function () {
const elem = document.getElementById('overlay');
if (elem.classList.contains('active')) {
elem.classList.remove('active');
}
}
var isNumeric = function (n) { var isNumeric = function (n) {
return !isNaN(parseFloat(n)) && isFinite(n); return !isNaN(parseFloat(n)) && isFinite(n);
}; };

View File

@ -7,27 +7,72 @@ mobile.ble = {
SERVICE_ID : '149582bd-d49d-4b5c-acd1-1ae503d09e7a', SERVICE_ID : '149582bd-d49d-4b5c-acd1-1ae503d09e7a',
CHAR_ID : '47bf69fb-f62f-4ef8-9be8-eb727a54fae4', //general data CHAR_ID : '47bf69fb-f62f-4ef8-9be8-eb727a54fae4', //general data
WIFI_ID : '3fe7d9cf-7bd2-4ff0-97c5-ebe87288c2cc', //wifi only WIFI_ID : '3fe7d9cf-7bd2-4ff0-97c5-ebe87288c2cc', //wifi only
DEVICES : [] devices : [],
device : {},
connected : false,
active : false
}; };
mobile.ble.scan = function () { mobile.ble.scan = function () {
ble.scan([], 5, mobile.ble.onDiscover, BLE.onError); spinnerShow();
ble.scan([], 5, mobile.ble.onDiscover, mobile.ble.onError);
mobile.ble.devices = [];
setTimeout(() => {
if (!mobile.ble.connected) {
ble.stopScan(() => {}, mobile.ble.onError);
spinnerHide();
alert('No INTVAL devices found.');
}
}, 5000)
}; };
mobile.ble.onDiscover = function (device) { mobile.ble.onDiscover = function (device) {
if (device && device.name && device.name === 'intval3') {
console.log('BLE - Discovered INTVAL');
console.dir(device); console.dir(device);
mobile.ble.connect(device.id); mobile.ble.devices.push(device);
if (!mobile.ble.connected) {
mobile.ble.connect(device);
}
} else {
//console.log(`BLE - Discovered Other ${device.id}`);
}
} }
mobile.ble.connect = function (deviceId) { mobile.ble.connect = function (device) {
ble.connect(deviceId, function (peripheral) { console.log(`BLE - Connecting to ${device.id}`)
mobile.ble.onConnect(peripheral, deviceId); ble.connect(device.id, (peripheral) => {
mobile.ble.onConnect(peripheral, device);
}, mobile.ble.onError); }, mobile.ble.onError);
}; };
mobile.ble.onConnect = function (peripheral, deviceId) { mobile.ble.onConnect = function (peripheral, device) {
spinnerHide();
ble.stopScan(() => {}, moble.ble.onError);
console.log(`BLE - Connected to ${device.id}`);
console.log(peripheral); console.log(peripheral);
console.log(deviceId); console.dir(device);
mobile.ble.device = device;
mobile.ble.connected = true;
getState();
};
mobile.ble.disconnect = function () {
let device
if (!mobile.ble.connected) {
console.warn('Not connected to any device')
return false
}
device = mobile.ble.device
console.log(`BLE - Disconnecting from ${device.id}`)
ble.disconnect(device.id, mobile.ble.onDisconnect, mobile.ble.onDisconnect);
};
mobile.ble.onDisconnect = function (res) {
console.log(`BLE - Disconnected from ${res}`);
mobile.ble.connected = false;
mobile.ble.device = {};
}; };
mobile.ble.onError = function (err) { mobile.ble.onError = function (err) {
@ -35,15 +80,154 @@ mobile.ble.onError = function (err) {
}; };
mobile.init = function () { mobile.init = function () {
frame = mobile.frame; const bleInputs = document.querySelectorAll('.ble')
getState = mobile.getState;
setDir = mobile.setDir; window.frame = mobile.frame;
setExposure = mobile.setExposure; window.getState = mobile.getState;
setCounter = mobile.setCounter; window.setDir = mobile.setDir;
window.setExposure = mobile.setExposure;
window.setDelay = mobile.setDelay;
window.setCounter = mobile.setCounter;
//show ble-specific fields in settings
for (let i of bleInputs) {
i.classList.add('active');
}
spinnerInit();
mobile.ble.scan();
}; };
mobile.frame = function () {}; mobile.getState = function () {
mobile.getState = function () {}; if (!mobile.ble.connected) {
mobile.setDir = function () {}; //
mobile.setExposure = function () {}; }
mobile.setCounter = function () {}; ble.read(mobile.ble.device.id,
mobile.ble.SERVICE_ID,
mobile.ble.CHAR_ID,
mobile.stateSuccess,
mobile.ble.onError);
};
mobile.stateSuccess = function (data) {
let str = bytesToString(data);
let res = JSON.parse(str);
setState(res)
};
mobile.frame = function () {
const opts = {
type : 'frame'
};
if (!mobile.ble.connected) {
return alert('Not connected to an INTVAL device.');
}
if (mobile.ble.active) {
return false;
}
ble.write(mobile.ble.device.id,
mobile.ble.SERVICE_ID,
mobile.ble.CHAR_ID,
stringToBytes(JSON.stringify(opts)), //check length?
mobile.frameSuccess,
mobile.ble.onError);
document.getElementById('frame').classList.add('focus');
mobile.ble.active = true;
};
mobile.frameSuccess = function () {
console.log('Frame finished, getting state.');
mobile.ble.active = false;
document.getElementById('frame').classList.remove('focus');
mobile.getState();
}
mobile.setDir = function () {
const opts = {
type : 'dir',
dir : !document.getElementById('dir').checked
};
ble.write(mobile.ble.device.id,
mobile.ble.SERVICE_ID,
mobile.ble.CHAR_ID,
stringToBytes(JSON.stringify(opts)), //check length?
mobile.dirSuccess,
mobile.ble.onError);
};
mobile.dirSuccess = function () {
console.log('Set direction');
mobile.getState();
};
mobile.setExposure = function () {
let exposure = document.getElementById('exposure').value;
let scaledExposure;
let opts = {
type : 'exposure'
};
if (exposure === '' || exposure === null) {
exposure = 0;
}
scaledExposure = scaleTime(exposure, STATE.scale);
opts.exposure = scaledExposure;
ble.write(mobile.ble.device.id,
mobile.ble.SERVICE_ID,
mobile.ble.CHAR_ID,
stringToBytes(JSON.stringify(opts)), //check length?
mobile.exposureSuccess,
mobile.ble.onError);
};
mobile.exposureSuccess = function () {
console.log('Set exposure');
mobile.getState();
};
mobile.setDelay = function () {
const delay = document.getElementById('delay').value;
const scaledDelay = scaleTime(delay, STATE.delayScale)
let opts = {
type : 'delay',
delay : scaledDelay
};
ble.write(mobile.ble.device.id,
mobile.ble.SERVICE_ID,
mobile.ble.CHAR_ID,
stringToBytes(JSON.stringify(opts)), //check length?
mobile.delaySuccess,
mobile.ble.onError);
}
mobile.delaySuccess = function () {
console.log('Set delay')
mobile.getState();
};
mobile.setCounter = function () {
const counter = document.getElementById('counter').value;
const change = prompt(`Change counter value?`, counter);
if (change === null || !isNumeric(change)) return false;
let opts = {
type : 'counter',
counter : change
};
ble.write(mobile.ble.device.id,
mobile.ble.SERVICE_ID,
mobile.ble.CHAR_ID,
stringToBytes(JSON.stringify(opts)), //check length?
mobile.counterSuccess,
mobile.ble.onError);
};
mobile.counterSuccess = function () {
console.log('Set counter');
mobile.getState();
};
function bytesToString (buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
};
function stringToBytes(string) {
var array = new Uint8Array(string.length);
for (var i = 0, l = string.length; i < l; i++) {
array[i] = string.charCodeAt(i);
}
return array.buffer;
};

View File

@ -55,36 +55,12 @@ web.getState = function () {
.then(res => { .then(res => {
return res.json(); return res.json();
}) })
.then(web.getStateSuccess) .then(setState)
.catch(err => { .catch(err => {
console.error('Error getting state'); console.error('Error getting state');
console.error(err); console.error(err);
}); });
}; };
web.getStateSuccess = function (res) {
let exposure;
let scale;
if (res.frame.dir !== true) {
document.getElementById('dir').checked = true;
STATE.dir = res.frame.dir;
setDirLabel(false);
}
document.getElementById('counter').value = res.counter;
STATE.counter = res.counter;
//Exposure
if (res.frame.exposure === 0) {
res.frame.exposure = BOLEX.expected;
}
STATE.exposure = res.frame.exposure;
exposure = shutter(STATE.exposure);
scale = scaleAuto(STATE.exposure);
document.getElementById('str').value = exposure.str;
document.getElementById('scale').value = scale;
setExposureScale();
document.getElementById('delay').value = res.frame.delay;
STATE.delay = res.frame.delay;
};
web.setExposure = function () { web.setExposure = function () {
let exposure = document.getElementById('exposure').value; let exposure = document.getElementById('exposure').value;
let scaledExposure; let scaledExposure;
@ -165,6 +141,7 @@ web.init = function () {
window.frame = web.frame; window.frame = web.frame;
window.getState = web.getState; window.getState = web.getState;
window.setDir = web.setDir; window.setDir = web.setDir;
window.setDelay = web.setDelay;
window.setExposure = web.setExposure; window.setExposure = web.setExposure;
window.setCounter = web.setCounter; window.setCounter = web.setCounter;
console.log('started web') console.log('started web')

2
app/www/static/js/spin.min.js vendored Normal file
View File

@ -0,0 +1,2 @@
// http://spin.js.org/#v2.3.2
!function(a,b){"object"==typeof module&&module.exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return m[e]||(k.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",k.cssRules.length),m[e]=1),e}function d(a,b){var c,d,e=a.style;if(b=b.charAt(0).toUpperCase()+b.slice(1),void 0!==e[b])return b;for(d=0;d<l.length;d++)if(c=l[d]+b,void 0!==e[c])return c}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}k.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.scale*d.width,left:d.scale*d.radius,top:-d.scale*d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.scale*(d.length+d.width),k=2*d.scale*j,l=-(d.width+d.length)*d.scale*2+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k,l=["webkit","Moz","ms","O"],m={},n={lines:12,length:7,width:5,radius:10,scale:1,corners:1,color:"#000",opacity:.25,rotate:0,direction:1,speed:1,trail:100,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",shadow:!1,hwaccel:!1,position:"absolute"};if(h.defaults={},f(h.prototype,{spin:function(b){this.stop();var c=this,d=c.opts,f=c.el=a(null,{className:d.className});if(e(f,{position:d.position,width:0,zIndex:d.zIndex,left:d.left,top:d.top}),b&&b.insertBefore(f,b.firstChild||null),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.scale*(f.length+f.width)+"px",height:f.scale*f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.scale*f.radius+"px,0)",borderRadius:(f.corners*f.scale*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.scale*f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}}),"undefined"!=typeof document){k=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}();var o=e(a("group"),{behavior:"url(#default#VML)"});!d(o,"transform")&&o.adj?i():j=d(o,"animation")}return h});

12
package-lock.json generated
View File

@ -95,7 +95,8 @@
"integrity": "sha1-IesK10O850eU45L0ph4TsHOT26o=", "integrity": "sha1-IesK10O850eU45L0ph4TsHOT26o=",
"requires": { "requires": {
"bplist-parser": "0.0.6", "bplist-parser": "0.0.6",
"debug": "2.6.8" "debug": "2.6.8",
"xpc-connection": "0.1.4"
} }
}, },
"bluebird": { "bluebird": {
@ -2212,6 +2213,15 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}, },
"xpc-connection": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/xpc-connection/-/xpc-connection-0.1.4.tgz",
"integrity": "sha1-3Nf6oq7Gt6bhjMXdrQQvejTHcVY=",
"optional": true,
"requires": {
"nan": "2.6.2"
}
},
"yallist": { "yallist": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",