locomotive-aloha-rails 0.20.1.2 → 0.20.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/Rakefile +1 -1
  2. data/lib/aloha/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/aloha/css/aloha.css +3 -0
  4. data/vendor/assets/javascripts/aloha/css/ext-aloha.css +3 -0
  5. data/vendor/assets/javascripts/aloha/lib/aloha-bootstrap.js +4565 -3934
  6. data/vendor/assets/javascripts/aloha/lib/aloha.js +1357 -702
  7. data/vendor/assets/javascripts/aloha/lib/aloha/command.js +16 -13
  8. data/vendor/assets/javascripts/aloha/lib/aloha/core.js +23 -3
  9. data/vendor/assets/javascripts/aloha/lib/aloha/ecma5shims.js +23 -7
  10. data/vendor/assets/javascripts/aloha/lib/aloha/editable.js +57 -14
  11. data/vendor/assets/javascripts/aloha/lib/aloha/engine.js +9 -5
  12. data/vendor/assets/javascripts/aloha/lib/aloha/floatingmenu.js +288 -96
  13. data/vendor/assets/javascripts/aloha/lib/aloha/jquery.js +11 -1
  14. data/vendor/assets/javascripts/aloha/lib/aloha/markup.js +318 -40
  15. data/vendor/assets/javascripts/aloha/lib/aloha/repositorymanager.js +11 -10
  16. data/vendor/assets/javascripts/aloha/lib/aloha/selection.js +20 -1
  17. data/vendor/assets/javascripts/aloha/lib/aloha/sidebar.js +11 -1
  18. data/vendor/assets/javascripts/aloha/lib/jquery-plugin.js +10 -7
  19. data/vendor/assets/javascripts/aloha/lib/util/dom.js +18 -6
  20. data/vendor/assets/javascripts/aloha/lib/util/range.js +6 -6
  21. data/vendor/assets/javascripts/aloha/lib/vendor/ext-3.2.1/ext-all-debug.js +26 -2
  22. data/vendor/assets/javascripts/aloha/lib/vendor/jquery.store.js +39 -15
  23. data/vendor/assets/javascripts/aloha/plugins/common/abbr/lib/abbr-plugin.js +1 -0
  24. data/vendor/assets/javascripts/aloha/plugins/common/align/lib/align-plugin.js +344 -334
  25. data/vendor/assets/javascripts/aloha/plugins/common/block/css/block.css +65 -12
  26. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/block-plugin.js +12 -15
  27. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/block.js +796 -180
  28. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/blockcontenthandler.js +54 -13
  29. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/blockmanager.js +315 -78
  30. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/editor.js +111 -8
  31. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/editormanager.js +2 -0
  32. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/jquery-ui-1.8.16.custom.min.js +198 -0
  33. data/vendor/assets/javascripts/aloha/plugins/common/block/lib/sidebarattributeeditor.js +7 -20
  34. data/vendor/assets/javascripts/aloha/plugins/common/characterpicker/lib/characterpicker-plugin.js +15 -3
  35. data/vendor/assets/javascripts/aloha/plugins/common/contenthandler/lib/sanitizecontenthandler.js +3 -2
  36. data/vendor/assets/javascripts/aloha/plugins/common/contenthandler/lib/wordcontenthandler.js +111 -5
  37. data/vendor/assets/javascripts/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml-plugin.js +29 -0
  38. data/vendor/assets/javascripts/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml.js +306 -0
  39. data/vendor/assets/javascripts/aloha/plugins/common/format/lib/format-plugin.js +59 -5
  40. data/vendor/assets/javascripts/aloha/plugins/common/format/nls/i18n.js +1 -1
  41. data/vendor/assets/javascripts/aloha/plugins/common/horizontalruler/lib/horizontalruler-plugin.js +18 -3
  42. data/vendor/assets/javascripts/aloha/plugins/common/image/img/crop-buttons.gif +0 -0
  43. data/vendor/assets/javascripts/aloha/plugins/common/image/lib/image-plugin.js +1629 -1601
  44. data/vendor/assets/javascripts/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.css +11 -0
  45. data/vendor/assets/javascripts/aloha/plugins/common/link/extra/linklist.js +8 -6
  46. data/vendor/assets/javascripts/aloha/plugins/common/link/lib/link-plugin.js +26 -10
  47. data/vendor/assets/javascripts/aloha/plugins/common/list/nls/de/i18n.js +5 -1
  48. data/vendor/assets/javascripts/aloha/plugins/common/paste/lib/paste-plugin.js +3 -4
  49. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-cell.js +13 -12
  50. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-plugin.js +108 -61
  51. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table-selection.js +61 -1
  52. data/vendor/assets/javascripts/aloha/plugins/common/table/lib/table.js +1 -0
  53. data/vendor/assets/javascripts/aloha/plugins/common/table/nls/de/i18n.js +28 -1
  54. data/vendor/assets/javascripts/aloha/plugins/common/table/nls/i18n.js +36 -10
  55. data/vendor/assets/javascripts/aloha/plugins/extra/browser/css/browser.jqgrid.css +292 -292
  56. data/vendor/assets/javascripts/aloha/plugins/extra/browser/lib/browser.js +28 -5
  57. data/vendor/assets/javascripts/aloha/plugins/extra/browser/lib/locale.js +2 -2
  58. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/grid.locale.de.js +6 -1
  59. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/grid.locale.en.js +5 -0
  60. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/jquery.jqGrid.js +5 -0
  61. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/jquery.jstree.js +6 -1
  62. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/jquery.ui.js +6 -1
  63. data/vendor/assets/javascripts/aloha/plugins/extra/browser/vendor/ui-layout.js +6 -1
  64. data/vendor/assets/javascripts/aloha/plugins/extra/cite/lib/cite-plugin.js +18 -4
  65. data/vendor/assets/javascripts/aloha/plugins/extra/formatlesspaste/lib/formatlesspaste-plugin.js +1 -1
  66. data/vendor/assets/javascripts/aloha/plugins/extra/linkbrowser/lib/linkbrowser-plugin.js +14 -2
  67. data/vendor/assets/javascripts/aloha/plugins/extra/numerated-headers/demo/js/aloha-config.js +2 -2
  68. data/vendor/assets/javascripts/aloha/plugins/extra/toc/lib/toc-plugin.js +382 -0
  69. data/vendor/assets/javascripts/aloha/plugins/extra/toc/nls/de/i18n.js +3 -0
  70. data/vendor/assets/javascripts/aloha/plugins/extra/toc/nls/i18n.js +4 -0
  71. metadata +15 -11
  72. data/vendor/assets/javascripts/aloha/plugins/extra/toc/i18n/de.json +0 -1
  73. data/vendor/assets/javascripts/aloha/plugins/extra/toc/i18n/en.json +0 -1
  74. data/vendor/assets/javascripts/aloha/plugins/extra/toc/src/toc.js +0 -350
