kiteditor 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (229) hide show
  1. data/LICENSE +25 -0
  2. data/app/controllers/mercury/images_controller.rb +5 -0
  3. data/app/controllers/mercury_controller.rb +34 -0
  4. data/app/models/mercury/image.rb +17 -0
  5. data/app/views/layouts/mercury.html.erb +33 -0
  6. data/app/views/layouts/popup.html.haml +9 -0
  7. data/app/views/mercury/images/_list.html.haml +22 -0
  8. data/app/views/mercury/images/index.html.haml +4 -0
  9. data/app/views/mercury/images/index.js.erb +2 -0
  10. data/app/views/mercury/lightviews/about.html +11 -0
  11. data/app/views/mercury/modals/character.html +255 -0
  12. data/app/views/mercury/modals/htmleditor.html +13 -0
  13. data/app/views/mercury/modals/link.html +94 -0
  14. data/app/views/mercury/modals/media.html +1 -0
  15. data/app/views/mercury/modals/table.html +84 -0
  16. data/app/views/mercury/palettes/backcolor.html +73 -0
  17. data/app/views/mercury/palettes/forecolor.html +73 -0
  18. data/app/views/mercury/panels/history.html +3 -0
  19. data/app/views/mercury/panels/notes.html +3 -0
  20. data/app/views/mercury/panels/snippets.html +12 -0
  21. data/app/views/mercury/selects/formatblock.html +11 -0
  22. data/app/views/mercury/selects/style.html +5 -0
  23. data/app/views/mercury/snippets/example/options.html.erb +34 -0
  24. data/app/views/mercury/snippets/example/preview.html.erb +1 -0
  25. data/config/engine.rb +44 -0
  26. data/db/migrate/20110526035601_create_mercury_images.rb +11 -0
  27. data/features/loading/loading.feature +22 -0
  28. data/features/loading/navigating.feature +77 -0
  29. data/features/loading/user_interface.feature +67 -0
  30. data/features/regions/editable/advanced_editing.feature +0 -0
  31. data/features/regions/editable/basic_editing.feature +195 -0
  32. data/features/regions/editable/inserting_links.feature +98 -0
  33. data/features/regions/editable/inserting_media.feature +110 -0
  34. data/features/regions/editable/inserting_snippets.feature +102 -0
  35. data/features/regions/editable/inserting_special_characters.feature +24 -0
  36. data/features/regions/editable/inserting_tables.feature +109 -0
  37. data/features/regions/editable/pasting.feature +0 -0
  38. data/features/regions/editable/uploading_images.feature +0 -0
  39. data/features/regions/markupable/advanced_editing.feature +0 -0
  40. data/features/regions/markupable/basic_editing.feature +0 -0
  41. data/features/regions/markupable/inserting_links.feature +0 -0
  42. data/features/regions/markupable/inserting_media.feature +0 -0
  43. data/features/regions/markupable/inserting_snippets.feature +0 -0
  44. data/features/regions/markupable/inserting_special_characters.feature +0 -0
  45. data/features/regions/markupable/inserting_tables.feature +0 -0
  46. data/features/regions/markupable/uploading_images.feature +0 -0
  47. data/features/regions/snippetable/advanced_editing.feature +0 -0
  48. data/features/regions/snippetable/basic_editing.feature +0 -0
  49. data/features/regions/snippetable/inserting_snippets.feature +0 -0
  50. data/features/saving/saving.feature +33 -0
  51. data/features/step_definitions/debug_steps.rb +14 -0
  52. data/features/step_definitions/mercury_steps.rb +438 -0
  53. data/features/step_definitions/web_steps.rb +211 -0
  54. data/features/support/env.rb +46 -0
  55. data/features/support/mercury_contents.rb +25 -0
  56. data/features/support/mercury_selectors.rb +148 -0
  57. data/features/support/paths.rb +38 -0
  58. data/features/support/selectors.rb +44 -0
  59. data/lib/generators/mercury/install/install_generator.rb +49 -0
  60. data/lib/generators/mercury/install/templates/mongoid_paperclip_image.rb +17 -0
  61. data/lib/mercury/authentication.rb +8 -0
  62. data/lib/mercury-rails.rb +3 -0
  63. data/spec/javascripts/mercury/dialog_spec.js.coffee +281 -0
  64. data/spec/javascripts/mercury/dialogs/backcolor_spec.js.coffee +37 -0
  65. data/spec/javascripts/mercury/dialogs/forecolor_spec.js.coffee +37 -0
  66. data/spec/javascripts/mercury/dialogs/formatblock_spec.js.coffee +25 -0
  67. data/spec/javascripts/mercury/dialogs/snippetpanel_spec.js.coffee +30 -0
  68. data/spec/javascripts/mercury/dialogs/style_spec.js.coffee +25 -0
  69. data/spec/javascripts/mercury/history_buffer_spec.js.coffee +76 -0
  70. data/spec/javascripts/mercury/lightview_spec.js.coffee +497 -0
  71. data/spec/javascripts/mercury/mercury_spec.js.coffee +132 -0
  72. data/spec/javascripts/mercury/modal_spec.js.coffee +504 -0
  73. data/spec/javascripts/mercury/modals/htmleditor_spec.js.coffee +30 -0
  74. data/spec/javascripts/mercury/modals/insertcharacter_spec.js.coffee +29 -0
  75. data/spec/javascripts/mercury/modals/insertlink_spec.js.coffee +220 -0
  76. data/spec/javascripts/mercury/modals/insertmedia_spec.js.coffee +167 -0
  77. data/spec/javascripts/mercury/modals/insertsnippet_spec.js.coffee +52 -0
  78. data/spec/javascripts/mercury/modals/inserttable_spec.js.coffee +160 -0
  79. data/spec/javascripts/mercury/native_extensions_spec.js.coffee +60 -0
  80. data/spec/javascripts/mercury/page_editor_spec.js.coffee +750 -0
  81. data/spec/javascripts/mercury/palette_spec.js.coffee +49 -0
  82. data/spec/javascripts/mercury/panel_spec.js.coffee +185 -0
  83. data/spec/javascripts/mercury/region_spec.js.coffee +298 -0
  84. data/spec/javascripts/mercury/regions/editable_spec.js.coffee +561 -0
  85. data/spec/javascripts/mercury/regions/markupable_spec.js.coffee +367 -0
  86. data/spec/javascripts/mercury/regions/snippetable_spec.js.coffee +370 -0
  87. data/spec/javascripts/mercury/select_spec.js.coffee +49 -0
  88. data/spec/javascripts/mercury/snippet_spec.js.coffee +245 -0
  89. data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +184 -0
  90. data/spec/javascripts/mercury/statusbar_spec.js.coffee +150 -0
  91. data/spec/javascripts/mercury/table_editor_spec.js.coffee +194 -0
  92. data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +90 -0
  93. data/spec/javascripts/mercury/toolbar.button_spec.js.coffee +360 -0
  94. data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +118 -0
  95. data/spec/javascripts/mercury/toolbar_spec.js.coffee +222 -0
  96. data/spec/javascripts/mercury/tooltip_spec.js.coffee +186 -0
  97. data/spec/javascripts/mercury/uploader_spec.js.coffee +514 -0
  98. data/spec/javascripts/spec_helper.js +513 -0
  99. data/spec/javascripts/templates/mercury/dialog.html +2 -0
  100. data/spec/javascripts/templates/mercury/dialogs/backcolor.html +5 -0
  101. data/spec/javascripts/templates/mercury/dialogs/forecolor.html +5 -0
  102. data/spec/javascripts/templates/mercury/dialogs/formatblock.html +3 -0
  103. data/spec/javascripts/templates/mercury/dialogs/snippetpanel.html +16 -0
  104. data/spec/javascripts/templates/mercury/dialogs/style.html +3 -0
  105. data/spec/javascripts/templates/mercury/lightview.html +13 -0
  106. data/spec/javascripts/templates/mercury/modal.html +13 -0
  107. data/spec/javascripts/templates/mercury/modals/htmleditor.html +5 -0
  108. data/spec/javascripts/templates/mercury/modals/insertcharacter.html +5 -0
  109. data/spec/javascripts/templates/mercury/modals/insertlink.html +30 -0
  110. data/spec/javascripts/templates/mercury/modals/insertmedia.html +35 -0
  111. data/spec/javascripts/templates/mercury/modals/insertsnippet.html +6 -0
  112. data/spec/javascripts/templates/mercury/modals/inserttable.html +27 -0
  113. data/spec/javascripts/templates/mercury/page_editor.html +35 -0
  114. data/spec/javascripts/templates/mercury/palette.html +16 -0
  115. data/spec/javascripts/templates/mercury/panel.html +16 -0
  116. data/spec/javascripts/templates/mercury/region.html +2 -0
  117. data/spec/javascripts/templates/mercury/regions/editable.html +3 -0
  118. data/spec/javascripts/templates/mercury/regions/snippetable.html +4 -0
  119. data/spec/javascripts/templates/mercury/select.html +16 -0
  120. data/spec/javascripts/templates/mercury/snippet.html +1 -0
  121. data/spec/javascripts/templates/mercury/snippet_toolbar.html +16 -0
  122. data/spec/javascripts/templates/mercury/statusbar.html +8 -0
  123. data/spec/javascripts/templates/mercury/table_editor.html +65 -0
  124. data/spec/javascripts/templates/mercury/toolbar.button.html +64 -0
  125. data/spec/javascripts/templates/mercury/toolbar.button_group.html +9 -0
  126. data/spec/javascripts/templates/mercury/toolbar.expander.html +18 -0
  127. data/spec/javascripts/templates/mercury/toolbar.html +11 -0
  128. data/spec/javascripts/templates/mercury/tooltip.html +12 -0
  129. data/spec/javascripts/templates/mercury/uploader.html +11 -0
  130. data/vendor/assets/images/mercury/button.png +0 -0
  131. data/vendor/assets/images/mercury/close.png +0 -0
  132. data/vendor/assets/images/mercury/default-snippet.png +0 -0
  133. data/vendor/assets/images/mercury/loading-dark.gif +0 -0
  134. data/vendor/assets/images/mercury/loading-light.gif +0 -0
  135. data/vendor/assets/images/mercury/missing-image.png +0 -0
  136. data/vendor/assets/images/mercury/search-icon.png +0 -0
  137. data/vendor/assets/images/mercury/temp-logo.png +0 -0
  138. data/vendor/assets/images/mercury/toolbar/editable/buttons.png +0 -0
  139. data/vendor/assets/images/mercury/toolbar/primary/_expander.png +0 -0
  140. data/vendor/assets/images/mercury/toolbar/primary/_pressed.png +0 -0
  141. data/vendor/assets/images/mercury/toolbar/primary/historypanel.png +0 -0
  142. data/vendor/assets/images/mercury/toolbar/primary/insertcharacter.png +0 -0
  143. data/vendor/assets/images/mercury/toolbar/primary/insertlink.png +0 -0
  144. data/vendor/assets/images/mercury/toolbar/primary/insertmedia.png +0 -0
  145. data/vendor/assets/images/mercury/toolbar/primary/inserttable.png +0 -0
  146. data/vendor/assets/images/mercury/toolbar/primary/inspectorpanel.png +0 -0
  147. data/vendor/assets/images/mercury/toolbar/primary/notespanel.png +0 -0
  148. data/vendor/assets/images/mercury/toolbar/primary/preview.png +0 -0
  149. data/vendor/assets/images/mercury/toolbar/primary/redo.png +0 -0
  150. data/vendor/assets/images/mercury/toolbar/primary/save.png +0 -0
  151. data/vendor/assets/images/mercury/toolbar/primary/snippetpanel.png +0 -0
  152. data/vendor/assets/images/mercury/toolbar/primary/undo.png +0 -0
  153. data/vendor/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
  154. data/vendor/assets/javascripts/mercury/dependencies/jquery-1.7.js +9300 -0
  155. data/vendor/assets/javascripts/mercury/dependencies/jquery-ui-1.8.13.custom.js +1328 -0
  156. data/vendor/assets/javascripts/mercury/dependencies/jquery-ui-1.8.18.custom.min.js +356 -0
  157. data/vendor/assets/javascripts/mercury/dependencies/jquery-ui.1.8.13.custom.min.js +356 -0
  158. data/vendor/assets/javascripts/mercury/dependencies/jquery.additions.js +206 -0
  159. data/vendor/assets/javascripts/mercury/dependencies/jquery.htmlClean.js +527 -0
  160. data/vendor/assets/javascripts/mercury/dependencies/liquidmetal.js +88 -0
  161. data/vendor/assets/javascripts/mercury/dependencies/showdown.js +1340 -0
  162. data/vendor/assets/javascripts/mercury/dialog.js.coffee +159 -0
  163. data/vendor/assets/javascripts/mercury/dialogs/backcolor.js.coffee +6 -0
  164. data/vendor/assets/javascripts/mercury/dialogs/forecolor.js.coffee +6 -0
  165. data/vendor/assets/javascripts/mercury/dialogs/formatblock.js.coffee +4 -0
  166. data/vendor/assets/javascripts/mercury/dialogs/snippetpanel.js.coffee +10 -0
  167. data/vendor/assets/javascripts/mercury/dialogs/style.js.coffee +4 -0
  168. data/vendor/assets/javascripts/mercury/finalize.js.coffee +3 -0
  169. data/vendor/assets/javascripts/mercury/history_buffer.js.coffee +30 -0
  170. data/vendor/assets/javascripts/mercury/lightview.js.coffee +205 -0
  171. data/vendor/assets/javascripts/mercury/locales/da.locale.js.coffee +0 -0
  172. data/vendor/assets/javascripts/mercury/locales/de.locale.js.coffee +206 -0
  173. data/vendor/assets/javascripts/mercury/locales/es.locale.js.coffee +211 -0
  174. data/vendor/assets/javascripts/mercury/locales/example.local.js.coffee +211 -0
  175. data/vendor/assets/javascripts/mercury/locales/fr.locale.js.coffee +211 -0
  176. data/vendor/assets/javascripts/mercury/locales/it.locale.js.coffee +208 -0
  177. data/vendor/assets/javascripts/mercury/locales/ko.local.js.coffee +206 -0
  178. data/vendor/assets/javascripts/mercury/locales/nl.locale.js.coffee +206 -0
  179. data/vendor/assets/javascripts/mercury/locales/pt.locale.js.coffee +211 -0
  180. data/vendor/assets/javascripts/mercury/locales/sv.local.js.coffee +209 -0
  181. data/vendor/assets/javascripts/mercury/locales/swedish_chef.locale.js.coffee +213 -0
  182. data/vendor/assets/javascripts/mercury/mercury.js.coffee +109 -0
  183. data/vendor/assets/javascripts/mercury/modal.js.coffee +204 -0
  184. data/vendor/assets/javascripts/mercury/modals/htmleditor.js.coffee +11 -0
  185. data/vendor/assets/javascripts/mercury/modals/insertcharacter.js.coffee +4 -0
  186. data/vendor/assets/javascripts/mercury/modals/insertlink.js.coffee +95 -0
  187. data/vendor/assets/javascripts/mercury/modals/insertmedia.js.coffee +107 -0
  188. data/vendor/assets/javascripts/mercury/modals/insertsnippet.js.coffee +12 -0
  189. data/vendor/assets/javascripts/mercury/modals/inserttable.js.coffee +54 -0
  190. data/vendor/assets/javascripts/mercury/native_extensions.js.coffee +55 -0
  191. data/vendor/assets/javascripts/mercury/page_editor.js.coffee +241 -0
  192. data/vendor/assets/javascripts/mercury/palette.js.coffee +29 -0
  193. data/vendor/assets/javascripts/mercury/panel.js.coffee +115 -0
  194. data/vendor/assets/javascripts/mercury/plugins/save_as_xml/mercury/page_editor.js.coffee +28 -0
  195. data/vendor/assets/javascripts/mercury/plugins/save_as_xml/plugin.js +9 -0
  196. data/vendor/assets/javascripts/mercury/region.js.coffee +107 -0
  197. data/vendor/assets/javascripts/mercury/regions/editable.js.coffee +600 -0
  198. data/vendor/assets/javascripts/mercury/regions/markupable.js.coffee +398 -0
  199. data/vendor/assets/javascripts/mercury/regions/simple.js.coffee +339 -0
  200. data/vendor/assets/javascripts/mercury/regions/snippetable.js.coffee +124 -0
  201. data/vendor/assets/javascripts/mercury/select.js.coffee +44 -0
  202. data/vendor/assets/javascripts/mercury/snippet.js.coffee +104 -0
  203. data/vendor/assets/javascripts/mercury/snippet_toolbar.js.coffee +72 -0
  204. data/vendor/assets/javascripts/mercury/statusbar.js.coffee +51 -0
  205. data/vendor/assets/javascripts/mercury/support/history.js +1 -0
  206. data/vendor/assets/javascripts/mercury/table_editor.js.coffee +265 -0
  207. data/vendor/assets/javascripts/mercury/toolbar.button.js.coffee +173 -0
  208. data/vendor/assets/javascripts/mercury/toolbar.button_group.js.coffee +42 -0
  209. data/vendor/assets/javascripts/mercury/toolbar.expander.js.coffee +56 -0
  210. data/vendor/assets/javascripts/mercury/toolbar.js.coffee +86 -0
  211. data/vendor/assets/javascripts/mercury/tooltip.js.coffee +74 -0
  212. data/vendor/assets/javascripts/mercury/uploader.js.coffee +227 -0
  213. data/vendor/assets/javascripts/mercury.js +479 -0
  214. data/vendor/assets/javascripts/mercury_loader.js +193 -0
  215. data/vendor/assets/javascripts/mercury_overrides.js +6 -0
  216. data/vendor/assets/javascripts/popup.js +8 -0
  217. data/vendor/assets/stylesheets/mercury/all_images.css.erb +89 -0
  218. data/vendor/assets/stylesheets/mercury/dialog.css +208 -0
  219. data/vendor/assets/stylesheets/mercury/lightview.css +151 -0
  220. data/vendor/assets/stylesheets/mercury/mercury.css +151 -0
  221. data/vendor/assets/stylesheets/mercury/modal.css +183 -0
  222. data/vendor/assets/stylesheets/mercury/statusbar.css +32 -0
  223. data/vendor/assets/stylesheets/mercury/toolbar.css +304 -0
  224. data/vendor/assets/stylesheets/mercury/tooltip.css +26 -0
  225. data/vendor/assets/stylesheets/mercury/uploader.css +111 -0
  226. data/vendor/assets/stylesheets/mercury.css +28 -0
  227. data/vendor/assets/stylesheets/mercury_overrides.css +17 -0
  228. data/vendor/assets/stylesheets/popup.css.erb +37 -0
  229. metadata +634 -0
