CKEDITOR.dialog.add('leaflet', function(editor) { var autocomplete; var mapContainer = ''; // Access the current translation file. var pluginTranslation = editor.lang.leaflet; // Use the core translation file. Used mainly for the `Alignment` values. var commonTranslation = editor.lang.common; // Dialog's function callback for the Leaflet Map Widget. return { title: pluginTranslation.dialogTitle, minWidth: 320, minHeight: 125, contents: [{ // Create a Location tab. id: 'location_tab', label: pluginTranslation.locationTabLabel, elements: [ // { // id: 'map_geocode', // className: 'geocode', // type: 'text', // label: pluginTranslation.googleSearchFieldLabel, // style: 'margin-top: -7px;', // // setup: function(widget) { // this.setValue(''); // }, // // onLoad: function (widget) { // // Get the DOM reference for the Search field. // var input = this.getInputElement().$; // // // Set a diffused/default text for better user experience. // // This will override the Google's default placeholder text: // // 'Enter a location'. // jQuery('.geocode input').attr('placeholder', pluginTranslation.googleSearchFieldHint); // // var config = editor.config; // // // Default value, but eventually will reach its quota if many users // // will just utilize this key instead of creating their own. // var googleApiKey = 'AIzaSyA9ySM6msnGm0qQB1L1cLTMBdKEUKPySmQ'; // // if (typeof config.leaflet_maps_google_api_key != 'undefined' && config.leaflet_maps_google_api_key != '') { // googleApiKey = config.leaflet_maps_google_api_key; // } // // // Execute only once, and not every dialog pop-up. // if (typeof google == 'undefined') { // // Load other needed external library. // // Wait for the script to finish loading before binding // // the autocomplete mechanism to prevent rendering issue. // CKEDITOR.scriptLoader.load('//maps.googleapis.com/maps/api/js?libraries=places&callback=dummy&key=' + googleApiKey, function() { // // Bind the Search field to the Autocomplete widget. // autocomplete = new google.maps.places.Autocomplete(input); // }); // } else { // autocomplete = new google.maps.places.Autocomplete(input); // } // // // Fix for the Google's type-ahead search displaying behind // // the widgets dialog window. // // Basically, we want to override the z-index of the // // Seach Autocomplete list, in which the styling is being set // // in real-time by Google. // // Make a new DOM element. // var stylesheet = jQuery(''); // // // Set the inner HTML. Include also the vertical alignment // // adjustment for the MiniMap checkbox. // stylesheet.html('.pac-container { z-index: 100000 !important;} input.minimap { margin-top: 18px !important; }'); // // // Append to the main document's Head section. // jQuery('head').append(stylesheet); // }, // }, { // Dummy element serving as label/text container only. type: 'html', id: 'map_label', className: 'label', style: 'margin-bottom: -10px;', html: '
' + pluginTranslation.manualCoordinatesFieldLabel + '
' }, { // Create a new horizontal group. type: 'hbox', // Set the relative widths of Latitude, Longitude and Zoom fields. widths: [ '50%', '50%' ], children: [ { id: 'map_latitude', className: 'latitude', type: 'text', label: pluginTranslation.manualLatitudeFieldLabel, setup: function(widget) { // Set the Lat values if widget has previous value. if (widget.element.data('lat') !== '') { // Update the data-lat based on the map lat in iframe. // Make sure that mapContainer is set. // Also avoids setting it again since zoom/longitude // might already computed/set this object. if (mapContainer === '') { mapContainer = widget.element.getChild(0).$.contentDocument.getElementById('map_container'); } var currentLat = mapContainer.getAttribute('data-lat'); this.setValue(currentLat); } }, }, { id: 'map_longitude', className: 'longitude', type: 'text', label: pluginTranslation.manualLongitudeFieldLabel, setup: function(widget) { // Set the Lon values if widget has previous value. if (widget.element.data('lat') !== '') { // Update the data-lon based on the map lon in iframe. // Make sure that mapContainer is set. // Also avoids setting it again since zoom/latitude // might already computed/set this object. if (mapContainer === '') { mapContainer = widget.element.getChild(0).$.contentDocument.getElementById('map_container'); } var currentLon = mapContainer.getAttribute('data-lon'); this.setValue(currentLon); } }, }, ] }, { id: 'popup_text', className: 'popup-text', type: 'text', label: pluginTranslation.popupTextFieldLabel, style: 'margin-bottom: 8px;', setup: function(widget) { // Set the Lat values if widget has previous value. if (widget.element.data('popup-text') != '') { this.setValue(widget.element.data('popup-text')); } else { // Set a diffused/default text for better user experience. this.getInputElement().setAttribute('placeholder', pluginTranslation.popupTextFieldHint) } }, }, ] }, { // Create an Options tab. id: 'options_tab', label: pluginTranslation.optionsTabLabel, elements: [ { // Create a new horizontal group. type: 'hbox', style: 'margin-top: -7px;', // Set the relative widths of Latitude, Longitude and Zoom fields. widths: [ '38%', '38%', '24%' ], children: [ { id: 'width', className: 'map_width', type: 'text', label: pluginTranslation.mapWidthFieldLabel, setup: function(widget) { // Set a diffused/default text for better user experience. this.getInputElement().setAttribute('placeholder', '400') // Set the map width value if widget has a previous value. if (widget.element.data('width') != '') { this.setValue(widget.element.data('width')); } }, }, { id: 'height', className: 'map_height', type: 'text', label: pluginTranslation.mapHeightFieldLabel, setup: function(widget) { // Set a diffused/default text for better user experience. this.getInputElement().setAttribute('placeholder', '400'); // Set the map height value if widget has a previous value. if (widget.element.data('height') != '') { this.setValue(widget.element.data('height')); } }, }, { // Create a select list for Zoom Levels. // 'className' attribute is used for targeting this element in jQuery. id: 'map_zoom', className: 'zoom', type: 'select', label: pluginTranslation.mapZoomLevelFieldLabel, width: '70px', items: [['1'], ['2'], ['3'], ['4'],['5'], ['6'], ['7'], ['8'], ['9'], ['10'], ['11'], ['12'], ['13'], ['14'], ['15'], ['16'], ['17'], ['18'], ['19'], ['20']], // This will execute also every time you edit/double-click the widget. setup: function(widget) { // Set this Zoom Level's select list when // the current location has been initialized and set previously. if (widget.element.data('zoom') != '') { // Update the data-zoom based on the map zoom level in iframe. // Make sure that mapContainer is set. // Also avoids setting it again since latitude/longitude // might already computed/set this object. if (mapContainer === '') { mapContainer = widget.element.getChild(0).$.contentDocument.getElementById('map_container'); } var currentZoom = mapContainer.getAttribute('data-zoom'); this.setValue(currentZoom); } // Set the Default Zoom Level value. else { this.setValue('10'); } }, } ] }, { // Create a new horizontal group. type: 'hbox', // Set the relative widths for the tile and overview map fields. widths: [ '50%', '50%' ], children: [ { // Create a select list for map tiles. // 'className' attribute is used for targeting this element in jQuery. type: 'select', id: 'map_tile', className: 'tile', label: pluginTranslation.baseMapTileLabel, items: [['OpenStreetMap.Mapnik'], ['OpenStreetMap.DE'], ['OpenStreetMap.HOT'], ['Esri.DeLorme'], ['Esri.NatGeoWorldMap'], ['Esri.WorldPhysical'], ['Esri.WorldTopoMap'], ['Thunderforest.OpenCycleMap'], ['Thunderforest.Landscape'], ['Stamen.Watercolor']], // This will execute also every time you edit/double-click the widget. setup: function(widget) { var restrictedTiles = ['MapQuestOpen.Aerial', 'MapQuestOpen.OSM']; var tile = widget.element.data('tile'); // Set the Tile data attribute. // Must not be the restricted, MapQuest tiles. if ( tile != '' && restrictedTiles.indexOf(tile) == -1 ) { this.setValue(tile); } else { // Set the default value. // Includes the case for existing MapQuest tiles. this.setValue('OpenStreetMap.Mapnik'); } }, // This will execute every time you click the Dialog's OK button. // It will inject a map iframe in the CKEditor page. commit: function(widget) { var dialog = this.getDialog(); // Remove the iframe if it has one. widget.element.setHtml(''); // Retrieve the value in the Search field. var geocode = ''; //dialog.getContentElement('location_tab','map_geocode').getValue(); var latitude, longitude; if (geocode != '') { // No need to call the encodeURIComponent(). var geocodingRequest = '//maps.googleapis.com/maps/api/geocode/json?address=' + geocode + '&sensor=false'; // Disable the asynchoronous behavior temporarily so that // waiting for results will happen before proceeding // to the next statements. jQuery.ajaxSetup({ async: false }); // Geocode the retrieved place name. jQuery.getJSON(geocodingRequest, function(data) { if (data['status'] != 'ZERO_RESULTS') { // Get the Latitude and Longitude object in the // returned JSON object. latitude = data.results[0].geometry.location.lat; longitude = data.results[0].geometry.location.lng; } // Handle queries with no results or have some // malformed parameters. else { alert('The Place could not be Geocoded properly. Kindly choose another one.') } }); } // Get the Lat/Lon values from the corresponding fields. var latInput = dialog.getContentElement('location_tab','map_latitude').getValue(); var lonInput = dialog.getContentElement('location_tab','map_longitude').getValue(); // Get the data-lat and data-lon values. // It is empty for yet to be created widgets. var latSaved = widget.element.data('lat'); var lonSaved = widget.element.data('lon'); // Used the inputted values if it's not empty or // not equal to the previously saved values. // latSaved and lonSaved are initially empty also // for widgets that are yet to be created. // Or if the user edited an existing map, and did not edit // the lat/lon fields, and the Search field is empty. if ((latInput != '' && lonInput != '') && ((latInput != latSaved && lonInput != lonSaved) || geocode == '')) { latitude = latInput; longitude = lonInput; } var width = dialog.getContentElement('options_tab','width').getValue() || '400'; var height = dialog.getContentElement('options_tab','height').getValue() || '400'; var zoom = dialog.getContentElement('options_tab','map_zoom').getValue(); var popUpText = dialog.getContentElement('location_tab','popup_text').getValue(); var tile = dialog.getContentElement('options_tab','map_tile').getValue(); var alignment = dialog.getContentElement('options_tab','map_alignment').getValue(); // Returns 'on' or 'off'. var minimap = dialog.getContentElement('options_tab','map_mini').getValue()?'on':'off'; // Get a unique timestamp: var milliseconds = new Date().getTime(); // Set/Update the widget's data attributes. widget.element.setAttribute('id', 'leaflet_div-' + milliseconds); widget.element.data('lat', latitude); widget.element.data('lon', longitude); widget.element.data('width', width); widget.element.data('height', height); widget.element.data('zoom', zoom); widget.element.data('popup-text', popUpText); widget.element.data('tile', tile); widget.element.data('minimap', minimap); widget.element.data('alignment', alignment); // Remove the previously set alignment class. // Only one alignment class is set per map. widget.element.removeClass('align-left'); widget.element.removeClass('align-right'); widget.element.removeClass('align-center'); // Set the alignment for this map. widget.element.addClass('align-' + alignment); // Returns 'on' or 'off'. var responsive = dialog.getContentElement('options_tab','map_responsive').getValue()?'on':'off'; // Use 'off' if the Responsive checkbox is unchecked. if (responsive === 'off') { // Remove the previously set responsive map class, // if there's any. widget.element.removeClass('responsive-map'); } else { // Add a class for styling. widget.element.addClass('responsive-map'); } // Set the 'responsive' data attribute. widget.element.data('responsive', responsive); // Build the full path to the map renderer. mapParserPathFull = mapParserPath + '?lat=' + latitude + '&lon=' + longitude + '&width=' + width + '&height=' + height + '&zoom=' + zoom + '&text=' + popUpText + '&tile=' + tile + '&minimap=' + minimap + '&responsive=' + responsive; // Create a new CKEditor DOM's iFrame. var iframe = new CKEDITOR.dom.element('iframe'); // Setup the iframe characteristics. iframe.setAttributes({ 'scrolling': 'no', 'id': 'leaflet_iframe-' + milliseconds, 'class': 'leaflet_iframe', 'width': width + 'px', 'height': height + 'px', 'frameborder': 0, 'allowTransparency': true, 'src': mapParserPathFull, 'data-cke-saved-src': mapParserPathFull }); // If map is responsive. if (responsive == 'on') { // Add a class for styling. iframe.setAttribute('class', 'leaflet_iframe responsive-map-iframe'); } // Insert the iframe to the widget's DIV element. widget.element.append(iframe); }, }, { type: 'checkbox', id: 'map_mini', className: 'minimap', label: pluginTranslation.minimapCheckboxLabel, // This will execute also every time you edit/double-click the widget. setup: function(widget) { // Set the MiniMap check button. if (widget.element.data('minimap') != '' && widget.element.data('minimap') != 'on') { this.setValue(''); } else { // Set the default value. this.setValue('true'); } }, } ] }, { // Create a new horizontal group. type: 'hbox', // Set the relative widths for alignment and responsive options. widths: [ '50%', '50%' ], children: [ { // Create a select list for Map Alignment. // 'className' attribute is used for targeting this element in jQuery. id: 'map_alignment', className: 'alignment', type: 'select', label: commonTranslation.align, items: [[commonTranslation.alignLeft, 'left'], [commonTranslation.alignRight, 'right'], [commonTranslation.alignCenter, 'center']], style: 'margin-bottom: 4px;', // This will execute also every time you edit/double-click the widget. setup: function(widget) { // Set this map alignment's select list when // the current map has been initialized and set previously. if (widget.element.data('alignment') != '') { // Set the alignment. this.setValue(widget.element.data('alignment')); } // Set the Default alignment value. else { this.setValue('left'); } }, }, { type: 'checkbox', id: 'map_responsive', className: 'responsive', label: pluginTranslation.responsiveMapCheckboxLabel, // style: 'margin-top: 18px;', // This will execute also every time you edit/double-click the widget. setup: function(widget) { // Set the Responsive check button, when editing widget. if (widget.element.data('responsive') != '') { if (widget.element.data('responsive') == 'on') { this.setValue('true'); } else { this.setValue(''); } } // Set the default value for new ones. else { this.setValue(''); } }, } ] } ] }], onHide: function(){ // Reset/clear the map iframe/DOM object reference. // Fixes bug with lon/lat/zoom artifact values when closing dialog by pressing anything except ok. mapContainer = ''; } }; });