root/trunk/ippu.js

Revision 269, 20.6 kB (checked in by sup, 12 months ago)

LJSUP-3353: Syndicate my content, phase 1 - JS fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2  IPPU methods:
3     init([innerHTML]) -- takes innerHTML as optional argument
4     show() -- shows the popup
5     hide() -- hides popup
6     cancel() -- hides and calls cancel callback
7
8  Content setters:
9     setContent(innerHTML) -- set innerHTML
10     setContentElement(element) -- adds element as a child of the popup
11
12   Accessors:
13     getElement() -- returns popup DIV element
14     visible() -- returns whether the popup is visible or not
15
16   Titlebar:
17     setTitlebar(show) -- true: show titlebar / false: no titlebar
18     setTitle(title) -- sets the titlebar text
19     getTitlebarElement() -- returns the titlebar element
20     setTitlebarClass(className) -- set the class of the titlebar
21
22   Styling:
23     setOverflow(overflow) -- sets ele.style.overflow to overflow
24     addClass(className) -- adds class to popup
25     removeClass(className) -- removes class to popup
26
27   Browser Hacks:
28     setAutoHideSelects(autohide) -- when the popup is shown should it find all the selects
29                                on the page and hide them (and show them again) (for IE)
30
31   Positioning/Sizing:
32     setLocation(left, top) -- set popup location: will be pixels if units not specified
33     setLeft(left) -- set left location
34     setTop(top)   -- set top location
35     setDimensions(width, height) -- set popup dimensions: will be pixels if units not specified
36     setAutoCenter(x, y) -- what dimensions to auto-center
37     center() -- centers popup on screen
38     centerX() -- centers popup horizontally
39     centerY() -- centers popup vertically
40     setFixedPosition(fixed) -- should the popup stay fixed on the page when it scrolls?
41     centerOnWidget(widget) -- center popup on this widget
42     setAutoCenterCallback(callback) -- calls callback with this IPPU instance as a parameter
43                                        for auto-centering. Some common built-in class methods
44                                        you can use as callbacks are:
45                                        IPPU.center
46                                        IPPU.centerX
47                                        IPPU.centerY
48
49     moveForward(amount) -- increases the zIndex by one or amount if specified
50     moveBackward(amount) -- decreases the zIndex by one or amount if specified
51
52   Modality:
53     setClickToClose(clickToClose) -- if clickToClose is true, clicking outside of the popup
54                                      will close it
55     setModal(modality) -- If modality is true, then popup will capture all mouse events
56                     and optionally gray out the rest of the page. (overrides clickToClose)
57     setOverlayVisible(visible) -- If visible is true, when this popup is on the page it
58                                   will gray out the rest of the page if this is modal
59
60   Callbacks:
61     setCancelledCallback(callback) -- call this when the dialog is closed through clicking
62                                       outside, titlebar close button, etc...
63     setHiddenCallback(callback) -- called when the dialog is closed in any fashion
64
65   Fading:
66     setFadeIn(fadeIn) -- set whether or not to automatically fade the ippu in
67     setFadeOut(fadeOut) -- set whether or not to automatically fade the ippu out
68     setFadeSpeed(secs) -- sets fade speed
69
70  Class Methods:
71   Handy callbacks:
72     IPPU.center
73     IPPU.centerX
74     IPPU.centerY
75   Browser testing:
76     IPPU.isIE() -- is the browser internet exploder?
77     IPPU.ieSafari() -- is this safari?
78
79////////////////////
80
81
82ippu.setModalDenialCallback(IPPU.cssBorderFlash);
83
84
85   private:
86    Properties:
87     ele -- DOM node of div
88     shown -- boolean; if element is in DOM
89     autoCenterX -- boolean; auto-center horiz
90     autoCenterY -- boolean; auto-center vertical
91     fixedPosition -- boolean; stay in fixed position when browser scrolls?
92     titlebar -- titlebar element
93     title -- string; text to go in titlebar
94     showTitlebar -- boolean; whether or not to show titlebar
95     content -- DIV containing user's specified content
96     clickToClose -- boolean; clicking outside popup will close it
97     clickHandlerSetup -- boolean; have we set up the click handlers?
98     docOverlay -- DIV that overlays the document for capturing clicks
99     modal -- boolean; capture all events and prevent user from doing anything
100                       until dialog is dismissed
101     visibleOverlay -- boolean; make overlay slightly opaque
102     clickHandlerFunc -- function; function to handle document clicks
103     resizeHandlerFunc -- function; function to handle document resizing
104     autoCenterCallback -- function; what callback to call for auto-centering
105     cancelledCallback -- function; called when dialog is cancelled
106     setAutoHideSelects -- boolean; autohide all SELECT elements on the page when popup is visible
107     hiddenSelects -- array; SELECT elements that have been hidden
108     hiddenCallback -- funciton; called when dialog is hidden
109     fadeIn, fadeOut, fadeSpeed -- fading settings
110     fadeMode -- current fading mode (in, out) if there is fading going on
111
112    Methods:
113     updateTitlebar() -- create titlebar if it doesn't exist,
114                         hide it if titlebar == false,
115                         update titlebar text
116     updateContent() -- makes sure all currently specified properties are applied
117     setupClickCapture() -- if modal, create document-sized div overlay to capture click events
118                            otherwise install document onclick handler
119     removeClickHandlers() -- remove overlay, event handlers
120     clickHandler() -- event handler for clicks
121     updateOverlay() -- if we have an overlay, make sure it's where it should be and (in)visible
122                        if it should be
123     autoCenter() -- centers popup on screen according to autoCenterX and autoCenterY
124     hideSelects() -- hide all select element on page
125     showSelects() -- show all selects
126     _hide () -- actually hides everything, called by hide(), which does fading if necessary
127*/
128
129// this belongs somewhere else:
130function changeOpac(id, opacity) {
131    var e =  $(id);
132    if (e && e.style) {
133        var object = e.style;
134        if (object) {
135            //reduce flicker
136            if (IPPU.isSafari() && opacity >= 100)
137                opacity = 99.99;
138
139            // IE
140            if (object.filters)
141                object.filters.alpha.opacity = opacity * 100;
142
143            object.opacity = opacity;
144        }
145    }
146}
147
148IPPU = new Class( Object, {
149  setFixedPosition: function (fixed) {
150    // no fixed position for IE
151    if (IPPU.isIE())
152      return;
153
154    this.fixedPosition = fixed;
155    this.updateContent();
156  },
157
158  clickHandler : function (evt) {
159    if (!this.clickToClose) return;
160    if (!this.visible()) return;
161
162    evt = Event.prep(evt);
163    var target = evt.target;
164    // don't do anything if inside the popup
165    if (DOM.getAncestorsByClassName(target, "ippu", true).length > 0) return;
166    this.cancel();
167  },
168
169  setCancelledCallback : function (callback) {
170    this.cancelledCallback = callback;
171  },
172
173  cancel : function () {
174    if (this.cancelledCallback)
175      this.cancelledCallback();
176    this.hide();
177  },
178
179  setHiddenCallback: function (callback) {
180    this.hiddenCallback = callback;
181  },
182
183  setupClickCapture : function () {
184    if (!this.visible() || this.clickHandlerSetup){return;}
185    if (!this.clickToClose && !this.modal) {return;}
186
187    this.clickHandlerFunc = this.clickHandler.bindEventListener(this);
188
189    if (this.modal) {
190      // create document-sized div to capture events
191      if (this.overlay) return; // wtf? shouldn't exist yet
192      this.overlay = document.createElement("div");
193      this.overlay.style.left = "0px";
194      this.overlay.style.top = "0px";
195      this.overlay.style.margin = "0px";
196      this.overlay.style.padding = "0px";
197     
198      this.overlay.style.backgroundColor = "#000000";
199      this.overlay.style.zIndex="900";
200      if (IPPU.isIE()){
201                this.overlay.style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity=50)";
202                this.overlay.style.position="absolute";
203                this.overlay.style.width=document.body.scrollWidth;
204                this.overlay.style.height=document.body.scrollHeight;
205      }
206      else{
207        this.overlay.style.position = "fixed";
208      }
209
210      this.ele.parentNode.insertBefore(this.overlay, this.ele);
211      this.updateOverlay();
212
213      DOM.addEventListener(this.overlay, "click", this.clickHandlerFunc);
214    } else {
215      // simple document onclick handler
216      DOM.addEventListener(document, "click", this.clickHandlerFunc);
217    }
218
219    this.clickHandlerSetup = true;
220  },
221
222  updateOverlay : function () {
223    if (this.overlay) {
224      var cd = DOM.getClientDimensions();
225      this.overlay.style.width = (cd.x - 1) + "px";
226      if(!IPPU.isIE()){
227        this.overlay.style.height = (cd.y - 1) + "px";
228      } 
229      if (this.visibleOverlay) {
230        this.overlay.backgroundColor = "#000000";
231        changeOpac(this.overlay, 0.50);
232      } else {
233        this.overlay.backgroundColor = "#FFFFFF";
234        changeOpac(this.overlay, 0.0);
235      }
236    }
237  },
238
239  resizeHandler : function (evt) {
240    this.updateContent();
241  },
242
243  removeClickHandlers : function () {
244    if (!this.clickHandlerSetup) return;
245
246    var myself = this;
247    var handlerFunc = function (evt) {
248      myself.clickHandler(evt);
249    };
250
251    DOM.removeEventListener(document, "click", this.clickHandlerFunc, false);
252
253    if (this.overlay) {
254      DOM.removeEventListener(this.overlay, "click", this.clickHandlerFunc, true);
255      this.overlay.parentNode.removeChild(this.overlay);
256      this.overlay = undefined;
257    }
258
259    this.clickHandlerFunc = undefined;
260    this.clickHandlerSetup = false;
261  },
262
263  setClickToClose : function (clickToClose) {
264    this.clickToClose = clickToClose;
265
266    if (!this.clickHandlerSetup && clickToClose && this.visible()) {
267      // popup is already visible, need to set up click handler
268      var setupClickCaptureCallback = this.setupClickCapture.bind(this);
269      window.setTimeout(setupClickCaptureCallback, 100);
270    } else if (!clickToClose && this.clickHandlerSetup) {
271      this.removeClickHandlers();
272    }
273
274    this.updateContent();
275  },
276
277  setModal : function (modal) {
278    var changed = (this.modal == modal);
279
280    // if it's modal, we don't want click-to-close
281    if (modal)
282      this.setClickToClose(false);
283
284    this.modal = modal;
285    if (changed) {
286      this.removeClickHandlers();
287      this.updateContent();
288    }
289  },
290
291  setOverlayVisible : function (vis) {
292    this.visibleOverlay = vis;
293    this.updateContent();
294  },
295
296  updateContent : function () {
297    this.autoCenter();
298    this.updateTitlebar();
299    this.updateOverlay();
300    if (this.titlebar)
301      this.setTitlebarClass(this.titlebar.className);
302
303    var setupClickCaptureCallback = this.setupClickCapture.bind(this);
304    window.setTimeout(setupClickCaptureCallback, 100);
305
306    if (this.fixedPosition && this.ele.style.position != "fixed")
307      this.ele.style.position = "fixed";
308    else if (!this.fixedPosition && this.ele.style.position == "fixed")
309      this.ele.style.position = "absolute";
310  },
311
312  getTitlebarElement : function () {
313    return this.titlebar;
314  },
315
316  setTitlebarClass : function (className) {
317    if (this.titlebar)
318      this.titlebar.className = className;
319  },
320
321  setOverflow : function (overflow) {
322    if (this.ele)
323      this.ele.style.overflow = overflow;
324  },
325
326  visible : function () {
327    return this.shown;
328  },
329
330  setTitlebar : function (show) {
331    this.showTitlebar = show;
332
333    if (show) {
334      if (!this.titlebar) {
335        // titlebar hasn't been created. Create it.
336        var tbar = document.createElement("div");
337        if (!tbar) return;
338        tbar.style.width = "100%";
339
340        if (this.title) tbar.innerHTML = this.title;
341        this.ele.insertBefore(tbar, this.content);
342        this.titlebar = tbar;
343
344      }
345    } else if (this.titlebar) {
346      this.ele.removeChild(this.titlebar);
347      this.titlebar = false;
348    }
349  },
350
351  setTitle : function (title) {
352    this.title = title;
353    this.updateTitlebar();
354  },
355
356  updateTitlebar : function() {
357    if (this.showTitlebar && this.titlebar && this.title != this.titlebar.innerHTML) {
358      this.titlebar.innerHTML = this.title;
359    }
360  },
361
362  addClass : function (className) {
363    DOM.addClassName(this.ele, className);
364  },
365
366  removeClass : function (className) {
367    DOM.removeClassName(this.ele, className);
368  },
369
370  setAutoCenterCallback : function (callback) {
371    this.autoCenterCallback = callback;
372  },
373
374  autoCenter : function () {
375    if (!this.visible || !this.visible()) return;
376
377    if (this.autoCenterCallback) {
378      this.autoCenterCallback(this);
379      return;
380    }
381
382    if (this.autoCenterX)
383      this.centerX();
384
385    if (this.autoCenterY)
386      this.centerY();
387  },
388
389  center : function () {
390    this.centerX();
391    this.centerY();
392  },
393
394  centerOnWidget : function (widget, offsetTop, offsetLeft) {
395        offsetTop = offsetTop || 0;
396        offsetLeft = offsetLeft || 0;
397        this.setAutoCenter(false, false);
398        this.setAutoCenterCallback(null);
399  var wd = DOM.getAbsoluteDimensions(widget);
400    var ed = DOM.getAbsoluteDimensions(this.ele);
401    var newleft = (wd.absoluteRight - wd.offsetWidth / 2 - ed.offsetWidth / 2) + offsetLeft;
402    var newtop = (wd.absoluteBottom - wd.offsetHeight / 2 - ed.offsetHeight / 2) + offsetTop;
403
404        newleft = newleft < 0 ? 0 : newleft;
405        newtop  = newtop  < 0 ? 0 : newtop;
406    DOM.setLeft(this.ele, newleft);
407    DOM.setTop(this.ele, newtop);
408  },
409
410  centerX : function () {
411    if (!this.visible || !this.visible()) return;
412
413    var cd = DOM.getClientDimensions();
414    var newleft = cd.x / 2 - DOM.getDimensions(this.ele).offsetWidth / 2;
415
416    // If not fixed position, center relative to the left of the page
417    if (!this.fixedPosition) {
418        var wd = DOM.getWindowScroll();
419        newleft += wd.left;
420    }
421
422   DOM.setLeft(this.ele, newleft);
423  },
424
425  centerY : function () {
426    if (!this.visible || !this.visible()) return;
427
428    var cd = DOM.getClientDimensions();
429    var newtop = cd.y / 2 - DOM.getDimensions(this.ele).offsetHeight / 2;
430
431    // If not fixed position, center relative to the top of the page
432    if (!this.fixedPosition) {
433        var wd = DOM.getWindowScroll();
434        newtop += wd.top;
435    }
436
437    DOM.setTop(this.ele, newtop);
438  },
439
440  setAutoCenter : function (autoCenterX, autoCenterY) {
441    this.autoCenterX = autoCenterX || false;
442    this.autoCenterY = autoCenterY || false;
443
444    if (!autoCenterX && !autoCenterY) {
445        this.setAutoCenterCallback(null);
446        return;
447    }
448
449    this.autoCenter();
450  },
451
452  setDimensions : function (width, height) {
453    width = width + "";
454    height = height + "";
455    if (width.match(/^\d+$/)) width += "px";
456    if (height.match(/^\d+$/)) height += "px";
457
458    this.ele.style.width  = width;
459    this.ele.style.height = height;
460  },
461
462  moveForward : function (howMuch) {
463      if (!howMuch) howMuch = 1;
464      if (! this.ele) return;
465
466      this.ele.style.zIndex += howMuch;
467  },
468
469  moveBackward : function (howMuch) {
470      if (!howMuch) howMuch = 1;
471      if (! this.ele) return;
472
473      this.ele.style.zIndex -= howMuch;
474  },
475
476  setLocation : function (left, top) {
477      this.setLeft(left);
478      this.setTop(top);
479  },
480
481  setTop : function (top) {
482    top = top + "";
483    if (top.match(/^\d+$/)) top += "px";
484    this.ele.style.top = top;
485  },
486
487  setLeft : function (left) {
488    left = left + "";
489    if (left.match(/^\d+$/)) left += "px";
490    this.ele.style.left = left;
491  },
492
493  getElement : function () {
494    return this.ele;
495  },
496
497  setContent : function (html) {
498    this.content.innerHTML = html;
499  },
500
501  setContentElement : function (element) {
502      // remove child nodes
503      while (this.content.firstChild) {
504          this.content.removeChild(this.content.firstChild);
505      };
506
507    this.content.appendChild(element);
508  },
509
510  setFadeIn : function (fadeIn) {
511      this.fadeIn = fadeIn;
512  },
513
514  setFadeOut : function (fadeOut) {
515      this.fadeOut = fadeOut;
516  },
517
518  setFadeSpeed : function (fadeSpeed) {
519      this.fadeSpeed = fadeSpeed;
520  },
521
522  show : function () {
523    this.shown = true;
524
525    if (this.fadeIn) {
526        var opp = 0.01;
527
528        changeOpac(this.ele, opp);
529    }
530
531    document.body.appendChild(this.ele);
532    this.ele.style.position = "absolute";
533    if (this.autoCenterX || this.autoCenterY) this.center();
534
535    this.updateContent();
536
537    if (!this.resizeHandlerFunc) {
538      this.resizeHandlerFunc = this.resizeHandler.bindEventListener(this);
539      DOM.addEventListener(window, "resize", this.resizeHandlerFunc, false);
540    }
541
542    if (this.fadeIn)
543        this.fade("in");
544
545    this.hideSelects();
546  },
547
548  fade : function (mode, callback) {
549      var opp;
550      var delta;
551
552      var steps = 10.0;
553
554      if (mode == "in") {
555          delta = 1 / steps;
556          opp = 0.1;
557      } else {
558          if (this.ele.style.opacity)
559          opp = finiteFloat(this.ele.style.opacity);
560          else
561          opp = 0.99;
562
563          delta = -1 / steps;
564      }
565
566      var fadeSpeed = this.fadeSpeed;
567      if (!fadeSpeed) fadeSpeed = 1;
568
569      var fadeInterval = steps / fadeSpeed * 5;
570
571      this.fadeMode = mode;
572
573      var self = this;
574      var fade = function () {
575          opp += delta;
576
577          // did someone start a fade in the other direction? if so,
578          // cancel this fade
579          if (self.fadeMode && self.fadeMode != mode) {
580              if (callback)
581                  callback.call(self, []);
582
583              return;
584          }
585
586          if (opp <= 0.1) {
587              if (callback)
588                  callback.call(self, []);
589
590              self.fadeMode = null;
591
592              return;
593          } else if (opp >= 1.0) {
594              if (callback)
595                  callback.call(self, []);
596
597              self.fadeMode = null;
598
599              return;
600          } else {
601              changeOpac(self.ele, opp);
602              window.setTimeout(fade, fadeInterval);
603          }
604      };
605
606      fade();
607  },
608
609  hide : function () {
610    if (! this.visible()) return;
611
612    if (this.fadeOut && this.ele) {
613        this.fade("out", this._hide.bind(this));
614    } else {
615        this._hide();
616    }
617  },
618
619  _hide : function () {
620    if (this.hiddenCallback)
621      this.hiddenCallback();
622
623    this.shown = false;
624    this.removeClickHandlers();
625
626    if (this.ele)
627    document.body.removeChild(this.ele);
628
629    if (this.resizeHandlerFunc)
630      DOM.removeEventListener(window, "resize", this.resizeHandlerFunc);
631
632    this.showSelects();
633  },
634
635  // you probably want this for IE being dumb
636  // (IE thinks select elements are cool and puts them in front of every element on the page)
637  setAutoHideSelects : function (autohide) {
638    this.autoHideSelects = autohide;
639    this.updateContent();
640  },
641
642  hideSelects : function () {
643    if (!this.autoHideSelects || !IPPU.isIE()) return;
644    var sels = document.getElementsByTagName("select");
645    var ele;
646    for (var i = 0; i < sels.length; i++) {
647      ele = sels[i];
648      if (!ele) continue;
649
650      // if this element is inside the ippu, skip it
651      if (DOM.getAncestorsByClassName(ele, "ippu", true).length > 0) continue;
652
653      if (ele.style.visibility != 'hidden') {
654        ele.style.visibility = 'hidden';
655        this.hiddenSelects.push(ele);
656      }
657    }
658  },
659
660  showSelects : function () {
661    if (! this.autoHideSelects) return;
662    var ele;
663    while (ele = this.hiddenSelects.pop())
664      ele.style.visibility = '';
665  },
666
667  init: function (html) {
668    var ele = document.createElement("div");
669    this.ele = ele;
670    this.shown = false;
671    this.autoCenterX = false;
672    this.autoCenterY = false;
673    this.titlebar = null;
674    this.title = "";
675    this.showTitlebar = false;
676    this.clickToClose = false;
677    this.modal = false;
678    this.clickHandlerSetup = false;
679    this.docOverlay = false;
680    this.visibleOverlay = false;
681    this.clickHandlerFunc = false;
682    this.resizeHandlerFunc = false;
683    this.fixedPosition = false;
684    this.autoCenterCallback = null;
685    this.cancelledCallback = null;
686    this.autoHideSelects = false;
687    this.hiddenCallback = null;
688    this.fadeOut = false;
689    this.fadeIn = false;
690    this.hiddenSelects = [];
691    this.fadeMode = null;
692
693    ele.style.position = "absolute";
694    ele.style.zIndex   = "1000";
695
696    // plz don't remove thx
697    DOM.addClassName(ele, "ippu");
698
699    // create DIV to hold user's content
700    this.content = document.createElement("div");
701
702    this.content.innerHTML = html;
703
704    this.ele.appendChild(this.content);
705  }
706});
707
708// class methods
709IPPU.center = function (obj) {
710  obj.centerX();
711  obj.centerY();
712};
713
714IPPU.centerX = function (obj) {
715  obj.centerX();
716};
717
718IPPU.centerY = function (obj) {
719  obj.centerY();
720};
721
722IPPU.isIE = function () {
723    var UA = navigator.userAgent.toLowerCase();
724    if (UA.indexOf('msie') != -1) return true;
725    return false;
726};
727
728IPPU.isSafari = function () {
729    var UA = navigator.userAgent.toLowerCase();
730    if (UA.indexOf('safari') != -1) return true;
731    return false;
732};
Note: See TracBrowser for help on using the browser.