@@ -0,0 +1,527 @@
1
+ /*
2
+ HTML Clean for jQuery
3
+ Anthony Johnston
4
+ http://www.antix.co.uk
5
+
6
+ version 1.2.3
7
+
8
+ $Revision: 51 $
9
+
10
+ requires jQuery http://jquery.com
11
+
12
+ Use and distibution http://www.opensource.org/licenses/bsd-license.php
13
+
14
+ 2010-04-02 allowedTags/removeTags added (white/black list) thanks to David Wartian (Dwartian)
15
+ 2010-06-30 replaceStyles added for replacement of bold, italic, super and sub styles on a tag
16
+ 2010-07-01 notRenderedTags added, where tags are to be removed but their contents are kept
17
+ */
18
+ (function ($) {
19
+ $.fn.htmlClean = function (options) {
20
+ // iterate and html clean each matched element
21
+ return this.each(function () {
22
+ if (this.value) {
23
+ this.value = $.htmlClean(this.value, options);
24
+ } else {
25
+ this.innerHTML = $.htmlClean(this.innerHTML, options);
26
+ }
27
+ });
28
+ };
29
+
30
+ // clean the passed html
31
+ $.htmlClean = function (html, options) {
32
+ options = $.extend({}, $.htmlClean.defaults, options);
33
+
34
+ var tagsRE = /<(\/)?(\w+:)?([\w]+)([^>]*)>/gi;
35
+ var attrsRE = /(\w+)=(".*?"|'.*?'|[^\s>]*)/gi;
36
+
37
+ var tagMatch;
38
+ var root = new Element();
39
+ var stack = [root];
40
+ var container = root;
41
+
42
+ if (options.bodyOnly) {
43
+ // check for body tag
44
+ if (tagMatch = /<body[^>]*>((\n|.)*)<\/body>/i.exec(html)) {
45
+ html = tagMatch[1];
46
+ }
47
+ }
48
+ html = html.concat("<xxx>"); // ensure last element/text is found
49
+ var lastIndex;
50
+
51
+ while (tagMatch = tagsRE.exec(html)) {
52
+ var tag = new Tag(tagMatch[3], tagMatch[1], tagMatch[4], options);
53
+
54
+ // add the text
55
+ var text = html.substring(lastIndex, tagMatch.index);
56
+ if (text.length > 0) {
57
+ var child = container.children[container.children.length - 1];
58
+ if (container.children.length > 0 && isText(child = container.children[container.children.length - 1])) {
59
+ // merge text
60
+ container.children[container.children.length - 1] = child.concat(text);
61
+ } else {
62
+ container.children.push(text);
63
+ }
64
+ }
65
+ lastIndex = tagsRE.lastIndex;
66
+
67
+ if (tag.isClosing) {
68
+ // find matching container
69
+ if (pop(stack, [tag.name])) {
70
+ stack.pop();
71
+ container = stack[stack.length - 1];
72
+ }
73
+ } else {
74
+ // create a new element
75
+ var element = new Element(tag);
76
+
77
+ // add attributes
78
+ var attrMatch;
79
+ while (attrMatch = attrsRE.exec(tag.rawAttributes)) {
80
+ // check style attribute and do replacements
81
+ if (attrMatch[1].toLowerCase() == "style" && options.replaceStyles) {
82
+
83
+ var renderParent = !tag.isInline;
84
+ for (var i = 0; i < options.replaceStyles.length; i++) {
85
+ if (options.replaceStyles[i][0].test(attrMatch[2])) {
86
+
87
+ if (!renderParent) {
88
+ tag.render = false;
89
+ renderParent = true;
90
+ }
91
+ container.children.push(element); // assumes not replaced
92
+ stack.push(element);
93
+ container = element; // assumes replacement is a container
94
+ // create new tag and element
95
+ tag = new Tag(options.replaceStyles[i][1], "", "", options);
96
+ element = new Element(tag);
97
+ }
98
+ }
99
+ }
100
+
101
+ if (tag.allowedAttributes != null
102
+ && (tag.allowedAttributes.length == 0
103
+ || $.inArray(attrMatch[1], tag.allowedAttributes) > -1)) {
104
+ element.attributes.push(new Attribute(attrMatch[1], attrMatch[2]));
105
+ }
106
+ }
107
+
108
+ // add required empty ones
109
+ $.each(tag.requiredAttributes, function () {
110
+ var name = this.toString();
111
+ if (!element.hasAttribute(name)) element.attributes.push(new Attribute(name, ""));
112
+ });
113
+
114
+ // check for replacements
115
+ for (var repIndex = 0; repIndex < options.replace.length; repIndex++) {
116
+ for (var tagIndex = 0; tagIndex < options.replace[repIndex][0].length; tagIndex++) {
117
+ var byName = typeof (options.replace[repIndex][0][tagIndex]) == "string";
118
+ if ((byName && options.replace[repIndex][0][tagIndex] == tag.name)
119
+ || (!byName && options.replace[repIndex][0][tagIndex].test(tagMatch))) {
120
+ // don't render this tag
121
+ tag.render = false;
122
+ container.children.push(element);
123
+ stack.push(element);
124
+ container = element;
125
+
126
+ // render new tag, keep attributes
127
+ tag = new Tag(options.replace[repIndex][1], tagMatch[1], tagMatch[4], options);
128
+ element = new Element(tag);
129
+ element.attributes = container.attributes;
130
+
131
+ repIndex = options.replace.length; // break out of both loops
132
+ break;
133
+ }
134
+ }
135
+ }
136
+
137
+ // check container rules
138
+ var add = true;
139
+ if (!container.isRoot) {
140
+ if (container.tag.isInline && !tag.isInline) {
141
+ add = false;
142
+ } else if (container.tag.disallowNest && tag.disallowNest
143
+ && !tag.requiredParent) {
144
+ add = false;
145
+ } else if (tag.requiredParent) {
146
+ if (add = pop(stack, tag.requiredParent)) {
147
+ container = stack[stack.length - 1];
148
+ }
149
+ }
150
+ }
151
+
152
+ if (add) {
153
+ container.children.push(element);
154
+
155
+ if (tag.toProtect) {
156
+ // skip to closing tag
157
+ var tagMatch2 = null;
158
+ while (tagMatch2 = tagsRE.exec(html)) {
159
+ var tag2 = new Tag(tagMatch2[3], tagMatch2[1], tagMatch2[4], options);
160
+ if (tag2.isClosing && tag2.name == tag.name) {
161
+ element.children.push(RegExp.leftContext.substring(lastIndex));
162
+ lastIndex = tagsRE.lastIndex;
163
+ break;
164
+ }
165
+ }
166
+ } else {
167
+ // set as current container element
168
+ if (!tag.isSelfClosing && !tag.isNonClosing) {
169
+ stack.push(element);
170
+ container = element;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ // render doc
178
+ return render(root, options).join("");
179
+ };
180
+
181
+ // defaults
182
+ $.htmlClean.defaults = {
183
+ // only clean the body tagbody
184
+ bodyOnly: true,
185
+ // only allow tags in this array, (white list), contents still rendered
186
+ allowedTags: [],
187
+ // remove tags in this array, (black list), contents still rendered
188
+ removeTags: ["basefont", "center", "dir", "font", "frame", "frameset", "iframe", "isindex", "menu", "noframes", "s", "strike", "u"],
189
+ // array of attribute names to remove on all elements in addition to those not in tagAttributes e.g ["width", "height"]
190
+ removeAttrs: [],
191
+ // array of [className], [optional array of allowed on elements] e.g. [["class"], ["anotherClass", ["p", "dl"]]]
192
+ allowedClasses: [],
193
+ // tags not rendered, contents remain
194
+ notRenderedTags: [],
195
+ // format the result
196
+ format: false,
197
+ // format indent to start on
198
+ formatIndent: 0,
199
+ // tags to replace, and what to replace with, tag name or regex to match the tag and attributes
200
+ replace: [
201
+ [
202
+ ["b", "big"],
203
+ "strong"
204
+ ],
205
+ [
206
+ ["i"],
207
+ "em"
208
+ ]
209
+ ],
210
+ // styles to replace with tags, multiple style matches supported, inline tags are replaced by the first match blocks are retained
211
+ replaceStyles: [
212
+ [/font-weight:\s*bold/i, "strong"],
213
+ [/font-style:\s*italic/i, "em"],
214
+ [/vertical-align:\s*super/i, "sup"],
215
+ [/vertical-align:\s*sub/i, "sub"]
216
+ ]
217
+ };
218
+
219
+ function applyFormat(element, options, output, indent) {
220
+ if (!element.tag.isInline && output.length > 0) {
221
+ output.push("\n");
222
+ for (var i = 0; i < indent; i++) output.push("\t");
223
+ }
224
+ }
225
+
226
+ function render(element, options) {
227
+ var output = [],
228
+ empty = element.attributes.length == 0,
229
+ indent = 0,
230
+ outputChildren = null;
231
+
232
+ // don't render if not in allowedTags or in removeTags
233
+ var renderTag
234
+ = element.tag.render
235
+ && (options.allowedTags.length == 0 || $.inArray(element.tag.name, options.allowedTags) > -1)
236
+ && (options.removeTags.length == 0 || $.inArray(element.tag.name, options.removeTags) == -1);
237
+
238
+ if (!element.isRoot && renderTag) {
239
+ // render opening tag
240
+ output.push("<");
241
+ output.push(element.tag.name);
242
+ $.each(element.attributes, function () {
243
+ if ($.inArray(this.name, options.removeAttrs) == -1) {
244
+ var m = new RegExp(/^(['"]?)(.*?)['"]?$/).exec(this.value);
245
+ var value = m[2];
246
+ var valueQuote = m[1] || "'";
247
+
248
+ // check for classes allowed
249
+ if (this.name == "class") {
250
+ value =
251
+ $.grep(value.split(" "), function (c) {
252
+ return $.grep(options.allowedClasses,
253
+ function (a) {
254
+ return a[0] == c && (a.length == 1 || $.inArray(element.tag.name, a[1]) > -1);
255
+ }).length > 0;
256
+ })
257
+ .join(" ");
258
+ valueQuote = "'";
259
+ }
260
+
261
+ if (value != null && (value.length > 0 || $.inArray(this.name, element.tag.requiredAttributes) > -1)) {
262
+ output.push(" ");
263
+ output.push(this.name);
264
+ output.push("=");
265
+ output.push(valueQuote);
266
+ output.push(value);
267
+ output.push(valueQuote);
268
+ }
269
+ }
270
+ });
271
+ }
272
+
273
+ if (element.tag.isSelfClosing) {
274
+ // self closing
275
+ if (renderTag) output.push(" />");
276
+ empty = false;
277
+ } else if (element.tag.isNonClosing) {
278
+ empty = false;
279
+ } else {
280
+ if (!element.isRoot && renderTag) {
281
+ // close
282
+ output.push(">");
283
+ }
284
+
285
+ indent = options.formatIndent++;
286
+
287
+ // render children
288
+ if (element.tag.toProtect) {
289
+ outputChildren = $.htmlClean.trim(element.children.join("")).replace(/<br>/ig, "\n");
290
+ output.push(outputChildren);
291
+ empty = outputChildren.length == 0;
292
+ options.formatIndent--;
293
+ } else {
294
+ outputChildren = [];
295
+ for (var i = 0; i < element.children.length; i++) {
296
+ var child = element.children[i];
297
+ var text = $.htmlClean.trim(textClean(isText(child) ? child : child.childrenToString()));
298
+ if (isInline(child)) {
299
+ if (i > 0 && text.length > 0
300
+ && (startsWithWhitespace(child) || endsWithWhitespace(element.children[i - 1]))) {
301
+ outputChildren.push(" ");
302
+ }
303
+ }
304
+ if (isText(child)) {
305
+ if (text.length > 0) {
306
+ outputChildren.push(text);
307
+ }
308
+ } else {
309
+ // don't allow a break to be the last child
310
+ if (i != element.children.length - 1 || child.tag.name != "br") {
311
+ if (options.format) applyFormat(child, options, outputChildren, indent);
312
+ outputChildren = outputChildren.concat(render(child, options));
313
+ }
314
+ }
315
+ }
316
+ options.formatIndent--;
317
+
318
+ if (outputChildren.length > 0) {
319
+ if (options.format && outputChildren[0] != "\n") applyFormat(element, options, output, indent);
320
+ output = output.concat(outputChildren);
321
+ empty = false;
322
+ }
323
+ }
324
+
325
+ if (!element.isRoot && renderTag) {
326
+ // render the closing tag
327
+ if (options.format) applyFormat(element, options, output, indent - 1);
328
+ output.push("</");
329
+ output.push(element.tag.name);
330
+ output.push(">");
331
+ }
332
+ }
333
+
334
+ // check for empty tags
335
+ if (!element.tag.allowEmpty && empty) {
336
+ return [];
337
+ }
338
+
339
+ return output;
340
+ }
341
+
342
+ // find a matching tag, and pop to it, if not do nothing
343
+ function pop(stack, tagNameArray, index) {
344
+ index = index || 1;
345
+ if ($.inArray(stack[stack.length - index].tag.name, tagNameArray) > -1) {
346
+ return true;
347
+ } else if (stack.length - (index + 1) > 0
348
+ && pop(stack, tagNameArray, index + 1)) {
349
+ stack.pop();
350
+ return true;
351
+ }
352
+ return false;
353
+ }
354
+
355
+ // Element Object
356
+ function Element(tag) {
357
+ if (tag) {
358
+ this.tag = tag;
359
+ this.isRoot = false;
360
+ } else {
361
+ this.tag = new Tag("root");
362
+ this.isRoot = true;
363
+ }
364
+ this.attributes = [];
365
+ this.children = [];
366
+
367
+ this.hasAttribute = function (name) {
368
+ for (var i = 0; i < this.attributes.length; i++) {
369
+ if (this.attributes[i].name == name) return true;
370
+ }
371
+ return false;
372
+ };
373
+
374
+ this.childrenToString = function () {
375
+ return this.children.join("");
376
+ };
377
+
378
+ return this;
379
+ }
380
+
381
+ // Attribute Object
382
+ function Attribute(name, value) {
383
+ this.name = name;
384
+ this.value = value;
385
+
386
+ return this;
387
+ }
388
+
389
+ // Tag object
390
+ function Tag(name, close, rawAttributes, options) {
391
+ this.name = name.toLowerCase();
392
+
393
+ this.isSelfClosing = $.inArray(this.name, tagSelfClosing) > -1;
394
+ this.isNonClosing = $.inArray(this.name, tagNonClosing) > -1;
395
+ this.isClosing = (close != undefined && close.length > 0);
396
+
397
+ this.isInline = $.inArray(this.name, tagInline) > -1;
398
+ this.disallowNest = $.inArray(this.name, tagDisallowNest) > -1;
399
+ this.requiredParent = tagRequiredParent[$.inArray(this.name, tagRequiredParent) + 1];
400
+ this.allowEmpty = $.inArray(this.name, tagAllowEmpty) > -1;
401
+
402
+ this.toProtect = $.inArray(this.name, tagProtect) > -1;
403
+
404
+ this.rawAttributes = rawAttributes;
405
+ this.allowedAttributes = tagAttributes[$.inArray(this.name, tagAttributes) + 1];
406
+ this.requiredAttributes = tagAttributesRequired[$.inArray(this.name, tagAttributesRequired) + 1];
407
+
408
+ this.render = options && $.inArray(this.name, options.notRenderedTags) == -1;
409
+
410
+ return this;
411
+ }
412
+
413
+ function startsWithWhitespace(item) {
414
+ while (isElement(item) && item.children.length > 0) {
415
+ item = item.children[0]
416
+ }
417
+ return isText(item) && item.length > 0 && $.htmlClean.isWhitespace(item.charAt(0));
418
+ }
419
+
420
+ function endsWithWhitespace(item) {
421
+ while (isElement(item) && item.children.length > 0) {
422
+ item = item.children[item.children.length - 1]
423
+ }
424
+ return isText(item) && item.length > 0 && $.htmlClean.isWhitespace(item.charAt(item.length - 1));
425
+ }
426
+
427
+ function isText(item) {
428
+ return item.constructor == String;
429
+ }
430
+
431
+ function isInline(item) {
432
+ return isText(item) || item.tag.isInline;
433
+ }
434
+
435
+ function isElement(item) {
436
+ return item.constructor == Element;
437
+ }
438
+
439
+ function textClean(text) {
440
+ return text.replace(/&nbsp;|\n/g, " ").replace(/\s\s+/g, " ");
441
+ }
442
+
443
+ // trim off white space, doesn't use regex
444
+ $.htmlClean.trim = function (text) {
445
+ return $.htmlClean.trimStart($.htmlClean.trimEnd(text));
446
+ };
447
+ $.htmlClean.trimStart = function (text) {
448
+ return text.substring($.htmlClean.trimStartIndex(text));
449
+ };
450
+ $.htmlClean.trimStartIndex = function (text) {
451
+ for (var start = 0; start < text.length - 1 && $.htmlClean.isWhitespace(text.charAt(start)); start++);
452
+ return start;
453
+ };
454
+ $.htmlClean.trimEnd = function (text) {
455
+ return text.substring(0, $.htmlClean.trimEndIndex(text));
456
+ };
457
+ $.htmlClean.trimEndIndex = function (text) {
458
+ for (var end = text.length - 1; end >= 0 && $.htmlClean.isWhitespace(text.charAt(end)); end--);
459
+ return end + 1;
460
+ };
461
+ // checks a char is white space or not
462
+ $.htmlClean.isWhitespace = function (c) {
463
+ return $.inArray(c, whitespace) != -1;
464
+ };
465
+
466
+ // tags which are inline
467
+ var tagInline = [
468
+ "a", "abbr", "acronym", "address", "b", "big", "br", "button",
469
+ "caption", "cite", "code", "del", "em", "font",
470
+ "hr", "i", "input", "img", "ins", "label", "legend", "map", "q",
471
+ "samp", "select", "small", "span", "strong", "sub", "sup",
472
+ "tt", "var"];
473
+ var tagDisallowNest = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "th", "td"];
474
+ var tagAllowEmpty = ["th", "td"];
475
+ var tagRequiredParent = [
476
+ null,
477
+ "li", ["ul", "ol"],
478
+ "dt", ["dl"],
479
+ "dd", ["dl"],
480
+ "td", ["tr"],
481
+ "th", ["tr"],
482
+ "tr", ["table", "thead", "tbody", "tfoot"],
483
+ "thead", ["table"],
484
+ "tbody", ["table"],
485
+ "tfoot", ["table"]
486
+ ];
487
+ var tagProtect = ["script", "style", "pre", "code"];
488
+ // tags which self close e.g. <br />
489
+ var tagSelfClosing = ["br", "hr", "img", "link", "meta"];
490
+ // tags which do not close
491
+ var tagNonClosing = ["!doctype", "?xml"];
492
+ // attributes allowed on tags
493
+ var tagAttributes = [
494
+ ["class"], // default, for all tags not mentioned
495
+ "?xml", [],
496
+ "!doctype", [],
497
+ "a", ["accesskey", "class", "href", "name", "title", "rel", "rev", "type", "tabindex"],
498
+ "abbr", ["class", "title"],
499
+ "acronym", ["class", "title"],
500
+ "blockquote", ["cite", "class"],
501
+ "button", ["class", "disabled", "name", "type", "value"],
502
+ "del", ["cite", "class", "datetime"],
503
+ "form", ["accept", "action", "class", "enctype", "method", "name"],
504
+ "input", ["accept", "accesskey", "alt", "checked", "class", "disabled", "ismap", "maxlength", "name", "size", "readonly", "src", "tabindex", "type", "usemap", "value"],
505
+ "img", ["alt", "class", "height", "src", "width"],
506
+ "ins", ["cite", "class", "datetime"],
507
+ "label", ["accesskey", "class", "for"],
508
+ "legend", ["accesskey", "class"],
509
+ "link", ["href", "rel", "type"],
510
+ "meta", ["content", "http-equiv", "name", "scheme"],
511
+ "map", ["name"],
512
+ "optgroup", ["class", "disabled", "label"],
513
+ "option", ["class", "disabled", "label", "selected", "value"],
514
+ "q", ["class", "cite"],
515
+ "td", ["colspan", "rowspan"],
516
+ "th", ["colspan", "rowspan"],
517
+ "script", ["src", "type"],
518
+ "select", ["class", "disabled", "multiple", "name", "size", "tabindex"],
519
+ "style", ["type"],
520
+ "table", ["class", "summary"],
521
+ "textarea", ["accesskey", "class", "cols", "disabled", "name", "readonly", "rows", "tabindex"]
522
+ ];
523
+ var tagAttributesRequired = [[], "img", ["alt"]];
524
+ // white space chars
525
+ var whitespace = [" ", " ", "\t", "\n", "\r", "\f"];
526
+
527
+ })(jQuery);
@@ -0,0 +1,88 @@
1
+ /*
2
+ * LiquidMetal, version: 0.1 (2009-02-05)
3
+ *
4
+ * A mimetic poly-alloy of Quicksilver's scoring algorithm, essentially
5
+ * LiquidMetal.
6
+ *
7
+ * For usage and examples, visit:
8
+ * http://github.com/rmm5t/liquidmetal
9
+ *
10
+ * Licensed under the MIT:
11
+ * http://www.opensource.org/licenses/mit-license.php
12
+ *
13
+ * Copyright (c) 2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
14
+ */
15
+ var LiquidMetal = function() {
16
+ var SCORE_NO_MATCH = 0.0;
17
+ var SCORE_MATCH = 1.0;
18
+ var SCORE_TRAILING = 0.8;
19
+ var SCORE_TRAILING_BUT_STARTED = 0.9;
20
+ var SCORE_BUFFER = 0.85;
21
+
22
+ return {
23
+ score: function(string, abbreviation) {
24
+ // Short circuits
25
+ if (abbreviation.length == 0) return SCORE_TRAILING;
26
+ if (abbreviation.length > string.length) return SCORE_NO_MATCH;
27
+
28
+ var scores = this.buildScoreArray(string, abbreviation);
29
+
30
+ var sum = 0.0;
31
+ for (var i =0; i < scores.length; i++) {
32
+ sum += scores[i];
33
+ }
34
+
35
+ return (sum / scores.length);
36
+ },
37
+
38
+ buildScoreArray: function(string, abbreviation) {
39
+ var scores = new Array(string.length);
40
+ var lower = string.toLowerCase();
41
+ var chars = abbreviation.toLowerCase().split("");
42
+
43
+ var lastIndex = -1;
44
+ var started = false;
45
+ for (var i =0; i < chars.length; i++) {
46
+ var c = chars[i];
47
+ var index = lower.indexOf(c, lastIndex+1);
48
+ if (index < 0) return fillArray(scores, SCORE_NO_MATCH);
49
+ if (index == 0) started = true;
50
+
51
+ if (isNewWord(string, index)) {
52
+ scores[index-1] = 1;
53
+ fillArray(scores, SCORE_BUFFER, lastIndex+1, index-1);
54
+ }
55
+ else if (isUpperCase(string, index)) {
56
+ fillArray(scores, SCORE_BUFFER, lastIndex+1, index);
57
+ }
58
+ else {
59
+ fillArray(scores, SCORE_NO_MATCH, lastIndex+1, index);
60
+ }
61
+
62
+ scores[index] = SCORE_MATCH;
63
+ lastIndex = index;
64
+ }
65
+
66
+ var trailingScore = started ? SCORE_TRAILING_BUT_STARTED : SCORE_TRAILING;
67
+ fillArray(scores, trailingScore, lastIndex+1);
68
+ return scores;
69
+ }
70
+ };
71
+
72
+ function isUpperCase(string, index) {
73
+ var c = string.charAt(index);
74
+ return ("A" <= c && c <= "Z");
75
+ }
76
+
77
+ function isNewWord(string, index) {
78
+ var c = string.charAt(index-1);
79
+ return (c == " " || c == "\t");
80
+ }
81
+
82
+ function fillArray(array, value, from, to) {
83
+ from = Math.max(from || 0, 0);
84
+ to = Math.min(to || array.length, array.length);
85
+ for (var i = from; i < to; i++) { array[i] = value; }
86
+ return array;
87
+ }
88
+ }();