some changes
This commit is contained in:
parent
7ecf2ec9ef
commit
e6e767bf26
11
.gitignore
vendored
11
.gitignore
vendored
@ -178,9 +178,9 @@ xcuserdata
|
||||
*.xcuserstate
|
||||
|
||||
dist
|
||||
www/libs
|
||||
/www/
|
||||
/app/libs/
|
||||
www
|
||||
# app/libs
|
||||
|
||||
### Android template
|
||||
# Built application files
|
||||
*.apk
|
||||
@ -228,3 +228,8 @@ captures/
|
||||
.dropbox.attr
|
||||
.dropbox.cache
|
||||
|
||||
/app/libs/mui/
|
||||
/app/libs/bluebird/
|
||||
/app/libs/ejs/
|
||||
/app/libs/jquery/
|
||||
/platforms/android/assets
|
||||
|
@ -95,6 +95,10 @@
|
||||
<script type="text/javascript" src="libs/ejs/ejs.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="libs/bluebird/js/browser/bluebird.js"></script>
|
||||
|
||||
<script type="text/javascript" src="libs/jsfft/complex_array.js"></script>
|
||||
<script type="text/javascript" src="libs/jsfft/fft.js"></script>
|
||||
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- build:standards -->
|
||||
|
@ -109,7 +109,7 @@ CC2650_ACCEL = function(p) {
|
||||
this.data.mag.y = this.storeData(calcData.mag.y, this.data.mag.y);
|
||||
this.data.mag.z = this.storeData(calcData.mag.z, this.data.mag.z);
|
||||
|
||||
// console.log(JSON.stringify(this.data));
|
||||
// Console.log(JSON.stringify(this.data));
|
||||
// Console.log(this.state);
|
||||
};
|
||||
|
||||
@ -156,6 +156,8 @@ CC2650_ACCEL = function(p) {
|
||||
|
||||
this.advancedGraph = function(mode, data, subID) {
|
||||
|
||||
var xstep;
|
||||
var scalePos;
|
||||
var lm;
|
||||
var ceiling;
|
||||
var elm;
|
||||
@ -169,6 +171,10 @@ CC2650_ACCEL = function(p) {
|
||||
var lineID;
|
||||
var max;
|
||||
|
||||
var reducer = function(p, v) {
|
||||
return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v));
|
||||
};
|
||||
|
||||
|
||||
var parts = ['x', 'y', 'z'];
|
||||
|
||||
@ -186,10 +192,11 @@ CC2650_ACCEL = function(p) {
|
||||
|
||||
for (var lineMode = 0; lineMode < parts.length; lineMode++) {
|
||||
lm = parts[lineMode];
|
||||
ceiling = _data[lm].reduce(function(p, v) {
|
||||
/*Ceiling = _data[lm].reduce(function(p, v) {
|
||||
return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v));
|
||||
});
|
||||
});*/
|
||||
|
||||
ceiling = _data[lm].reduce(reducer);
|
||||
|
||||
if (ceiling > 500) {
|
||||
max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 50) * 50) : max;
|
||||
@ -203,9 +210,9 @@ CC2650_ACCEL = function(p) {
|
||||
floor = ceiling * -1;
|
||||
ceilingLimit = ceiling;
|
||||
|
||||
var scalePos = (124 / 2) / ceiling;
|
||||
var scaleNeg = (124 / 2) / floor;
|
||||
var xstep = (680 - 46) / 100;
|
||||
scalePos = (124 / 2) / ceiling;
|
||||
|
||||
xstep = (680 - 46) / 100;
|
||||
|
||||
//Var xstep = 2.34;
|
||||
|
||||
@ -314,6 +321,10 @@ CC2650_ACCEL = function(p) {
|
||||
|
||||
this.insertFrame = function(mode) {
|
||||
|
||||
var _graph;
|
||||
var row;
|
||||
var button;
|
||||
var elm;
|
||||
var frame;
|
||||
var title;
|
||||
var modeID = mode + 'ID';
|
||||
@ -322,7 +333,6 @@ CC2650_ACCEL = function(p) {
|
||||
var titles = {
|
||||
gyro: 'Gyroscope', accel: 'Accelerometer', mag: 'Magnetometer'
|
||||
};
|
||||
var modes = ['gyro', 'accel', 'mag'];
|
||||
|
||||
console.log('FrameID: ', this.frames[modeID]);
|
||||
|
||||
@ -333,12 +343,17 @@ CC2650_ACCEL = function(p) {
|
||||
});
|
||||
|
||||
if (mode === 'mag') {
|
||||
var elm = $('<div />', {class: 'mui-row'});
|
||||
var button = $('<button />',{class: 'mui-btn mui-btn--raised', id: modeID + '-cal', text: 'Calibrate', click: this.startCalibrate.bind(this)});
|
||||
elm = $('<div />', {class: 'mui-row'});
|
||||
button = $('<button />', {
|
||||
class: 'mui-btn mui-btn--raised',
|
||||
id: modeID + '-cal',
|
||||
text: 'Calibrate',
|
||||
click: this.startCalibrate.bind(this)
|
||||
});
|
||||
|
||||
elm.append($('<div />', { class: 'mui-col-xs-8 mui--text-title mui-ellipsis-2', text: title}));
|
||||
|
||||
// elm.append($('<div />', {class: 'mui-col-xs-4 mui--text-right'}).append(button));
|
||||
// Elm.append($('<div />', {class: 'mui-col-xs-4 mui--text-right'}).append(button));
|
||||
|
||||
frame.append(elm);
|
||||
|
||||
@ -353,7 +368,7 @@ CC2650_ACCEL = function(p) {
|
||||
|
||||
// Call the parent displayForm first...
|
||||
|
||||
var row = $('<div />', {class: 'mui-row'});
|
||||
row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'X'
|
||||
@ -393,7 +408,7 @@ CC2650_ACCEL = function(p) {
|
||||
|
||||
row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
var _graph = this.generateBlankGraph(mode);
|
||||
_graph = this.generateBlankGraph(mode);
|
||||
row.append($('<div>', {class: 'mui-col-sm-12'}).append(_graph));
|
||||
|
||||
this.$id[modeID].append(row);
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* global MANUFACTUREDECODER */
|
||||
/* global */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
/**
|
||||
|
116
app/libs/jsfft/complex_array.js
Normal file
116
app/libs/jsfft/complex_array.js
Normal file
@ -0,0 +1,116 @@
|
||||
'use strict';
|
||||
|
||||
!function(exports, undefined) {
|
||||
|
||||
var
|
||||
// If the typed array is unspecified, use this.
|
||||
DefaultArrayType = Float32Array,
|
||||
// Simple math functions we need.
|
||||
sqrt = Math.sqrt,
|
||||
sqr = function(number) {return Math.pow(number, 2)},
|
||||
// Internal convenience copies of the exported functions
|
||||
isComplexArray,
|
||||
ComplexArray
|
||||
|
||||
exports.isComplexArray = isComplexArray = function(obj) {
|
||||
return obj !== undefined &&
|
||||
obj.hasOwnProperty !== undefined &&
|
||||
obj.hasOwnProperty('real') &&
|
||||
obj.hasOwnProperty('imag')
|
||||
}
|
||||
|
||||
exports.ComplexArray = ComplexArray = function(other, opt_array_type){
|
||||
if (isComplexArray(other)) {
|
||||
// Copy constuctor.
|
||||
this.ArrayType = other.ArrayType
|
||||
this.real = new this.ArrayType(other.real)
|
||||
this.imag = new this.ArrayType(other.imag)
|
||||
} else {
|
||||
this.ArrayType = opt_array_type || DefaultArrayType
|
||||
// other can be either an array or a number.
|
||||
this.real = new this.ArrayType(other)
|
||||
this.imag = new this.ArrayType(this.real.length)
|
||||
}
|
||||
|
||||
this.length = this.real.length
|
||||
}
|
||||
|
||||
ComplexArray.prototype.toString = function() {
|
||||
var components = []
|
||||
|
||||
this.forEach(function(c_value, i) {
|
||||
components.push(
|
||||
'(' +
|
||||
c_value.real.toFixed(2) + ',' +
|
||||
c_value.imag.toFixed(2) +
|
||||
')'
|
||||
)
|
||||
})
|
||||
|
||||
return '[' + components.join(',') + ']'
|
||||
}
|
||||
|
||||
// In-place mapper.
|
||||
ComplexArray.prototype.map = function(mapper) {
|
||||
var
|
||||
i,
|
||||
n = this.length,
|
||||
// For GC efficiency, pass a single c_value object to the mapper.
|
||||
c_value = {}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
c_value.real = this.real[i]
|
||||
c_value.imag = this.imag[i]
|
||||
mapper(c_value, i, n)
|
||||
this.real[i] = c_value.real
|
||||
this.imag[i] = c_value.imag
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
ComplexArray.prototype.forEach = function(iterator) {
|
||||
var
|
||||
i,
|
||||
n = this.length,
|
||||
// For consistency with .map.
|
||||
c_value = {}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
c_value.real = this.real[i]
|
||||
c_value.imag = this.imag[i]
|
||||
iterator(c_value, i, n)
|
||||
}
|
||||
}
|
||||
|
||||
ComplexArray.prototype.conjugate = function() {
|
||||
return (new ComplexArray(this)).map(function(value) {
|
||||
value.imag *= -1
|
||||
})
|
||||
}
|
||||
|
||||
// Helper so we can make ArrayType objects returned have similar interfaces
|
||||
// to ComplexArrays.
|
||||
function iterable(obj) {
|
||||
if (!obj.forEach)
|
||||
obj.forEach = function(iterator) {
|
||||
var i, n = this.length
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
iterator(this[i], i, n)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
ComplexArray.prototype.magnitude = function() {
|
||||
var mags = new this.ArrayType(this.length)
|
||||
|
||||
this.forEach(function(value, i) {
|
||||
mags[i] = sqrt(sqr(value.real) + sqr(value.imag))
|
||||
})
|
||||
|
||||
// ArrayType will not necessarily be iterable: make it so.
|
||||
return iterable(mags)
|
||||
}
|
||||
}(typeof exports === 'undefined' && (this.complex_array = {}) || exports)
|
225
app/libs/jsfft/fft.js
Normal file
225
app/libs/jsfft/fft.js
Normal file
@ -0,0 +1,225 @@
|
||||
'use strict';
|
||||
|
||||
!function(exports, complex_array) {
|
||||
|
||||
var
|
||||
ComplexArray = complex_array.ComplexArray,
|
||||
// Math constants and functions we need.
|
||||
PI = Math.PI,
|
||||
SQRT1_2 = Math.SQRT1_2,
|
||||
sqrt = Math.sqrt,
|
||||
cos = Math.cos,
|
||||
sin = Math.sin
|
||||
|
||||
ComplexArray.prototype.FFT = function() {
|
||||
return FFT(this, false)
|
||||
}
|
||||
|
||||
exports.FFT = function(input) {
|
||||
return ensureComplexArray(input).FFT()
|
||||
}
|
||||
|
||||
ComplexArray.prototype.InvFFT = function() {
|
||||
return FFT(this, true)
|
||||
}
|
||||
|
||||
exports.InvFFT = function(input) {
|
||||
return ensureComplexArray(input).InvFFT()
|
||||
}
|
||||
|
||||
// Applies a frequency-space filter to input, and returns the real-space
|
||||
// filtered input.
|
||||
// filterer accepts freq, i, n and modifies freq.real and freq.imag.
|
||||
ComplexArray.prototype.frequencyMap = function(filterer) {
|
||||
return this.FFT().map(filterer).InvFFT()
|
||||
}
|
||||
|
||||
exports.frequencyMap = function(input, filterer) {
|
||||
return ensureComplexArray(input).frequencyMap(filterer)
|
||||
}
|
||||
|
||||
function ensureComplexArray(input) {
|
||||
return complex_array.isComplexArray(input) && input ||
|
||||
new ComplexArray(input)
|
||||
}
|
||||
|
||||
function FFT(input, inverse) {
|
||||
var n = input.length
|
||||
|
||||
if (n & (n - 1)) {
|
||||
return FFT_Recursive(input, inverse)
|
||||
} else {
|
||||
return FFT_2_Iterative(input, inverse)
|
||||
}
|
||||
}
|
||||
|
||||
function FFT_Recursive(input, inverse) {
|
||||
var
|
||||
n = input.length,
|
||||
// Counters.
|
||||
i, j,
|
||||
output,
|
||||
// Complex multiplier and its delta.
|
||||
f_r, f_i, del_f_r, del_f_i,
|
||||
// Lowest divisor and remainder.
|
||||
p, m,
|
||||
normalisation,
|
||||
recursive_result,
|
||||
_swap, _real, _imag
|
||||
|
||||
if (n === 1) {
|
||||
return input
|
||||
}
|
||||
|
||||
output = new ComplexArray(n, input.ArrayType)
|
||||
|
||||
// Use the lowest odd factor, so we are able to use FFT_2_Iterative in the
|
||||
// recursive transforms optimally.
|
||||
p = LowestOddFactor(n)
|
||||
m = n / p
|
||||
normalisation = 1 / sqrt(p)
|
||||
recursive_result = new ComplexArray(m, input.ArrayType)
|
||||
|
||||
// Loops go like O(n Σ p_i), where p_i are the prime factors of n.
|
||||
// for a power of a prime, p, this reduces to O(n p log_p n)
|
||||
for(j = 0; j < p; j++) {
|
||||
for(i = 0; i < m; i++) {
|
||||
recursive_result.real[i] = input.real[i * p + j]
|
||||
recursive_result.imag[i] = input.imag[i * p + j]
|
||||
}
|
||||
// Don't go deeper unless necessary to save allocs.
|
||||
if (m > 1) {
|
||||
recursive_result = FFT(recursive_result, inverse)
|
||||
}
|
||||
|
||||
del_f_r = cos(2*PI*j/n)
|
||||
del_f_i = (inverse ? -1 : 1) * sin(2*PI*j/n)
|
||||
f_r = 1
|
||||
f_i = 0
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
_real = recursive_result.real[i % m]
|
||||
_imag = recursive_result.imag[i % m]
|
||||
|
||||
output.real[i] += f_r * _real - f_i * _imag
|
||||
output.imag[i] += f_r * _imag + f_i * _real
|
||||
|
||||
_swap = f_r * del_f_r - f_i * del_f_i
|
||||
f_i = f_r * del_f_i + f_i * del_f_r
|
||||
f_r = _swap
|
||||
}
|
||||
}
|
||||
|
||||
// Copy back to input to match FFT_2_Iterative in-placeness
|
||||
// TODO: faster way of making this in-place?
|
||||
for(i = 0; i < n; i++) {
|
||||
input.real[i] = normalisation * output.real[i]
|
||||
input.imag[i] = normalisation * output.imag[i]
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
function FFT_2_Iterative(input, inverse) {
|
||||
var
|
||||
n = input.length,
|
||||
// Counters.
|
||||
i, j,
|
||||
output, output_r, output_i,
|
||||
// Complex multiplier and its delta.
|
||||
f_r, f_i, del_f_r, del_f_i, temp,
|
||||
// Temporary loop variables.
|
||||
l_index, r_index,
|
||||
left_r, left_i, right_r, right_i,
|
||||
// width of each sub-array for which we're iteratively calculating FFT.
|
||||
width
|
||||
|
||||
output = BitReverseComplexArray(input)
|
||||
output_r = output.real
|
||||
output_i = output.imag
|
||||
// Loops go like O(n log n):
|
||||
// width ~ log n; i,j ~ n
|
||||
width = 1
|
||||
while (width < n) {
|
||||
del_f_r = cos(PI/width)
|
||||
del_f_i = (inverse ? -1 : 1) * sin(PI/width)
|
||||
for (i = 0; i < n/(2*width); i++) {
|
||||
f_r = 1
|
||||
f_i = 0
|
||||
for (j = 0; j < width; j++) {
|
||||
l_index = 2*i*width + j
|
||||
r_index = l_index + width
|
||||
|
||||
left_r = output_r[l_index]
|
||||
left_i = output_i[l_index]
|
||||
right_r = f_r * output_r[r_index] - f_i * output_i[r_index]
|
||||
right_i = f_i * output_r[r_index] + f_r * output_i[r_index]
|
||||
|
||||
output_r[l_index] = SQRT1_2 * (left_r + right_r)
|
||||
output_i[l_index] = SQRT1_2 * (left_i + right_i)
|
||||
output_r[r_index] = SQRT1_2 * (left_r - right_r)
|
||||
output_i[r_index] = SQRT1_2 * (left_i - right_i)
|
||||
temp = f_r * del_f_r - f_i * del_f_i
|
||||
f_i = f_r * del_f_i + f_i * del_f_r
|
||||
f_r = temp
|
||||
}
|
||||
}
|
||||
width <<= 1
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
function BitReverseIndex(index, n) {
|
||||
var bitreversed_index = 0
|
||||
|
||||
while (n > 1) {
|
||||
bitreversed_index <<= 1
|
||||
bitreversed_index += index & 1
|
||||
index >>= 1
|
||||
n >>= 1
|
||||
}
|
||||
return bitreversed_index
|
||||
}
|
||||
|
||||
function BitReverseComplexArray(array) {
|
||||
var n = array.length,
|
||||
flips = {},
|
||||
swap,
|
||||
i
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
var r_i = BitReverseIndex(i, n)
|
||||
|
||||
if (flips.hasOwnProperty(i) || flips.hasOwnProperty(r_i)) continue
|
||||
|
||||
swap = array.real[r_i]
|
||||
array.real[r_i] = array.real[i]
|
||||
array.real[i] = swap
|
||||
|
||||
swap = array.imag[r_i]
|
||||
array.imag[r_i] = array.imag[i]
|
||||
array.imag[i] = swap
|
||||
|
||||
flips[i] = flips[r_i] = true
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
|
||||
function LowestOddFactor(n) {
|
||||
var factor = 3,
|
||||
sqrt_n = sqrt(n)
|
||||
|
||||
while(factor <= sqrt_n) {
|
||||
if (n % factor === 0) return factor
|
||||
factor = factor + 2
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
}(
|
||||
typeof exports === 'undefined' && (this.fft = {}) || exports,
|
||||
typeof require === 'undefined' && (this.complex_array) ||
|
||||
require('./complex_array')
|
||||
)
|
87
app/libs/jsfft/fft_image.js
Normal file
87
app/libs/jsfft/fft_image.js
Normal file
@ -0,0 +1,87 @@
|
||||
'use strict';
|
||||
|
||||
!function(complex_array, fft) {
|
||||
|
||||
var ComplexArray = complex_array.ComplexArray
|
||||
|
||||
fft.FFTImageDataRGBA = function(data, nx, ny) {
|
||||
var rgb = splitRGB(data)
|
||||
|
||||
return mergeRGB(
|
||||
FFT2D(new ComplexArray(rgb[0], Float32Array), nx, ny),
|
||||
FFT2D(new ComplexArray(rgb[1], Float32Array), nx, ny),
|
||||
FFT2D(new ComplexArray(rgb[2], Float32Array), nx, ny)
|
||||
)
|
||||
}
|
||||
|
||||
function splitRGB(data) {
|
||||
var n = data.length / 4,
|
||||
r = new Uint8ClampedArray(n),
|
||||
g = new Uint8ClampedArray(n),
|
||||
b = new Uint8ClampedArray(n),
|
||||
i
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
r[i] = data[4 * i ]
|
||||
g[i] = data[4 * i + 1]
|
||||
b[i] = data[4 * i + 2]
|
||||
}
|
||||
|
||||
return [r, g, b]
|
||||
}
|
||||
|
||||
function mergeRGB(r, g, b) {
|
||||
var n = r.length,
|
||||
output = new ComplexArray(n * 4),
|
||||
i
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
output.real[4 * i ] = r.real[i]
|
||||
output.imag[4 * i ] = r.imag[i]
|
||||
output.real[4 * i + 1] = g.real[i]
|
||||
output.imag[4 * i + 1] = g.imag[i]
|
||||
output.real[4 * i + 2] = b.real[i]
|
||||
output.imag[4 * i + 2] = b.imag[i]
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
function FFT2D(input, nx, ny, inverse) {
|
||||
var i, j,
|
||||
transform = inverse ? 'InvFFT' : 'FFT',
|
||||
output = new ComplexArray(input.length, input.ArrayType),
|
||||
row = new ComplexArray(nx, input.ArrayType),
|
||||
col = new ComplexArray(ny, input.ArrayType)
|
||||
|
||||
for(j = 0; j < ny; j++) {
|
||||
row.map(function(v, i) {
|
||||
v.real = input.real[i + j * nx]
|
||||
v.imag = input.imag[i + j * nx]
|
||||
})
|
||||
row[transform]().forEach(function(v, i) {
|
||||
output.real[i + j * nx] = v.real
|
||||
output.imag[i + j * nx] = v.imag
|
||||
})
|
||||
}
|
||||
|
||||
for(i = 0; i < nx; i++) {
|
||||
col.map(function(v, j) {
|
||||
v.real = output.real[i + j * nx]
|
||||
v.imag = output.imag[i + j * nx]
|
||||
})
|
||||
col[transform]().forEach(function(v, j) {
|
||||
output.real[i + j * nx] = v.real
|
||||
output.imag[i + j * nx] = v.imag
|
||||
})
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
}(
|
||||
typeof require === 'undefined' && (this.complex_array) ||
|
||||
require('./complex_array'),
|
||||
typeof require === 'undefined' && (this.fft) ||
|
||||
require('./fft')
|
||||
)
|
16
gulpfile.js
16
gulpfile.js
@ -16,6 +16,7 @@ var stripDebug = require('gulp-strip-debug');
|
||||
var scss = require('gulp-scss');
|
||||
var sass = require('gulp-sass');
|
||||
var googleWebFonts = require('gulp-google-webfonts');
|
||||
var sloc = require('gulp-sloc');
|
||||
|
||||
|
||||
var filePath = {
|
||||
@ -24,6 +25,12 @@ var filePath = {
|
||||
|
||||
var fontOptions = { };
|
||||
|
||||
gulp.task('sloc', function(){
|
||||
gulp.src(['app/js/**/*.js'])
|
||||
.pipe(sloc());
|
||||
});
|
||||
|
||||
|
||||
gulp.task('appJS', function() {
|
||||
return gulp.src(['app/js/mandecoder.js','app/js/index.js'])
|
||||
.pipe(stripDebug())
|
||||
@ -65,7 +72,8 @@ gulp.task('devices', function() {
|
||||
|
||||
gulp.task('vendor', function() {
|
||||
return gulp.src(['app/libs/jquery/dist/jquery.min.js',
|
||||
'app/libs/mui/packages/cdn/js/mui.min.js'])
|
||||
'app/libs/mui/packages/cdn/js/mui.min.js',
|
||||
'app/libs/ejs/ejs_production.js'])
|
||||
.pipe(concat('vendor.js'))
|
||||
.pipe(uglify({mangle: false}))
|
||||
.pipe(gulp.dest('www/libs'));
|
||||
@ -123,7 +131,7 @@ gulp.task('index', function() {
|
||||
|
||||
gulp.task('partials', function() {
|
||||
|
||||
// Gulp.src(['app/partials/**/*']).pipe(gulp.dest('dist/partials'));
|
||||
gulp.src(['app/partials/**/*']).pipe(gulp.dest('www/partials'));
|
||||
// gulp.src(['app/libs/ejs_production.js']).pipe(gulp.dest('dist/libs'));
|
||||
// gulp.src(['app/libs/microevent.js']).pipe(gulp.dest('dist/libs'));
|
||||
//gulp.src(['app/fav/**/*']).pipe(size({title: 'Partials'})).pipe(gulp.dest('dist/fav'));
|
||||
@ -146,11 +154,11 @@ gulp.task('clean', function() {
|
||||
|
||||
gulp.task('normal', ['clean'], function() {
|
||||
'use strict';
|
||||
gulp.start('copy','watch');
|
||||
gulp.start('copy', 'sloc','watch');
|
||||
});
|
||||
|
||||
gulp.task('default', ['clean'], function() {
|
||||
gulp.start('buildJS','mui','styles','fonts', 'index', 'partials');
|
||||
gulp.start('buildJS','mui','styles','fonts', 'index', 'partials', 'sloc');
|
||||
});
|
||||
|
||||
gulp.task('watch',function() {
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,213 +1,2 @@
|
||||
|
||||
#lightR, #projR { color: red !important; }
|
||||
|
||||
#lightG, #projG { color: green !important; }
|
||||
|
||||
#lightB, #projB { color: blue !important; }
|
||||
|
||||
#lightW, #projW { background-color: #aabbcc; }
|
||||
|
||||
.lightBG, .heatingBG, .projectorBG {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
.h105 {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.mdHeading {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.item_content {
|
||||
height: 100px;
|
||||
/* border: 1px solid grey;*/
|
||||
min-height: 100px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item_content a.title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.item_content div.body, .item_content div.site, .item_content div.tags {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #313131;
|
||||
}
|
||||
|
||||
.time, .date, .temp {
|
||||
font-family: 'Ubuntu Condensed', sans-serif;
|
||||
font-size: 80px;
|
||||
color: #bad649;
|
||||
}
|
||||
|
||||
.time span.hour:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 35px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.temp::after {
|
||||
content: "°c";
|
||||
}
|
||||
|
||||
.item_content div.tags {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.noConnection {
|
||||
color: rgb(244, 150, 26);
|
||||
}
|
||||
|
||||
#caltext {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Smartphones (portrait and landscape) ----------- */
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
|
||||
/* Styles */
|
||||
|
||||
}
|
||||
|
||||
/* Smartphones (landscape) ----------- */
|
||||
@media only screen and (min-width: 321px) {
|
||||
/* Styles */
|
||||
}
|
||||
|
||||
/* Smartphones (portrait) ----------- */
|
||||
@media only screen and (max-width: 320px) {
|
||||
/* Styles */
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin: 25px auto 0;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner > div {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-color: rgb(244, 150, 26);
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
}
|
||||
|
||||
.spinner .bounce1 {
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.spinner .bounce2 {
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
}
|
||||
40% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.md-display {
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s, visibility 0.3s;
|
||||
|
||||
}
|
||||
|
||||
.lostConnection {
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.3s, visibility 0.3s;
|
||||
}
|
||||
|
||||
|
||||
.mui-ellipsis-2 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-wrap: break-word;
|
||||
white-space: normal!important;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.pulser {
|
||||
display: block;
|
||||
margin-top:10%;
|
||||
border-radius: 100px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 10px solid #C5F4EB;
|
||||
-webkit-animation: pulse 0.75s ease-in infinite;
|
||||
-moz-animation: pulse 0.75s ease-in infinite;
|
||||
animation: pulse 0.75s ease-in infinite;
|
||||
}
|
||||
@-webkit-keyframes pulse {
|
||||
0% { -webkit-transform: scale(0); }
|
||||
85% { opacity: 1; }
|
||||
100% { -webkit-transform: scale(1); -webkit-filter: blur(5px); opacity: 0; }
|
||||
}
|
||||
@-moz-keyframes pulse {
|
||||
0% { -moz-transform: scale(0); }
|
||||
85% { opacity: 1; }
|
||||
100% { -moz-transform: scale(1); -moz-filter: blur(5px); opacity: 0; }
|
||||
}
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(0); }
|
||||
85% { opacity: 1; }
|
||||
100% { transform: scale(1); filter: blur(5px); opacity: 0; }
|
||||
}
|
||||
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
right:0;
|
||||
transition: left .2s;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.mui-tabs__bar > li.tabOnWhite > a
|
||||
|
||||
{
|
||||
color:#78909C;
|
||||
}
|
||||
|
||||
.mui-tabs__bar > li.mui--is-active.tabOnWhite > a
|
||||
{
|
||||
color:#2196F3;
|
||||
}
|
||||
|
||||
|
||||
/* svg classes */
|
||||
|
||||
svg text {
|
||||
font-family:'Ubuntu Condensed',sans-serif;
|
||||
font-size:12;
|
||||
fill: #bad649;
|
||||
text-align:right;
|
||||
}
|
||||
#lightR,#projR{color:red!important}#lightG,#projG{color:green!important}#lightB,#projB{color:blue!important}#lightW,#projW{background-color:#abc}.heatingBG,.lightBG,.projectorBG{float:right}.h105{height:100px}.item_content,.mdHeading{overflow:hidden}.item_content{height:100px;min-height:100px}.item_content a.title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#fff}.item_content div.body,.item_content div.site,.item_content div.tags{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#313131}.date,.temp,.time{font-family:Ubuntu Condensed,sans-serif;font-size:80px;color:#bad649}.time span.hour:after{content:":"}.date{font-size:35px;line-height:1}.temp:after{content:"°c"}.item_content div.tags{color:blue}.noConnection{color:#f4961a}#caltext{color:#fff}.spinner{margin:25px auto 0;width:70px;text-align:center}.spinner>div{width:18px;height:18px;background-color:#f4961a;border-radius:100%;display:inline-block;animation:a 1.4s infinite ease-in-out both}.spinner .bounce1{animation-delay:-.32s}.spinner .bounce2{animation-delay:-.16s}@keyframes a{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.md-display{opacity:1}.lostConnection,.md-display{transition:opacity .3s,visibility .3s}.lostConnection{opacity:.5}.mui-ellipsis-2{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;word-wrap:break-word;white-space:normal!important;-webkit-line-clamp:1;-webkit-box-orient:vertical}.pulser{display:block;margin-top:10%;border-radius:100px;width:30px;height:30px;border:10px solid #c5f4eb;animation:b .75s ease-in infinite}@keyframes b{0%{transform:scale(0)}85%{opacity:1}to{transform:scale(1);-webkit-filter:blur(5px);filter:blur(5px);opacity:0}}header{position:fixed;top:0;z-index:1;right:0;transition:left .2s;width:100%}.mui-tabs__bar>li.tabOnWhite>a{color:#78909c}.mui-tabs__bar>li.mui--is-active.tabOnWhite>a{color:#2196f3}svg text{font-family:Ubuntu Condensed,sans-serif;font-size:12;fill:#bad649;text-align:right}
|
||||
.progress{position:relative;height:4px;display:block;width:100%;background-color:#acece6;border-radius:2px;background-clip:padding-box;overflow:hidden}.progress .determinate{position:absolute;background-color:inherit;top:0;bottom:0;transition:width .3s linear}.progress .determinate,.progress .indeterminate{background-color:#26a69a}.progress .indeterminate:before{animation:a 2.1s cubic-bezier(.65,.815,.735,.395) infinite}.progress .indeterminate:after,.progress .indeterminate:before{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left,right}.progress .indeterminate:after{animation:b 2.1s cubic-bezier(.165,.84,.44,1) infinite;animation-delay:1.15s}@keyframes a{0%{left:-35%;right:100%}60%{left:100%;right:-90%}to{left:100%;right:-90%}}@keyframes b{0%{left:-200%;right:100%}60%{left:107%;right:-8%}to{left:107%;right:-8%}}
|
@ -1,20 +0,0 @@
|
||||
@import "app/libs/mui/src/sass/mui/colors";
|
||||
|
||||
|
||||
$mui-body-bg-color: /*#003F5a*/ mui-color('grey', '800');
|
||||
$mui-base-font-color: rgba(#FFF, 0.87) !default;
|
||||
$mui-base-font-family: Ubuntu, "Helvetica Neue", Helvetica, Arial, Verdana, Tahoma !default;
|
||||
|
||||
$mui-panel-bg-color : /*#004c6d*/ mui-color('grey', '900');
|
||||
|
||||
//$mui-accent-color: #bad649;
|
||||
$mui-accent-color: #00aeef;
|
||||
$mui-btn-accent-font-color: #004c6d;
|
||||
//$mui-accent-color-dark: mui-color('green', 'A100');
|
||||
$mui-accent-color-dark: #004c6d;
|
||||
$mui-accent-color-light: mui-color('green', 'A400');
|
||||
$mui-tab-font-color: rgba(255, 255, 255, 0.87);
|
||||
$mui-appbar-bg-color: #004c6d;
|
||||
|
||||
// import MUI SASS
|
||||
@import "app/libs/mui/src/sass/mui";
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
|
||||
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
|
||||
-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
|
||||
background-color:#E4E4E4;
|
||||
background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||
background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||
background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||
background-image:-webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
color-stop(0, #A7A7A7),
|
||||
color-stop(0.51, #E4E4E4)
|
||||
);
|
||||
background-attachment:fixed;
|
||||
font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
|
||||
font-size:12px;
|
||||
height:100%;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
text-transform:uppercase;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
/* Portrait layout (default) */
|
||||
.app {
|
||||
background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
|
||||
position:absolute; /* position in the center of the screen */
|
||||
left:50%;
|
||||
top:50%;
|
||||
height:50px; /* text area height */
|
||||
width:225px; /* text area width */
|
||||
text-align:center;
|
||||
padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
|
||||
margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
|
||||
/* offset horizontal: half of text area width */
|
||||
}
|
||||
|
||||
/* Landscape layout (with min-width) */
|
||||
@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
|
||||
.app {
|
||||
background-position:left center;
|
||||
padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
|
||||
margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
|
||||
/* offset horizontal: half of image width and text area width */
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:24px;
|
||||
font-weight:normal;
|
||||
margin:0px;
|
||||
overflow:visible;
|
||||
padding:0px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.event {
|
||||
border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
color:#FFFFFF;
|
||||
font-size:12px;
|
||||
margin:0px 30px;
|
||||
padding:2px 0px;
|
||||
}
|
||||
|
||||
.event.listening {
|
||||
background-color:#333333;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.event.received {
|
||||
background-color:#4B946A;
|
||||
display:none;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
from { opacity: 1.0; }
|
||||
50% { opacity: 0.4; }
|
||||
to { opacity: 1.0; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade {
|
||||
from { opacity: 1.0; }
|
||||
50% { opacity: 0.4; }
|
||||
to { opacity: 1.0; }
|
||||
}
|
||||
|
||||
.blink {
|
||||
animation:fade 3000ms infinite;
|
||||
-webkit-animation:fade 3000ms infinite;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1
platforms/android/assets/www/css/mui.min.css
vendored
1
platforms/android/assets/www/css/mui.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,94 +0,0 @@
|
||||
/* Progress Bar */
|
||||
.progress {
|
||||
position: relative;
|
||||
height: 4px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
background-color: #acece6;
|
||||
border-radius: 2px;
|
||||
background-clip: padding-box;
|
||||
/* margin: 0.5rem 0 1rem 0; */
|
||||
overflow: hidden; }
|
||||
|
||||
.progress .determinate {
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #26a69a;
|
||||
transition: width .3s linear; }
|
||||
|
||||
.progress .indeterminate {
|
||||
background-color: #26a69a; }
|
||||
|
||||
.progress .indeterminate:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; }
|
||||
|
||||
.progress .indeterminate:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: inherit;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
will-change: left, right;
|
||||
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||
-webkit-animation-delay: 1.15s;
|
||||
animation-delay: 1.15s; }
|
||||
|
||||
@-webkit-keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
}
|
||||
|
||||
@keyframes indeterminate {
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%; }
|
||||
60% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
100% {
|
||||
left: 100%;
|
||||
right: -90%; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
}
|
||||
|
||||
@keyframes indeterminate-short {
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%; }
|
||||
60% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
100% {
|
||||
left: 107%;
|
||||
right: -8%; }
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
|
||||
@-webkit-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-moz-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-ms-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-moz-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-o-keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes uil-ripple {
|
||||
0% {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
33% {
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
margin: -22% 0 0 -22%;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
width: 88%;
|
||||
height: 88%;
|
||||
margin: -44% 0 0 -44%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.uil-ripple-css {
|
||||
background: none;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
.uil-ripple-css div {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
border-radius: 50%;
|
||||
border-width: 12px;
|
||||
border-style: solid;
|
||||
-ms-animation: uil-ripple 2s ease-out infinite;
|
||||
-moz-animation: uil-ripple 2s ease-out infinite;
|
||||
-webkit-animation: uil-ripple 2s ease-out infinite;
|
||||
-o-animation: uil-ripple 2s ease-out infinite;
|
||||
animation: uil-ripple 2s ease-out infinite;
|
||||
}
|
||||
.uil-ripple-css div:nth-of-type(1) {
|
||||
border-color: #afafb7;
|
||||
}
|
||||
.uil-ripple-css div:nth-of-type(2) {
|
||||
border-color: #5cffd6;
|
||||
-ms-animation-delay: 1s;
|
||||
-moz-animation-delay: 1s;
|
||||
-webkit-animation-delay: 1s;
|
||||
-o-animation-delay: 1s;
|
||||
animation-delay: 1s;
|
||||
}
|
Binary file not shown.
@ -1,10 +1,3 @@
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(Material_Icons-normal-400.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Ubuntu';
|
||||
font-style: normal;
|
||||
|
@ -1,130 +1 @@
|
||||
<!DOCTYPE html><!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
Customize this policy to fit your own app's needs. For more guidance, see:
|
||||
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
|
||||
Some notes:
|
||||
* gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
|
||||
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
|
||||
* Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
|
||||
* Enable inline JS: add 'unsafe-inline' to default-src
|
||||
-->
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport"
|
||||
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||
<!-- build:fonts -->
|
||||
<link rel="stylesheet" href="fonts/fonts.css">
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- build:mui -->
|
||||
<link href="css/mui.custom.css" rel="stylesheet" type="text/css"/>
|
||||
<!-- endbuild -->
|
||||
<!-- build:css -->
|
||||
<link href="css/app.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="css/ripple.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="css/progress.css" rel="stylesheet" type="text/css"/>
|
||||
<!-- endbuild -->
|
||||
<title>Sensor Toy</title>
|
||||
</head>
|
||||
<body class="mui--no-user-select">
|
||||
<header id="header">
|
||||
<div class="mui-appbar">
|
||||
<ul id='app-tabs' class="mui-tabs__bar mui--z1 mui--appbar-height">
|
||||
<li class="mui--is-active"><a data-mui-toggle="tab"
|
||||
data-mui-controls="pane-default-1">Devices</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
<div class="mui--appbar-height"></div>
|
||||
<div id="tab-panes" class='' style="height:100%;">
|
||||
<div class="mui-tabs__pane mui--is-active" id="pane-default-1">
|
||||
<div id='app' class="mui-container">
|
||||
<div>
|
||||
<div class="mui-row mui--appbar-height mui--appbar-line-height">
|
||||
<div class="mui-col-xs-6 mui--text-subhead">
|
||||
<span class="">Devices</span>
|
||||
</div>
|
||||
<div class="mui-col-xs-6 mui--text-right">
|
||||
<button class="mui-btn mui-btn--small mui-btn--primary"
|
||||
id="scan">Scan
|
||||
</button>
|
||||
<button class="mui-btn mui-btn--small mui-btn--danger" id="stop"
|
||||
style="display: none;">Stop
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 0.5rem 0 1rem 0;">
|
||||
<div class="progress" id='ripple' style="display: none;">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="scanResults"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="cordova.js"></script>
|
||||
|
||||
<!-- build:vendor -->
|
||||
<script type="text/javascript" src="libs/jquery/dist/jquery.js"></script>
|
||||
<script type="text/javascript" src="libs/mui/packages/cdn/js/mui.js"></script>
|
||||
<script type="text/javascript" src="libs/ejs/ejs.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="libs/bluebird/js/browser/bluebird.js"></script>
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- build:standards -->
|
||||
<script type="text/javascript"
|
||||
src="js/standards/bluetooth_company_identifiers.js"></script>
|
||||
<script type="text/javascript" src="js/standards/capability.js"></script>
|
||||
<script type="text/javascript" src="js/standards/battery.js"></script>
|
||||
<script type="text/javascript" src="js/standards/button.js"></script>
|
||||
<script type="text/javascript" src="js/mandecoder.js"></script>
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- build:cc2650 -->
|
||||
<script type="text/javascript"
|
||||
src="js/device/CC2650/cc2650_accelerometer.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="js/device/CC2650/cc2650_barometer.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="js/device/CC2650/cc2650_luxometer.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="js/device/CC2650/cc2650_thermopile.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="js/device/CC2650/cc2650_humidity.js"></script>
|
||||
<!-- endbuild -->
|
||||
|
||||
<script type="text/javascript"
|
||||
src="js/device/fmc/TSL.js"></script>
|
||||
|
||||
|
||||
<!-- build:js -->
|
||||
<script type="text/javascript" src="js/index.js"></script>
|
||||
<!-- endbuild -->
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html><html><head><meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *"><meta name="format-detection" content="telephone=no"><meta name="msapplication-tap-highlight" content="no"><meta name="viewport" content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel="stylesheet" href="fonts/fonts.css"><link rel="stylesheet" href="css/custom.css"><link rel="stylesheet" href="css/app.css"><title>Sensor Toy</title></head><body class="mui--no-user-select"><header id="header"><div class="mui-appbar"><ul id="app-tabs" class="mui-tabs__bar mui--z1 mui--appbar-height"><li class="mui--is-active"><a data-mui-toggle="tab" data-mui-controls="pane-default-1">Devices</a></li></ul></div></header><div class="mui--appbar-height"></div><div id="tab-panes" class="" style="height:100%"><div class="mui-tabs__pane mui--is-active" id="pane-default-1"><div id="app" class="mui-container"><div><div class="mui-row mui--appbar-height mui--appbar-line-height"><div class="mui-col-xs-6 mui--text-subhead"><span class="">Devices</span></div><div class="mui-col-xs-6 mui--text-right"><button class="mui-btn mui-btn--small mui-btn--primary" id="scan">Scan</button> <button class="mui-btn mui-btn--small mui-btn--danger" id="stop" style="display: none">Stop</button></div></div><div style="margin: 0.5rem 0 1rem 0"><div class="progress" id="ripple" style="display: none"><div class="indeterminate"></div></div></div><div id="scanResults"></div></div></div></div></div><script type="text/javascript" src="cordova.js"></script><script src="libs/vendor.js"></script><script src="js/standards.js"></script><script src="js/cc2650.js"></script><script type="text/javascript" src="js/device/fmc/TSL.js"></script><script src="js/app.js"></script></body></html>
|
@ -1,407 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var CC2650_ACCEL;
|
||||
CC2650_ACCEL = function(p) {
|
||||
'use strict';
|
||||
this.name = 'Accelerometer';
|
||||
this.deviceID = p.deviceID || null;
|
||||
this.target = p.target || null;
|
||||
|
||||
this.capabilityID = 'F000AA80-0451-4000-B000-000000000000';
|
||||
this.serviceDef = {
|
||||
service: 'F000AA80-0451-4000-B000-000000000000',
|
||||
data: 'F000AA81-0451-4000-B000-000000000000', // Read/notify 3 bytes X : Y : Z
|
||||
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||
configuration: 'F000AA82-0451-4000-B000-000000000000', // Read/write 1 byte
|
||||
period: 'F000AA83-0451-4000-B000-000000000000' // Read/write 1 byte Period = [Input*10]ms
|
||||
};
|
||||
this.frames = {};
|
||||
|
||||
this.$id = {};
|
||||
this.$result = {};
|
||||
this.data = {
|
||||
gyro: {x: [], y: [], z: []},
|
||||
accel: {x: [], y: [], z: []},
|
||||
mag: {x: [], y: [], z: []}
|
||||
};
|
||||
|
||||
this.setFrame();
|
||||
|
||||
this.sensorMpu9250GyroConvert = function(data) {
|
||||
return (data * 1.0) / (65536 / 500);
|
||||
};
|
||||
|
||||
this.sensorMpu9250AccConvert = function(data) {
|
||||
// Change /2 to match accel range...i.e. 16 g would be /16
|
||||
return (data * 1.0) / (32768 / 2);
|
||||
};
|
||||
|
||||
this.processData = function(data) {
|
||||
var a = new Int16Array(data);
|
||||
var calcData = {
|
||||
gyro: {
|
||||
x: this.sensorMpu9250GyroConvert(a[0]),
|
||||
y: this.sensorMpu9250GyroConvert(a[1]),
|
||||
z: this.sensorMpu9250GyroConvert(a[2])
|
||||
}, accel: {
|
||||
x: this.sensorMpu9250AccConvert(a[3]),
|
||||
y: this.sensorMpu9250AccConvert(a[4]),
|
||||
z: this.sensorMpu9250AccConvert(a[5])
|
||||
}, mag: {
|
||||
x: a[6], y: a[7], z: a[8]
|
||||
}
|
||||
};
|
||||
|
||||
return calcData;
|
||||
};
|
||||
this.onAccelerometerData = function(data) {
|
||||
// Console.log(data);
|
||||
var message;
|
||||
var calcData;
|
||||
|
||||
function gString(v) {
|
||||
return [v.toFixed(3),'G'].join('');
|
||||
}
|
||||
|
||||
function aString(v) {
|
||||
return [v.toFixed(3),'\'/s'].join('');
|
||||
}
|
||||
|
||||
function mString(v) {
|
||||
return [v.toFixed(3),'mT'].join('');
|
||||
}
|
||||
calcData = this.processData(data);
|
||||
|
||||
message = 'Gyro <br/>' + 'X: ' + calcData.gyro.x + '<br/>' + 'Y: ' + calcData.gyro.y + '<br/>' + 'Z: ' + calcData.gyro.z + '<br/>' + 'Accel <br/>' + 'X: ' + calcData.accel.x + '<br/>' + 'Y: ' + calcData.accel.y + '<br/>' + 'Z: ' + calcData.accel.z + '<br/>' + 'Mag <br/>' + 'X: ' + calcData.mag.x + '<br/>' + 'Y: ' + calcData.mag.y + '<br/>' + 'Z: ' + calcData.mag.z + '<br/>';
|
||||
|
||||
this.state = message;
|
||||
|
||||
this.$result[this.frames.gyroID + '-x'].text(gString(calcData.gyro.x));
|
||||
this.$result[this.frames.gyroID + '-y'].text(gString(calcData.gyro.y));
|
||||
this.$result[this.frames.gyroID + '-z'].text(gString(calcData.gyro.z));
|
||||
|
||||
this.$result[this.frames.accelID + '-x'].text(aString(calcData.accel.x));
|
||||
this.$result[this.frames.accelID + '-y'].text(aString(calcData.accel.y));
|
||||
this.$result[this.frames.accelID + '-z'].text(aString(calcData.accel.z));
|
||||
|
||||
this.$result[this.frames.magID + '-x'].text(mString(calcData.mag.x));
|
||||
this.$result[this.frames.magID + '-y'].text(mString(calcData.mag.y));
|
||||
this.$result[this.frames.magID + '-z'].text(mString(calcData.mag.z));
|
||||
|
||||
this.data.gyro.x = this.storeData(calcData.gyro.x, this.data.gyro.x);
|
||||
this.data.gyro.y = this.storeData(calcData.gyro.y, this.data.gyro.y);
|
||||
this.data.gyro.z = this.storeData(calcData.gyro.z, this.data.gyro.z);
|
||||
|
||||
this.data.accel.x = this.storeData(calcData.accel.x, this.data.accel.x);
|
||||
this.data.accel.y = this.storeData(calcData.accel.y, this.data.accel.y);
|
||||
this.data.accel.z = this.storeData(calcData.accel.z, this.data.accel.z);
|
||||
|
||||
this.data.mag.x = this.storeData(calcData.mag.x, this.data.mag.x);
|
||||
this.data.mag.y = this.storeData(calcData.mag.y, this.data.mag.y);
|
||||
this.data.mag.z = this.storeData(calcData.mag.z, this.data.mag.z);
|
||||
|
||||
// console.log(JSON.stringify(this.data));
|
||||
// Console.log(this.state);
|
||||
};
|
||||
|
||||
this.startService = function() {
|
||||
|
||||
if (this.deviceID !== null) {
|
||||
|
||||
console.log('Starting CC2650 Accelerometer Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
|
||||
this.setInternalID();
|
||||
this.insertFrame('gyro');
|
||||
this.insertFrame('accel');
|
||||
this.insertFrame('mag');
|
||||
|
||||
ble.startNotification(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.data,
|
||||
this.onAccelerometerData.bind(this),
|
||||
this.onError);
|
||||
|
||||
// Turn accelerometer on
|
||||
var configData = new Uint16Array(1);
|
||||
// Turn on gyro, accel, and mag, 2G range, Disable wake on motion
|
||||
configData[0] = 0x007F;
|
||||
ble.write(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.configuration,
|
||||
configData.buffer,
|
||||
function() { console.log('Started accelerometer.'); },
|
||||
this.onError);
|
||||
|
||||
var periodData = new Uint8Array(1);
|
||||
periodData[0] = 0x0A;
|
||||
ble.write(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.period,
|
||||
periodData.buffer,
|
||||
function() { console.log('Configured accelerometer period.'); },
|
||||
this.onError);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.advancedGraph = function(mode, data, subID) {
|
||||
|
||||
var lm;
|
||||
var ceiling;
|
||||
var elm;
|
||||
var text2ID;
|
||||
var ceilingLimit;
|
||||
var calcArray;
|
||||
var floor;
|
||||
var _subID;
|
||||
var _data;
|
||||
var text1ID;
|
||||
var lineID;
|
||||
var max;
|
||||
|
||||
|
||||
var parts = ['x', 'y', 'z'];
|
||||
|
||||
_data = data || this.data;
|
||||
|
||||
_subID = subID || '';
|
||||
|
||||
// LineID = [this.frameID , _subID , '-line'].join('');
|
||||
text1ID = [this.frameID, _subID, '-txt1'].join('');
|
||||
text2ID = [this.frameID, _subID, '-txt2'].join('');
|
||||
|
||||
if (_data.x.length > 0) {
|
||||
|
||||
max = 2;
|
||||
|
||||
for (var lineMode = 0; lineMode < parts.length; lineMode++) {
|
||||
lm = parts[lineMode];
|
||||
ceiling = _data[lm].reduce(function(p, v) {
|
||||
return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v));
|
||||
});
|
||||
|
||||
|
||||
if (ceiling > 500) {
|
||||
max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 50) * 50) : max;
|
||||
} else {
|
||||
max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 10) * 10) : max;
|
||||
}
|
||||
}
|
||||
|
||||
ceiling = max;
|
||||
|
||||
floor = ceiling * -1;
|
||||
ceilingLimit = ceiling;
|
||||
|
||||
var scalePos = (124 / 2) / ceiling;
|
||||
var scaleNeg = (124 / 2) / floor;
|
||||
var xstep = (680 - 46) / 100;
|
||||
|
||||
//Var xstep = 2.34;
|
||||
|
||||
for (lineMode = 0; lineMode < parts.length; lineMode++) {
|
||||
|
||||
lm = parts[lineMode];
|
||||
var startX = 46 + (100 - _data[lm].length) * xstep;
|
||||
|
||||
calcArray = [];
|
||||
|
||||
lineID = this.frameID + _subID + '-' + lm + '-line';
|
||||
for (var x = 0; x < _data[lm].length; x++) {
|
||||
|
||||
calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (71 - ((_data[lm][x]) * scalePos)).toFixed(
|
||||
2));
|
||||
|
||||
}
|
||||
|
||||
elm = document.getElementById(lineID);
|
||||
|
||||
elm.setAttribute('points', calcArray.join(' '));
|
||||
|
||||
}
|
||||
|
||||
elm = document.getElementById(text1ID);
|
||||
elm.textContent = ceilingLimit;
|
||||
|
||||
elm = document.getElementById(text2ID);
|
||||
elm.textContent = floor;
|
||||
|
||||
}
|
||||
|
||||
this.previousCeil = ceiling;
|
||||
};
|
||||
|
||||
this.animateGraph = function() {
|
||||
// Nothing to animate yet
|
||||
|
||||
// return -1;
|
||||
this.advancedGraph(0, this.data.gyro, 'gyro');
|
||||
this.advancedGraph(0, this.data.accel, 'accel');
|
||||
this.advancedGraph(0, this.data.mag, 'mag');
|
||||
// This.simpleGraph(this.data.temp, 'temp');
|
||||
// this.simpleGraph(this.data.pressure, 'pressure');
|
||||
|
||||
};
|
||||
|
||||
this.generateBlankGraphBase = function(subID, settings) {
|
||||
|
||||
var _subID = subID || '';
|
||||
var xmlns = 'http://www.w3.org/2000/svg';
|
||||
|
||||
var svgID = this.frameID + _subID + '-svg';
|
||||
var text1ID = this.frameID + _subID + '-txt1';
|
||||
var text2ID = this.frameID + _subID + '-txt2';
|
||||
|
||||
var _width = settings.width || 300;
|
||||
var _height = settings.height || 150;
|
||||
var _fill = settings.fill || 'blue';
|
||||
|
||||
var svg = document.createElementNS(xmlns, 'svg');
|
||||
|
||||
svg.setAttribute('id', svgID);
|
||||
// Svg.setAttribute(xmlns, 'version', '1.1');
|
||||
svg.setAttribute('width', _width.toString());
|
||||
svg.setAttribute('height', _height.toString());
|
||||
svg.setAttribute('fill', _fill);
|
||||
|
||||
|
||||
svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
svg.setAttributeNS(xmlns, 'viewBox', '0 0 700 150');
|
||||
// Svg.setAttributeNS(xmlns, 'style', 'width:700px;height:150px;');
|
||||
|
||||
|
||||
svg = this.graphAddXAxis(svg, {y: 12, x2: 680, colour: '#004c6d', id: text1ID});
|
||||
svg = this.graphAddXAxis(svg, {y: 136, x2: 680, colour: '#004c6d', id: text2ID});
|
||||
svg = this.graphAddXAxis(svg, {y: 71, x2: 680, colour: '#004c6d', text: '0'});
|
||||
|
||||
return svg;
|
||||
|
||||
};
|
||||
|
||||
this.generateBlankGraph = function(subID) {
|
||||
|
||||
var _subID = subID || '';
|
||||
var xlineID = this.frameID + _subID + '-x-line';
|
||||
var ylineID = this.frameID + _subID + '-y-line';
|
||||
var zlineID = this.frameID + _subID + '-z-line';
|
||||
|
||||
var svg = this.generateBlankGraphBase(_subID,{width: '700',height: 150});
|
||||
|
||||
svg = this.graphAddLine(svg, xlineID, 'rgba(255,0,99,1)');
|
||||
svg = this.graphAddLine(svg, ylineID, 'rgba(46,255,0,1)');
|
||||
svg = this.graphAddLine(svg, zlineID, 'rgba(0,191,255,1)');
|
||||
|
||||
return svg;
|
||||
|
||||
};
|
||||
|
||||
this.startCalibrate = function() {
|
||||
console.log('Start calibrate');
|
||||
|
||||
alert('Mag Calibration: Wave device in a figure eight until done!');
|
||||
};
|
||||
|
||||
this.insertFrame = function(mode) {
|
||||
|
||||
var frame;
|
||||
var title;
|
||||
var modeID = mode + 'ID';
|
||||
this.frames[modeID] = this.frameID + '-' + mode;
|
||||
|
||||
var titles = {
|
||||
gyro: 'Gyroscope', accel: 'Accelerometer', mag: 'Magnetometer'
|
||||
};
|
||||
var modes = ['gyro', 'accel', 'mag'];
|
||||
|
||||
console.log('FrameID: ', this.frames[modeID]);
|
||||
|
||||
title = [titles[mode], ' - ', this.deviceID].join(' ');
|
||||
|
||||
frame = $('<div />', {
|
||||
class: 'mui-panel', id: this.frames[modeID]
|
||||
});
|
||||
|
||||
if (mode === 'mag') {
|
||||
var elm = $('<div />', {class: 'mui-row'});
|
||||
var button = $('<button />',{class: 'mui-btn mui-btn--raised', id: modeID + '-cal', text: 'Calibrate', click: this.startCalibrate.bind(this)});
|
||||
|
||||
elm.append($('<div />', { class: 'mui-col-xs-8 mui--text-title mui-ellipsis-2', text: title}));
|
||||
|
||||
// elm.append($('<div />', {class: 'mui-col-xs-4 mui--text-right'}).append(button));
|
||||
|
||||
frame.append(elm);
|
||||
|
||||
} else {
|
||||
$('<div />', {class: 'mui-row'}).append($('<div />', {
|
||||
class: 'mui-col-xs-12 mui--text-title mui-ellipsis-2', text: title
|
||||
})).appendTo(frame);
|
||||
|
||||
}
|
||||
this.$frame.append(frame);
|
||||
this.$id[modeID] = $('#' + this.frames[modeID]);
|
||||
|
||||
// Call the parent displayForm first...
|
||||
|
||||
var row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'X'
|
||||
}).appendTo(row);
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'Y'
|
||||
}).appendTo(row);
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'Z'
|
||||
}).appendTo(row);
|
||||
|
||||
this.$id[modeID].append(row);
|
||||
|
||||
row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-light mui--text-center',
|
||||
text: '--',
|
||||
id: this.frames[modeID] + '-x'
|
||||
}).appendTo(row);
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-light mui--text-center',
|
||||
text: '--',
|
||||
id: this.frames[modeID] + '-y'
|
||||
}).appendTo(row);
|
||||
$('<div />', {
|
||||
class: 'mui-col-xs-4 mui--text-light mui--text-center',
|
||||
text: '--',
|
||||
id: this.frames[modeID] + '-z'
|
||||
}).appendTo(row);
|
||||
|
||||
this.$id[modeID].append(row);
|
||||
|
||||
this.$result[this.frames[modeID] + '-x'] = $('#' + this.frames[modeID] + '-x');
|
||||
this.$result[this.frames[modeID] + '-y'] = $('#' + this.frames[modeID] + '-y');
|
||||
this.$result[this.frames[modeID] + '-z'] = $('#' + this.frames[modeID] + '-z');
|
||||
|
||||
row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
var _graph = this.generateBlankGraph(mode);
|
||||
row.append($('<div>', {class: 'mui-col-sm-12'}).append(_graph));
|
||||
|
||||
this.$id[modeID].append(row);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
inheritsFrom(CC2650_ACCEL, CAPABILITY);
|
||||
|
||||
capabilityManager.register({id: 'F000AA80-0451-4000-B000-000000000000', module: CC2650_ACCEL});
|
@ -1,190 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager, EJS */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var CC2650_BAR = function(p) {
|
||||
'use strict';
|
||||
this.name = 'Barometer';
|
||||
this.deviceID = p.deviceID || null;
|
||||
this.target = p.target || null;
|
||||
|
||||
this.capabilityID = 'F000AA40-0451-4000-B000-000000000000';
|
||||
this.serviceDef = {
|
||||
service: 'F000AA40-0451-4000-B000-000000000000',
|
||||
data: 'F000AA41-0451-4000-B000-000000000000',
|
||||
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||
configuration: 'F000AA42-0451-4000-B000-000000000000',
|
||||
period: 'F000AA43-0451-4000-B000-000000000000'
|
||||
|
||||
};
|
||||
this.data = {temp: [], pressure: []};
|
||||
this.$result = {temp: null, pressure: null};
|
||||
this.setFrame();
|
||||
|
||||
this.startService = function() {
|
||||
|
||||
if (this.deviceID !== null) {
|
||||
|
||||
console.log('Starting CC2650 Barometer Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
this.insertFrame();
|
||||
|
||||
ble.startNotification(this.deviceID, this.serviceDef.service, this.serviceDef.data, this.onBarometerData.bind(this), this.onError);
|
||||
|
||||
// Turn on barometer
|
||||
var barometerConfig = new Uint8Array(1);
|
||||
barometerConfig[0] = 0x01;
|
||||
ble.write(this.deviceID, this.serviceDef.service, this.serviceDef.configuration, barometerConfig.buffer,
|
||||
function() { console.log('Started barometer.'); },this.onError);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.sensorBarometerConvert = function(data) {
|
||||
return (data / 100);
|
||||
|
||||
};
|
||||
|
||||
this.onBarometerData = function(data) {
|
||||
var pStr;
|
||||
var tStr;
|
||||
var message;
|
||||
var a = new Uint8Array(data);
|
||||
|
||||
// 0-2 Temp
|
||||
// 3-5 Pressure
|
||||
var temp, pressure;
|
||||
temp = this.sensorBarometerConvert(a[0] | (a[1] << 8) | (a[2] << 16));
|
||||
pressure = this.sensorBarometerConvert(a[3] | (a[4] << 8) | (a[5] << 16));
|
||||
tStr = temp + '°C';
|
||||
pStr = pressure + 'hPa';
|
||||
|
||||
message = 'Temperature <br/>' + tStr +
|
||||
'Pressure <br/>' + pStr ;
|
||||
|
||||
|
||||
this.data.temp = this.storeData(temp, this.data.temp);
|
||||
this.data.pressure = this.storeData(pressure, this.data.pressure);
|
||||
|
||||
|
||||
this.$result.temp.text(tStr);
|
||||
this.$result.pressure.text(pStr);
|
||||
|
||||
this.state = message;
|
||||
|
||||
// Console.log('Barometer:', this.state);
|
||||
};
|
||||
|
||||
this.animateGraph = function() {
|
||||
/* This.simpleGraph(this.data.temp, 'temp');
|
||||
this.simpleGraph(this.data.pressure, 'pressure');*/
|
||||
|
||||
var arcTemp = this.frameID + 'temp-arc';
|
||||
var arcPressure = this.frameID + 'pressure-arc';
|
||||
this.updateArc(this.data.temp, 'temp' , arcTemp, '°C', 50);
|
||||
this.updateArc(this.data.pressure, 'pressure' , arcPressure, 'hPa');
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
this.insertFrame = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Call the parent displayForm first...
|
||||
this.superClass_.insertFrame.call(self);
|
||||
|
||||
var temp = this.frameID + '-t';
|
||||
var pressure = this.frameID + '-p';
|
||||
|
||||
var arcB = this.frameID + 'temp-arcB';
|
||||
var arcTemp = this.frameID + 'temp-arc';
|
||||
|
||||
var pressureArcB = this.frameID + 'pressure-arcB';
|
||||
var arcPressure = this.frameID + 'pressure-arc';
|
||||
|
||||
var settings = {data: {baseID: this.frameID}};
|
||||
var html = new EJS({url: './partials/cc2650_barometer_dial.ejs'}).render(settings);
|
||||
|
||||
this.$id.append(html);
|
||||
|
||||
document.getElementById(arcB).setAttribute('d', this.describeArc(150, 150, 100, 0, 240));
|
||||
document.getElementById(arcTemp).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(0)));
|
||||
|
||||
document.getElementById(pressureArcB).setAttribute('d', this.describeArc(150, 150, 100, 0, 240));
|
||||
document.getElementById(arcPressure).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(0)));
|
||||
|
||||
|
||||
/* Var row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />', { class: 'mui-col-xs-3 mui--text-accent mui--text-right', text: 'Temp:'}).appendTo(row);
|
||||
|
||||
$('<div />', { class: 'mui-col-xs-3 mui--text-dark', id: temp}).appendTo(row);
|
||||
$('<div />', { class: 'mui-col-xs-3 mui--text-accent mui--text-right', text: 'Pressure:'}).appendTo(row);
|
||||
|
||||
$('<div />', { class: 'mui-col-xs-3 mui--text-dark', id: pressure}).appendTo(row);
|
||||
|
||||
this.$id.append(row);
|
||||
|
||||
if (/ipad/i.test(device.model)) {
|
||||
|
||||
tabBody = $('<div>', {class: 'mui-row'});
|
||||
|
||||
tabBody.append($('<div>',{class: 'mui-col-md-6'}).append(this.generateBlankGraph('temp'))) ;
|
||||
tabBody.append($('<div>',{class: 'mui-col-md-6'}).append(this.generateBlankGraph('pressure'))) ;
|
||||
this.$id.append(tabBody);
|
||||
|
||||
} else {
|
||||
|
||||
var tabBody = $('<ul>',
|
||||
{class: 'mui-tabs__bar mui-tabs__bar--justified'});
|
||||
$('<li>', {class: 'mui--is-active tabOnWhite'}).append($('<a>',
|
||||
{
|
||||
text: 'Temperature',
|
||||
'data-mui-toggle': 'tab',
|
||||
'data-mui-controls': (temp + '-pane')
|
||||
})).appendTo(tabBody);
|
||||
$('<li>', {class: 'tabOnWhite'}).append($('<a>',
|
||||
{
|
||||
text: 'Pressure',
|
||||
'data-mui-toggle': 'tab',
|
||||
'data-mui-controls': (pressure + '-pane')
|
||||
})).appendTo(tabBody);
|
||||
|
||||
this.$id.append(tabBody);
|
||||
|
||||
blankChart = this.generateBlankGraph('temp');
|
||||
|
||||
this.$id.append($('<div>',
|
||||
{class: 'mui-tabs__pane mui--is-active', id: (temp + '-pane')}).append(
|
||||
blankChart));
|
||||
|
||||
blankChart = this.generateBlankGraph('pressure');
|
||||
|
||||
this.$id.append($('<div>',
|
||||
{
|
||||
class: 'mui-tabs__pane',
|
||||
id: (pressure + '-pane')
|
||||
}).append(blankChart));
|
||||
}*/
|
||||
this.$result.temp = $('#' + temp);
|
||||
this.$result.pressure = $('#' + pressure);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
inheritsFrom(CC2650_BAR, CAPABILITY);
|
||||
|
||||
capabilityManager.register({id: 'F000AA40-0451-4000-B000-000000000000', module: CC2650_BAR});
|
@ -1,199 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager, EJS */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var CC2650_HUM = function(p) {
|
||||
'use strict';
|
||||
this.name = 'Humidity';
|
||||
this.deviceID = p.deviceID || null;
|
||||
this.target = p.target || null;
|
||||
|
||||
this.capabilityID = 'F000AA20-0451-4000-B000-000000000000';
|
||||
this.serviceDef = {
|
||||
service: 'F000AA20-0451-4000-B000-000000000000',
|
||||
data: 'F000AA21-0451-4000-B000-000000000000',
|
||||
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||
configuration: 'F000AA22-0451-4000-B000-000000000000',
|
||||
period: 'F000AA23-0451-4000-B000-000000000000'
|
||||
|
||||
};
|
||||
this.data = {temp: [], humidity: []};
|
||||
this.$result = {temp: null, humidity: null};
|
||||
this.setFrame();
|
||||
|
||||
this.startService = function() {
|
||||
|
||||
if (this.deviceID !== null) {
|
||||
|
||||
console.log('Starting CC2650 Humidity Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
this.insertFrame();
|
||||
|
||||
ble.startNotification(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.data,
|
||||
this.onHumidityData.bind(this),
|
||||
this.onError);
|
||||
|
||||
// Turn on barometer
|
||||
var humidityConfig = new Uint8Array(1);
|
||||
humidityConfig[0] = 0x01;
|
||||
ble.write(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.configuration,
|
||||
humidityConfig.buffer,
|
||||
function() { console.log('Started Humidity.'); },
|
||||
this.onError);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.onHumidityData = function(data) {
|
||||
var hStr;
|
||||
var tStr;
|
||||
// Console.log(data);
|
||||
var message;
|
||||
var raw = new Uint16Array(data);
|
||||
|
||||
// -- calculate temperature [°C]
|
||||
var temp = (raw[0] / 65536) * 165 - 40;
|
||||
|
||||
// -- calculate relative humidity [%RH]
|
||||
var hum = (raw[1] / 65536) * 100;
|
||||
|
||||
tStr = temp.toFixed(2) + '°C';
|
||||
hStr = hum.toFixed(2) + '%RH';
|
||||
|
||||
message = 'Temperature <br/>' + tStr + 'Humidity <br/>' + hStr;
|
||||
|
||||
this.data.temp = this.storeData(temp, this.data.temp);
|
||||
this.data.humidity = this.storeData(hum, this.data.humidity);
|
||||
|
||||
|
||||
this.$result.temp.text(tStr);
|
||||
this.$result.humidity.text(hStr);
|
||||
|
||||
this.state = message;
|
||||
|
||||
// Console.log('Barometer:', this.state);
|
||||
};
|
||||
|
||||
this.animateGraph = function() {
|
||||
/*
|
||||
this.simpleGraph(this.data.temp, 'temp');
|
||||
this.simpleGraph(this.data.humidity, 'humidity');
|
||||
*/
|
||||
var arcTemp = this.frameID + 'temp-arc';
|
||||
var arcHumidity = this.frameID + 'humidity-arc';
|
||||
this.updateArc(this.data.temp, 'temp' , arcTemp, '°C', 50);
|
||||
this.updateArc(this.data.humidity, 'humidity' , arcHumidity, '%RH', 100);
|
||||
|
||||
};
|
||||
|
||||
|
||||
this.insertFrame = function() {
|
||||
|
||||
var self = this;
|
||||
var blankChart;
|
||||
|
||||
// Call the parent displayForm first...
|
||||
this.superClass_.insertFrame.call(self);
|
||||
|
||||
var temp = this.frameID + '-t';
|
||||
var humidity = this.frameID + '-h';
|
||||
|
||||
var arcB = this.frameID + 'temp-arcB';
|
||||
var arcTemp = this.frameID + 'temp-arc';
|
||||
|
||||
|
||||
var humidityArcB = this.frameID + 'humidity-arcB';
|
||||
var arcHumidity = this.frameID + 'humidity-arc';
|
||||
|
||||
|
||||
var settings = {data: {baseID: this.frameID}};
|
||||
var html = new EJS({url: './partials/cc2650_humidity_dial.ejs'}).render(settings);
|
||||
|
||||
this.$id.append(html);
|
||||
|
||||
document.getElementById(arcB).setAttribute('d', this.describeArc(150, 150, 100, 0, 240));
|
||||
document.getElementById(arcTemp).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(0)));
|
||||
|
||||
document.getElementById(humidityArcB).setAttribute('d', this.describeArc(150, 150, 100, 0, 240));
|
||||
document.getElementById(arcHumidity).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(0)));
|
||||
|
||||
|
||||
/*
|
||||
var row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-3 mui--text-accent mui--text-right', text: 'Temp:'}).appendTo(row);
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-3 mui--text-light', id: temp}).appendTo(row);
|
||||
$('<div />',
|
||||
{
|
||||
class: 'mui-col-xs-3 mui--text-accent mui--text-right',
|
||||
text: 'Humidity:'
|
||||
}).appendTo(row);
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-3 mui--text-light', id: humidity}).appendTo(row);
|
||||
|
||||
this.$id.append(row);
|
||||
|
||||
if (/ipad/i.test(device.model)) {
|
||||
|
||||
tabBody = $('<div>', {class: 'mui-row'});
|
||||
|
||||
tabBody.append($('<div>',{class: 'mui-col-md-6'}).append(this.generateBlankGraph('temp'))) ;
|
||||
tabBody.append($('<div>',{class: 'mui-col-md-6'}).append(this.generateBlankGraph('humidity'))) ;
|
||||
this.$id.append(tabBody);
|
||||
|
||||
} else {
|
||||
var tabBody = $('<ul>',
|
||||
{class: 'mui-tabs__bar mui-tabs__bar--justified'});
|
||||
$('<li>', {class: 'mui--is-active tabOnWhite'}).append($('<a>',
|
||||
{
|
||||
text: 'Temperature',
|
||||
'data-mui-toggle': 'tab',
|
||||
'data-mui-controls': (temp + '-pane')
|
||||
})).appendTo(tabBody);
|
||||
$('<li>', {class: 'tabOnWhite'}).append($('<a>',
|
||||
{
|
||||
text: 'Humidity',
|
||||
'data-mui-toggle': 'tab',
|
||||
'data-mui-controls': (humidity + '-pane')
|
||||
})).appendTo(tabBody);
|
||||
this.$id.append(tabBody);
|
||||
|
||||
blankChart = this.generateBlankGraph('temp');
|
||||
|
||||
this.$id.append($('<div>',
|
||||
{class: 'mui-tabs__pane mui--is-active', id: (temp + '-pane')}).append(
|
||||
blankChart));
|
||||
|
||||
blankChart = this.generateBlankGraph('humidity');
|
||||
this.$id.append($('<div>',
|
||||
{
|
||||
class: 'mui-tabs__pane',
|
||||
id: (humidity + '-pane')
|
||||
}).append(blankChart));
|
||||
}*/
|
||||
this.$result.temp = $('#' + temp);
|
||||
this.$result.humidity = $('#' + humidity);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inheritsFrom(CC2650_HUM, CAPABILITY);
|
||||
|
||||
capabilityManager.register({id: 'F000AA20-0451-4000-B000-000000000000', module: CC2650_HUM});
|
@ -1,113 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var CC2650_LUX = function(p) {
|
||||
'use strict';
|
||||
this.name = 'Luxometer';
|
||||
this.deviceID = p.deviceID || null;
|
||||
this.target = p.target || null;
|
||||
|
||||
this.capabilityID = 'F000AA70-0451-4000-B000-000000000000';
|
||||
this.serviceDef = {
|
||||
service: 'F000AA70-0451-4000-B000-000000000000',
|
||||
data: 'F000AA71-0451-4000-B000-000000000000',
|
||||
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||
configuration: 'F000AA72-0451-4000-B000-000000000000',
|
||||
period: 'F000AA73-0451-4000-B000-000000000000'
|
||||
|
||||
};
|
||||
|
||||
this.$result = {temp: null, pressure: null};
|
||||
this.data = [];
|
||||
this.setFrame();
|
||||
|
||||
this.startService = function() {
|
||||
|
||||
if (this.deviceID !== null) {
|
||||
|
||||
console.log('Starting CC2650 Luxometer Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
this.insertFrame();
|
||||
|
||||
ble.startNotification(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.data,
|
||||
this.onLuxData.bind(this),
|
||||
this.onError);
|
||||
|
||||
// Turn on luxometer
|
||||
var luxConfig = new Uint8Array(1);
|
||||
luxConfig[0] = 0x01;
|
||||
ble.write(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.configuration,
|
||||
luxConfig.buffer,
|
||||
function() { console.log('Started luxometer.'); },
|
||||
this.onError);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.onLuxData = function(data) {
|
||||
|
||||
var m, e, lux;
|
||||
|
||||
var raw = new Uint16Array(data);
|
||||
|
||||
m = raw & 0x0FFF;
|
||||
e = (raw & 0xF000) >> 12;
|
||||
|
||||
lux = m * (0.01 * Math.pow(2.0, e));
|
||||
|
||||
this.state = [lux.toFixed(2), 'lux'].join(' ');
|
||||
|
||||
this.storeData(lux);
|
||||
|
||||
this.$result.text(this.state);
|
||||
};
|
||||
|
||||
this.animateGraph = function() {
|
||||
this.simpleGraph(this.data, '');
|
||||
};
|
||||
|
||||
this.insertFrame = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Call the parent displayForm first...
|
||||
this.superClass_.insertFrame.call(self);
|
||||
|
||||
var lux = this.frameID + '-l';
|
||||
|
||||
var row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-4 mui--text-accent mui--text-right', text: 'Luminosity:'}).appendTo(
|
||||
row);
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-8 mui--text-light', id: lux}).appendTo(row);
|
||||
|
||||
this.$id.append(row);
|
||||
|
||||
var blankChart = this.generateBlankGraph();
|
||||
|
||||
this.$id.append(blankChart);
|
||||
|
||||
this.$result = $('#' + lux);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inheritsFrom(CC2650_LUX, CAPABILITY);
|
||||
capabilityManager.register({id: 'F000AA70-0451-4000-B000-000000000000', module: CC2650_LUX});
|
@ -1,189 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager, EJS */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var CC2650_TMP = function(p) {
|
||||
'use strict';
|
||||
this.name = 'Thermopile';
|
||||
this.deviceID = p.deviceID || null;
|
||||
this.target = p.target || null;
|
||||
|
||||
this.capabilityID = 'F000AA00-0451-4000-B000-000000000000';
|
||||
this.serviceDef = {
|
||||
service: 'F000AA00-0451-4000-B000-000000000000',
|
||||
data: 'F000AA01-0451-4000-B000-000000000000',
|
||||
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||
configuration: 'F000AA02-0451-4000-B000-000000000000',
|
||||
period: 'F000AA03-0451-4000-B000-000000000000'
|
||||
|
||||
};
|
||||
|
||||
this.data = {temp: [], ambient: []};
|
||||
this.$result = {temp: null, ambient: null};
|
||||
this.setFrame();
|
||||
|
||||
this.startService = function() {
|
||||
|
||||
if (this.deviceID !== null) {
|
||||
|
||||
console.log('Starting CC2650 Thermopile Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
this.insertFrame();
|
||||
|
||||
ble.startNotification(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.data,
|
||||
this.onThermData.bind(this),
|
||||
this.onError);
|
||||
|
||||
// Turn on thermopile
|
||||
var tmpConfig = new Uint8Array(1);
|
||||
tmpConfig[0] = 0x01;
|
||||
ble.write(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.configuration,
|
||||
tmpConfig.buffer,
|
||||
function() { console.log('Started Thermopile.'); },
|
||||
this.onError);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.onThermData = function(data) {
|
||||
|
||||
var ambTemp;
|
||||
var objTemp;
|
||||
var scale_lsb = 0.03125;
|
||||
var raw = new Uint16Array(data);
|
||||
|
||||
var it = raw[0] >> 2;
|
||||
|
||||
objTemp = it * scale_lsb;
|
||||
|
||||
it = raw[1] >> 2;
|
||||
|
||||
ambTemp = it * scale_lsb;
|
||||
|
||||
var tStr = objTemp.toFixed(2) + '°C';
|
||||
var aStr = ambTemp.toFixed(2) + '°C';
|
||||
|
||||
this.state = ['Temp: ', tStr, ', Ambient:', aStr].join(' ');
|
||||
|
||||
this.data.temp = this.storeData(objTemp, this.data.temp);
|
||||
this.data.ambient = this.storeData(ambTemp, this.data.ambient);
|
||||
|
||||
|
||||
this.$result.temp.text(tStr);
|
||||
this.$result.ambient.text(aStr);
|
||||
|
||||
};
|
||||
|
||||
this.animateGraph = function() {
|
||||
// This.simpleGraph(this.data.temp, 'temp');
|
||||
// debugger;
|
||||
var arcTemp = this.frameID + 'temp-arc';
|
||||
var arcAmbient = this.frameID + 'ambient-arc';
|
||||
this.updateArc(this.data.temp, 'temp' , arcTemp, '°C', 50);
|
||||
this.updateArc(this.data.ambient, 'ambient' , arcAmbient, '°C', 50);
|
||||
|
||||
};
|
||||
|
||||
this.insertFrame = function() {
|
||||
|
||||
var self = this;
|
||||
// Console.log('Overloading...');
|
||||
// Call the parent displayForm first...
|
||||
|
||||
this.superClass_.insertFrame.call(self);
|
||||
|
||||
var temp = this.frameID + '-t';
|
||||
var amb = this.frameID + '-a';
|
||||
|
||||
|
||||
var arcB = this.frameID + 'temp-arcB';
|
||||
var arcTemp = this.frameID + 'temp-arc';
|
||||
|
||||
var ambientArcB = this.frameID + 'ambient-arcB';
|
||||
var arcAmbient = this.frameID + 'ambient-arc';
|
||||
|
||||
var settings = {data: {baseID: this.frameID}};
|
||||
var html = new EJS({url: './partials/cc2650_thermopile_dial.ejs'}).render(settings);
|
||||
|
||||
this.$id.append(html);
|
||||
|
||||
document.getElementById(arcB).setAttribute('d', this.describeArc(150, 150, 100, 0, 240));
|
||||
document.getElementById(arcTemp).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(0)));
|
||||
|
||||
document.getElementById(ambientArcB).setAttribute('d', this.describeArc(150, 150, 100, 0, 240));
|
||||
document.getElementById(arcAmbient).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(0)));
|
||||
|
||||
|
||||
/*Var row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-3 mui--text-accent mui--text-right', text: 'Temp:'}).appendTo(row);
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-3 mui--text-light mui--text-left', id: temp}).appendTo(row);
|
||||
$('<div />',
|
||||
{
|
||||
class: 'mui-col-xs-3 mui--text-accent mui--text-right',
|
||||
text: 'Ambient:'
|
||||
}).appendTo(row);
|
||||
|
||||
$('<div />',
|
||||
{class: 'mui-col-xs-3 mui--text-light', id: amb}).appendTo(row);
|
||||
|
||||
this.$id.append(row);
|
||||
|
||||
if (/ipad/i.test(device.model)) {
|
||||
|
||||
tabBody = $('<div>', {class: 'mui-row'});
|
||||
|
||||
tabBody.append($('<div>',{class: 'mui-col-md-6'}).append(this.generateBlankGraph('temp'))) ;
|
||||
tabBody.append($('<div>',{class: 'mui-col-md-6'}).append(this.generateBlankGraph('ambient'))) ;
|
||||
this.$id.append(tabBody);
|
||||
|
||||
} else {
|
||||
tabBody = $('<ul>', {class: 'mui-tabs__bar mui-tabs__bar--justified'});
|
||||
liSetting = {
|
||||
text: 'Temperature',
|
||||
'data-mui-toggle': 'tab',
|
||||
'data-mui-controls': (temp + '-pane')
|
||||
};
|
||||
$('<li>',{class: 'mui--is-active tabOnWhite'}).append($('<a>',liSetting)).appendTo(tabBody);
|
||||
liSetting = { text: 'Ambient','data-mui-toggle': 'tab', 'data-mui-controls': (amb + '-pane')};
|
||||
$('<li>', {class: 'tabOnWhite'}).append($('<a>',liSetting)).appendTo(tabBody);
|
||||
|
||||
this.$id.append(tabBody);
|
||||
|
||||
blankChart = this.generateBlankGraph('temp');
|
||||
|
||||
this.$id.append($('<div>',{class: 'mui-tabs__pane mui--is-active',id: (temp + '-pane')}).append(blankChart));
|
||||
|
||||
blankChart = this.generateBlankGraph('ambient');
|
||||
|
||||
this.$id.append($('<div>',{class: 'mui-tabs__pane',id: (amb + '-pane')}).append(blankChart));
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
this.$result.temp = $('#' + temp);
|
||||
this.$result.ambient = $('#' + amb);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inheritsFrom(CC2650_TMP, CAPABILITY);
|
||||
|
||||
capabilityManager.register({id: 'F000AA00-0451-4000-B000-000000000000', module: CC2650_TMP});
|
@ -1,599 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* global mui, bt_company_ids, ble, LocalFileSystem, capabilityManager, MANUFACTUREDECODER */
|
||||
|
||||
var app;
|
||||
app = {
|
||||
mode: 0, stop: false, log: {}, activeServices: {},
|
||||
|
||||
list: {}, foundDevices: {},
|
||||
|
||||
manufactureDecoder: new MANUFACTUREDECODER(), // Application Constructor
|
||||
initialize: function() {
|
||||
this.bindEvents();
|
||||
},
|
||||
|
||||
arrayBufferToIntArray: function(buffer) {
|
||||
var result;
|
||||
|
||||
if (buffer) {
|
||||
var typedArray = new Uint8Array(buffer);
|
||||
result = [];
|
||||
for (var i = 0; i < typedArray.length; i++) {
|
||||
result[i] = typedArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
parseAdvertisingData: function(bytes) {
|
||||
var length;
|
||||
var type;
|
||||
var data;
|
||||
var i = 0;
|
||||
var advertisementData = {};
|
||||
|
||||
while (length !== 0) {
|
||||
|
||||
length = bytes[i] & 0xFF;
|
||||
i++;
|
||||
|
||||
type = bytes[i] & 0xFF;
|
||||
i++;
|
||||
|
||||
data = bytes.slice(i, i + length - 1); // Length includes type byte, but not length byte
|
||||
i += length - 2; // Move to end of data
|
||||
i++;
|
||||
|
||||
advertisementData[type] = data;
|
||||
}
|
||||
|
||||
return advertisementData;
|
||||
}, handle255: function(buffer) {
|
||||
'use strict';
|
||||
|
||||
var company;
|
||||
var cid;
|
||||
var manID;
|
||||
var bin = buffer;
|
||||
var decoded = {};
|
||||
|
||||
console.log('Block255', bin);
|
||||
manID = app.manufactureDecoder.getManID(bin);
|
||||
|
||||
console.log('ManID:', manID);
|
||||
|
||||
cid = '0x' + manID;
|
||||
|
||||
company = bt_company_ids.find(cid);
|
||||
|
||||
switch (manID) {
|
||||
case '004C': {
|
||||
decoded = app.manufactureDecoder.decodeIbeacon(bin);
|
||||
decoded.company = company;
|
||||
break;
|
||||
}
|
||||
case '1235': {
|
||||
decoded = app.manufactureDecoder.decodeSiliconLabsSensorPuck(bin);
|
||||
decoded.company = company;
|
||||
break;
|
||||
|
||||
}
|
||||
case '0060': {
|
||||
decoded = app.manufactureDecoder.decodeSansible(bin);
|
||||
decoded.company = company;
|
||||
break;
|
||||
|
||||
}
|
||||
default: {
|
||||
console.log('Unknown manID: ', manID);
|
||||
decoded = {company: company};
|
||||
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
}, makeHexBuffer: function(buffer) {
|
||||
'use strict';
|
||||
return buffer.map(function(i) {
|
||||
return ('00' + i.toString(16)).slice(-2) + ',';
|
||||
});
|
||||
}, makeChars: function(buffer) {
|
||||
'use strict';
|
||||
return buffer.map(function(i) {
|
||||
return String.fromCharCode(i);
|
||||
});
|
||||
}, calculateDistance: function(txPower, rssi) {
|
||||
|
||||
// If there is 0 txPower then default it to -12dBm which appears to be a general default.
|
||||
|
||||
var _txPower = (txPower !== 0) ? txPower : -12;
|
||||
|
||||
var ratio_db = _txPower - rssi;
|
||||
var ratio_linear = Math.pow(10, ratio_db / 10);
|
||||
|
||||
return Math.sqrt(ratio_linear);
|
||||
|
||||
}, /**
|
||||
*
|
||||
* @param device
|
||||
* @param device.rssi
|
||||
* @param device.otherData
|
||||
* @param device.id
|
||||
* @param device.name
|
||||
* @param device.rssiBuffer
|
||||
* @returns {jQuery|HTMLElement|*}
|
||||
*/
|
||||
|
||||
buildNewDeviceResultPanel: function(device) {
|
||||
'use strict';
|
||||
var dString;
|
||||
var accuracy;
|
||||
var avg;
|
||||
var sum;
|
||||
var newPanel, newRow;
|
||||
var otherData = device.otherData;
|
||||
var newId = 'd-' + device.id.replace(/:/g, '').split('-')[0];
|
||||
var title = device.hasOwnProperty('name') ? device.name : '*** Unknown';
|
||||
|
||||
newPanel = $('<div>',
|
||||
{id: newId, class: 'mui-panel deviceRow', style: 'min-height:75px;'});
|
||||
|
||||
newRow = $('<div>', {class: 'mui-row'});
|
||||
|
||||
newRow.append($('<div>',
|
||||
{class: 'mui-col-xs-12 mui--text-title', text: device.id}));
|
||||
|
||||
newPanel.append(newRow);
|
||||
|
||||
newRow = $('<div>', {class: 'mui-row'});
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-3', text: 'Name:'}));
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-3', text: title}));
|
||||
|
||||
if (typeof otherData !== 'undefined' && otherData !== null && otherData.hasOwnProperty(
|
||||
'txpower')) {
|
||||
if (device.hasOwnProperty('rssiBuffer') && (device.rssiBuffer.length > 0)) {
|
||||
sum = device.rssiBuffer.reduce(function(a, b) { return a + b; });
|
||||
avg = sum / device.rssiBuffer.length;
|
||||
accuracy = app.calculateDistance(otherData.txpower, avg);
|
||||
} else {
|
||||
accuracy = app.calculateDistance(otherData.txpower, device.rssi);
|
||||
}
|
||||
|
||||
dString = (accuracy <= 30.00) ? accuracy.toFixed(2) + ' m' : 'Far';
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-3', text: 'Distance:'}));
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-3', text: dString}));
|
||||
|
||||
} else {
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-3', text: 'RSSI:'}));
|
||||
newRow.append($('<div>',
|
||||
{class: 'mui-col-xs-3', text: device.rssi + ' dB'}));
|
||||
|
||||
}
|
||||
|
||||
newPanel.append(newRow);
|
||||
|
||||
if (typeof otherData !== 'undefined' && otherData !== null) {
|
||||
if (otherData.hasOwnProperty('msg')) {
|
||||
newRow = $('<div>', {class: 'mui-row'});
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-3', text: 'Details:'}));
|
||||
newRow.append($('<div>', {class: 'mui-col-xs-8', text: otherData.msg}));
|
||||
newPanel.append(newRow);
|
||||
}
|
||||
}
|
||||
|
||||
return newPanel;
|
||||
}, extractPData: function(prev) {
|
||||
'use strict';
|
||||
|
||||
if (typeof prev === 'undefined' || prev === null) {
|
||||
return {};
|
||||
}
|
||||
return prev.pData;
|
||||
|
||||
}, extractRSSIBuffer: function(prev) {
|
||||
'use strict';
|
||||
|
||||
if (typeof prev === 'undefined' || prev === null) {
|
||||
return [];
|
||||
}
|
||||
return prev.rssiBuffer;
|
||||
|
||||
},
|
||||
|
||||
processPData: function(newData, oldData) {
|
||||
'use strict';
|
||||
var output = {};
|
||||
var wa = [];
|
||||
if (newData === null || newData.data === null) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (var key in newData.data) {
|
||||
|
||||
if (newData.data.hasOwnProperty(key)) {
|
||||
|
||||
if (Object.keys(oldData).indexOf(key) !== -1) {
|
||||
wa = oldData[key];
|
||||
}
|
||||
|
||||
if (wa.length === 99) {
|
||||
wa = wa.slice(1);
|
||||
}
|
||||
|
||||
wa.push(newData.data[key]);
|
||||
|
||||
output[key] = wa;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}, processRSSIData: function(rssi, oldBuffer) {
|
||||
'use strict';
|
||||
if (typeof oldBuffer === 'undefined' || oldBuffer === null) {
|
||||
return [];
|
||||
}
|
||||
var wa = oldBuffer;
|
||||
|
||||
if (wa.length === 10) {
|
||||
wa = wa.slice(1);
|
||||
}
|
||||
|
||||
wa.push(rssi);
|
||||
|
||||
return wa;
|
||||
}, doScan: function(mode) {
|
||||
'use strict';
|
||||
app.mode = mode;
|
||||
$('#ripple').show();
|
||||
if (mode !== 2) {
|
||||
$('#tbody').empty();
|
||||
}
|
||||
|
||||
ble.startScan([], app.foundDevice.bind(this), function(e) {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
var _t = [5000, 60000, 200][mode];
|
||||
|
||||
setTimeout(ble.stopScan, _t, app.scanComplete, function() {
|
||||
console.log('stopScan failed');
|
||||
$('#ripple').hide();
|
||||
});
|
||||
|
||||
}, populateObject: function(source, dest) {
|
||||
var rObj = dest;
|
||||
for (var item in source) {
|
||||
if (source.hasOwnProperty(item)) {
|
||||
rObj[item] = source[item];
|
||||
}
|
||||
}
|
||||
|
||||
return rObj;
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param device
|
||||
* @param device.advertising
|
||||
* @param device.rssi
|
||||
* @param device.id
|
||||
*/
|
||||
|
||||
foundDevice: function(device) {
|
||||
var rssiBuffer;
|
||||
var oldRSSIBuffer;
|
||||
var newPData;
|
||||
var oldPdata;
|
||||
var parsed;
|
||||
var hexBuffer;
|
||||
var advertBuffer;
|
||||
var newTR;
|
||||
var newId = 'd-' + device.id.replace(/:/g, '').split('-')[0];
|
||||
var _device = app.foundDevices[newId] || {};
|
||||
var $newID;
|
||||
var otherData;
|
||||
|
||||
_device = app.populateObject(device, _device);
|
||||
// _device.pData = {};
|
||||
|
||||
otherData = null;
|
||||
this.list[newId] = _device.id;
|
||||
|
||||
if (_device.hasOwnProperty('advertising')) {
|
||||
|
||||
advertBuffer = app.arrayBufferToIntArray(_device.advertising);
|
||||
|
||||
hexBuffer = app.makeHexBuffer(advertBuffer);
|
||||
|
||||
parsed = app.parseAdvertisingData(advertBuffer);
|
||||
|
||||
if (parsed.hasOwnProperty('9')) {
|
||||
|
||||
var name = app.makeChars(parsed['9']);
|
||||
|
||||
_device.name = name.join('');
|
||||
console.log('Name: ', name.join(''));
|
||||
|
||||
}
|
||||
|
||||
if (parsed.hasOwnProperty('255')) {
|
||||
|
||||
otherData = app.handle255(parsed['255']);
|
||||
console.log(otherData);
|
||||
_device.otherData = otherData;
|
||||
}
|
||||
_device.advertBuffer = advertBuffer;
|
||||
_device.hexBuffer = hexBuffer;
|
||||
_device.parsed = parsed;
|
||||
}
|
||||
|
||||
// OldPdata = app.extractPData(app.log[newId]);
|
||||
oldPdata = app.extractPData(_device);
|
||||
|
||||
newPData = app.processPData(otherData, oldPdata);
|
||||
|
||||
// OldRSSIBuffer = app.extractRSSIBuffer(app.log[newId]);
|
||||
oldRSSIBuffer = app.extractRSSIBuffer(_device);
|
||||
rssiBuffer = app.processRSSIData(_device.rssi, oldRSSIBuffer);
|
||||
|
||||
_device.pData = newPData;
|
||||
_device.rssiBuffer = rssiBuffer;
|
||||
|
||||
newTR = app.buildNewDeviceResultPanel(_device);
|
||||
|
||||
$newID = $('div#' + newId);
|
||||
if ($newID.length > 0) {
|
||||
$newID.replaceWith(newTR);
|
||||
} else {
|
||||
$('#scanResults').append(newTR);
|
||||
}
|
||||
|
||||
app.log[newId] = _device;
|
||||
app.foundDevices[newId] = _device;
|
||||
|
||||
console.log(JSON.stringify(_device));
|
||||
|
||||
}, scanComplete: function() {
|
||||
console.log('Scan complete');
|
||||
|
||||
if (app.mode === 1) {
|
||||
app.saveLog();
|
||||
$('#ripple').hide();
|
||||
}
|
||||
|
||||
if (app.mode === 2) {
|
||||
if (!app.stop) {
|
||||
setTimeout(function() {
|
||||
app.doScan(2);
|
||||
}.bind(this), 200);
|
||||
} else {
|
||||
app.saveLog();
|
||||
$('#ripple').hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, writeFile: function(fileEntry, dataObj) {
|
||||
// Create a FileWriter object for our FileEntry (log.txt).
|
||||
fileEntry.createWriter(function(fileWriter) {
|
||||
|
||||
fileWriter.onwriteend = function() {
|
||||
console.log('Successful file write...');
|
||||
// ReadFile(fileEntry);
|
||||
};
|
||||
|
||||
fileWriter.onerror = function(e) {
|
||||
console.error('Failed file write: ' + e.toString());
|
||||
};
|
||||
|
||||
// If data object is not passed in,
|
||||
// create a new Blob instead.
|
||||
if (!dataObj) {
|
||||
dataObj = new Blob(['some file data'], {type: 'text/plain'});
|
||||
}
|
||||
|
||||
fileWriter.write(dataObj);
|
||||
});
|
||||
}, saveLog: function() {
|
||||
'use strict';
|
||||
var dt = new Date().toISOString().replace(/:|-/g, '').replace(/(\.\w+)/g,
|
||||
'');
|
||||
var payload = JSON.stringify(app.log);
|
||||
var filename = 'sensortoy-' + dt + '.json';
|
||||
|
||||
// Var dataObj = new Blob(payload, { type: 'text/plain' });
|
||||
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
|
||||
|
||||
console.log('file system open: ' + fs.name);
|
||||
fs.root.getFile(filename,
|
||||
{create: true, exclusive: false},
|
||||
function(fileEntry) {
|
||||
|
||||
console.log('fileEntry is file?' + fileEntry.isFile.toString());
|
||||
// FileEntry.name == 'someFile.txt'
|
||||
// fileEntry.fullPath == '/someFile.txt'
|
||||
console.log('Path: ', fileEntry.fullPath);
|
||||
app.writeFile(fileEntry, payload);
|
||||
|
||||
app.log = [];
|
||||
|
||||
},
|
||||
app.onError);
|
||||
|
||||
}, app.onError);
|
||||
}, forceStop: function() {
|
||||
'use strict';
|
||||
app.stop = true;
|
||||
$('#scan').show();
|
||||
$('#stop').hide();
|
||||
},
|
||||
|
||||
// Bind Event Listeners
|
||||
//
|
||||
// Bind any events that are required on startup. Common events are:
|
||||
// 'load', 'deviceready', 'offline', and 'online'.
|
||||
bindEvents: function() {
|
||||
var self = this;
|
||||
document.addEventListener('deviceready', this.onDeviceReady, false);
|
||||
$('#scan').on('click', function() {
|
||||
'use strict';
|
||||
this.stop = false;
|
||||
this.doScan(2);
|
||||
$('#scan').hide();
|
||||
$('#stop').show();
|
||||
}.bind(this));
|
||||
|
||||
$('#stop').on('click', function() {
|
||||
'use strict';
|
||||
app.forceStop();
|
||||
|
||||
}.bind(this));
|
||||
|
||||
$('#longScan').on('click', function() {
|
||||
'use strict';
|
||||
this.doScan(1);
|
||||
}.bind(this));
|
||||
|
||||
$('#scanResults').on('click', 'div.mui-panel.deviceRow', function() {
|
||||
'use strict';
|
||||
var tID = $(this).context.id;
|
||||
var id = self.list[tID];
|
||||
|
||||
console.log(tID, id);
|
||||
|
||||
app.forceStop();
|
||||
self.connect(id);
|
||||
});
|
||||
|
||||
}, addTab: function(tID) {
|
||||
var appTabs = $('#app-tabs');
|
||||
var panes = $('#tab-panes');
|
||||
|
||||
var paneID = 'pane-' + tID;
|
||||
|
||||
var _device = app.foundDevices[tID];
|
||||
var _name = _device.name || _device.id;
|
||||
|
||||
console.log('Found:', _device);
|
||||
|
||||
$('<div>', {class: 'mui-tabs__pane', id: paneID}).appendTo(panes);
|
||||
|
||||
var li = $('<li>').append($('<a>',
|
||||
{'data-mui-toggle': 'tab', 'data-mui-controls': paneID, text: _name}));
|
||||
|
||||
appTabs.append(li);
|
||||
|
||||
return paneID;
|
||||
|
||||
},
|
||||
|
||||
// Deviceready Event Handler
|
||||
//
|
||||
// The scope of 'this' is the event. In order to call the 'receivedEvent'
|
||||
// function, we must explicitly call 'app.receivedEvent(...);'
|
||||
onDeviceReady: function() {
|
||||
|
||||
},
|
||||
|
||||
doAnimate: function() {
|
||||
for (var item in app.activeServices) {
|
||||
if (app.activeServices.hasOwnProperty(item)) {
|
||||
var activeService = app.activeServices[item];
|
||||
for (var t = 0; t < activeService.length; t++) {
|
||||
activeService[t].animateGraph();
|
||||
}
|
||||
}
|
||||
}
|
||||
window.requestAnimFrame(app.doAnimate.bind(this));
|
||||
}, connect: function(deviceId) {
|
||||
|
||||
$('#results').slideUp();
|
||||
console.log('Connect to ', deviceId);
|
||||
|
||||
var tID = 'd-' + deviceId.replace(/:/g, '').split('-')[0];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param a
|
||||
* @param a.services
|
||||
*/
|
||||
var onConnect = function(a) {
|
||||
var services = [];
|
||||
|
||||
services = a.services;
|
||||
|
||||
console.log('Searching services for ', tID);
|
||||
var usedServices = [];
|
||||
|
||||
var target = app.addTab(tID);
|
||||
|
||||
var _params = {
|
||||
deviceID: deviceId, target: target
|
||||
};
|
||||
|
||||
for (var t = 0; t < services.length; t++) {
|
||||
|
||||
var ident = services[t].toUpperCase();
|
||||
|
||||
var SERVICE = capabilityManager.discover(ident);
|
||||
|
||||
if (SERVICE !== null) {
|
||||
|
||||
var newService = new SERVICE(_params);
|
||||
newService.startService();
|
||||
usedServices.push(newService);
|
||||
} else {
|
||||
console.error('Unknown service: ', ident);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app.activeServices[tID] = usedServices;
|
||||
|
||||
mui.tabs.activate(target);
|
||||
window.requestAnimFrame(app.doAnimate.bind(this));
|
||||
};
|
||||
|
||||
if (!app.activeServices.hasOwnProperty(tID)) {
|
||||
|
||||
ble.connect(deviceId, onConnect, function(e) {
|
||||
'use strict';
|
||||
console.log(e);
|
||||
console.error(e);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}, onError: function(reason) {
|
||||
console.error('ERROR: ' + reason); // Real apps should use notification.alert
|
||||
}
|
||||
};
|
||||
|
||||
window.requestAnimFrame = (function() {
|
||||
return window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
function(callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
};
|
||||
})();
|
||||
|
||||
app.initialize();
|
@ -1,112 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-24
|
||||
* Time: 14:21
|
||||
*
|
||||
*/
|
||||
|
||||
/* global MANUFACTUREDECODER */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var MANUFACTUREDECODER = function() {
|
||||
'use strict';
|
||||
|
||||
this.getManID = function(data) {
|
||||
return ('0000' + ((data[1] << 8) | data[0]).toString(16)).slice(-4).toUpperCase();
|
||||
};
|
||||
|
||||
this.decodeIbeacon = function(data) {
|
||||
|
||||
// https://support.kontakt.io/hc/en-gb/articles/201492492-iBeacon-advertising-packet-structure
|
||||
var bin = data;
|
||||
var obj = { msg: '(iBeacon)'};
|
||||
// Obj.manID = ('0000' + ((bin[1] << 8) | bin[0]).toString(16)).slice(-4);
|
||||
obj.manID = this.getManID(bin);
|
||||
var uuid = [];
|
||||
if (bin[2] === 2) {
|
||||
uuid.push(bin[4].toString(16) + bin[5].toString(16) + bin[6].toString(16) + bin[7].toString(16)) ;
|
||||
|
||||
uuid.push(bin[8].toString(16) + bin[9].toString(16)) ;
|
||||
uuid.push(bin[10].toString(16) + bin[11].toString(16)) ;
|
||||
uuid.push(bin[12].toString(16) + bin[13].toString(16)) ;
|
||||
|
||||
var p4 = bin[14].toString(16);
|
||||
p4 = p4 + bin[15].toString(16);
|
||||
p4 = p4 + bin[16].toString(16);
|
||||
p4 = p4 + bin[17].toString(16);
|
||||
p4 = p4 + bin[18].toString(16);
|
||||
p4 = p4 + bin[19].toString(16);
|
||||
|
||||
uuid.push(p4);
|
||||
obj.uuid = uuid.join('-');
|
||||
}
|
||||
|
||||
if (bin[2] === 9) {
|
||||
// This looks like an ip address?
|
||||
var ipaddy = [];
|
||||
ipaddy.push(bin[6]);
|
||||
ipaddy.push(bin[7]);
|
||||
ipaddy.push(bin[8]);
|
||||
ipaddy.push(bin[9]);
|
||||
|
||||
obj.ipaddress = ipaddy.join('.');
|
||||
obj.msg = obj.msg + ' IP:' + obj.ipaddress;
|
||||
}
|
||||
|
||||
if (bin[2] === 12) {
|
||||
|
||||
|
||||
var output = bin.map(function(i) {
|
||||
|
||||
return ('0000' + i.toString(16)).slice(-2) + '';
|
||||
});
|
||||
|
||||
obj.secureUUID = output.join('');
|
||||
|
||||
}
|
||||
|
||||
var signedByte = new Int8Array(1);
|
||||
signedByte[0] = bin[24];
|
||||
obj.txpower = signedByte[0];
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
this.decodeSiliconLabsSensorPuck = function(data) {
|
||||
var bin = data;
|
||||
var obj = {data: {}};
|
||||
obj.manID = this.getManID(bin);
|
||||
obj.a = (bin[3] << 8) | bin[2];
|
||||
obj.b = (bin[5] << 8) | bin[4];
|
||||
obj.data.humidity = (bin[7] << 8) | bin[6];
|
||||
obj.data.temp = (bin[9] << 8) | bin[8];
|
||||
obj.c = (bin[11] << 8) | bin[10];
|
||||
obj.d = (bin[13] << 8) | bin[12];
|
||||
|
||||
obj.msg = 'Humidity: ' + (obj.data.humidity / 10) + ', temp: ' + (obj.data.temp / 10);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
this.decodeSansible = function(data) {
|
||||
var bin = data;
|
||||
var obj = {data: {}};
|
||||
obj.manID = this.getManID(bin);
|
||||
|
||||
obj.data.p1 = ((bin[2] << 16) | bin[3] << 8 | bin[4]);
|
||||
obj.data.p2 = ((bin[5] << 16) | bin[6] << 8 | bin[7]);
|
||||
|
||||
obj.msg = 'Left: ' + (obj.data.p1 / 100) + ' hPa, Right: ' + (obj.data.p2 / 100) + ' hPa';
|
||||
return obj;
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
@ -1,61 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var BATTERY = function() {
|
||||
this.name = 'Battery';
|
||||
this.capabilityID = '180F';
|
||||
this.serviceDef = {
|
||||
service: '180F', level: '2A19'
|
||||
};
|
||||
|
||||
this.onBatteryLevelChange = function(data) {
|
||||
console.log(data);
|
||||
var a = new Uint8Array(data);
|
||||
this.state = a[0];
|
||||
console.log('onBatteryLevelChange', this.state);
|
||||
};
|
||||
this.readBatteryState = function() {
|
||||
console.log('readBatteryState');
|
||||
ble.read(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.level,
|
||||
this.onReadBatteryLevel.bind(this),
|
||||
this.onError);
|
||||
};
|
||||
|
||||
this.onReadBatteryLevel = function(data) {
|
||||
console.log(data);
|
||||
var a = new Uint8Array(data);
|
||||
this.state = a[0];
|
||||
console.log('onReadBatteryLevel', this.state);
|
||||
};
|
||||
|
||||
this.startService = function() {
|
||||
'use strict';
|
||||
if (this.deviceID !== null) {
|
||||
console.log('Starting Battery Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
|
||||
this.insertFrame();
|
||||
|
||||
ble.startNotification(this.deviceID,
|
||||
this.serviceDef.service,
|
||||
this.serviceDef.level,
|
||||
this.onBatteryLevelChange.bind(this),
|
||||
this.onError);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inheritsFrom(BATTERY, CAPABILITY);
|
||||
capabilityManager.register({id: '180F', module: BATTERY});
|
File diff suppressed because it is too large
Load Diff
@ -1,99 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:13
|
||||
*
|
||||
*/
|
||||
/* global CAPABILITY, inheritsFrom, capabilityManager */
|
||||
/* global ble */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
var BUTTON = function(p) {
|
||||
'use strict';
|
||||
this.name = 'Button';
|
||||
this.deviceID = p.deviceID || null;
|
||||
this.target = p.target || null;
|
||||
|
||||
this.capabilityID = 'FFE0';
|
||||
this.serviceDef = {
|
||||
service: 'FFE0',
|
||||
data: 'FFE1' // Bit 2: side key, Bit 1- right key, Bit 0 –left key
|
||||
};
|
||||
|
||||
this.buttonMatrix = {
|
||||
LEFT_BUTTON: 1, // 0001
|
||||
RIGHT_BUTTON: 2, // 0010
|
||||
REED_SWITCH: 4 // 0100
|
||||
};
|
||||
|
||||
this.setFrame();
|
||||
|
||||
this.onButtonData = function(data) {
|
||||
console.log('+ onButtonData');
|
||||
console.log(data);
|
||||
var state = new Uint8Array(data);
|
||||
var message = '';
|
||||
|
||||
if (state === 0) {
|
||||
message = 'No buttons are pressed.';
|
||||
}
|
||||
|
||||
if (state & this.buttonMatrix.LEFT_BUTTON) {
|
||||
message += 'Left button is pressed. ';
|
||||
}
|
||||
|
||||
if (state & this.buttonMatrix.RIGHT_BUTTON) {
|
||||
message += 'Right button is pressed.';
|
||||
}
|
||||
|
||||
if (state & this.buttonMatrix.REED_SWITCH) {
|
||||
message += 'Reed switch is activated.<br/>';
|
||||
}
|
||||
|
||||
this.state = message;
|
||||
|
||||
if (this.$result !== null) {
|
||||
this.$result.text(this.state);
|
||||
}
|
||||
console.log('ButtonState: ', this.state);
|
||||
|
||||
console.log('- onButtonData');
|
||||
};
|
||||
|
||||
this.startService = function() {
|
||||
if (this.deviceID !== null) {
|
||||
|
||||
console.log('Starting Button Service on ', this.deviceID);
|
||||
console.log(this.serviceDef);
|
||||
ble.startNotification(this.deviceID, this.serviceDef.service, this.serviceDef.data, this.onButtonData.bind(this), this.onError);
|
||||
|
||||
}
|
||||
|
||||
this.insertFrame();
|
||||
};
|
||||
|
||||
this.insertFrame = function() {
|
||||
|
||||
var self = this;
|
||||
console.log('Overloading...');
|
||||
// Call the parent displayForm first...
|
||||
this.superClass_.insertFrame.call(self);
|
||||
|
||||
var detail = this.frameID + '-d';
|
||||
var row = $('<div />', {class: 'mui-row'});
|
||||
|
||||
$('<div />', { class: 'mui-col-xs-4 mui--text-accent', text: 'Status:'}).appendTo(row);
|
||||
|
||||
$('<div />', { class: 'mui-col-xs-8 mui--text-dark', id: detail}).appendTo(row);
|
||||
|
||||
this.$id.append(row);
|
||||
this.$result = $('#' + detail);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
inheritsFrom(BUTTON, CAPABILITY);
|
||||
capabilityManager.register({id: 'FFE0', module: BUTTON});
|
@ -1,397 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-05-20
|
||||
* Time: 10:32
|
||||
*
|
||||
*/
|
||||
|
||||
/* global inheritsFrom */
|
||||
/* jshint browser: true , devel: true*/
|
||||
|
||||
'use strict';
|
||||
var capabilityManager = {
|
||||
capabilityList: [],
|
||||
register: function(details) {
|
||||
console.log('Registered:', details);
|
||||
this.capabilityList.push(details);
|
||||
},
|
||||
discover: function(id) {
|
||||
|
||||
var wanted = this.capabilityList.filter(function(obj) {
|
||||
return obj.id === id;
|
||||
});
|
||||
|
||||
return wanted.length === 1 ? wanted[0].module : null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var CAPABILITY = function(p) {
|
||||
this.name = '-CAPABILITY-';
|
||||
this.capabilityID = p.capabilityID || null;
|
||||
this.state = '';
|
||||
this.serviceDef = p.service || null;
|
||||
|
||||
this.internalID = null;
|
||||
this.frameID = null;
|
||||
this.$id = null;
|
||||
|
||||
this.deviceID = null;
|
||||
|
||||
this.data = [];
|
||||
this.ctx = null;
|
||||
this.first = false;
|
||||
|
||||
this.target = null;
|
||||
this.$frame = null;
|
||||
|
||||
this.previousCeil = 0;
|
||||
|
||||
capabilityManager.register({id: this.capabilityID, module: this});
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.setFrame = function() {
|
||||
this.$frame = (this.target !== null) ? $('#' + this.target) : null;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.setInternalID = function() {
|
||||
this.internalID = (Math.floor(Math.random() * 60000) + 1).toString(36);
|
||||
this.frameID = 'f-' + this.internalID;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.setDeviceID = function(dID) {
|
||||
this.deviceID = dID;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.getDeviceID = function() {
|
||||
return this.deviceID ;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.insertFrame = function() {
|
||||
|
||||
this.setInternalID();
|
||||
|
||||
console.log('FrameID: ' , this.frameID);
|
||||
|
||||
var title = [this.name, ' - ', this.deviceID].join(' ');
|
||||
|
||||
var frame = $('<div />', {
|
||||
class: 'mui-panel',
|
||||
id: this.frameID});
|
||||
|
||||
$('<div />', { class: 'mui-row'}).append($('<div />', { class: 'mui-col-xs-12 mui--text-title', text: title})).appendTo(frame);
|
||||
|
||||
this.$frame.append(frame);
|
||||
this.$id = $('#' + this.frameID);
|
||||
};
|
||||
|
||||
|
||||
CAPABILITY.prototype.inherits = function(a, b) {
|
||||
var C = function() {};
|
||||
C.prototype = b.prototype;
|
||||
a.superClass_ = b.prototype;
|
||||
a.prototype = new C;
|
||||
a.prototype.constructor = a;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.onError = function(e) {
|
||||
console.error(e);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param alt
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
CAPABILITY.prototype.storeData = function(data, alt) {
|
||||
|
||||
if (!this.first) {
|
||||
this.first = true;
|
||||
return [];
|
||||
}
|
||||
var target = alt || this.data;
|
||||
|
||||
if (target.length === 99) {
|
||||
target = target.slice(1);
|
||||
}
|
||||
|
||||
target.push(data);
|
||||
if (alt) {
|
||||
return target;
|
||||
} else {
|
||||
this.data = target;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.startGraph = function(id) {
|
||||
|
||||
var c;
|
||||
c = id[0].getContext('2d');
|
||||
this.ctx = c;
|
||||
|
||||
this.ctx.fillStyle = '#ffffff';
|
||||
this.ctx.fillRect(0,0,300,150);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
CAPABILITY.prototype.generateBlankGraphBase = function(subID) {
|
||||
|
||||
var _subID = subID || '';
|
||||
var xmlns = 'http://www.w3.org/2000/svg';
|
||||
|
||||
var svgID = this.frameID + _subID + '-svg';
|
||||
var text1ID = this.frameID + _subID + '-txt1';
|
||||
|
||||
var svg = document.createElementNS(xmlns,'svg');
|
||||
|
||||
svg.setAttributeNS(xmlns,'id',svgID);
|
||||
svg.setAttributeNS(xmlns,'width','300');
|
||||
svg.setAttributeNS(xmlns,'height','150');
|
||||
svg.setAttributeNS(xmlns,'fill', 'blue');
|
||||
|
||||
|
||||
svg = this.graphAddXAxis(svg,{y: 12, colour: '#004c6d', id: text1ID});
|
||||
svg = this.graphAddXAxis(svg,{y: 136, colour: '#004c6d', text: '0'});
|
||||
|
||||
return svg;
|
||||
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.graphAddXAxis = function(svg, settings) {
|
||||
var xmlns = 'http://www.w3.org/2000/svg';
|
||||
var _svg = svg;
|
||||
var y = settings.y || 0;
|
||||
var y2 = y + 3;
|
||||
var x2 = settings.x2 || 280;
|
||||
var colour = settings.colour || '#ff0000';
|
||||
var id = settings.id;
|
||||
var textContent = settings.text || '-';
|
||||
var lineStyle = ['stroke:',colour,';stroke-width:2;'].join('');
|
||||
var textStyle = ['font-family:"Ubuntu Condensed",sans-serif;font-size:12;fill: ',colour,';text-align:right;'].join('');
|
||||
|
||||
var line = document.createElementNS(xmlns,'line');
|
||||
|
||||
line.setAttributeNS(null,'x1','46');
|
||||
line.setAttributeNS(null,'y1', y);
|
||||
line.setAttributeNS(null,'x2', x2);
|
||||
line.setAttributeNS(null,'y2', y);
|
||||
line.setAttributeNS(null,'style',lineStyle);
|
||||
|
||||
_svg.appendChild(line);
|
||||
|
||||
var text = document.createElementNS(xmlns,'text');
|
||||
|
||||
if (id !== null) {
|
||||
text.setAttributeNS(null,'id',id);
|
||||
}
|
||||
text.setAttributeNS(null,'x','36');
|
||||
text.setAttributeNS(null,'y', y2);
|
||||
text.setAttributeNS(null,'text-anchor', 'end');
|
||||
text.setAttributeNS(null,'style',textStyle);
|
||||
text.textContent = textContent;
|
||||
|
||||
_svg.appendChild(text);
|
||||
|
||||
return _svg;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.graphAddLine = function(svg, lineId, colour) {
|
||||
var xmlns = 'http://www.w3.org/2000/svg';
|
||||
var _svg = svg;
|
||||
|
||||
var polyline = document.createElementNS(xmlns,'polyline');
|
||||
|
||||
polyline.setAttributeNS(null,'id',lineId);
|
||||
polyline.setAttributeNS(null,'fill','none');
|
||||
// Proper '#2196F3'
|
||||
polyline.setAttributeNS(null,'stroke',colour);
|
||||
// #e5f7fd
|
||||
// old #B5C7FF
|
||||
polyline.setAttributeNS(null,'text-anchor', 'end');
|
||||
polyline.setAttributeNS(null,'stroke-width','2');
|
||||
|
||||
_svg.appendChild(polyline);
|
||||
|
||||
return _svg;
|
||||
|
||||
};
|
||||
|
||||
|
||||
CAPABILITY.prototype.generateBlankGraph = function(subID) {
|
||||
|
||||
var _subID = subID || '';
|
||||
var lineID = this.frameID + _subID + '-line';
|
||||
|
||||
var svg = this.generateBlankGraphBase(_subID);
|
||||
|
||||
svg = this.graphAddLine(svg, lineID, '#2196F3');
|
||||
|
||||
return svg;
|
||||
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.animateGraph = function() {
|
||||
// This.simpleGraph(this.data);
|
||||
};
|
||||
|
||||
|
||||
CAPABILITY.prototype.polarToCartesian = function(centerX, centerY, radius, angleInDegrees) {
|
||||
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
|
||||
|
||||
return {
|
||||
x: centerX + (radius * Math.cos(angleInRadians)),
|
||||
y: centerY + (radius * Math.sin(angleInRadians))
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
CAPABILITY.prototype.describeArc = function(x, y, radius, startAngle, endAngle) {
|
||||
|
||||
var start = this.polarToCartesian(x, y, radius, endAngle);
|
||||
var end = this.polarToCartesian(x, y, radius, startAngle);
|
||||
|
||||
var arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
|
||||
|
||||
var d = [
|
||||
'M', start.x, start.y,
|
||||
'A', radius, radius, 0, arcSweep, 0, end.x, end.y
|
||||
].join(' ');
|
||||
|
||||
return d;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.setArc = function(percent) {
|
||||
return (240 / 100) * percent;
|
||||
};
|
||||
|
||||
CAPABILITY.prototype.updateArc = function(data, subID, elmID, suffix, limiter) {
|
||||
|
||||
|
||||
var ceilingLimit;
|
||||
var ceiling;
|
||||
var _subID;
|
||||
var _data;
|
||||
var _limiter = limiter || null;
|
||||
var _suffix = suffix || '';
|
||||
var label;
|
||||
|
||||
_data = data || this.data;
|
||||
|
||||
_subID = subID || '';
|
||||
label = '#' + this.frameID + _subID + '-label';
|
||||
|
||||
if (_data.length > 0) {
|
||||
|
||||
if (_limiter === null) {
|
||||
ceiling = _data.reduce(function(p, v) {
|
||||
return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v));
|
||||
});
|
||||
|
||||
ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 10) * 10);
|
||||
if (ceilingLimit > 1000) {
|
||||
ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 50) * 50);
|
||||
}
|
||||
|
||||
} else {
|
||||
ceilingLimit = _limiter;
|
||||
}
|
||||
|
||||
var latest = _data[_data.length - 1];
|
||||
var scale = 100 / ceilingLimit;
|
||||
var arcP = scale * latest;
|
||||
|
||||
document.getElementById(elmID).setAttribute('d', this.describeArc(150, 150, 100, 0, this.setArc(arcP)));
|
||||
$(label).text(latest.toFixed(2) + _suffix);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
CAPABILITY.prototype.simpleGraph = function(data, subID) {
|
||||
|
||||
var ceilingLimit;
|
||||
var ceiling;
|
||||
var _subID;
|
||||
var _data;
|
||||
var text1ID;
|
||||
var lineID;
|
||||
|
||||
_data = data || this.data;
|
||||
|
||||
_subID = subID || '';
|
||||
|
||||
lineID = [this.frameID , _subID , '-line'].join('');
|
||||
text1ID = [this.frameID , _subID , '-txt1'].join('');
|
||||
|
||||
if (_data.length > 0) {
|
||||
|
||||
ceiling = _data.reduce(function(p, v) {
|
||||
return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v));
|
||||
});
|
||||
|
||||
|
||||
/* Var floor = _data.reduce(function(p, v) {
|
||||
return (p < v ? p : v);
|
||||
});
|
||||
*/
|
||||
|
||||
var calcArray = [];
|
||||
|
||||
/*
|
||||
Var ceilingLimit = Math.floor(ceiling / 10) * 10;
|
||||
if (ceilingLimit < ceiling) {
|
||||
ceilingLimit = Math.floor((ceiling + (ceiling * 0.25)) / 10) * 10;
|
||||
}
|
||||
|
||||
if (ceilingLimit < 30) {
|
||||
ceilingLimit = 30;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 10) * 10);
|
||||
if (ceilingLimit > 1000) {
|
||||
ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 50) * 50);
|
||||
}
|
||||
|
||||
var scale = 124 / ceilingLimit;
|
||||
// Var xstep = (280 - 46) / 100;
|
||||
var xstep = 2.34;
|
||||
var startX = 46 + (100 - _data.length) * xstep;
|
||||
|
||||
for (var x = 0;x < _data.length;x++) {
|
||||
|
||||
calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (136 - ((_data[x]) * scale)).toFixed(2));
|
||||
|
||||
}
|
||||
|
||||
var elm = document.getElementById(lineID);
|
||||
|
||||
elm.setAttribute('points',calcArray.join(' '));
|
||||
|
||||
elm = document.getElementById(text1ID);
|
||||
|
||||
elm.textContent = ceilingLimit;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
var inheritsFrom = function(a, b) {
|
||||
var C = function() {};
|
||||
C.prototype = b.prototype;
|
||||
a.superClass_ = b.prototype;
|
||||
a.prototype = new C;
|
||||
a.prototype.constructor = a;
|
||||
a.prototype.superClass_ = b.prototype;
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-06-01
|
||||
* Time: 13:30
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param p
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
var GADGET = function(p) {
|
||||
'use strict';
|
||||
|
||||
|
||||
this._gadget = p;
|
||||
|
||||
};
|
@ -1 +0,0 @@
|
||||
[http://bluebirdjs.com/docs/api-reference.html](http://bluebirdjs.com/docs/api-reference.html)
|
@ -1,9 +0,0 @@
|
||||
|
||||
# Questions and issues
|
||||
|
||||
Please see [The Support Page](http://bluebirdjs.com/docs/support.html)
|
||||
The [github issue tracker](https://github.com/petkaantonov/bluebird/issues) is **_only_** for bug reports and feature requests.
|
||||
|
||||
# Contributing to the library
|
||||
|
||||
Contributions are welcome and appreciated. See the [Contribution Page](http://bluebirdjs.com/docs/contribute.html) on bluebirdjs.com
|
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 Petka Antonov
|
||||
|
||||
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.
|
@ -1,51 +0,0 @@
|
||||
<a href="http://promisesaplus.com/">
|
||||
<img src="http://promisesaplus.com/assets/logo-small.png" alt="Promises/A+ logo"
|
||||
title="Promises/A+ 1.1 compliant" align="right" />
|
||||
</a>
|
||||
[![Build Status](https://travis-ci.org/petkaantonov/bluebird.svg?branch=master)](https://travis-ci.org/petkaantonov/bluebird)
|
||||
[![coverage-98%](http://img.shields.io/badge/coverage-98%-brightgreen.svg?style=flat)](http://petkaantonov.github.io/bluebird/coverage/debug/index.html)
|
||||
|
||||
**Got a question?** Join us on [stackoverflow](http://stackoverflow.com/questions/tagged/bluebird), the [mailing list](https://groups.google.com/forum/#!forum/bluebird-js) or chat on [IRC](https://webchat.freenode.net/?channels=#promises)
|
||||
|
||||
# Introduction
|
||||
|
||||
Bluebird is a fully featured promise library with focus on innovative features and performance
|
||||
|
||||
See the [**bluebird website**](http://bluebirdjs.com/docs/getting-started.html) for further documentation, references and instructions. See the [**API reference**](http://bluebirdjs.com/docs/api-reference.html) here.
|
||||
|
||||
For bluebird 2.x documentation and files, see the [2.x tree](https://github.com/petkaantonov/bluebird/tree/2.x).
|
||||
|
||||
# Questions and issues
|
||||
|
||||
The [github issue tracker](https://github.com/petkaantonov/bluebird/issues) is **_only_** for bug reports and feature requests. Anything else, such as questions for help in using the library, should be posted in [StackOverflow](http://stackoverflow.com/questions/tagged/bluebird) under tags `promise` and `bluebird`.
|
||||
|
||||
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to BrowserStack for providing us with a free account which lets us support old browsers like IE8.
|
||||
|
||||
# License
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2016 Petka Antonov
|
||||
|
||||
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.
|
||||
|
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
./build --release --no-debug
|
||||
benchmark=$1
|
||||
nodepath=${2:-node}
|
||||
shift 2;
|
||||
cwd=${PWD}
|
||||
|
||||
trap 'cd "$cwd"' EXIT
|
||||
|
||||
if [ "$benchmark" = "doxbee" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "Doxbee sequential"
|
||||
$nodepath performance.js --n 10000 --t 1 ./doxbee-sequential/*.js --harmony "$@"
|
||||
exit 0
|
||||
elif [ "$benchmark" = "doxbee-errors" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "Doxbee sequential with 10% errors"
|
||||
$nodepath performance.js --n 10000 --t 1 --e 0.1 ./doxbee-sequential-errors/*.js --harmony "$@"
|
||||
exit 0
|
||||
elif [ "$benchmark" = "parallel" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "Madeup parallel"
|
||||
$nodepath performance.js --n 10000 --t 1 --p 25 ./madeup-parallel/*.js --harmony "$@"
|
||||
exit 0
|
||||
elif [ "$benchmark" = "analysis" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "analysis"
|
||||
$nodepath performance.js --n 10000 --t 1 ./analysis/*.js --harmony "$@"
|
||||
exit 0
|
||||
else
|
||||
echo "Invalid benchmark name $benchmark"
|
||||
exit -1
|
||||
fi
|
@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "bluebird",
|
||||
"version": "3.4.0",
|
||||
"homepage": "https://github.com/petkaantonov/bluebird",
|
||||
"authors": [
|
||||
"Petka Antonov <petka_antonov@hotmail.com>"
|
||||
],
|
||||
"description": "Bluebird is a full featured promise library with unmatched performance.",
|
||||
"main": "js/browser/bluebird.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"benchmark",
|
||||
"bower_components",
|
||||
"./browser",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
"keywords": [
|
||||
"promise",
|
||||
"performance",
|
||||
"promises",
|
||||
"promises-a",
|
||||
"promises-aplus",
|
||||
"async",
|
||||
"await",
|
||||
"deferred",
|
||||
"deferreds",
|
||||
"future",
|
||||
"flow control",
|
||||
"dsl",
|
||||
"fluent interface"
|
||||
]
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
node tools/build.js "$@"
|
@ -1 +0,0 @@
|
||||
[http://bluebirdjs.com/docs/changelog.html](http://bluebirdjs.com/docs/changelog.html)
|
@ -1 +0,0 @@
|
||||
[http://bluebirdjs.com/docs/deprecated-apis.html](http://bluebirdjs.com/docs/deprecated-apis.html)
|
@ -1,8 +0,0 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "jekyll"
|
||||
gem "jekyll-redirect-from"
|
||||
gem "sanitize", '4.0.1'
|
||||
gem "redcarpet"
|
||||
gem "pygments.rb"
|
||||
gem 'wdm', '>= 0.1.0' if Gem.win_platform?
|
@ -1,5 +0,0 @@
|
||||
Requires ruby and [jekyll](http://jekyllrb.com/). See the gem file for dependencies.
|
||||
|
||||
Change directory to `bluebird/docs` and run `jekyll serve`. The docs will be hosted under `/docs` directory in relation to the web root. Typically something like `http://localhost:4000/docs/`
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
name: bluebird
|
||||
description: Bluebird is a fully featured JavaScript promises library with unmatched performance.
|
||||
url: "http://bluebirdjs.com"
|
||||
baseurl: ""
|
||||
title: bluebird
|
||||
timezone: Helsinki/Finland
|
||||
highlighter: pygments
|
||||
exclude:
|
||||
- Gemfile
|
||||
- Gemfile.lock
|
||||
- helpers.rb
|
||||
defaults:
|
||||
- scope:
|
||||
path: docs
|
||||
type: pages
|
||||
values:
|
||||
layout: page
|
||||
markdown: redcarpet
|
||||
redcarpet:
|
||||
extensions:
|
||||
- fenced_code_blocks
|
||||
version: 3.4.0
|
||||
gems:
|
||||
- jekyll-redirect-from
|
||||
destination: ../gh-pages/
|
||||
keep_files:
|
||||
- .git
|
||||
- .gitignore
|
||||
- logo.png
|
||||
- CNAME
|
||||
- coverage
|
||||
safe: false
|
||||
encoding: utf-8
|
||||
host: 0.0.0.0
|
||||
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<div class="post">
|
||||
<article class="post-content">
|
||||
{{ content }}
|
||||
</article>
|
||||
</div>
|
@ -1,136 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!-->
|
||||
<html class="no-js">
|
||||
<!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href='http://fonts.googleapis.com/css?family=Raleway:400,300,200,700,500,100,800,600,900' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
|
||||
<title>{% if page.title %}{{ page.title }} | {{ site.title }}{% else %}{{ site.title }}{% endif %}</title>
|
||||
<meta name="description" content="{% if page.excerpt %}{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.description }}{% endif %}">
|
||||
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ "/css/mono-blue.css" | prepend: site.baseurl }}" type='text/css' />
|
||||
<link rel="stylesheet" href="{{ "/css/hover-min.css" | prepend: site.baseurl }}" media="all">
|
||||
<link rel="stylesheet" href="{{ "/css/main.css" | prepend: site.baseurl }}">
|
||||
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}">
|
||||
<link rel="icon" href="{{ "/img/favicon.png" | prepend: site.baseurl }}" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
<a href="/" class="title">
|
||||
<img src="{{ "/img/logo.png" | prepend: site.baseurl }}" class="hidden-xs" />
|
||||
|
||||
<span class="tagline">bluebird</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse navbar-bluebird navbar-right collapse">
|
||||
<ul class="nav navbar-nav bb-nav">
|
||||
{% if page.path == 'docs/support.md' %}
|
||||
{% assign name = 'support' %}
|
||||
{% elsif page.path == 'docs/install.md' %}
|
||||
{% assign name = 'install' %}
|
||||
{% else %}
|
||||
{% assign name = 'docs' %}
|
||||
{% endif %}
|
||||
|
||||
<li class="{% if name == 'docs' %}active{% endif %}"><a href="{{ "/docs/getting-started.html" | prepend: site.baseurl }}">Docs</a></li>
|
||||
<li class="{% if name == 'support' %}active{% endif %}"><a href="{{ "/docs/support.html" | prepend: site.baseurl }}">Support</a></li>
|
||||
<li class="{% if name == 'install' %}active{% endif %}"><a href="{{ "/docs/install.html" | prepend: site.baseurl }}">Install</a></li>
|
||||
<li><a href="https://github.com/petkaantonov/bluebird/">Github</a></li>
|
||||
</ul>
|
||||
</div><!--/.navbar-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<ul class="nav left-nav">
|
||||
<li><a href="{{ "/docs/getting-started.html" | prepend: site.baseurl }}">Getting Started</a></li>
|
||||
<li><a href="{{ "/docs/features.html" | prepend: site.baseurl }}">Features</a></li>
|
||||
<li><a href="{{ "/docs/changelog.html" | prepend: site.baseurl }}">Changelog</a></li>
|
||||
<li><a href="{{ "/docs/api-reference.html" | prepend: site.baseurl }}"><strong>API Reference</strong></a></li>
|
||||
<li><a href="{{ "/docs/new-in-bluebird-3.html" | prepend: site.baseurl }}"><strong>New in 3.0</strong></a></li>
|
||||
<li><a href="{{ "/docs/warning-explanations.html" | prepend: site.baseurl }}">Warning Explanations</a></li>
|
||||
<li><a href="{{ "/docs/error-explanations.html" | prepend: site.baseurl }}">Error Explanations</a></li>
|
||||
<li><a href="{{ "/docs/contribute.html" | prepend: site.baseurl }}">Contribute</a></li>
|
||||
<li><a href="{{ "/docs/benchmarks.html" | prepend: site.baseurl }}">Benchmarks</a></li>
|
||||
<li><a href="{{ "/docs/deprecated-apis.html" | prepend: site.baseurl }}">Deprecated APIs</a></li>
|
||||
<li><a href="{{ "/docs/download-api-reference.html" | prepend: site.baseurl }}">Download API Reference</a></li>
|
||||
<li><hr></li>
|
||||
<li>Why?
|
||||
<ul class="nav nav-child">
|
||||
<li><a href="{{ "/docs/why-promises.html" | prepend: site.baseurl }}">Why Promises?</a></li>
|
||||
<li><a href="{{ "/docs/why-bluebird.html" | prepend: site.baseurl }}">Why bluebird?</a></li>
|
||||
<li><a href="{{ "/docs/why-performance.html" | prepend: site.baseurl }}">Why Performance?</a></li>
|
||||
<li><a href="{{ "/docs/what-about-generators.html" | prepend: site.baseurl }}">What About Generators?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><hr></li>
|
||||
<li>
|
||||
Tutorials
|
||||
<ul class="nav nav-child">
|
||||
<li><a href="{{ "/docs/async-dialogs.html" | prepend: site.baseurl }}">Async Dialogs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><hr></li>
|
||||
<li>
|
||||
Guides
|
||||
<ul class="nav nav-child">
|
||||
<li><a href="{{ "/docs/beginners-guide.html" | prepend: site.baseurl }}">Beginner's Guide</a></li>
|
||||
<li><a href="{{ "/docs/anti-patterns.html" | prepend: site.baseurl }}">Anti-patterns</a></li>
|
||||
<li><a href="{{ "/docs/working-with-callbacks.html" | prepend: site.baseurl }}">Working with Callbacks</a></li>
|
||||
<li><a href="{{ "/docs/coming-from-other-languages.html" | prepend: site.baseurl }}">Coming from Other Languages</a></li>
|
||||
<li><a href="{{ "/docs/coming-from-other-libraries.html" | prepend: site.baseurl }}">Coming from Other Libraries</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
{% if page.path %}
|
||||
<div class="post-info">
|
||||
<a href="{{ page.path | prepend: "https://github.com/petkaantonov/bluebird/edit/master/docs/" }}">
|
||||
<i class="fa fa-edit"></i>
|
||||
Edit on Github</a>
|
||||
<br>
|
||||
<i>Updated {{ page.path | file_date | date_to_string }}</i>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
{% endif %}
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer></footer>
|
||||
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/bluebird/{{ site.version }}/bluebird.js"></script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-46253177-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,14 +0,0 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
<div class="post">
|
||||
|
||||
<header class="post-header">
|
||||
<h1 class="post-title">{{ page.title }}</h1>
|
||||
</header>
|
||||
|
||||
<article class="post-content">
|
||||
{{ content }}
|
||||
</article>
|
||||
|
||||
</div>
|
@ -1,19 +0,0 @@
|
||||
module Jekyll
|
||||
module MyFilters
|
||||
def file_date(input)
|
||||
File.mtime(input)
|
||||
end
|
||||
|
||||
def check_active(page_path, link_type)
|
||||
if (link_type == "support" and page_path =~ /support/) or
|
||||
(link_type == "install" and page_path =~ /install/) or
|
||||
(link_type == "docs")
|
||||
"active"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Liquid::Template.register_filter(Jekyll::MyFilters)
|
@ -1,55 +0,0 @@
|
||||
require "redcarpet"
|
||||
require "pygments"
|
||||
require_relative "../helpers"
|
||||
|
||||
|
||||
class Redcarpet::Render::HTML
|
||||
def header(title, level)
|
||||
anchor = Helpers.clean(title)
|
||||
|
||||
return <<-eos
|
||||
<h#{level}>
|
||||
<a class="header-anchor"
|
||||
name="#{anchor}"
|
||||
aria-hidden="true"
|
||||
href="##{anchor}"><i class="fa fa-link"></i></a>
|
||||
#{title}
|
||||
</h#{level}>
|
||||
eos
|
||||
end
|
||||
# Hacks to get markdown working inside html blocks ....
|
||||
def block_html(html)
|
||||
html.gsub(/<markdown>([\d\D]+?)<\/markdown>/) {|_|
|
||||
extensions = {fenced_code_blocks: true}
|
||||
renderer = Redcarpet::Markdown.new(WithHighlights, extensions)
|
||||
renderer.render(Regexp.last_match[1])
|
||||
}
|
||||
end
|
||||
|
||||
def link(link, title, content)
|
||||
if link == "unfinished-article"
|
||||
return <<-eos
|
||||
<div class="info-box">
|
||||
This article is partially or completely unfinished.
|
||||
You are welcome to create <a href="https://github.com/petkaantonov/bluebird/edit/master/docs/docs/#{content}.md">pull requests</a>
|
||||
to help completing this article.
|
||||
</div>
|
||||
eos
|
||||
elsif link == "."
|
||||
if content =~ /#\d+/
|
||||
url = "https://github.com/petkaantonov/bluebird/issues/" + content[1..-1]
|
||||
else
|
||||
url = "/docs/api/" + Helpers.clean(content) + ".html"
|
||||
end
|
||||
return "<a href='#{url}'><code>#{content}</code></a>"
|
||||
else
|
||||
return "<a href='#{link}' title='#{title}'>#{content}</a>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class WithHighlights < Redcarpet::Render::HTML
|
||||
def block_code(code, language)
|
||||
Pygments.highlight(code, :lexer => language)
|
||||
end
|
||||
end
|
@ -1,181 +0,0 @@
|
||||
body {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
body > .container {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.navbar-bluebird {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-size: 18px;
|
||||
margin-top: 50px;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
|
||||
.nav {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
.nav.bb-nav > li > a{
|
||||
transition: all 0.3s ease-in-out;
|
||||
border-bottom: 1px solid rgba(0,0,0,0);
|
||||
}
|
||||
.nav.bb-nav > li > a:focus, .nav.bb-nav > li > a:hover,
|
||||
.nav.bb-nav > li.active > a {
|
||||
background-color:initial;
|
||||
border-bottom:1px solid #BE7306;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: #BE7306;
|
||||
}
|
||||
|
||||
.nav.left-nav li a {
|
||||
padding: 2px 0px;
|
||||
font-size: 14px;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
.nav.left-nav li a:focus, .nav.left-nav li a:hover {
|
||||
background: none;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navbar-bluebird li {
|
||||
text-align:center;
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-family: 'Raleway', sans-serif;
|
||||
/*color:#5275B4;*/
|
||||
color: #1B4288;
|
||||
}
|
||||
.api-code-section h2, code, pre {
|
||||
font-family: 'Consolas', 'Lucida Console', 'Courier New', 'monospace'
|
||||
}
|
||||
body {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.icon-bar {
|
||||
background-color:#5275B4;
|
||||
}
|
||||
.promises-showroom .arrow {
|
||||
text-align: center;
|
||||
margin-top: 100px;
|
||||
color:#EC9313;
|
||||
}
|
||||
|
||||
pre{
|
||||
background-color: initial;
|
||||
border: none;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
.promises-showroom .hljs{
|
||||
border-radius: 6px;
|
||||
padding-left: 30px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.take-action{
|
||||
position:relative;
|
||||
min-height:300px;
|
||||
|
||||
}
|
||||
|
||||
.take-action .cloud-bg{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.take-action .action-buttons{
|
||||
position:absolute;
|
||||
top:50%;
|
||||
text-align:center;
|
||||
width:100%;
|
||||
}
|
||||
.btn-bb {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
color: white;
|
||||
}
|
||||
.btn-beak{
|
||||
background-color: #EC9313;
|
||||
border-bottom: 4px solid #BE7306;
|
||||
}
|
||||
.btn-wings {
|
||||
background-color: #265584;
|
||||
border-bottom: 4px solid #1A3A59;
|
||||
}
|
||||
.btn-bb:hover{
|
||||
color:white;
|
||||
}
|
||||
.undo-margin{
|
||||
margin-left:-15px;
|
||||
}
|
||||
|
||||
.main-line{
|
||||
font-family: 'Raleway', sans-serif;
|
||||
margin-bottom: 59px;
|
||||
margin-top: -74px;
|
||||
font-size: 20px;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-size:26px;
|
||||
color:#5275B4;
|
||||
font-weight:200;
|
||||
}
|
||||
|
||||
.nav-child {
|
||||
margin-left:20px;
|
||||
}
|
||||
.title:hover{
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.header-anchor {
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition: opacity 0.2s ease-in-out 0.1s;
|
||||
-moz-transition: opacity 0.2s ease-in-out 0.1s;
|
||||
-ms-transition: opacity 0.2s ease-in-out 0.1s;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.header-anchor:active, .header-anchor:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
h1:hover .header-anchor,
|
||||
h2:hover .header-anchor,
|
||||
h3:hover .header-anchor,
|
||||
h4:hover .header-anchor,
|
||||
h5:hover .header-anchor,
|
||||
h6:hover .header-anchor {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.api-reference-menu {
|
||||
-moz-column-count: 2;
|
||||
-webkit-column-count: 2;
|
||||
columns: 2;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.post-info {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 20px;
|
||||
color: #8a6d3b;
|
||||
background-color: #fcf8e3;
|
||||
border-color: #faebcc;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px dashed #8a6d3b;
|
||||
border-radius: 4px;
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
.highlight {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
margin: 15px 0px;
|
||||
background: #eaeef3;
|
||||
-webkit-text-size-adjust: none;
|
||||
color: #00193a;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #00193a;
|
||||
background: #eaeef3;
|
||||
}
|
||||
|
||||
a code {
|
||||
color: #337AB7;
|
||||
}
|
||||
|
||||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight .c { color: #738191; font-style: italic } /* Comment */
|
||||
.highlight .err { border: 1px solid #FF0000 } /* Error */
|
||||
.highlight .k { color: #4c81c9; font-weight: bold } /* Keyword */
|
||||
.highlight .o { color: #666666 } /* Operator */
|
||||
.highlight .cm { color: #738191; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #738191; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #738191; font-style: italic } /* Comment.Special */
|
||||
.highlight .gd { color: #A00000 } /* Generic.Deleted */
|
||||
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { color: #00A000 } /* Generic.Inserted */
|
||||
.highlight .go { color: #808080 } /* Generic.Output */
|
||||
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
||||
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
|
||||
.highlight .kc { color: #4c81c9; font-weight: bold } /* Keyword.Constant */
|
||||
.highlight .kd { color: #4c81c9; font-weight: bold } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #4c81c9; font-weight: bold } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #4c81c9 } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #4c81c9; font-weight: bold } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #B00040 } /* Keyword.Type */
|
||||
.highlight .m { color: #666666 } /* Literal.Number */
|
||||
.highlight .s { color: #BE7306;} /* Literal.String */
|
||||
.highlight .na { color: #7D9029 } /* Name.Attribute */
|
||||
.highlight .nb { color: #4c81c9 } /* Name.Builtin */
|
||||
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||||
.highlight .no { color: #880000 } /* Name.Constant */
|
||||
.highlight .nd { color: #AA22FF } /* Name.Decorator */
|
||||
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
|
||||
.highlight .nf { color: #0000FF } /* Name.Function */
|
||||
.highlight .nl { color: #A0A000 } /* Name.Label */
|
||||
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||||
.highlight .nt { color: #4c81c9; font-weight: bold } /* Name.Tag */
|
||||
.highlight .nv { color: #19177C } /* Name.Variable */
|
||||
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||||
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
|
||||
.highlight .mf { color: #666666 } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
|
||||
.highlight .sb { color: #BE7306 } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #BE7306 } /* Literal.String.Char */
|
||||
.highlight .sd { color: #BE7306; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #BE7306 } /* Literal.String.Double */
|
||||
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #BE7306 } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #BE7306 } /* Literal.String.Other */
|
||||
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #BE7306 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #4c81c9 } /* Name.Builtin.Pseudo */
|
||||
.highlight .vc { color: #19177C } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #19177C } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
|
||||
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
|
@ -1,172 +0,0 @@
|
||||
---
|
||||
id: anti-patterns
|
||||
title: Anti-patterns
|
||||
---
|
||||
|
||||
This page will contain common promise anti-patterns that are exercised in the wild.
|
||||
|
||||
|
||||
- [The explicit construction anti-pattern](#the-explicit-construction-anti-pattern)
|
||||
- [The `.then(success, fail)` anti-pattern](#the-.then)
|
||||
|
||||
##The Explicit Construction Anti-Pattern
|
||||
|
||||
This is the most common anti-pattern. It is easy to fall into this when you don't really understand promises and think of them as glorified event emitters or callback utility. It's also sometimes called the promise constructor anti-pattern. Let's recap: promises are about making asynchronous code retain most of the lost properties of synchronous code such as flat indentation and one exception channel. This pattern is also called the deferred anti-pattern.
|
||||
|
||||
In the explicit construction anti-pattern, promise objects are created for no reason, complicating code.
|
||||
|
||||
First example is creating deferred object when you already have a promise or thenable:
|
||||
|
||||
```js
|
||||
//Code copyright by Twisternha http://stackoverflow.com/a/19486699/995876 CC BY-SA 2.5
|
||||
myApp.factory('Configurations', function (Restangular, MotorRestangular, $q) {
|
||||
var getConfigurations = function () {
|
||||
var deferred = $q.defer();
|
||||
|
||||
MotorRestangular.all('Motors').getList().then(function (Motors) {
|
||||
//Group by Config
|
||||
var g = _.groupBy(Motors, 'configuration');
|
||||
//Map values
|
||||
var mapped = _.map(g, function (m) {
|
||||
return {
|
||||
id: m[0].configuration,
|
||||
configuration: m[0].configuration,
|
||||
sizes: _.map(m, function (a) {
|
||||
return a.sizeMm
|
||||
})
|
||||
}
|
||||
});
|
||||
deferred.resolve(mapped);
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return {
|
||||
config: getConfigurations()
|
||||
}
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
This superfluous wrapping is also dangerous, any kind of errors and rejections are swallowed and not propagated to the caller of this function.
|
||||
|
||||
Instead of using the Deferred anti-pattern, the code should simply return the promise it already has and propagate values using `return`:
|
||||
|
||||
```js
|
||||
myApp.factory('Configurations', function (Restangular, MotorRestangular, $q) {
|
||||
var getConfigurations = function () {
|
||||
//Just return the promise we already have!
|
||||
return MotorRestangular.all('Motors').getList().then(function (Motors) {
|
||||
//Group by Cofig
|
||||
var g = _.groupBy(Motors, 'configuration');
|
||||
//Return the mapped array as the value of this promise
|
||||
return _.map(g, function (m) {
|
||||
return {
|
||||
id: m[0].configuration,
|
||||
configuration: m[0].configuration,
|
||||
sizes: _.map(m, function (a) {
|
||||
return a.sizeMm
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
config: getConfigurations()
|
||||
}
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
Not only is the code shorter but more importantly, if there is any error it will propagate properly to the final consumer.
|
||||
|
||||
Second example is creating a function that does nothing but manually wrap a callback API and doing a poor job at that:
|
||||
|
||||
```js
|
||||
function applicationFunction(arg1) {
|
||||
return new Promise(function(resolve, reject){ //Or Q.defer() in Q
|
||||
libraryFunction(arg1, function (err, value) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
This is reinventing the square wheel because any callback API wrapping can and should be done immediately using the promise library's promisification methods:
|
||||
|
||||
```js
|
||||
var applicationFunction = Promise.promisify(libraryFunction);
|
||||
```
|
||||
|
||||
The generic promisification is likely to be faster because it can use internals directly but also handles edge cases like `libraryFunction` throwing synchronously or using multiple success values.
|
||||
|
||||
|
||||
**So when should deferred be used?**
|
||||
|
||||
Well simply, when you have to.
|
||||
|
||||
You might have to use a deferred object when wrapping a callback API that doesn't follow the standard convention. Like `setTimeout`:
|
||||
|
||||
```js
|
||||
//setTimeout that returns a promise
|
||||
function delay(ms) {
|
||||
var deferred = Promise.defer(); // warning, defer is deprecated, use the promise constructor
|
||||
setTimeout(function(){
|
||||
deferred.fulfill();
|
||||
}, ms);
|
||||
return deferred.promise;
|
||||
}
|
||||
```
|
||||
|
||||
Such wrappers should be rare, if they're common for the reason that the promise library cannot generically promisify them, you should file an issue.
|
||||
|
||||
If you cannot do static promisification (promisify and promisifyAll perform too slowly to use at runtime), you may use [Promise.fromCallback](.).
|
||||
|
||||
Also see [this StackOverflow question](http://stackoverflow.com/questions/23803743/what-is-the-deferred-antipattern-and-how-do-i-avoid-it) for more examples and a debate around it.
|
||||
|
||||
##The `.then(success, fail)` anti-pattern
|
||||
|
||||
*Almost* a sure sign of using promises as glorified callbacks. Instead of `doThat(function(err, success))` you do `doThat().then(success, err)` and rationalize to yourself that at least the code is "less coupled" or something.
|
||||
|
||||
The `.then` signature is mostly about interop, there is *almost* never a reason to use `.then(success, fail)` in application code. It is even awkward to express it in the sync parallel:
|
||||
|
||||
```js
|
||||
var t0;
|
||||
try {
|
||||
t0 = doThat();
|
||||
}
|
||||
catch(e) {
|
||||
|
||||
}
|
||||
//deal with t0 here and waste the try-catch
|
||||
var stuff = JSON.parse(t0);
|
||||
```
|
||||
|
||||
It is more likely that you would write this instead in the sync world:
|
||||
|
||||
```js
|
||||
try {
|
||||
var stuff = JSON.parse(doThat());
|
||||
}
|
||||
catch(e) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
So please write the same when using promises too:
|
||||
|
||||
```js
|
||||
doThat()
|
||||
.then(function(v) {
|
||||
return JSON.parse(v);
|
||||
})
|
||||
.catch(function(e) {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
`.catch` is specified for built-in Javascript promises and is "sugar" for `.then(null, function(){})`. Since the way errors work in promises is almost the entire point (and the only thing jQuery never got right, even if it used `.pipe` as a `.then`), I really hope the implementation you are using provides this method for readability.
|
@ -1,95 +0,0 @@
|
||||
---
|
||||
id: api-reference
|
||||
title: API Reference
|
||||
redirect_from: "/docs/api/index.html"
|
||||
---
|
||||
|
||||
|
||||
<div class="api-reference-menu">
|
||||
<markdown>
|
||||
|
||||
- [Core](api/core.html)
|
||||
- [new Promise](api/new-promise.html)
|
||||
- [.then](api/then.html)
|
||||
- [.spread](api/spread.html)
|
||||
- [.catch](api/catch.html)
|
||||
- [.error](api/error.html)
|
||||
- [.finally](api/finally.html)
|
||||
- [.bind](api/bind.html)
|
||||
- [Promise.join](api/promise.join.html)
|
||||
- [Promise.try](api/promise.try.html)
|
||||
- [Promise.method](api/promise.method.html)
|
||||
- [Promise.resolve](api/promise.resolve.html)
|
||||
- [Promise.reject](api/promise.reject.html)
|
||||
- [Synchronous inspection](api/synchronous-inspection.html)
|
||||
- [PromiseInspection](api/promiseinspection.html)
|
||||
- [.isFulfilled](api/isfulfilled.html)
|
||||
- [.isRejected](api/isrejected.html)
|
||||
- [.isPending](api/ispending.html)
|
||||
- [.isCancelled](api/iscancelled.html)
|
||||
- [.value](api/value.html)
|
||||
- [.reason](api/reason.html)
|
||||
- [Collections](api/collections.html)
|
||||
- [Promise.all](api/promise.all.html)
|
||||
- [Promise.props](api/promise.props.html)
|
||||
- [Promise.any](api/promise.any.html)
|
||||
- [Promise.some](api/promise.some.html)
|
||||
- [Promise.map](api/promise.map.html)
|
||||
- [Promise.reduce](api/promise.reduce.html)
|
||||
- [Promise.filter](api/promise.filter.html)
|
||||
- [Promise.each](api/promise.each.html)
|
||||
- [Promise.mapSeries](api/promise.mapseries.html)
|
||||
- [Promise.race](api/promise.race.html)
|
||||
- [.all](api/all.html)
|
||||
- [.props](api/props.html)
|
||||
- [.any](api/any.html)
|
||||
- [.some](api/some.html)
|
||||
- [.map](api/map.html)
|
||||
- [.reduce](api/reduce.html)
|
||||
- [.filter](api/filter.html)
|
||||
- [.each](api/each.html)
|
||||
- [.mapSeries](api/mapseries.html)
|
||||
- [Resource management](api/resource-management.html)
|
||||
- [Promise.using](api/promise.using.html)
|
||||
- [.disposer](api/disposer.html)
|
||||
- [Promisification](api/promisification.html)
|
||||
- [Promise.promisify](api/promise.promisify.html)
|
||||
- [Promise.promisifyAll](api/promise.promisifyall.html)
|
||||
- [Promise.fromCallback](api/promise.fromcallback.html)
|
||||
- [.asCallback](api/ascallback.html)
|
||||
- [Timers](api/timers.html)
|
||||
- [.delay](api/delay.html)
|
||||
- [.timeout](api/timeout.html)
|
||||
- [Cancellation](api/cancellation.html)
|
||||
- [.cancel](api/cancel.html)
|
||||
- [Generators](api/generators.html)
|
||||
- [Promise.coroutine](api/promise.coroutine.html)
|
||||
- [Promise.coroutine.addYieldHandler](api/promise.coroutine.addyieldhandler.html)
|
||||
- [Utility](api/utility.html)
|
||||
- [.tap](api/tap.html)
|
||||
- [.call](api/call.html)
|
||||
- [.get](api/get.html)
|
||||
- [.return](api/return.html)
|
||||
- [.throw](api/throw.html)
|
||||
- [.catchReturn](api/catchreturn.html)
|
||||
- [.catchThrow](api/catchthrow.html)
|
||||
- [.reflect](api/reflect.html)
|
||||
- [Promise.noConflict](api/promise.noconflict.html)
|
||||
- [Promise.setScheduler](api/promise.setscheduler.html)
|
||||
- [Built-in error types](api/built-in-error-types.html)
|
||||
- [OperationalError](api/operationalerror.html)
|
||||
- [TimeoutError](api/timeouterror.html)
|
||||
- [CancellationError](api/cancellationerror.html)
|
||||
- [AggregateError](api/aggregateerror.html)
|
||||
- [Configuration](api/error-management-configuration.html)
|
||||
- [Global rejection events](api/error-management-configuration.html#global-rejection-events)
|
||||
- [Local rejection events](api/promise.onpossiblyunhandledrejection.html)
|
||||
- [Promise.config](api/promise.config.html)
|
||||
- [.suppressUnhandledRejections](api/suppressunhandledrejections.html)
|
||||
- [.done](api/done.html)
|
||||
- [Progression migration](api/progression-migration.html)
|
||||
- [Deferred migration](api/deferred-migration.html)
|
||||
- [Environment variables](api/environment-variables.html)
|
||||
|
||||
</markdown>
|
||||
</div>
|
@ -1,49 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: aggregateerror
|
||||
title: AggregateError
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##AggregateError
|
||||
|
||||
```js
|
||||
new AggregateError() extends Array -> AggregateError
|
||||
```
|
||||
|
||||
|
||||
A collection of errors. `AggregateError` is an array-like object, with numeric indices and a `.length` property. It supports all generic array methods such as `.forEach` directly.
|
||||
|
||||
`AggregateError`s are caught in [`.error`](.) handlers, even if the contained errors are not operational.
|
||||
|
||||
[Promise.some](.) and [Promise.any](.) use `AggregateError` as rejection reason when they fail.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
//Assumes AggregateError has been made global
|
||||
var err = new AggregateError();
|
||||
err.push(new Error("first error"));
|
||||
err.push(new Error("second error"));
|
||||
throw err;
|
||||
```
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "AggregateError";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-aggregateerror";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: all
|
||||
title: .all
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.all
|
||||
|
||||
```js
|
||||
.all() -> Promise
|
||||
```
|
||||
|
||||
Same as [Promise.all(this)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".all";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-all";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: any
|
||||
title: .any
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.any
|
||||
|
||||
```js
|
||||
.any() -> Promise
|
||||
```
|
||||
|
||||
Same as [Promise.any(this)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".any";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-any";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,114 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: ascallback
|
||||
title: .asCallback
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.asCallback
|
||||
|
||||
```js
|
||||
.asCallback(
|
||||
[function(any error, any value) callback],
|
||||
[Object {spread: boolean=false} options]
|
||||
) -> this
|
||||
```
|
||||
```js
|
||||
.nodeify(
|
||||
[function(any error, any value) callback],
|
||||
[Object {spread: boolean=false} options]
|
||||
) -> this
|
||||
```
|
||||
|
||||
Register a node-style callback on this promise. When this promise is either fulfilled or rejected, the node callback will be called back with the node.js convention where error reason is the first argument and success value is the second argument. The error argument will be `null` in case of success.
|
||||
|
||||
Returns back this promise instead of creating a new one. If the `callback` argument is not a function, this method does not do anything.
|
||||
|
||||
This can be used to create APIs that both accept node-style callbacks and return promises:
|
||||
|
||||
```js
|
||||
function getDataFor(input, callback) {
|
||||
return dataFromDataBase(input).asCallback(callback);
|
||||
}
|
||||
```
|
||||
|
||||
The above function can then make everyone happy.
|
||||
|
||||
Promises:
|
||||
|
||||
```js
|
||||
getDataFor("me").then(function(dataForMe) {
|
||||
console.log(dataForMe);
|
||||
});
|
||||
```
|
||||
|
||||
Normal callbacks:
|
||||
|
||||
```js
|
||||
getDataFor("me", function(err, dataForMe) {
|
||||
if( err ) {
|
||||
console.error( err );
|
||||
}
|
||||
console.log(dataForMe);
|
||||
});
|
||||
```
|
||||
|
||||
Promises can be rejected with falsy values (or no value at all, equal to rejecting with `undefined`), however `.asCallback` will call the callback with an `Error` object if the promise's rejection reason is a falsy value. You can retrieve the original falsy value from the error's `.cause` property.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
Promise.reject(null).asCallback(function(err, result) {
|
||||
// If is executed
|
||||
if (err) {
|
||||
// Logs 'null'
|
||||
console.log(err.cause);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
There is no effect on performance if the user doesn't actually pass a node-style callback function.
|
||||
|
||||
####Option: spread
|
||||
|
||||
Some nodebacks expect more than 1 success value but there is no mapping for this in the promise world. You may specify the option `spread` to call the nodeback with multiple values when the fulfillment value is an array:
|
||||
|
||||
```js
|
||||
Promise.resolve([1,2,3]).asCallback(function(err, result) {
|
||||
// err == null
|
||||
// result is the array [1,2,3]
|
||||
});
|
||||
|
||||
Promise.resolve([1,2,3]).asCallback(function(err, a, b, c) {
|
||||
// err == null
|
||||
// a == 1
|
||||
// b == 2
|
||||
// c == 3
|
||||
}, {spread: true});
|
||||
|
||||
Promise.resolve(123).asCallback(function(err, a, b, c) {
|
||||
// err == null
|
||||
// a == 123
|
||||
// b == undefined
|
||||
// c == undefined
|
||||
}, {spread: true});
|
||||
```
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".asCallback";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-ascallback";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: bind
|
||||
title: .bind
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.bind
|
||||
|
||||
```js
|
||||
.bind(any|Promise<any> thisArg) -> BoundPromise
|
||||
```
|
||||
|
||||
Same as calling [Promise.bind(thisArg, thisPromise)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".bind";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-bind";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: built-in-error-types
|
||||
title: Built-in error types
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Built-in error types
|
||||
|
||||
Bluebird includes a few built-in error types for common usage. All error types have the same identity across different copies of bluebird
|
||||
module so that pattern matching works in [`.catch`](.). All error types have a constructor taking a message string as their first argument, with that message
|
||||
becoming the `.message` property of the error object.
|
||||
|
||||
By default the error types need to be referenced from the Promise constructor, e.g. to get a reference to [TimeoutError](.), do `var TimeoutError = Promise.TimeoutError`. However, for convenience you will probably want to just make the references global.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Built-in error types";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-built-in-error-types";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,101 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: call
|
||||
title: .call
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.call
|
||||
|
||||
```js
|
||||
.call(
|
||||
String methodName,
|
||||
[any args...]
|
||||
)
|
||||
```
|
||||
|
||||
This is a convenience method for doing:
|
||||
|
||||
```js
|
||||
promise.then(function(obj) {
|
||||
return obj[methodName].call(obj, arg...);
|
||||
});
|
||||
```
|
||||
|
||||
For example ([`some` is a built-in array method](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some)):
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
var fs = Promise.promisifyAll(require("fs"));
|
||||
var path = require("path");
|
||||
var thisPath = process.argv[2] || ".";
|
||||
var now = Date.now();
|
||||
|
||||
fs.readdirAsync(thisPath)
|
||||
.map(function(fileName) {
|
||||
return fs.statAsync(path.join(thisPath, fileName));
|
||||
})
|
||||
.call("some", function(stat) {
|
||||
return (now - new Date(stat.mtime)) < 10000;
|
||||
})
|
||||
.then(function(someFilesHaveBeenModifiedLessThanTenSecondsAgo) {
|
||||
console.log(someFilesHaveBeenModifiedLessThanTenSecondsAgo) ;
|
||||
});
|
||||
```
|
||||
|
||||
Chaining lo-dash or underscore methods (Copy-pasteable example):
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
var pmap = Promise.map;
|
||||
var props = Promise.props;
|
||||
var _ = require("lodash");
|
||||
var fs = Promise.promisifyAll(require("fs"));
|
||||
|
||||
function getTotalSize(paths) {
|
||||
return pmap(paths, function(path) {
|
||||
return fs.statAsync(path).get("size");
|
||||
}).reduce(function(a, b) {
|
||||
return a + b;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
fs.readdirAsync(".").then(_)
|
||||
.call("groupBy", function(fileName) {
|
||||
return fileName.charAt(0);
|
||||
})
|
||||
.call("map", function(fileNames, firstCh) {
|
||||
return props({
|
||||
firstCh: firstCh,
|
||||
count: fileNames.length,
|
||||
totalSize: getTotalSize(fileNames)
|
||||
});
|
||||
})
|
||||
// Since the currently wrapped array contains promises we need to unwrap it and call .all() before continuing the chain
|
||||
// If the currently wrapped thing was an object with properties that might be promises, we would call .props() instead
|
||||
.call("value").all().then(_)
|
||||
.call("sortBy", "count")
|
||||
.call("reverse")
|
||||
.call("map", function(data) {
|
||||
return data.count + " total files beginning with " + data.firstCh + " with total size of " + data.totalSize + " bytes";
|
||||
})
|
||||
.call("join", "\n")
|
||||
.then(console.log)
|
||||
```
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".call";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-call";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: cancel
|
||||
title: .cancel
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.cancel
|
||||
|
||||
```js
|
||||
.cancel() -> undefined
|
||||
```
|
||||
|
||||
Cancel this promise. Will not do anything if this promise is already settled or if the [Cancellation](.) feature has not been enabled. See [Cancellation](.) for how to use cancellation.
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".cancel";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-cancel";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,112 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: cancellation
|
||||
title: Cancellation
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Cancellation
|
||||
|
||||
Cancellation has been redesigned for bluebird 3.x, any code that relies on 2.x cancellation semantics won't work in 3.x.
|
||||
|
||||
The cancellation feature is **by default turned off**, you can enable it using [Promise.config](.).
|
||||
|
||||
The new cancellation has "don't care" semantics while the old cancellation had abort semantics. Cancelling a promise simply means that its handler callbacks will not be called.
|
||||
|
||||
The advantages of the new cancellation compared to the old cancellation are:
|
||||
|
||||
- [.cancel()](.) is synchronous.
|
||||
- no setup code required to make cancellation work
|
||||
- composes with other bluebird features, like [Promise.all](.).
|
||||
- [reasonable semantics for multiple consumer cancellation](#what-about-promises-that-have-multiple-consumers)
|
||||
|
||||
As an optimization, the cancellation signal propagates upwards the promise chain so that an ongoing operation e.g. network request can be aborted. However, *not* aborting the network request still doesn't make any operational difference as the callbacks are still not called either way.
|
||||
|
||||
You may register an optional cancellation hook at a root promise by using the `onCancel` argument that is passed to the executor function when cancellation is enabled:
|
||||
|
||||
```js
|
||||
function makeCancellableRequest(url) {
|
||||
return new Promise(function(resolve, reject, onCancel) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.on("load", resolve);
|
||||
xhr.on("error", reject);
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send(null);
|
||||
// Note the onCancel argument only exists if cancellation has been enabled!
|
||||
onCancel(function() {
|
||||
xhr.abort();
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `onCancel` hook is really an optional disconnected optimization, there is no real requirement to register any cancellation hooks for cancellation to work. As such, any errors that may occur while inside the `onCancel` callback are not caught and turned into rejections.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var searchPromise = Promise.resolve(); // Dummy promise to avoid null check.
|
||||
document.querySelector("#search-input").addEventListener("input", function() {
|
||||
// The handlers of the previous request must not be called
|
||||
searchPromise.cancel();
|
||||
var url = "/search?term=" + encodeURIComponent(this.value.trim());
|
||||
showSpinner();
|
||||
searchPromise = makeCancellableRequest(url)
|
||||
.then(function(results) {
|
||||
return transformData(results);
|
||||
})
|
||||
.then(function(transformedData) {
|
||||
document.querySelector("#search-results").innerHTML = transformedData;
|
||||
})
|
||||
.catch(function(e) {
|
||||
document.querySelector("#search-results").innerHTML = renderErrorBox(e);
|
||||
})
|
||||
.finally(function() {
|
||||
// This check is necessary because `.finally` handlers are always called.
|
||||
if (!searchPromise.isCancelled()) {
|
||||
hideSpinner();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
As shown in the example the handlers registered with `.finally` are called even if the promise is cancelled. Another such exception is [.reflect()](.). No other types of handlers will be called in case of cancellation. This means that in `.then(onSuccess, onFailure)` neither `onSuccess` or `onFailure` handler is called. This is similar to how [`Generator#return`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return) works - only active `finally` blocks are executed and then the generator exits.
|
||||
|
||||
###What about promises that have multiple consumers?
|
||||
|
||||
It is often said that promises cannot be cancellable because they can have multiple consumers.
|
||||
|
||||
For instance:
|
||||
|
||||
```js
|
||||
var result = makeCancellableRequest(...);
|
||||
|
||||
var firstConsumer = result.then(...);
|
||||
var secondConsumer = result.then(...);
|
||||
```
|
||||
|
||||
Even though in practice most users of promises will never have any need to take advantage of the fact that you can attach multiple consumers to a promise, it is nevertheless possible. The problem: "what should happen if [.cancel()](.) is called on `firstConsumer`?" Propagating the cancellation signal (and therefore making it abort the request) would be very bad as the second consumer might still be interested in the result despite the first consumer's disinterest.
|
||||
|
||||
What actually happens is that `result` keeps track of how many consumers it has, in this case 2, and only if all the consumers signal cancel will the request be aborted. However, as far as `firstConsumer` can tell, the promise was successfully cancelled and its handlers will not be called.
|
||||
|
||||
Note that it is an error to consume an already cancelled promise, doing such a thing will give you a promise that is rejected with `new CancellationError("late cancellation observer")` as the rejection reason.
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Cancellation";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-cancellation";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,32 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: cancellationerror
|
||||
title: CancellationError
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##CancellationError
|
||||
|
||||
```js
|
||||
new CancellationError(String message) -> CancellationError
|
||||
```
|
||||
|
||||
|
||||
Signals that an operation has been aborted or cancelled. The default reason used by [`.cancel`](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "CancellationError";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-cancellationerror";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,227 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: catch
|
||||
title: .catch
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.catch
|
||||
|
||||
`.catch` is a convenience method for handling errors in promise chains.
|
||||
It comes in two variants
|
||||
- A catch-all variant similar to the synchronous `catch(e) {` block. This variant is compatible with native promises.
|
||||
- A filtered variant (like other non-JS languages typically have) that lets you only handle specific errors. **This variant is usually preferable and is significantly safer**.
|
||||
|
||||
### A note on promise exception handling.
|
||||
|
||||
Promise exception handling mirrors native exception handling in JavaScript. A synchronous function `throw`ing is similar to a promise rejecting. Here is an example to illustrate it:
|
||||
|
||||
```js
|
||||
function getItems(parma) {
|
||||
try {
|
||||
var items = getItemsSync();
|
||||
if(!items) throw new InvalidItemsError();
|
||||
} catch(e) {
|
||||
// can address the error here, either from getItemsSync returning a falsey value or throwing itself
|
||||
throw e; // need to re-throw the error unless I want it to be considered handled.
|
||||
}
|
||||
return process(items);
|
||||
}
|
||||
```
|
||||
|
||||
Similarly, with promises:
|
||||
|
||||
```js
|
||||
function getItems(param) {
|
||||
return getItemsAsync().then(items => {
|
||||
if(!items) throw new InvalidItemsError();
|
||||
return items;
|
||||
}).catch(e => {
|
||||
// can address the error here and recover from it, from getItemsAsync rejects or returns a falsey value
|
||||
throw e; // Need to rethrow unless we actually recovered, just like in the synchronous version
|
||||
}).then(process);
|
||||
}
|
||||
```
|
||||
|
||||
### Catch-all
|
||||
|
||||
```js
|
||||
.catch(function(any error) handler) -> Promise
|
||||
```
|
||||
```js
|
||||
.caught(function(any error) handler) -> Promise
|
||||
```
|
||||
|
||||
This is a catch-all exception handler, shortcut for calling [`.then(null, handler)`](.) on this promise. Any exception happening in a `.then`-chain will propagate to nearest `.catch` handler.
|
||||
|
||||
*For compatibility with earlier ECMAScript versions, an alias `.caught` is provided for [`.catch`](.).*
|
||||
|
||||
### Filtered Catch
|
||||
|
||||
```js
|
||||
.catch(
|
||||
class ErrorClass|function(any error)|Object predicate...,
|
||||
function(any error) handler
|
||||
) -> Promise
|
||||
```
|
||||
```js
|
||||
.caught(
|
||||
class ErrorClass|function(any error)|Object predicate...,
|
||||
function(any error) handler
|
||||
) -> Promise
|
||||
```
|
||||
This is an extension to [`.catch`](.) to work more like catch-clauses in languages like Java or C#. Instead of manually checking `instanceof` or `.name === "SomeError"`, you may specify a number of error constructors which are eligible for this catch handler. The catch handler that is first met that has eligible constructors specified, is the one that will be called.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
somePromise.then(function() {
|
||||
return a.b.c.d();
|
||||
}).catch(TypeError, function(e) {
|
||||
//If it is a TypeError, will end up here because
|
||||
//it is a type error to reference property of undefined
|
||||
}).catch(ReferenceError, function(e) {
|
||||
//Will end up here if a was never declared at all
|
||||
}).catch(function(e) {
|
||||
//Generic catch-the rest, error wasn't TypeError nor
|
||||
//ReferenceError
|
||||
});
|
||||
```
|
||||
|
||||
You may also add multiple filters for a catch handler:
|
||||
|
||||
```js
|
||||
somePromise.then(function() {
|
||||
return a.b.c.d();
|
||||
}).catch(TypeError, ReferenceError, function(e) {
|
||||
//Will end up here on programmer error
|
||||
}).catch(NetworkError, TimeoutError, function(e) {
|
||||
//Will end up here on expected everyday network errors
|
||||
}).catch(function(e) {
|
||||
//Catch any unexpected errors
|
||||
});
|
||||
```
|
||||
|
||||
For a parameter to be considered a type of error that you want to filter, you need the constructor to have its `.prototype` property be `instanceof Error`.
|
||||
|
||||
Such a constructor can be minimally created like so:
|
||||
|
||||
```js
|
||||
function MyCustomError() {}
|
||||
MyCustomError.prototype = Object.create(Error.prototype);
|
||||
```
|
||||
|
||||
Using it:
|
||||
|
||||
```js
|
||||
Promise.resolve().then(function() {
|
||||
throw new MyCustomError();
|
||||
}).catch(MyCustomError, function(e) {
|
||||
//will end up here now
|
||||
});
|
||||
```
|
||||
|
||||
However if you want stack traces and cleaner string output, then you should do:
|
||||
|
||||
*in Node.js and other V8 environments, with support for `Error.captureStackTrace`*
|
||||
|
||||
```js
|
||||
function MyCustomError(message) {
|
||||
this.message = message;
|
||||
this.name = "MyCustomError";
|
||||
Error.captureStackTrace(this, MyCustomError);
|
||||
}
|
||||
MyCustomError.prototype = Object.create(Error.prototype);
|
||||
MyCustomError.prototype.constructor = MyCustomError;
|
||||
```
|
||||
|
||||
Using CoffeeScript's `class` for the same:
|
||||
|
||||
```coffee
|
||||
class MyCustomError extends Error
|
||||
constructor: (@message) ->
|
||||
@name = "MyCustomError"
|
||||
Error.captureStackTrace(this, MyCustomError)
|
||||
```
|
||||
|
||||
This method also supports predicate-based filters. If you pass a
|
||||
predicate function instead of an error constructor, the predicate will receive
|
||||
the error as an argument. The return result of the predicate will be used
|
||||
determine whether the error handler should be called.
|
||||
|
||||
Predicates should allow for very fine grained control over caught errors:
|
||||
pattern matching, error-type sets with set operations and many other techniques
|
||||
can be implemented on top of them.
|
||||
|
||||
Example of using a predicate-based filter:
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
var request = Promise.promisify(require("request"));
|
||||
|
||||
function ClientError(e) {
|
||||
return e.code >= 400 && e.code < 500;
|
||||
}
|
||||
|
||||
request("http://www.google.com").then(function(contents) {
|
||||
console.log(contents);
|
||||
}).catch(ClientError, function(e) {
|
||||
//A client error like 400 Bad Request happened
|
||||
});
|
||||
```
|
||||
|
||||
Predicate functions that only check properties have a handy shorthand. In place of a predicate function, you can pass an object, and its properties will be checked against the error object for a match:
|
||||
|
||||
```js
|
||||
fs.readFileAsync(...)
|
||||
.then(...)
|
||||
.catch({code: 'ENOENT'}, function(e) {
|
||||
console.log("file not found: " + e.path);
|
||||
});
|
||||
```
|
||||
|
||||
The object predicate passed to `.catch` in the above code (`{code: 'ENOENT'}`) is shorthand for a predicate function `function predicate(e) { return isObject(e) && e.code == 'ENOENT' }`, I.E. loose equality is used.
|
||||
|
||||
*For compatibility with earlier ECMAScript version, an alias `.caught` is provided for [`.catch`](.).*
|
||||
</markdown></div>
|
||||
|
||||
By not returning a rejected value or `throw`ing from a catch, you "recover from failure" and continue the chain:
|
||||
|
||||
```js
|
||||
Promise.reject(Error('fail!'))
|
||||
.catch(function(e) {
|
||||
// fallback with "recover from failure"
|
||||
return Promise.resolve('success!'); // promise or value
|
||||
})
|
||||
.then(function(result) {
|
||||
console.log(result); // will print "success!"
|
||||
});
|
||||
```
|
||||
|
||||
This is exactly like the synchronous code:
|
||||
|
||||
```js
|
||||
var result;
|
||||
try {
|
||||
throw Error('fail');
|
||||
} catch(e) {
|
||||
result = 'success!';
|
||||
}
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".catch";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-catch";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,43 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: catchreturn
|
||||
title: .catchReturn
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.catchReturn
|
||||
|
||||
```js
|
||||
.catchReturn(
|
||||
[class ErrorClass|function(any error) predicate],
|
||||
any value
|
||||
) -> Promise
|
||||
```
|
||||
|
||||
Convenience method for:
|
||||
|
||||
```js
|
||||
.catch(function() {
|
||||
return value;
|
||||
});
|
||||
```
|
||||
You may optionally prepend one predicate function or ErrorClass to pattern match the error (the generic [.catch](.) methods accepts multiple)
|
||||
|
||||
Same limitations regarding to the binding time of `value` to apply as with [`.return`](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".catchReturn";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-catchreturn";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,43 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: catchthrow
|
||||
title: .catchThrow
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.catchThrow
|
||||
|
||||
```js
|
||||
.catchThrow(
|
||||
[class ErrorClass|function(any error) predicate],
|
||||
any reason
|
||||
) -> Promise
|
||||
```
|
||||
|
||||
Convenience method for:
|
||||
|
||||
```js
|
||||
.catch(function() {
|
||||
throw reason;
|
||||
});
|
||||
```
|
||||
You may optionally prepend one predicate function or ErrorClass to pattern match the error (the generic [.catch](.) methods accepts multiple)
|
||||
|
||||
Same limitations regarding to the binding time of `reason` to apply as with [`.return`](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".catchThrow";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-catchthrow";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,32 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: collections
|
||||
title: Collections
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Collections
|
||||
|
||||
Methods of `Promise` instances and core static methods of the Promise class to deal with collections of promises or mixed promises and values.
|
||||
|
||||
All collection methods have a static equivalent on the Promise object, e.g. `somePromise.map(...)...` is same as `Promise.map(somePromise, ...)...`,
|
||||
`somePromise.all` is same as [`Promise.all`](.) and so on.
|
||||
|
||||
None of the collection methods modify the original input. Holes in arrays are treated as if they were defined with the value `undefined`.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Collections";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-collections";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,27 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: core
|
||||
title: Core
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Core
|
||||
|
||||
Core methods of `Promise` instances and core static methods of the Promise class.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Core";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-core";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,44 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: deferred-migration
|
||||
title: Deferred migration
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Deferred migration
|
||||
|
||||
Deferreds are deprecated in favor of the promise constructor. If you need deferreds for some reason, you can create them trivially using the constructor:
|
||||
|
||||
```js
|
||||
function defer() {
|
||||
var resolve, reject;
|
||||
var promise = new Promise(function() {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
return {
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
promise: promise
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
For old code that still uses deferred objects, see [the deprecated API docs ](/bluebird/web/docs/deprecated_apis.html#promise-resolution).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Deferred migration";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-deferred-migration";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: delay
|
||||
title: .delay
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.delay
|
||||
|
||||
```js
|
||||
.delay(int ms) -> Promise
|
||||
```
|
||||
|
||||
Same as calling [Promise.delay(ms, this)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".delay";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-delay";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,158 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: disposer
|
||||
title: .disposer
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.disposer
|
||||
|
||||
```js
|
||||
.disposer(function(any resource, Promise usingOutcomePromise) disposer) -> Disposer
|
||||
```
|
||||
|
||||
A meta method used to specify the disposer method that cleans up a resource when using `Promise.using`.
|
||||
|
||||
Returns a Disposer object which encapsulates both the resource as well as the method to clean it up. The user can pass this object to `Promise.using` to get access to the resource when it becomes available, as well as to ensure its automatically cleaned up.
|
||||
|
||||
The second argument passed to a disposer is the result promise of the using block, which you can inspect synchronously.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
// This function doesn't return a promise but a Disposer
|
||||
// so it's very hard to use it wrong (not passing it to `using`)
|
||||
function getConnection() {
|
||||
return db.connect().disposer(function(connection, promise) {
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the connection returned by `getConnection` can only be
|
||||
used via `Promise.using`, like so:
|
||||
|
||||
```js
|
||||
function useConnection(query) {
|
||||
return Promise.using(getConnection(), function(connection) {
|
||||
return connection.sendQuery(query).then(function(results) {
|
||||
return process(results);
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
This will ensure that `connection.close()` will be called once the promise returned
|
||||
from the `Promise.using` closure is resolved or if an exception was thrown in the closure
|
||||
body.
|
||||
|
||||
Real example:
|
||||
|
||||
```js
|
||||
var pg = require("pg");
|
||||
// Uncomment if pg has not been properly promisified yet
|
||||
//var Promise = require("bluebird");
|
||||
//Promise.promisifyAll(pg, {
|
||||
// filter: function(methodName) {
|
||||
// return methodName === "connect"
|
||||
// },
|
||||
// multiArgs: true
|
||||
//});
|
||||
// Promisify rest of pg normally
|
||||
//Promise.promisifyAll(pg);
|
||||
|
||||
function getSqlConnection(connectionString) {
|
||||
var close;
|
||||
return pg.connectAsync(connectionString).spread(function(client, done) {
|
||||
close = done;
|
||||
return client;
|
||||
}).disposer(function() {
|
||||
if (close) close();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = getSqlConnection;
|
||||
```
|
||||
|
||||
Real example 2:
|
||||
|
||||
```js
|
||||
var mysql = require("mysql");
|
||||
// Uncomment if pg has not been properly promisified yet
|
||||
// var Promise = require("bluebird");
|
||||
// Promise.promisifyAll(mysql);
|
||||
// Promise.promisifyAll(require("mysql/lib/Connection").prototype);
|
||||
// Promise.promisifyAll(require("mysql/lib/Pool").prototype);
|
||||
var pool = mysql.createPool({
|
||||
connectionLimit: 10,
|
||||
host: 'example.org',
|
||||
user: 'bob',
|
||||
password: 'secret'
|
||||
});
|
||||
|
||||
function getSqlConnection() {
|
||||
return pool.getConnectionAsync().disposer(function(connection) {
|
||||
connection.release();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = getSqlConnection;
|
||||
```
|
||||
|
||||
#### Note about disposers in node
|
||||
|
||||
If a disposer method throws or returns a rejected promise, its highly likely that it failed to dispose of the resource. In that case, Bluebird has two options - it can either ignore the error and continue with program execution or throw an exception (crashing the process in node.js).
|
||||
|
||||
In bluebird we've chosen to do the latter because resources are typically scarce. For example, if a database connection cannot be disposed of and Bluebird ignores that, the connection pool will be quickly depleted and the process will become unusable (all requests that query the database will wait forever). Since Bluebird doesn't know how to handle that, the only sensible default is to crash the process. That way, rather than getting a useless process that cannot fulfill more requests, we can swap the faulty worker with a new one letting the OS clean up the resources for us.
|
||||
|
||||
As a result, if you anticipate thrown errors or promise rejections while disposing of the resource you should use a `try..catch` block (or Promise.try) and write the appropriate catch code to handle the errors. If its not possible to sensibly handle the error, letting the process crash is the next best option.
|
||||
|
||||
This also means that disposers should not contain code that does anything other than resource disposal. For example, you cannot write code inside a disposer to commit or rollback a transaction, because there is no mechanism for the disposer to signal a failure of the commit or rollback action without crashing the process.
|
||||
|
||||
For transactions, you can use the following similar pattern instead:
|
||||
|
||||
```js
|
||||
function withTransaction(fn) {
|
||||
return Promise.using(pool.acquireConnection(), function(connection) {
|
||||
var tx = connection.beginTransaction()
|
||||
return Promise
|
||||
.try(fn, tx)
|
||||
.then(function(res) { return connection.commit().thenReturn(res) },
|
||||
function(err) {
|
||||
return connection.rollback()
|
||||
.catch(function(e) {/* maybe add the rollback error to err */})
|
||||
.thenThrow(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// If the withTransaction block completes successfully, the transaction is automatically committed
|
||||
// Any error or rejection will automatically roll it back
|
||||
|
||||
withTransaction(function(tx) {
|
||||
return tx.queryAsync(...).then(function() {
|
||||
return tx.queryAsync(...)
|
||||
}).then(function() {
|
||||
return tx.queryAsync(...)
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".disposer";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-disposer";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,37 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: done
|
||||
title: .done
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.done
|
||||
|
||||
```js
|
||||
.done(
|
||||
[function(any value) fulfilledHandler],
|
||||
[function(any error) rejectedHandler]
|
||||
) -> undefined
|
||||
```
|
||||
|
||||
|
||||
Like [`.then`](.), but any unhandled rejection that ends up here will crash the process (in node) or be thrown as an error (in browsers). The use of this method is heavily discouraged and it only exists for historical reasons.
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".done";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-done";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,51 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: each
|
||||
title: .each
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.each
|
||||
|
||||
```js
|
||||
.each(function(any item, int index, int length) iterator) -> Promise
|
||||
```
|
||||
|
||||
Iterate over an array, or a promise of an array, which contains promises (or a mix of promises and values) with the given `iterator` function with the signature `(value, index, length)` where `value` is the resolved value of a respective promise in the input array. Iteration happens serially. If any promise in the input array is rejected the returned promise is rejected as well.
|
||||
|
||||
Resolves to the original array unmodified, this method is meant to be used for side effects. If the iterator function returns a promise or a thenable, then the result of the promise is awaited, before continuing with next iteration.
|
||||
|
||||
Example where you might want to utilize `.each`:
|
||||
|
||||
```js
|
||||
// Source: http://jakearchibald.com/2014/es7-async-functions/
|
||||
function loadStory() {
|
||||
return getJSON('story.json')
|
||||
.then(function(story) {
|
||||
addHtmlToPage(story.heading);
|
||||
return story.chapterURLs.map(getJSON);
|
||||
})
|
||||
.each(function(chapter) { addHtmlToPage(chapter.html); })
|
||||
.then(function() { addTextToPage("All done"); })
|
||||
.catch(function(err) { addTextToPage("Argh, broken: " + err.message); })
|
||||
.then(function() { document.querySelector('.spinner').style.display = 'none'; });
|
||||
}
|
||||
```
|
||||
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".each";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-each";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,41 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: environment-variables
|
||||
title: Environment variables
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Environment variables
|
||||
|
||||
This section only applies to node.js or io.js.
|
||||
|
||||
You can change bluebird behavior globally with various environment variables. These global variables affect all instances of bluebird that are running in your environment, rather than just the one you have `require`d in your application. The effect an environment variable has depends on the bluebird version.
|
||||
|
||||
Environment variables supported by 2.x:
|
||||
|
||||
- `BLUEBIRD_DEBUG` - Set to any truthy value this will enable long stack traces and warnings
|
||||
- `NODE_ENV` - If set exactly to `development` it will have the same effect as if the `BLUEBIRD_DEBUG` variable was set.
|
||||
|
||||
Environment variables supported by 3.x:
|
||||
|
||||
- `BLUEBIRD_DEBUG` - If set this will enable long stack traces and warnings, unless those are explicitly disabled. Setting this to exactly `0` can be used to override `NODE_ENV=development` enabling long stack traces and warnings.
|
||||
- `NODE_ENV` - If set exactly to `development` it will have the same effect as if the `BLUEBIRD_DEBUG` variable was set.
|
||||
- `BLUEBIRD_WARNINGS` - if set exactly to `0` it will explicitly disable warnings and this overrides any other setting that might enable warnings. If set to any truthy value, it will explicitly enable warnings.
|
||||
- `BLUEBIRD_LONG_STACK_TRACES` - if set exactly to `0` it will explicitly disable long stack traces and this overrides any other setting that might enable long stack traces. If set to any truthy value, it will explicitly enable long stack traces.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Environment variables";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-environment-variables";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,107 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: error-management-configuration
|
||||
title: Error management configuration
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Error management configuration
|
||||
|
||||
The default approach of bluebird is to immediately log the stack trace when there is an unhandled rejection. This is similar to how uncaught exceptions cause the stack trace to be logged so that you have something to work with when something is not working as expected.
|
||||
|
||||
However because it is possible to handle a rejected promise at any time in the indeterminate future, some programming patterns will result in false positives. Because such programming patterns are not necessary and can always be refactored to never cause false positives, we recommend doing that to keep debugging as easy as possible . You may however feel differently so bluebird provides hooks to implement more complex failure policies.
|
||||
|
||||
Such policies could include:
|
||||
|
||||
- Logging after the promise became GCd (requires a native node.js module)
|
||||
- Showing a live list of rejected promises
|
||||
- Using no hooks and using [`.done`](.) to manually to mark end points where rejections will not be handled
|
||||
- Swallowing all errors (challenge your debugging skills)
|
||||
- ...
|
||||
|
||||
<hr>
|
||||
|
||||
###Global rejection events
|
||||
|
||||
Starting from 2.7.0 all bluebird instances also fire rejection events globally so that applications can register one universal hook for them.
|
||||
|
||||
The global events are:
|
||||
|
||||
- `"unhandledRejection"` (corresponds to the local [`Promise.onPossiblyUnhandledRejection`](.))
|
||||
- `"rejectionHandled"` (corresponds to the local [`Promise.onUnhandledRejectionHandled`](.))
|
||||
|
||||
|
||||
Attaching global rejection event handlers in **node.js**:
|
||||
|
||||
```js
|
||||
// NOTE: event name is camelCase as per node convention
|
||||
process.on("unhandledRejection", function(reason, promise) {
|
||||
// See Promise.onPossiblyUnhandledRejection for parameter documentation
|
||||
});
|
||||
|
||||
// NOTE: event name is camelCase as per node convention
|
||||
process.on("rejectionHandled", function(promise) {
|
||||
// See Promise.onUnhandledRejectionHandled for parameter documentation
|
||||
});
|
||||
```
|
||||
|
||||
Attaching global rejection event handlers in **browsers**:
|
||||
|
||||
Using DOM3 `addEventListener` APIs (support starting from IE9+):
|
||||
|
||||
```js
|
||||
// NOTE: event name is all lower case as per DOM convention
|
||||
window.addEventListener("unhandledrejection", function(e) {
|
||||
// NOTE: e.preventDefault() must be manually called to prevent the default
|
||||
// action which is currently to log the stack trace to console.warn
|
||||
e.preventDefault();
|
||||
// NOTE: parameters are properties of the event detail property
|
||||
var reason = e.detail.reason;
|
||||
var promise = e.detail.promise;
|
||||
// See Promise.onPossiblyUnhandledRejection for parameter documentation
|
||||
});
|
||||
|
||||
// NOTE: event name is all lower case as per DOM convention
|
||||
window.addEventListener("rejectionhandled", function(e) {
|
||||
// NOTE: e.preventDefault() must be manually called prevent the default
|
||||
// action which is currently unset (but might be set to something in the future)
|
||||
e.preventDefault();
|
||||
// NOTE: parameters are properties of the event detail property
|
||||
var promise = e.detail.promise;
|
||||
// See Promise.onUnhandledRejectionHandled for parameter documentation
|
||||
});
|
||||
```
|
||||
|
||||
In Web Workers you may use `self.addEventListener`.
|
||||
|
||||
Using legacy APIs (support starting from IE6+):
|
||||
|
||||
```js
|
||||
// NOTE: event name is all lower case as per legacy convention
|
||||
window.onunhandledrejection = function(reason, promise) {
|
||||
// See Promise.onPossiblyUnhandledRejection for parameter documentation
|
||||
};
|
||||
|
||||
// NOTE: event name is all lower case as per legacy convention
|
||||
window.onrejectionhandled = function(promise) {
|
||||
// See Promise.onUnhandledRejectionHandled for parameter documentation
|
||||
};
|
||||
```
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Error management configuration";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-error-management-configuration";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,101 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: error
|
||||
title: .error
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.error
|
||||
|
||||
```js
|
||||
.error([function(any error) rejectedHandler]) -> Promise
|
||||
```
|
||||
|
||||
|
||||
Like [`.catch`](.) but instead of catching all types of exceptions, it only catches operational errors.
|
||||
|
||||
*Note, "errors" mean errors, as in objects that are `instanceof Error` - not strings, numbers and so on. See [a string is not an error](http://www.devthought.com/2011/12/22/a-string-is-not-an-error/).*
|
||||
|
||||
It is equivalent to the following [`.catch`](.) pattern:
|
||||
|
||||
```js
|
||||
// Assumes OperationalError has been made global
|
||||
function isOperationalError(e) {
|
||||
if (e == null) return false;
|
||||
return (e instanceof OperationalError) || (e.isOperational === true);
|
||||
}
|
||||
|
||||
// Now this bit:
|
||||
.catch(isOperationalError, function(e) {
|
||||
// ...
|
||||
})
|
||||
|
||||
// Is equivalent to:
|
||||
|
||||
.error(function(e) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
For example, if a promisified function errbacks the node-style callback with an error, that could be caught with [`.error`](.). However if the node-style callback **throws** an error, only `.catch` would catch that.
|
||||
|
||||
In the following example you might want to handle just the `SyntaxError` from JSON.parse and Filesystem errors from `fs` but let programmer errors bubble as unhandled rejections:
|
||||
|
||||
```js
|
||||
var fs = Promise.promisifyAll(require("fs"));
|
||||
|
||||
fs.readFileAsync("myfile.json").then(JSON.parse).then(function (json) {
|
||||
console.log("Successful json")
|
||||
}).catch(SyntaxError, function (e) {
|
||||
console.error("file contains invalid json");
|
||||
}).error(function (e) {
|
||||
console.error("unable to read file, because: ", e.message);
|
||||
});
|
||||
```
|
||||
|
||||
Now, because there is no catch-all handler, if you typed `console.lag` (causes an error you don't expect), you will see:
|
||||
|
||||
```
|
||||
Possibly unhandled TypeError: Object #<Console> has no method 'lag'
|
||||
at application.js:8:13
|
||||
From previous event:
|
||||
at Object.<anonymous> (application.js:7:4)
|
||||
at Module._compile (module.js:449:26)
|
||||
at Object.Module._extensions..js (module.js:467:10)
|
||||
at Module.load (module.js:349:32)
|
||||
at Function.Module._load (module.js:305:12)
|
||||
at Function.Module.runMain (module.js:490:10)
|
||||
at startup (node.js:121:16)
|
||||
at node.js:761:3
|
||||
```
|
||||
|
||||
*( If you don't get the above - you need to enable [long stack traces](#promiselongstacktraces---undefined) )*
|
||||
|
||||
And if the file contains invalid JSON:
|
||||
|
||||
```
|
||||
file contains invalid json
|
||||
```
|
||||
|
||||
And if the `fs` module causes an error like file not found:
|
||||
|
||||
```
|
||||
unable to read file, because: ENOENT, open 'not_there.txt'
|
||||
```
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".error";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-error";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: filter
|
||||
title: .filter
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.filter
|
||||
|
||||
```js
|
||||
.filter(
|
||||
function(any item, int index, int length) filterer,
|
||||
[Object {concurrency: int=Infinity} options]
|
||||
) -> Promise
|
||||
```
|
||||
|
||||
Same as [Promise.filter(this, filterer, options)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".filter";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-filter";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,97 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: finally
|
||||
title: .finally
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.finally
|
||||
|
||||
```js
|
||||
.finally(function() handler) -> Promise
|
||||
```
|
||||
```js
|
||||
.lastly(function() handler) -> Promise
|
||||
```
|
||||
|
||||
|
||||
Pass a handler that will be called regardless of this promise's fate. Returns a new promise chained from this promise. There are special semantics for [`.finally`](.) in that the final value cannot be modified from the handler.
|
||||
|
||||
*Note: using [`.finally`](.) for resource management has better alternatives, see [resource management](/docs/api/resource-management.html)*
|
||||
|
||||
Consider the example:
|
||||
|
||||
```js
|
||||
function anyway() {
|
||||
$("#ajax-loader-animation").hide();
|
||||
}
|
||||
|
||||
function ajaxGetAsync(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.addEventListener("error", reject);
|
||||
xhr.addEventListener("load", resolve);
|
||||
xhr.open("GET", url);
|
||||
xhr.send(null);
|
||||
}).then(anyway, anyway);
|
||||
}
|
||||
```
|
||||
|
||||
This example doesn't work as intended because the `then` handler actually swallows the exception and returns `undefined` for any further chainers.
|
||||
|
||||
The situation can be fixed with `.finally`:
|
||||
|
||||
```js
|
||||
function ajaxGetAsync(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.addEventListener("error", reject);
|
||||
xhr.addEventListener("load", resolve);
|
||||
xhr.open("GET", url);
|
||||
xhr.send(null);
|
||||
}).finally(function() {
|
||||
$("#ajax-loader-animation").hide();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Now the animation is hidden but, unless it throws an exception, the function has no effect on the fulfilled or rejected value of the returned promise. This is similar to how the synchronous `finally` keyword behaves.
|
||||
|
||||
If the handler function passed to `.finally` returns a promise, the promise returned by `.finally` will not be settled until the promise returned by the handler is settled. If the handler fulfills its promise, the returned promise will be fulfilled or rejected with the original value. If the handler rejects its promise, the returned promise will be rejected with the handler's value. This is similar to throwing an exception in a synchronous `finally` block, causing the original value or exception to be forgotten. This delay can be useful if the actions performed by the handler are done asynchronously. For example:
|
||||
|
||||
```js
|
||||
function ajaxGetAsync(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.addEventListener("error", reject);
|
||||
xhr.addEventListener("load", resolve);
|
||||
xhr.open("GET", url);
|
||||
xhr.send(null);
|
||||
}).finally(function() {
|
||||
return Promise.fromCallback(function(callback) {
|
||||
$("#ajax-loader-animation").fadeOut(1000, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
If the fade out completes successfully, the returned promise will be fulfilled or rejected with the value from `xhr`. If `.fadeOut` throws an exception or passes an error to the callback, the returned promise will be rejected with the error from `.fadeOut`.
|
||||
|
||||
*For compatibility with earlier ECMAScript version, an alias `.lastly` is provided for [`.finally`](.).*
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".finally";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-finally";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,27 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: generators
|
||||
title: Generators
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Generators
|
||||
|
||||
Using ECMAScript6 generators feature to implement C# 5.0 `async/await` like syntax.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Generators";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-generators";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,59 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: get
|
||||
title: .get
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.get
|
||||
|
||||
```js
|
||||
.get(String propertyName|int index) -> Promise
|
||||
```
|
||||
|
||||
|
||||
This is a convenience method for doing:
|
||||
|
||||
```js
|
||||
promise.then(function(obj) {
|
||||
return obj[propertyName];
|
||||
});
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
db.query("...")
|
||||
.get(0)
|
||||
.then(function(firstRow) {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
If `index` is negative, the indexed load will become `obj.length + index`. So that -1 can be used to read last item
|
||||
in the array, -2 to read the second last and so on. For example:
|
||||
|
||||
```js
|
||||
Promise.resolve([1,2,3]).get(-1).then(function(value) {
|
||||
console.log(value); // 3
|
||||
});
|
||||
```
|
||||
|
||||
If the `index` is still negative after `obj.length + index`, it will be clamped to 0.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".get";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-get";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: iscancelled
|
||||
title: .isCancelled
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.isCancelled
|
||||
|
||||
```js
|
||||
.isCancelled() -> boolean
|
||||
```
|
||||
|
||||
See if this `promise` has been cancelled.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".isCancelled";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-iscancelled";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: isfulfilled
|
||||
title: .isFulfilled
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.isFulfilled
|
||||
|
||||
```js
|
||||
.isFulfilled() -> boolean
|
||||
```
|
||||
|
||||
See if this `promise` has been fulfilled.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".isFulfilled";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-isfulfilled";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,32 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: ispending
|
||||
title: .isPending
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.isPending
|
||||
|
||||
```js
|
||||
.isPending() -> boolean
|
||||
```
|
||||
|
||||
|
||||
See if this `promise` is pending (not fulfilled or rejected or cancelled).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".isPending";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-ispending";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: isrejected
|
||||
title: .isRejected
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.isRejected
|
||||
|
||||
```js
|
||||
.isRejected() -> boolean
|
||||
```
|
||||
|
||||
See if this `promise` has been rejected.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".isRejected";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-isrejected";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: map
|
||||
title: .map
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.map
|
||||
|
||||
```js
|
||||
.map(
|
||||
function(any item, int index, int length) mapper,
|
||||
[Object {concurrency: int=Infinity} options]
|
||||
) -> Promise
|
||||
```
|
||||
|
||||
Same as [Promise.map(this, mapper, options)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".map";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-map";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: mapseries
|
||||
title: .mapseries
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##.mapSeries
|
||||
|
||||
```js
|
||||
.mapSeries(function(any item, int index, int length) mapper) -> Promise
|
||||
```
|
||||
|
||||
Same as [Promise.mapSeries(this, iterator)](.).
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = ".mapSeries";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-mapSeries";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,79 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: new-promise
|
||||
title: new Promise
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##new Promise
|
||||
|
||||
```js
|
||||
new Promise(function(function resolve, function reject) resolver) -> Promise
|
||||
```
|
||||
|
||||
|
||||
Create a new promise. The passed in function will receive functions `resolve` and `reject` as its arguments which can be called to seal the fate of the created promise.
|
||||
|
||||
*Note: See [explicit construction anti-pattern]({{ "/docs/anti-patterns.html#the-explicit-construction-anti-pattern" | prepend: site.baseurl }}) before creating promises yourself*
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
function ajaxGetAsync(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.addEventListener("error", reject);
|
||||
xhr.addEventListener("load", resolve);
|
||||
xhr.open("GET", url);
|
||||
xhr.send(null);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
If you pass a promise object to the `resolve` function, the created promise will follow the state of that promise.
|
||||
|
||||
<hr>
|
||||
|
||||
To make sure a function that returns a promise is following the implicit but critically important contract of promises, you can start a function with `new Promise` if you cannot start a chain immediately:
|
||||
|
||||
```js
|
||||
function getConnection(urlString) {
|
||||
return new Promise(function(resolve) {
|
||||
//Without new Promise, this throwing will throw an actual exception
|
||||
var params = parse(urlString);
|
||||
resolve(getAdapter(params).getConnection());
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The above ensures `getConnection` fulfills the contract of a promise-returning function of never throwing a synchronous exception. Also see [`Promise.try`](.) and [`Promise.method`](.)
|
||||
|
||||
The resolver is called synchronously (the following is for documentation purposes and not idiomatic code):
|
||||
|
||||
```js
|
||||
function getPromiseResolveFn() {
|
||||
var res;
|
||||
new Promise(function (resolve) {
|
||||
res = resolve;
|
||||
});
|
||||
// res is guaranteed to be set
|
||||
return res;
|
||||
}
|
||||
```
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "new Promise";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-new-promise";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,35 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: operationalerror
|
||||
title: OperationalError
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##OperationalError
|
||||
|
||||
```js
|
||||
new OperationalError(String message) -> OperationalError
|
||||
```
|
||||
|
||||
|
||||
Represents an error is an explicit promise rejection as opposed to a thrown error. For example, if an error is errbacked by a callback API promisified through undefined or undefined
|
||||
and is not a typed error, it will be converted to a `OperationalError` which has the original error in the `.cause` property.
|
||||
|
||||
`OperationalError`s are caught in [`.error`](.) handlers.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "OperationalError";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-operationalerror";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,105 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: progression-migration
|
||||
title: Progression migration
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Progression migration
|
||||
|
||||
Progression has been removed as there are composability and chaining issues with APIs that use promise progression handlers. Implementing the common use case of progress bars can be accomplished using a pattern similar to [IProgress](http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx) in C#.
|
||||
|
||||
For old code that still uses it, see [the progression docs in the deprecated API documentation](/docs/deprecated-apis.html#progression).
|
||||
|
||||
Using jQuery before:
|
||||
|
||||
```js
|
||||
Promise.resolve($.get(...))
|
||||
.progressed(function() {
|
||||
// ...
|
||||
})
|
||||
.then(function() {
|
||||
// ...
|
||||
})
|
||||
.catch(function(e) {
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
Using jQuery after:
|
||||
|
||||
```js
|
||||
Promise.resolve($.get(...).progress(function() {
|
||||
// ...
|
||||
}))
|
||||
.then(function() {
|
||||
// ...
|
||||
})
|
||||
.catch(function(e) {
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
Implementing general progress interfaces like in C#:
|
||||
|
||||
```js
|
||||
function returnsPromiseWithProgress(progressHandler) {
|
||||
return doFirstAction().tap(function() {
|
||||
progressHandler(0.33);
|
||||
}).then(doSecondAction).tap(function() {
|
||||
progressHandler(0.66);
|
||||
}).then(doThirdAction).tap(function() {
|
||||
progressHandler(1.00);
|
||||
});
|
||||
}
|
||||
|
||||
returnsPromiseWithProgress(function(progress) {
|
||||
ui.progressbar.setWidth((progress * 200) + "px"); // update with on client side
|
||||
}).then(function(value) { // action complete
|
||||
// entire chain is complete.
|
||||
}).catch(function(e) {
|
||||
// error
|
||||
});
|
||||
```
|
||||
|
||||
Another example using `coroutine`:
|
||||
|
||||
```js
|
||||
var doNothing = function() {};
|
||||
var progressSupportingCoroutine = Promise.coroutine(function* (progress) {
|
||||
progress = typeof progress === "function" ? progress : doNothing;
|
||||
var first = yield getFirstValue();
|
||||
// 33% done
|
||||
progress(0.33);
|
||||
var second = yield getSecondValue();
|
||||
progress(0.67);
|
||||
var third = yield getThirdValue();
|
||||
progress(1);
|
||||
return [first, second, third];
|
||||
});
|
||||
|
||||
var progressConsumingCoroutine = Promise.coroutine(function* () {
|
||||
var allValues = yield progressSupportingCoroutine(function(p) {
|
||||
ui.progressbar.setWidth((p * 200) + "px");
|
||||
});
|
||||
var second = allValues[1];
|
||||
// ...
|
||||
});
|
||||
```
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Progression migration";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-progression-migration";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,47 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.all
|
||||
title: Promise.all
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.all
|
||||
|
||||
```js
|
||||
Promise.all(Iterable<any>|Promise<Iterable<any>> input) -> Promise
|
||||
```
|
||||
|
||||
This method is useful for when you want to wait for more than one promise to complete.
|
||||
|
||||
Given an [`Iterable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)\(arrays are `Iterable`\), or a promise of an `Iterable`, which produces promises (or a mix of promises and values), iterate over all the values in the `Iterable` into an array and return a promise that is fulfilled when all the items in the array are fulfilled. The promise's fulfillment value is an array with fulfillment values at respective positions to the original array. If any promise in the array rejects, the returned promise is rejected with the rejection reason.
|
||||
|
||||
|
||||
```js
|
||||
var files = [];
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
files.push(fs.writeFileAsync("file-" + i + ".txt", "", "utf-8"));
|
||||
}
|
||||
Promise.all(files).then(function() {
|
||||
console.log("all the files were created");
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
This method is compatible with [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) from native promises.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.all";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.all";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.any
|
||||
title: Promise.any
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.any
|
||||
|
||||
```js
|
||||
Promise.any(Iterable<any>|Promise<Iterable<any>> input) -> Promise
|
||||
```
|
||||
|
||||
Like [Promise.some](.), with 1 as `count`. However, if the promise fulfills, the fulfillment value is not an array of 1 but the value directly.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.any";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.any";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,177 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.bind
|
||||
title: Promise.bind
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.bind
|
||||
|
||||
```js
|
||||
Promise.bind(
|
||||
any|Promise<any> thisArg,
|
||||
[any|Promise<any> value=undefined]
|
||||
) -> BoundPromise
|
||||
```
|
||||
|
||||
Create a promise that follows this promise or in the static method is resolved with the given `value`, but is bound to the given `thisArg` value. A bound promise will call its handlers with the bound value set to `this`. Additionally promises derived from a bound promise will also be bound promises with the same `thisArg` binding as the original promise.
|
||||
|
||||
If `thisArg` is a promise or thenable, its resolution will be awaited for and the bound value will be the promise's fulfillment value. If `thisArg` rejects
|
||||
then the returned promise is rejected with the `thisArg's` rejection reason. Note that this means you cannot use `this` without checking inside catch handlers for promises that bind to promise because in case of rejection of `thisArg`, `this` will be `undefined`.
|
||||
|
||||
<hr>
|
||||
|
||||
Without arrow functions that provide lexical `this`, the correspondence between async and sync code breaks down when writing object-oriented code. [`.bind`](.) alleviates this.
|
||||
|
||||
Consider:
|
||||
|
||||
```js
|
||||
MyClass.prototype.method = function() {
|
||||
try {
|
||||
var contents = fs.readFileSync(this.file);
|
||||
var url = urlParse(contents);
|
||||
var result = this.httpGetSync(url);
|
||||
var refined = this.refine(result);
|
||||
return this.writeRefinedSync(refined);
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e.stack);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The above has a direct translation:
|
||||
|
||||
```js
|
||||
MyClass.prototype.method = function() {
|
||||
return fs.readFileAsync(this.file).bind(this)
|
||||
.then(function(contents) {
|
||||
var url = urlParse(contents);
|
||||
return this.httpGetAsync(url);
|
||||
}).then(function(result) {
|
||||
var refined = this.refine(result);
|
||||
return this.writeRefinedAsync(refined);
|
||||
}).catch(function(e) {
|
||||
this.error(e.stack);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
`.bind` is the most efficient way of utilizing `this` with promises. The handler functions in the above code are not closures and can therefore even be hoisted out if needed. There is literally no overhead when propagating the bound value from one promise to another.
|
||||
|
||||
<hr>
|
||||
|
||||
`.bind` also has a useful side purpose - promise handlers don't need to share a function to use shared state:
|
||||
|
||||
```js
|
||||
somethingAsync().bind({})
|
||||
.spread(function (aValue, bValue) {
|
||||
this.aValue = aValue;
|
||||
this.bValue = bValue;
|
||||
return somethingElseAsync(aValue, bValue);
|
||||
})
|
||||
.then(function (cValue) {
|
||||
return this.aValue + this.bValue + cValue;
|
||||
});
|
||||
```
|
||||
|
||||
The above without [`.bind`](.) could be achieved with:
|
||||
|
||||
```js
|
||||
var scope = {};
|
||||
somethingAsync()
|
||||
.spread(function (aValue, bValue) {
|
||||
scope.aValue = aValue;
|
||||
scope.bValue = bValue;
|
||||
return somethingElseAsync(aValue, bValue);
|
||||
})
|
||||
.then(function (cValue) {
|
||||
return scope.aValue + scope.bValue + cValue;
|
||||
});
|
||||
```
|
||||
|
||||
However, there are many differences when you look closer:
|
||||
|
||||
- Requires a statement so cannot be used in an expression context
|
||||
- If not there already, an additional wrapper function is required to aundefined leaking or sharing `scope`
|
||||
- The handler functions are now closures, thus less efficient and not reusable
|
||||
|
||||
<hr>
|
||||
|
||||
Note that bind is only propagated with promise transformation. If you create new promise chains inside a handler, those chains are not bound to the "upper" `this`:
|
||||
|
||||
```js
|
||||
something().bind(var1).then(function() {
|
||||
//`this` is var1 here
|
||||
return Promise.all(getStuff()).then(function(results) {
|
||||
//`this` is undefined here
|
||||
//refine results here etc
|
||||
});
|
||||
}).then(function() {
|
||||
//`this` is var1 here
|
||||
});
|
||||
```
|
||||
|
||||
However, if you are utilizing the full bluebird API offering, you will *almost never* need to resort to nesting promises in the first place. The above should be written more like:
|
||||
|
||||
```js
|
||||
something().bind(var1).then(function() {
|
||||
//`this` is var1 here
|
||||
return getStuff();
|
||||
}).map(function(result) {
|
||||
//`this` is var1 here
|
||||
//refine result here
|
||||
}).then(function() {
|
||||
//`this` is var1 here
|
||||
});
|
||||
```
|
||||
|
||||
Also see this [Stackoverflow answer](http://stackoverflow.com/a/24412873/191693) as an additional example.
|
||||
|
||||
<hr>
|
||||
|
||||
If you don't want to return a bound promise to the consumers of a promise, you can rebind the chain at the end:
|
||||
|
||||
```js
|
||||
MyClass.prototype.method = function() {
|
||||
return fs.readFileAsync(this.file).bind(this)
|
||||
.then(function(contents) {
|
||||
var url = urlParse(contents);
|
||||
return this.httpGetAsync(url);
|
||||
}).then(function(result) {
|
||||
var refined = this.refine(result);
|
||||
return this.writeRefinedAsync(refined);
|
||||
}).catch(function(e) {
|
||||
this.error(e.stack);
|
||||
}).bind(); //The `thisArg` is implicitly undefined - I.E. the default promise `this` value
|
||||
};
|
||||
```
|
||||
|
||||
Rebinding can also be abused to do something gratuitous like this:
|
||||
|
||||
```js
|
||||
Promise.resolve("my-element")
|
||||
.bind(document)
|
||||
.then(document.getElementById)
|
||||
.bind(console)
|
||||
.then(console.log);
|
||||
```
|
||||
|
||||
The above does a `console.log` of `my-element`. Doing it this way is necessary because neither of the methods (`getElementById`, `console.log`) can be called as stand-alone methods.
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.bind";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.bind";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,84 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.config
|
||||
title: Promise.config
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.config
|
||||
|
||||
```js
|
||||
Promise.config(Object {
|
||||
warnings: boolean=false,
|
||||
longStackTraces: boolean=false,
|
||||
cancellation: boolean=false,
|
||||
monitoring: boolean=false
|
||||
} options) -> undefined;
|
||||
```
|
||||
|
||||
Configure long stack traces, warnings, monitoring and cancellation. Note that even though `false` is the default here, a development environment might be detected which automatically enables long stack traces and warnings.
|
||||
|
||||
```js
|
||||
Promise.config({
|
||||
// Enable warnings
|
||||
warnings: true,
|
||||
// Enable long stack traces
|
||||
longStackTraces: true,
|
||||
// Enable cancellation
|
||||
cancellation: true,
|
||||
// Enable monitoring
|
||||
monitoring: true
|
||||
});
|
||||
```
|
||||
|
||||
You can configure the warning for checking forgotten return statements with `wForgottenReturn`:
|
||||
|
||||
```js
|
||||
Promise.config({
|
||||
// Enables all warnings except forgotten return statements.
|
||||
warnings: {
|
||||
wForgottenReturn: false
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
`wForgottenReturn` is the only warning type that can be separately configured. The corresponding environmental variable key is `BLUEBIRD_W_FORGOTTEN_RETURN`.
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
|
||||
In Node.js you may configure warnings and long stack traces for the entire process using environment variables:
|
||||
|
||||
```
|
||||
BLUEBIRD_LONG_STACK_TRACES=1 BLUEBIRD_WARNINGS=1 node app.js
|
||||
```
|
||||
|
||||
Both features are automatically enabled if the `BLUEBIRD_DEBUG` environment variable has been set or if the `NODE_ENV` environment variable is equal to `"development"`.
|
||||
|
||||
Using the value `0` will explicitly disable a feature despite debug environment otherwise activating it:
|
||||
|
||||
```
|
||||
# Warnings are disabled despite being in development environment
|
||||
NODE_ENV=development BLUEBIRD_WARNINGS=0 node app.js
|
||||
```
|
||||
|
||||
Cancellation is always configured separately per bluebird instance.
|
||||
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.config";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.config";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,122 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.coroutine.addyieldhandler
|
||||
title: Promise.coroutine.addYieldHandler
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.coroutine.addYieldHandler
|
||||
|
||||
```js
|
||||
Promise.coroutine.addYieldHandler(function handler) -> undefined
|
||||
```
|
||||
|
||||
|
||||
By default you can only yield Promises and Thenables inside coroutines. You can use this function to add yielding support for arbitrary types.
|
||||
|
||||
For example, if you wanted `yield 500` to be same as `yield Promise.delay`:
|
||||
|
||||
```js
|
||||
Promise.coroutine.addYieldHandler(function(value) {
|
||||
if (typeof value === "number") return Promise.delay(value);
|
||||
});
|
||||
```
|
||||
|
||||
Yield handlers are called when you yield something that is not supported by default. The first yield handler to return a promise or a thenable will be used.
|
||||
If no yield handler returns a promise or a thenable then an error is raised.
|
||||
|
||||
An example of implementing callback support with `addYieldHandler`:
|
||||
|
||||
*This is a demonstration of how powerful the feature is and not the recommended usage. For best performance you need to use `promisifyAll` and yield promises directly.*
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
var fs = require("fs");
|
||||
|
||||
var _ = (function() {
|
||||
var promise = null;
|
||||
Promise.coroutine.addYieldHandler(function(v) {
|
||||
if (v === undefined && promise != null) {
|
||||
return promise;
|
||||
}
|
||||
promise = null;
|
||||
});
|
||||
return function() {
|
||||
var def = Promise.defer();
|
||||
promise = def.promise;
|
||||
return def.callback;
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
var readFileJSON = Promise.coroutine(function* (fileName) {
|
||||
var contents = yield fs.readFile(fileName, "utf8", _());
|
||||
return JSON.parse(contents);
|
||||
});
|
||||
```
|
||||
|
||||
An example of implementing thunks support with `addYieldHandler`:
|
||||
|
||||
*This is a demonstration of how powerful the feature is and not the recommended usage. For best performance you need to use `promisifyAll` and yield promises directly.*
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
var fs = require("fs");
|
||||
|
||||
Promise.coroutine.addYieldHandler(function(v) {
|
||||
if (typeof v === "function") {
|
||||
return Promise.fromCallback(function(cb) {
|
||||
v(cb);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var readFileThunk = function(fileName, encoding) {
|
||||
return function(cb) {
|
||||
return fs.readFile(fileName, encoding, cb);
|
||||
};
|
||||
};
|
||||
|
||||
var readFileJSON = Promise.coroutine(function* (fileName) {
|
||||
var contents = yield readFileThunk(fileName, "utf8");
|
||||
return JSON.parse(contents);
|
||||
});
|
||||
```
|
||||
|
||||
An example of handling promises in parallel by adding an `addYieldHandler` for arrays :
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
var fs = Promise.promisifyAll(require("fs"));
|
||||
|
||||
Promise.coroutine.addYieldHandler(function(yieldedValue) {
|
||||
if (Array.isArray(yieldedValue)) return Promise.all(yieldedValue);
|
||||
});
|
||||
|
||||
var readFiles = Promise.coroutine(function* (fileNames) {
|
||||
var promises = [];
|
||||
|
||||
fileNames.forEach(function (fileName) {
|
||||
promises.push(fs.readFileAsync(fileName, "utf8"));
|
||||
});
|
||||
|
||||
return yield promises;
|
||||
});
|
||||
```
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.coroutine.addYieldHandler";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.coroutine.addyieldhandler";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,76 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.coroutine
|
||||
title: Promise.coroutine
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.coroutine
|
||||
|
||||
```js
|
||||
Promise.coroutine(GeneratorFunction(...arguments) generatorFunction) -> function
|
||||
```
|
||||
|
||||
Returns a function that can use `yield` to yield promises. Control is returned back to the generator when the yielded promise settles. This can lead to less verbose code when doing lots of sequential async calls with minimal processing in between. Requires node.js 0.12+, io.js 1.0+ or Google Chrome 40+.
|
||||
|
||||
```js
|
||||
var Promise = require("bluebird");
|
||||
|
||||
function PingPong() {
|
||||
|
||||
}
|
||||
|
||||
PingPong.prototype.ping = Promise.coroutine(function* (val) {
|
||||
console.log("Ping?", val)
|
||||
yield Promise.delay(500)
|
||||
this.pong(val+1)
|
||||
});
|
||||
|
||||
PingPong.prototype.pong = Promise.coroutine(function* (val) {
|
||||
console.log("Pong!", val)
|
||||
yield Promise.delay(500);
|
||||
this.ping(val+1)
|
||||
});
|
||||
|
||||
var a = new PingPong();
|
||||
a.ping(0);
|
||||
```
|
||||
|
||||
Running the example:
|
||||
|
||||
$ node test.js
|
||||
Ping? 0
|
||||
Pong! 1
|
||||
Ping? 2
|
||||
Pong! 3
|
||||
Ping? 4
|
||||
Pong! 5
|
||||
Ping? 6
|
||||
Pong! 7
|
||||
Ping? 8
|
||||
...
|
||||
|
||||
When called, the coroutine function will start an instance of the generator and returns a promise for its final value.
|
||||
|
||||
Doing `Promise.coroutine` is almost like using the C# `async` keyword to mark the function, with `yield` working as the `await` keyword. Promises are somewhat like `Task`s.
|
||||
|
||||
**Tip**
|
||||
|
||||
You are able to yield non-promise values by adding your own yield handler using [`Promise.coroutine.addYieldHandler`](.)
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.coroutine";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.coroutine";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
@ -1,47 +0,0 @@
|
||||
---
|
||||
layout: api
|
||||
id: promise.delay
|
||||
title: Promise.delay
|
||||
---
|
||||
|
||||
|
||||
[← Back To API Reference](/docs/api-reference.html)
|
||||
<div class="api-code-section"><markdown>
|
||||
##Promise.delay
|
||||
|
||||
```js
|
||||
Promise.delay(
|
||||
int ms,
|
||||
[any|Promise<any> value=undefined]
|
||||
) -> Promise
|
||||
```
|
||||
|
||||
|
||||
Returns a promise that will be resolved with `value` (or `undefined`) after given `ms` milliseconds. If `value` is a promise, the delay will start counting down when it is fulfilled and the returned promise will be fulfilled with the fulfillment value of the `value` promise.
|
||||
|
||||
```js
|
||||
Promise.delay(500).then(function() {
|
||||
console.log("500 ms passed");
|
||||
return "Hello world";
|
||||
}).delay(500).then(function(helloWorldString) {
|
||||
console.log(helloWorldString);
|
||||
console.log("another 500 ms passed") ;
|
||||
});
|
||||
```
|
||||
|
||||
<hr>
|
||||
</markdown></div>
|
||||
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="text/javascript">
|
||||
var disqus_title = "Promise.delay";
|
||||
var disqus_shortname = "bluebirdjs";
|
||||
var disqus_identifier = "disqus-id-promise.delay";
|
||||
|
||||
(function() {
|
||||
var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
|
||||
dsq.src = "//" + disqus_shortname + ".disqus.com/embed.js";
|
||||
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user