PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/2010.Q3.1110/Source/Telerik.Web.Mvc.Examples/Scripts/Editor/inlineformat.js

#
JavaScript | 346 lines | 271 code | 74 blank | 1 comment | 57 complexity | 67fbee390fc06283839985bcb90aa201 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. function InlineFormatFinder(format) {
  2. function numberOfSiblings(referenceNode) {
  3. var count = 0;
  4. for (var node = referenceNode.parentNode.firstChild; node; node = node.nextSibling)
  5. if (node != referenceNode && node.className != 't-marker' && node.nodeType == 1)
  6. count++;
  7. return count;
  8. }
  9. this.findSuitable = function (sourceNode, skip) {
  10. if (!skip && numberOfSiblings(sourceNode) > 0)
  11. return null;
  12. return dom.parentOfType(sourceNode, format[0].tags);
  13. }
  14. this.findFormat = function (sourceNode) {
  15. for (var i = 0; i < format.length; i++) {
  16. var node = sourceNode;
  17. var tags = format[i].tags;
  18. var attributes = format[i].attr;
  19. if (node && dom.ofType(node, tags) && attrEquals(node, attributes))
  20. return node;
  21. while (node) {
  22. node = dom.parentOfType(node, tags);
  23. if (node && attrEquals(node, attributes))
  24. return node;
  25. }
  26. }
  27. return null;
  28. }
  29. this.isFormatted = function (nodes) {
  30. for (var i = 0; i < nodes.length; i++)
  31. if (this.findFormat(nodes[i]))
  32. return true;
  33. return false;
  34. }
  35. }
  36. function InlineFormatter(format, values) {
  37. this.finder = new InlineFormatFinder(format);
  38. var attributes = $.extend({}, format[0].attr, values);
  39. var tag = format[0].tags[0];
  40. function wrap(node) {
  41. return dom.wrap(node, dom.create(node.ownerDocument, tag, attributes));
  42. }
  43. this.activate = function(range, nodes) {
  44. if (this.finder.isFormatted(nodes)) {
  45. this.split(range);
  46. this.remove(nodes);
  47. } else
  48. this.apply(nodes);
  49. }
  50. this.toggle = function (range) {
  51. var nodes = textNodes(range);
  52. var isPending = nodes.length == 0;
  53. var caretMarker;
  54. if (isPending) {
  55. var markers = getMarkers(range);
  56. caretMarker = markers[1];
  57. var invisibleNode = this.editor.document.createTextNode('\ufeff');
  58. dom.insertBefore(invisibleNode, caretMarker);
  59. nodes.push(invisibleNode);
  60. invisibleNode = invisibleNode.cloneNode(true);
  61. dom.insertAfter(invisibleNode, caretMarker);
  62. nodes.push(invisibleNode);
  63. range.setEndAfter(markers[2]);
  64. }
  65. this.activate(range, nodes);
  66. if (isPending)
  67. this.editor.pendingFormats.push(caretMarker.parentNode);
  68. }
  69. this.apply = function (nodes) {
  70. var formatNodes = [];
  71. for (var i = 0, l = nodes.length; i < l; i++) {
  72. var node = nodes[i];
  73. var formatNode = this.finder.findSuitable(node);
  74. if (formatNode)
  75. dom.attr(formatNode, attributes);
  76. else
  77. formatNode = wrap(node);
  78. formatNodes.push(formatNode);
  79. }
  80. this.consolidate(formatNodes);
  81. }
  82. this.remove = function (nodes) {
  83. for (var i = 0, l = nodes.length; i < l; i++) {
  84. var formatNode = this.finder.findFormat(nodes[i]);
  85. if (formatNode)
  86. dom.unwrap(formatNode);
  87. }
  88. }
  89. this.split = function (range) {
  90. var nodes = textNodes(range);
  91. var isPending = nodes.length == 0;
  92. var caretMarker;
  93. if (isPending) {
  94. caretMarker = getMarkers(range)[1];
  95. nodes.push(caretMarker);
  96. }
  97. for (var i = 0, l = nodes.length; i < l; i++) {
  98. var formatNode = this.finder.findFormat(nodes[i]);
  99. if (formatNode)
  100. split(range, formatNode, true);
  101. }
  102. }
  103. this.consolidate = function (nodes) {
  104. while (nodes.length > 1) {
  105. var node = nodes.pop();
  106. var last = nodes[nodes.length - 1];
  107. if (node.previousSibling && node.previousSibling.className == 't-marker') {
  108. last.appendChild(node.previousSibling);
  109. }
  110. if (node.previousSibling == last && node.style.cssText == last.style.cssText) {
  111. while (node.firstChild)
  112. last.appendChild(node.firstChild);
  113. dom.remove(node);
  114. }
  115. }
  116. }
  117. }
  118. function GreedyInlineFormatFinder(format, greedyProperty) {
  119. InlineFormatFinder.call(this, format);
  120. function getInlineCssValue(node) {
  121. var attributes = node.attributes,
  122. trim = $.trim;
  123. for (var i = 0, l = attributes.length; i < l; i++) {
  124. var attribute = attributes[i];
  125. var name = attribute.nodeName;
  126. var attributeValue = attribute.nodeValue;
  127. if (attribute.specified && name == 'style') {
  128. var css = trim(attributeValue || node.style.cssText).split(';');
  129. for (var cssIndex = 0, len = css.length; cssIndex < len; cssIndex++) {
  130. var pair = css[cssIndex];
  131. if (pair.length) {
  132. var propertyAndValue = pair.split(':');
  133. var property = trim(propertyAndValue[0].toLowerCase()),
  134. value = trim(propertyAndValue[1]);
  135. if (property != greedyProperty)
  136. continue;
  137. return property.indexOf('color') >= 0 ? dom.toHex(value) : value;
  138. }
  139. }
  140. }
  141. }
  142. return;
  143. }
  144. function getFormat (node) {
  145. var $node = $(isDataNode(node) ? node.parentNode : node);
  146. var parents = $node.parents().andSelf();
  147. for (var i = 0, len = parents.length; i < len; i++) {
  148. var value = greedyProperty == 'className' ? parents[i].className : getInlineCssValue(parents[i]);
  149. if (value)
  150. return value;
  151. }
  152. return 'inherit';
  153. }
  154. this.getFormat = function (nodes) {
  155. var result = getFormat(nodes[0]);
  156. for (var i = 1, len = nodes.length; i < len; i++)
  157. if (result != getFormat(nodes[i]))
  158. return '';
  159. return result;
  160. }
  161. this.isFormatted = function (nodes) {
  162. return this.getFormat(nodes) !== '';
  163. }
  164. }
  165. function GreedyInlineFormatter(format, values, greedyProperty) {
  166. InlineFormatter.call(this, format, values);
  167. this.finder = new GreedyInlineFormatFinder(format, greedyProperty)
  168. this.activate = function(range, nodes) {
  169. this.split(range);
  170. if (greedyProperty) {
  171. var camelCase = greedyProperty.replace(/-([a-z])/, function(all, letter){return letter.toUpperCase()});
  172. this[values.style[camelCase] == 'inherit' ? 'remove' : 'apply'](nodes);
  173. } else {
  174. this.apply(nodes);
  175. }
  176. }
  177. }
  178. function InlineFormatTool(options) {
  179. FormatTool.call(this, $.extend(options, {
  180. finder: new InlineFormatFinder(options.format),
  181. formatter: function () { return new InlineFormatter(options.format) }
  182. }));
  183. }
  184. function FontTool(options){
  185. Tool.call(this, options);
  186. // IE has single selection hence we are using select box instead of combobox
  187. var type = $.browser.msie ? 'tSelectBox' : 'tComboBox';
  188. var finder = new GreedyInlineFormatFinder([{ tags: ['span'] }], options.cssAttr);
  189. this.command = function (commandArguments) {
  190. return new FormatCommand($.extend(commandArguments, {
  191. formatter: function () {
  192. var style = {};
  193. style[options.domAttr] = commandArguments.value;
  194. return new GreedyInlineFormatter([{ tags: ['span'] }], { style: style }, options.cssAttr);
  195. }
  196. }))
  197. }
  198. this.update = function ($ui, nodes) {
  199. var list = $ui.data(type);
  200. list.close();
  201. list.value(finder.getFormat(nodes));
  202. }
  203. this.init = function($ui, initOptions) {
  204. var editor = initOptions.editor;
  205. $ui[type]({
  206. data: editor[options.name],
  207. onChange: function (e) {
  208. Tool.exec(editor, options.name, e.value);
  209. },
  210. highlightFirst: false
  211. });
  212. $ui.data(type).dropDown.onItemCreate =
  213. function (e) {
  214. e.html = '<span unselectable="on" style="' + options.cssAttr + ': ' + e.dataItem.Value + '">' + e.dataItem.Text + '</span>';
  215. };
  216. }
  217. };
  218. function ColorTool (options) {
  219. Tool.call(this, options);
  220. var finder = new GreedyInlineFormatFinder([{ tags: ['span'] }], options.cssAttr);
  221. this.update = function($ui) {
  222. $ui.data('tColorPicker').close();
  223. }
  224. this.command = function (commandArguments) {
  225. return new FormatCommand($.extend(commandArguments, {
  226. formatter: function () {
  227. var style = {};
  228. style[options.domAttr] = commandArguments.value;
  229. return new GreedyInlineFormatter([{ tags: ['span'] }], { style: style }, options.cssAttr);
  230. }
  231. }))
  232. }
  233. this.init = function($ui, initOptions) {
  234. var editor = initOptions.editor;
  235. $ui.tColorPicker({
  236. selectedColor: '#000000',
  237. onChange: function (e) {
  238. Tool.exec(editor, options.name, e.value);
  239. }
  240. });
  241. }
  242. }
  243. function StyleTool() {
  244. Tool.call(this);
  245. var finder = new GreedyInlineFormatFinder([{ tags: ['span'] }], 'className');
  246. this.command = function (commandArguments) {
  247. return new FormatCommand($.extend(commandArguments, {
  248. formatter: function () {
  249. return new GreedyInlineFormatter([{ tags: ['span'] }], { className: commandArguments.value });
  250. }
  251. }));
  252. }
  253. this.update = function($ui, nodes) {
  254. var list = $ui.data('tSelectBox');
  255. list.close();
  256. list.value(finder.getFormat(nodes));
  257. }
  258. this.init = function($ui, initOptions) {
  259. var editor = initOptions.editor;
  260. $ui.tSelectBox({
  261. data: editor['style'],
  262. title: editor.localization.style,
  263. onItemCreate: function (e) {
  264. var style = dom.inlineStyle(editor.document, 'span', {className : e.dataItem.Value});
  265. e.html = '<span unselectable="on" style="display:block;' + style +'">' + e.html + '</span>';
  266. },
  267. onChange: function (e) {
  268. Tool.exec(editor, 'style', e.value);
  269. }
  270. });
  271. }
  272. };