blob: ff32f0de3f7b9ae46a815d06e03be9c695c8468e [file] [log] [blame]
Matteo Scandolofb46ae62017-08-08 09:10:50 -07001
2/*
3 * Copyright 2017-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
Matteo Scandolo4222a432017-01-23 12:18:40 -080019import * as $ from 'jquery';
20import * as _ from 'lodash';
21
22export interface IXosComponentInjectorService {
Matteo Scandoloe2643b92017-01-31 14:40:33 -080023 injectedComponents: IXosInjectedComponent[];
Matteo Scandolo4222a432017-01-23 12:18:40 -080024 injectComponent(target: string | JQuery, componentName: string, attributes?: any, transclude?: string, clean?: boolean): void;
25 removeInjectedComponents(target: string | JQuery): void;
26}
27
Matteo Scandoloe2643b92017-01-31 14:40:33 -080028export interface IXosInjectedComponent {
29 targetEl: string;
30 componentName: string;
31 attributes?: any;
32 transclude?: string;
33 clean?: boolean;
34}
35
Matteo Scandolo4222a432017-01-23 12:18:40 -080036export class XosComponentInjector implements IXosComponentInjectorService {
Matteo Scandolo5053cbe2017-01-31 17:37:56 -080037 static $inject = ['$rootScope', '$compile', '$transitions', '$log', '$timeout'];
Matteo Scandoloe2643b92017-01-31 14:40:33 -080038
39 public injectedComponents: IXosInjectedComponent[] = [];
Matteo Scandolo4222a432017-01-23 12:18:40 -080040
41 constructor (
42 private $rootScope: ng.IRootScopeService,
Matteo Scandoloe2643b92017-01-31 14:40:33 -080043 private $compile: ng.ICompileService,
44 private $transitions: any,
Matteo Scandolo5053cbe2017-01-31 17:37:56 -080045 private $log: ng.ILogService,
46 private $timeout: ng.ITimeoutService
Matteo Scandolo4222a432017-01-23 12:18:40 -080047 ) {
Matteo Scandoloe2643b92017-01-31 14:40:33 -080048 $transitions.onFinish({ to: '**' }, (transtion) => {
49 // wait for route transition to complete
50 transtion.promise.then(t => {
51 _.forEach(this.injectedComponents, (component: IXosInjectedComponent) => {
52 const container = $(component.targetEl);
53 // if we have the container, re-attach the component
54 if (container.length > 0) {
55 this.injectComponent(
56 container,
57 component.componentName,
58 component.attributes,
59 component.transclude,
60 component.clean
61 );
62 }
63 });
64 });
65 });
Matteo Scandolo4222a432017-01-23 12:18:40 -080066 }
67
68 public injectComponent(target: string | JQuery, componentName: string, attributes?: any, transclude?: string, clean?: boolean) {
69 let targetEl;
70 if (angular.isString(target)) {
Matteo Scandoloe2643b92017-01-31 14:40:33 -080071
72 if (target.indexOf('#') === -1) {
73 this.$log.warn(`[XosComponentInjector] Target element should be identified by an ID, you passed: ${target}`);
74 }
75
Matteo Scandolo4222a432017-01-23 12:18:40 -080076 targetEl = $(target);
77 }
78 else {
79 targetEl = target;
80 }
81
82 const componentTagName = this.camelToSnakeCase(componentName);
83 let scope = this.$rootScope.$new();
84 let attr: string = '';
85
86 if (clean) {
87 this.removeInjectedComponents(target);
88 }
89
90 if (angular.isDefined(attributes) && angular.isObject(attributes)) {
91 attr = this.stringifyAttributes(attributes);
Matteo Scandolo520a8a12017-03-10 17:31:37 -080092 // we cannot use angular.merge as it cast Resource to Objects
93 _.forEach(Object.keys(attributes), (k: string) => {
94 scope[k] = attributes[k];
95 });
Matteo Scandolo4222a432017-01-23 12:18:40 -080096 }
97
98 const componentTag = `<${componentTagName} ${attr}>${transclude || ''}</${componentTagName}>`;
99 const element = this.$compile(componentTag)(scope);
100
Matteo Scandolo5053cbe2017-01-31 17:37:56 -0800101 this.$timeout(function() {
102 scope.$apply();
103 });
104
Matteo Scandolo4222a432017-01-23 12:18:40 -0800105 targetEl.append(element);
Matteo Scandoloe2643b92017-01-31 14:40:33 -0800106
107 // store a reference for the element
108 this.storeInjectedComponent({
109 targetEl: angular.isString(target) ? target : '#' + targetEl.attr('id'),
110 componentName: componentName,
111 attributes: attributes,
112 transclude: transclude,
113 clean: clean,
114 });
Matteo Scandolo4222a432017-01-23 12:18:40 -0800115 }
116
117 public removeInjectedComponents(target: string | JQuery) {
118 const targetEl = $(target);
119 targetEl.html('');
120 }
121
Matteo Scandoloe2643b92017-01-31 14:40:33 -0800122 private isComponendStored(component: IXosInjectedComponent) {
123 return _.find(this.injectedComponents, (c: IXosInjectedComponent) => {
124 return c.targetEl === component.targetEl
125 && c.componentName === component.componentName
126 && _.isEqual(c.attributes, component.attributes)
127 && c.transclude === component.transclude
128 && c.clean === component.clean;
129 });
130 }
131
132 private storeInjectedComponent(component: IXosInjectedComponent) {
133 const isAlreadyStored = this.isComponendStored(component);
134 if (!isAlreadyStored) {
135 this.injectedComponents.push(component);
136 }
137 }
138
Matteo Scandolo4222a432017-01-23 12:18:40 -0800139 private stringifyAttributes(attributes: any): string {
140 return _.reduce(Object.keys(attributes), (string: string, a: string) => {
Matteo Scandolo837e0cc2017-01-25 11:37:34 -0800141 string += `${this.camelToSnakeCase(a)}="${a}"`;
Matteo Scandolo4222a432017-01-23 12:18:40 -0800142 return string;
143 }, '');
144 }
145
146 private camelToSnakeCase(name: string): string {
147 return name.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join('-');
148 };
149}