Added Side panel component

Change-Id: I6c10fc025c904262872b984a137c3252fd435374
diff --git a/src/app/core/index.ts b/src/app/core/index.ts
index 2df80c8..e6f740e 100644
--- a/src/app/core/index.ts
+++ b/src/app/core/index.ts
@@ -16,6 +16,8 @@
 import {xosAlert} from './alert/alert';
 import {xosValidation} from './validation/validation';
 import {ModelSetup} from './services/helpers/model-setup.helpers';
+import {xosSidePanel} from './side-panel/side-panel';
+import {XosSidePanel} from './side-panel/side-panel.service';
 
 export const xosCore = 'xosCore';
 
@@ -32,6 +34,7 @@
   .service('XosFormHelpers', XosFormHelpers)
   .service('ConfigHelpers', ConfigHelpers)
   .service('ModelSetup', ModelSetup)
+  .service('XosSidePanel', XosSidePanel)
   .directive('xosLinkWrapper', xosLinkWrapper)
   .component('xosHeader', xosHeader)
   .component('xosFooter', xosFooter)
@@ -41,4 +44,5 @@
   .component('xosForm', xosForm)
   .component('xosField', xosField)
   .component('xosAlert', xosAlert)
-  .component('xosValidation', xosValidation);
+  .component('xosValidation', xosValidation)
+  .component('xosSidePanel', xosSidePanel);
diff --git a/src/app/core/nav/nav.html b/src/app/core/nav/nav.html
index a45d3c8..402d2fa 100644
--- a/src/app/core/nav/nav.html
+++ b/src/app/core/nav/nav.html
@@ -44,6 +44,7 @@
             <a ng-click="vm.logout()" class="btn btn-accent btn-block btn-logout">Logout</a>
           </div>
         </div>
+        <!--<a ng-click="vm.togglePanel()" class="btn btn-success">Open XSP</a>-->
       </li>
     </ul>
   </nav>
diff --git a/src/app/core/nav/nav.spec.ts b/src/app/core/nav/nav.spec.ts
index fafec7d..f443d91 100644
--- a/src/app/core/nav/nav.spec.ts
+++ b/src/app/core/nav/nav.spec.ts
@@ -31,7 +31,8 @@
       .component('xosNav', xosNav)
       .service('NavigationService', NavigationService)
       .value('AuthService', AuthMock)
-      .value('StyleConfig', {});
+      .value('StyleConfig', {})
+      .value('XosSidePanel', {});
     angular.mock.module('xosNav');
   });
 
diff --git a/src/app/core/nav/nav.ts b/src/app/core/nav/nav.ts
index c100c42..ec2d8b2 100644
--- a/src/app/core/nav/nav.ts
+++ b/src/app/core/nav/nav.ts
@@ -2,9 +2,10 @@
 import {IXosNavigationService, IXosNavigationRoute} from '../services/navigation';
 import {IXosAuthService} from '../../datasources/rest/auth.rest';
 import {IXosStyleConfig} from '../../../index';
+import {IXosSidePanelService} from '../side-panel/side-panel.service';
 
 class NavCtrl {
-  static $inject = ['$scope', '$state', 'NavigationService', 'AuthService', 'StyleConfig'];
+  static $inject = ['$scope', '$state', 'NavigationService', 'AuthService', 'StyleConfig', 'XosSidePanel'];
   public routes: IXosNavigationRoute[];
   public navSelected: string;
   public appName: string;
@@ -15,7 +16,8 @@
     private $state: angular.ui.IStateService,
     private navigationService: IXosNavigationService,
     private authService: IXosAuthService,
-    private StyleConfig: IXosStyleConfig
+    private StyleConfig: IXosStyleConfig,
+    private XosSidePanel: IXosSidePanelService
   ) {
     // NOTE we'll need to have:
     // - Base routes (defined from configuration based on BRAND)
@@ -56,6 +58,11 @@
     }
   }
 
