@qooxdoo/framework
Version:
The JS Framework for Coders
529 lines (439 loc) • 13 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Fabian Jakobs (fjakobs)
************************************************************************ */
/**
* Container widget for internal frames (iframes) with qooxdoo scroll bar and
* size hint support.
*
* An iframe can display any HTML page inside the widget. Note that custom
* scroll bars do only work if the iframe's source points to the same domain
* as the application.
*
* @childControl iframe {qx.ui.embed.Iframe} embedded iframe component
* @childControl scrollbar-x {qx.ui.core.scroll.ScrollBar} horizontal scrollbar
* @childControl scrollbar-y {qx.ui.core.scroll.ScrollBar} vertical scrollbar
* @childControl corner {qx.ui.core.Widget} corner widget where no scrollbar is shown
*
* *Example*
*
* Here is a little example of how to use the widget:
*
* <pre class='javascript'>
* var document = this.getRoot();
* var iframe = new qx.ui.embed.ThemedIframe("frame.html");
* document.add(iframe);
* </pre>
*
*
* *External Documentation*
*
* <a href='http://manual.qooxdoo.org/${qxversion}/pages/widget/themediframe.html' target='_blank'>
* Documentation of this widget in the qooxdoo manual.</a>
*/
qx.Class.define("qx.ui.embed.ThemedIframe",
{
extend : qx.ui.embed.AbstractIframe,
include : qx.ui.core.scroll.MRoll,
construct : function(source)
{
this.base(arguments, source);
// Create 'fixed' grid layout
var grid = new qx.ui.layout.Grid();
grid.setColumnFlex(0, 1);
grid.setRowFlex(0, 1);
this._setLayout(grid);
this._showChildControl("iframe");
},
properties :
{
// overridden
appearance :
{
refine : true,
init : "scrollarea"
},
/**
* The policy, when the horizontal scrollbar should be shown.
* <ul>
* <li><b>auto</b>: Show scrollbar on demand</li>
* <li><b>on</b>: Always show the scrollbar</li>
* <li><b>off</b>: Never show the scrollbar</li>
* </ul>
*/
scrollbarX :
{
check : ["auto", "on", "off"],
init : "auto",
themeable : true,
apply : "_updateScrollbars"
},
/**
* The policy, when the horizontal scrollbar should be shown.
* <ul>
* <li><b>auto</b>: Show scrollbar on demand</li>
* <li><b>on</b>: Always show the scrollbar</li>
* <li><b>off</b>: Never show the scrollbar</li>
* </ul>
*/
scrollbarY :
{
check : ["auto", "on", "off"],
init : "auto",
themeable : true,
apply : "_updateScrollbars"
},
/**
* Group property, to set the overflow of both scroll bars.
*/
scrollbar : {
group : [ "scrollbarX", "scrollbarY" ]
}
},
members :
{
__iframeSize : null,
__iframeObserverId : null,
// overridden
_getIframeElement : function() {
return this.getChildControl("iframe").getContentElement();
},
// overridden
_createChildControlImpl : function(id, hash)
{
var control;
switch(id)
{
case "iframe":
control = new qx.ui.embed.Iframe(this.getSource());
control.addListener("load", this._onIframeLoad, this);
control.addListener("resize", this._onIframeResize, this);
this._add(control, {row: 0, column: 0});
break;
case "scrollbar-x":
control = new qx.ui.core.scroll.ScrollBar("horizontal");
control.setMinWidth(0);
control.exclude();
control.addListener("scroll", this._onScrollBarX, this);
this._add(control, {row: 1, column: 0});
break;
case "scrollbar-y":
control = new qx.ui.core.scroll.ScrollBar("vertical");
control.setMinHeight(0);
control.exclude();
control.addListener("scroll", this._onScrollBarY, this);
this._add(control, {row: 0, column: 1});
break;
case "corner":
control = new qx.ui.core.Widget();
control.setWidth(0);
control.setHeight(0);
control.exclude();
this._add(control, {row: 1, column: 1});
break;
}
return control || this.base(arguments, id);
},
/*
---------------------------------------------------------------------------
EVENT LISTENERS
---------------------------------------------------------------------------
*/
/**
* Event handler for the iframe's load event
*/
_onIframeLoad : function()
{
this._disableScollbars();
var body = this._getIframeElement().getBody();
if (body) {
this._startIframeObserver();
this._addRollListener();
}
this.fireEvent("load");
},
/**
* Event handler for resize event of the iframe widget.
*/
_onIframeResize : function() {
this._updateScrollbars();
},
/**
* Hide all scrollbars and stop observing the iframe document
*/
_disableScollbars : function()
{
this._excludeChildControl("scrollbar-x");
this._excludeChildControl("scrollbar-y");
this._excludeChildControl("corner");
this._stopIframeObserver();
},
/**
* Attach roll listener to the iframe
*/
_addRollListener : function()
{
try
{
var body = this._getIframeElement().getBody();
qx.bom.Element.addListener(body, "roll", this._onRoll, this);
qx.bom.Element.addListener(body, "pointerdown", this._onPointerDownForRoll, this);
} catch (e) {
this._disableScollbars();
}
},
/**
* Start observing size changes of the iframe document
*/
_startIframeObserver : function()
{
if (this.__iframeObserverId) {
this._stopIframeObserver();
}
var idle = qx.event.Idle.getInstance();
this.__iframeObserverId = idle.addListener("interval", this._onIframeObserverInterval, this);
},
/**
* Stop observing size changes of the iframe document
*/
_stopIframeObserver : function()
{
this.__iframeSize = null;
if (!this.__iframeObserverId) {
return;
}
var idle = qx.event.Idle.getInstance();
idle.removeListenerById(this.__iframeObserverId);
},
/**
* Event handler, which is called periodically to update the scroll bars
*/
_onIframeObserverInterval : function()
{
var iframeSize = this._getIframeSize();
if (!iframeSize)
{
this._disableScollbars();
return;
}
if (
this.__iframeSize &&
iframeSize.width == this.__iframeSize.width &&
iframeSize.height == this.__iframeSize.height
) {
return;
}
this.__iframeSize = iframeSize;
this._preventIframeScrolling();
this._updateScrollbars();
},
/**
* Try to hide native scrollbars in the iframe
*/
_preventIframeScrolling : function()
{
try
{
var win = this._getIframeElement().getWindow();
var doc = this._getIframeElement().getDocument();
if (qx.bom.Document.isStandardMode(win)) {
doc.documentElement.style.overflow = "hidden";
} else {
doc.body.style.overflow = "hidden";
}
} catch (e) {
this._disableScollbars();
}
},
/**
* Recompute scrollbar visibility and positions based on the iframe's
* document size
*/
_updateScrollbars : function()
{
var iframeSize = this.__iframeSize;
var paneSize = this.getChildControl("iframe").getBounds();
var innerSize = this.getChildControl("iframe").getInnerSize();
if (!iframeSize || !innerSize || !innerSize) {
return;
}
var showX = false;
var showY = false;
var scrollbarX = this.getScrollbarX();
var scrollbarY = this.getScrollbarY();
if (scrollbarX === "auto" && scrollbarY === "auto")
{
// Check if the container is big enough to show
// the full content.
var showX = iframeSize.width > innerSize.width;
var showY = iframeSize.height > innerSize.height;
// Dependency check
// We need a special intelligence here when only one
// of the autosized axis requires a scrollbar
// This scrollbar may then influence the need
// for the other one as well.
if ((showX || showY) && !(showX && showY))
{
if (showX) {
showY = iframeSize.height > paneSize.height;
} else if (showY) {
showX = iframeSize.width > paneSize.width;
}
}
}
else
{
var showX = scrollbarX === "on";
var showY = scrollbarY === "on";
// Check auto values afterwards with already
// corrected client dimensions
if (iframeSize.width > (showX ? paneSize.width : innerSize.width) && scrollbarX === "auto") {
showX = true;
}
if (iframeSize.height > (showX ? paneSize.height : innerSize.height) && scrollbarY === "auto") {
showY = true;
}
}
this._configureScrollbar(
"scrollbar-x", showX,
innerSize.width, iframeSize.width
);
this._configureScrollbar(
"scrollbar-y", showY,
innerSize.height, iframeSize.height
);
this._updateCornerWidget();
},
/**
* Compute the size of the iframe body
*
* @return {Object|null} A map with the body size or <code>null</code>.
*/
_getIframeSize : function()
{
try
{
var win = this._getIframeElement().getWindow();
var frameSize = {
width: qx.bom.Document.getWidth(win),
height: qx.bom.Document.getHeight(win)
};
return frameSize;
}
catch (e)
{
return null;
}
},
/**
* Update visibility of the corner widget based on the visibility of the
* scrollbars
*/
_updateCornerWidget : function()
{
if (
this._isChildControlVisible("scrollbar-x") &&
this._isChildControlVisible("scrollbar-y")
) {
this._showChildControl("corner");
} else {
this._excludeChildControl("corner");
}
},
/**
* Configures the given scrollbar
*
* @param scrollbarId {String} child control id of the scrollbar to
* configure
* @param show {Boolean} whether the scrollbar should be visible
* @param containerSize {Integer} size of the container widget
* @param contentSize {Integer} size of the iframe's document
*/
_configureScrollbar : function(scrollbarId, show, containerSize, contentSize)
{
if (!show)
{
this._excludeChildControl(scrollbarId);
return;
}
var bar = this._showChildControl(scrollbarId);
if (containerSize >= contentSize)
{
bar.set({
position: 0,
maximum: contentSize,
knobFactor: 1,
enabled: false
});
}
else
{
bar.setMaximum(1000000);
bar.set({
position: Math.min(bar.getPosition(), contentSize),
maximum: contentSize - containerSize,
knobFactor: containerSize / contentSize,
enabled: true
});
}
},
/**
* Event handler for the scroll event of the horizontal scrollbar
*
* @param e {qx.event.type.Data} The scroll event object
*/
_onScrollBarX : function(e) {
this.scrollToX(e.getData());
},
/**
* Event handler for the scroll event of the vertical scrollbar
*
* @param e {qx.event.type.Data} The scroll event object
*/
_onScrollBarY : function(e) {
this.scrollToY(e.getData());
},
/**
* Scrolls the iframe's content to the given left coordinate
*
* @param x {Integer} The vertical position to scroll to.
*/
scrollToX : function(x)
{
try
{
var win = this._getIframeElement().getWindow();
win.scroll(x, qx.bom.Viewport.getScrollTop(win));
} catch (e) {
this._disableScollbars();
}
},
/**
* Scrolls the iframe's content to the given top coordinate
*
* @param y {Integer} The horizontal position to scroll to.
*/
scrollToY : function(y)
{
try
{
var win = this._getIframeElement().getWindow();
win.scroll(qx.bom.Viewport.getScrollLeft(win), y);
} catch (e) {
this._disableScollbars();
}
}
},
destruct : function()
{
this._stopIframeObserver();
this.__iframeSize = null;
}
});