From d4491015059e94a37ac1bb579fcc4494b3db31f1 Mon Sep 17 00:00:00 2001 From: psi77 Date: Tue, 5 Feb 2019 23:48:03 +0000 Subject: [PATCH 1/4] Sort of working dynamic loading and execution of javascript --- src/app/button-page/button-page.component.ts | 12 ++- src/app/custom-action.service.spec.ts | 15 ++++ src/app/custom-action.service.ts | 78 ++++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/app/custom-action.service.spec.ts create mode 100644 src/app/custom-action.service.ts diff --git a/src/app/button-page/button-page.component.ts b/src/app/button-page/button-page.component.ts index d62d003..845b6e4 100644 --- a/src/app/button-page/button-page.component.ts +++ b/src/app/button-page/button-page.component.ts @@ -19,6 +19,7 @@ import { OBFBoard, Button, LoadBoardAction, Grid } from '../obfboard'; import { Subscription, Subscriber } from 'rxjs'; import { ScanningService, ScanningModel, ScannableCollectionProvider, ScannableCollection, Scannable } from '../scanning.service'; import { ConfigService } from '../config.service'; +import { CustomActionService } from '../custom-action.service'; @Component({ selector: 'app-button-page', @@ -42,8 +43,13 @@ export class ButtonPageComponent implements OnInit, OnDestroy { ':space': this.speechbarService.space.bind(this.speechbarService) }; - constructor(private boardService: BoardService, private speechbarService: SpeechbarService, - private scanningService: ScanningService, private configService: ConfigService) { } + constructor( + private boardService: BoardService, + private speechbarService: SpeechbarService, + private scanningService: ScanningService, + private configService: ConfigService, + private customActionService: CustomActionService + ) { } ngOnInit() { this.loadBoard(); @@ -132,6 +138,8 @@ export class ButtonPageComponent implements OnInit, OnDestroy { if (action.startsWith('+')) { this.speechbarService.appendButton(button, action); + } else if (action.startsWith(':ext')) { + this.customActionService.handle(action); } else { const actionPerformer = this.actionPerformers[action]; diff --git a/src/app/custom-action.service.spec.ts b/src/app/custom-action.service.spec.ts new file mode 100644 index 0000000..cc97787 --- /dev/null +++ b/src/app/custom-action.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { CustomActionService } from './custom-action.service'; + +describe('CustomActionService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [CustomActionService] + }); + }); + + it('should be created', inject([CustomActionService], (service: CustomActionService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/custom-action.service.ts b/src/app/custom-action.service.ts new file mode 100644 index 0000000..347e207 --- /dev/null +++ b/src/app/custom-action.service.ts @@ -0,0 +1,78 @@ +import { Injectable } from '@angular/core'; + +interface Scripts { + name: string; + src: string; +} +export const ScriptStore: Scripts[] = [ + { + name: 'lib1', + src: 'https://dl.dropbox.com/s/yf06gz438yz9ftb/helloLib.js?dl=1' + } +]; + +declare var document: any; + +@Injectable({ + providedIn: 'root' +}) +export class CustomActionService { + + private scripts: any = {}; + + constructor() { + ScriptStore.forEach((script: any) => { + this.scripts[script.name] = { + loaded: false, + src: script.src + }; + }); + } + + load(...scripts: string[]) { + const promises: any[] = []; + scripts.forEach((script) => promises.push(this.loadScript(script))); + return Promise.all(promises); + } + + loadScript(name: string) { + return new Promise((resolve, reject) => { + // resolve if already loaded + if (this.scripts[name].loaded) { + resolve({ script: name, loaded: true, status: 'Already Loaded' }); + } else { + // load script + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = this.scripts[name].src; + if (script.readyState) { // IE + script.onreadystatechange = () => { + if (script.readyState === 'loaded' || script.readyState === 'complete') { + script.onreadystatechange = null; + this.scripts[name].loaded = true; + resolve({ script: name, loaded: true, status: 'Loaded' }); + } + }; + } else { // Others + script.onload = () => { + this.scripts[name].loaded = true; + resolve({ script: name, loaded: true, status: 'Loaded' }); + }; + } + script.onerror = (error: any) => resolve({ script: name, loaded: false, status: 'Loaded' }); + document.getElementsByTagName('head')[0].appendChild(script); + } + }); + } + + handle(action: string) { + + if (action.startsWith(':ext:ovf')) { + console.log(action); + this.load('lib1').then(data => { + console.log('script loaded ', data); + window['helloLib']['hello'](); + }).catch(error => console.log(error)); + } + } +} From 76c94df0b128daf86c05512a8221272d72022ee3 Mon Sep 17 00:00:00 2001 From: psi77 Date: Wed, 6 Feb 2019 14:00:44 +0000 Subject: [PATCH 2/4] More generic calling of js --- src/app/custom-action.service.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/custom-action.service.ts b/src/app/custom-action.service.ts index 347e207..19ad714 100644 --- a/src/app/custom-action.service.ts +++ b/src/app/custom-action.service.ts @@ -67,11 +67,21 @@ export class CustomActionService { handle(action: string) { - if (action.startsWith(':ext:ovf')) { + if (action.startsWith(':ext_ovf_js:')) { console.log(action); + const jsCall = action.slice(12); + // TODO: this doesn't make sense now! Load everything up front? + // Or interogate for namespace...(would still require loading!) this.load('lib1').then(data => { console.log('script loaded ', data); - window['helloLib']['hello'](); + let func = window; + for (const ns of jsCall.split('.')) { + // TODO: sometimes this will fail! + func = func[ns]; + } + if (typeof func === 'function') { + (func)(); + } }).catch(error => console.log(error)); } } From 23298465fe713cde58d72aab070877a14c3ad6e7 Mon Sep 17 00:00:00 2001 From: psi77 Date: Sat, 9 Feb 2019 20:22:53 +0000 Subject: [PATCH 3/4] Generic ifttt lib --- src/app/button-page/button-page.component.ts | 2 +- src/app/custom-action.service.ts | 17 ++++++++++++++--- src/assets/libraries/iftttLib.js | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 src/assets/libraries/iftttLib.js diff --git a/src/app/button-page/button-page.component.ts b/src/app/button-page/button-page.component.ts index 845b6e4..d12c42c 100644 --- a/src/app/button-page/button-page.component.ts +++ b/src/app/button-page/button-page.component.ts @@ -139,7 +139,7 @@ export class ButtonPageComponent implements OnInit, OnDestroy { if (action.startsWith('+')) { this.speechbarService.appendButton(button, action); } else if (action.startsWith(':ext')) { - this.customActionService.handle(action); + this.customActionService.handle(button, action); } else { const actionPerformer = this.actionPerformers[action]; diff --git a/src/app/custom-action.service.ts b/src/app/custom-action.service.ts index 19ad714..e8a806a 100644 --- a/src/app/custom-action.service.ts +++ b/src/app/custom-action.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { Button } from './obfboard'; interface Scripts { name: string; @@ -8,6 +9,10 @@ export const ScriptStore: Scripts[] = [ { name: 'lib1', src: 'https://dl.dropbox.com/s/yf06gz438yz9ftb/helloLib.js?dl=1' + }, + { + name: 'iftttLib', + src: '/assets/libraries/iftttLib.js' } ]; @@ -65,14 +70,14 @@ export class CustomActionService { }); } - handle(action: string) { + handle(button: Button, action: string) { if (action.startsWith(':ext_ovf_js:')) { console.log(action); const jsCall = action.slice(12); // TODO: this doesn't make sense now! Load everything up front? // Or interogate for namespace...(would still require loading!) - this.load('lib1').then(data => { + this.load('iftttLib').then(data => { console.log('script loaded ', data); let func = window; for (const ns of jsCall.split('.')) { @@ -80,7 +85,13 @@ export class CustomActionService { func = func[ns]; } if (typeof func === 'function') { - (func)(); + const context = { + 'button': button + }; + const config = { + 'key': 'p3TpnduBdAzMwwfgIkuzEB7fm3plXAyrd8pl2sOdCUp' + }; + (func)(context, config); } }).catch(error => console.log(error)); } diff --git a/src/assets/libraries/iftttLib.js b/src/assets/libraries/iftttLib.js new file mode 100644 index 0000000..6882eb7 --- /dev/null +++ b/src/assets/libraries/iftttLib.js @@ -0,0 +1,16 @@ +var iftttLib = (function () { + var self = {}; + + var sendRequest = function(action, key) { + var url = "https://maker.ifttt.com/trigger/" + action + "/with/key/" + key + var http = new XMLHttpRequest(); + http.open("GET", url); + http.send(); + } + + self.action = function(context, config) { + sendRequest(context.button.id, config['key']); + } + + return self; +}()); From 8821486bd20921523493fcddd2df2710c4d47cc2 Mon Sep 17 00:00:00 2001 From: psi77 Date: Sat, 9 Feb 2019 20:33:07 +0000 Subject: [PATCH 4/4] Remove secret stuff --- src/app/custom-action.service.ts | 9 ++++++--- src/assets/libraries/iftttLib.js | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/app/custom-action.service.ts b/src/app/custom-action.service.ts index e8a806a..4ad7a42 100644 --- a/src/app/custom-action.service.ts +++ b/src/app/custom-action.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { Button } from './obfboard'; +import { LocalStorage } from 'ngx-store'; interface Scripts { name: string; @@ -25,6 +26,9 @@ export class CustomActionService { private scripts: any = {}; + @LocalStorage() + private _iftttLibConfig; + constructor() { ScriptStore.forEach((script: any) => { this.scripts[script.name] = { @@ -40,6 +44,7 @@ export class CustomActionService { return Promise.all(promises); } + // TODO: tidy this up and get config involved loadScript(name: string) { return new Promise((resolve, reject) => { // resolve if already loaded @@ -88,9 +93,7 @@ export class CustomActionService { const context = { 'button': button }; - const config = { - 'key': 'p3TpnduBdAzMwwfgIkuzEB7fm3plXAyrd8pl2sOdCUp' - }; + const config = this._iftttLibConfig; (func)(context, config); } }).catch(error => console.log(error)); diff --git a/src/assets/libraries/iftttLib.js b/src/assets/libraries/iftttLib.js index 6882eb7..1feee32 100644 --- a/src/assets/libraries/iftttLib.js +++ b/src/assets/libraries/iftttLib.js @@ -1,14 +1,14 @@ var iftttLib = (function () { var self = {}; - var sendRequest = function(action, key) { - var url = "https://maker.ifttt.com/trigger/" + action + "/with/key/" + key + var sendRequest = function(trigger, key) { + var url = "https://maker.ifttt.com/trigger/" + trigger + "/with/key/" + key var http = new XMLHttpRequest(); http.open("GET", url); http.send(); } - self.action = function(context, config) { + self.trigger = function(context, config) { sendRequest(context.button.id, config['key']); }