@iebh/tera-fy 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/api.md +333 -188
- package/dist/plugin.vue2.es2019.js +1 -1
- package/dist/plugin.vue2.es2019.js.map +3 -3
- package/dist/terafy.es2019.js +2 -2
- package/dist/terafy.es2019.js.map +3 -3
- package/dist/terafy.js +2 -2
- package/dist/terafy.js.map +3 -3
- package/hints.md +26 -0
- package/lib/terafy.client.js +149 -18
- package/lib/terafy.server.js +415 -54
- package/package.json +10 -11
- package/plugins/vue2.js +68 -0
- package/utils/pDefer.js +15 -0
package/hints.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
TERA-fy Hints
|
|
2
|
+
=============
|
|
3
|
+
Hints are a single string attached to file uploads to provide some context as to where it fits within the overall process. They are usually past-tense single-words indicating the output from each stage.
|
|
4
|
+
|
|
5
|
+
When attached to files they indicate that the generated file is an output from a stage. e.g. if a file is noted with the hint 'deduped' it indicates it is the product of a de-duplication stage.
|
|
6
|
+
|
|
7
|
+
They are used in multiple places:
|
|
8
|
+
|
|
9
|
+
* Calls to most project library handling functions - `selectProjectLibrary()`, `setProjectLibrary()`
|
|
10
|
+
* Within the UI to indicate what library is used during what process
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Hint Reference
|
|
14
|
+
--------------
|
|
15
|
+
The following is a non-definitive list of hints that can be associated with files. In all cases the hint should be a lower-case single, past-tense word. Upper-case indicates a variable.
|
|
16
|
+
|
|
17
|
+
This list should also be mirrored in the main tera-tools.com/api/tools.json meta-list.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
| Hint | Description |
|
|
21
|
+
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
22
|
+
| `search` | The product of a search design stage |
|
|
23
|
+
| `deduped` | One or more files, that are the product of a deduplication stage |
|
|
24
|
+
| `screened-X` | One or more files from the screening stage, generally there will be one file per reviewer where `X` indicates the reviewer number starting with the number 1 |
|
|
25
|
+
| `disputed` | Generally a single file which is the product of a resolved dispute stage which merges in multiple `screened-X` files |
|
|
26
|
+
| `snowballed` | A file which has been through the snowballing stage |
|
package/lib/terafy.client.js
CHANGED
|
@@ -17,16 +17,19 @@ export default class TeraFy {
|
|
|
17
17
|
*
|
|
18
18
|
* @type {Object}
|
|
19
19
|
* @property {Boolean} devMode Operate in devMode - i.e. force outer refresh when encountering an existing TeraFy instance
|
|
20
|
-
* @property {'detect'|'parent'|'child'} How to communicate with TERA. 'parent' assumes that the parent of the current document is TERA, 'child' spawns an iFrame and uses TERA there, 'detect' tries parent and
|
|
20
|
+
* @property {'detect'|'parent'|'child'|'popup'} mode How to communicate with TERA. 'parent' assumes that the parent of the current document is TERA, 'child' spawns an iFrame and uses TERA there, 'detect' tries parent and switches to `modeFallback` if communication fails
|
|
21
|
+
* @property {String} modeFallback Method to use when all method detection fails
|
|
21
22
|
* @property {Number} modeTimeout How long entities have in 'detect' mode to identify themselves
|
|
22
23
|
* @property {String} siteUrl The TERA URL to connect to
|
|
23
24
|
* @property {String} restrictOrigin URL to restrict communications to
|
|
24
25
|
* @property {Array<String>} List of sandbox allowables for the embedded if in embed mode
|
|
26
|
+
* @property {Number} handshakeInterval Interval in milliseconds when sanning for a handshake
|
|
25
27
|
*/
|
|
26
28
|
settings = {
|
|
27
29
|
devMode: true,
|
|
28
30
|
mode: 'detect',
|
|
29
31
|
modeTimeout: 300,
|
|
32
|
+
modeFallback: 'child', // ENUM: 'child' (use iframes), 'popup' (use popup windows)
|
|
30
33
|
siteUrl: 'https://tera-tools.com/embed',
|
|
31
34
|
restrictOrigin: '*', // FIXME: Need to restrict this to TERA site
|
|
32
35
|
frameSandbox: [
|
|
@@ -39,8 +42,9 @@ export default class TeraFy {
|
|
|
39
42
|
'allow-presentation',
|
|
40
43
|
'allow-same-origin',
|
|
41
44
|
'allow-scripts',
|
|
42
|
-
'allow-top-navigation'
|
|
45
|
+
'allow-top-navigation',
|
|
43
46
|
],
|
|
47
|
+
handshakeInterval: 1000,
|
|
44
48
|
};
|
|
45
49
|
|
|
46
50
|
|
|
@@ -56,12 +60,14 @@ export default class TeraFy {
|
|
|
56
60
|
*
|
|
57
61
|
* @type {Object}
|
|
58
62
|
* @property {DOMElement} el The main tera-fy div wrapper
|
|
59
|
-
* @property {DOMElement} iframe The internal iFrame element
|
|
63
|
+
* @property {DOMElement} iframe The internal iFrame element (if `settings.mode == 'child'`)
|
|
64
|
+
* @property {Window} popup The popup window context (if `settings.mode == 'popup'`)
|
|
60
65
|
* @property {DOMElement} stylesheet The corresponding stylesheet
|
|
61
66
|
*/
|
|
62
67
|
dom = {
|
|
63
68
|
el: null,
|
|
64
69
|
iframe: null,
|
|
70
|
+
popup: null,
|
|
65
71
|
stylesheet: null,
|
|
66
72
|
};
|
|
67
73
|
|
|
@@ -87,13 +93,13 @@ export default class TeraFy {
|
|
|
87
93
|
// For bindProjectState() - See individual plugins
|
|
88
94
|
|
|
89
95
|
// Project files
|
|
90
|
-
'getProjectFiles',
|
|
96
|
+
'selectProjectFile', 'getProjectFiles',
|
|
91
97
|
|
|
92
98
|
// Project Libraries
|
|
93
|
-
'
|
|
99
|
+
'selectProjectLibrary', 'parseProjectLibrary', 'setProjectLibrary',
|
|
94
100
|
|
|
95
101
|
// UI
|
|
96
|
-
'uiAlert',
|
|
102
|
+
'uiAlert', 'uiSplat', 'uiWindow',
|
|
97
103
|
];
|
|
98
104
|
|
|
99
105
|
|
|
@@ -149,6 +155,8 @@ export default class TeraFy {
|
|
|
149
155
|
window.parent.postMessage(payload, this.settings.restrictOrigin);
|
|
150
156
|
} else if (this.settings.mode == 'child') {
|
|
151
157
|
this.dom.iframe.contentWindow.postMessage(payload, this.settings.restrictOrigin);
|
|
158
|
+
} else if (this.settings.mode == 'popup') {
|
|
159
|
+
this.dom.popup.postMessage(payload, this.settings.restrictOrigin);
|
|
152
160
|
} else if (this.settings.mode == 'detect') {
|
|
153
161
|
throw new Error('Call init() or detectMode() before trying to send data to determine the mode');
|
|
154
162
|
} else {
|
|
@@ -305,7 +313,8 @@ export default class TeraFy {
|
|
|
305
313
|
]))
|
|
306
314
|
.then(()=> this.rpc('setServerMode', // Tell server what mode its in
|
|
307
315
|
this.settings.mode == 'child' ? 'embedded'
|
|
308
|
-
: this.settings.mode == 'parent' ? '
|
|
316
|
+
: this.settings.mode == 'parent' ? 'frame'
|
|
317
|
+
: this.settings.mode == 'popup' ? 'popup'
|
|
309
318
|
: (()=> { throw(`Unknown server mode "${this.settings.mode}"`) })()
|
|
310
319
|
))
|
|
311
320
|
.then(()=> Promise.all( // Init all plugins (with this outer module as the context)
|
|
@@ -327,7 +336,7 @@ export default class TeraFy {
|
|
|
327
336
|
if (this.settings.mode != 'detect') { // Dev has specified a forced mode to use
|
|
328
337
|
return this.settings.mode;
|
|
329
338
|
} else if (window.self === window.parent) { // This frame is already at the top
|
|
330
|
-
return
|
|
339
|
+
return this.settings.modeFallback;
|
|
331
340
|
} else { // No idea - try messaging
|
|
332
341
|
return Promise.resolve()
|
|
333
342
|
.then(()=> this.settings.mode = 'parent') // Switch to parent mode...
|
|
@@ -339,7 +348,7 @@ export default class TeraFy {
|
|
|
339
348
|
.then(()=> resolve())
|
|
340
349
|
}))
|
|
341
350
|
.then(()=> 'parent')
|
|
342
|
-
.catch(()=>
|
|
351
|
+
.catch(()=> this.settings.modeFallback)
|
|
343
352
|
}
|
|
344
353
|
}
|
|
345
354
|
|
|
@@ -373,9 +382,34 @@ export default class TeraFy {
|
|
|
373
382
|
this.dom.el.append(this.dom.iframe);
|
|
374
383
|
break;
|
|
375
384
|
case 'parent':
|
|
376
|
-
this.debug('Using TERA
|
|
385
|
+
this.debug('Using TERA window parent');
|
|
377
386
|
resolve();
|
|
378
387
|
break;
|
|
388
|
+
case 'popup':
|
|
389
|
+
this.debug('Injecting TERA site as a popup window');
|
|
390
|
+
this.dom.popup = window.open(this.settings.siteUrl, '_blank', 'popup=1, location=0, menubar=0, status=0, scrollbars=0, width=500, height=600');
|
|
391
|
+
|
|
392
|
+
// Loop until the window context returns a handshake
|
|
393
|
+
(()=> {
|
|
394
|
+
let handshakeCount = 0;
|
|
395
|
+
let handshakeTimer;
|
|
396
|
+
|
|
397
|
+
const tryHandshake = ()=> {
|
|
398
|
+
this.debug('Trying handshake', ++handshakeCount);
|
|
399
|
+
|
|
400
|
+
clearTimeout(handshakeTimer);
|
|
401
|
+
handshakeTimer = setTimeout(tryHandshake, this.settings.handshakeInterval);
|
|
402
|
+
|
|
403
|
+
this.rpc('handshake')
|
|
404
|
+
.then(()=> {
|
|
405
|
+
clearTimeout(handshakeTimer);
|
|
406
|
+
this.debug('Popup window accepted handshake');
|
|
407
|
+
resolve();
|
|
408
|
+
});
|
|
409
|
+
};
|
|
410
|
+
tryHandshake();
|
|
411
|
+
})();
|
|
412
|
+
break;
|
|
379
413
|
default:
|
|
380
414
|
throw new Error(`Unsupported mode "${this.settings.mode}" when calling injectComms()`);
|
|
381
415
|
}
|
|
@@ -434,6 +468,7 @@ export default class TeraFy {
|
|
|
434
468
|
document.head.appendChild(this.dom.stylesheet);
|
|
435
469
|
break;
|
|
436
470
|
case 'parent':
|
|
471
|
+
case 'popup':
|
|
437
472
|
break;
|
|
438
473
|
default:
|
|
439
474
|
throw new Error(`Unsupported mode "${this.settings.mode}" when injectStylesheet()`);
|
|
@@ -624,7 +659,11 @@ export default class TeraFy {
|
|
|
624
659
|
* This is an pre-requisite step for requireProject()
|
|
625
660
|
*
|
|
626
661
|
* @function requireUser
|
|
627
|
-
*
|
|
662
|
+
*
|
|
663
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
664
|
+
* @param {Boolean} [options.forceRetry=false] Forcabily try to refresh the user state
|
|
665
|
+
*
|
|
666
|
+
* @returns {Promise<User>} The current logged in user or null if none
|
|
628
667
|
*/
|
|
629
668
|
|
|
630
669
|
|
|
@@ -798,6 +837,35 @@ export default class TeraFy {
|
|
|
798
837
|
* @property {String} mime The associated mime type for the file
|
|
799
838
|
*/
|
|
800
839
|
|
|
840
|
+
/**
|
|
841
|
+
* Data structure for a file filter
|
|
842
|
+
* @name FileFilters
|
|
843
|
+
*
|
|
844
|
+
* @property {Boolean} [library=false] Restrict to library files only
|
|
845
|
+
* @property {String} [filename] CSV of @momsfriendlydevco/match expressions to filter the filename by (filenames are the basename sans extension)
|
|
846
|
+
* @property {String} [basename] CSV of @momsfriendlydevco/match expressions to filter the basename by
|
|
847
|
+
* @property {String} [ext] CSV of @momsfriendlydevco/match expressions to filter the file extension by
|
|
848
|
+
*/
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Prompt the user to select a library to operate on
|
|
853
|
+
*
|
|
854
|
+
* @function selectProjectFile
|
|
855
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
856
|
+
* @param {String} [options.title="Select a file"] The title of the dialog to display
|
|
857
|
+
* @param {String|Array<String>} [options.hint] Hints to identify the file to select in array order of preference
|
|
858
|
+
* @param {FileFilters} [options.filters] Optional file filters
|
|
859
|
+
* @param {Boolean} [options.allowUpload=true] Allow uploading new files
|
|
860
|
+
* @param {Boolean} [options.allowRefresh=true] Allow the user to manually refresh the file list
|
|
861
|
+
* @param {Boolean} [options.allowDownloadZip=true] Allow the user to download a Zip of all files
|
|
862
|
+
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if acationed
|
|
863
|
+
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
864
|
+
* @param {FileFilters} [options.filter] Optional file filters
|
|
865
|
+
*
|
|
866
|
+
* @returns {Promise<ProjectFile>} The eventually selected file
|
|
867
|
+
*/
|
|
868
|
+
|
|
801
869
|
|
|
802
870
|
/**
|
|
803
871
|
* Fetch the files associated with a given project
|
|
@@ -807,25 +875,60 @@ export default class TeraFy {
|
|
|
807
875
|
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
808
876
|
* @param {Boolean} [options.meta=true] Pull meta information for each file entity
|
|
809
877
|
*
|
|
810
|
-
* @returns {Promise<ProjectFile
|
|
878
|
+
* @returns {Promise<Array<ProjectFile>>} A collection of project files for the given project
|
|
879
|
+
*/
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Prompt the user to select a library to operate on and return a array of references in a given format
|
|
884
|
+
*
|
|
885
|
+
* @function selectProjectLibrary
|
|
886
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
887
|
+
* @param {String} [options.title="Select a citation library"] The title of the dialog to display
|
|
888
|
+
* @param {String|Array<String>} [options.hint] Hints to identify the library to select in array order of preference. Generally corresponds to the previous stage - e.g. 'deduped', 'review1', 'review2', 'dedisputed'
|
|
889
|
+
* @param {Boolean} [options.allowUpload=true] Allow uploading new files
|
|
890
|
+
* @param {Boolean} [options.allowRefresh=true] Allow the user to manually refresh the file list
|
|
891
|
+
* @param {Boolean} [options.allowDownloadZip=true] Allow the user to download a Zip of all files
|
|
892
|
+
* @param {Boolean} [options.allowCancel=true] Allow cancelling the operation. Will throw `'CANCEL'` as the promise rejection if acationed
|
|
893
|
+
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
894
|
+
* @param {FileFilters} [options.filters] Optional file filters, defaults to citation library selection only
|
|
895
|
+
* @param {*} [options.*] Additional options - see `parseProjectLibrary()`
|
|
896
|
+
*
|
|
897
|
+
* @returns {Promise<Array<Ref>>} A collection of references from the selected file
|
|
811
898
|
*/
|
|
812
899
|
|
|
813
900
|
|
|
814
901
|
/**
|
|
815
|
-
*
|
|
902
|
+
* Convert a project file into a library of citations
|
|
816
903
|
*
|
|
817
|
-
* @function
|
|
818
|
-
* @param {String}
|
|
904
|
+
* @function parseProjectLibrary
|
|
905
|
+
* @param {String} path File path to read, if omitted the contents of `options` are used to guess at a suitable file
|
|
819
906
|
*
|
|
820
907
|
* @param {Object} [options] Additional options to mutate behaviour
|
|
821
908
|
* @param {String} [options.format='json'] Format for the file. ENUM: 'pojo' (return a parsed JS collection), 'blob' (raw JS Blob object), 'file' (named JS File object)
|
|
822
909
|
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
823
|
-
* @param {Boolean} [options.multiple=false] Allow selection of multiple libraries
|
|
824
910
|
* @param {Function} [options.filter] Optional async file filter, called each time as `(File:ProjectFile)`
|
|
825
911
|
* @param {Function} [options.find] Optional async final stage file filter to reduce all candidates down to one subject file
|
|
826
|
-
* @param {String|Array<String>} [options.hint] Hints to identify the library to select in array order of preference. Generally corresponds to the previous stage - e.g. 'deduped', 'review1', 'review2', 'dedisputed'
|
|
827
912
|
*
|
|
828
|
-
* @returns {Promise<Array<
|
|
913
|
+
* @returns {Promise<Array<Ref>>|Promise<*>} A collection of references (default bevahiour) or a whatever format was requested
|
|
914
|
+
*/
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* Save back a citation library from some input
|
|
919
|
+
*
|
|
920
|
+
* @function setProjectLibrary
|
|
921
|
+
* @param {String} [path] File path to save back to
|
|
922
|
+
* @param {Array<RefLibRef>} Collection of references for the selected library
|
|
923
|
+
*
|
|
924
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
925
|
+
* @param {String} [options.format='json'] Input format used. ENUM: 'pojo' (return a parsed JS collection), 'blob' (raw JS Blob object), 'file' (named JS File object)
|
|
926
|
+
* @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
|
|
927
|
+
* @param {String} [options.hint] Hint to store against the library. Generally corresponds to the current operation being performed - e.g. 'deduped'
|
|
928
|
+
* @param {Boolean} [options.overwrite=true] Allow existing file upsert
|
|
929
|
+
* @param {Object} [options.meta] Optional meta data to merge into the file data
|
|
930
|
+
*
|
|
931
|
+
* @returns {Promise} A promise which resolves when the save operation has completed
|
|
829
932
|
*/
|
|
830
933
|
|
|
831
934
|
|
|
@@ -856,5 +959,33 @@ export default class TeraFy {
|
|
|
856
959
|
* @returns {Promise} A promise which resolves when the alert has been dismissed
|
|
857
960
|
*/
|
|
858
961
|
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Display HTML content full-screen within TERA
|
|
965
|
+
* This function is ideally called within a requestFocus() wrapper
|
|
966
|
+
*
|
|
967
|
+
* @function uiSplat
|
|
968
|
+
* @param {DOMElement|String|false} content Either a prepared DOM element or string to compile, set to falsy to remove existing content
|
|
969
|
+
*
|
|
970
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
971
|
+
* @param {Boolean|String} [options.logo=false] Add a logo to the output, if boolean true the Tera-tools logo is used otherwise specify a path or URL
|
|
972
|
+
*/
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Open a popup window containing a new site
|
|
977
|
+
*
|
|
978
|
+
* @function uiWindow
|
|
979
|
+
* @param {String} url The URL to open
|
|
980
|
+
*
|
|
981
|
+
* @param {Object} [options] Additional options to mutate behaviour
|
|
982
|
+
* @param {Number} [options.width=500] The desired width of the window
|
|
983
|
+
* @param {Number} [options.height=600] The desired height of the window
|
|
984
|
+
* @param {Boolean} [options.center=true] Attempt to center the window on the screen
|
|
985
|
+
* @param {Object} [options.permissions] Additional permissions to set on opening, defaults to a suitable set of permission for popups (see code)
|
|
986
|
+
*
|
|
987
|
+
* @returns {WindowProxy} The opened window object (if `noopener` is not set in permissions)
|
|
988
|
+
*/
|
|
989
|
+
|
|
859
990
|
// }}}
|
|
860
991
|
}
|