From 585a8e3d61770dba9af907fd201443e2aec6ce37 Mon Sep 17 00:00:00 2001 From: secretr Date: Thu, 17 Dec 2009 17:15:20 +0000 Subject: [PATCH] JS Dialog widget done: currently supports almost everything what Prototype UI Window does (shadow, window manager, maximize/restore, blur/focus, iframe/ajax content etc). Just few details left, awaiting automated dialog creation by element selectors (JS API). --- e107_files/jslib/core/dialog.js | 488 ++++++++++++++++-- e107_files/jslib/core/dialog/e107/e107.css | 15 +- e107_files/jslib/core/shadow.js | 295 +++++++++++ .../core/shadow/e107_shadow/e107_shadow.css | 67 +++ .../jslib/core/shadow/e107_shadow/icons/e.png | Bin 0 -> 2875 bytes .../jslib/core/shadow/e107_shadow/icons/n.png | Bin 0 -> 2879 bytes .../core/shadow/e107_shadow/icons/ne.png | Bin 0 -> 3333 bytes .../core/shadow/e107_shadow/icons/nw.png | Bin 0 -> 3187 bytes .../jslib/core/shadow/e107_shadow/icons/s.png | Bin 0 -> 2880 bytes .../core/shadow/e107_shadow/icons/se.png | Bin 0 -> 3290 bytes .../core/shadow/e107_shadow/icons/sw.png | Bin 0 -> 3347 bytes .../jslib/core/shadow/e107_shadow/icons/w.png | Bin 0 -> 2878 bytes e107_files/jslib/e107.js.php | 39 +- 13 files changed, 853 insertions(+), 51 deletions(-) create mode 100644 e107_files/jslib/core/shadow.js create mode 100644 e107_files/jslib/core/shadow/e107_shadow/e107_shadow.css create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/e.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/n.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/ne.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/nw.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/s.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/se.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/sw.png create mode 100644 e107_files/jslib/core/shadow/e107_shadow/icons/w.png diff --git a/e107_files/jslib/core/dialog.js b/e107_files/jslib/core/dialog.js index f08bbba99..3b7eeaaa6 100644 --- a/e107_files/jslib/core/dialog.js +++ b/e107_files/jslib/core/dialog.js @@ -5,9 +5,10 @@ e107Base.setPrefs('core-dialog', { id: null, theme : '', + shadow: false, + shadowTheme: '', top: null, left: null, - zIndex: 2000, width: 300, height: 200, minWidth: 200, @@ -22,13 +23,15 @@ e107Base.setPrefs('core-dialog', { activeOnClick : true, show: Element.show, hide: Element.hide, + maximizeEffects: true, dialogManager: null, positionningStrategyOffset: null, - close: 'destroy' // e107Widgets.Dialog method for closing dialog + close: 'destroy', // e107Widgets.Dialog method for closing dialog or false to disable + maximize: 'toggleMaximize', // e107Widgets.Dialog method for closing dialog or false to disable }); -e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ +e107Widgets.Dialog = Class.create(e107WidgetAbstract, { Version : '1.0', style : "position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;", wiredElement: null, @@ -41,6 +44,7 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ focused: false, // windows on focus modal: false, // modal window zIndex: 0, + shadow: null, action: function(name) { var action = this.options[name]; @@ -50,14 +54,12 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ initialize : function(options) { this.events = new e107EventManager(this); - this.events.observe('create', this.createButtons)//bind create and createButtons - .observe('destroy', this.destroyButtons); //bind destroy and destroyButtons this.initMod('core-dialog', options); - // TODO - check e107Widgets.DialogManagerDefault presence, create if not found this.dialogManager = this.options.dialogManager || e107Widgets.DialogManagerDefault; - if(this.options.id && this.dialogManager.getWindow($(this.options.id))) return; + + this.setMethodChains(); this.create(); this.id = this.element.id; @@ -88,6 +90,25 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ getShadowTheme: function() { return this.options.shadowTheme || this.dialogManager.getShadowTheme(); }, + + setMethodChains: function() { + + this.events.observe('create', this.createButtons)//bind create and createButtons + .observe('destroy', this.destroyButtons); //bind destroy and destroyButtons + + + if(Object.isUndefined(e107Widgets.Shadow)) + this.options.shadow = false; + + if(this.options.shadow) { + this.events.observe('create', this.createShadow) + .observe('addElements', this.addElementsShadow) + .observe('setZIndex:pre', this.setZIndexShadow) + .observe('setPosition', this.setPositionShadow) + .observe('setSize', this.setSizeShadow) + .observe('setBounds', this.setBoundsShadow); + } + }, create : function() { function createDiv(className, options) { @@ -160,7 +181,7 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ return this.setBounds(this.options); }, - show : function(modal) { + show: function(modal) { if (this.visible) return this; @@ -247,8 +268,6 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ /* * Method: blur Blurs the window (without changing windows order) - * - * Returns: this */ blur: function() { if (!this.focused) @@ -268,6 +287,75 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ return this; }, + /* + * Method: maximize Maximizes window inside its viewport (managed by + * WindowManager) Makes window take full size of its viewport + */ + maximize: function() { + if (this.maximized) + return this; + + // Get bounds has to be before this.dialogManager.maximize for IE!! + // this.dialogManager.maximize remove overflow + // and it breaks this.getBounds() + var bounds = this.getBounds(); + if (this.dialogManager.maximize(this)) { + this.disableButton('minimize').setResizable(false).setDraggable(false); + + this.activate(); + this.maximized = true; + this.savedArea = bounds; + var newBounds = Object.extend(this.dialogManager.viewport.getDimensions(), { + top: 0, + left: 0 + }); + this[this.options.maximizeEffects && !e107API.Browser.IE ? "morph" : "setBounds"](newBounds); + + this.fire('maximized'); + return this; + } + }, + + /* + * Function: restore Restores a maximized window to its initial size + */ + restore: function() { + if (!this.maximized) + return this; + + if (this.dialogManager.restore(this)) { + this[this.options.maximizeEffects && !e107API.Browser.IE ? "morph" : "setBounds"](this.savedArea); + this.enableButton("minimize").setResizable(true).setDraggable(true); + + this.maximized = false; + + this.fire('restored'); + return this; + } + }, + + /* + * Function: toggleMaximize Maximizes/Restores window inside it's + * viewport (managed by DialogManager) + */ + toggleMaximize: function() { + return this.maximized ? this.restore() : this.maximize(); + }, + + /* + * Function: adapt Adapts window size to fit its content + * + * Returns: this + */ + adapt: function() { + var dimensions = this.content.getScrollDimensions(); + if (this.options.superflousEffects) + this.morph(dimensions, true); + else + this.setSize(dimensions.width, dimensions.height, true); + return this; + }, + /* * Method: destroy Destructor, closes window, cleans up DOM and memory */ @@ -277,8 +365,8 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ Event.stopObserving(this.dialogManager.scrollContainer, "scroll", this.centerOptions.handler); this.dialogManager.unregister(this); - this.fire('destroyed'); this.events.notify('destroy'); + this.fire('destroyed'); }, setHeader: function(header) { @@ -333,6 +421,7 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ elementStyle.top = pos.top + 'px'; elementStyle.left = pos.left + 'px'; + this.events.notify('setPosition', top, left); this.fire('position:changed'); return this; }, @@ -365,8 +454,8 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ } else return { - width: this.options.width, - height: this.options.height + width: this.options.width, + height: this.options.height }; }, @@ -385,6 +474,7 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ contentStyle.width = size.innerWidth + "px", contentStyle.height = size.innerHeight + "px"; this.overlay.style.height = size.innerHeight + "px"; + this.events.notify('setSize', width, height, innerSize); this.fire('size:changed'); return this; }, @@ -409,7 +499,50 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ * Returns: Hash {top:, left:, width:, height:} */ setBounds: function(bounds, innerSize) { - return this.setPosition(bounds.top, bounds.left).setSize(bounds.width, bounds.height, innerSize); + var ret = this.setPosition(bounds.top, bounds.left).setSize(bounds.width, bounds.height, innerSize); + this.events.notify('setBounds', bounds, innerSize); + return ret; + }, + + morph: function(bounds, innerSize) { + bounds = Object.extend(this.getBounds(innerSize), bounds || {}); + + if (this.centerOptions && this.centerOptions.auto) + bounds = Object.extend(bounds, this.computeRecenter(bounds)); + + if (innerSize) { + bounds.width += this.borderSize.width; + bounds.height += this.borderSize.height; + } + + if (this.options.wired) { + this.createWiredElement(); + if(this.shadow) this.shadow.hide(); + this.wiredElement.style.cssText = this.element.style.cssText; + this.element.hide(); + this.savedElement = this.element; + this.dialogManager.container.appendChild(this.wiredElement); + this.element = this.wiredElement; + } + + this.animating = true; + + new e107Widgets.Dialog.Effects.Morph(this, bounds, { + duration: 0.3, + afterFinish: function() { + this.animating = false; + if (this.options.wired) { + this.savedElement.style.cssText = this.wiredElement.style.cssText; + this.wiredElement.remove(); + this.element = this.savedElement; + if(this.shadow) this.shadow.show(); + this.savedElement = false; + } + }.bind(this) + }); + + Object.extend(this.options, bounds); + return this; }, /* @@ -432,21 +565,23 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ }, setDraggable : function(draggable) { + var element = this.savedElement || this.element; this.options.draggable = draggable; - this.element[(draggable ? 'add' : 'remove') + 'ClassName']('draggable'); + element[(draggable ? 'add' : 'remove') + 'ClassName']('draggable'); return this; }, setResizable: function(resizable) { this.options.resizable = resizable; - var toggleClassName = (resizable ? 'add' : 'remove') + 'ClassName'; + var toggleClassName = (resizable ? 'add' : 'remove') + 'ClassName', + element = this.savedElement || this.element; - this.element[toggleClassName]('resizable').select('div:[class*=_sizer]').invoke(resizable ? 'show' : 'hide'); + element[toggleClassName]('resizable').select('div:[class*=_sizer]').invoke(resizable ? 'show' : 'hide'); if (resizable) this.createResizeHandles(); - this.element.select('div.se').first()[toggleClassName]('se_resize_handle'); + element.select('div.se').first()[toggleClassName]('se_resize_handle'); return this; }, @@ -457,12 +592,13 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ }, observe: function(eventName, handler) { - this.element.observe('edialog:' + eventName, handler.bind(this)); + (this.savedElement || this.element).observe('edialog:' + eventName, handler.bind(this)); return this; }, addElements: function() { this.dialogManager.container.appendChild(this.element); + this.events.notify('addElements'); }, effect: function(name, element, options) { @@ -473,11 +609,13 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ // Set z-index to all window elements setZIndex: function(zIndex) { if (this.zIndex != zIndex) { + this.events.notify('setZIndex:pre', zIndex); this.zIndex = zIndex; [ this.element ].concat(this.element.childElements()).each(function(element) { element.style.zIndex = zIndex++; }); this.lastZIndex = zIndex; + this.events.notify('setZIndex', zIndex); } return this; }, @@ -575,6 +713,207 @@ e107Widgets.Dialog = Class.create(e107WidgetAbstract,{ } }); +e107Widgets.URLDialog = Class.create(e107Widgets.Dialog, { + + setAjaxContent: function() { + return this; + }, + + initialize: function($super, url, options) { + $super(options); + this.options.url = url || this.options.url; + this.createIFrame(); + }, + + destroy: function($super) { + this.iframe.src = null; + $super(); + }, + + getUrl: function() { + return this.iframe.src; + }, + + setUrl: function(url) { + this.iframe.src = url; + return this; + }, + + createIFrame: function($super) { + this.iframe = new Element('iframe', { + style: this.style, + frameborder: 0, + src: this.options.url, + name: this.element.id + "_frame", + id: this.element.id + "_frame" + }); + + this.content.insert(this.iframe); + } +}); + +e107Base.setPrefs('core-confirm-dialog', { + buttons: null, // default = ok/cancel button + beforeSelect: function() { + return true; + }, + close: false, + resizable: false, + activeOnClick: false +}); + +e107Widgets.ConfirmDialog = Class.create(e107Widgets.Dialog, { + + initialize: function($super, options) { + options = Object.extend(e107Base.getPrefs('core-confirm-dialog'), options || {}); + $super(options); + + }, + + disableDialogButton: function(index) { + var button = this.getDialogButton(index); + if (button) + button.addClassName("disabled"); + return this; + }, + + enableDialogButton: function(index) { + var button = this.getDialogButton(index); + if (button) + button.removeClassName("disabled"); + return this; + }, + + getDialogButton: function(index) { + var buttons = this.buttonContainer.childElements(); + if (index >= 0 && index < buttons.length) + return buttons[index]; + else + return null; + }, + + // Override create to add dialog buttons + create: function($super) { + $super(); + + // Create buttons + this.buttonContainer = this.createButtons(); + // Add a new content for dialog content + this.dialogContent = new Element('div', { + className: 'ui-dialog-confirm-content' + }); + + this.content.update(this.dialogContent); + this.content.insert(this.buttonContainer); + }, + + addElements: function($super) { + $super(); + // Pre compute buttons height + this.buttonsHeight = this.buttonContainer.getHeight() || this.buttonsHeight; + this.setDialogSize(); + }, + + setContent: function(content, withoutButton) { + this.dialogContent.update(content); + + // Remove button if need be + if (withoutButton && this.buttonContainer.parentNode) + this.buttonContainer.remove(); + else + this.content.insert(this.buttonContainer); + + // Update dialog size + this.setDialogSize(); + return this; + }, + + onSelect: function(e) { + var element = e.element(); + + if (element.callback && !element.hasClassName('disabled')) { + if (this.options.beforeSelect(element)) + element.callback(this); + } + }, + + createButtons: function(dialogButtons) { + var buttonContainer = new Element('div', { + className: 'ui-dialog-confirm-buttons' + }); + + (this.options.buttons || e107Widgets.ConfirmDialog.okCancelButtons).each(function(item) { + var button; + if (item.separator) + button = new Element('span', { + className: 'separator' + }); + else + button = new Element('button', { + title: item.title, + className: (item.className || '') + (item.disabled ? ' disabled' : '') + }).observe('click', this.onSelect.bind(this)).update(item.title); + + buttonContainer.insert(button); + button.callback = item.callback; + }.bind(this)); + return buttonContainer; + }, + + setDialogSize: function() { + // Do not compute dialog size if window is not completly ready + if (!this.borderSize) + return; + + this.buttonsHeight = this.buttonContainer.getHeight() || this.buttonsHeight; + var style = this.dialogContent.style, size = this.getSize(true); + style.width = size.width + "px", style.height = size.height - this.buttonsHeight + "px"; + }, + + setSize: function($super, width, height, innerSize) { + $super(width, height, innerSize); + this.setDialogSize(); + return this; + } +}); + +e107Widgets.ConfirmDialog = Object.extend(e107Widgets.ConfirmDialog, { + okButton : [{title: 'Ok', className: 'ok', callback: function(win) { win.destroy(); }}], + okCancelButtons : [{title: 'Ok', className: 'ok', callback: function(win) { win.destroy(); }}, + {title: 'Cancel', className: 'cancel', callback: function(win) { win.destroy(); }}] +}); + +if (!Object.isUndefined(window.Effect)) { + e107Widgets.Dialog.Effects = e107Widgets.Dialog.Effects || {}; + e107Widgets.Dialog.Effects.Morph = Class.create(Effect.Base, { + initialize: function(window, bounds) { + this.window = window; + var options = Object.extend( { + fromBounds: this.window.getBounds(), + toBounds: bounds, + from: 0, + to: 1 + }, arguments[2] || {}); + this.start(options); + }, + + update: function(position) { + var t = this.options.fromBounds.top + (this.options.toBounds.top - this.options.fromBounds.top) * position; + var l = this.options.fromBounds.left + (this.options.toBounds.left - this.options.fromBounds.left) * position; + + var ow = this.options.fromBounds.width + (this.options.toBounds.width - this.options.fromBounds.width) * position; + var oh = this.options.fromBounds.height + (this.options.toBounds.height - this.options.fromBounds.height) * position; + + this.window.setBounds( { + top: t, + left: l, + width: ow, + height: oh + }) + } + }); +} + e107Widgets.Dialog.addMethods( { startDrag: function(handle) { @@ -585,7 +924,8 @@ e107Widgets.Dialog.addMethods( { this.createWiredElement(); this.wiredElement.style.cssText = this.element.style.cssText; this.element.hide(); - this.saveElement = this.element; + if(this.shadow) this.shadow.hide(); + this.savedElement = this.element; this.dialogManager.container.appendChild(this.wiredElement); this.element = this.wiredElement; } @@ -597,10 +937,11 @@ e107Widgets.Dialog.addMethods( { this.element.hasClassName('resized') ? this.endResize() : this.endMove(); if (this.options.wired) { - this.saveElement.style.cssText = this.wiredElement.style.cssText; + this.savedElement.style.cssText = this.wiredElement.style.cssText; this.wiredElement.remove(); - this.element = this.saveElement; - this.saveElement = false; + this.element = this.savedElement; + if(this.shadow) this.shadow.show(); + this.savedElement = false; } }, @@ -674,6 +1015,7 @@ e107Widgets.Dialog.addMethods( { }); e107Widgets.Dialog.addMethods( { + createButtons: function() { this.buttons = new Element("div", { className: "buttons" @@ -690,10 +1032,11 @@ e107Widgets.Dialog.addMethods( { }, destroyButtons: function() { - this.buttons.stopObserving(); + if(this.buttons) + this.buttons.stopObserving(); }, - defaultButtons: $w('close'), + defaultButtons: $w('maximize close'), getButtonElement: function(buttonName) { return this.buttons.down("." + buttonName); @@ -717,17 +1060,20 @@ e107Widgets.Dialog.addMethods( { }, removeButton: function(buttonName) { - this.getButtonElement(buttonName).remove(); + var b = this.getButtonElement(buttonName); + if(b) b.remove(); return this; }, disableButton: function(buttonName) { - this.getButtonElement(buttonName).addClassName("disabled"); + var b = this.getButtonElement(buttonName); + if(b) b.addClassName("disabled"); return this; }, enableButton: function(buttonName) { - this.getButtonElement(buttonName).removeClassName("disabled"); + var b = this.getButtonElement(buttonName); + if(b) b.removeClassName("disabled"); return this; }, @@ -748,6 +1094,7 @@ e107Widgets.Dialog.addMethods( { }, updateButtonsOrder: function() { + if(!this.buttons) return; var buttons = this.buttons.childElements(); buttons.inject(new Array(buttons.length), function(array, button) { @@ -759,12 +1106,95 @@ e107Widgets.Dialog.addMethods( { } }); +e107Widgets.Dialog.addMethods( { + + showShadow: function() { + if (this.shadow) { + this.shadow.hide(); + this.effect('show', this.shadow.shadow); + } + }, + + hideShadow: function() { + if (this.shadow) + this.effect('hide', this.shadow.shadow); + }, + + removeShadow: function() { + if (this.shadow) + this.shadow.remove(); + }, + + focusShadow: function() { + if (this.shadow) + this.shadow.focus(); + }, + + blurShadow: function() { + if (this.shadow) + this.shadow.blur(); + }, + + // Private Functions + createShadow: function() { + if (!this.options.shadow || Object.isUndefined(e107Widgets.Shadow)) return; + + this.observe('showing', this.showShadow) + .observe('hiding', this.hideShadow) + .observe('hidden', this.removeShadow) + .observe('focused', this.focusShadow) + .observe('blurred', this.blurShadow); + + this.shadow = new e107Widgets.Shadow(this.element, { + theme: this.getShadowTheme() + }); + }, + + addElementsShadow: function() { + if (this.shadow) { + this.shadow.setBounds(this.options).render(); + } + }, + + setZIndexShadow: function(zIndex) { + if (this.zIndex != zIndex) { + if (this.shadow) + this.shadow.setZIndex(zIndex - 1); + + this.zIndex = zIndex; + } + return this; + }, + + setPositionShadow: function(top, left) { + if (this.shadow) { + var pos = this.getPosition(); + this.shadow.setPosition(pos.top, pos.left); + } + return this; + }, + + setSizeShadow: function(width, height, innerSize) { + if (this.shadow) { + var size = this.getSize(); + this.shadow.setSize(size.width, size.height); + } + return this; + }, + + setBoundsShadow: function(bounds, innerSize) { + if (this.shadow) + this.shadow.setBounds(this.getBounds()); + } +}); + + e107Base.setPrefs('core-dialogmanager', { className : 'e-dialog', container: null, // will default to document.body zIndex: 2000, theme: "e107", - shadowTheme: "e107", + shadowTheme: "e107_shadow", showOverlay: Element.show, hideOverlay: Element.hide, positionningStrategyOffset: null, diff --git a/e107_files/jslib/core/dialog/e107/e107.css b/e107_files/jslib/core/dialog/e107/e107.css index 44d1700e7..d8293cbe1 100644 --- a/e107_files/jslib/core/dialog/e107/e107.css +++ b/e107_files/jslib/core/dialog/e107/e107.css @@ -24,9 +24,9 @@ height:22px; margin:0; padding:0; - text-align:center; + text-align: left; overflow: hidden; - padding-left:60px; + padding-right: 60px; line-height: 20px; color: #000; } @@ -112,7 +112,7 @@ } .e107 .buttons a.close { - float:left; + float: right; background:transparent url(icons/button_unactive.gif) no-repeat 0 0; background-repeat: no-repeat; height:15px; @@ -132,7 +132,7 @@ } .e107 .buttons a.maximize { - float:left; + float: right; background:transparent url(icons/button_unactive.gif) no-repeat 0 0; height:15px; width:14px; @@ -149,13 +149,15 @@ background:transparent url(icons/buttons_over.gif) no-repeat 0 -30px !important; } +/* padding-top = buttons order, it will be reset to 0, do not use padding, use margin*/ +/* not implemented .e107 .buttons a.minimize { - float:left; + float: right; background:transparent url(icons/button_unactive.gif) no-repeat 0 0; height:15px; width:14px; margin: 3px 7px 0 0; - padding-top:1px; /* padding-top = buttons order, it will be reset to 0, do not use padding, use margin*/ + padding-top:1px; overflow:hidden; } @@ -170,6 +172,7 @@ .e107 .buttons a.minimize.disabled, .e107 .buttons.over a.minimize.disabled { background:transparent url(icons/button_unactive.gif) no-repeat 0 0 !important; } +*/ .e107_overlay { position:absolute; diff --git a/e107_files/jslib/core/shadow.js b/e107_files/jslib/core/shadow.js new file mode 100644 index 000000000..ea9984090 --- /dev/null +++ b/e107_files/jslib/core/shadow.js @@ -0,0 +1,295 @@ + +/** + * Global prefs + */ +e107Base.setPrefs('core-shadow', { + theme: "e107_shadow", + focus: false, + zIndex: 100 +}); + +/* + * Class: e107Widgets.Shadow Add shadow around a DOM element. The element MUST BE in + * ABSOLUTE position. + * + * Shadow can be skinned by CSS (see e107_shadow.css). CSS + * must be included to see shadow. + * + * A shadow can have two states: focused and blur. Shadow shifts are set in CSS + * file as margin and padding of shadow_container to add visual information. + * + * Example: new e107Widgets.Shadow("element_id"); + */ +e107Widgets.Shadow = Class.create(e107WidgetAbstract, { + /* + * Method: initialize Constructor, adds shadow elements to the DOM if + * element is in the DOM. Element MUST BE in ABSOLUTE position. + * Parameters: element - DOM element options - Hashmap of options - + * theme (default: mac_shadow) - focus (default: true) - zIndex + * (default: 100) + */ + initialize: function(element, options) { + this.initMod('core-shadow', options); + + this.element = $(element); + this.create(); + this.iframe = e107API.Browser.IE && e107API.Browser.IE < 7 ? new e107Utils.IframeShim() : null; + + this.render(); + }, + + /* + * Method: destroy Destructor, removes elements from the DOM + */ + destroy: function() { + if (this.shadow.parentNode) + this.remove(); + }, + + // Group: Size and Position + /* + * Method: setPosition Sets top/left shadow position in pixels + * Parameters: top - top position in pixel left - left position in pixel + */ + setPosition: function(top, left) { + if (this.shadowSize) { + var shadowStyle = this.shadow.style; + top = parseInt(top) - this.shadowSize.top + this.shadowShift.top; + left = parseInt(left) - this.shadowSize.left + this.shadowShift.left; + shadowStyle.top = top + 'px'; + shadowStyle.left = left + 'px'; + if (this.iframe) + this.iframe.setPosition(top, left); + } + return this; + }, + + /* + * Method: setSize Sets width/height shadow in pixels + * Parameters: width - width in pixel height - height in pixel + */ + setSize: function(width, height) { + if (this.shadowSize) { + try { + var w = Math.max(0, parseInt(width) + this.shadowSize.width - this.shadowShift.width) + "px"; + this.shadow.style.width = w; + var h = Math.max(0, parseInt(height) - this.shadowShift.height) + "px"; + + // this.shadowContents[1].style.height = h; + this.shadowContents[1].childElements().each(function(e) { + e.style.height = h + }); + this.shadowContents.each(function(item) { + item.style.width = w + }); + if (this.iframe) + this.iframe.setSize(width + this.shadowSize.width - this.shadowShift.width, height + this.shadowSize.height - this.shadowShift.height); + + } catch (e) { + // IE could throw an exception if called to early + } + } + return this; + }, + + /* + * Method: setBounds Sets shadow bounds in pixels + * Parameters: bounds - an Hash {top:, left:, width:, height:} + */ + setBounds: function(bounds) { + return this.setPosition(bounds.top, bounds.left).setSize(bounds.width, bounds.height); + }, + + /* + * Method: setZIndex Sets shadow z-index + * Parameters: zIndex - zIndex value + */ + setZIndex: function(zIndex) { + this.shadow.style.zIndex = zIndex; + return this; + }, + + // Group: Render + /* + * Method: show Displays shadow + */ + show: function() { + this.render(); + this.shadow.show(); + if (this.iframe) + this.iframe.show(); + return this; + }, + + /* + * Method: hide Hides shadow + */ + hide: function() { + this.shadow.hide(); + if (this.iframe) + this.iframe.hide(); + return this; + }, + + /* + * Method: remove Removes shadow from the DOM + */ + remove: function() { + this.shadow.remove(); + return this; + }, + + // Group: Status + /* + * Method: focus Focus shadow. + * Change shadow shift. Shift values are set in CSS file as margin and + * padding of shadow_container to add visual information of shadow + * status. + */ + focus: function() { + this.options.focus = true; + this.updateShadow(); + return this; + }, + + /* + * Method: blur Blurs shadow. + * Change shadow shift. Shift values are set in CSS file as margin and + * padding of shadow_container to add visual information of shadow + * status. + */ + blur: function() { + this.options.focus = false; + this.updateShadow(); + return this; + }, + + // Private Functions + // Adds shadow elements to DOM, computes shadow size and displays it + render: function() { + if (this.element.parentNode && !Object.isElement(this.shadow.parentNode)) { + this.element.parentNode.appendChild(this.shadow); + this.computeSize(); + this.setBounds(Object.extend(this.element.getDimensions(), this.getElementPosition())); + this.shadow.show(); + } + return this; + }, + + // Creates HTML elements without inserting them into the DOM + create: function() { + var zIndex = this.element.getStyle('zIndex'); + zIndex = (zIndex || this.options.zIndex) - 1; + this.element.setStyle( { + zIndex: zIndex + }); + + this.shadowContents = new Array(3); + this.shadowContents[0] = new Element("div").insert(new Element("div", { + className: "shadow_center_wrapper" + }).insert(new Element("div", { + className: "n_shadow" + }))).insert(new Element("div", { + className: "shadow_right ne_shadow" + })).insert(new Element("div", { + className: "shadow_left nw_shadow" + })); + + this.shadowContents[1] = new Element("div").insert(new Element("div", { + className: "shadow_center_wrapper c_shadow" + })).insert(new Element("div", { + className: "shadow_right e_shadow" + })).insert(new Element("div", { + className: "shadow_left w_shadow" + })); + this.centerElements = this.shadowContents[1].childElements(); + + this.shadowContents[2] = new Element("div").insert(new Element("div", { + className: "shadow_center_wrapper" + }).insert(new Element("div", { + className: "s_shadow" + }))).insert(new Element("div", { + className: "shadow_right se_shadow" + })).insert(new Element("div", { + className: "shadow_left sw_shadow" + })); + + this.shadow = new Element("div", { + className: "shadow_container " + this.options.theme, + style: "position:absolute; top:-10000px; left:-10000px; display:none; z-index:" + zIndex + }).insert(this.shadowContents[0]).insert(this.shadowContents[1]).insert(this.shadowContents[2]); + }, + + // Compute shadow size + computeSize: function() { + if (this.focusedShadowShift) + return; + this.shadow.show(); + + // Trick to get shadow shift designed in CSS as padding + var content = this.shadowContents[1].select("div.c_shadow").first(); + this.unfocusedShadowShift = {}; + this.focusedShadowShift = {}; + + $w("top left bottom right").each(function(pos) { + this.unfocusedShadowShift[pos] = content.getNumStyle("padding-" + pos) || 0 + }.bind(this)); + this.unfocusedShadowShift.width = this.unfocusedShadowShift.left + this.unfocusedShadowShift.right; + this.unfocusedShadowShift.height = this.unfocusedShadowShift.top + this.unfocusedShadowShift.bottom; + + $w("top left bottom right").each(function(pos) { + this.focusedShadowShift[pos] = content.getNumStyle("margin-" + pos) || 0 + }.bind(this)); + this.focusedShadowShift.width = this.focusedShadowShift.left + this.focusedShadowShift.right; + this.focusedShadowShift.height = this.focusedShadowShift.top + this.focusedShadowShift.bottom; + + this.shadowShift = this.options.focus ? this.focusedShadowShift : this.unfocusedShadowShift; + + // Get shadow size + this.shadowSize = { + top: this.shadowContents[0].childElements()[1].getNumStyle("height"), + left: this.shadowContents[0].childElements()[1].getNumStyle("width"), + bottom: this.shadowContents[2].childElements()[1].getNumStyle("height"), + right: this.shadowContents[0].childElements()[2].getNumStyle("width") + }; + + this.shadowSize.width = this.shadowSize.left + this.shadowSize.right; + this.shadowSize.height = this.shadowSize.top + this.shadowSize.bottom; + + // Remove padding + content.setStyle("padding:0; margin:0"); + this.shadow.hide(); + }, + + // Update shadow size (called when it changes from focused to blur and + // vice-versa) + updateShadow: function() { + this.shadowShift = this.options.focus ? this.focusedShadowShift : this.unfocusedShadowShift; + var shadowStyle = this.shadow.style, + pos = this.getElementPosition(), + size = this.element.getDimensions(); + + shadowStyle.top = pos.top - this.shadowSize.top + this.shadowShift.top + 'px'; + shadowStyle.left = pos.left - this.shadowSize.left + this.shadowShift.left + 'px'; + shadowStyle.width = size.width + this.shadowSize.width - this.shadowShift.width + "px"; + + var h = parseInt(size.height - this.shadowShift.height) + "px"; + this.centerElements.each(function(e) { + e.style.height = h + }); + + var w = parseInt(size.width + this.shadowSize.width - this.shadowShift.width) + "px"; + this.shadowContents.each(function(item) { + item.style.width = w + }); + }, + + // Get element position in integer values + getElementPosition: function() { + return { + top: this.element.getNumStyle("top"), + left: this.element.getNumStyle("left") + } + } +}); + \ No newline at end of file diff --git a/e107_files/jslib/core/shadow/e107_shadow/e107_shadow.css b/e107_files/jslib/core/shadow/e107_shadow/e107_shadow.css new file mode 100644 index 000000000..6d843bdcc --- /dev/null +++ b/e107_files/jslib/core/shadow/e107_shadow/e107_shadow.css @@ -0,0 +1,67 @@ +.shadow_container.e107_shadow .shadow_center_wrapper { + float:left; + width:100%; +} + +.shadow_container.e107_shadow .shadow_right { + float:left; + width:30px; + margin-left:-30px +} + +.shadow_container.e107_shadow .shadow_left { + float:left; + margin-left:-100%; + width:30px; +} + +.shadow_container.e107_shadow .se_shadow { + background:url(icons/se.png); + height:30px; +} + +.shadow_container.e107_shadow .s_shadow { + background:url(icons/s.png); + height:30px; + margin: 0 30px; +} + +.shadow_container.e107_shadow .sw_shadow { + background:url(icons/sw.png); + height:30px; +} + +.shadow_container.e107_shadow .ne_shadow { + background:url(icons/ne.png); + height:30px; +} + +.shadow_container.e107_shadow .n_shadow { + background:url(icons/n.png); + height:30px; + margin: 0 30px; +} + +.shadow_container.e107_shadow .nw_shadow { + background:url(icons/nw.png); + height:30px; +} + +.shadow_container.e107_shadow .e_shadow { + background:url(icons/e.png) repeat-y; +} + +.shadow_container.e107_shadow .w_shadow { + background:url(icons/w.png) repeat-y; +} + +.shadow_container.e107_shadow .c_shadow { + /* Padding is used to set shift values for unfocused window */ + padding:20px 17px 17px 17px; + /* Maring is used to set shift values for focused window */ + margin:17px 12px 12px 12px; +} + +.shadow_container.e107_shadow { + font-size: 2px; +} diff --git a/e107_files/jslib/core/shadow/e107_shadow/icons/e.png b/e107_files/jslib/core/shadow/e107_shadow/icons/e.png new file mode 100644 index 0000000000000000000000000000000000000000..573090e1d7b3d5f463634cba4d00459129ce24d6 GIT binary patch literal 2875 zcmV-B3&iw^P)0tDdAZ9o73ZrB8d;W+$% zP#4PN3IHSw0H%w?*+KxM5CAfA6*2_?G713fq;#1A03`qbTOJ!14}fX`06S%pPXhpU z(j@l+0JbPoDgr>G06-?n6o~-P4ggq}qZEq(uwVcv%8`h30kE3@V3MKClmKAw0Dzq- z7Gwhu7yw|R5DQZQ2=)NLkVi%E00=VyD2$Y^c+yu~A!AINCaVwW$9Z z{ELWe@Q#JLh_3eL-tiX;k2mK2vr|C5P-v+NI; zylVhp)qV!{LR(O~$_DJ0E+DYzfFK@c*+L|BM6Vt|+; z)`%m*MP?y>NH7wC#36}D3L-_6$WmlAQi7BtRmfhX9{C z7|KA|s2*yD+M!(38x2CE(D`Tzx(Llj3(*Z|C0c_XLYvXE=oR!9+KWC%$1uR?7zZ=N zY%ngy!$PrmEE$ty%dujt0;|Cqu{Nv|yMgs$BiMTaiNGS@1RH`oA&@YaAS5gzEGLu_ zst5-N&4doZ4MHDbl<=9zBT%>LK-$#>ix{Hrbl&K@KGg$O>{1c{}+K`84@Dd4T+mLZ=u| z94Y>kc#4!#K&hY{q@1E$rwmfYscKYHsv9+wDxxl?mQib|ZPcsO0qQtSon}t+pheNr zXsc+Iv_{%_+C$naI-PDrccq8ZCG?f_O8Q~?MS36oJwt zCX;E#^kT*{70eCHdgeLiW9B;*mWr(kUqz&{LZw=zS>?LQ3stJBsj9c?0@Zxg3e}^k zS5-&UsA^_vJT-yZah$}`!vpJ z^s_LQF^k6%vR1QdS?5^;Y!cg?&1a{vOW5DByV;|f8k#dSqc!t1t2Iw*_HrV>*%V3s)#9)iTX@h6DChm=A;FWj>K5D3I7-*<8+-ulvIBsNaG}oxW zsLAM&G0m83oNT02{%vlz3rW-Vqz=33@_ z^L+CL^M@8p3r~wh7Bv<(ElHMK%XG_~me;IMD<`W|t7@yO)~L0!wZwX-b`d(9?KatU+I_Znvd^%uwSVBC;V|2wz@g3I zH%BW+p<}h<&FReP{?k`XZ=L>fhV=~bj9oMCI5S6S0C3Et|wgIyE(fl+>W^Y>Tctn?tajHXr}p0@yyzp{T@ah0*}2O zy|eIHiL>_1>h(1A6nNHnKJha45_#2m4SHL8r+FXpe&J*9BlkJx^OonvTgE%%i}?ol z7W;PlY52|ctMYs7Z{(li-{3zQ;1sYV;7lMfFeq?S;2pjmU&ycLkIr_Py=-?QME! z`u_BZjF^n3OiE^A=5eWpG+o+}rJt3T)g!Z(70G%Rxh>kdXjC2~uggZV=V!Mn*b14V zOKG88qwLF>l~bMbE;l;&Xr6kWG_Py1)#CMw2lM^&zg z?sbH9l6Bqdr?20>{&TUY_;QJTNkz%WQeo-kZydg<{AOZ9@`mm*=dxWJNgJgbZ*TJ4 zbf8?lJiokubI9iAE%=t=Ew8sO++@f7m10b9ZmR-sT#!nu>j-eL4G{)<)NMe#`x~zD}pE zr0&yx>HgjW5eGWzUFz!(>K-g>KpT_|!-o^R0cR@{s zWv6JT3QtX(&ObeNMs{Z8Y|7dG_J!>a&c&X)*%98+eLm>?#S8uy&UJcsp1$aD@x&#! zOUEyBFSlHAzS7*~)OGA9r=N~>J9jrbX7l_T4)PcY5!N?hf6{xcBmY&i(NRD<2Xc7C%yZRPk8%am~+`KR5L{_nz$Y?dy6H z`Q$;ru>bi#vj6dMpzta4X~m$yVEvHe(1~IH;cL(4JsWr~dp44_~BQt zU%N(QM+aWYUrzj1`bzuN{?{{Jw~vL5J${q(_`g8%^e{{R4h=>PzAFaQAR zU;qF*m;eA5Z<1fdMgRZ+24YJ`MF0Q)|Ns99Sohoj000SZMn-c000E5v004Rb3!^Il z00009a7bBm000XU000XU0RWnu7ytkO33hNnX8-^J^Z)<>^Z-n>qdWir06a-VK~xCW zwa7UR03ZwlLHu3*&k+(Zg{w%kxEXmtl4SWd003&$Yfbi^9YfBUHOsCg-QVslBjh=` ZlNWMICNa@7C; literal 0 HcmV?d00001 diff --git a/e107_files/jslib/core/shadow/e107_shadow/icons/n.png b/e107_files/jslib/core/shadow/e107_shadow/icons/n.png new file mode 100644 index 0000000000000000000000000000000000000000..3b9623f621c5e2e81cdec45f06097b0657216ef6 GIT binary patch literal 2879 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 P00000NkvXXu0mjfl)+X< literal 0 HcmV?d00001 diff --git a/e107_files/jslib/core/shadow/e107_shadow/icons/nw.png b/e107_files/jslib/core/shadow/e107_shadow/icons/nw.png new file mode 100644 index 0000000000000000000000000000000000000000..5fe15a5fc1e6c19a24758492baba82ad03e13a0c GIT binary patch literal 3187 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 Y1vw8OJ&B%vq5uE@07*qoM6N<$g2eJpXaE2J literal 0 HcmV?d00001 diff --git a/e107_files/jslib/core/shadow/e107_shadow/icons/sw.png b/e107_files/jslib/core/shadow/e107_shadow/icons/sw.png new file mode 100644 index 0000000000000000000000000000000000000000..336a9155583f7b7fe65bf13afe0cab4615bd4a2d GIT binary patch literal 3347 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 c{;h>iZ6jF?{0`RkHUIzs07*qoM6N<$f