+  // NOTE remove me
+  togglePanel() {
+    this.XosSidePanel.injectComponent('xosAlert', {config: {type: 'danger'}, show: true}, 'Sample message');
+  }
+
   logout() {
     this.authService.logout()
       .then(() => {
diff --git a/src/app/core/side-panel/side-panel.html b/src/app/core/side-panel/side-panel.html
new file mode 100644
index 0000000..5d06e79
--- /dev/null
+++ b/src/app/core/side-panel/side-panel.html
@@ -0,0 +1,13 @@
+<section class="xos-side-panel">
+    <pre>{{vm.isOpened | json}}</pre>
+    <div class="row">
+        <div class="col-xs-12 text-right">
+            <i class="fa fa-remove" ng-click="vm.close()"></i>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-xs-12" id="side-panel-container">
+
+        </div>
+    </div>
+</section>
\ No newline at end of file
diff --git a/src/app/core/side-panel/side-panel.scss b/src/app/core/side-panel/side-panel.scss
new file mode 100644
index 0000000..05f34e0
--- /dev/null
+++ b/src/app/core/side-panel/side-panel.scss
@@ -0,0 +1,20 @@
+@import './../../style/vars.scss';
+
+$side-panel-width: 400px;
+
+xos-side-panel {
+  .xos-side-panel {
+    width: $side-panel-width;
+    height: 100%;
+    position: fixed;
+    background: $background-dark-color;
+    z-index: 9999;
+    right: -$side-panel-width;
+    padding: $padding;
+    transition: all .5s cubic-bezier(0.215, 0.610, 0.355, 1.000);
+
+    &.open {
+      right: 0;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/app/core/side-panel/side-panel.service.ts b/src/app/core/side-panel/side-panel.service.ts
new file mode 100644
index 0000000..06dfef9
--- /dev/null
+++ b/src/app/core/side-panel/side-panel.service.ts
@@ -0,0 +1,64 @@
+import * as $ from 'jquery';
+import * as _ from 'lodash';
+
+export interface IXosSidePanelService {
+  open(): void;
+  close(): void;
+  injectComponent(componentName: string, attributes?: any, transclude?: string): void;
+}
+
+export class XosSidePanel implements IXosSidePanelService {
+  static $inject = ['$rootScope', '$compile'];
+  public sidePanelElName = 'xos-side-panel';
+  public sidePanelElClass = '.xos-side-panel';
+  public sidePanelEl: JQuery;
+
+  constructor (
+    private $rootScope: ng.IRootScopeService,
+    private $compile: ng.ICompileService
+  ) {
+    this.sidePanelEl = $(`${this.sidePanelElName} > ${this.sidePanelElClass}`);
+  }
+
+  public open() {
+    $(`${this.sidePanelElName} > ${this.sidePanelElClass}`).addClass('open');
+  };
+
+  public close() {
+    $(`${this.sidePanelElName} > ${this.sidePanelElClass}`).removeClass('open');
+  };
+
+  public injectComponent(componentName: string, attributes?: any, transclude?: string) {
+    const componentTagName = this.camelToSnakeCase(componentName);
+    let scope = this.$rootScope.$new();
+    let attr: string = '';
+
+    // NOTE add a flag to keep the loaded compoenents?
+    this.removeInjectedComponents();
+
+    if (angular.isDefined(attributes) && angular.isObject(attributes)) {
+      attr = this.stringifyAttributes(attributes);
+      scope = angular.merge(scope, attributes);
+    }
+
+    const componentTag = `<${componentTagName} ${attr}>${transclude || ''}</${componentTagName}>`;
+    const element = this.$compile(componentTag)(scope);
+    this.sidePanelEl.find('#side-panel-container').append(element);
+    this.open();
+  }
+
+  public removeInjectedComponents() {
+    this.sidePanelEl.find('#side-panel-container').html('');
+  }
+
+  private stringifyAttributes(attributes: any): string {
+    return _.reduce(Object.keys(attributes), (string: string, a: string) => {
+      string += `${a}="${a}"`;
+      return string;
+    }, '');
+  }
+
+  private camelToSnakeCase(name: string): string {
+    return name.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join('-');
+  };
+}
diff --git a/src/app/core/side-panel/side-panel.ts b/src/app/core/side-panel/side-panel.ts
new file mode 100644
index 0000000..4d400f4
--- /dev/null
+++ b/src/app/core/side-panel/side-panel.ts
@@ -0,0 +1,25 @@
+import './side-panel.scss';
+import {IXosSidePanelService} from './side-panel.service';
+
+class XosSidePanelController {
+
+  static $inject = ['XosSidePanel'];
+
+  constructor (
+    private XosSidePanel: IXosSidePanelService
+  ) {}
+
+  public close() {
+    this.XosSidePanel.close();
+  }
+
+  public open() {
+    this.XosSidePanel.open();
+  }
+}
+
+export const xosSidePanel: angular.IComponentOptions = {
+  template: require('./side-panel.html'),
+  controllerAs: 'vm',
+  controller: XosSidePanelController
+};