| @@ -1,17 +1,18 | |||||
| 1 | 
            
            import inject  | 
        
             | 
        1 | import inject from "./dom-inject"; | |
| 2 | import { id as mid} from "module"; | 
             | 
        2 | ||
| 3 | import { TraceSource } from "@implab/core-amd/log/TraceSource"; | 
             | 
        3 | interface OnLoad { | |
| 4 | const log = TraceSource.get(mid); | 
             | 
        4 | (result?: any): void; | |
| 
             | 
        5 | error(err: any): void; | |||
| 
             | 
        6 | } | |||
| 5 | 
             | 
        7 | |||
| 6 | const plugin = { | 
             | 
        8 | const plugin = { | |
| 7 | 
            
                load: | 
        
             | 
        9 | load: (id: string, require: Require, cb: OnLoad, config: { isBuild?: boolean }) => { | |
| 8 | const url = require.toUrl(id); | 
             | 
        10 | if (config.isBuild) { | |
| 9 | 
            
                     | 
        
             | 
        11 | cb(); | |
| 10 | await inject.injectStylesheet(url); | 
             | 
        12 | } else { | |
| 11 | 
            
                        c | 
        
             | 
        13 | const url = require.toUrl(id); | |
| 12 | } catch (e) { | 
             | 
        14 | inject.injectStylesheet(url).then(() => cb({ url }), e => cb.error(e)); | |
| 13 | log.error("CSS plugin failed to load {0} ({1}): {2}", id, url, e); | 
             | 
        |||
| 14 | } | 
             | 
        15 | } | |
| 15 | } | 
             | 
        16 | } | |
| 16 | }; | 
             | 
        17 | }; | |
| 17 | export = plugin; | 
             | 
        18 | export = plugin; | |
| @@ -1,97 +1,100 | |||||
| 1 | import { id as mid } from "module"; | 
             | 
        1 | import { id as mid } from "module"; | |
| 2 | import { TraceSource } from "@implab/core-amd/log/TraceSource"; | 
             | 
        2 | import { TraceSource } from "@implab/core-amd/log/TraceSource"; | |
| 3 | import { MapOf } from "@implab/core-amd/interfaces"; | 
             | 
        3 | import { MapOf } from "@implab/core-amd/interfaces"; | |
| 4 | import { mixin } from "@implab/core-amd/safe"; | 
             | 
        4 | import { mixin } from "@implab/core-amd/safe"; | |
| 5 | 
             | 
        5 | |||
| 6 | const trace = TraceSource.get(mid); | 
             | 
        6 | const trace = TraceSource.get(mid); | |
| 7 | 
             | 
        7 | |||
| 8 | 
             | 
        8 | |||
| 9 | function on<T extends keyof HTMLElementEventMap>(node: HTMLElement, eventName: T, handler: (this: HTMLElement, ev: HTMLElementEventMap[T]) => any): () => void { | 
             | 
        9 | function on<T extends keyof HTMLElementEventMap>(node: HTMLElement, eventName: T, handler: (this: HTMLElement, ev: HTMLElementEventMap[T]) => any): () => void { | |
| 10 | // Add an event listener to a DOM node | 
             | 
        10 | // Add an event listener to a DOM node | |
| 11 | node.addEventListener(eventName, handler, false); | 
             | 
        11 | node.addEventListener(eventName, handler, false); | |
| 12 | 
             | 
        12 | |||
| 13 | return () => node.removeEventListener(eventName, handler, false); | 
             | 
        13 | return () => node.removeEventListener(eventName, handler, false); | |
| 14 | } | 
             | 
        14 | } | |
| 15 | 
             | 
        15 | |||
| 16 | interface NodeLoadResult { | 
             | 
        16 | interface NodeLoadResult { | |
| 17 | node: HTMLElement; | 
             | 
        17 | node: HTMLElement; | |
| 18 | } | 
             | 
        18 | } | |
| 19 | 
             | 
        19 | |||
