aboutsummaryrefslogtreecommitdiff
path: root/javascript/app/components/info-window.js
blob: da669f109b5030ab1a68ee6df010886f821ea66f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import Ember from 'ember';

let resizing = false;
let dragging = false;

function updatePosition(component) {
  const targetElement = component.get('targetElement');
  if(targetElement) {
    const infoWindowHeight = component.element.offsetHeight;
    const targetElementHeight = targetElement.offsetHeight;

    const parent = targetElement.parentNode;//<td> element
    const containerElement = document.querySelector("#" + component.get('containerElementId'));

    //getBoundingClientRect() returns the smallest rectangle which contains
    //the entire element, with read-only left, top, right, bottom, x, y, width,
    //and height properties describing the overall border-box in pixels. Properties
    //other than width and height are relative to the top-left of the *viewport*.
    const targetTopViewport = targetElement.getBoundingClientRect().top;

    let containerTopViewport;
    if (containerElement) {
      containerTopViewport = containerElement.getBoundingClientRect().top;
    } else {
      containerTopViewport = 0;
    }

    let infoWindowTop;
    if(targetTopViewport < infoWindowHeight + containerTopViewport) {
      //offsetTop is the number of pixels from the top of the closest relatively
      //positioned parent element.
      infoWindowTop = targetElement.offsetTop + parent.offsetTop
        + targetElementHeight + 10 + "px";
    } else {
      infoWindowTop = targetElement.offsetTop + parent.offsetTop
        - infoWindowHeight + "px";
    }

    const infoWindowLeft = targetElement.offsetLeft + parent.offsetLeft + "px";

    component.$().css({
      top:infoWindowTop,
      left:infoWindowLeft
    });
  } else {
    component.set('isPinned',false);
  }
}

export default Ember.Component.extend({
  classNames : ["info-window-container"],
  attributeBindings: ['hidden'],
  isPinned : false,
  isFocused: false,
  didInsertElement () {
    const component = this;

    const $headerElement = Ember.$(component.element.querySelector(".info-window-header"));
    const $contentElement = Ember.$(component.element.querySelector(".info-window-content"));
    const $infoWindowElement = Ember.$(component.element.querySelector(".info-window"));
    const $infoWindowContainerElement = Ember.$(component.element);

    this.$headerElement = $headerElement;
    this.$contentElement = $contentElement;

    this.$().resizable({
      handles: "n,w",
      minHeight: 80,
      minWidth: 400,
      start: function() {
        resizing = true;
      },
      stop: function() {
        resizing = false;
      },
      resize : function() {
        const containerHeight = $infoWindowContainerElement.height();
        $infoWindowElement.css({
          "height": containerHeight + 2 + "px"
        });
        $contentElement.css({
          "max-height":(containerHeight - $headerElement.outerHeight(true)) + "px"
        });
      }
    });
    this.$().draggable({
      containment:"#" + this.get('containerElementId'),
      handle: $headerElement,
      start: function() {
        dragging = true;
      },
      stop: function() {
        dragging = false;
      }
    });
  },
  mouseEnter () {
    if(!this.get('hasSelectedExpression')) {
      this.set('isFocused',true);
    }
  },
  mouseLeave (event) {
    //Workaround for a bug in Chrome
    const element = document.elementFromPoint(event.clientX,event.clientY);
    if(element && element.classList.contains('link')) {
      return;
    }
    if(!resizing
       && !dragging
       && !this.get('isPinned')
       && !this.get('hasSelectedExpression')) {
      this.set('isFocused',false);
    }
  },
  hidden : Ember.computed('isHoveredOverIdentifier',
                          'isFocused',
                          'hasSelectedExpression',
                          'isPinned', function() {
    if (this.$contentElement) {
       this.$contentElement.scrollTop(0);
    }
    if (this.get('isPinned')
        || this.get('isFocused')
        || this.get('isHoveredOverIdentifier')
        || this.get('hasSelectedExpression')) {
      return false;
    } else {
      return true;
    }
  }),
  didUpdate() {
    updatePosition(this);
  },
  actions : {
    close() {
      this.set('isPinned',false);
      this.set('isFocused',false);
      this.set('hasSelectedExpression',false);
    },
    pin() {
      this.toggleProperty('isPinned');
    }
  }
});