@@ -5,8 +5,14 @@
5
5
  * Licensed unter the terms of http://www.aloha-editor.com/license.html
6
6
  */
7
7
  define(
8
- ['aloha', 'aloha/jquery', 'aloha/plugin', 'aloha/floatingmenu', 'i18n!characterpicker/nls/i18n', 'i18n!aloha/nls/i18n', 'css!characterpicker/css/characterpicker.css'],
9
- function(Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore) {
8
+ ['aloha',
9
+ 'aloha/jquery',
10
+ 'aloha/plugin',
11
+ 'aloha/floatingmenu',
12
+ 'i18n!characterpicker/nls/i18n',
13
+ 'i18n!aloha/nls/i18n',
14
+ 'css!characterpicker/css/characterpicker.css'],
15
+ function( Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore ) {
10
16
 
11
17
 
12
18
  var
@@ -207,10 +213,14 @@ function(Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore) {
207
213
  );
208
214
  self.characterOverlay = new CharacterOverlay(self.settings.characters, self.onCharacterSelect);
209
215
  },
216
+ /**
217
+ * insert a character after selecting it from the list
218
+ */
210
219
  onCharacterSelect: function(character) {
211
220
  var self = this;
212
221
  var range = Aloha.Selection.getRangeObject();
213
- if(Aloha.activeEditable) {
222
+
223
+ if( Aloha.activeEditable ) {
214
224
  var charNode = jQuery(document.createTextNode(character));
215
225
  GENTICS.Utils.Dom.insertIntoDOM(
216
226
  charNode,
@@ -218,6 +228,8 @@ function(Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore) {
218
228
  jQuery(Aloha.activeEditable.obj),
219
229
  true
220
230
  );
231
+ range.startContainer = range.endContainer = charNode.get( 0 );
232
+ range.startOffset = range.endOffset = charNode.length;
221
233
  range.select();
222
234
  }
223
235
  }
@@ -62,7 +62,7 @@ function( Aloha, jQuery, ContentHandlerManager, console ) {
62
62
  ],
63
63
 
64
64
  attributes: {
65
- 'a': ['href', 'title', 'id', 'data-gentics-aloha-repository', 'data-gentics-aloha-object-id'],
65
+ 'a': ['href', 'title', 'id', 'class', 'data-gentics-aloha-repository', 'data-gentics-aloha-object-id'],
66
66
  'div': [ 'id', 'class'],
67
67
  'abbr': ['title'],
68
68
  'blockquote': ['cite'],
@@ -75,7 +75,8 @@ function( Aloha, jQuery, ContentHandlerManager, console ) {
75
75
  'table': ['summary', 'width'],
76
76
  'td': ['abbr', 'axis', 'colspan', 'rowspan', 'width'],
77
77
  'th': ['abbr', 'axis', 'colspan', 'rowspan', 'scope', 'width'],
78
- 'ul': ['type']
78
+ 'ul': ['type'],
79
+ 'span': ['class']
79
80
  },
80
81
 
81
82
  protocols: {
@@ -15,6 +15,7 @@ function( Aloha, jQuery, ContentHandlerManager ) {
15
15
  * @param content
16
16
  */
17
17
  handleContent: function( content ) {
18
+
18
19
  if ( typeof content === 'string' ){
19
20
  content = jQuery( '<div>' + content + '</div>' );
20
21
  } else if ( content instanceof jQuery ) {
@@ -120,7 +121,7 @@ function( Aloha, jQuery, ContentHandlerManager ) {
120
121
  var jqElem = jQuery(this),
121
122
  innerText = jqElem.text().trim().replace(/&nbsp;/g, ''),
122
123
  outerText;
123
-
124
+
124
125
  if (innerText.length === 0) {
125
126
  // check whether the outermost of the three spans contains nothing more than numbering
126
127
  outerText = jqElem.parent().parent().text().trim().replace(/&nbsp;/g, '');
@@ -257,21 +258,126 @@ function( Aloha, jQuery, ContentHandlerManager ) {
257
258
  Aloha.Markup.transformDomObject(jQuery(this), 'h1');
258
259
  });
259
260
  content.find('p.MsoSubtitle').each(function() {
260
- // titles will be transformed to h1
261
+ // sub titles will be transformed to h2
261
262
  Aloha.Markup.transformDomObject(jQuery(this), 'h2');
262
263
  });
263
264
  },
265
+
266
+ /**
267
+ * Cleanup MS Word HTML
268
+ * @param content
269
+ */
270
+ cleanHtml: function ( content ) {
271
+
272
+ // unwrap empty tags
273
+ // do not remove them here because of eg. spaces wrapped in spans which are needed
274
+ content.find('*').filter( function() {
275
+ return jQuery.trim(jQuery(this).text()) == '';
276
+ }).contents().unwrap();
277
+
278
+ // unwrap all spans
279
+ content.find('span').contents().unwrap();
280
+
281
+ // when href starts with #, it's the link to an anchor. remove it.
282
+ content.find('a').each(function() {
283
+ if ( jQuery(this).attr('href') && jQuery(this).attr('href').trim().match(/^#(.*)$/) ) {
284
+ jQuery(this).contents().unwrap();
285
+ }
286
+ });
287
+
288
+ // eg. footnotes are wrapped in divs. unwrap them.
289
+ content.find('div').contents().unwrap();
290
+
291
+ // remove empty tags
292
+ content.find('*').filter( function() {
293
+ return jQuery.trim(jQuery(this).text()) == '';
294
+ }).remove();
295
+
296
+ },
297
+
298
+ /**
299
+ * Remove paragraph numbering from TOC feature
300
+ * @param content
301
+ */
302
+ removeParagraphNumbering: function( content ) {
303
+ var detectionFilter = 'h1,h2,h3,h4,h5,h6',
304
+ paragraphs = content.find(detectionFilter);
305
+
306
+ if (paragraphs.length > 0) {
307
+ paragraphs.each(function() {
308
+ var jqElem = jQuery(this),
309
+ spans = jqElem.find('span'),
310
+ links = jqElem.find('a');
311
+
312
+ // remove TOC numbering
313
+ spans.each(function() {
314
+ if ( jQuery(this).text().trim().match(/^([\.\(]?[\d\D][\.\(]?){1,4}$/) ) {
315
+ jQuery(this).remove();
316
+ }
317
+ })
318
+
319
+ // remove TOC anchor links
320
+ links.each(function() {
321
+ // no href, so it's an anchor
322
+ if ( typeof jQuery(this).attr('href') === 'undefined' ) {
323
+ jQuery(this).contents().unwrap();
324
+ }
325
+ });
326
+
327
+ });
328
+ }
329
+ },
330
+
331
+
332
+ /**
333
+ * Transform TOC
334
+ * @param content
335
+ */
336
+ transformToc: function( content ) {
337
+ var detectionFilter = '[class*=MsoToc]',
338
+ paragraphs = content.find(detectionFilter);
339
+
340
+ paragraphs.each(function() {
341
+ var jqElem = jQuery(this),
342
+ spans = jqElem.find('span'),
343
+ links = jqElem.find('a');
344
+
345
+ // a table of contents entry looks like
346
+ // 1. Title text ... 5
347
+ // we get rid of the "... 5" part which repesents the page number
348
+ spans.each(function() {
349
+ if ( jQuery(this).attr('style') && jQuery(this).attr('style').search('mso-hide') > -1 ) {
350
+ jQuery(this).remove();
351
+ }
352
+ jQuery(this).contents().unwrap();
353
+ });
354
+
355
+ // remove the anchor link of the toc item
356
+ links.each(function() {
357
+ jQuery(this).contents().unwrap();
358
+ });
359
+ });
360
+ },
264
361
 
265
362
  /**
266
363
  * This is the main transformation method
267
364
  * @param content
268
365
  */
269
- transformWordContent: function (content) {
366
+ transformWordContent: function( content ) {
367
+ // transform table of contents
368
+ this.transformToc( content );
369
+
370
+ // remove paragraph numbering
371
+ this.removeParagraphNumbering( content );
372
+
270
373
  // transform lists
271
- this.transformListsFromWord(content);
374
+ this.transformListsFromWord( content );
272
375
 
273
376
  // transform titles
274
- this.transformTitles(content);
377
+ this.transformTitles( content );
378
+
379
+ // clean html
380
+ this.cleanHtml( content );
275
381
  }
276
382
  });
277
383
 
@@ -0,0 +1,29 @@
1
+ /*!
2
+ * Aloha Editor
3
+ * Author & Copyright (c) 2010 Gentics Software GmbH
4
+ * aloha-sales@gentics.com
5
+ * Licensed unter the terms of http://www.aloha-editor.com/license.html
6
+ */
7
+ /**
8
+ * The dom-to-xhtml plugin extends the serialization method of the
9
+ * Aloha.Editable.getContent() instance method to generate valid XHTML
10
+ * (in so far as the DOM of the editables itself is valid).
11
+ */
12
+ define(
13
+ ['aloha', 'aloha/jquery', 'aloha/plugin', 'dom-to-xhtml/dom-to-xhtml'],
14
+ function( Aloha, $, Plugin, domToXhtml) {
15
+
16
+
17
+ return Plugin.create('dom-to-xhtml', {
18
+ /**
19
+ * Called by the plugin-manager on intialization.
20
+ *
21
+ * @Override
22
+ */
23
+ init: function () {
24
+ Aloha.Editable.setContentSerializer(function(editableElement){
25
+ return domToXhtml.contentsToXhtml(editableElement);
26
+ });
27
+ }
28
+ });
29
+ });
@@ -0,0 +1,306 @@
1
+ /*!
2
+ * Aloha Editor
3
+ * Author & Copyright (c) 2010 Gentics Software GmbH
4
+ * aloha-sales@gentics.com
5
+ * Licensed unter the terms of http://www.aloha-editor.com/license.html
6
+ */
7
+ /**
8
+ * Provides public utility methods to convert DOM nodes to XHTML.
9
+ */
10
+ define(
11
+ ['aloha', 'aloha/jquery', 'aloha/console'],
12
+ function( Aloha, $, console) {
13
+
14
+
15
+ /**
16
+ * Gets the attributes of the given element.
17
+ *
18
+ * @param element
19
+ * An element to get the attributes for.
20
+ * @return
21
+ * An array of consisting of [name, value] tuples for each attribute.
22
+ * Attribute values may be strings, booleans or undefined.
23
+ */
24
+ function getAttrs(element) {
25
+ var attrs = element.attributes;
26
+ var cleanAttrs = [];
27
+ for ( var i = 0; i < attrs.length; i++ ) {
28
+ var attr = attrs[ i ];
29
+ if ( typeof attr.specified === "undefined" || attr.specified ) {
30
+ var name = attr.nodeName;
31
+ // Use jQuery to get a corrected style attribute on IE.
32
+ // Otherwise prefer getAttribute() over attr.nodeValue as the
33
+ // latter stringifies the attribute value.
34
+ // There seems to be a jQuery bug that returns undefined
35
+ // for the "checked" attribute on IE7, otherwise we
36
+ // could always use jquery.
37
+ var value = ( "style" === name ? $.attr(element, name) : element.getAttribute(name) );
38
+ cleanAttrs.push( [ name, value ] );
39
+ }
40
+ }
41
+ return cleanAttrs;
42
+ }
43
+
44
+ /**
45
+ * Elements that are to be serialized like <img /> and not like <img></img>
46
+ */
47
+ var emptyElements = [
48
+ "area", "base", "basefont", "br", "col", "frame", "hr",
49
+ "img", "input", "isindex", "link", "meta", "param", "embed" ];
50
+
51
+ /**
52
+ * Attributes that are to be serialized like checked="checked" for any true attribute value.
53
+ */
54
+ var booleanAttrs = [
55
+ "checked", "compact", "declare", "defer", "disabled", "ismap", "multiple",
56
+ "nohref", "noresize", "noshade", "nowrap", "readonly", "selected" ];
57
+
58
+ /**
59
+ * Encodes a string meant to be used wherever parsable character data occurs in XML.
60
+ * @param str
61
+ * An unencoded piece of character data
62
+ * @return
63
+ * The given string with & and < characters replaced with the corresponding HTML entity references.
64
+ */
65
+ function encodePcdata(str) {
66
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;');
67
+ }
68
+
69
+ /**
70
+ * Encodes a string meant to be used between double-quoted attribute values.
71
+ *
72
+ * @param str
73
+ * An unencoded attribute value
74
+ * @return
75
+ * The given string with & < and " characters replaced with the corresponding HTML entity references.
76
+ */
77
+ function encodeDqAttrValue(str) {
78
+ return encodePcdata(str).replace(/"/g, '&quot;');
79
+ }
80
+
81
+ /**
82
+ * Serializes the attributes of the given element.
83
+ *
84
+ * Attributes that have the empty string as value will not appear in the string at all.
85
+ *
86
+ * @param element
87
+ * An element to serialize the attributes of
88
+ * @return
89
+ * A string made up of name="value" for each attribute of the
90
+ * given element, separated by space. The string will have a leading space.
91
+ */
92
+ function makeAttrString(element) {
93
+ var attrs = getAttrs(element);
94
+ var str = "";
95
+ for (var i = 0; i < attrs.length; i++) {
96
+ var name = attrs[i][0];
97
+ var value = attrs[i][1];
98
+ if ( "" === value || null == value ) {
99
+ // I don't think it is ever an error to make an
100
+ // attribute not appear if its string value is empty.
101
+ continue;
102
+ }
103
+ // The XHTML spec says attributes are lowercase
104
+ name = name.toLowerCase();
105
+ //TODO it's only a boolean attribute if the element is in an HTML namespace
106
+ var isBool = (-1 !== $.inArray(name, booleanAttrs));
107
+ if ( ! isBool || (isBool && value) ) {
108
+ str += " " + name + '="' + encodeDqAttrValue( "" + (isBool ? name : value) ) + '"';
109
+ }
110
+ }
111
+ return str;
112
+ }
113
+
114
+ /**
115
+ * IE8 turns the following
116
+ * <book id="x">{content}</book>
117
+ * into
118
+ * <book id="x"></book>{content}</book><//book>
119
+ * This seems to occur with any element IE doesn't recognize.
120
+ *
121
+ * @param element
122
+ * An element node.
123
+ * @return
124
+ * true if the given element isn't recognized by IE and
125
+ * causes a broken DOM structure as outlined above.
126
+ */
127
+ function isUnrecognized(element) {
128
+ var closingName = "/" + element.nodeName;
129
+ var sibling = element.nextSibling;
130
+ while (null != sibling) {
131
+ if (closingName == sibling.nodeName) {
132
+ return true;
133
+ }
134
+ sibling = sibling.nextSibling;
135
+ }
136
+ return false;
137
+ }
138
+
139
+ /**
140
+ * Serializes the children of the given element into an XHTML string.
141
+ *
142
+ * The same as serializeElement() except it only serializes the children.
143
+ * The start and end tag of the given element will not appear in the resulting XHTML.
144
+ *
145
+ * @see serializeElement()
146
+ */
147
+ function serializeChildren(element, child, unrecognized, xhtml) {
148
+ while (null != child) {
149
+ if (1 === child.nodeType && unrecognized && "/" + element.nodeName == child.nodeName) {
150
+ child = child.nextSibling;
151
+ break;
152
+ } else if (1 === child.nodeType && isUnrecognized(child)) {
153
+ child = serializeElement(child, child.nextSibling, true, xhtml);
154
+ } else {
155
+ serialize(child, xhtml);
156
+ child = child.nextSibling;
157
+ }
158
+ }
159
+ return child;
160
+ }
161
+
162
+ /**
163
+ * Serializes an element into an XHTML string.
164
+ *
165
+ * @param element
166
+ * An element to serialize.
167
+ * @param child
168
+ * The first child of the given element. This will usually be
169
+ * element.firstChild. On IE this may be element.nextSibling because
170
+ * of the broken DOM structure IE sometimes generates.
171
+ * @param unrecognized
172
+ * Whether the given element is unrecognized on IE. If IE doesn't
173
+ * recognize the element, it will create a broken DOM structure
174
+ * which has to be compensated for. See isUnrecognized() for more.
175
+ * @param xhtml
176
+ * An array which receives the serialized element and whic, if joined,
177
+ * will yield the XHTML string.
178
+ * @return
179
+ * null if all siblings of the given child have been processed as children
180
+ * of the given element, or otherwise the first sibling of child that is not considered
181
+ * a child of the given element.
182
+ */
183
+ function serializeElement(element, child, unrecognized, xhtml) {
184
+ // TODO: we should only lowercase element names if they are in an HTML namespace
185
+ var elementName = element.nodeName.toLowerCase();
186
+ // This is a hack around an IE bug which strips the namespace prefix
187
+ // of element.nodeName if it occurs inside an contentEditable=true.
188
+ if (element.scopeName && 'HTML' != element.scopeName && -1 === elementName.indexOf(':')) {
189
+ elementName = element.scopeName.toLowerCase() + ':' + elementName;
190
+ }
191
+ if ( ! unrecognized && null == child && -1 !== $.inArray(elementName, emptyElements) ) {
192
+ xhtml.push('<' + elementName + makeAttrString(element) + '/>');
193
+ } else {
194
+ xhtml.push('<' + elementName + makeAttrString(element) + '>');
195
+ child = serializeChildren(element, child, unrecognized, xhtml);
196
+ xhtml.push('</' + elementName + '>');
197
+ }
198
+ return child;
199
+ }
200
+
201
+ /**
202
+ * Serializes a DOM node into a XHTML string.
203
+ *
204
+ * @param node
205
+ * A DOM node to serialize.
206
+ * @param xhtml
207
+ * An array that will receive snippets of XHTML,
208
+ * which if joined will yield the XHTML string.
209
+ */
210
+ function serialize(node, xhtml) {
211
+ var nodeType = node.nodeType;
212
+ if (1 === nodeType) {
213
+ serializeElement(node, node.firstChild, isUnrecognized(node), xhtml);
214
+ } else if (3 === node.nodeType) {
215
+ xhtml.push(encodePcdata(node.nodeValue));
216
+ } else if (8 === node.nodeType) {
217
+ xhtml.push('<' + '!--' + node.nodeValue + '-->');
218
+ } else {
219
+ console.log('Unknown node type encountered during serialization, ignoring it:'
220
+ + ' type=' + node.nodeType
221
+ + ' name=' + node.nodeName
222
+ + ' value=' + node.nodeValue);
223
+ }
224
+ }
225
+
226
+ return {
227
+ /**
228
+ * Serializes a number of DOM nodes in an array-like object to an XHTML string.
229
+ *
230
+ * The XHTML of the nodes in the given array-like object will be concatenated.
231
+ *
232
+ * @param nodes
233
+ * An array or jQuery object or another array-like object to serialize.
234
+ * @return
235
+ * The serialized XHTML String representing the given DOM nodes in the given array-like object.
236
+ * The result may look like an XML fragment with multiple top-level elements and text nodes.
237
+ * @see nodeToXhtml()
238
+ */
239
+ contentsToXhtml: function(element) {
240
+ var xhtml = [];
241
+ serializeChildren(element, element.firstChild, false, xhtml);
242
+ return xhtml.join("");
243
+ },
244
+
245
+ /**
246
+ * Serializes a DOM node to an XHTML string.
247
+ *
248
+ * Beware that the serialization method will generate XHTML as
249
+ * close as possible to the DOM tree represented by the given
250
+ * node. The result will only be valid XHTML if the DOM tree
251
+ * doesn't violate any contained-in rules.
252
+ *
253
+ * Element attributes with an empty string as value will not
254
+ * appear in the serialized output.
255
+ *
256
+ * When iterating over the DOM, CDATA sections are comment nodes
257
+ * on some browsers (Chrome) and not there at all on others (IE).
258
+ * This is the same as what comes out from element.innerHTML.
259
+ *
260
+ * IE8 bug: comments will sometimes be silently stripped inside
261
+ * contentEditable=true. Conditional includes don't work inside
262
+ * contentEditable=true. See the tests for more information.
263
+ *
264
+ * IE8 bug: a title element will not be serialized correctly
265
+ * unless it occurs in the head of a HTML document, even if it occurs
266
+ * in a non-HTML namespace (maybe it works with a prefix).
267
+ * This will probably also apply for other HTML elements that
268
+ * occur in the header.
269
+ *
270
+ * IE8 bug: unrecognized elements in the HTML scope will cause
271
+ * broken DOM structure (some HTML5 elements that are not yet
272
+ * implemented in IE for example). Some effort was made to fix a
273
+ * broken DOM structure, if it is encountered. There is one case
274
+ * which results in an unrecoverably broken DOM structure, which
275
+ * is an unrecognized element not preceded by some text. See the
276
+ * tests for further information.
277
+ *
278
+ * IE8 bug: whitespace is not reliably preserved when the style
279
+ * white-space:pre (or similar) is used. See the tests for
280
+ * further information. Whitespace inside <pre> elements will
281
+ * be preserved, but \n characters will become \r characters.
282
+ *
283
+ * IE7 bug: URLs in href and src attributes of a and img
284
+ * elements will be absolutized (including hostname and
285
+ * protocol) if they are given as a relative path.
286
+ *
287
+ * IE bug: Namespace support inside contentEditable=true is a
288
+ * bit shaky on IE. Don't use it if possible. See the tests to
289
+ * get an idea of what seems to work. Make namespace prefixes
290
+ * and element names all lower-case, as they are always
291
+ * lower-cased, even if the element doesn't occur in an HTML
292
+ * namespace. Don't use default namespaces, use prefixes (except
293
+ * for an HTML namespace).
294
+ *
295
+ * @param node
296
+ * A DOM node to serialize
297
+ * @return
298
+ * The serialized XHTML string represnting the given DOM node.
299
+ */
300
+ nodeToXhtml: function(node) {
301
+ var xhtml = [];
302
+ serialize(node, xhtml);
303
+ return xhtml.join("");
304
+ }
305
+ };
306
+ });