/**
* @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, '').replace(/\\n/g, '').replace(/\\'/g, '\'').replace(/\\"/g, '\"').replace(/\\\\/g, '\\');
};
CKEGoogleMap.prototype.encodeText = function(string) {
return string.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/'/g, '\\\'').replace(/\n/g, '').replace(/<\//g, '<\\/');
};
CKEGoogleMap.prototype.parse = function( script ) {
// Get version info:
if ( !/CK googlemaps v(\d+)\.(\d+)/.test(script) )
return false;
var regexpKml = /google\.maps\.GeoXml\("([^"]*?)"\)/ ,
majorVersion = parseInt(RegExp.$1, 10) ,
minorVersion = parseInt(RegExp.$2, 10) ,
regexpId = /dMap\s=\sdocument\.getElementById\("(.*?)"\)/ ,
regexpWidth = /dMap\.style\.width\s=\s"(.*?)"/ ,
regexpHeight = /dMap\.style\.height\s=\s"(.*?)"/ ,
regexpType = /\/(?:\/|\*)generatedType = (\d)/ ,
maxWidth ,
regexpPosition = /map\.setCenter\(new google\.maps\.LatLng\((-?\d{1,3}\.\d{1,6}),(-?\d{1,3}\.\d{1,6})\), (\d{1,2})\);/ ,
markerText, markerLat = 0, markerLon = 0 ,
regexpText = /var text\s*=\s*("|')(.*)\1;\s*\n/ ,
regexpDimensions = /
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