Projet

Général

Profil

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

root / drupal7 / sites / all / modules / media_ckeditor / js / plugins / media / library.js @ 59ae487e

1

    
2
/**
3
 *  @file
4
 *  Attach Media ckeditor behaviors.
5
 */
6

    
7
(function ($) {
8
  Drupal.media = Drupal.media || {};
9

    
10
  /**
11
   * Attaches 'insert' button to media widget.
12
   */
13
  Drupal.behaviors.mediaWidgetInsert = {
14
    attach: function (context, settings) {
15
      if (Drupal.ckeditorInstance && Drupal.settings.media_ckeditor && Drupal.settings.media_ckeditor.wysiwyg_insert) {
16
        // Only add buttons on fields that have been configured so, by
17
        // consulting the Drupal.settings.media_ckeditor.wysiwyg_insert var.
18
        for (var fieldName in Drupal.settings.media_ckeditor.wysiwyg_insert) {
19
          var fieldId = '#edit-' + fieldName.replace(/_/g, '-');
20
          // Within the field markup, look for the table of files.
21
          $(fieldId, context).find('.media-widget').once('mediaInsertButton', function() {
22
            // For each file, check to see if there is a file ID.
23
            if ($(this).find('input.fid').val() != 0) {
24
              // Now we add the button next to "Remove".
25
              var insertButton = $('<a class="media-insert button">' + Drupal.t('Insert') + '</a>')
26
                .click(function(e) {
27
                  e.preventDefault();
28
                  var fid = $(this).parent().parent().find('.fid').val();
29
                  var mediaFile = {fid: fid}
30
                  Drupal.ckeditorInstance.mediaInsert = {mediaFiles: [mediaFile]};
31
                  Drupal.ckeditorInstance.execCommand('media');
32
                });
33
              // Insert the button, differently for single vs. multi value.
34
              var multiValue = $(fieldId + ' table', context).length;
35
              if (multiValue) {
36
                insertButton.insertBefore($(this).parent().parent().find('input.remove'));
37
              }
38
              else {
39
                insertButton.insertBefore($(this).find('input.remove'));
40
              }
41
            }
42
          });
43
        }
44
      }
45
    }
46
  };
47

    
48
  Drupal.settings.ckeditor.plugins['media'] = {
49
    /**
50
     * Execute the button.
51
     */
52
    invoke: function (data, settings, instanceId) {
53
      if (data.format == 'html') {
54
        // CKEDITOR module support doesn't set this setting
55
        if (typeof settings['global'] === 'undefined') {
56
          settings['global'] = {id: 'media_wysiwyg'};
57
        }
58
        // If the selection is (or contains) an element with the attribute of
59
        // "data-media-element", assume the user wants to edit that thing.
60
        var $alreadyInsertedMedia;
61
        if (jQuery(data.node).is('[data-media-element]')) {
62
          $alreadyInsertedMedia = jQuery(data.node);
63
        }
64
        else {
65
          $alreadyInsertedMedia = jQuery(data.node).find('[data-media-element]');
66
        }
67
        // First check to see if we are using an Insert button.
68
        if (typeof Drupal.ckeditorInstance.mediaInsert !== 'undefined') {
69
          var mediaFile = Drupal.ckeditorInstance.mediaInsert.mediaFiles[0];
70
          delete Drupal.ckeditorInstance.mediaInsert;
71
          Drupal.media.popups.mediaStyleSelector(mediaFile, function (mediaFiles) {
72
            Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, mediaFiles, CKEDITOR.instances[instanceId]);
73
          }, settings['global']);
74
        }
75
        // Next check to see if we are editing already-inserted media.
76
        else if ($alreadyInsertedMedia.length) {
77
          var mediaFile = Drupal.media.filter.extract_file_info($alreadyInsertedMedia);
78
          Drupal.media.popups.mediaStyleSelector(mediaFile, function (mediaFiles) {
79
            Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, mediaFiles, CKEDITOR.instances[instanceId]);
80
          }, settings['global']);
81
        }
82
        // Otherwise we are embedding new media.
83
        else {
84
          Drupal.media.popups.mediaBrowser(function (mediaFiles) {
85
            Drupal.settings.ckeditor.plugins['media'].mediaBrowserOnSelect(mediaFiles, instanceId);
86
          }, settings['global']);
87
        }
88
      }
89
    },
90

    
91
    /**
92
     * Respond to the mediaBrowser's onSelect event.
93
     */
94
    mediaBrowserOnSelect: function (mediaFiles, instanceId) {
95
      var mediaFile = mediaFiles[0];
96
      var options = {};
97
      Drupal.media.popups.mediaStyleSelector(mediaFile, function (formattedMedia) {
98
        Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, formattedMedia, CKEDITOR.instances[instanceId]);
99
      }, options);
100

    
101
      return;
102
    },
