/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.gwt.widgets.client.utils; import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Frame; import java.util.HashMap; import java.util.Map; /** * Contains methods to show/hide iframes if they contain PDFs (<embeds>). This is primarily of interest to Firefox * browsers who's Acrobat Plug-in does not work well with overlapping HTML elements. */ public class FrameUtils { private static Map<Frame, FrameTimer> timers = new HashMap<Frame, FrameTimer>(); /** * Private method that does the actual hiding or showing of frames if an embed is in. * * @param frame * @param visible */ private static native void toggleEmbedVisibility( Element frame, boolean visible )/*-{ if(! window.globalStorage){ return; } try{ var doc = (frame.contentWindow.document || frame.contentDocument); if(doc == null) { return; } var embeds = doc.getElementsByTagName("embed"); if(embeds.length > 0){ var containsPdf = false; for(var i=0; i< embeds.length; i++){ if(embeds[i].type && embeds[i].type == "application/pdf"){ containsPdf = true; break; } } if(containsPdf){ if(visible){ if(frame.style.display == "none"){ //don't do anything unless you need to frame.style.display = "" ; //Show frame if (frame.style.height == "100%") { // force the frame to reload frame.style.height = "99%"; frame.style.height = "100%"; } } } else { frame.style.display = "none" ; //hide frame } } } var iframes = doc.getElementsByTagName("iframe"); if(iframes.length > 0){ // iframe has it's own iframes //recurse with child iframe for(var i=0; i<iframes.length; i++){ @org.pentaho.gwt.widgets.client.utils.FrameUtils::toggleEmbedVisibility(Lcom/google/gwt/dom/client/Element;Z)( iframes[i], visible); } } } catch(e) { // Cross-site scripting error in all likelihood } }-*/; /** * If the frame contains an <embed> schedule it for showing/hiding * * @param frame * @param visible */ public static void setEmbedVisibility( Frame frame, boolean visible ) { if ( timers.containsKey( frame ) ) { // Already Scheduled FrameTimer t = timers.get( frame ); if ( t.visible == visible ) { // dupe call, ignore return; } else { // timer exists but the visibility call has changed t.cancel(); t.visible = visible; t.schedule( 200 ); } } else { // Not currently in the operations queue FrameTimer t = new FrameTimer( frame, visible ); timers.put( frame, t ); t.schedule( 200 ); } } /** * Loops through all iframe object on the document. Used when reference to Frame is not available. * * @param visible */ public static void toggleEmbedVisibility( boolean visible ) { Element[] frames = new Element[0]; try { frames = ElementUtils.getElementsByTagName( "iframe" ); //$NON-NLS-1$ } catch ( ClassCastException cce ) { // ignore class cast exceptions in here, they are happening in hosted mode for Elements //ignore } for ( Element ele : frames ) { Frame f = null; // Attempt to find a previously GWT-wrapped frame instance in our timer collection Object[] tmap = timers.entrySet().toArray(); for ( int i = 0; i < tmap.length; i++ ) { @SuppressWarnings( "unchecked" ) Map.Entry<Frame, FrameTimer> t = (Map.Entry<Frame, FrameTimer>) tmap[i]; if ( t.getKey().getElement() == ele ) { // found an already wrapped instance f = t.getKey(); } } if ( f == null ) { f = Frame.wrap( ele ); } setEmbedVisibility( f, visible ); } } /** * This Timer adds a buffer to show/hide operations so other code has a chance of "canceling" it. */ private static class FrameTimer extends Timer { Frame frame; boolean visible; public FrameTimer( Frame frame, boolean visible ) { this.frame = frame; this.visible = visible; } public void run() { toggleEmbedVisibility( frame.getElement(), visible ); timers.remove( frame ); } } }