1 type("PopupDialog", ["PopupWidget"], {
2 draw: function(content, x, y) {
3 return this.PopupWidget.prototype.draw.call(this, content, x, y, null, true);
6 clickTriggersClosing: function(target) {
7 // Check if one of the elements that should not trigger
9 var nonCloseTriggeringClick = false;
10 each(this.nonCloseTriggeringElements, function(e) {
11 if (e.ancestorOf(target)) {
12 nonCloseTriggeringClick = true;
15 return (!this.canvas.ancestorOf(target) &&
16 !this.triggerElement.ancestorOf(target) &&
17 !nonCloseTriggeringClick);
20 open: function(x, y) {
22 this.PopupWidget.prototype.open.call(this, x, y);
24 self.clickHandler = function(event) {
25 if (self.clickTriggersClosing($E(eventTarget(event)))) {
29 IndicoUtil.onclickHandlerAdd(self.clickHandler);
33 if (this.closeHandler() && this.isopen) {
34 IndicoUtil.onclickHandlerRemove(this.clickHandler);
35 this.PopupWidget.prototype.close.call(this);
39 * Adds an element to the list of elements that when clicked
40 * on do not trigger close of the popup dialog.
42 addNonCloseTriggeringElement: function(element) {
43 this.nonCloseTriggeringElements.push(element);
46 function(content, triggerElement, closeHandler, nonCloseTriggeringElements) {
47 this.content = content;
49 this.triggerElement = triggerElement;
50 this.closeHandler = any(closeHandler, function() {return true; });
51 this.nonCloseTriggeringElements = any(nonCloseTriggeringElements, []);
56 type("ExclusivePopup", ["Printable"], {
59 this.canvas.dialog('open');
62 draw: function(content, customStyle, popupStyle) {
63 customStyle = customStyle || {};
67 else if(content.dom) {
68 content = content.dom;
71 if(popupStyle === undefined) {
72 popupStyle = customStyle;
74 var container = $('<div class="exclusivePopup"/>').css(popupStyle).append(content);
76 this.showCloseButton = !!this.title;
78 this.canvas.empty().css(customStyle).append(container);
79 this.dialogElement.css(customStyle);
84 this.canvas.dialog('close');
88 _getDialogOptions: function() {
92 _makeCanvas: function() {
94 var opts = $.extend(true, {
103 open: $.proxy(this._onOpen, this),
104 close: $.proxy(this._onClose, this),
105 beforeClose: $.proxy(this._onBeforeClose, this)
106 }, this._getDialogOptions());
107 this.canvas = $('<div/>').dialog(opts);
109 if(!this.dialogElement) {
110 this.dialogElement = this.canvas.dialog('widget');
112 this.buttons = this.dialogElement.find('.ui-dialog-buttonset button');
115 _onBeforeClose: function(e) {
116 // Close button clicked
117 if(e.originalEvent && $(e.originalEvent.currentTarget).hasClass('ui-dialog-titlebar-close')) {
118 if(isFunction(this.closeHandler) && !this.closeHandler()) {
123 else if(e.keyCode && e.keyCode === $.ui.keyCode.ESCAPE) {
124 e.stopPropagation(); // otherwise this triggers twice for some reason
125 if(this.closeHandler === null || !this.showCloseButton) {
126 // Ignore escape if we don't have a close button
129 if(isFunction(this.closeHandler) && !this.closeHandler()) {
135 _onOpen: function(e) {
137 if(this.closeHandler === null || !this.showCloseButton) {
138 this.dialogElement.find('.ui-dialog-titlebar-close').hide();
140 this.dialogElement.find('.ui-dialog-titlebar').hide();
144 if(this.postDraw() === true) {
146 var pos = this.canvas.dialog('option', 'position');
147 this.canvas.dialog('option', 'position', pos);
151 postDraw: function() {
155 _onClose: function(e, ui) {
157 this.canvas.dialog('destroy');
158 this.canvas.remove();
159 this.canvas = this.dialogElement = null;
163 }, function(title, closeButtonHandler, printable, showPrintButton, noCanvas) {
164 this.title = any(title, null);
166 // Called when user clicks the close button, if the function
167 // returns true the dialog will be closed.
168 this.closeHandler = any(closeButtonHandler, positive);
169 // the close button will be enabled in draw() so if that method is overridden it will not be drawn
170 this.showCloseButton = false;
172 // The maximum allowed height, used since it doesn't look
173 // very nice it the dialog gets too big.
174 this.maxHeight = 600;
176 // Decides whether the popup should be printable. That is, when the user
177 // clicks print only the content of the dialog will be printed not the
178 // whole page. Should be true in general unless the dialog is containing
179 // something users normally don't want to print, i.e. the loading dialog.
180 this.printable = any(printable, true);
182 // Whether to show the print button or not in the title
183 // Note: the button will only be shown if the popup dialog has a title.
185 this.showPrintButton = any(showPrintButton && title && printable, false);
197 * Builds an exclusive popup with a button bar
198 * Constructor arguments: the same ones as ExclusivePopup
200 type("ExclusivePopupWithButtons", ["ExclusivePopup"], {
201 _getButtons: function() {
204 _getDialogOptions: function() {
206 var buttons = this._getButtons();
208 this.defaultButton = null;
210 $.each(buttons, function(i, button) {
215 if(button.length > 2 && button[2]) {
216 self.defaultButton = i;
224 _onOpen: function(e) {
225 this.ExclusivePopup.prototype._onOpen.call(this, e);
226 if(this.defaultButton !== null) {
227 this.buttons[this.defaultButton].focus();
230 draw: function(mainContent, buttonContent, popupCustomStyle, mainContentStyle, buttonBarStyle) {
231 this.ExclusivePopup.prototype.draw.call(this, mainContent, popupCustomStyle);
233 }, function(title, closeButtonHandler, printable, showPrintButton, noCanvas){
234 this.ExclusivePopup(title, closeButtonHandler, printable, showPrintButton, noCanvas);
237 type("BalloonPopup", ["PopupDialog"], {
238 draw: function(x, y) {
241 this.closeButton = Html.div({className: 'balloonPopupCloseButton'});
242 this.balloonContent = Html.div({className: this.balloonClass}, this.hasCloseButton ? this.closeButton : '', this.content);
243 this.arrowDiv = Html.div({className: this.arrowClass, style: {width: this.arrowWidth, height: this.arrowHeight}});
244 this.mainDiv = Html.div({}, this.balloonContent, this.arrowDiv);
246 // Hide it until everything is prepared
247 this.mainDiv.dom.style.visibility = 'hidden';
249 // Sets the orientation to up
250 this.switchOrientation();
252 var toReturn = this.PopupDialog.prototype.draw.call(this, this.mainDiv, x, y);
254 this.arrowDiv.dom.style.left = pixels(0);
256 if (this.hasCloseButton) {
257 this.closeButton.observeClick(function() {self.close();});
262 open: function(x, y) {
268 this.PopupDialog.prototype.open.call(this, x, y);
272 // Everything is done, can now be shown to user
273 this.mainDiv.dom.style.visibility = 'visible';
275 switchOrientation: function() {
276 if (this.balloonContent.dom.style.bottom === '') {
277 // current orientation is down, set it to up
278 this.balloonContent.dom.style.bottom = pixels(this.arrowHeight - 1);
279 this.balloonContent.dom.style.top = '';
280 this.arrowDiv.dom.style.backgroundPosition = '0 -6px';
281 this.arrowDiv.dom.style.top = '';
282 this.arrowDiv.dom.style.bottom = pixels(0);
284 // current orientation is up, set it to down
285 this.balloonContent.dom.style.top = pixels(this.arrowHeight - 1);
286 this.balloonContent.dom.style.bottom = '';
287 this.arrowDiv.dom.style.backgroundPosition = '0px -25px';
288 this.arrowDiv.dom.style.bottom = '';
289 this.arrowDiv.dom.style.top = pixels(0);
292 verifyYPos: function() {
293 var height = this.getBalloonHeight();
295 if ((this.y - height) < 5) {
296 this.switchOrientation();
300 if ((this.y - height) < $(window).scrollTop()) {
301 if (($(window).height() + $(window).scrollTop()) > (this.y + height)) {
302 this.switchOrientation();
307 verifyXPos: function() {
308 var balloonWidth = this.balloonContent.dom.offsetWidth;
310 // Try place the middle of the balloon on mouse pointer position
311 var leftPos = this.x - Math.floor(balloonWidth/2);
313 // Check if the balloon is outside left side of browser window
314 if (leftPos - $(window).scrollLeft() < 0) {
315 leftPos = $(window).scrollLeft() + 5; // 5 pixel margin
317 // Check if the arrow is outside the balloon, then move the balloon to
318 // a correct position based on the arrow
319 var arrowLeftMargin = this.x - Math.floor(this.arrowWidth/2) - this.cornerRadius;
320 if (arrowLeftMargin < leftPos) {
321 leftPos = arrowLeftMargin;
324 // Check if the balloon is outside the right side of browser windows
325 // Counts width 25px margin because of the scrollbar.
326 else if (leftPos + balloonWidth > $(window).scrollLeft() + $(window).width() - 25) {
328 leftPos = $(window).scrollLeft() + $(window).width() - balloonWidth - 25;
330 // Check if the arrow is outside the balloon, then move the balloon to
331 // a correct position based on the arrow
332 var arrowRightMargin = this.x + Math.floor(this.arrowWidth/2) + this.cornerRadius;
333 if (arrowRightMargin > leftPos + balloonWidth) {
334 leftPos = arrowRightMargin - balloonWidth;
338 this.canvas.dom.style.left = pixels(leftPos);
339 this.arrowDiv.dom.style.left = pixels(this.x - leftPos - Math.floor(this.arrowWidth/2));
341 getBalloonHeight: function() {
342 return this.balloonContent.dom.offsetHeight +
343 this.arrowDiv.dom.offsetHeight;
346 function(content, triggerElement, closeHandler, nonCloseElements, balloonClass, arrowClass) {
347 this.PopupDialog(content, triggerElement, closeHandler, nonCloseElements);
349 this.hasCloseButton = exists(closeHandler);
351 this.balloonClass = balloonClass || 'balloonPopup';
352 this.arrowClass = arrowClass || 'balloonPopupArrow';
355 this.arrowHeight = 19;
356 this.arrowWidth = 35;
357 this.cornerRadius = 6;
362 * Utility function to display a simple notification popup.
363 * @param {XElement} pointElement The element that triggers the event (onClick on it will be ignored)
364 * @param {XElement} content Anything you want to put inside.
366 type("NotificationBalloonPopup", ["BalloonPopup"],
369 function(pointElement, content) {
370 this.pointElement = pointElement;
372 var canvas = Html.div({style:
373 {padding: '5px'}}, content);
375 this.BalloonPopup(canvas,
379 'balloonPopup yellowBalloon',
380 'balloonPopupArrow yellowArrow');
385 * Utility function to display a simple alert popup.
386 * You can think of it as an "alert" replacement.
387 * It will have a title, a close button, and an OK button.
388 * @param {Html or String} title The title of the error popup.
389 * @param {Element} content Anything you want to put inside.
391 type("AlertPopup", ["ExclusivePopupWithButtons"],
394 var content = $('<div/>').css({
398 }).append($('<div/>').css('textAlign', 'left').html(this.content));
399 return this.ExclusivePopup.prototype.draw.call(this, content);
402 _getButtons: function() {
405 [$T('OK'), function() {
413 function(title, content, callback) {
414 this.content = content;
415 this.callback = callback || positive;
416 this.ExclusivePopup(title, this.callback);
421 * Utility function to display a simple alert popup.
422 * You can think of it as an "confirm" replacement.
423 * It will have a title, a close button, an OK button and a Cancel button.
424 * @param {Html or String} title The title of the error popup.
425 * @param {Element} content Anything you want to put inside.
426 * @param {function} handler A function that will be called with a boolean as argument:
427 * true if the user pressers "ok", or false if the user presses "cancel"
429 type("ConfirmPopup", ["ExclusivePopupWithButtons"],
432 return this.ExclusivePopup.prototype.draw.call(this, this.content);
434 _getButtons: function() {
437 [$T(this.buttonTitle), function() {
441 [$T(this.cancelButtonTitle), function() {
449 function(title, content, handler, buttonTitle, cancelButtonTitle) {
452 this.buttonTitle = buttonTitle || 'OK';
453 this.cancelButtonTitle = cancelButtonTitle || 'Cancel';
454 this.content = content;
455 this.handler = handler;
456 this.ExclusivePopupWithButtons(title, function() {
465 * Works exactly the same as the ConfirmPopup, but includes a parametermanager to perform checks when pressing OK
467 type("ConfirmPopupWithPM", ["ExclusivePopupWithButtons"],
470 return this.ExclusivePopup.prototype.draw.call(this, this.content);
472 _getButtons: function() {
475 [$T(this.buttonTitle), function() {
476 if(self.parameterManager.check()) {
480 [$T(this.cancelButtonTitle), function() {
488 function(title, content, handler) {
491 this.content = content;
492 this.handler = handler;
493 this.parameterManager = new IndicoUtil.parameterManager();
494 this.ExclusivePopupWithButtons(title, function(){
502 * Utility function to display a three buttons popup.
503 * The difference with ConfirmButton is the existence of a third button.
504 * Apart from the title and close button, the three buttons display, two of them configurables and Cancel
505 * @param {Html or String} title The title of the error popup.
506 * @param {Element} content Anything you want to put inside.
507 * @param {function} handler A function that will be called with an Integer as argument:
508 * 1 if the user press button1, 2 for button2, 0 for "Cancel"
510 type("SpecialRemovePopup", ["ExclusivePopupWithButtons"],
513 return this.ExclusivePopupWithButtons.prototype.draw.call(this, this.content);
516 _getButtons: function() {
519 [$T(this.buttonTitle1), function() {
523 [$T(this.buttonTitle2), function() {
527 [$T('Cancel'), function() {
535 function(title, content, handler, buttonTitle1, buttonTitle2) {
538 this.buttonTitle1 = buttonTitle1;
539 this.buttonTitle2 = buttonTitle2;
540 this.content = content;
541 this.handler = handler;
542 this.ExclusivePopupWithButtons(title, function(){
551 * Utility function to display a three buttons popup.
552 * The difference with ConfirmButton is the existence of a third button.
553 * Apart from the title and close button, the three buttons display Save, Don't Save and Cancel
554 * @param {Html or String} title The title of the error popup.
555 * @param {Element} content Anything you want to put inside.
556 * @param {function} handler A function that will be called with an Integer as argument:
557 * 1 if the user press "Save", 2 for "Don't Save", 0 for "Cancel"
559 type("SaveConfirmPopup", ["ExclusivePopupWithButtons"],
562 return this.ExclusivePopupWithButtons.prototype.draw.call(this, this.content);
565 _getButtons: function() {
568 [$T('Save'), function() {
572 [$T('Don\'t Save'), function() {
576 [$T('Cancel'), function() {
584 function(title, content, handler) {
587 this.content = content;
588 this.handler = handler;
589 this.ExclusivePopupWithButtons(title, function(){
597 type("WarningPopup", ["AlertPopup"],
599 _formatLine: function(line) {
600 var result = Html.div({paddingBottom: pixels(2)});
607 while (linkStart >= 0) {
608 linkStart = line.indexOf('[[', linkEnd);
610 if (linkStart >= 0) {
611 result.append(Html.span('',line.substring(linkEnd, linkStart)));
613 linkMiddle = line.indexOf(' ', linkStart);
614 linkEnd = line.indexOf(']]', linkStart);
616 result.append(Html.a({href: line.substring(linkStart+2, linkMiddle)}, line.substring(linkMiddle + 1, linkEnd) ));
619 result.append(Html.span('',line.substring(linkEnd, line.length)));
626 _formatContent: function(content, level) {
629 if (isString(content)) {
630 return Html.span('', self._formatLine(content));
632 } else if (isArray(content)) {
633 var result = Html.ul(level === 0 ? 'warningLevel0' : 'warningLevel1');
634 each (content, function(line){
635 if (isString(line)) {
636 result.append(Html.li({}, self._formatLine(line)));
637 } else if (isArray(line)) {
638 result.append(self._formatContent(line, level + 1));
640 result.append(Html.li({}, line));
647 function(title, lines) {
648 this.AlertPopup(title, this._formatContent(lines, 0).dom);
653 * Utility function to display a popup with errors.
654 * Useful for notifying the user of input mistakes or other errors.
655 * @param {Html or String} title The title of the error popup.
656 * @param {Array of String} errors An Array of strings with the errors to display.
657 * @param {Html or String} afterMessage A message to display after the list of errors.
659 type("ErrorPopup", ["ExclusivePopup"],
662 var errorList = null;
663 if (this.errors.length == 1) {
664 errorList = Html.div({className:"errorList"}, this.errors[0]);
666 errorList = Html.ul("errorList");
667 each(this.errors, function(e) {
668 errorList.append(Html.li('', e));
672 return this.ExclusivePopup.prototype.draw.call(this, Widget.block([errorList, this.afterMessage]).dom);
676 function(title, errors, afterMessage) {
677 this.afterMessage = afterMessage;
678 this.errors = errors;
679 this.ExclusivePopup(title, positive);