103

    
104
    insertMediaFile: function (mediaFile, formattedMedia, ckeditorInstance, fullyRenderedFile) {
105

    
106
      // See if we should use ajax to get the fully rendered file.
107
      if (typeof fullyRenderedFile === 'undefined' &&
108
          Drupal.settings.media_ckeditor.fully_rendered_files) {
109

    
110
        $.ajax({
111
          url: Drupal.settings.basePath + 'media/rendered-in-wysiwyg',
112
          type: 'GET',
113
          data: {
114
            fid: mediaFile.fid,
115
            view_mode: formattedMedia.type,
116
            fields: formattedMedia.options
117
          },
118
          success: function(html) {
119
            // To work around an IE issue, preload any image. The issue is
120
            // that IE requests the image 2 times, and one request gets a 503,
121
            // causing a broken image icon in the WYSIWYG instead of the actual
122
            // image.
123
            var $images = $(html).find('img');
124
            if (!$images.length || $(html).find('picture').length) {
125
              // If there are no images, just insert the html immediately, by
126
              // re-calling this function with the ajax-retrieved HTML.
127
              Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, formattedMedia, ckeditorInstance, html);
128
            }
129
            else {
130
              // Otherwise do the same, but only after the first image preloads.
131
              // Possible future improvement might be to handle multiple images
132
              // instead of just the first, but even better would be to remove
133
              // this workaround entirely, when/if IE's behavior changes.
134
              var image = new Image();
135
              image.onload = function() {
136
                Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, formattedMedia, ckeditorInstance, html);
137
              }
138
              image.src = $images.first().attr('src');
139
            }
140
          },
141
          error: function(data) {
142
            // Fallback to whatever the HTML was already going to be.
143
            Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, formattedMedia, ckeditorInstance, formattedMedia.html);
144
          }
145
        });
146

    
147
        // Stop for now, because the callback above re-calls this same function.
148
        return;
149
      }
150

    
151
      // See if we already used ajax to get the fully rendered file.
152
      if (typeof fullyRenderedFile !== 'undefined') {
153
        formattedMedia.html = fullyRenderedFile;
154
      }
155

    
156
      // Customization of Drupal.media.filter.registerNewElement().
157
      var element = Drupal.media.filter.create_element(formattedMedia.html, {
158
        fid: mediaFile.fid,
159
        view_mode: formattedMedia.type,
160
        attributes: mediaFile.attributes,
161
        fields: formattedMedia.options
162
      });
163

    
164
      var hasWidgetSupport = typeof(CKEDITOR.plugins.registered.widget) != 'undefined';
165

    
166
      // Use own wrapper element to be able to properly deal with selections.
167
      // Check prepareDataForWysiwygMode() in plugin.js for details.
168
      var wysiwygHTML = Drupal.media.filter.getWysiwygHTML(element);
169

    
170
      if (wysiwygHTML.indexOf("<!--MEDIA-WRAPPER-START-") !== -1) {
171
        ckeditorInstance.plugins.media.mediaLegacyWrappers = true;
172
        wysiwygHTML = wysiwygHTML.replace(/<!--MEDIA-WRAPPER-START-(\d+)-->(.*?)<!--MEDIA-WRAPPER-END-\d+-->/gi, '');
173
      }
174

    
175
      // Insert element. Use CKEDITOR.dom.element.createFromHtml to ensure our
176
      // custom wrapper element is preserved.
177
      var editorElement = CKEDITOR.dom.element.createFromHtml(wysiwygHTML);
178
      ckeditorInstance.insertElement(editorElement);
179

    
180
      // Initialize widget on our html if possible.
181
      if (parseFloat(CKEDITOR.version) >= 4.3 && hasWidgetSupport) {
182
        ckeditorInstance.widgets.initOn( editorElement, 'mediabox' );
183

    
184
        // Also support the image2 plugin.
185
        ckeditorInstance.widgets.initOn( editorElement, 'image' );
186
      }
187
    },
