No help from experts ?) Am I out of scope ? Regards,
didier > Hi devs, > > I am developing a client side print control. Basically, the idea is to > clone the map's div into a new window. > > Everything works (FF, Chrome, Safari, Opera --almost there is still CSS > issues--) except for IE and for VML nodes ... > > Digging the web, I found that to get access to VML nodes' attributes (all > of them not only the casual attributes), it is required to remove the node > from the document. This has been done and all attributes for all shapes > are accessed. > > > Here is the code of the importNode() function, I am using : > > > if (!window.Node || !Node.ELEMENT_NODE) { > Node= { > ELEMENT_NODE: 1, > ATTRIBUTE_NODE: 2, > TEXT_NODE: 3, > CDATA_SECTION_NODE: 4, > ENTITY_REFERENCE_NODE: 5, > ENTITY_NODE: 6, > PROCESSING_INSTRUCTION_NODE: 7, > COMMENT_NODE: 8, > DOCUMENT_NODE: 9, > DOCUMENT_TYPE_NODE: 10, > DOCUMENT_FRAGMENT_NODE: 11, > NOTATION_NODE: 12 > }; > }; > > /** > * APIFunction: importNode > * Clone a node that belongs to a different document than the target > * document. Only ELEMENT_NODE, TEXT_NODE, CDATA_SECTION_NODE and > * COMMENT_NODE are supported. > * > * Parameters: > * doc - {DOMElement} the target document. > * externalNode - {DOMElement} the node to clone. > * deepCopy - {Boolean} indicator of cloning inner nodes and > attributes. > * > * Returns: > * {DOMElement} the cloned node or null if not possible. > */ > OpenLayers.Element.importNode= function(doc, externalNode, deepCopy) { > if (doc.importNode) { > // FF, Opera, Safari, Chrome : > return doc.importNode(externalNode, deepCopy); > } > // IE > var clonedNode= null, vmlNode= null, detached= false; > // FIXME: should be a constant of OpenLayers.Renderer.VML : > var shapes= ['shape','rect', 'oval', 'fill', 'stroke', > 'imagedata', 'group','textbox']; > switch (externalNode.nodeType) { > case Node.ELEMENT_NODE: > // FIXME: VML nodes are not properly copied ... > if (deepCopy && externalNode.tagName && > OpenLayers.Util.indexOf(shapes,externalNode.tagName)!=-1) { > //OpenLayers.Console.log('name=['+externalNode.tagName+'] > urn=['+externalNode.tagUrn+']:'); > > //OpenLayers.Console.log('=====('+externalNode.attributes.length+')('+(externalNode.childNodes > || []).length+')'); > // VML node: detach it from the source document to get > access all attributes : > if (externalNode.__detached!==true) {//not yet detached > //OpenLayers.Console.log('===== detaching'); > vmlNode= > externalNode.document.createElement('div');//dummy > node > vmlNode.id= 'dummy_'+externalNode.id; > > externalNode.parentNode.insertBefore(vmlNode,externalNode); > externalNode.parentNode.removeChild(externalNode); > externalNode.__detached= true; > } > detached= true; > > //OpenLayers.Console.log('=====('+externalNode.attributes.length+')('+(externalNode.childNodes > || []).length+')'); > } > > clonedNode= doc.createElement(externalNode.nodeName); > /* does the node have any attributes to add? */ > if (externalNode.attributes && > externalNode.attributes.length>0) { > for (var i= 0, il= externalNode.attributes.length; i<il; > i++) { > var att= externalNode.attributes[i]; > if (detached===true && att.nodeName==='__detached') { > continue; } > clonedNode.setAttribute(att.nodeName, > externalNode.getAttribute(att.nodeName)); > } > } > /* are we going after children too, and does the node have > any? */ > if (deepCopy && externalNode.childNodes && > externalNode.childNodes.length>0) { > for (var i= 0, il= externalNode.childNodes.length; i<il; > i++) { > var node= externalNode.childNodes[i]; > if (detached===true) { > node.__detached= true; > } > clonedNode.appendChild(OpenLayers.Element.importNode(doc, > node, deepCopy)); > if (detached===true) { > node.removeAttribute('__detached'); > } > } > } > > if (vmlNode) { > // insert node back ... > externalNode.removeAttribute('__detached'); > vmlNode.parentNode.insertBefore(externalNode,vmlNode); > vmlNode.parentNode.removeChild(vmlNode); > vmlNode= null; > } > break; > case Node.TEXT_NODE: > case Node.CDATA_SECTION_NODE: > clonedNode= doc.createTextNode(externalNode.nodeValue); > break; > case Node.COMMENT_NODE: > clonedNode= doc.createCommentNode(externalNode.nodeValue); > break; > default: > //OpenLayers.Console.log('unsupported > '+externalNode.nodeType+'=['+externalNode.innerHTML+']'); > break; > } > return clonedNode; > }; > > > On the popup window side, I set the document.namespaces as > OpenLayers.Renderer.VML does it. Here is the control (under construction) > that does the job : > > > /* > * Copyright (c) 2008-2010 Institut Geographique National France, released > under the > * BSD license. > */ > /* > * @requires OpenLayers/Control.js > */ > /** > * Class: OpenLayers.Control.PrintMap > * Implements a button control for printing the current map. > * > * Inherits from: > * - <OpenLayers.Control> > */ > OpenLayers.Control.PrintMap= OpenLayers.Class(OpenLayers.Control, { > > /** > * Property: type > * {String} The type of <OpenLayers.Control> -- When added to a > * <Control.Panel>, 'type' is used by the panel to determine how > to > * handle our events. > */ > type: OpenLayers.Control.TYPE_BUTTON, > > /** > * APIProperty: title > * {String} Print page's title (i18n used). > * Defaults to *'olControlPrintMap.title'* > */ > title: null, > > /** > * APIProperty: popupSettings > * {String} Attributes of the popup window that will contain the > printable > * page. > * Defaults to > *'toolbar=no,location=no,directories=no,menubar=no,scrollbars=no'* > */ > popupSettings: > "toolbar=no,location=no,directories=no,menubar=yes,scrollbars=no", > > /** > * APIProperty: cntrlsVisibility > * {Object} List of control's class name to hide during the printing > * preparation. > * Each object holds : > * * visible : current status of the control to hide; > * * toggleFunc : function to call for hidding the control. This > * function is assumed to have one boolean parameter; > * * scope : context for call 'toggleFunc', if none the map is > * used. > */ > cntrlsVisibility: null, > > /** > * APIProperty: onLoad > * {String} Javascript code to invoke when loading the popup window. > * Defaults to *"self.print();self.close();"* > */ > onLoad: "self.print();self.close();", > > /** > * Constructor: OpenLayers.Control.PrintMap > * Build a simple print preview button. > * > * Parameters: > * options - {Object} any options usefull for control. > */ > initialize: function(options) { > OpenLayers.Control.prototype.initialize.apply(this, arguments); > if (!this.title) { > this.title= this.displayClass+'.title'; > } > }, > > /** > * APIMethod: trigger > * Do the print by openning a popup that contains the map's div > content to > * be printed. > * Can be overwritten to modify the printing output. > */ > trigger: function() { > // open a new window by copying the inner content of the map's div > ... > // add attributions/originators for each layer on the window. > if (!this.map) { return; } > // hide controls : > for (var cn in this.cntrlsVisibility) { > var cntrl= this.map.getControlsByClass(cn)[0]; > if (cntrl && cntrl.div.style.display!='none') { > this.cntrlsVisibility[cn].visible= true; > > this.cntrlsVisibility[cn].toggleFunc.apply(this.cntrlsVisibility[cn].scope > || this.map,[false]) > } > } > var T= this.getPageContent(); > var printableDocument= null; > var settings= this.popupSettings; > if (!settings.match(/width/i)) { > settings+=",width="+(16+this.map.div.clientWidth); > } > if (!settings.match(/height/i)) { > settings+=",height="+(16+this.map.div.clientHeight); > } > printableDocument= window.open((T.isUrl? T.html:""),"",settings); > if (printableDocument) { > if (!T.isUrl) { > printableDocument.document.open(); > printableDocument.document.write(T.html); > if (!!document.namespaces) { > for (var i= 0, l= document.namespaces.length; i<l; > i++) { > var ns= document.namespaces.item(i); > printableDocument.document.namespaces.add(ns.name, > ns.urn); > } > } > // we return the imported clone of the map's div to > preserve rendered SVG/VML/... > var mapDiv= > OpenLayers.Element.importNode(printableDocument.document,this.map.div,true); > if (mapDiv) { > > printableDocument.document.getElementById('container_'+this.id).appendChild(mapDiv); > } > } > printableDocument.document.close(); > } > // show controls : > for (var cn in this.cntrlsVisibility) { > if (this.cntrlsVisibility[cn].visible===true) { > this.cntrlsVisibility[cn].visible= false; > > this.cntrlsVisibility[cn].toggleFunc.apply(this.cntrlsVisibility[cn].scope > || this.map,[true]) > } > } > }, > > /** > * Method: getStyles > * Retrieve CSS rules governing this map. > * > * Returns: > * {String} the CSS links et styles found in the current map. > */ > getStyles: function() { > var csses= ''; > for (var i= 0, li= document.styleSheets.length; i<li; i++) { > var css= document.styleSheets.item(i); > var ownerNode= css.owningElement || css.ownerNode; > if (css.href) { //LINK > csses+= > '<link '+ > 'rel="stylesheet" '+ > 'type="text/css" '+ > (ownerNode.id? 'id="'+ownerNode.id+'" ':'')+ > 'href="'+css.href+'"'+ > '/>\n'; > } else { //STYLE > csses+= > '<style type="text/css"'+(ownerNode.id? ' > id="'+ownerNode.id+'"':'')+'>\n'+ > '<!--\n'; > var rules= css.rules || css.cssRules; > for (var j= 0, lj= rules.length; j<lj; j++) { > var rule= rules.item(j); > csses+= > rule.selectorText+'{'+rule.style.cssText+'}\n'; > } > csses+= > ' -->\n'+ > '</style>\n'; > } > } > return csses; > }, > > /** > * APIMethod: getPageContent > * Build page content or URL to print. > * > * Returns: > * {Object} with an indicator of page content or URL ('isUrl' field), > * the HTML code or URL for the page to print ('html' field) and the > base URL > * of the popup window ('base' field). > */ > getPageContent: function() { > var base= document.location.pathname.split('?')[0]; > var parts= base.split('/'); > base= parts.pop(); > base= parts.join('/'); > var baseUrl= > document.location.protocol+'//'+ > document.location.hostname+ > (document.location.port? ':'+document.location.port : '')+ > base+'/'; > var page= > '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" > "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'+ > '<html xmlns="http://www.w3.org/1999/xhtml">\n'+ > '<head>\n'+ > '<title>'+OpenLayers.i18n(this.title)+'</title>\n'+ > '<meta http-equiv="Content-Type" content="text/html; > charset=UTF-8"/>\n'+ > '<base url="'+baseUrl+'"/>\n'+ > this.getStyles()+ > '<style type="text/css">\n'+ > '<!--\n'+ > '@media print {\n'+ > 'body{display:block!important;}\n'+ > '}\n'+ > ' -->\n'+ > '</style>\n'+ > '</head>\n'+ > '<body onload="'+this.onLoad+'">\n'+ > '<center>\n'+ > '<div id="container_'+this.id+'"></div>\n'+ > '</center>\n'+ > '</body>\n'+ > '</html>\n'; > return {'isUrl':false, 'html':page, 'base':baseUrl}; > }, > > /** > * Constant: CLASS_NAME > * {String} *"OpenLayers.Control.PrintMap"* > */ > CLASS_NAME: "OpenLayers.Control.PrintMap" > }); > > > Tests (based on panel.html and kml-layer.html) : > > <html xmlns="http://www.w3.org/1999/xhtml"> > <head> > <title>OpenLayers: Control Panel</title> > <link rel="stylesheet" href="../theme/default/style.css" > type="text/css" /> > <link rel="stylesheet" href="style.css" type="text/css" /> > <style type="text/css"> > .olControlPanel div { > display:block; > width: 24px; > height: 24px; > margin: 5px; > background-color:red; > } > > .olControlPanel .olControlMouseDefaultsItemActive { > background-color: blue; > background-image: url("../theme/default/img/pan_on.png"); > } > .olControlPanel .olControlMouseDefaultsItemInactive { > background-color: orange; > background-image: url("../theme/default/img/pan_off.png"); > } > .olControlPanel .olControlZoomBoxItemInactive { > width: 22px; > height: 22px; > background-color: orange; > background-image: url("../img/drag-rectangle-off.png"); > } > .olControlPanel .olControlZoomBoxItemActive { > width: 22px; > height: 22px; > background-color: blue; > background-image: url("../img/drag-rectangle-on.png"); > } > .olControlPanel .olControlZoomToMaxExtentItemInactive { > width: 18px; > height: 18px; > background-image: url("../img/zoom-world-mini.png"); > } > .olControlPanel .olControlPrintMapItemActive, > .olControlPanel .olControlPrintMapItemInactive { > width: 24px; > height: 22px; > background-image: url("../theme/default/img/draw_point_on.png"); > } > > </style> > <script src="../lib/Firebug/firebug.js"></script> > <script src="../lib/OpenLayers.js"></script> > > <script type="text/javascript"> > var lon = 5; > var lat = 40; > var zoom = 5; > var map, layer; > > function init(){ > map = new OpenLayers.Map( 'map', { controls: [] } ); > layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", > "http://labs.metacarta.com/wms/vmap0", {layers: > 'basic'} ); > map.addLayer(layer); > > map.addLayer(new OpenLayers.Layer.GML("KML", "kml/lines.kml", > { > format: OpenLayers.Format.KML, > formatOptions: { > extractStyles: true, > extractAttributes: true, > maxDepth: 2 > } > })); > > zb = new OpenLayers.Control.ZoomBox( > {title:"Zoom box: Selecting it you can zoom on an area by > clicking and dragging."}); > var panel = new OpenLayers.Control.Panel({defaultControl: > zb}); > panel.addControls([ > new OpenLayers.Control.MouseDefaults( > {title:'You can use the default mouse > configuration'}), > zb, > new OpenLayers.Control.PrintMap( > {title:"preview",onLoad:'javascript:void(0);'}) > ]); > map.addControl(panel); > > map.zoomToExtent(new > OpenLayers.Bounds(-112.306698,36.017792,-112.03204,36.18087)); > } > </script> > </head> > <body onload="init()"> > <h1 id="title">Custom Control.Panel</h1> > <p id="shortdesc"> > Create a custom control.panel, styled entirely with > CSS, and add your own controls to it. > </p> > <div id="panel"></div> > <div id="map" class="smallmap"></div> > > </body> > </html> > > > > In the end, all VML nodes are copied (with all of their attributes), but > they never show in the popup window !( > > Any advice/hint ? > Did I miss something in the process ? > > Regards, > > didier > -- > RICHARD Didier - Chef du pôle technique du Géoportail > 2/4, avenue Pasteur - 94165 Saint Mandé Cedex > Tél : +33 (0) 1 43 98 83 23 > _______________________________________________ > Dev mailing list > Dev@openlayers.org > http://openlayers.org/mailman/listinfo/dev > -- RICHARD Didier - Chef du pôle technique du Géoportail 2/4, avenue Pasteur - 94165 Saint Mandé Cedex Tél : +33 (0) 1 43 98 83 23 _______________________________________________ Dev mailing list Dev@openlayers.org http://openlayers.org/mailman/listinfo/dev