dashgrid.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. ///<reference path="../../../headers/common.d.ts" />
  2. import coreModule from 'app/core/core_module';
  3. import {CELL_HEIGHT, CELL_VMARGIN} from '../model';
  4. import 'jquery-ui';
  5. import 'gridstack';
  6. import 'gridstack.jquery-ui';
  7. const template = `
  8. <div class="grid-stack">
  9. <dash-grid-item ng-repeat="panel in ctrl.dashboard.panels track by panel.id"
  10. class="grid-stack-item"
  11. grid-ctrl="ctrl"
  12. panel="panel">
  13. <plugin-component type="panel" class="grid-stack-item-content">
  14. </plugin-component>
  15. </dash-grid-item>
  16. </div>
  17. `;
  18. var rowIndex = 0;
  19. export class GridCtrl {
  20. options: any;
  21. dashboard: any;
  22. panels: any;
  23. gridstack: any;
  24. gridElem: any;
  25. isInitialized: boolean;
  26. isDestroyed: boolean;
  27. index: number;
  28. changeRenderPromise: any;
  29. /** @ngInject */
  30. constructor(private $scope, private $element, private $timeout) {
  31. console.log(this.dashboard);
  32. this.index = rowIndex;
  33. rowIndex += 1;
  34. }
  35. init() {
  36. this.gridElem = this.$element.find('.grid-stack');
  37. this.gridstack = this.gridElem.gridstack({
  38. animate: true,
  39. cellHeight: CELL_HEIGHT,
  40. verticalMargin: CELL_VMARGIN,
  41. acceptWidgets: '.grid-stack-item',
  42. handle: '.grid-drag-handle'
  43. }).data('gridstack');
  44. this.isInitialized = true;
  45. this.gridElem.on('added', (e, items) => {
  46. for (let item of items) {
  47. this.onGridStackItemAdded(item);
  48. }
  49. });
  50. this.gridElem.on('removed', (e, items) => {
  51. for (let item of items) {
  52. this.onGridStackItemRemoved(item);
  53. }
  54. });
  55. this.gridElem.on('change', (e, items) => {
  56. this.$timeout(() => this.onGridStackItemsChanged(items), 50);
  57. });
  58. }
  59. onGridStackItemAdded(item) {
  60. console.log('row: ' + this.index + ' item added', item);
  61. }
  62. onGridStackItemRemoved(item) {
  63. console.log('row: ' + this.index + ' item removed', item.id, item);
  64. }
  65. onGridStackItemsChanged(items) {
  66. console.log('onGridStackItemsChanged');
  67. for (let item of items) {
  68. // find panel
  69. var panel = this.dashboard.getPanelById(parseInt(item.id));
  70. if (!panel) {
  71. console.log('item change but no panel found for item', item);
  72. continue;
  73. }
  74. // update panel model position
  75. panel.x = item.x;
  76. panel.y = item.y;
  77. panel.width = item.width;
  78. panel.height = item.height;
  79. console.log('updating panel: ' + panel.id + ' x: ' + panel.x + ' y: ' + panel.y);
  80. }
  81. this.dashboard.panels.sort(function (a, b) {
  82. let aScore = a.x + (a.y * 12);
  83. let bScore = b.x + (b.y * 12);
  84. if (aScore < bScore) { return -1; }
  85. if (aScore > bScore) { return 1; }
  86. return 0;
  87. });
  88. if (this.changeRenderPromise) {
  89. this.$timeout.cancel(this.changeRenderPromise);
  90. }
  91. this.changeRenderPromise = this.$timeout(() => {
  92. console.log('broadcasting render');
  93. this.$scope.$broadcast('render');
  94. });
  95. }
  96. destroy() {
  97. this.gridstack.destroy();
  98. this.gridstack = null;
  99. this.isDestroyed = true;
  100. }
  101. }
  102. /** @ngInject **/
  103. export function dashGrid($timeout) {
  104. return {
  105. restrict: 'E',
  106. template: template,
  107. controller: GridCtrl,
  108. bindToController: true,
  109. controllerAs: 'ctrl',
  110. scope: {
  111. dashboard: "=",
  112. },
  113. link: function(scope, elem, attrs, ctrl) {
  114. $timeout(function() {
  115. ctrl.init();
  116. });
  117. scope.$on('$destroy', () => {
  118. ctrl.destroy();
  119. });
  120. }
  121. };
  122. }
  123. /** @ngInject **/
  124. export function dashGridItem($timeout, $rootScope) {
  125. return {
  126. restrict: "E",
  127. scope: {
  128. panel: '=',
  129. gridCtrl: '='
  130. },
  131. link: function (scope, element, attrs) {
  132. let gridCtrl = scope.gridCtrl;
  133. let panel = scope.panel;
  134. let gridStackNode = null;
  135. element.attr({
  136. 'data-gs-id': panel.id,
  137. 'data-gs-x': panel.x,
  138. 'data-gs-y': panel.y,
  139. 'data-gs-width': panel.width,
  140. 'data-gs-height': panel.height,
  141. 'data-gs-no-resize': panel.type === 'row',
  142. });
  143. $rootScope.onAppEvent('panel-fullscreen-exit', (evt, payload) => {
  144. if (panel.id !== payload.panelId) {
  145. return;
  146. }
  147. gridCtrl.gridstack.locked(element, false);
  148. element.removeClass('panel-fullscreen');
  149. }, scope);
  150. $rootScope.onAppEvent('panel-fullscreen-enter', (evt, payload) => {
  151. if (panel.id !== payload.panelId) {
  152. return;
  153. }
  154. element.addClass('panel-fullscreen');
  155. }, scope);
  156. scope.$on('$destroy', () => {
  157. console.log('grid-item scope $destroy');
  158. if (gridCtrl.isDestroyed) {
  159. return;
  160. }
  161. if (gridStackNode) {
  162. console.log('grid-item scope $destroy removeWidget');
  163. gridStackNode._grid.removeWidget(element);
  164. }
  165. });
  166. if (gridCtrl.isInitialized) {
  167. gridCtrl.gridstack.makeWidget(element);
  168. gridStackNode = element.data('_gridstack_node');
  169. } else {
  170. setTimeout(function() {
  171. gridStackNode = element.data('_gridstack_node');
  172. }, 500);
  173. }
  174. }
  175. };
  176. }
  177. coreModule.directive('dashGrid', dashGrid);
  178. coreModule.directive('dashGridItem', dashGridItem);