| 20 | class DomInject { | 
             | 
        20 | class DomInject { | |
| 21 | 
            
                injectionPoint | 
        
             | 
        21 | injectionPoint?: HTMLElement; | |
| 22 | injectBefore = document.head.firstChild; | 
             | 
        22 | injectBefore?: HTMLElement; | |
| 23 | 
             | 
        23 | |||
| 24 | _map: MapOf<Promise<NodeLoadResult>> = {}; | 
             | 
        24 | _map: MapOf<Promise<NodeLoadResult>> = {}; | |
| 25 | 
             | 
        25 | |||
| 26 | _inject<T extends keyof HTMLElementTagNameMap>(name: T, attr: Partial<HTMLElementTagNameMap[T]>) { | 
             | 
        26 | _inject<T extends keyof HTMLElementTagNameMap>(name: T, attr: Partial<HTMLElementTagNameMap[T]>) { | |
| 27 | const node = document.createElement(name); | 
             | 
        27 | const node = document.createElement(name); | |
| 28 | 
             | 
        28 | |||
| 29 | return new Promise<NodeLoadResult>((ok, fail) => { | 
             | 
        29 | return new Promise<NodeLoadResult>((ok, fail) => { | |
| 30 | 
             | 
        30 | |||
| 31 | const cleanup = () => { | 
             | 
        31 | const cleanup = () => { | |
| 32 | noerr(); | 
             | 
        32 | noerr(); | |
| 33 | noload(); | 
             | 
        33 | noload(); | |
| 34 | }; | 
             | 
        34 | }; | |
| 35 | 
             | 
        35 | |||
| 36 | const noload = on(node, "load", () => { | 
             | 
        36 | const noload = on(node, "load", () => { | |
| 37 | ok({ node }); | 
             | 
        37 | ok({ node }); | |
| 38 | cleanup(); | 
             | 
        38 | cleanup(); | |
| 39 | }); | 
             | 
        39 | }); | |
| 40 | 
             | 
        40 | |||
| 41 | const noerr = on(node, "error", e => { | 
             | 
        41 | const noerr = on(node, "error", e => { | |
| 42 | fail({ | 
             | 
        42 | fail({ | |
| 43 | erorr: e, | 
             | 
        43 | erorr: e, | |
| 44 | node | 
             | 
        44 | node | |
| 45 | }); | 
             | 
        45 | }); | |
| 46 | cleanup(); | 
             | 
        46 | cleanup(); | |
| 47 | }); | 
             | 
        47 | }); | |
| 48 | 
             | 
        48 | |||
| 49 | mixin(node, attr); | 
             | 
        49 | mixin(node, attr); | |
| 50 | 
             | 
        50 | |||
| 51 | this.injectionPoint.insertBefore(node, this.injectBefore); | 
             | 
        51 | const _injectionPoint = this.injectionPoint || document.head; | |
| 
             | 
        52 | const _injectBefore = this.injectBefore || _injectionPoint.firstChild; | |||
| 
             | 
        53 | ||||
| 
             | 
        54 | _injectionPoint.insertBefore(node, _injectBefore); | |||
| 52 | }); | 
             | 
        55 | }); | |
| 53 | } | 
             | 
        56 | } | |
| 54 | 
             | 
        57 | |||
| 55 | async injectScript(url: string) { | 
             | 
        58 | async injectScript(url: string) { | |
| 56 | let d = this._map[url]; | 
             | 
        59 | let d = this._map[url]; | |
| 57 | if (!d) { | 
             | 
        60 | if (!d) { | |
| 58 | trace.log("js {0}", url); | 
             | 
        61 | trace.log("js {0}", url); | |
| 59 | d = this._inject("script", { | 
             | 
        62 | d = this._inject("script", { | |
| 60 | type: "text/javascript", | 
             | 
        63 | type: "text/javascript", | |
| 61 | charset: "utf-8", | 
             | 
        64 | charset: "utf-8", | |
| 62 | src: url | 
             | 
        65 | src: url | |
| 63 | }); | 
             | 
        66 | }); | |
| 64 | this._map[url] = d; | 
             | 
        67 | this._map[url] = d; | |
| 65 | } | 
             | 
        68 | } | |
| 66 | try { | 
             | 
        69 | try { | |
| 67 | await d; | 
             | 
        70 | await d; | |
| 68 | trace.log("done {0}", url); | 
             | 
        71 | trace.log("done {0}", url); | |
| 69 | } catch (e) { | 
             | 
        72 | } catch (e) { | |
| 70 | trace.error("failed {0}: {1}", url, e); | 
             | 
        73 | trace.error("failed {0}: {1}", url, e); | |
| 71 | throw e; | 
             | 
        74 | throw e; | |
| 72 | } | 
             | 
        75 | } | |
| 73 | } | 
             | 
        76 | } | |
| 74 | 
             | 
        77 | |||
| 75 | async injectStylesheet(url: string) { | 
             | 
        78 | async injectStylesheet(url: string) { | |
| 76 | let d = this._map[url]; | 
             | 
        79 | let d = this._map[url]; | |
| 77 | if (!d) { | 
             | 
        80 | if (!d) { | |
| 78 | trace.log("js {0}", url); | 
             | 
        81 | trace.log("js {0}", url); | |
| 79 | d = this._inject("link", { | 
             | 
        82 | d = this._inject("link", { | |
| 80 | type: "text/css", | 
             | 
        83 | type: "text/css", | |
| 81 | rel: "stylesheet", | 
             | 
        84 | rel: "stylesheet", | |
| 82 | href: url | 
             | 
        85 | href: url | |
| 83 | }); | 
             | 
        86 | }); | |
| 84 | this._map[url] = d; | 
             | 
        87 | this._map[url] = d; | |
| 85 | } | 
             | 
        88 | } | |
| 86 | try { | 
             | 
        89 | try { | |
| 87 | await d; | 
             | 
        90 | await d; | |
| 88 | trace.log("done {0}", url); | 
             | 
        91 | trace.log("done {0}", url); | |
| 89 | } catch (e) { | 
             | 
        92 | } catch (e) { | |
| 90 | trace.error("failed {0}: {1}", url, e); | 
             | 
        93 | trace.error("failed {0}: {1}", url, e); | |
| 91 | throw e; | 
             | 
        94 | throw e; | |
| 92 | } | 
             | 
        95 | } | |
| 93 | } | 
             | 
        96 | } | |
| 94 | }; | 
             | 
        97 | }; | |
