view class doc
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468/// FOURJS_START_COPYRIGHT(D,2020)
/// Property of Four Js*
/// (c) Copyright Four Js 2020, 2022. 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('RTableItemWidget', ['WidgetGroupBase'],
  function(context, cls) {

    /**
     * Responsive Table item widget.
     * @class RTableItemWidget
     * @memberOf classes
     * @extends classes.WidgetGroupBase
     * @publicdoc
     */
    cls.RTableItemWidget = context.oo.Class(cls.WidgetGroupBase, function($super) {
      return /** @lends classes.RTableItemWidget.prototype */ {
        __name: "RTableItemWidget",

        /** @type {Element|null} */
        _treeAnchor: null,
        /** @type {classes.ImageWidget} */
        _imageWidget: null,
        /** @type {Function} */
        _imageClickHandler: null,
        /** @type {boolean} */
        _dndEnabled: false,
        /** @type {string|null} */
        _currentImagePath: null,
        /** @type {boolean} */
        _clientSelected: false,
        /** @type {boolean} */
        _isTreeItem: false,
        /** @type {classes.RTableColumnWidget} */
        _columnWidget: null,

        /**
         * @constructs
         * @param {*} opts - Options passed to the constructor
         */
        constructor: function(opts) {
          opts = (opts || {});
          this._isTreeItem = opts.isTreeItem;
          opts.inTable = true;
          $super.constructor.call(this, opts);
        },

        /**
         * @inheritDoc
         */
        _initLayout: function() {
          // no layout
        },

        /**
         * @inheritDoc
         */
        isLayoutMeasureable: function(deep) {
          // first table item of each row is measurable
          return true;
        },

        /**
         * Init item
         */
        init: function() {
          this.setLeftFrozen(this._columnWidget.isLeftFrozen());
          this.setRightFrozen(this._columnWidget.isRightFrozen());
          this.setOrder(this._columnWidget.getOrder());
          this.setCurrentColumn(this._columnWidget.isCurrent());
          this.setDndEnabled(this.getTableWidgetBase().isDndItemEnabled());
        },

        /**
         * @inheritDoc
         */
        destroy: function() {
          this._treeAnchor = null;

          if (this._imageClickHandler) {
            this._imageClickHandler();
            this._imageClickHandler = null;
          }
          if (this._imageWidget) {
            this._imageWidget.destroy();
            this._imageWidget = null;
          }
          this._columnWidget = null;

          $super.destroy.call(this);
        },

        /**
         * @inheritDoc
         */
        setHidden: function(hidden) {
          if (this._hidden !== Boolean(hidden)) {
            this._hidden = Boolean(hidden);
            if (this._element) {
              if (this._hidden) {
                this.addClass("hidden");
              } else {
                this.removeClass("hidden");
              }
            }
          }
        },

        /**
         * Request focus for this row (keep current column)
         * @param {*} domEvent - dom event object
         */
        requestFocus: function(domEvent) {
          let tableWidget = this.getTableWidgetBase();
          if (tableWidget) {
            tableWidget.requestFocusFromWidget(this._children[0], domEvent);
          }
        },

        /**
         * @inheritDoc
         */
        manageMouseClick: function(domEvent) {
          if (domEvent.target === this.getElement()) { // click on item, but not on sub element
            this.getTableWidgetBase().requestFocusFromWidget(this._children[0], domEvent);
            return false;
          }
          if (domEvent.target === this._treeAnchor) { // click on tree anchor
            let index = this.getRowIndex();
            let tableWidget = this.getTableWidgetBase();
            tableWidget.emit(context.constants.widgetEvents.toggleClick, index);
            return false;
          }
          return true;
        },

        /**
         * @inheritDoc
         */
        manageMouseDblClick: function(domEvent) {
          if (domEvent.target === this._treeAnchor) { // double click on tree anchor
            return false;
          }
          return true;
        },

        /**
         * @inheritDoc
         */
        addChildWidget: function(widget, options) {
          if (this._children.length !== 0) {
            throw "A item only contain a single child";
          }

          this._layoutInformation = widget.getLayoutInformation();
          $super.addChildWidget.call(this, widget, options);

          if (this._isTreeItem) {
            this._treeAnchor = document.createElement("span");
            this._treeAnchor.addClass("gbc_TreeAnchor");
            this._element.prependChild(this._treeAnchor);
            this.setLeaf(true);
          }
        },

        /**
         * @inheritDoc
         */
        setBackgroundColor: function(color) {
          if (this._backgroundColor !== color) {
            this._backgroundColor = color;
            this.setStyle({
              "background-color": color && !this._ignoreBackgroundColor ? color : null
            });
          }
        },

        /**
         * Enable drag and drop
         * @param {boolean} b - true to enable
         */
        setDndEnabled: function(b) {
          if (this._dndEnabled !== b) {
            this._dndEnabled = b;
            if (b) {
              this._element.setAttribute("draggable", "true");
            } else {
              this._element.removeAttribute("draggable");
            }
          }
        },

        /**
         * Check if item is tree item
         * @returns {boolean} true if the element is a tree item, false otherwise
         * @publicdoc
         */
        isTreeItem: function() {
          return this._isTreeItem;
        },

        /**
         * Sets if item is a leaf of tree
         * @param {boolean} leaf - true if the item is a leaf item, false otherwise
         */
        setLeaf: function(leaf) {
          if (this.isTreeItem()) {
            this.setAriaExpanded(null);
            if (leaf) {
              this._treeAnchor.removeClass("treeExpanded");
              this._treeAnchor.removeClass("treeCollapsed");
            }
            this._treeAnchor.toggleClass("treeLeaf", leaf);

          }
        },

        /**
         * Checks if item is tree leaf item
         * @returns {boolean} leaf true if the item is a leaf item, false otherwise
         * @publicdoc
         */
        isLeaf: function() {
          return this.isTreeItem() && this._treeAnchor.hasClass("treeLeaf");
        },

        /**
         * Expands or collapse tree item
         * @param {boolean} expanded - true if the item should be expanded, false otherwise
         * @publicdoc
         */
        setExpanded: function(expanded) {
          if (this.isTreeItem() && !this.isLeaf()) {
            this.setAriaExpanded(expanded);
            this._treeAnchor.toggleClass("treeExpanded", "treeCollapsed", expanded);

            if (gbc.qaMode) {
              // add qa expanded info
              let qaElement = this.getContainerElement().querySelector("[data-gqa-name]");
              if (qaElement) {
                qaElement.setAttribute('data-gqa-expanded', expanded.toString());
              }
            }
          }
        },

        /**
         * Sets aria attribute expanded
         * @param {boolean} expanded - true if the item should be expanded, false otherwise
         */
        setAriaExpanded: function(expanded) {
          this.setAriaAttribute("expanded", expanded);
          if (this._children[0]) {
            this._children[0].setAriaAttribute("expanded", expanded);
          }
        },

        /**
         * @inheritDoc
         */
        isReversed: function() {
          return this.getParentWidget().isReversed();
        },

        /**
         * Sets tree item depth
         * @param {number} depth - item depth
         */
        setDepth: function(depth) {
          let depthObj = {};
          depthObj["padding-" + this.getStart()] = depth + 'em';
          this.setStyle(depthObj);
        },

        /**
         * Sets if the item is left frozen
         * @param {boolean} b - is left frozen ?
         * @publicdoc
         */
        setLeftFrozen: function(b) {
          this.toggleClass("leftFrozen", b);
          this.toggleClass("lastLeftFrozen", this.getColumnWidget().isLastLeftFrozen());
          if (b) {
            this.setStyle({
              "left": this.getColumnWidget().getLeftFrozenPosition() + "px"
            });
          }
        },

        /**
         * Sets if the item is right frozen
         * @param {boolean} b - is right frozen ?
         * @publicdoc
         */
        setRightFrozen: function(b) {
          this.toggleClass("rightFrozen", b);
          this.toggleClass("firstRightFrozen", this.getColumnWidget().isFirstRightFrozen());
          if (b) {
            this.setStyle({
              "right": this.getColumnWidget().getRightFrozenPosition() + "px"
            });
          }
        },

        /**
         * Sets if the item is in the current column
         * @param {boolean} b - is in current column ?
         * @publicdoc
         */
        setCurrentColumn: function(b) {
          this.toggleClass("currentColumn", b);
        },

        /**
         * Sets index order  (row + col)
         * @param {number} index - order column index
         */
        setOrder: function(colIndex) {
          let rowWidget = this.getParentWidget();
          let colIndexString = colIndex === -1 ? "0" : colIndex.toString();
          // transform colIndex to 3 number (ex: 3 --> 003)
          while (colIndexString.length < 3) {
            colIndexString = "0" + colIndexString;
          }
          let order = parseInt(rowWidget.getRowIndex() + "" + colIndexString);
          this.setStyle({
            "order": order
          });
        },

        /**
         * Sets image item
         * @param {string} path - image path
         * @publicdoc
         */
        setImage: function(path) {
          if (this._currentImagePath !== path) {
            if (path && path !== "") {
              if (!this._imageWidget) {
                let opts = this.getBuildParameters();
                opts.inTable = true;
                this._imageWidget = cls.WidgetFactory.createWidget("ImageWidget", opts);
                this._imageWidget.getElement().addClass("gbc_RTableItemImage");
                this._imageWidget.setParentWidget(this);
                this._imageClickHandler = this._imageWidget.when(context.constants.widgetEvents.click, function(event) {
                  this.getTableWidgetBase().requestFocusFromWidget(this._children[0], event);
                }.bind(this));
                this._element.prependChild(this._imageWidget.getElement());
              }
              this._imageWidget.setSrc(path, true);
              this._imageWidget.setHidden(false);
            } else if (this._imageWidget) {
              this._imageWidget.setHidden(true);
            }
            this._currentImagePath = path;
          }
        },

        /**
         * Checks if item is client selected
         * @returns {boolean} true if the row item is client selected, false otherwise
         */
        isClientSelected: function() {
          return this._clientSelected;
        },

        /**
         * Sets if item is client selected
         * @param {boolean} selected - true if the item is client selected, false otherwise
         */
        setClientSelected: function(selected) {
          this._clientSelected = selected;
        },

        /**
         * Returns column widget which contains this item
         * @returns {classes.RTableColumnWidget} column widget
         */
        getColumnWidget: function() {
          return this._columnWidget;
        },

        /**
         * Sets the column widget wich contains this itme
         * @param {classes.RTableColumnWidget} colWidget - column widget
         */
        setColumnWidget: function(colWidget) {
          this._columnWidget = colWidget;
        },

        /**
         * Returns row index of the item
         * @returns {number} row index of the item
         * @publicdoc
         */
        getRowIndex: function() {
          let parent = this.getParentWidget();
          if (parent) {
            return parent.getRowIndex();
          }
          return -1;
        },

        /**
         * Handle dragStart event
         * @param {Object} evt - dragstart event
         */
        onDragStart: function(evt) {
          if (window.browserInfo.isFirefox) { // Firefox 1.0+
            try {
              evt.dataTransfer.setData('text/plain', ''); // for Firefox compatibility
            } catch (ex) {
              console.error("evt.dataTransfer.setData('text/plain', ''); not supported");
            }
          }

          this._columnWidget.emit(gbc.constants.widgetEvents.tableDragStart, this.getRowIndex(), evt);
        },

        /**
         * Handle dragEnd event
         */
        onDragEnd: function() {
          this._columnWidget.emit(gbc.constants.widgetEvents.tableDragEnd);
        },

        /**
         * Handle dragOver event
         * @param {Object} evt - dragover event
         */
        onDragOver: function(evt) {
          this._columnWidget.emit(gbc.constants.widgetEvents.tableDragOver, this.getRowIndex(), evt);
        },

        /**
         * Handle dragLeave event
         * @param {Object} evt - dragleave event
         */
        onDragLeave: function(evt) {
          this._columnWidget.emit(gbc.constants.widgetEvents.tableDragLeave, this.getRowIndex(), evt);
        },

        /**
         * Handle dragEnter event
         * @param {Object} evt - dragenter event
         */
        onDragEnter: function(evt) {
          this._columnWidget.emit(gbc.constants.widgetEvents.tableDragEnter, this.getRowIndex(), evt);
        },

        /**
         * Handle drop event
         */
        onDrop: function() {
          this._columnWidget.emit(gbc.constants.widgetEvents.tableDrop, this.getRowIndex());
        }
      };
    });
    cls.WidgetFactory.registerBuilder('RTableItem', cls.RTableItemWidget);
  });