188

    
189
    /**
190
     * Forces custom attributes into the class field of the specified image.
191
     *
192
     * Due to a bug in some versions of Firefox
193
     * (http://forums.mozillazine.org/viewtopic.php?f=9&t=1991855), the
194
     * custom attributes used to share information about the image are
195
     * being stripped as the image markup is set into the rich text
196
     * editor.  Here we encode these attributes into the class field so
197
     * the data survives.
198
     *
199
     * @param imgElement
200
     *   The image
201
     * @fid
202
     *   The file id.
203
     * @param view_mode
204
     *   The view mode.
205
     * @param additional
206
     *   Additional attributes to add to the image.
207
     */
208
    forceAttributesIntoClass: function (imgElement, fid, view_mode, additional) {
209
      var wysiwyg = imgElement.attr('wysiwyg');
210
      if (wysiwyg) {
211
        imgElement.addClass('attr__wysiwyg__' + wysiwyg);
212
      }
213
      var format = imgElement.attr('format');
214
      if (format) {
215
        imgElement.addClass('attr__format__' + format);
216
      }
217
      var typeOf = imgElement.attr('typeof');
218
      if (typeOf) {
219
        imgElement.addClass('attr__typeof__' + typeOf);
220
      }
221
      if (fid) {
222
        imgElement.addClass('img__fid__' + fid);
223
      }
224
      if (view_mode) {
225
        imgElement.addClass('img__view_mode__' + view_mode);
226
      }
227
      if (additional) {
228
        for (var name in additional) {
229
          if (additional.hasOwnProperty(name)) {
230
            switch (name) {
231
              case 'field_file_image_alt_text[und][0][value]':
232
                imgElement.attr('alt', additional[name]);
233
                break;
234
              case 'field_file_image_title_text[und][0][value]':
235
                imgElement.attr('title', additional[name]);
236
                break;
237
              default:
238
                imgElement.addClass('attr__' + name + '__' + additional[name]);
239
                break;
240
            }
241
          }
242
        }
243
      }
244
    },
245

    
246
    /**
247
     * Retrieves encoded attributes from the specified class string.
248
     *
249
     * @param classString
250
     *   A string containing the value of the class attribute.
251
     * @return
252
     *   An array containing the attribute names as keys, and an object
253
     *   with the name, value, and attribute type (either 'attr' or
254
     *   'img', depending on whether it is an image attribute or should
255
     *   be it the attributes section)
256
     */
257
    getAttributesFromClass: function (classString) {
258
      var actualClasses = [];
259
      var otherAttributes = [];
260
      var classes = classString.split(' ');
261
      var regexp = new RegExp('^(attr|img)__([^\S]*)__([^\S]*)$');
262
      for (var index = 0; index < classes.length; index++) {
263
        var matches = classes[index].match(regexp);
264
        if (matches && matches.length === 4) {
265
          otherAttributes[matches[2]] = {
266
            name: matches[2],
267
            value: matches[3],
268
            type: matches[1]
269
          };
270
        }
271
        else {
272
          actualClasses.push(classes[index]);
273
        }
274
      }
275
      if (actualClasses.length > 0) {
276
        otherAttributes['class'] = {
277
          name: 'class',
278
          value: actualClasses.join(' '),
279
          type: 'attr'
280
        };
281
      }
282
      return otherAttributes;
283
    },
284

    
285
    sortAttributes: function (a, b) {
286
      var nameA = a.name.toLowerCase();
287
      var nameB = b.name.toLowerCase();
288
      if (nameA < nameB) {
289
        return -1;
290
      }
291
      if (nameA > nameB) {
292
        return 1;
293
      }
294
      return 0;
295
    }
296
  };
297

    
298
  // If media_ckeditor is configured to render items in the wysiwyg as full
299
  // rendered file entities, we need to completely hijack a function from
300
  // media_wysiwyg.filter.js.
301
  if (Drupal.settings.media_ckeditor.fully_rendered_files) {
302

    
303
    // Replaces function of the same name, from media_wysiwyg.filter.js.
304
    Drupal.media.filter.replacePlaceholderWithToken = function(content) {
305

    
306
      var $placeholder = $(content);
307
      if ($placeholder.hasClass('media-element')) {
308
        var macro = Drupal.media.filter.create_macro($placeholder);
309
        Drupal.media.filter.ensure_tagmap();
310
        Drupal.settings.tagmap[macro] = content;
311
        return macro;
312
      }
313
      return content;
314
    }
315
  }
316
})(jQuery);