romo 0.19.10 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,411 +1,271 @@
1
- $.fn.romoDropdown = function() {
2
- return $.map(this, function(element) {
3
- return new RomoDropdown(element);
4
- });
5
- }
6
-
7
- var RomoDropdown = function(element) {
8
- this.elem = $(element);
9
- this.doInitPopup();
10
- this.romoAjax = this.elem.romoAjax()[0];
11
- this.romoAjax.doUnbindElem(); // disable auto invoke on click
12
-
13
- if (this.elem.data('romo-dropdown-disable-click-invoke') !== true) {
14
- this.elem.unbind('click');
15
- this.elem.on('click', $.proxy(this.onToggleClick, this));
16
- }
17
- this.elem.on('dropdown:triggerToggle', $.proxy(this.onToggleClick, this));
18
- this.elem.on('dropdown:triggerPopupOpen', $.proxy(this.onPopupOpen, this));
19
- this.elem.on('dropdown:triggerPopupClose', $.proxy(this.onPopupClose, this));
20
- this.elem.on('romoAjax:callStart', $.proxy(function(e, romoAjax) {
21
- this.doLoadBodyStart();
22
- return false;
23
- }, this));
24
- this.elem.on('romoAjax:callSuccess', $.proxy(function(e, data, romoAjax) {
25
- this.doLoadBodySuccess(data);
26
- return false;
27
- }, this));
28
- this.elem.on('romoAjax:callError', $.proxy(function(e, xhr, romoAjax) {
29
- this.doLoadBodyError(xhr);
30
- return false;
31
- }, this));
32
-
33
- this.doBindElemKeyUp();
1
+ var RomoDropdown = RomoComponent(function(elem) {
2
+ this.elem = elem;
34
3
 
35
4
  this.doInit();
36
- this.doInitBody();
5
+ this._bindElem();
37
6
 
38
- this.elem.trigger('dropdown:ready', [this]);
39
- }
7
+ Romo.trigger(this.elem, 'romoDropdown:ready', [this]);
8
+ });
40
9
 
41
10
  RomoDropdown.prototype.popupOpen = function() {
42
- return this.popupElem.hasClass('romo-dropdown-open') === true;
11
+ return Romo.hasClass(this.popupElem, 'romo-dropdown-open') === true;
43
12
  }
44
13
 
45
14
  RomoDropdown.prototype.popupClosed = function() {
46
- return this.popupElem.hasClass('romo-dropdown-open') === false;
15
+ return Romo.hasClass(this.popupElem, 'romo-dropdown-open') === false;
47
16
  }
48
17
 
