plugin.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /**
  2. * @fileOverview Leaflet Map Widget.
  3. */
  4. (function() {
  5. /* Flow of Control for CKEditor and Widget components:
  6. Loading the page:
  7. CKEditor init()
  8. Widget upcast()
  9. Creating new widgets:
  10. Widget init()
  11. Widget data()
  12. Dialog select element's items()
  13. Dialog onShow()
  14. Dialog setup()
  15. Dialog commit()
  16. When editing existing widgets:
  17. Dialog onShow()
  18. Dialog setup()
  19. Dialog commit()
  20. Widget data()
  21. When saving page or clicking the CKEditor's Source button:
  22. Widget downcast()
  23. */
  24. // Dummy global method for quick workaround of asynchronous document.write()
  25. // issue of Google APIs with respect to CKEditor.
  26. // See the Google APIs URL below for the query string usage of this dummy().
  27. // Using this hack, the document.write(...) requirement of Google APIs
  28. // will be replaced by the more 'gentle' combination of
  29. // document.createElement(...) and document.body.appendChild(...).
  30. window.dummy = function(){
  31. // Do nothing.
  32. }
  33. // Load the needed external libraries. This is asynchronous loading,
  34. // that is, they will be loaded in parallel to boost performance.
  35. // See also CKEDITOR.scriptLoader.queue.
  36. CKEDITOR.scriptLoader.load('//code.jquery.com/jquery-1.11.0.min.js');
  37. CKEDITOR.scriptLoader.load('http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false&callback=dummy');
  38. // Add a new CKEditor plugin. Note that widgets are subclass of plugins.
  39. CKEDITOR.plugins.add('leaflet', {
  40. // Declare dependencies.
  41. requires: 'widget',
  42. init: function(editor) {
  43. // Declare a new Dialog for interactive selection of
  44. // map parameters. It's still not bound to any widget at this moment.
  45. CKEDITOR.dialog.add('leaflet', this.path + 'dialogs/leaflet.js');
  46. // For reusability, declare a global variable pointing to the map script path
  47. // that will build and render the map.
  48. // In JavaScript, relative path must include the leading slash.
  49. mapParserPath = CKEDITOR.getUrl(this.path + 'scripts/mapParser.html');
  50. // Declare a new widget.
  51. editor.widgets.add('leaflet', {
  52. // Bind the widget to the Dialog command.
  53. dialog: 'leaflet',
  54. // Declare the elements to be upcasted back.
  55. // Otherwise, the widget's code will be ignored.
  56. // Basically, we will allow all divs with 'leaflet_div' class,
  57. // including their alignment classes, and all iframes with
  58. // 'leaflet_iframe' class, and then include
  59. // all their attributes.
  60. // Read more about the Advanced Content Filter here:
  61. // * http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
  62. // * http://docs.ckeditor.com/#!/guide/plugin_sdk_integration_with_acf
  63. allowedContent: 'div(!leaflet_div,align-left,align-right,align-center)[*];'
  64. + 'iframe(!leaflet_iframe)[*];',
  65. // Declare the widget template/structure, containing the
  66. // important elements/attributes. This is a required property of widget.
  67. template:
  68. '<div id="" class="leaflet_div" data-lat="" data-lon="" data-width="" data-height="" ' +
  69. 'data-zoom="" data-popup-text="" data-tile="" data-minimap="" data-alignment=""></div>',
  70. // This will be executed when going from the View Mode to Source Mode.
  71. // This is usually used as the function to convert the widget to a
  72. // dummy, simpler, or equivalent textual representation.
  73. downcast: function(element) {
  74. // Note that 'element' here refers to the DIV widget.
  75. // Get the previously saved zoom value data attribute.
  76. // It will be compared to the current value in the map view.
  77. var zoomSaved = element.attributes["data-zoom"];
  78. // Get the id of the div element.
  79. var divId = element.attributes["id"];
  80. // Get the numeric part of divId: leaflet_div-1399121271748.
  81. // We'll use that number for quick fetching of target iframe.
  82. var iframeId = "leaflet_iframe-" + divId.substring(12);
  83. // Get the zoom level's snapshot because the current user
  84. // might have changed it via mouse events or via the zoom bar.
  85. // Basically, get the zoom level of a map embedded
  86. // in this specific iframe and widget.
  87. var zoomIframe = editor.document.$.getElementById(iframeId).contentDocument.getElementById("map_container").getAttribute("data-zoom");
  88. // In case there are changes in zoom level.
  89. if (zoomIframe != zoomSaved) {
  90. // Update the saved zoom value in data attribute.
  91. element.attributes["data-zoom"] = zoomIframe;
  92. // Fetch the data attributes needed for
  93. // updating the full path of the map.
  94. var latitude = element.attributes["data-lat"];
  95. var longitude = element.attributes["data-lon"];
  96. var width = element.attributes["data-width"];
  97. var height = element.attributes["data-height"];
  98. var zoom = element.attributes["data-zoom"];
  99. var popUpText = element.attributes["data-popup-text"];
  100. var tile = element.attributes["data-tile"];
  101. var minimap = element.attributes["data-minimap"];
  102. // Build the updated full path to the map renderer.
  103. var mapParserPathFull = mapParserPath + "?lat=" + latitude + "&lon=" + longitude + "&width=" + width + "&height=" + height + "&zoom=" + zoom + "&text=" + popUpText + "&tile=" + tile + "&minimap=" + minimap;
  104. // Update also the iframe's 'src' attributes.
  105. // Updating 'data-cke-saved-src' is also required for
  106. // internal use of CKEditor.
  107. element.children[0].attributes["src"] = mapParserPathFull;
  108. element.children[0].attributes["data-cke-saved-src"] = mapParserPathFull;
  109. }
  110. // Return the DOM's textual representation.
  111. return element;
  112. },
  113. // Required property also for widgets, used when switching
  114. // from CKEditor's Source Mode to View Mode.
  115. // The reverse of downcast() method.
  116. upcast: function(element) {
  117. // If we encounter a div with a class of 'leaflet_div',
  118. // it means that it's a widget and we need to convert it properly
  119. // to its original structure.
  120. // Basically, it says to CKEditor which div is a valid widget.
  121. if (element.name == 'div' && element.hasClass('leaflet_div')) {
  122. return element;
  123. }
  124. },
  125. });
  126. // Add the widget button in the toolbar and bind the widget command,
  127. // which is also bound to the Dialog command.
  128. // Apparently, this is required just like their plugin counterpart.
  129. editor.ui.addButton('leaflet', {
  130. label : 'Leaflet Map',
  131. command : 'leaflet',
  132. icon : this.path + 'icons/leaflet.png',
  133. toolbar: "insert,1"
  134. });
  135. // Append the widget's styles when in the CKEditor edit page,
  136. // added for better user experience.
  137. // Assign or append the widget's styles depending on the existing setup.
  138. if (typeof editor.config.contentsCss == 'object') {
  139. editor.config.contentsCss.push(CKEDITOR.getUrl(this.path + 'css/contents.css'));
  140. }
  141. else {
  142. editor.config.contentsCss = [editor.config.contentsCss, CKEDITOR.getUrl(this.path + 'css/contents.css')];
  143. }
  144. },
  145. });
  146. })();