App supports controlling intval with bluetooth
This commit is contained in:
parent
52194e0b41
commit
e5207a8474
|
@ -22,8 +22,10 @@
|
|||
<allow-intent href="itms:*" />
|
||||
<allow-intent href="itms-apps:*" />
|
||||
</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="android" spec="^6.3.0" />
|
||||
<plugin name="cordova-plugin-whitelist" spec="^1.3.3" />
|
||||
<plugin name="cordova-plugin-device" spec="^1.1.7" />
|
||||
<plugin name="cordova-plugin-dialogs" spec="^1.3.4" />
|
||||
|
|
|
@ -4,15 +4,10 @@
|
|||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"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": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-6.3.0.tgz",
|
||||
"integrity": "sha1-2lQYQz0lx1pZd7QoJEu+Q30BKNI=",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-6.4.0.tgz",
|
||||
"integrity": "sha1-VK6NpXKKjX5e/MYXLT3MoXvH/n0=",
|
||||
"requires": {
|
||||
"android-versions": "1.2.1",
|
||||
"cordova-common": "2.1.0",
|
||||
|
@ -27,6 +22,10 @@
|
|||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
},
|
||||
"android-versions": {
|
||||
"version": "1.2.1",
|
||||
"bundled": true
|
||||
},
|
||||
"ansi": {
|
||||
"version": "0.3.1",
|
||||
"bundled": true
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"author": "M McWilliams",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cordova-android": "^6.3.0",
|
||||
"cordova-android": "^6.4.0",
|
||||
"cordova-ios": "^4.5.4",
|
||||
"cordova-plugin-ble-central": "^1.1.4",
|
||||
"cordova-plugin-compat": "^1.2.0",
|
||||
|
@ -30,8 +30,8 @@
|
|||
}
|
||||
},
|
||||
"platforms": [
|
||||
"ios",
|
||||
"android"
|
||||
"android",
|
||||
"ios"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -4,12 +4,15 @@
|
|||
<title>INTVAL</title>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<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/monokai.css" />
|
||||
<link rel="stylesheet" href="static/css/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="overlay">
|
||||
<div id="spinner"></div>
|
||||
</div>
|
||||
<div id="app" class="page selected">
|
||||
<h2>INTVAL</h2>
|
||||
<div>
|
||||
|
@ -27,7 +30,7 @@
|
|||
</div>
|
||||
<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();">
|
||||
<option value="ms" selected>ms</option>
|
||||
<option value="sec">sec</option>
|
||||
|
@ -37,7 +40,7 @@
|
|||
</div>
|
||||
<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();">
|
||||
<option value="ms" selected>ms</option>
|
||||
<option value="sec">sec</option>
|
||||
|
@ -49,7 +52,7 @@
|
|||
<button id="seq">START SEQUENCE</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="frame" onclick="frame();">FRAME</button>
|
||||
<button id="frame" onclick="frame();">1 FRAME</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settings" class="page">
|
||||
|
@ -62,10 +65,13 @@
|
|||
<option value="33">2 Stop</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ble">
|
||||
<h2>BLUETOOTH</h2>
|
||||
<select id="bluetooth">
|
||||
<option>N/A</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ble">
|
||||
<h2>WIFI</h2>
|
||||
<div>
|
||||
<input type="text" id="ssid" placeholder="Wifi SSID" />
|
||||
|
@ -74,6 +80,7 @@
|
|||
<input type="password" id="password" placeholder="Wifi Password" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mscript" class="page">
|
||||
<h2>MSCRIPT</h2>
|
||||
<textarea id="mscript_editor"></textarea>
|
||||
|
@ -92,6 +99,7 @@
|
|||
</div>
|
||||
</footer>
|
||||
<script src="cordova.js"></script>
|
||||
<script src="static/js/spin.min.js"></script>
|
||||
<script src="static/js/codemirror.js"></script>
|
||||
<script src="static/js/intval.core.js"></script>
|
||||
<script src="static/js/intval.web.js"></script>
|
||||
|
|
|
@ -46,6 +46,12 @@ body{
|
|||
.page.selected{
|
||||
display: block;
|
||||
}
|
||||
.ble{
|
||||
display: none;
|
||||
}
|
||||
.ble.active{
|
||||
display: block;
|
||||
}
|
||||
h2{
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
|
@ -144,7 +150,8 @@ button{
|
|||
padding: 5px 0;
|
||||
text-align: center;
|
||||
}
|
||||
button:focus{
|
||||
button:focus,
|
||||
button.focus{
|
||||
background-color: #20ce45;
|
||||
border-color: #20ce45;
|
||||
color: #212121;
|
||||
|
@ -162,7 +169,7 @@ button:focus{
|
|||
right: 10%;
|
||||
}
|
||||
.label{
|
||||
text-align: center;
|
||||
/*text-align: center;*/
|
||||
color: #666;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 9px;
|
||||
|
@ -244,3 +251,26 @@ footer > div.selected{
|
|||
#compile{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ var app = {
|
|||
// 'pause', 'resume', etc.
|
||||
onDeviceReady: function() {
|
||||
mobile.init();
|
||||
getState();
|
||||
},
|
||||
onDeviceResume : function () {
|
||||
getState();
|
||||
|
|
|
@ -12,6 +12,7 @@ const STATE = {
|
|||
delayScale : 'ms',
|
||||
counter : 0
|
||||
};
|
||||
|
||||
//functions
|
||||
window.frame = null;
|
||||
window.getState = null;
|
||||
|
@ -93,7 +94,7 @@ var setExposureScale = function () {
|
|||
};
|
||||
|
||||
var setDelayScale = function () {
|
||||
const scale = document.getElementById('scale').value;
|
||||
const scale = document.getElementById('delayScale').value;
|
||||
const elem = document.getElementById('delay');
|
||||
if (scale === 'ms') {
|
||||
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 () {
|
||||
unsetPages();
|
||||
document.getElementById('app').classList.add('selected');
|
||||
|
@ -154,6 +185,44 @@ var mscriptPage = function () {
|
|||
document.getElementById('mscriptIcon').classList.add('selected');
|
||||
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) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
};
|
|
@ -7,27 +7,72 @@ mobile.ble = {
|
|||
SERVICE_ID : '149582bd-d49d-4b5c-acd1-1ae503d09e7a',
|
||||
CHAR_ID : '47bf69fb-f62f-4ef8-9be8-eb727a54fae4', //general data
|
||||
WIFI_ID : '3fe7d9cf-7bd2-4ff0-97c5-ebe87288c2cc', //wifi only
|
||||
DEVICES : []
|
||||
devices : [],
|
||||
device : {},
|
||||
connected : false,
|
||||
active : false
|
||||
};
|
||||
|
||||
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) {
|
||||
if (device && device.name && device.name === 'intval3') {
|
||||
console.log('BLE - Discovered INTVAL');
|
||||
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) {
|
||||
ble.connect(deviceId, function (peripheral) {
|
||||
mobile.ble.onConnect(peripheral, deviceId);
|
||||
mobile.ble.connect = function (device) {
|
||||
console.log(`BLE - Connecting to ${device.id}`)
|
||||
ble.connect(device.id, (peripheral) => {
|
||||
mobile.ble.onConnect(peripheral, device);
|
||||
}, 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(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) {
|
||||
|
@ -35,15 +80,154 @@ mobile.ble.onError = function (err) {
|
|||
};
|
||||
|
||||
mobile.init = function () {
|
||||
frame = mobile.frame;
|
||||
getState = mobile.getState;
|
||||
setDir = mobile.setDir;
|
||||
setExposure = mobile.setExposure;
|
||||
setCounter = mobile.setCounter;
|
||||
const bleInputs = document.querySelectorAll('.ble')
|
||||
|
||||
window.frame = mobile.frame;
|
||||
window.getState = mobile.getState;
|
||||
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.setDir = function () {};
|
||||
mobile.setExposure = function () {};
|
||||
mobile.setCounter = function () {};
|
||||
mobile.getState = function () {
|
||||
if (!mobile.ble.connected) {
|
||||
//
|
||||
}
|
||||
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;
|
||||
};
|
|
@ -55,36 +55,12 @@ web.getState = function () {
|
|||
.then(res => {
|
||||
return res.json();
|
||||
})
|
||||
.then(web.getStateSuccess)
|
||||
.then(setState)
|
||||
.catch(err => {
|
||||
console.error('Error getting state');
|
||||
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 () {
|
||||
let exposure = document.getElementById('exposure').value;
|
||||
let scaledExposure;
|
||||
|
@ -165,6 +141,7 @@ web.init = function () {
|
|||
window.frame = web.frame;
|
||||
window.getState = web.getState;
|
||||
window.setDir = web.setDir;
|
||||
window.setDelay = web.setDelay;
|
||||
window.setExposure = web.setExposure;
|
||||
window.setCounter = web.setCounter;
|
||||
console.log('started web')
|
||||
|
|
|
@ -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});
|
|
@ -95,7 +95,8 @@
|
|||
"integrity": "sha1-IesK10O850eU45L0ph4TsHOT26o=",
|
||||
"requires": {
|
||||
"bplist-parser": "0.0.6",
|
||||
"debug": "2.6.8"
|
||||
"debug": "2.6.8",
|
||||
"xpc-connection": "0.1.4"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
|
@ -2212,6 +2213,15 @@
|
|||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"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": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
|
|
Loading…
Reference in New Issue