49
- RomoDropdown.prototype.doInit = function() {
50
- // override as needed
18
+ RomoDropdown.prototype.doToggle = function() {
19
+ if (this.popupOpen()) {
20
+ Romo.pushFn(Romo.proxy(this.doPopupClose, this));
21
+ } else {
22
+ Romo.pushFn(Romo.proxy(this.doPopupOpen, this));
23
+ }
24
+ Romo.trigger(this.elem, 'romoDropdown:toggle', [this]);
51
25
  }
52
26
 
53
- RomoDropdown.prototype.doInitPopup = function() {
54
- this.popupElem = $('<div class="romo-dropdown-popup"><div class="romo-dropdown-body"></div></div>');
55
- this.popupElem.appendTo(this.elem.closest(this.elem.data('romo-dropdown-append-to-closest') || 'body'));
56
-
57
- this.popupElem.on('modal:popupOpen', $.proxy(function(e) {
58
- this.doUnBindWindowBodyClick();
59
- this.doUnBindWindowBodyKeyUp();
60
- this.doUnBindElemKeyUp();
61
- }, this));
62
- this.popupElem.on('modal:popupClose', $.proxy(function(e) {
63
- this.doBindWindowBodyClick();
64
- this.doBindWindowBodyKeyUp();
65
- this.doBindElemKeyUp();
66
- }, this));
67
-
68
- this.bodyElem = this.popupElem.find('> .romo-dropdown-body');
69
- if (this.elem.data('romo-dropdown-style-class') !== undefined) {
70
- this.bodyElem.addClass(this.elem.data('romo-dropdown-style-class'));
71
- }
27
+ RomoDropdown.prototype.doPopupOpen = function() {
28
+ Romo.popupStack.addElem(
29
+ this.popupElem,
30
+ Romo.proxy(this._openPopup, this),
31
+ Romo.proxy(this._closePopup, this),
32
+ Romo.proxy(this.doPlacePopupElem, this)
33
+ );
34
+ }
72
35
 
73
- this.contentElem = $();
36
+ RomoDropdown.prototype.doPopupClose = function() {
37
+ Romo.popupStack.closeThru(this.popupElem);
38
+ }
74
39
 
75
- var positionData = this._parsePositionData(this.elem.data('romo-dropdown-position'));
76
- this.popupPosition = positionData.position || 'bottom';
77
- this.popupAlignment = positionData.alignment || 'left';
78
- this.popupElem.attr('data-romo-dropdown-position', this.popupPosition);
79
- this.popupElem.attr('data-romo-dropdown-alignment', this.popupAlignment);
80
- this.popupElem.attr('data-romo-dropdown-fixed', this.elem.data('romo-dropdown-fixed'));
40
+ RomoDropdown.prototype.doPlacePopupElem = function() {
41
+ var configHeight = Romo.data(this.elem, 'romo-dropdown-height') ||
42
+ Romo.data(this.elem, 'romo-dropdown-max-height');
43
+ var configPosition = this.popupPosition;
81
44
 
82
- this.doSetPopupZIndex(this.elem);
45
+ if (configHeight === 'detect') {
46
+ var popupHeight = this.popupElem.offsetHeight;
47
+ var topAvailHeight = this._getPopupMaxAvailableHeight('top');
48
+ var bottomAvailHeight = this._getPopupMaxAvailableHeight('bottom');
83
49
 
84
- // don't propagate click events on the popup elem. this prevents the popup
85
- // from closing when clicked (see body click event bind on popup open)
86
- this.popupElem.on('click', function(e) {
87
- if (e !== undefined) {
88
- e.stopPropagation();
50
+ if (popupHeight < topAvailHeight && popupHeight < bottomAvailHeight) {
51
+ // if it fits both ways, use the config position way
52
+ configHeight = this._getPopupMaxAvailableHeight(configPosition);
53
+ } else if (topAvailHeight > bottomAvailHeight) {
54
+ configPosition = 'top';
55
+ configHeight = topAvailHeight;
56
+ } else {
57
+ configPosition = 'bottom';
58
+ configHeight = bottomAvailHeight;
89
59
  }
90
- })
91
-
92
- // the popup should be treated like a child elem. add it to Romo's
93
- // parent-child elems so it will be removed when the elem is removed.
94
- // delay adding it b/c other components may `append` generated dropdowns
95
- // meaning the dropdown is removed and then re-added. if added immediately
96
- // the "remove" part will incorrectly remove the popup.
97
- setTimeout($.proxy(function() {
98
- Romo.parentChildElems.add(this.elem, [this.popupElem]);
99
- }, this), 1);
100
- }
101
-
102
- RomoDropdown.prototype.doInitBody = function() {
103
- this.doResetBody();
104
60
 
105
- this.contentElem = this.bodyElem.find('.romo-dropdown-content').last();
106
- if (this.contentElem.size() === 0) {
107
- this.contentElem = this.bodyElem;
61
+ // remove any height difference between the popup and content elems
62
+ // assumes popup height always greater than or equal to content height
63
+ var contentMaxHeight = configHeight - (popupHeight - this.contentElem.offsetHeight);
64
+ Romo.setStyle(this.contentElem, 'max-height', contentMaxHeight.toString() + 'px');
108
65
  }
109
66
 
110
- this.closeElem = this.popupElem.find('[data-romo-dropdown-close="true"]');
111
- this.closeElem.unbind('click');
112
- this.closeElem.on('click', $.proxy(this.onPopupClose, this));
67
+ var elemRect = this.elem.getBoundingClientRect();
68
+ var elemOffset = Romo.offset(this.elem);
113
69
 
114
- this.contentElem.css({
115
- 'min-height': this.elem.data('romo-dropdown-min-height'),
116
- 'height': this.elem.data('romo-dropdown-height'),
117
- 'overflow-x': this.elem.data('romo-dropdown-overflow-x') || 'auto',
118
- 'overflow-y': this.elem.data('romo-dropdown-overflow-y') || 'auto'
119
- });
70
+ var elemHeight = elemRect.height;
71
+ var elemWidth = elemRect.width;
72
+ var elemTop = elemOffset.top;
73
+ var elemLeft = elemOffset.left
120
74
 
121
- if (this.elem.data('romo-dropdown-max-height') === undefined) {
122
- this.elem.attr('data-romo-dropdown-max-height', 'detect');
123
- }
124
- if (this.elem.data('romo-dropdown-max-height') !== 'detect') {
125
- this.contentElem.css({
126
- 'max-height': this.elem.data('romo-dropdown-max-height')
127
- });
128
- }
75
+ var popupOffsetHeight = this.popupElem.offsetHeight;
76
+ var popupOffsetWidth = this.popupElem.offsetWidth;
129
77
 
130
- if (this.elem.data('romo-dropdown-width') === 'elem') {
131
- this.popupElem.css({
132
- 'width': this.elem.css('width')
133
- });
134
- } else {
135
- this.contentElem.css({
136
- 'min-width': this.elem.data('romo-dropdown-min-width'),
137
- 'max-width': this.elem.data('romo-dropdown-max-width'),
138
- 'width': this.elem.data('romo-dropdown-width')
139
- });
78
+ var posTop = undefined;
79
+ switch (configPosition) {
80
+ case 'top':
81
+ var pad = 2;
82
+ posTop = elemTop - popupOffsetHeight - pad;
83
+ break;
84
+ case 'bottom':
85
+ var pad = 2;
86
+ posTop = elemTop + elemHeight + pad;
87
+ break;
140
88
  }
141
- }
142
-
143
- RomoDropdown.prototype.doResetBody = function() {
144
- this.contentElem.css({
145
- 'min-width': '',
146
- 'max-width': '',
147
- 'width': '',
148
- 'min-height': '',
149
- 'max-height': '',
150
- 'height': '',
151
- 'overflow-x': '',
152
- 'overflow-y': ''
153
- });
154
- }
155
-
156
- RomoDropdown.prototype.doLoadBodyStart = function() {
157
- this.bodyElem.html('');
158
- this.doInitBody();
159
- this.doPlacePopupElem();
160
- this.elem.trigger('dropdown:loadBodyStart', [this]);
161
- }
162
-
163
- RomoDropdown.prototype.doLoadBodySuccess = function(data) {
164
- Romo.initHtml(this.bodyElem, data);
165
- this.doInitBody();
166
- this.doPlacePopupElem();
167
- this.elem.trigger('dropdown:loadBodySuccess', [data, this]);
168
- }
169
-
170
- RomoDropdown.prototype.doLoadBodyError = function(xhr) {
171
- this.elem.trigger('dropdown:loadBodyError', [xhr, this]);
172
- }
173
89
 
174
- RomoDropdown.prototype.onToggleClick = function(e) {
175
- if (e !== undefined) {
176
- e.preventDefault();
90
+ var posLeft = undefined;
91
+ switch (this.popupAlignment) {
92
+ case 'left':
93
+ posLeft = elemLeft;
94
+ break;
95
+ case 'right':
96
+ posLeft = elemLeft + elemWidth - popupOffsetWidth;
97
+ break;
177
98
  }
178
99
 
179
- if (this.elem.hasClass('disabled') === false &&
180
- this.elem.data('romo-dropdown-disable-toggle') !== true) {
181
- this.doToggle();
182
- return true;
183
- }
184
- return false;
100
+ Romo.setStyle(this.popupElem, 'top', this._roundPosOffsetVal(posTop)+'px');
101
+ Romo.setStyle(this.popupElem, 'left', this._roundPosOffsetVal(posLeft)+'px');
185
102
  }
186
103
 
187
- RomoDropdown.prototype.doToggle = function() {
188
- if (this.popupOpen()) {
189
- setTimeout($.proxy(function() {
190
- this.doPopupClose();
191
- }, this), 100);
192
- } else {
193
- setTimeout($.proxy(function() {
194
- this.doPopupOpen();
195
- }, this), 100);
196
- }
197
- this.elem.trigger('dropdown:toggle', [this]);
104
+ RomoDropdown.prototype.doSetPopupZIndex = function(relativeElem) {
105
+ var relativeZIndex = Romo.parseZIndex(relativeElem);
106
+ Romo.setStyle(this.popupElem, 'z-index', relativeZIndex + 1200); // see z-index.css
198
107
  }
199
108
 
200
- RomoDropdown.prototype.onPopupOpen = function(e) {
201
- if (e !== undefined) {
202
- e.preventDefault();
203
- }
109
+ // private
204
110
 
205
- if (this.elem.hasClass('disabled') === false && this.popupClosed()) {
206
- setTimeout($.proxy(function() {
207
- this.doPopupOpen();
208
- }, this), 100);
209
- }
210
- }
111
+ RomoDropdown.prototype._openPopup = function() {
112
+ Romo.on(Romo.scrollableParents(this.elem), 'scroll', this._onScrollableParentsScroll);
211
113
 
212
- RomoDropdown.prototype.doPopupOpen = function() {
213
- if (this.elem.data('romo-dropdown-content-elem') !== undefined) {
214
- this.doLoadBodySuccess($(this.elem.data('romo-dropdown-content-elem')).html())
114
+ if (Romo.data(this.elem, 'romo-dropdown-content-elem') !== undefined) {
115
+ var contentElem = Romo.elems(Romo.data(this.elem, 'romo-dropdown-content-elem'))[0];
116
+ this._loadBodySuccess(contentElem.outerHTML);
215
117
  } else {
216
118
  this.romoAjax.doInvoke();
217
119
  }
218
120
 
219
- this.popupElem.addClass('romo-dropdown-open');
121
+ Romo.addClass(this.popupElem, 'romo-dropdown-open');
220
122
  this.doPlacePopupElem();
221
123
 
222
- // bind an event to close the popup when clicking away from the
223
- // popup. Bind on a timeout to allow time for any toggle
224
- // click event to propagate. If no timeout, we'll bind this
225
- // event, then the toggle click will propagate which will call
226
- // this event and immediately close the popup.
227
- setTimeout($.proxy(function() {
228
- this.doBindWindowBodyClick();
229
- }, this), 100);
230
-
231
- // bind "esc" keystroke to toggle close
232
- this.doBindWindowBodyKeyUp();
233
-
234
- // bind window resizes reposition dropdown
235
- $(window).on('resize', $.proxy(this.onResizeWindow, this));
236
-
237
- this.elem.trigger('dropdown:popupOpen', [this]);
124
+ Romo.trigger(this.elem, 'romoDropdown:popupOpen', [this]);
238
125
  }
239
126
 
240
- RomoDropdown.prototype.onPopupClose = function(e) {
241
- if (e !== undefined) {
242
- e.preventDefault();
243
- }
127
+ RomoDropdown.prototype._closePopup = function() {
128
+ Romo.removeClass(this.popupElem, 'romo-dropdown-open');
129
+ Romo.off(Romo.scrollableParents(this.elem), 'scroll', this._onScrollableParentsScroll);
244
130
 
245
- if (this.elem.hasClass('disabled') === false && this.popupOpen()) {
246
- setTimeout($.proxy(function() {
247
- this.doPopupClose();
248
- }, this), 100);
131
+ if (Romo.data(this.elem, 'romo-dropdown-clear-content') === true) {
132
+ Romo.updateHtml(this.contentElem, '');
249
133
  }
134
+
135
+ Romo.trigger(this.elem, 'romoDropdown:popupClose', [this]);
250
136
  }
251
137
 
252
- RomoDropdown.prototype.doPopupClose = function() {
253
- this.popupElem.removeClass('romo-dropdown-open');
138
+ RomoDropdown.prototype._bindElem = function() {
139
+ this._bindPopup();
140
+ this._bindAjax();
141
+ this._bindBody();
254
142
 
255
- // unbind any event to close the popup when clicking away from it
256
- this.doUnBindWindowBodyClick();
143
+ if (Romo.data(this.elem, 'romo-dropdown-disable-click-invoke') !== true) {
144
+ Romo.on(this.elem, 'click', Romo.proxy(this._onToggle, this));
145
+ }
146
+ Romo.on(this.elem, 'romoDropdown:triggerToggle', Romo.proxy(this._onToggle, this));
147
+ Romo.on(this.elem, 'romoDropdown:triggerPopupOpen', Romo.proxy(this._onPopupOpen, this));
148
+ Romo.on(this.elem, 'romoDropdown:triggerPopupClose', Romo.proxy(this._onPopupClose, this));
149
+ }
150
+
151
+ RomoDropdown.prototype._bindPopup = function() {
152
+ this.popupElem = Romo.elems(
153
+ '<div class="romo-dropdown-popup"><div class="romo-dropdown-body"></div></div>'
154
+ )[0];
155
+ var popupParentElem = Romo.closest(
156
+ this.elem,
157
+ Romo.data(this.elem, 'romo-dropdown-append-to-closest') || 'body'
158
+ );
159
+ Romo.append(popupParentElem, this.popupElem);
160
+
161
+ this.bodyElem = Romo.children(this.popupElem).find(Romo.proxy(function(childElem) {
162
+ return Romo.is(childElem, '.romo-dropdown-body');
163
+ }, this));
164
+ if (Romo.data(this.elem, 'romo-dropdown-style-class') !== undefined) {
165
+ Romo.addClass(this.bodyElem, Romo.data(this.elem, 'romo-dropdown-style-class'));
166
+ }
257
167
 
258
- // unbind "esc" keystroke to toggle close
259
- this.doUnBindWindowBodyKeyUp();
168
+ this.contentElem = undefined;
260
169
 
261
- // unbind window resizes reposition dropdown
262
- $(window).off('resize', $.proxy(this.onResizeWindow, this));
170
+ var positionData = this._parsePositionData(Romo.data(this.elem, 'romo-dropdown-position'));
171
+ this.popupPosition = positionData.position || 'bottom';
172
+ this.popupAlignment = positionData.alignment || 'left';
173
+ Romo.setData(this.popupElem, 'romo-dropdown-position', this.popupPosition);
174
+ Romo.setData(this.popupElem, 'romo-dropdown-alignment', this.popupAlignment);
263
175
 
264
- // clear the content elem markup if configured to
265
- if (this.elem.data('romo-dropdown-clear-content') === true) {
266
- this.contentElem.html('');
267
- }
176
+ this.doSetPopupZIndex(this.elem);
268
177
 
269
- this.elem.trigger('dropdown:popupClose', [this]);
178
+ Romo.parentChildElems.add(this.elem, [this.popupElem]);
179
+ Romo.on(this.popupElem, 'romoParentChildElems:childRemoved', Romo.proxy(function(e, childElem) {
180
+ Romo.popupStack.closeThru(this.popupElem);
181
+ }, this));
182
+ Romo.on(this.popupElem, 'romoPopupStack:popupClosedByEsc', Romo.proxy(function(e, romoPopupStack) {
183
+ Romo.trigger(this.elem, 'romoDropdown:popupClosedByEsc', [this]);
184
+ }, this));
270
185
  }
271
186
 
272
- RomoDropdown.prototype.doBindElemKeyUp = function() {
273
- this.elem.on('keyup', $.proxy(this.onElemKeyUp, this));
274
- this.popupElem.on('keyup', $.proxy(this.onElemKeyUp, this));
275
- }
187
+ RomoDropdown.prototype._bindAjax = function() {
188
+ this.romoAjax = new RomoAjax(this.elem);
189
+ this.romoAjax.doUnbindElem(); // disable auto invoke on click
276
190
 
277
- RomoDropdown.prototype.doUnBindElemKeyUp = function() {
278
- this.elem.off('keyup', $.proxy(this.onElemKeyUp, this));
279
- this.popupElem.off('keyup', $.proxy(this.onElemKeyUp, this));
191
+ Romo.on(this.elem, 'romoAjax:callStart', Romo.proxy(function(e, romoAjax) {
192
+ this._loadBodyStart();
193
+ return false;
194
+ }, this));
195
+ Romo.on(this.elem, 'romoAjax:callSuccess', Romo.proxy(function(e, data, romoAjax) {
196
+ this._loadBodySuccess(data);
197
+ return false;
198
+ }, this));
199
+ Romo.on(this.elem, 'romoAjax:callError', Romo.proxy(function(e, xhr, romoAjax) {
200
+ this._loadBodyError(xhr);
201
+ return false;
202
+ }, this));
280
203
  }
281
204
 
282
- RomoDropdown.prototype.onElemKeyUp = function(e) {
283
- if (this.elem.hasClass('disabled') === false) {
284
- if (this.popupOpen()) {
285
- if(e.keyCode === 27 /* Esc */ ) {
286
- this.doPopupClose();
287
- this.elem.trigger('dropdown:popupClosedByEsc', [this]);
288
- return false;
289
- } else {
290
- return true;
291
- }
292
- } else {
293
- return true;
294
- }
205
+ RomoDropdown.prototype._bindBody = function() {
206
+ this._resetBody();
207
+
208
+ var contentElems = Romo.find(this.bodyElem, '.romo-dropdown-content');
209
+ this.contentElem = contentElems[contentElems.length - 1];
210
+ if (this.contentElem === undefined) {
211
+ this.contentElem = this.bodyElem;
295
212
  }
296
- return true;
297
- }
298
213
 
299
- RomoDropdown.prototype.doBindWindowBodyClick = function() {
300
- $('body').on('click', $.proxy(this.onWindowBodyClick, this));
301
- $('body').on('modal:mousemove', $.proxy(this.onWindowBodyClick, this));
302
- }
214
+ this.closeElems = Romo.find(this.popupElem, '[data-romo-dropdown-close="true"]');
215
+ Romo.on(this.closeElems, 'click', Romo.proxy(this._onPopupClose, this));
303
216
 
304
- RomoDropdown.prototype.doUnBindWindowBodyClick = function() {
305
- $('body').off('click', $.proxy(this.onWindowBodyClick, this));
306
- $('body').off('modal:mousemove', $.proxy(this.onWindowBodyClick, this));
307
- }
217
+ Romo.setStyle(this.contentElem, 'min-height', Romo.data(this.elem, 'romo-dropdown-min-height'));
218
+ Romo.setStyle(this.contentElem, 'height', Romo.data(this.elem, 'romo-dropdown-height'));
219
+ Romo.setStyle(this.contentElem, 'overflow-x', Romo.data(this.elem, 'romo-dropdown-overflow-x') || 'auto');
220
+ Romo.setStyle(this.contentElem, 'overflow-y', Romo.data(this.elem, 'romo-dropdown-overflow-y') || 'auto');
308
221
 
309
- RomoDropdown.prototype.onWindowBodyClick = function(e) {
310
- // if not clicked on the popup elem or the elem
311
- var target = $(e.target);
312
- if (e !== undefined &&
313
- target.parents('.romo-dropdown-popup').size() === 0 &&
314
- target.closest(this.elem).size() === 0) {
315
- this.doPopupClose();
222
+ if (Romo.data(this.elem, 'romo-dropdown-max-height') === undefined) {
223
+ Romo.setData(this.elem, 'romo-dropdown-max-height', 'detect');
224
+ }
225
+ if (Romo.data(this.elem, 'romo-dropdown-max-height') !== 'detect') {
226
+ Romo.setStyle(this.contentElem, 'max-height', Romo.data(this.elem, 'romo-dropdown-max-height'));
316
227
  }
317
- return true;
318
- }
319
-
320
- RomoDropdown.prototype.doBindWindowBodyKeyUp = function() {
321
- $('body').on('keyup', $.proxy(this.onWindowBodyKeyUp, this));
322
- }
323
228
 
324
- RomoDropdown.prototype.doUnBindWindowBodyKeyUp = function() {
325
- $('body').off('keyup', $.proxy(this.onWindowBodyKeyUp, this));
229
+ if (Romo.data(this.elem, 'romo-dropdown-width') === 'elem') {
230
+ Romo.setStyle(this.popupElem, 'width', Romo.css(this.elem, 'width'));
231
+ } else {
232
+ Romo.setStyle(this.contentElem, 'min-width', Romo.data(this.elem, 'romo-dropdown-min-width'));
233
+ Romo.setStyle(this.contentElem, 'max-width', Romo.data(this.elem, 'romo-dropdown-max-width'));
234
+ Romo.setStyle(this.contentElem, 'width', Romo.data(this.elem, 'romo-dropdown-width'));
235
+ }
326
236
  }
327
237
 
328
- RomoDropdown.prototype.onWindowBodyKeyUp = function(e) {
329
- if (e.keyCode === 27 /* Esc */) {
330
- this.doPopupClose();
331
- this.elem.trigger('dropdown:popupClosedByEsc', [this]);
238
+ RomoDropdown.prototype._resetBody = function() {
239
+ if (this.contentElem !== undefined) {
240
+ Romo.rmStyle(this.contentElem, 'min-width');
241
+ Romo.rmStyle(this.contentElem, 'max-width');
242
+ Romo.rmStyle(this.contentElem, 'width');
243
+ Romo.rmStyle(this.contentElem, 'min-height');
244
+ Romo.rmStyle(this.contentElem, 'max-height');
245
+ Romo.rmStyle(this.contentElem, 'height');
246
+ Romo.rmStyle(this.contentElem, 'overflow-x');
247
+ Romo.rmStyle(this.contentElem, 'overflow-y');
332
248
  }
333
- return true;
334
249
  }
335
250
 
336
- RomoDropdown.prototype.onResizeWindow = function(e) {
251
+ RomoDropdown.prototype._loadBodyStart = function() {
252
+ Romo.updateHtml(this.bodyElem, '');
253
+ this._bindBody();
337
254
  this.doPlacePopupElem();
338
- return true;
255
+ Romo.pushFn(Romo.proxy(this.doPlacePopupElem, this));
256
+ Romo.trigger(this.elem, 'romoDropdown:loadBodyStart', [this]);
339
257
  }
340
258
 
341
- RomoDropdown.prototype.doPlacePopupElem = function() {
342
- if (this.elem.parents('.romo-modal-popup').size() !== 0) {
343
- this.popupElem.css({'position': 'fixed'});
344
- }
345
-
346
- var pos = $.extend({}, this.elem[0].getBoundingClientRect(), this.elem.offset());
347
- var w = this.popupElem[0].offsetWidth;
348
- var h = this.popupElem[0].offsetHeight;
349
- var offset = {};
350
-
351
- var configHeight = this.elem.data('romo-dropdown-height') || this.elem.data('romo-dropdown-max-height');
352
- var configPosition = this.popupPosition;
353
-
354
- if (configHeight === 'detect') {
355
- var popupHeight = this.popupElem.height();
356
- var topAvailHeight = this._getPopupMaxAvailableHeight('top');
357
- var bottomAvailHeight = this._getPopupMaxAvailableHeight('bottom');
358
-
359
- if (popupHeight < topAvailHeight && popupHeight < bottomAvailHeight) {
360
- // if it fits both ways, use the config position way
361
- configHeight = this._getPopupMaxAvailableHeight(configPosition);
362
- } else if (topAvailHeight > bottomAvailHeight) {
363
- configPosition = 'top';
364
- configHeight = topAvailHeight;
365
- } else {
366
- configPosition = 'bottom';
367
- configHeight = bottomAvailHeight;
368
- }
369
-
370
- // remove any height difference between the popup and content elems
371
- // assumes popup height always greater than or equal to content height
372
- configHeight = configHeight - (h - this.contentElem[0].offsetHeight);
373
- this.contentElem.css({'max-height': configHeight.toString() + 'px'});
374
- }
375
-
376
- if(h > configHeight) {
377
- h = configHeight;
378
- }
379
-
380
- switch (configPosition) {
381
- case 'top':
382
- var pad = 2;
383
- $.extend(offset, { top: pos.top - h - pad });
384
- break;
385
- case 'bottom':
386
- var pad = 2;
387
- $.extend(offset, { top: pos.top + pos.height + pad });
388
- break;
389
- }
390
- switch (this.popupAlignment) {
391
- case 'left':
392
- $.extend(offset, { left: pos.left });
393
- break;
394
- case 'right':
395
- $.extend(offset, { left: pos.left + pos.width - w });
396
- break;
397
- }
398
-
399
- $.extend(offset, {
400
- top: this._roundPosOffsetVal(offset['top']),
401
- left: this._roundPosOffsetVal(offset['left'])
402
- });
403
- this.popupElem.offset(offset);
259
+ RomoDropdown.prototype._loadBodySuccess = function(data) {
260
+ Romo.initUpdateHtml(this.bodyElem, data);
261
+ this._bindBody();
262
+ this.doPlacePopupElem();
263
+ Romo.pushFn(Romo.proxy(this.doPlacePopupElem, this));
264
+ Romo.trigger(this.elem, 'romoDropdown:loadBodySuccess', [data, this]);
404
265
  }
405
266
 
406
- RomoDropdown.prototype.doSetPopupZIndex = function(relativeElem) {
407
- var relativeZIndex = Romo.parseZIndex(relativeElem);
408
- this.popupElem.css({'z-index': relativeZIndex + 1200}); // see z-index.css
267
+ RomoDropdown.prototype._loadBodyError = function(xhr) {
268
+ Romo.trigger(this.elem, 'romoDropdown:loadBodyError', [xhr, this]);
409
269
  }
410
270
 
411
271
  RomoDropdown.prototype._parsePositionData = function(posString) {
@@ -418,12 +278,13 @@ RomoDropdown.prototype._getPopupMaxAvailableHeight = function(position) {
418
278
 
419
279
  switch (position) {
420
280
  case 'top':
421
- var elemTop = this.elem[0].getBoundingClientRect().top;
281
+ var elemTop = this.elem.getBoundingClientRect().top;
422
282
  maxHeight = elemTop - this._getPopupMaxHeightDetectPad(position);
423
283
  break;
424
284
  case 'bottom':
425
- var elemBottom = this.elem[0].getBoundingClientRect().bottom;
426
- maxHeight = $(window).height() - elemBottom - this._getPopupMaxHeightDetectPad(position);
285
+ var viewportHeight = document.documentElement.clientHeight;
286
+ var elemBottom = this.elem.getBoundingClientRect().bottom;
287
+ maxHeight = viewportHeight - elemBottom - this._getPopupMaxHeightDetectPad(position);
427
288
  break;
428
289
  }
429
290
 
@@ -431,13 +292,43 @@ RomoDropdown.prototype._getPopupMaxAvailableHeight = function(position) {
431
292
  }
432
293
 
433
294
  RomoDropdown.prototype._getPopupMaxHeightDetectPad = function(position) {
434
- return this.elem.data('romo-dropdown-max-height-detect-pad-'+position) || this.elem.data('romo-dropdown-max-height-detect-pad') || 10;
295
+ return Romo.data(this.elem, 'romo-dropdown-max-height-detect-pad-'+position) || Romo.data(this.elem, 'romo-dropdown-max-height-detect-pad') || 10;
435
296
  }
436
297
 
437
298
  RomoDropdown.prototype._roundPosOffsetVal = function(value) {
438
299
  return Math.round(value*100) / 100;
439
300
  }
440
301
 
441
- Romo.onInitUI(function(e) {
442
- Romo.initUIElems(e, '[data-romo-dropdown-auto="true"]').romoDropdown();
443
- });
302
+ // event functions
303
+
304
+ RomoDropdown.prototype.romoEvFn._onToggle = function(e) {
305
+ e.preventDefault();
306
+
307
+ if (
308
+ Romo.hasClass(this.elem, 'disabled') === false &&
309
+ Romo.data(this.elem, 'romo-dropdown-disable-toggle') !== true
310
+ ) {
311
+ this.doToggle();
312
+ }
313
+ }
314
+
315
+ RomoDropdown.prototype.romoEvFn._onPopupOpen = function(e) {
316
+ if (Romo.hasClass(this.elem, 'disabled') === false && this.popupClosed()) {
317
+ Romo.pushFn(Romo.proxy(this.doPopupOpen, this));
318
+ }
319
+ }
320
+
321
+ RomoDropdown.prototype.romoEvFn._onPopupClose = function(e) {
322
+ if (Romo.hasClass(this.elem, 'disabled') === false && this.popupOpen()) {
323
+ Romo.pushFn(Romo.proxy(this.doPopupClose, this));
324
+ }
325
+ }
326
+
327
+ RomoDropdown.prototype.romoEvFn._onScrollableParentsScroll = function(e) {
328
+ Romo.popupStack.placeAllPopups();
329
+ }
330
+
331
+ // init
332
+
333
+ Romo.popupStack.addStyleClass('romo-dropdown-popup');
334
+ Romo.addElemsInitSelector('[data-romo-dropdown-auto="true"]', RomoDropdown);