view class doc
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303/// FOURJS_START_COPYRIGHT(D,2015)
/// Property of Four Js*
/// (c) Copyright Four Js 2015, 2023. All Rights Reserved.
/// * Trademark of Four Js Development Tools Europe Ltd
///   in the United States and elsewhere
///
/// This file can be modified by licensees according to the
/// product manual.
/// FOURJS_END_COPYRIGHT

"use strict";

modulum('WidgetGroupBase', ['TextWidgetBase'],
  function(context, cls) {

    /**
     * Base class for widget group.
     * @class WidgetGroupBase
     * @memberOf classes
     * @extends classes.TextWidgetBase
     * @publicdoc Widgets
     */
    cls.WidgetGroupBase = context.oo.Class(cls.TextWidgetBase, function($super) {
      return /** @lends classes.WidgetGroupBase.prototype */ {
        __name: "WidgetGroupBase",
        __virtual: true,
        /**
         * the container element
         * @type HTMLElement
         * @protected
         */
        _containerElement: null,
        /**
         * the children widget
         * @type {classes.WidgetBase[]}
         * @protected
         */
        _children: null,
        /**
         * @inheritDoc
         */
        constructor: function(opts) {
          this._children = [];
          $super.constructor.call(this, opts);
        },
        /**
         * @inheritDoc
         */
        _afterInitElement: function() {
          $super._afterInitElement.call(this);
          this._initContainerElement();
        },

        /**
         * init the container element
         * @protected
         */
        _initContainerElement: function() {
          var elt = this._element;
          this._containerElement = elt.hasClass("containerElement") ? elt : elt.getElementsByClassName("containerElement")[0];
          if (!this._containerElement) {
            throw "Widgets inheriting WidgetGroupBase must have one container with class containerElement in its template";
          }
        },

        /**
         * @inheritDoc
         */
        destroy: function() {
          this._containerElement = null;
          if (this._children.length > 0) {
            gbc.error(this.__name + "(uuid: " + this.getUniqueIdentifier() + ") has been destroyed whereas it still has children");
          }
          $super.destroy.call(this);
        },

        /**
         * Destroy all children widgets
         */
        destroyChildren: function() {
          var children = this.getChildren();
          if (children) {
            for (var i = children.length - 1; i > -1; i--) {
              var currentChildren = children[i];
              currentChildren.destroy();
              currentChildren = null;
            }
          }
          this._children.length = 0;
        },

        /**
         * Get the container Element
         * @return {HTMLElement} the element
         * @publicdoc
         */
        getContainerElement: function() {
          return this._containerElement;
        },

        /**
         * Add a child widget to the widget
         * @param {classes.WidgetBase} widget the widget to add
         * @param {Object=} options - possible options
         * @param {boolean=} options.noDOMInsert - won't add child to DOM
         * @param {number=} options.position - insert position
         * @param {string=} options.tag - context tag
         * @param {string=} options.mode - context mode : null|"replace"
         * @publicdoc
         */
        addChildWidget: function(widget, options) {
          options = options || {};

          if (widget._parentWidget && widget._parentWidget !== this) {
            gbc.error(this.__name + "(uuid: " + this.getUniqueIdentifier() +
              ") addChildWidget cannot be executed if child has already a parent");
          }

          var position = Object.isNumber(options.position) ? options.position : (this._children.length);
          if (options.ordered) {
            if (this._children.length > 0) {
              for (var i = this._children.length; i > 0; i--) {
                if (widget.getAuiLinkedUniqueIdentifier() < this._children[i - 1].getAuiLinkedUniqueIdentifier()) {
                  position = i - 1;
                }
              }
            }
          }

          widget.setParentWidget(this, {
            noLayoutInvalidation: Boolean(options.noDOMInsert)
          });
          if (!options.noDOMInsert) {
            this._addChildWidgetToDom(widget, position);
            widget._setDOMAttachedOrDetached();
          }
          this._children.splice(position, 0, widget);
        },

        /**
         * Add a child widget which has already a parent to the widget
         * @param {classes.WidgetBase} widget the widget to add
         * @param {Object=} options - possible options
         * @param {boolean=} options.noDOMInsert - won't add child to DOM
         * @param {number=} options.position - insert position
         * @param {string=} options.ordered - auto order item by unique auiID
         * @param {string=} options.tag - context tag
         * @param {string=} options.mode - context mode : null|"replace"
         * @publicdoc
         */
        adoptChildWidget: function(widget, options) {
          options = options || {};

          if (widget.getParentWidget()) {
            var children = widget.getParentWidget().getChildren();
            if (children) {
              children.remove(widget);
            }
          }

          var position = Object.isNumber(options.position) ? options.position : (this._children.length);

          if (options.ordered) {
            if (this._children.length > 0) {
              for (var i = this._children.length; i > 0; i--) {
                if (widget.getAuiLinkedUniqueIdentifier() < this._children[i - 1].getAuiLinkedUniqueIdentifier()) {
                  position = i - 1;
                }
              }
            }
          }
          if (!options.noDOMInsert) { // move DOM element
            this._addChildWidgetToDom(widget, position);
          } else { // just remove DOM element from previous location
            this._removeChildWidgetFromDom(widget);
          }
          widget.setParentWidget(this, {
            noLayoutInvalidation: Boolean(options.noDOMInsert)
          });
          this._children.splice(position, 0, widget);

          widget._setDOMAttachedOrDetached();
        },

        /**
         * add child widget to dom
         * @param {classes.WidgetBase} widget the widget to add
         * @param {number} position where to add the widget
         * @protected
         */
        _addChildWidgetToDom: function(widget, position) {
          widget._element.insertAt(position, this._containerElement);
        },

        /**
         * Remove a child widget from this widget
         * @param {classes.WidgetBase} widget the widget to remove
         * @publicdoc
         */
        removeChildWidget: function(widget) {
          this._removeChildWidgetFromDom(widget);
          widget.setParentWidget(null);
          if (this._children) {
            this._children.remove(widget);
          }
          widget._setDOMAttachedOrDetached();
        },
        /**
         * remove child widget from dom
         * @param {classes.WidgetBase} widget the widget to remove
         * @protected
         */
        _removeChildWidgetFromDom: function(widget) {
          if (widget._element.parentNode === this._containerElement) {
            widget._element.remove();
          }
        },

        /**
         * Remove a child widget to use another widget instead
         * @param {classes.WidgetBase} oldWidget the widget to replace
         * @param {classes.WidgetBase} newWidget the widget to add
         * @publicdoc
         */
        replaceChildWidget: function(oldWidget, newWidget) {
          var index = this.getIndexOfChild(oldWidget);
          var layoutInfo = newWidget.getLayoutInformation();
          if (layoutInfo) {
            layoutInfo.setOwningGrid(oldWidget.getLayoutInformation() && oldWidget.getLayoutInformation().getOwningGrid());
          }
          this.removeChildWidget(oldWidget);
          this.addChildWidget(newWidget, {
            position: index,
            mode: "replace"
          });
        },

        /**
         * Remove all children
         * @publicdoc
         */
        empty: function() {
          var remove = this._children.slice();
          for (var i = 0; i < remove.length; i++) {
            this.removeChildWidget(remove[i]);
          }
        },

        /**
         * Get the child widget position
         * @param {classes.WidgetBase} widget the widget
         * @returns {number} widget position
         * @publicdoc
         */
        getIndexOfChild: function(widget) {
          return this._children.indexOf(widget);
        },

        /**
         * Get all children of this widget
         * @returns {classes.WidgetBase[]} the list of children of this widget group
         * @publicdoc
         */
        getChildren: function() {
          return this._children;
        },

        /**
         * Returns current widget (flagged with 'current' class)
         * @returns {?classes.WidgetBase} The current child
         * @publicdoc
         */
        getCurrentChildren: function() {
          for (var i = 0; i < this._children.length; i++) {
            var child = this._children[i];
            if (child.getElement().hasClass("current")) {
              return child;
            }
          }
          return null;
        },

        /**
         * returns true if a WebComponent is contained in any sublevel child
         * @publicdoc
         * @returns {boolean} true if the widget has webcomponent, false otherwise
         */
        hasChildWebComponent: function() {
          return this._hasWebcomp; // Tell window that it has a webcomp
        },

        /**
         * Flag/unflag having child with WebComponent
         * @param {boolean} has - flag the widget as having a webcomponent
         */
        setHasChildWebComponent: function(has) {
          this._hasWebcomp = has;
        },

      };
    });
  });