Spaces:
Sleeping
Sleeping
File size: 4,946 Bytes
e7b2eb4 | 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 | // @flow
import {Event, Evented} from '../util/evented';
import {getArrayBuffer} from '../util/ajax';
import browser from '../util/browser';
import assert from 'assert';
import {isWorker} from '../util/util';
const status = {
unavailable: 'unavailable', // Not loaded
deferred: 'deferred', // The plugin URL has been specified, but loading has been deferred
loading: 'loading', // request in-flight
loaded: 'loaded',
error: 'error'
};
export type PluginState = {
pluginStatus: $Values<typeof status>;
pluginURL: ?string
};
type ErrorCallback = (error: ?Error) => void;
type PluginStateSyncCallback = (state: PluginState) => void;
let _completionCallback = null;
//Variables defining the current state of the plugin
let pluginStatus = status.unavailable;
let pluginURL = null;
export const triggerPluginCompletionEvent = function(error: ?Error) {
// NetworkError's are not correctly reflected by the plugin status which prevents reloading plugin
if (error && typeof error === 'string' && error.indexOf('NetworkError') > -1) {
pluginStatus = status.error;
}
if (_completionCallback) {
_completionCallback(error);
}
};
function sendPluginStateToWorker() {
evented.fire(new Event('pluginStateChange', {pluginStatus, pluginURL}));
}
export const evented = new Evented();
export const getRTLTextPluginStatus = function () {
return pluginStatus;
};
export const registerForPluginStateChange = function(callback: PluginStateSyncCallback) {
// Do an initial sync of the state
callback({pluginStatus, pluginURL});
// Listen for all future state changes
evented.on('pluginStateChange', callback);
return callback;
};
export const clearRTLTextPlugin = function() {
pluginStatus = status.unavailable;
pluginURL = null;
};
export const setRTLTextPlugin = function(url: string, callback: ?ErrorCallback, deferred: boolean = false) {
if (pluginStatus === status.deferred || pluginStatus === status.loading || pluginStatus === status.loaded) {
throw new Error('setRTLTextPlugin cannot be called multiple times.');
}
pluginURL = browser.resolveURL(url);
pluginStatus = status.deferred;
_completionCallback = callback;
sendPluginStateToWorker();
//Start downloading the plugin immediately if not intending to lazy-load
if (!deferred) {
downloadRTLTextPlugin();
}
};
export const downloadRTLTextPlugin = function() {
if (pluginStatus !== status.deferred || !pluginURL) {
throw new Error('rtl-text-plugin cannot be downloaded unless a pluginURL is specified');
}
pluginStatus = status.loading;
sendPluginStateToWorker();
if (pluginURL) {
getArrayBuffer({url: pluginURL}, (error) => {
if (error) {
triggerPluginCompletionEvent(error);
} else {
pluginStatus = status.loaded;
sendPluginStateToWorker();
}
});
}
};
export const plugin: {
applyArabicShaping: ?Function,
processBidirectionalText: ?(string, Array<number>) => Array<string>,
processStyledBidirectionalText: ?(string, Array<number>, Array<number>) => Array<[string, Array<number>]>,
isLoaded: () => boolean,
isLoading: () => boolean,
setState: (state: PluginState) => void,
isParsed: () => boolean,
getPluginURL: () => ?string
} = {
applyArabicShaping: null,
processBidirectionalText: null,
processStyledBidirectionalText: null,
isLoaded() {
return pluginStatus === status.loaded || // Main Thread: loaded if the completion callback returned successfully
plugin.applyArabicShaping != null; // Web-worker: loaded if the plugin functions have been compiled
},
isLoading() { // Main Thread Only: query the loading status, this function does not return the correct value in the worker context.
return pluginStatus === status.loading;
},
setState(state: PluginState) { // Worker thread only: this tells the worker threads that the plugin is available on the Main thread
assert(isWorker(), 'Cannot set the state of the rtl-text-plugin when not in the web-worker context');
pluginStatus = state.pluginStatus;
pluginURL = state.pluginURL;
},
isParsed(): boolean {
assert(isWorker(), 'rtl-text-plugin is only parsed on the worker-threads');
return plugin.applyArabicShaping != null &&
plugin.processBidirectionalText != null &&
plugin.processStyledBidirectionalText != null;
},
getPluginURL(): ?string {
assert(isWorker(), 'rtl-text-plugin url can only be queried from the worker threads');
return pluginURL;
}
};
export const lazyLoadRTLTextPlugin = function() {
if (!plugin.isLoading() &&
!plugin.isLoaded() &&
getRTLTextPluginStatus() === 'deferred'
) {
downloadRTLTextPlugin();
}
};
|