Projet

Général

Profil

Paste
Télécharger (12,4 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / media_ckeditor / js / plugins / media / plugin.js @ 5d940405

1
/*
2
Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
3
For licensing, see LICENSE.html or http://ckeditor.com/license
4
*/
5

    
6
/**
7
 * @file Plugin for inserting images from Drupal media module
8
 *
9
 * @TODO Remove all the legecy media wrapper once it's sure nobody uses that
10
 * anymore.
11
 */
12
( function() {
13
  var mediaPluginDefinition = {
14
    icons: 'media',
15
    requires: ['button'],
16
    // All the default distributions of the editor have the widget plugin
17
    // disabled by default.
18
    hasWidgetSupport: false,
19
    mediaLegacyWrappers: false,
20
    hidpi: true,
21
    onLoad: function() {
22
      // Check if Image Properties option is set, and this instance has widget support.
23
      if (!Drupal.settings.media_ckeditor.image_properties) {
24
        mediaPluginDefinition.hasWidgetSupport = typeof(CKEDITOR.plugins.registered.widget) != 'undefined';
25
      }
26
      // Add dependency to widget plugin if possible.
27
      if (Drupal.settings.ckeditor.plugins['media'].compareVersions(CKEDITOR.version, '4.3') >= 0 && mediaPluginDefinition.hasWidgetSupport) {
28
        mediaPluginDefinition.requires.push('widget');
29
      }
30
    },
31

    
32
    // Wrap Drupal plugin in a proxy plugin.
33
    init: function(editor){
34
      editor.addCommand( 'media',
35
      {
36
        exec: function (editor) {
37
          var data = {
38
            format: 'html',
39
            node: null,
40
            content: ''
41
          };
42
          var selection = editor.getSelection();
43
          if (selection) {
44
            data.node = selection.getSelectedElement();
45

    
46
            if (data.node) {
47
              data.node = data.node.$;
48
            }
49
            if (selection.getType() == CKEDITOR.SELECTION_TEXT) {
50
              if (CKEDITOR.env.ie && CKEDITOR.env.version < 10) {
51
                data.content = selection.getNative().createRange().text;
52
              }
53
              else {
54
                data.content = selection.getNative().toString();
55
              }
56
            }
57
            else if (data.node) {
58
              // content is supposed to contain the "outerHTML".
59
              data.content = data.node.parentNode.innerHTML;
60
            }
61
          }
62

    
63
          // If we are inside another media element, we need to move the cursor to the end of the element
64
          var selected_element = selection.getStartElement();
65
          var parent = selected_element.getParent();
66
          //if we are inside "a" tag and inside "span" (with class media-element)
67
          if (selected_element.is('a') && parent.is('span') && parent.hasClass('media-element')) {
68
            selection.selectElement(parent);
69
            selected_ranges = selection.getRanges();
70
            selected_ranges[0].collapse(false);
71
            selection.selectRanges(selected_ranges);
72
          }
73
          //if we are outside "a" tag but inside "span" (with class media-element)
74
          else if (selected_element.is('span') && selected_element.hasClass('media-element')) {
75
              selection.selectElement(selected_element);
76
              selected_ranges = selection.getRanges();
77
              selected_ranges[0].collapse(false);
78
              selection.selectRanges(selected_ranges);
79
          }
80
          Drupal.settings.ckeditor.plugins['media'].invoke(data, Drupal.settings.ckeditor.plugins['media'], editor.name);
81
        }
82
      });
83

    
84
      // Add a Ckeditor context menu item for editing already-inserted media.
85
      if (editor.contextMenu) {
86
        editor.addCommand('mediaConfigure', {
87
          exec: function (editor) {
88
            editor.execCommand('media');
89
          },
90
        });
91

    
92
        editor.addMenuGroup('mediaGroup');
93
        editor.addMenuItem('mediaConfigureItem', {
94
          label: Drupal.settings.media_ckeditor.labels['settings'],
95
          icon: this.path + 'icons/media.png',
96
          command: 'mediaConfigure',
97
          group: 'mediaGroup'
98
        });
99

    
100
        editor.contextMenu.addListener(function(element) {
101
          if (element.getAttribute('data-media-element') ||
102
              element.find('[data-media-element]').count()) {
103
            return { mediaConfigureItem: CKEDITOR.TRISTATE_OFF };
104
          };
105
        });
106
      }
107

    
108
      // Add the toolbar button.
109
      editor.ui.addButton( 'Media',
110
      {
111
        label: Drupal.settings.media_ckeditor.labels['add'],
112
        command: 'media'
113
      });
114

    
115
      // Because the media comment wrapper don't work well for CKEditor we
116
      // replace them by using a custom mediawrapper element.
117
      // Instead having
118
      // <!--MEDIA-WRAPPER-START-1--><img /><!--MEDIA-WRAPPER-END-1-->
119
      // We wrap the placeholder with
120
      // <mediawrapper data="1"><img /></mediawrapper>
121
      // That way we can deal better with selections - see selectionChange.
122
      CKEDITOR.dtd['mediawrapper'] = CKEDITOR.dtd;
123
      CKEDITOR.dtd.$blockLimit['mediawrapper'] = 1;
124
      CKEDITOR.dtd.$inline['mediawrapper'] = 1;
125
      CKEDITOR.dtd.$nonEditable['mediawrapper'] = 1;
126
      if (Drupal.settings.ckeditor.plugins['media'].compareVersions(CKEDITOR.version, '4.1') >= 0) {
127
        // Register allowed tag for advanced filtering.
128
        editor.filter.allow( 'mediawrapper[!data]', 'mediawrapper', true);
129
        // Don't remove the data-file_info attribute added by media!
130
        editor.filter.allow( '*[!data-file_info]', 'mediawrapper', true);
131
        // Ensure image tags accept all kinds of attributes.
132
        editor.filter.allow( 'img[*]{*}(*)', 'mediawrapper', true);
133
        // Objects should be selected as a whole in the editor.
134
        CKEDITOR.dtd.$object['mediawrapper'] = 1;
135
      }
136
      function prepareDataForWysiwygMode(data) {
137
        if (typeof Drupal.media !== 'undefined') {
138
          data = Drupal.media.filter.replaceTokenWithPlaceholder(data);
139
        }
140
        // Legacy media wrapper.
141
        mediaPluginDefinition.mediaLegacyWrappers = (data.indexOf("<!--MEDIA-WRAPPER-START-") !== -1);
142
        if (mediaPluginDefinition.mediaLegacyWrappers) {
143
          data = data.replace(/<!--MEDIA-WRAPPER-START-(\d+)-->(.*?)<!--MEDIA-WRAPPER-END-\d+-->/gi, '<mediawrapper data="$1">$2</mediawrapper>');
144
        }
145
        return data;
146
      }
147
      function prepareDataForSourceMode(data) {
148
        var replacement = '$2';
149
        // Legacy wrapper
150
        if (mediaPluginDefinition.mediaLegacyWrappers) {
151
          replacement = '<!--MEDIA-WRAPPER-START-$1-->$2<!--MEDIA-WRAPPER-END-$1-->';
152
        }
153
        data = data.replace(/<mediawrapper data="(.*?)">(.*?)<\/mediawrapper>/gi, replacement);
154
        if (typeof Drupal.media !== 'undefined') {
155
          data = Drupal.media.filter.replacePlaceholderWithToken(data);
156
        }
157
        return data;
158
      }
159

    
160
      // Ensure the tokens are replaced by placeholders while editing.
161
      // Check for widget support.
162
      if (mediaPluginDefinition.hasWidgetSupport) {
163
        editor.widgets.add( 'mediabox',
164
        {
165
          button: 'Create a mediabox',
166
          editables: {},
167
          allowedContent: '*',
168
          upcast: function( element ) {
169
            // Ensure media tokens are converted to media placeholders.
170
            html = Drupal.media.filter.replaceTokenWithPlaceholder(element.getHtml());
171
            // Only replace html if it's different
172
            if (html != element.getHtml()) {
173
              element.setHtml(html);
174
              // CKEditor's setHtml() method automatically fixes the HTML that
175
              // it receives, which means that if it gets an <li> without a
176
              // <ul> or <ol> parent, it adds a <ul>. These extra <ul> tags just
177
              // keep piling up every time this function runs. So check here to
178
              // see if we may need to fix this.
179
              if (element.children && element.children[0]) {
180
                // We identify this by looking for a <ul> inside a <ul> or <ol>.
181
                if (('ul' === element.name && 'ul' === element.children[0].name) ||
182
                    ('ol' === element.name && 'ul' === element.children[0].name)) {
183
                  // If this did happen, fix it by promoting the grandchildren
184
                  // (ie, actual list items) to children.
185
                  element.children = element.children[0].children;
186
                }
187
              }
188
            }
189
            return element.name == 'mediawrapper' || 'data-media-element' in element.attributes;
190
          },
191

    
192
          downcast: function( widgetElement ) {
193
            var token = Drupal.media.filter.replacePlaceholderWithToken(widgetElement.getOuterHtml());
194
            if (token) {
195
              return new CKEDITOR.htmlParser.text(token);
196
            }
197
            return false;
198
          },
199

    
200
          init: function() {
201
            // Add double-click functionality to the widget.
202
            this.on('doubleclick', function(evt) {
203
              editor.execCommand('media');
204
            }, null, null, 5 );
205
          }
206
        });
207
      }
208
      else if (Drupal.settings.ckeditor.plugins['media'].compareVersions(CKEDITOR.version, '4') >= 0) {
209
        // CKEditor >=4.0
210
        editor.on('setData', function( event ) {
211
          event.data.dataValue = prepareDataForWysiwygMode(event.data.dataValue);
212
        });
213
      }
214
      else {
215
        // CKEditor >=3.6 behaviour.
216
        editor.on( 'beforeSetMode', function( event, data ) {
217
          event.removeListener();
218
          var wysiwyg = editor._.modes[ 'wysiwyg' ];
219
          var source = editor._.modes[ 'source' ];
220
          wysiwyg.loadData = CKEDITOR.tools.override( wysiwyg.loadData, function( org )
221
          {
222
            return function( data ) {
223
              return ( org.call( this, prepareDataForWysiwygMode(data)) );
224
            };
225
          } );
226
          source.loadData = CKEDITOR.tools.override( source.loadData, function( org )
227
          {
228
            return function( data ) {
229
              return ( org.call( this, prepareDataForSourceMode(data) ) );
230
            };
231
          } );
232
        });
233
      }
234

    
235
      // Provide alternative to the widget functionality introduced in 4.3.
236
      if (!mediaPluginDefinition.hasWidgetSupport) {
237
        // Ensure tokens instead the html element is saved.
238
        editor.on('getData', function( event ) {
239
          event.data.dataValue = prepareDataForSourceMode(event.data.dataValue);
240
        });
241

    
242
        // Ensure our enclosing wrappers are always included in the selection.
243
        editor.on('selectionChange', function( event ) {
244
          var ranges = editor.getSelection().getRanges().createIterator();
245
          var newRanges = [];
246
          var currRange;
247
          while(currRange = ranges.getNextRange()) {
248
            var commonAncestor = currRange.getCommonAncestor(false);
249
            if (commonAncestor && typeof(commonAncestor.getName) != 'undefined' && commonAncestor.getName() == 'mediawrapper') {
250
              var range = new CKEDITOR.dom.range( editor.document );
251
              if (currRange.collapsed === true) {
252
                // Don't allow selection within the wrapper element.
253
                if (currRange.startOffset == 0) {
254
                  // While v3 plays nice with setting start and end to avoid
255
                  // editing within the media wrapper element, v4 ignores that.
256
                  // Thus we try to move the cursor further away.
257
                  if (Drupal.settings.ckeditor.plugins['media'].compareVersions(CKEDITOR.version, '3') > 0) {
258
                    range.setStart(commonAncestor.getPrevious());
259
                    range.setEnd(commonAncestor.getPrevious());
260
                  }
261
                  else {
262
                    range.setStartBefore(commonAncestor);
263
                  }
264
                }
265
                else {
266
                  // While v3 plays nice with setting start and end to avoid
267
                  // editing within the media wrapper element, v4 ignores that.
268
                  // Thus we try to move the cursor further away.
269
                  if (Drupal.settings.ckeditor.plugins['media'].compareVersions(CKEDITOR.version, '3') > 0) {
270
                    range.setStart(commonAncestor.getNext(), 1);
271
                    range.setEnd(commonAncestor.getNext(), 1);
272
                  }
273
                  else {
274
                    range.setStartAfter(commonAncestor);
275
                  }
276
                }
277
              }
278
              else {
279
                // Always select the whole wrapper element.
280
                range.setStartBefore(commonAncestor);
281
                range.setEndAfter(commonAncestor);
282
              }
283
              newRanges.push(range);
284
            }
285
          }
286
          if (newRanges.length) {
287
            editor.getSelection().selectRanges(newRanges);
288
          }
289
        });
290
      }
291
    }
292
  };
293

    
294
  CKEDITOR.plugins.add( 'media', mediaPluginDefinition);
295
} )();