Projet

Général

Profil

Paste
Télécharger (11,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ckeditor / plugins / media / library.js @ 6fd71452

1

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

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

    
10
  Drupal.settings.ckeditor.plugins['media'] = {
11

    
12
    /**
13
       * Initializes the tag map.
14
       */
15
    initializeTagMap: function () {
16
      if (typeof Drupal.settings.tagmap == 'undefined') {
17
        Drupal.settings.tagmap = { };
18
      }
19
    },
20
    /**
21
       * Execute the button.
22
       */
23
    invoke: function (data, settings, instanceId) {
24
      if (data.format == 'html') {
25
        Drupal.media.popups.mediaBrowser(function (mediaFiles) {
26
          Drupal.settings.ckeditor.plugins['media'].mediaBrowserOnSelect(mediaFiles, instanceId);
27
        }, settings['global']);
28
      }
29
    },
30

    
31
    /**
32
       * Respond to the mediaBrowser's onSelect event.
33
       */
34
    mediaBrowserOnSelect: function (mediaFiles, instanceId) {
35
      var mediaFile = mediaFiles[0];
36
      var options = {};
37
      Drupal.media.popups.mediaStyleSelector(mediaFile, function (formattedMedia) {
38
        Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, formattedMedia.type, formattedMedia.html, formattedMedia.options, CKEDITOR.instances[instanceId]);
39
      }, options);
40

    
41
      return;
42
    },
43

    
44
    insertMediaFile: function (mediaFile, viewMode, formattedMedia, options, ckeditorInstance) {
45

    
46
      this.initializeTagMap();
47
      // @TODO: the folks @ ckeditor have told us that there is no way
48
      // to reliably add wrapper divs via normal HTML.
49
      // There is some method of adding a "fake element"
50
      // But until then, we're just going to embed to img.
51
      // This is pretty hacked for now.
52
      //
53
      var imgElement = $(this.stripDivs(formattedMedia));
54
      this.addImageAttributes(imgElement, mediaFile.fid, viewMode, options);
55

    
56
      var toInsert = this.outerHTML(imgElement);
57
      // Create an inline tag
58
      var inlineTag = Drupal.settings.ckeditor.plugins['media'].createTag(imgElement);
59
      // Add it to the tag map in case the user switches input formats
60
      Drupal.settings.tagmap[inlineTag] = toInsert;
61
      ckeditorInstance.insertHtml(toInsert);
62
    },
63

    
64
    /**
65
       * Gets the HTML content of an element
66
       *
67
       * @param jQuery element
68
       */
69
    outerHTML: function (element) {
70
      return $('<div>').append( element.eq(0).clone() ).html();
71
    },
72

    
73
    addImageAttributes: function (imgElement, fid, view_mode, additional) {
74
      imgElement.addClass('media-image');
75

    
76
      this.forceAttributesIntoClass(imgElement, fid, view_mode, additional);
77
    },
78

    
79
    /**
80
       * Due to problems handling wrapping divs in ckeditor, this is needed.
81
       *
82
       * Going forward, if we don't care about supporting other editors
83
       * we can use the fakeobjects plugin to ckeditor to provide cleaner
84
       * transparency between what Drupal will output <div class="field..."><img></div>
85
       * instead of just <img>, for now though, we're going to remove all the stuff surrounding the images.
86
       *
87
       * @param String formattedMedia
88
       *  Element containing the image
89
       *
90
       * @return HTML of <img> tag inside formattedMedia
91
       */
92
    stripDivs: function (formattedMedia) {
93
      // Check to see if the image tag has divs to strip
94
      var stripped = null;
95
      if ($(formattedMedia).is('img')) {
96
        stripped = this.outerHTML($(formattedMedia));
97
      } else {
98
        stripped = this.outerHTML($('img', $(formattedMedia)));
99
      }
100
      // This will fail if we pass the img tag without anything wrapping it, like we do when re-enabling ckeditor
101
      return stripped;
102
    },
103

    
104
    /**
105
       * Attach function, called when a rich text editor loads.
106
       * This finds all [[tags]] and replaces them with the html
107
       * that needs to show in the editor.
108
       *
109
       */
110
    attach: function (content, settings, instanceId) {
111
      var matches = content.match(/\[\[.*?\]\]/g);
112
      this.initializeTagMap();
113
      var tagmap = Drupal.settings.tagmap;
114
      if (matches) {
115
        var inlineTag = "";
116
        for (i = 0; i < matches.length; i++) {
117
          inlineTag = matches[i];
118
          if (tagmap[inlineTag]) {
119
            // This probably needs some work...
120
            // We need to somehow get the fid propogated here.
121
            // We really want to
122
            var tagContent = tagmap[inlineTag];
123
            var mediaMarkup = this.stripDivs(tagContent); // THis is <div>..<img>
124

    
125
            var _tag = inlineTag;
126
            _tag = _tag.replace('[[','');
127
            _tag = _tag.replace(']]','');
128
            mediaObj = JSON.parse(_tag);
129

    
130
            var imgElement = $(mediaMarkup);
131
            this.addImageAttributes(imgElement, mediaObj.fid, mediaObj.view_mode);
132
            var toInsert = this.outerHTML(imgElement);
133
            content = content.replace(inlineTag, toInsert);
134
          }
135
          else {
136
            debug.debug("Could not find content for " + inlineTag);
137
          }
138
        }
139
      }
140
      return content;
141
    },
142

    
143
    /**
144
       * Detach function, called when a rich text editor detaches
145
       */
146
    detach: function (content, settings, instanceId) {
147
      var content = $('<div>' + content + '</div>');
148
      $('img.media-image',content).each(function (elem) {
149
        var tag = Drupal.settings.ckeditor.plugins['media'].createTag($(this));
150
        $(this).replaceWith(tag);
151
        var newContent = content.html();
152
        var tagContent = $('<div></div>').append($(this)).html();
153
        Drupal.settings.tagmap[tag] = tagContent;
154
      });
155
      return content.html();
156
    },
157

    
158
    /**
159
       * @param jQuery imgNode
160
       *  Image node to create tag from
161
       */
162
    createTag: function (imgNode) {
163
      // Currently this is the <img> itself
164
      // Collect all attribs to be stashed into tagContent
165
      var mediaAttributes = {};
166
      var imgElement = imgNode[0];
167
      var sorter = [];
168

    
169
      // @todo: this does not work in IE, width and height are always 0.
170
      for (i=0; i< imgElement.attributes.length; i++) {
171
        var attr = imgElement.attributes[i];
172
        if (attr.specified == true) {
173
          if (attr.name !== 'class') {
174
            sorter.push(attr);
175
          }
176
          else {
177
            // Exctract expando properties from the class field.
178
            var attributes = this.getAttributesFromClass(attr.value);
179
            for (var name in attributes) {
180
              if (attributes.hasOwnProperty(name)) {
181
                var value = attributes[name];
182
                if (value.type && value.type === 'attr') {
183
                  sorter.push(value);
184
                }
185
              }
186
            }
187
          }
188
        }
189
      }
190

    
191
      sorter.sort(this.sortAttributes);
192

    
193
      for (var prop in sorter) {
194
        mediaAttributes[sorter[prop].name] = sorter[prop].value;
195
      }
196

    
197
      // The following 5 ifs are dedicated to IE7
198
      // If the style is null, it is because IE7 can't read values from itself
199
      if (jQuery.browser.msie && jQuery.browser.version == '7.0') {
200
        if (mediaAttributes.style === "null") {
201
          var imgHeight = imgNode.css('height');
202
          var imgWidth = imgNode.css('width');
203
          mediaAttributes.style = {
204
            height: imgHeight,
205
            width: imgWidth
206
          }
207
          if (!mediaAttributes['width']) {
208
            mediaAttributes['width'] = imgWidth;
209
          }
210
          if (!mediaAttributes['height']) {
211
            mediaAttributes['height'] = imgHeight;
212
          }
213
        }
214
        // If the attribute width is zero, get the CSS width
215
        if (Number(mediaAttributes['width']) === 0) {
216
          mediaAttributes['width'] = imgNode.css('width');
217
        }
218
        // IE7 does support 'auto' as a value of the width attribute. It will not
219
        // display the image if this value is allowed to pass through
220
        if (mediaAttributes['width'] === 'auto') {
221
          delete mediaAttributes['width'];
222
        }
223
        // If the attribute height is zero, get the CSS height
224
        if (Number(mediaAttributes['height']) === 0) {
225
          mediaAttributes['height'] = imgNode.css('height');
226
        }
227
        // IE7 does support 'auto' as a value of the height attribute. It will not
228
        // display the image if this value is allowed to pass through
229
        if (mediaAttributes['height'] === 'auto') {
230
          delete mediaAttributes['height'];
231
        }
232
      }
233

    
234
      // Remove elements from attribs using the blacklist
235
      for (var blackList in Drupal.settings.media.blacklist) {
236
        delete mediaAttributes[Drupal.settings.media.blacklist[blackList]];
237
      }
238
      tagContent = {
239
        "type": 'media',
240
        // @todo: This will be selected from the format form
241
        "view_mode": attributes['view_mode'].value,
242
        "fid" : attributes['fid'].value,
243
        "attributes": mediaAttributes
244
      };
245
      return '[[' + JSON.stringify(tagContent) + ']]';
246
    },
247

    
248
    /**
249
       * Forces custom attributes into the class field of the specified image.
250
       *
251
       * Due to a bug in some versions of Firefox
252
       * (http://forums.mozillazine.org/viewtopic.php?f=9&t=1991855), the
253
       * custom attributes used to share information about the image are
254
       * being stripped as the image markup is set into the rich text
255
       * editor.  Here we encode these attributes into the class field so
256
       * the data survives.
257
       *
258
       * @param imgElement
259
       *   The image
260
       * @fid
261
       *   The file id.
262
       * @param view_mode
263
       *   The view mode.
264
       * @param additional
265
       *   Additional attributes to add to the image.
266
       */
267
    forceAttributesIntoClass: function (imgElement, fid, view_mode, additional) {
268
      var wysiwyg = imgElement.attr('wysiwyg');
269
      if (wysiwyg) {
270
        imgElement.addClass('attr__wysiwyg__' + wysiwyg);
271
      }
272
      var format = imgElement.attr('format');
273
      if (format) {
274
        imgElement.addClass('attr__format__' + format);
275
      }
276
      var typeOf = imgElement.attr('typeof');
277
      if (typeOf) {
278
        imgElement.addClass('attr__typeof__' + typeOf);
279
      }
280
      if (fid) {
281
        imgElement.addClass('img__fid__' + fid);
282
      }
283
      if (view_mode) {
284
        imgElement.addClass('img__view_mode__' + view_mode);
285
      }
286
      if (additional) {
287
        for (var name in additional) {
288
          if (additional.hasOwnProperty(name)) {
289
            if (name !== 'alt') {
290
              imgElement.addClass('attr__' + name + '__' + additional[name]);
291
            }
292
          }
293
        }
294
      }
295
    },
296

    
297
    /**
298
       * Retrieves encoded attributes from the specified class string.
299
       *
300
       * @param classString
301
       *   A string containing the value of the class attribute.
302
       * @return
303
       *   An array containing the attribute names as keys, and an object
304
       *   with the name, value, and attribute type (either 'attr' or
305
       *   'img', depending on whether it is an image attribute or should
306
       *   be it the attributes section)
307
       */
308
    getAttributesFromClass: function (classString) {
309
      var actualClasses = [];
310
      var otherAttributes = [];
311
      var classes = classString.split(' ');
312
      var regexp = new RegExp('^(attr|img)__([^\S]*)__([^\S]*)$');
313
      for (var index = 0; index < classes.length; index++) {
314
        var matches = classes[index].match(regexp);
315
        if (matches && matches.length === 4) {
316
          otherAttributes[matches[2]] = {
317
            name: matches[2],
318
            value: matches[3],
319
            type: matches[1]
320
          };
321
        }
322
        else {
323
          actualClasses.push(classes[index]);
324
        }
325
      }
326
      if (actualClasses.length > 0) {
327
        otherAttributes['class'] = {
328
          name: 'class',
329
          value: actualClasses.join(' '),
330
          type: 'attr'
331
        };
332
      }
333
      return otherAttributes;
334
    },
335

    
336
    sortAttributes: function (a, b) {
337
      var nameA = a.name.toLowerCase();
338
      var nameB = b.name.toLowerCase();
339
      if (nameA < nameB) {
340
        return -1;
341
      }
342
      if (nameA > nameB) {
343
        return 1;
344
      }
345
      return 0;
346
    }
347
  };
348

    
349
})(jQuery);