summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/print_preview/margins_ui.js
blob: c2d5309d33eb1ff16ba2e676052eea1ff5236223 (plain)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('print_preview', function() {
  'use strict';

  function MarginsUI() {
    var marginsUI = document.createElement('div');
    marginsUI.__proto__ = MarginsUI.prototype;
    marginsUI.id = 'customized-margins';

    // @type {print_preview.MarginsUIPair} The object corresponding to the top
    //     margin.
    marginsUI.topPair_ = new print_preview.MarginsUIPair(
        print_preview.MarginSettings.TOP_GROUP);
    // @type {print_preview.MarginsUIPair} The object corresponding to the left
    //     margin.
    marginsUI.leftPair_ = new print_preview.MarginsUIPair(
        print_preview.MarginSettings.LEFT_GROUP);
    // @type {print_preview.MarginsUIPair} The object corresponding to the right
    //     margin.
    marginsUI.rightPair_ = new print_preview.MarginsUIPair(
        print_preview.MarginSettings.RIGHT_GROUP);
    // @type {print_preview.MarginsUIPair} The object corresponding to the
    //     bottom margin.
    marginsUI.bottomPair_ = new print_preview.MarginsUIPair(
        print_preview.MarginSettings.BOTTOM_GROUP);

    var uiPairs = marginsUI.pairsAsList;
    for (var i = 0; i < uiPairs.length; i++)
      marginsUI.appendChild(uiPairs[i]);

    // @type {print_preview.MarginsUIPair} The object that is being dragged.
    //     null if no drag session is in progress.
    marginsUI.lastClickedMarginsUIPair = null;

    // @type {EventTracker} Used to keep track of certain event listeners.
    marginsUI.eventTracker_ = new EventTracker();

    marginsUI.addEventListeners_();
    return marginsUI;
  }

  /**
   * @param {{x: number, y: number}} point The point with respect to the top
   *     left corner of the webpage.
   * @return {{x: number, y: number}} The point with respect to the top left
   *     corner of the plugin area.
   */
  MarginsUI.convert = function(point) {
    var mainview = $('mainview');
    return { x: point.x - mainview.offsetLeft,
             y: point.y - mainview.offsetTop };
  }

  MarginsUI.prototype = {
    __proto__: HTMLDivElement.prototype,

    /**
     * Adds an observer for |customEvents.MARGINS_MAY_HAVE_CHANGED| event.
     * @param {function} func A callback function to be called when
     *     |customEvents.MARGINS_MAY_HAVE_CHANGED| event occurs.
     */
    addObserver: function(func) {
      var uiPairs = this.pairsAsList;
      for (var i = 0; i < uiPairs.length; i++) {
        uiPairs[i].box_.addEventListener(
            customEvents.MARGINS_MAY_HAVE_CHANGED, func);
      }
    },

    /**
     * @return {array} An array including all |MarginUIPair| objects.
     */
    get pairsAsList() {
      return [this.topPair_, this.leftPair_, this.rightPair_, this.bottomPair_];
    },

    /**
     * Updates the state of the margins UI.
     * @param {print_preview.Rect} marginsRectangle A rectangle describing the
     *     four margins.
     * @param {Margins} marginValues The margin values in points.
     * @param {Array.<number>} valueLimits The maximum allowed margins for each
     *     side in points.
     * @param {boolean} keepDisplayedValue True if the currently displayed
     *     margin values should not be updated.
     * @param {Array.<number>} valueLimitsInPercent The maximum allowed margins
     *     for each side in percentages.
     */
    update: function(marginsRectangle, marginValues, valueLimits,
        keepDisplayedValue, valueLimitsInPercent) {
      var uiPairs = this.pairsAsList;
      var order = ['top', 'left', 'right', 'bottom'];
      for (var i = 0; i < uiPairs.length; i++) {
        uiPairs[i].update(marginsRectangle,
                          marginValues[order[i]],
                          valueLimits[i],
                          keepDisplayedValue,
                          valueLimitsInPercent[i]);
      }
    },

    /**
     * Draws |this| based on the latest state.
     */
    draw: function() {
      this.applyClippingMask_();
      this.pairsAsList.forEach(function(pair) { pair.draw(); });
    },

    /**
     * Shows the margins UI.
     */
    show: function() {
      this.hidden = false;
      this.classList.remove('invisible');
    },

    /**
     * Hides the margins UI and removes from the rendering flow if requested.
     * @param {boolean} removeFromFlow True if |this| should also be removed
     *     from the rendering flow (in order to not interfere with the tab
     *     order).
     */
    hide: function(removeFromFlow) {
      removeFromFlow ? this.hidden = true : this.classList.add('invisible');
    },

    /**
     * Applies a clipping mask on |this| so that it does not paint on top of the
     * scrollbars (if any).
     */
    applyClippingMask_: function() {
      var bottom = previewArea.height;
      var right = previewArea.width;
      this.style.clip = 'rect(0, ' + right + 'px, ' + bottom + 'px, 0)';
    },

    /**
     * Adds event listeners for various events.
     * @private
     */
    addEventListeners_: function() {
      var uiPairs = this.pairsAsList;
      for (var i = 0; i < uiPairs.length; i++) {
        uiPairs[i].addEventListener(customEvents.MARGIN_LINE_MOUSE_DOWN,
                                    this.onMarginLineMouseDown.bind(this));
      }
      // After snapping to min/max the MarginUIPair might not receive the
      // mouseup event since it is not under the mouse pointer, so it is handled
      // here.
      window.document.addEventListener('mouseup',
                                       this.onMarginLineMouseUp.bind(this));
    },

    /**
     * Executes when a "MarginLineMouseDown" event occurs.
     * @param {cr.Event} e The event that triggered this listener.
     */
    onMarginLineMouseDown: function(e) {
      this.lastClickedMarginsUIPair = e.target;
      this.bringToFront(this.lastClickedMarginsUIPair);
      // Note: Capturing mouse events at a higher level in the DOM than |this|,
      // so that the plugin can still receive mouse events.
      this.eventTracker_.add(
          window.document, 'mousemove', this.onMouseMove_.bind(this), false);
    },

    /**
     * Executes when a "MarginLineMouseUp" event occurs.
     * @param {cr.Event} e The event that triggered this listener.
     */
    onMarginLineMouseUp: function(e) {
      if (this.lastClickedMarginsUIPair == null)
        return;
      this.lastClickedMarginsUIPair.onMouseUp();
      this.lastClickedMarginsUIPair = null;
      this.eventTracker_.remove(window.document, 'mousemove');
    },

    /**
     * Brings |uiPair| in front of the other pairs. Used to make sure that the
     * dragged pair is visible when overlapping with a not dragged pair.
     * @param {print_preview.MarginsUIPair} uiPair The pair to bring in front.
     */
    bringToFront: function(uiPair) {
      this.pairsAsList.forEach(function(pair) {
        pair.classList.remove('dragging');
      });
      uiPair.classList.add('dragging');
    },

    /**
     * Executes when a mousemove event occurs.
     * @param {MouseEvent} e The event that triggered this listener.
     */
    onMouseMove_: function(e) {
      var point = MarginsUI.convert({ x: e.x, y: e.y });

      var dragEvent = new cr.Event(customEvents.MARGIN_LINE_DRAG);
      dragEvent.dragDelta =
          this.lastClickedMarginsUIPair.getDragDisplacementFrom(point);
      dragEvent.destinationPoint = point;
      this.dispatchEvent(dragEvent);
    }
  };

  return {
    MarginsUI: MarginsUI
  };
});