-
-
Notifications
You must be signed in to change notification settings - Fork 29
/
asq-helpers.js
154 lines (135 loc) · 5.97 KB
/
asq-helpers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// asq-helpers.js: Helpers for asynquence and Chrome callbacks.
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define('asq-helpers', ['asynquence-contrib'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('asynquence-contrib'));
} else {
// Browser globals (root is `window`)
root.ASQH = factory(root.ASQ);
}
}(this, function (ASQ) {
"use strict";
function loginfo(...args) { log_orig.info('TabFern template.js: ', ...args); }; //TODO
/// The module we are creating
let module = {};
// Test for Firefox //
// Not sure if I need this, but I'm playing it safe for now. Firefox puts
// null rather than undefined in chrome.runtime.lastError when there is
// no error. This is to test for null in Firefox without changing my
// Chrome code. Hopefully in the future I can test for null/undefined
// in either browser, and get rid of this block.
// This duplicates code in TabFern's src/common/common.js, but I am
// including it here to avoid a circular dependency.
// src/common/common.js relies on this file, but not the other way around.
(function(mod){
let isLastError_chrome =
()=>{return (typeof(chrome.runtime.lastError) !== 'undefined');};
let isLastError_firefox =
()=>{return (chrome.runtime.lastError !== null);};
if(typeof browser !== 'undefined' && browser.runtime &&
browser.runtime.getBrowserInfo) {
browser.runtime.getBrowserInfo().then(
(info)=>{ // fullfillment
if(info.name === 'Firefox') {
mod.isLastError = isLastError_firefox;
} else {
mod.isLastError = isLastError_chrome;
}
},
()=>{ //rejection --- assume Chrome by default
mod.isLastError = isLastError_chrome;
}
);
} else { // Chrome
mod.isLastError = isLastError_chrome;
}
})(module);
/// Chrome Callback: make a Chrome extension API callback that
/// wraps the done() callback of an asynquence step. This is for use within
/// an ASQ().then(...).
module.CC = (function(){
/// A special-purpose empty object, per getify
const ø = Object.create(null);
return (done)=>{
return function cbk() {
if(module.isLastError()) {
done.fail(chrome.runtime.lastError);
} else {
//done.apply(ø,...args);
// for some reason done() doesn't get the args
// provided to cbk(...args)
done.apply(ø,[].slice.call(arguments));
}
}
}
})(); //CC()
/// Chrome callback to kick off a sequence, rather than within a sequence.
/// @param seq An asynquence instance
/// @param ignore_error [optional, default false]
// If truthy, read but disregard chrome.runtime.lastError
/// @return A Chrome callback that will resume the sequence.
/// @post The provided #seq will pause at whatever was the end of the chain
/// when this was called. It will stay there until the returned
/// callback is invoked.
module.CCgo = function(seq, ignore_error = false) {
let cbk = seq.errfcb();
let retval;
if(ignore_error) {
retval = function inner(...args) { void chrome.runtime.lastError; cbk(null, ...args); }
} else {
retval = function inner(...args) { cbk(chrome.runtime.lastError, ...args); }
}
return retval;
} //CCgo()
/// Take action on this tick, and kick off a sequence based on a Chrome
/// callback.
/// @param do_right_now {function} Called as do_right_now(chrome_cbk).
/// Should cause chrome_cbk to be invoked
/// when the sequence should proceed.
/// @return A sequence to chain off.
module.NowCC = function(do_right_now) {
let seq = ASQ();
let chrcbk = module.CCgo(seq);
do_right_now(chrcbk);
return seq;
} //ASQ.NowCC()
/// Take action on this tick, and kick off a sequence based on a Chrome
/// callback, as if called with ASQ.try.
/// @param do_right_now {function} Called as do_right_now(chrome_cbk).
/// Should cause chrome_cbk to be invoked
/// when the sequence should proceed.
/// @return A sequence to chain off.
module.NowCCTry = function(do_right_now) {
// Inner sequence that provides the Chrome callback and the
// try/catch functionality
let inner_seq = ASQ();
let inner_chrcbk = module.CCgo(inner_seq);
// Outer sequence that we will return
let outer_seq = ASQ().duplicate(); //paused
// When inner_seq finishes, run outer_seq. There must be a
// better way to do this, but I don't know what it is. You can't
// put a .then() after a .or(), as far as I know.
// ... Actually, maybe there's not a better way. asq-contrib.try()
// also uses an inner sequence.
inner_seq.val((...args)=>{
outer_seq.unpause(...args);
})
.or((failure)=>{ // like ASQ().try()
outer_seq.unpause( { 'catch': failure } );
});
// Kick it off
do_right_now(inner_chrcbk);
return outer_seq;
} //ASQ.NowCCTry()
/// Check for an asynquence-contrib try() error return
module.is_asq_try_err = function(o)
{
return (typeof o === 'object' && o &&
typeof o.catch !== 'undefined');
} //is_asq_try_err
return module;
}));
// vi: set ts=4 sts=4 sw=4 et ai fo-=o: //