| 95 | 
             | 
        98 | |||
| 96 | const instance = new DomInject(); | 
             | 
        99 | const instance = new DomInject(); | |
| 97 | 
            
            export  | 
        
             | 
        100 | export default instance; | |
| @@ -1,29 +1,38 | |||||
| 1 | import { MapOf } from "@implab/core-amd/interfaces"; | 
             | 
        1 | import { MapOf } from "@implab/core-amd/interfaces"; | |
| 2 | import { NlsBundle } from "./NlsBundle"; | 
             | 
        2 | import { NlsBundle } from "./NlsBundle"; | |
| 3 | import { isPromise } from "@implab/core-amd/safe"; | 
             | 
        3 | import { isPromise } from "@implab/core-amd/safe"; | |
| 4 | 
             | 
        4 | |||
| 
             | 
        5 | interface OnLoad { | |||
| 
             | 
        6 | (result?: any): void; | |||
| 
             | 
        7 | error(err: any): void; | |||
| 
             | 
        8 | } | |||
| 
             | 
        9 | ||||
| 5 | export function bundle<T extends object>(nls: T, locales?: MapOf<any>) { | 
             | 
        10 | export function bundle<T extends object>(nls: T, locales?: MapOf<any>) { | |
| 6 | const nlsBundle = new NlsBundle(nls, locales); | 
             | 
        11 | const nlsBundle = new NlsBundle(nls, locales); | |
| 7 | 
             | 
        12 | |||
| 8 | const fn = (locale?: string) => { | 
             | 
        13 | const fn = (locale?: string) => { | |
| 9 | const result = locale ? nlsBundle.getLocale(locale) : nlsBundle.default; | 
             | 
        14 | const result = locale ? nlsBundle.getLocale(locale) : nlsBundle.default; | |
| 10 | 
             | 
        15 | |||
| 11 | if (isPromise(result)) | 
             | 
        16 | if (isPromise(result)) | |
| 12 | throw new Error(`The bundle '${locale}' isn't loaded`); | 
             | 
        17 | throw new Error(`The bundle '${locale}' isn't loaded`); | |
| 13 | else | 
             | 
        18 | else | |
| 14 | return result; | 
             | 
        19 | return result; | |
| 15 | }; | 
             | 
        20 | }; | |
| 16 | 
             | 
        21 | |||
| 17 | fn.define = (pack: Partial<T>) => pack; | 
             | 
        22 | fn.define = (pack: Partial<T>) => pack; | |
| 18 | fn.default = nlsBundle.default; | 
             | 
        23 | fn.default = nlsBundle.default; | |
| 19 | 
            
                fn.load = async (id: string, require: Require, cb:  | 
        
             | 
        24 | fn.load = async (id: string, require: Require, cb: OnLoad, config: any) => { | |
| 20 | try { | 
             | 
        25 | if (config.isBuild) { | |
| 21 | await nlsBundle.getLocale(id); | 
             | 
        |||
| 22 | cb(); | 
             | 
        26 | cb(); | |
| 23 | 
            
                    }  | 
        
             | 
        27 | } else { | |
| 24 | 
            
                         | 
        
             | 
        28 | try { | |
| 
             | 
        29 | await nlsBundle.getLocale(id); | |||
| 
             | 
        30 | cb(); | |||
| 
             | 
        31 | } catch (e) { | |||
| 
             | 
        32 | cb.error(e); | |||
| 
             | 
        33 | } | |||
| 25 | } | 
             | 
        34 | } | |
| 26 | }; | 
             | 
        35 | }; | |
| 27 | 
             | 
        36 | |||
| 28 | return fn; | 
             | 
        37 | return fn; | |
| 29 | } | 
             | 
        38 | } | |
        
        General Comments 0
    
    
  
  
                      You need to be logged in to leave comments.
                      Login now
                    
                