Skip to content
Snippets Groups Projects
ui_select.js 5.26 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { action } from '@ember/object';
    import Modifier from 'ember-modifier';
    
    import Rectangle from 'papermerge/utils/rectangle';
    
    Eugen Ciur's avatar
    Eugen Ciur committed
    class UISelect {
      /**
        Desktop like select
      **/
    
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      get DRAG_THRESHOLD() {
        /*
          Some mouse clicks are acompanied by slight mouse movements, which
          makes 'clicks' look like mouse drag events. In order the avoid
          this confusion, DRAG_THRESHOLD is introduced. Any rectangle with
          height or width < DRAG_THRESHOLD will be discarded.
        */
        return 5;
      }
    
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      constructor(parent_selector) {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        /***
          x, y coordinates where selection started.
          parent - dom parent element. Selection DOM element
          will be attached to parent and it's coordinates
          will be relative to the parent DOM.
        **/
        // x,y where selection started
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.start_x = 0;
        this.start_y = 0;
        this.current_x = 0;
        this.current_y = 0;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.parent = parent_selector;
    
        this.select_div = document.getElementById('ui-select');
    
        this.nodes_arr = Array.from(
          document.getElementsByClassName('node')
        );
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      init(x, y) {
        this.start_x = x;
        this.start_y = y;
      }
    
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.visibility = 'visible';
        this.top = `${x}px`;
        this.left  = `${y}px`;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.visibility = 'hidden';
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      }
    
      update(x, y) {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        let height, width, top, left;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
    
        this.show(x, y);
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.current_x = x;
        this.current_y = y;
    
        width = Math.abs(this.current_x - this.start_x);
        height = Math.abs(this.current_y - this.start_y);
    
        if (this.select_div) {
    
          if (this.current_y <  this.start_y) {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
            this.top = `${this.current_y + 7}px`;
    
            top = this.current_y + 7;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          } else {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
            this.top = `${this.start_y}px`;
    
            top = this.start_y;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          }
          if (this.current_x <  this.start_x) {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
            this.left = `${this.current_x + 7}px`;
    
            left = this.current_x + 7;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          } else {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
            this.left = `${this.start_x}px`;
    
            left = this.start_x;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          }
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          this.width = `${width}px`;
          this.height = `${height}px`;
    
    
          const { selected_nodes, unselected_nodes } = this.get_nodes_selection(
            new Rectangle(left, top, width, height)
          );
    
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          if (width < this.DRAG_THRESHOLD && height < this.DRAG_THRESHOLD) {
            console.log('Not passing DRAG_THRESHOLD. Ignored.');
            return;
          }
    
    
          this.select_nodes(selected_nodes);
          this.unselect_nodes(unselected_nodes);
    
      get_nodes_selection(selection_rect) {
        /**
          selection_rect is instance of utils.MgRect
        **/
        let selected_nodes = [], unselected_nodes = [];
    
        this.nodes_arr.forEach(element => {
          let _r, rect;
    
          _r = element.getBoundingClientRect();
          rect = new Rectangle(_r.x, _r.y, _r.width, _r.height);
    
    
          if (rect.intersect(selection_rect)) {
    
            selected_nodes.push(element);
          } else {
            unselected_nodes.push(element);
          }
        });
    
        return {selected_nodes, unselected_nodes};
      }
    
      select_nodes(elements) {
        let input_el;
    
        elements.forEach(element => {
          input_el = element.querySelector('input');
          if (input_el && !input_el.checked) {
            input_el.click();
          }
        });
      }
    
      unselect_nodes(elements) {
        let input_el;
    
        elements.forEach(element => {
          input_el = element.querySelector('input');
          if (input_el && input_el.checked) {
            input_el.click();
          }
        });
      }
    
      deselect_all_nodes() {
        let input_el;
    
        this.nodes_arr.forEach(element => {
          input_el = element.querySelector('input');
          if (input_el && input_el.checked) {
            input_el.click();
          }
        });
      }
    
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      set width(value) {
        if (!this.select_div) {
          return;
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.select_div.style.width = value;
      }
    
      set height(value) {
        if (!this.select_div) {
          return;
        }
        this.select_div.style.height = value;
      }
    
      set top(value) {
        if (!this.select_div) {
          return;
        }
        this.select_div.style.top = value;
      }
    
      set left(value) {
        if (!this.select_div) {
          return;
        }
        this.select_div.style.left = value;
      }
    
      set visibility(value) {
        if (!this.select_div) {
          return;
        }
        this.select_div.style.visibility = value;
    
    export default class UISelectModifier extends Modifier {
    
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      ui_select = undefined;
    
    
      addEventListener() {
        this.element.addEventListener('mousedown', this.onMouseDown);
        this.element.addEventListener('mouseup', this.onMouseUp);
        this.element.addEventListener('mousemove', this.onMouseMove);
      }
    
      removeEventListener() {
        this.element.removeEventListener('mousedown', this.onMouseDown);
        this.element.removeEventListener('mouseup', this.onMouseUp);
        this.element.removeEventListener('mousemove', this.onMouseMove);
      }
    
      // lifecycle hooks
      didReceiveArguments() {
        this.removeEventListener();
        this.addEventListener();
    
    Eugen Ciur's avatar
    Eugen Ciur committed
    
        this.ui_select = new UISelect(this.element);
    
      }
    
      willDestroy() {
        this.removeEventListener();
      }
    
      @action
      onMouseMove(event) {
    
        if (!event.buttons) {
    
        } else if (this.ui_select) {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
          this.ui_select.update(event.clientX, event.clientY);
    
    Eugen Ciur's avatar
    Eugen Ciur committed
      onMouseUp() {
    
      }
    
      @action
      onMouseDown(event) {
    
    Eugen Ciur's avatar
    Eugen Ciur committed
        this.ui_select.init(event.clientX, event.clientY);
    
        if (this.ui_select) {
    
          this.ui_select.hide();