/** * @file GoogleMaps plugin for CKEditor * Version 3.6.0 * Allows to insert and edit GoogleMaps inside CKEditor with markers, polygons,... * * Copyright (C) 2012-16 Alfonso Martínez de Lizarrondo * */ /* global CKEDITOR */ (function() { 'use strict'; // Object that handles the common functions about all the maps function GoogleMapsHandler(editor) { this.editor = editor; // Clean up editor.on( 'destroy', function() { this.maps = {}; this.editor = null;}); // Object to store a reference to each map this.maps = {}; // We will use this to track the number of maps that are generated // This way we know if we must add the Google Script or not. // We store their names so they are called properly from BuildEndingScript this.CreatedMapsNames = []; return this; } GoogleMapsHandler.prototype = { majorVersion : 3, minorVersion : 6, isStaticImage: function( node ) { return node.getAttribute( 'mapnumber' ) || (/^(https?\:)?\/\/maps\.google(apis)?\.com\/(maps\/api\/)?staticmap/).test( node.src ); }, getMap: function( id ) { return this.maps[id]; }, // Verify that the node is a script generated by this plugin. detectMapScript: function( script ) { if ( !/CK googlemaps v(\d)\.(\d+)/.test(script) ) return false; var version = parseInt(RegExp.$1, 10), revision = parseInt(RegExp.$2, 10); if ( version > this.majorVersion || (version == this.majorVersion && revision > this.minorVersion) ) return false; return true; }, // Detects both the google script as well as our ending block // both must be removed and then added later only if necessary detectGoogleScript: function( script ) { // Our final script if (/CK googlemapsEnd v(\d)\.(\d+)/.test(script) ) { var version = parseInt(RegExp.$1, 10), revision = parseInt(RegExp.$2, 10); if ( version > this.majorVersion || (version == this.majorVersion && revision > this.minorVersion) ) return false; if (version == 2) { if ( !/script.src\s*=\s*"http:\/\/www\.google\.com\/.*key=(.*?)("|&)/.test(script) ) return false; } return true; } // Check if it is the Google Maps script (but we don't need the key) if ( !(/^'); return aScript.join(''); }, // Function that will test if the divs and images are correctly wrapped // returns true if it was OK, false if it has modified the DOM validateDOM: function() { // if no maps have been used, then exit var tmpMap, aMaps = [], i, j, imgs, mapId, map, div, img, element, modified = false, maps = this.maps; for (tmpMap in maps) aMaps.push( tmpMap ); if (aMaps.length === 0) return true; var theDoc = this.editor.document.$; // the user might have moved an img outside its container div. for (i = 0; i < aMaps.length; i++) { mapId = aMaps[i]; map = maps[mapId]; img = theDoc.getElementById( mapId ); if ( img ) { if (img.parentNode.nodeName != 'DIV' || img.parentNode.id != 'd' + map.number) { modified = true; map.createDivs( img ); } map.updateDimensions( img ); } else { div = theDoc.getElementById( 'd' + mapId ); if (div) { element = new CKEDITOR.dom.element( div ); element.remove( true ); modified = true; } delete maps[ mapId ]; } } // Try to check if the container divs have been duplicated (for example by drag&drop) if ( document.querySelectorAll ) { for (i = 0; i < aMaps.length; i++) { mapId = aMaps[i]; var divs = theDoc.querySelectorAll('div#d' + mapId); if (divs.length <= 1) continue; //Ups, there are two or more divs, only one must remain for (j = divs.length - 1; j >= 0; j--) { div = divs[j]; imgs = div.getElementsByTagName( 'IMG' ); if ( !imgs || !imgs[0] || imgs[0].id != mapId) { // If it doesn't have an image inside, remove that div // but leave whatever it's inside, just in case... element = new CKEDITOR.dom.element( div ); element.remove( true ); modified = true; } } } } return !modified; } }; // Our object that will handle parsing of the script and creating the new one. function CKEGoogleMap( editor ) { this.editor = editor; var now = new Date(); this.number = 'gmap' + now.getFullYear() + now.getMonth() + now.getDate() + now.getHours() + now.getMinutes() + now.getSeconds(); this.width = editor.config.googleMaps_Width || 900; this.height = editor.config.googleMaps_Height || 250; this.responsive = true; //editor.config.googleMaps_Responsive; this.centerLat = editor.config.googleMaps_CenterLat || 37.4419; this.centerLon = editor.config.googleMaps_CenterLon || -122.1419; this.zoom = editor.config.googleMaps_Zoom || 11; this.tilt = 0; this.heading = 0; this.markerPoints = []; this.textsData = []; this.linesData = []; this.areasData = []; this.circlesData = []; this.mapType = 0; // map, satellite, hybrid... this.generatedType = 3; // 1: only static, 2: static + click to load, 3: load with page, 4: loaded on demand by call to initGmapsLoader this.kmlOverlay = ''; this.zoomControl = 'Default'; this.mapTypeControl = 'Default'; this.scaleControl = false; this.overviewMapControl = false; this.overviewMapControlOpened = true; this.googleBar = false; this.weather = false; this.weatherUsaUnits = editor.config.googleMaps_weatherUsaUnits || false; this.pathType = 'Default'; this.WrapperClass = editor.config.googleMaps_WrapperClass || ''; this.key = editor.config.googleMaps_ApiKey || ''; } CKEGoogleMap.prototype.createHtmlElement = function() { // let's assure that the map exists in the list this.editor.plugins.googleMapsHandler.maps[ this.number ] = this; var oFakeNode = this.editor.document.createElement( 'IMG' ); oFakeNode.setAttribute( 'mapnumber', this.number ); oFakeNode.setAttribute( 'id', this.number ); var oDiv = this.editor.document.createElement( 'DIV' ); oDiv.setAttribute( 'id', 'd' + this.number); if (this.WrapperClass !== '') { var oWrapper = this.editor.document.createElement( 'DIV' ); oWrapper.setAttribute( 'class', this.WrapperClass ); this.editor.insertElement( oWrapper ); oWrapper.append( oDiv ); } else this.editor.insertElement( oDiv ); oDiv.append( oFakeNode ); return oFakeNode.$; }; CKEGoogleMap.prototype.createDivs = function( oFakeNode ) { var oWrapper, oDiv = this.editor.document.$.createElement( 'DIV' ); oDiv.setAttribute( 'id', 'd' + this.number); oFakeNode.parentNode.insertBefore( oDiv, oFakeNode ); if (this.WrapperClass !== '') { oWrapper = this.editor.document.$.createElement( 'DIV' ); oWrapper.className = this.WrapperClass; oDiv.parentNode.insertBefore( oWrapper, oDiv ); oWrapper.appendChild( oDiv ); } oDiv.appendChild( oFakeNode ); }; CKEGoogleMap.prototype.updateHTMLElement = function( oFakeNode ) { // let's assure that the map exists in the list this.editor.plugins.googleMapsHandler.maps[ this.number ] = this; oFakeNode.setAttribute('width', this.width); oFakeNode.setAttribute('height', this.height); // Static maps preview :-) var staticMap = this.generateStaticMap(); oFakeNode.setAttribute( 'src', staticMap); oFakeNode.setAttribute( 'data-cke-saved-src', staticMap); oFakeNode.setAttribute( 'alt', ''); if (this.responsive) { oFakeNode.style.width = '100%'; oFakeNode.style.maxWidth = this.cssWidth(); oFakeNode.style.height = this.height; //'auto'; } else { oFakeNode.style.width = ''; oFakeNode.style.height = ''; } }; CKEGoogleMap.prototype.getMapTypeIndex = function( type ) { return CKEDITOR.tools.indexOf([ 'roadmap', 'satellite', 'hybrid', 'terrain' ], type); }; CKEGoogleMap.prototype.parseStaticMap = function( oImage ) { var reStatic = /center=(-?\d+\.\d*),(-?\d+\.\d*)&zoom=(\d+)&size=(\d+)x(\d+)&maptype=(.*?)(?:&markers=(.*?))?(&path=(?:.*?))?/, markers, paths, result, reMarks = /(-?\d+\.\d*),(-?\d+\.\d*),(\w+)\|?/g, reLines = /rgba:0x(\w{6})(\w\w),weight:(\d)(.*?)(&|$)/g; if (reStatic.test( oImage.src ) ) { this.generatedType = 1; this.centerLat = RegExp.$1; this.centerLon = RegExp.$2; this.zoom = RegExp.$3; this.width = oImage.width; this.height = oImage.height; alert( this.height ); this.mapType = this.getMapTypeIndex(RegExp.$6); // markers markers = RegExp.$7; // paths paths = RegExp.$8; while ( (result = reMarks.exec( markers )) ) { this.markerPoints.push( { lat:result[1], lon:result[2], text:'', color:result[3], title:'', maxWidth:200 } ); } while ( (result = reLines.exec( paths )) ) { this.linesData.push( { color:'#' + result[1], opacity:parseInt(result[2], 16) / 255, weight:parseInt(result[3], 10), PointsData:result[4], points:null, text:'', maxWidth:200 } ); } } }; CKEGoogleMap.prototype.parseStaticMap2 = function( oImage ) { var reStatic = /center=(-?\d+\.\d*),(-?\d+\.\d*)&zoom=(\d+)&size=(\d+)x(\d+)&maptype=(\w*?)(&markers=.*?)?(&path=.*?)?&?/, markers, paths, result, line, reMarks = /markers=color:(\w*)\|(-?\d+\.\d*),(-?\d+\.\d*)(&|$)/g, reLines = /path=color:0x(\w{6})(\w\w)\|weight:(\d)\|(fillcolor:0x(\w{6})(\w\w)\|)?enc:(.*?)&pathData=zf:(\d*)\|nl:(\d*)\|lvl:(.*?)(&|$)/g; if (reStatic.test( oImage.src ) ) { this.generatedType = 1; this.centerLat = RegExp.$1; this.centerLon = RegExp.$2; this.zoom = RegExp.$3; this.width = oImage.width; this.height = oImage.height; this.mapType = this.getMapTypeIndex(RegExp.$6); // markers markers = RegExp.$7; // paths paths = RegExp.$8; while ( (result = reMarks.exec( markers )) ) { this.markerPoints.push( { lat:result[2], lon:result[3], text:'', color:result[1], title:'', maxWidth:200 } ); } while ( (result = reLines.exec( paths )) ) { line = { color:'#' + result[1], opacity:parseInt(result[2], 16) / 255, weight:parseInt(result[3], 10), points:unescape(result[7]) }; if (result[4]) { //polygons this.areasData.push( { polylines: [ line ], fill:line.color, color:'#' + result[5], opacity:parseInt(result[6], 16) / 255, text:'', maxWidth:200 } ); } else { // lines line.text = ''; line.maxWidth = 200; this.linesData.push( line ); } } } else { // Static Maps V1 this.parseStaticMap( oImage ); } }; CKEGoogleMap.prototype.generateStaticMap = function() { var w = Math.min(this.width, 640), h = Math.min(this.height, 640), staticMapTypes = [ 'roadmap', 'satellite', 'hybrid', 'terrain' ]; if (this.panorama) { var fov = 180 / Math.pow(2, this.panorama.zoom); return 'https://maps.googleapis.com/maps/api/streetview?location=' + this.panorama.lat + ',' + this.panorama.lng + '&size=' + w + 'x' + h + '&heading=' + this.panorama.heading + '&pitch=' + this.panorama.pitch + '&fov=' + fov + '&key=' + this.key; } var part1 = 'https://maps.googleapis.com/maps/api/staticmap?center=' + this.centerLat + ',' + this.centerLon + '&zoom=' + this.zoom + '&size=' + w + 'x' + h + '&maptype=' + staticMapTypes[ this.mapType ], part2 = this.generateStaticMarkers(), part3 = this.generateStaticPaths() + '&key=' + this.key; // If the URL is too large Google won't generate the image. Try to trim it using default icons if ((part1 + part2 + part3).length >= 1950) { part2 = this.generateStaticMarkers(true); } return part1 + part2 + part3; }; CKEGoogleMap.prototype.generateStaticMarkers = function(shortened) { if (this.markerPoints.length === 0) return ''; var i = 0, point, aPoints = [], googleMaps_Icons = this.editor.config.googleMaps_Icons; for (; i < this.markerPoints.length; i++) { point = this.markerPoints[i]; aPoints.push('&markers='); // Custom icons if (!shortened) { if ( googleMaps_Icons && googleMaps_Icons[ point.color ] ) { var url = googleMaps_Icons[ point.color ].marker.image; // avoid linking to localhost or the map generator will return an error if (/:\/\/.*\..*\//.test( url )) aPoints.push('icon:' + url); else aPoints.push('icon:' + point.color); } else aPoints.push('color:' + point.color); } aPoints.push('|' + point.lat + ',' + point.lon ); } return aPoints.join(''); }; CKEGoogleMap.prototype.generateStaticPaths = function() { function hex(n) { var h = Math.round(255 * n).toString(16); if (h.length == 1) h = '0' + h; return h; } var strings = '', i = 0, line, area; for (; i < this.linesData.length; i++) { // transform the color to rgba.... line = this.linesData[i]; strings += '&path=' + 'color:0x' + line.color.replace('#', '') + hex(line.opacity) + '|weight:' + line.weight + '|enc:' + line.points; } // Polygons for (i = 0; i < this.areasData.length; i++) { area = this.areasData[i]; line = area.polylines[0]; strings += '&path=' + 'color:0x' + line.color.replace('#', '') + hex(line.opacity) + '|weight:' + line.weight + '|fillcolor:0x' + area.color.replace('#', '') + hex(area.opacity) + '|enc:' + line.points; } return strings; }; // Read the dimensions back from the fake node (the user might have manually resized it) CKEGoogleMap.prototype.updateDimensions = function( oFakeNode ) { var iWidth, iHeight, regexSize = /^\s*(\d+)px\s*$/i, aMatchW, aMatchH; if ( oFakeNode.style.width ) { aMatchW = oFakeNode.style.width.match( regexSize ); if ( aMatchW ) { iWidth = aMatchW[1]; oFakeNode.style.width = ''; oFakeNode.width = iWidth; } } if ( oFakeNode.style.height ) { aMatchH = oFakeNode.style.height.match( regexSize ); if ( aMatchH ) { iHeight = aMatchH[1]; oFakeNode.style.height = ''; oFakeNode.height = iHeight; } } this.width = iWidth ? iWidth : oFakeNode.width; this.height = iHeight ? iHeight : oFakeNode.height; }; CKEGoogleMap.prototype.decodeText = function(string) { return string.replace(/<\\\//g, ' 3) return false; if (majorVersion > 2) regexpKml = /AddKml\("([^"]*)"\)/; if (majorVersion >= 3 && minorVersion >= 3) regexpMarkers = /\{lat\:(-?\d{1,3}\.\d{1,6}),\s*lon\:(-?\d{1,3}\.\d{1,6}),\s*text\:("|')(.*?)\3,\s*color:"(.*?)",\s*title:"(.*?)",\s*maxWidth:(\d+),\s*open:(\d)}(?:,|])/g ; // dimensions: // document.writeln('
.
'); if (majorVersion < 2) { if (regexpDimensions.test( script ) ) { delete handler.maps[this.number]; this.number = RegExp.$1; handler.maps[this.number] = this; this.width = RegExp.$2; this.height = RegExp.$3; } } else { // var dMap = document.getElementById("gmap200893233020"); // dMap.style.width = "300px"; // dMap.style.height = "200px"; if (regexpId.test( script ) ) { delete handler.maps[this.number]; this.number = RegExp.$1; handler.maps[this.number] = this; } if (regexpWidth.test( script ) ) { this.width = RegExp.$1.replace(/px$/, ''); //if (this.width == '100%') this.responsive = true; } if (regexpHeight.test( script ) ) this.height = RegExp.$1.replace(/px$/, ''); if (regexpType.test( script ) ) this.generatedType = RegExp.$1; } // map.setCenter(new GLatLng(42.4298,-8.07756), 8); if (majorVersion == 1) regexpPosition = /map\.setCenter\(new GLatLng\((-?\d{1,3}\.\d{1,6}),(-?\d{1,3}\.\d{1,6})\), (\d{1,2})\);/; if (regexpPosition.test( script ) ) { this.centerLat = RegExp.$1; this.centerLon = RegExp.$2; this.zoom = RegExp.$3; } // v <= 1.5 if (majorVersion == 1 && minorVersion <= 5 ) { // var text = 'En O Carballino ha estado la d\'elegacion diplomatica japonesa'; if (regexpText.test( script ) ) { markerText = RegExp.$2; } // var point = new GLatLng(42.4298,-8.07756); if (regexpMarker.test( script ) ) { markerLat = RegExp.$1; markerLon = RegExp.$2; } if (markerLat !== 0 && markerLon !== 0) this.markerPoints.push( { lat:markerLat, lon:markerLon, text:this.decodeText(markerText), color:'red', title:'' } ); } else { // v > 1.5. multiple points. // AddMarkers( [{lat:37.45088, lon:-122.21123, text:'Write your text'}] ); while ( (result = regexpMarkers.exec(script)) ) { maxWidth = 200; var opened = false; if (result[5]) color = result[5]; if (result[6]) title = result[6]; if (result[7]) maxWidth = result[7]; if (result[8]) opened = result[8] == '1'; this.markerPoints.push( { lat:result[1], lon:result[2], text:this.decodeText(result[4]), color:color, title:this.decodeText(title), maxWidth:maxWidth, open:opened } ); } // Texts v>=2.1 while ( (result = regexpTexts.exec(script)) ) { this.textsData.push( { lat:result[1], lon:result[2], title:this.decodeText(result[3]), className:this.decodeText(result[4]) } ); } } if (majorVersion == 1) { // Notify back to parser that it must insert an img this.requiresImage = true; if (regexpLinePoints.test( script ) ) linePoints = RegExp.$2; if (regexpLineLevels.test( script ) ) lineLevels = RegExp.$2; if (linePoints !== '' && lineLevels !== '') { this.linesData.push({ color:'#3333cc', weight:5, opacity:0.45, points:linePoints, text:'', maxWidth:200 }); } } else { // V2: multiple lines and areas. // aLines.push('{color:\'' + line.color + '\', weight:' + line.weight + ', points:\'' + line.points + '\', levels:\'' + line.levels + '\'}'); // } // aScript.push(' AddLines( map, [' + aLines.join(',\r\n') + '] );'); if (majorVersion < 3 || (majorVersion == 3 && minorVersion === 0)) { while ( (result = regexpLines.exec(script)) ) { maxWidth = 200; if (result[9]) maxWidth = result[9]; this.linesData.push( { color:result[1], weight:result[2], opacity:result[3], points:this.decodeText(result[4]) } ); } // only one line in each area // we reverse the opacity and weight to be able to avoid parsing them as normal polylines // AddAreas( map, [{polylines: [{color:'#008000', opacity:0.7, weight:2, points:'iatcFnzrhVpfA{nOtuExkJnd@ffOwbIecJ', levels:'BBBBB'}], fill: true, color:'#008000', opacity:0.2, outline:true}] ); while ( (result = regexpAreas.exec(script)) ) { lines = [ { color:result[1], weight:parseInt(result[3],10), opacity:parseFloat(result[2]), points:this.decodeText(result[4]) } ]; maxWidth = 200; if (result[13]) maxWidth = parseInt(result[13], 10); this.areasData.push( { polylines: lines, fill:true, color:result[9], opacity:parseFloat(result[10]) } ); } } else { if (majorVersion == 3 && minorVersion < 6) { // withouth levels, zoomfactor and numLevels params, but always with maxWidth regexpLines = /\{color\:("|')(.*)\1,\s*weight:(\d+),\s*opacity:(-?\d\.\d{1,2}),\s*points\:("|')(.*?)\5,\s*text\:("|')(.*?)\7,\s*maxWidth:(\d+)}(?:,|])/g ; regexpAreas = /\{polylines:\s*\[\{color\:("|')(.*)\1,\s*opacity:(-?\d\.\d{1,2}),\s*weight:(\d+),\s*points\:("|')(.*)\5}\],\s*fill:(.*),\s*color:("|')(.*)\8,\s*opacity:(-?\d\.\d{1,2}),\s*text\:("|')(.*?)\11,\s*maxWidth:(\d+)\}(?:,|])/g ; while ( (result = regexpLines.exec(script)) ) { this.linesData.push( { color:result[2], weight:parseInt(result[3],10), opacity:parseFloat(result[4]), points:this.decodeText(result[6]) } ); } while ( (result = regexpAreas.exec(script)) ) { lines = [ { color:result[2], opacity:parseFloat(result[3]), weight:parseInt(result[4],10), points:this.decodeText(result[6]) } ]; this.areasData.push( { polylines:lines, color:result[9], opacity:parseFloat(result[10]) } ); } } else { regexpLines = /\{color\:"(.*)",\s*weight:(\d+),\s*opacity:(-?\d\.\d{1,2}),\s*points\:"(.*?)"}(?:,|])/g ; while ( (result = regexpLines.exec(script)) ) { this.linesData.push( { color:result[1], weight:parseInt(result[2],10), opacity:parseFloat(result[3]), points:this.decodeText(result[4]) } ); } regexpAreas = /\{polylines:\s*\[\{color\:"(.*)",\s*opacity:(-?\d\.\d{1,2}),\s*weight:(\d+),\s*points\:"(.*)"}\],\s*color:"(.*)",\s*opacity:(-?\d\.\d{1,2})\}(?:,|])/g ; while ( (result = regexpAreas.exec(script)) ) { lines = [ { color:result[1], opacity:parseFloat(result[2]), weight:parseInt(result[3],10), points:this.decodeText(result[4]) } ]; this.areasData.push( { polylines:lines, color:result[5], opacity:parseFloat(result[6]) } ); } var regexpCircles = /\{lat\:(-?\d{1,3}\.\d{1,6}),\s*lon\:(-?\d{1,3}\.\d{1,6}),radius:(\d+),color\:"(.*)",\s*weight:(\d+),\s*opacity:(-?\d\.\d{1,2}),\s*fillColor:"(.*)",\s*fillOpacity:(-?\d\.\d{1,2})\}(?:,|])/g ; while ( (result = regexpCircles.exec(script)) ) { this.circlesData.push( { lat:result[1], lon:result[2], radius:parseInt(result[3], 10), color:result[4], weight:parseInt(result[5],10), opacity:parseFloat(result[6]), fillColor:result[7], fillOpacity:parseFloat(result[8]) } ); } // panorama var regexpPanorama = /panorama:\{lat:(-?\d{1,3}\.\d+),lng:(-?\d{1,3}\.\d+),pov1:(\d+\.?\d*),pov2:(\d+\.?\d*),pov3:(\d+\.?\d*)\}/; if (regexpPanorama.test( script ) ) { var panorama = {}; panorama.lat = parseFloat(RegExp.$1); panorama.lng = parseFloat(RegExp.$2); panorama.heading = parseFloat(RegExp.$3); panorama.pitch = parseFloat(RegExp.$4); panorama.zoom = parseFloat(RegExp.$5); this.panorama = panorama; } } } } // 1.8 mapType // map.setMapType( allMapTypes[ 1 ] ); if (/setMapType\([^\[]*\[\s*(\d+)\s*\]\s*\)/.test( script ) ) { this.mapType = RegExp.$1; } // 1.9 wrapper div with custom class if ( majorVersion == 1 && minorVersion >= 9 ) { if (/
= 0; this.scaleControl = script.indexOf('ScaleControl') >= 0; this.googleBar = script.indexOf('enableGoogleBar') >= 0; // Remap them to v3: switch (this.zoomControl) { case 'SmallZoomControl': this.zoomControl = 'Small'; break; case 'SmallMapControl': this.zoomControl = 'Small'; break; case 'LargeMapControl': this.zoomControl = 'Full'; break; default: this.zoomControl = 'None'; break; } switch (this.mapTypeControl) { case 'MapTypeControl': this.mapTypeControl = 'Full'; break; case 'HierarchicalMapTypeControl': this.mapTypeControl = 'Menu'; break; default: this.mapTypeControl = 'None'; break; } } // controls: if ( majorVersion == 3 ) { /* var mapOptions = { zoom: 7, center: [42.7228,-1.72485], mapType: 0, zoomControl: 'Full', mapsControl: 'Menu', overviewMapControl: false, scaleControl: false, googleBar: false }; */ if (/center:\s*\[(-?\d{1,3}\.\d{1,6}),(-?\d{1,3}\.\d{1,6})\],/.test( script ) ) { this.centerLat = RegExp.$1; this.centerLon = RegExp.$2; } if (/zoom: (\d{1,2}),/.test( script ) ) this.zoom = parseInt(RegExp.$1, 10); if (/mapType: (\d{1,2}),/.test( script ) ) this.mapType = parseInt(RegExp.$1, 10); // old if (/navigationControl: "(.*?)",/.test( script ) ) this.zoomControl = RegExp.$1; if (/zoomControl: "(.*?)",/.test( script ) ) this.zoomControl = RegExp.$1; if (/mapsControl: "(.*?)",/.test( script ) ) this.mapTypeControl = RegExp.$1; if (/overviewMapControl: (.*?),/.test( script ) ) this.overviewMapControl = RegExp.$1 == 'true'; if (/overviewMapControlOptions: \{opened:(.*?)\},/.test( script ) ) this.overviewMapControlOpened = RegExp.$1 == 'true'; if (/scaleControl: (.*?),/.test( script ) ) this.scaleControl = RegExp.$1 == 'true'; if (/traffic: (.*?),/.test( script ) ) { if (RegExp.$1 == 'true') this.pathType = 'Traffic'; } if (/transit: (.*?),/.test( script ) ) { if (RegExp.$1 == 'true') this.pathType = 'Transit'; } if (/pathType: "(.*?)",/.test( script ) ) this.pathType = RegExp.$1; if (/weather: (.*?),/.test( script ) ) this.weather = RegExp.$1 == 'true'; if (/weatherUsaUnits: (.*?),/.test( script ) ) this.weatherUsaUnits = RegExp.$1 == 'true'; // last one without trailing comma if (/googleBar: (.*?)\n/.test( script ) ) this.googleBar = RegExp.$1 == 'true'; if (/heading: (\d{1,3}),/.test( script ) ) this.heading = parseInt(RegExp.$1, 10); if (/tilt: (\d{1,2}),/.test( script ) ) this.tilt = parseInt(RegExp.$1, 10); // extra icons if ( minorVersion >= 3 ) { if (!this.editor.config.googleMaps_Icons) this.editor.config.googleMaps_Icons = {}; var reIcons = /googleMaps_Icons\["(.*?)"\] = ({.*?});/g; while ( (result = reIcons.exec(script)) ) { // Simulate that it was included in the config: this.editor.config.googleMaps_Icons[ result[1] ] = JSON.parse( result[2] ); } } } return true; }; // fixme: allow % CKEGoogleMap.prototype.cssWidth = function() { if (/\d+\D+/.test(this.width)) return this.width; return this.width + 'px'; }; CKEGoogleMap.prototype.cssHeight = function() { if (/\d+\D+/.test(this.height)) return this.height; return this.height + 'px'; }; CKEGoogleMap.prototype.BuildScript = function() { var handler = this.editor.plugins.googleMapsHandler, aScript = [], i, aPoints = [], point, aTexts = [], aLines = [], line, aAreas = [], area, areaLine, aCircles = [], circle; aScript.push('\r\n'); return aScript.join('\r\n'); }; CKEDITOR.plugins.add( 'googlemaps', { requires : [ 'dialog' ], // translations lang : 'en,ar,cs,de,el,es,fi,fr,it,nl,pl,ru,sk,tr', icons: 'googlemaps,gmapsinsertdirections', // %REMOVE_LINE_CORE% init : function( editor ) { editor.plugins.googleMapsHandler = new GoogleMapsHandler( editor ); // Add buttons. var allowed = 'div[id];img[id,src,style];script'; if (editor.config.googleMaps_WrapperClass) allowed += ';div(' + editor.config.googleMaps_WrapperClass + ')'; editor.addCommand( 'googlemaps', new CKEDITOR.dialogCommand( 'googlemaps', { allowedContent: allowed, requiredContent: 'script' } ) ); editor.ui.addButton( 'GoogleMaps', { label : editor.lang.googlemaps.toolbar, command : 'googlemaps', icon : this.path + 'icons/googlemaps.png', // %REMOVE_LINE_CORE% toolbar : 'insert' } ); CKEDITOR.dialog.add( 'googlemaps', this.path + 'dialogs/googlemaps.js' ); CKEDITOR.dialog.add( 'googlemapsMarker', this.path + 'dialogs/marker.js' ); CKEDITOR.dialog.add( 'googlemapsIcons', this.path + 'dialogs/icons.js' ); CKEDITOR.dialog.add( 'googlemapsText', this.path + 'dialogs/text.js' ); CKEDITOR.dialog.add( 'googlemapsLine', this.path + 'dialogs/line.js' ); CKEDITOR.dialog.add( 'googlemapsArea', this.path + 'dialogs/area.js' ); // If the "menu" plugin is loaded, register the menu items. if ( editor.addMenuItems ) { editor.addMenuItems( { googlemaps : { label : editor.lang.googlemaps.menu, icon : this.path + 'icons/googlemaps.png', // %REMOVE_LINE_CORE% command : 'googlemaps', group : 'image', order : 1 } }); } // If the "contextmenu" plugin is loaded, register the listeners. if ( editor.contextMenu ) { // check the image // We put our listener as the first item // The aim of this listener is to mark the images as "fake", but only while the context menu is displayed editor.contextMenu._.listeners.unshift( function( element ) { if ( !element || !element.is( 'img' ) || !editor.plugins.googleMapsHandler.isStaticImage( element.$ ) ) return null; // Set here the trick element.data( 'cke-realelement', '1' ); return null; }); editor.contextMenu.addListener( function( element ) { if ( !element || !element.is( 'img' ) || !editor.plugins.googleMapsHandler.isStaticImage( element.$ ) ) return null; // Now we clear it element.data( 'cke-realelement', false ); // And say that this context menu item must be shown return { googlemaps : CKEDITOR.TRISTATE_ON }; }); } // Open our dialog on double click editor.on( 'doubleclick', function( evt ) { var element = evt.data.element; if ( element.is( 'img' ) && editor.plugins.googleMapsHandler.isStaticImage( element.$ ) ) { evt.data.dialog = 'googlemaps'; // evt.stop(); } }, null, null, 20); // after the default options // patch for #13481 var initialZindex; editor.on( 'beforeCommandExec', function( evt ) { if (evt.data.name != 'maximize') return; if (!initialZindex) initialZindex = editor.config.baseFloatZIndex; // Only the first time to get the initial value evt.removeListener(); } ); editor.on( 'afterCommandExec', function( evt ) { if (evt.data.name != 'maximize') return; if (evt.data.command.state == CKEDITOR.TRISTATE_ON) editor.config.baseFloatZIndex = initialZindex * 2; else editor.config.baseFloatZIndex = initialZindex; } ); // end patch for #13481 }, afterInit : function(editor) { // We need to control if the scripts must be added or removed processScriptOutput(editor); // Expand the editor to provide controlled dialogs. editor.openNestedDialog = function( dialogName, callbackOpen, callbackOK ) { var onOk = function() { releaseHandlers( this ); if (callbackOK) callbackOK( this ); }; var onCancel = function() { releaseHandlers( this ); }; var releaseHandlers = function( dialog ) { dialog.removeListener( 'ok', onOk ); dialog.removeListener( 'cancel', onCancel ); }; var bindToDialog = function( dialog ) { dialog.on( 'ok', onOk ); dialog.on( 'cancel', onCancel ); if (callbackOpen) callbackOpen( dialog ); }; if ( editor._.storedDialogs[ dialogName ]) bindToDialog( editor._.storedDialogs[ dialogName ] ); else { CKEDITOR.on( 'dialogDefinition', function( e ) { if ( e.data.name != dialogName ) return; var definition = e.data.definition; e.removeListener(); if (typeof definition.onLoad == 'function') { definition.onLoad = CKEDITOR.tools.override( definition.onLoad, function( original ) { return function() { definition.onLoad = original; if ( typeof original == 'function' ) original.call( this ); bindToDialog( this ); }; } ); } else { definition.onLoad = function() { bindToDialog( this ); }; } }); } editor.openDialog( dialogName ); }; // Workaround for #9060 if (CKEDITOR.env.ie) { CKEDITOR.dialog.prototype.hide = CKEDITOR.tools.override( CKEDITOR.dialog.prototype.hide , function( originalFunction ) { return function() { var parent = this._.parentDialog; originalFunction.call( this ); if (parent && this._.editor != parent._.editor) { if ( this._.editor.mode == 'wysiwyg' ) { var selection = this._.editor.getSelection(); if (selection) selection.unlock( true ); } } }; }); } } }); // Adjust the output function processScriptOutput( editor ) { var dataProcessor = editor.dataProcessor, htmlFilter = dataProcessor && dataProcessor.htmlFilter, dataFilter = dataProcessor && dataProcessor.dataFilter, handler = editor.plugins.googleMapsHandler; // Avoid that our images are upcasted to widgets editor.on( 'toHtml', function( evt ) { evt.data.dataValue.forEach( function( element ) { // find images and if they belong to us, set an attribute to avoid the conversion by image2 if (element.name == 'img') { var id = element.attributes['id']; if (id && (/^gmap\d+$/).test(id)) element.attributes['data-cke-realelement'] = 'googlemap'; else { var parent = element.parent; if (parent && parent.name == 'div') { id = parent.attributes['id']; if (id && (/^dgmap\d+$/).test(id)) { element.attributes['data-cke-realelement'] = 'googlemap'; } } } } }); // lower priority than the widget system }, null, null, 5); // dataFilter : conversion from html input to internal data dataFilter.addRules( { comment : function( contents ) { // Check if they are part of our scripts. Parse them and remove from the content. var protectedSourceMarker = '{cke_protected}'; if (contents.substr(0, protectedSourceMarker.length) == protectedSourceMarker) { var data = contents.substr( protectedSourceMarker.length ); data = decodeURIComponent( data ); if ( handler.detectMapScript( data ) ) { var oMap = handler.createNew(); if (oMap.parse( data ) ) { if (oMap.requiresImage) { // Insert an image with the map data return new CKEDITOR.htmlParser.element( 'img', { id: oMap.number, mapnumber: oMap.number, src: oMap.generateStaticMap(), width: oMap.width, height: oMap.height } ); } return false; } } else { if ( handler.detectGoogleScript( data ) ) return false; } } return contents; }, elements : { 'img' : function(element) { var id = element.attributes['id']; if (id && (/^gmap\d+$/).test(id)) element.attributes['mapnumber'] = id; else { var parent = element.parent; if (parent && parent.name == 'div') { id = parent.attributes['id']; if (id && (/^dgmap\d+$/).test(id)) { element.attributes['id'] = element.attributes['mapnumber'] = id.substr(1); } } } if (element.attributes['data-cke-realelement'] && element.attributes['data-cke-realelement'] == 'googlemap') { delete element.attributes['data-cke-realelement']; } }, 'div' : function(element) { // Readjust previous ids. var id = element.attributes['id']; if (id && (/^gmap\d+$/).test(id)) { element.attributes[ 'id' ] = 'd' + id; } } } } ); // htmlFilter : conversion from internal data to html output. htmlFilter.addRules( { elements : { 'img' : function( element ) { var number = element.attributes.mapnumber; if (number) { var scriptNode, handler = editor.plugins.googleMapsHandler, oMap = handler.getMap( number ); if (oMap && oMap.generatedType > 1) { handler.CreatedMapsNames.push( oMap.number ); // Inject the