right-rails 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/CHANGELOG +7 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +1 -1
  4. data/init.rb +1 -0
  5. data/lib/generators/right_rails/right_rails_generator.rb +15 -6
  6. data/lib/right_rails.rb +1 -1
  7. data/lib/right_rails/controller_extensions.rb +28 -15
  8. data/lib/right_rails/helpers/misc.rb +38 -38
  9. data/lib/right_rails/helpers/rails.rb +50 -7
  10. data/lib/rjs_renderer.rb +26 -0
  11. data/spec/lib/right_rails/controller_extensions_spec.rb +25 -14
  12. data/spec/lib/right_rails/helpers/forms_spec.rb +6 -6
  13. data/spec/lib/right_rails/helpers/rails_spec.rb +44 -45
  14. data/vendor/assets/images/rightjs-ui/rte.png +0 -0
  15. data/vendor/assets/javascripts/right-safe-src.js +2 -2
  16. data/vendor/assets/javascripts/right-safe.js +2 -2
  17. data/vendor/assets/javascripts/right-src.js +386 -100
  18. data/vendor/assets/javascripts/right.js +2 -2
  19. data/vendor/assets/javascripts/right/calendar-src.js +19 -3
  20. data/vendor/assets/javascripts/right/calendar.js +2 -2
  21. data/vendor/assets/javascripts/right/colorpicker-src.js +59 -20
  22. data/vendor/assets/javascripts/right/colorpicker.js +2 -2
  23. data/vendor/assets/javascripts/right/i18n/de.js +43 -42
  24. data/vendor/assets/javascripts/right/i18n/es.js +1 -0
  25. data/vendor/assets/javascripts/right/i18n/fi.js +1 -0
  26. data/vendor/assets/javascripts/right/i18n/fr.js +1 -0
  27. data/vendor/assets/javascripts/right/i18n/hu.js +1 -0
  28. data/vendor/assets/javascripts/right/i18n/it.js +1 -0
  29. data/vendor/assets/javascripts/right/i18n/jp.js +1 -0
  30. data/vendor/assets/javascripts/right/i18n/lt.js +96 -0
  31. data/vendor/assets/javascripts/right/i18n/nl.js +1 -0
  32. data/vendor/assets/javascripts/right/i18n/pt-br.js +1 -0
  33. data/vendor/assets/javascripts/right/i18n/ru.js +1 -0
  34. data/vendor/assets/javascripts/right/i18n/ua.js +1 -0
  35. data/vendor/assets/javascripts/right/jquerysh-src.js +4 -4
  36. data/vendor/assets/javascripts/right/jquerysh.js +2 -2
  37. data/vendor/assets/javascripts/right/rails-src.js +51 -15
  38. data/vendor/assets/javascripts/right/rails.js +2 -2
  39. data/vendor/assets/javascripts/right/resizable-src.js +11 -11
  40. data/vendor/assets/javascripts/right/rte-src.js +33 -13
  41. data/vendor/assets/javascripts/right/rte.js +2 -2
  42. data/vendor/assets/javascripts/right/slider-src.js +137 -28
  43. data/vendor/assets/javascripts/right/slider.js +2 -2
  44. metadata +24 -126
  45. data/generators/right_rails/right_rails_generator.rb +0 -46
  46. data/generators/right_rails/templates/iframed.html.erb +0 -10
  47. data/generators/right_scaffold/right_scaffold_generator.rb +0 -53
  48. data/generators/right_scaffold/templates/controller.rb +0 -99
  49. data/generators/right_scaffold/templates/helper.rb +0 -2
  50. data/generators/right_scaffold/templates/layout.html.erb +0 -18
  51. data/generators/right_scaffold/templates/style.css +0 -54
  52. data/generators/right_scaffold/templates/view__form.html.erb +0 -16
  53. data/generators/right_scaffold/templates/view__item.html.erb +0 -13
  54. data/generators/right_scaffold/templates/view_edit.html.erb +0 -6
  55. data/generators/right_scaffold/templates/view_index.html.erb +0 -9
  56. data/generators/right_scaffold/templates/view_new.html.erb +0 -5
  57. data/generators/right_scaffold/templates/view_show.html.erb +0 -10
  58. data/lib/generators/right_rails/templates/iframed.html.erb +0 -10
  59. data/public/images/rightjs-ui/colorpicker.png +0 -0
  60. data/public/images/rightjs-ui/resizable.png +0 -0
  61. data/public/images/rightjs-ui/rte.png +0 -0
  62. data/public/javascripts/right-olds-src.js +0 -652
  63. data/public/javascripts/right-olds.js +0 -9
  64. data/public/javascripts/right-safe-src.js +0 -68
  65. data/public/javascripts/right-safe.js +0 -7
  66. data/public/javascripts/right-src.js +0 -6014
  67. data/public/javascripts/right.js +0 -7
  68. data/public/javascripts/right/autocompleter-src.js +0 -625
  69. data/public/javascripts/right/autocompleter.js +0 -7
  70. data/public/javascripts/right/billboard-src.js +0 -564
  71. data/public/javascripts/right/billboard.js +0 -7
  72. data/public/javascripts/right/calendar-src.js +0 -1464
  73. data/public/javascripts/right/calendar.js +0 -7
  74. data/public/javascripts/right/casting-src.js +0 -183
  75. data/public/javascripts/right/casting.js +0 -7
  76. data/public/javascripts/right/colorpicker-src.js +0 -981
  77. data/public/javascripts/right/colorpicker.js +0 -7
  78. data/public/javascripts/right/dialog-src.js +0 -768
  79. data/public/javascripts/right/dialog.js +0 -7
  80. data/public/javascripts/right/dnd-src.js +0 -591
  81. data/public/javascripts/right/dnd.js +0 -7
  82. data/public/javascripts/right/effects-src.js +0 -508
  83. data/public/javascripts/right/effects.js +0 -7
  84. data/public/javascripts/right/i18n/de.js +0 -95
  85. data/public/javascripts/right/i18n/en-us.js +0 -11
  86. data/public/javascripts/right/i18n/es.js +0 -95
  87. data/public/javascripts/right/i18n/fi.js +0 -96
  88. data/public/javascripts/right/i18n/fr.js +0 -95
  89. data/public/javascripts/right/i18n/hu.js +0 -100
  90. data/public/javascripts/right/i18n/it.js +0 -95
  91. data/public/javascripts/right/i18n/jp.js +0 -99
  92. data/public/javascripts/right/i18n/nl.js +0 -95
  93. data/public/javascripts/right/i18n/pt-br.js +0 -95
  94. data/public/javascripts/right/i18n/ru.js +0 -95
  95. data/public/javascripts/right/i18n/ua.js +0 -99
  96. data/public/javascripts/right/in-edit-src.js +0 -373
  97. data/public/javascripts/right/in-edit.js +0 -7
  98. data/public/javascripts/right/jquerysh-src.js +0 -362
  99. data/public/javascripts/right/jquerysh.js +0 -7
  100. data/public/javascripts/right/json-src.js +0 -147
  101. data/public/javascripts/right/json.js +0 -7
  102. data/public/javascripts/right/keys-src.js +0 -87
  103. data/public/javascripts/right/keys.js +0 -7
  104. data/public/javascripts/right/lightbox-src.js +0 -931
  105. data/public/javascripts/right/lightbox.js +0 -7
  106. data/public/javascripts/right/rails-src.js +0 -402
  107. data/public/javascripts/right/rails.js +0 -7
  108. data/public/javascripts/right/rater-src.js +0 -384
  109. data/public/javascripts/right/rater.js +0 -7
  110. data/public/javascripts/right/resizable-src.js +0 -465
  111. data/public/javascripts/right/resizable.js +0 -7
  112. data/public/javascripts/right/rte-src.js +0 -2685
  113. data/public/javascripts/right/rte.js +0 -7
  114. data/public/javascripts/right/selectable-src.js +0 -725
  115. data/public/javascripts/right/selectable.js +0 -7
  116. data/public/javascripts/right/sizzle-src.js +0 -1132
  117. data/public/javascripts/right/sizzle.js +0 -7
  118. data/public/javascripts/right/slider-src.js +0 -395
  119. data/public/javascripts/right/slider.js +0 -7
  120. data/public/javascripts/right/sortable-src.js +0 -430
  121. data/public/javascripts/right/sortable.js +0 -7
  122. data/public/javascripts/right/table-src.js +0 -176
  123. data/public/javascripts/right/table.js +0 -7
  124. data/public/javascripts/right/tabs-src.js +0 -1157
  125. data/public/javascripts/right/tabs.js +0 -7
  126. data/public/javascripts/right/tags-src.js +0 -745
  127. data/public/javascripts/right/tags.js +0 -7
  128. data/public/javascripts/right/tooltips-src.js +0 -331
  129. data/public/javascripts/right/tooltips.js +0 -7
  130. data/public/javascripts/right/uploader-src.js +0 -302
  131. data/public/javascripts/right/uploader.js +0 -7
@@ -1,7 +0,0 @@
1
- /**
2
- * RightJS-UI Resizable v2.2.3
3
- * http://rightjs.org/ui/resizable
4
- *
5
- * Copyright (C) 2010-2011 Nikolay Nemshilov
6
- */
7
- var Resizable=RightJS.Resizable=function(a,b){function c(a,c){c||(c=a,a="DIV");var d=new b.Class(b.Element.Wrappers[a]||b.Element,{initialize:function(c,d){this.key=c;var e=[{"class":"rui-"+c}];this instanceof b.Input||this instanceof b.Form||e.unshift(a),this.$super.apply(this,e),b.isString(d)&&(d=b.$(d)),d instanceof b.Element&&(this._=d._,"$listeners"in d&&(d.$listeners=d.$listeners),d={}),this.setOptions(d,this);return b.Wrapper.Cache[b.$uid(this._)]=this},setOptions:function(a,c){c&&(a=b.Object.merge(a,(new Function("return "+(c.get("data-"+this.key)||"{}")))())),a&&b.Options.setOptions.call(this,b.Object.merge(this.options,a));return this}}),e=new b.Class(d,c);b.Observer.createShortcuts(e.prototype,e.EVENTS||b([]));return e}var d=b,e=b.$,f=b.$w,g=b.$E,h=b.Class,i=b.Element,j=new c({extend:{version:"2.2.3",EVENTS:f("resize start release"),Options:{direction:null,minWidth:null,maxWidth:null,minHeight:null,maxHeight:null}},initialize:function(a,b){this.$super("resizable",this.old_inst=e(a)).setOptions(b),this.options.direction?this.addClass("rui-resizable-"+this.options.direction):this.addClass("rui-resizable"),this.content=this.first(".rui-resizable-content")||g("div",{"class":"rui-resizable-content"}).insert(this.children()).insertTo(this),this.handle=this.first(".rui-resizable-handle")||g("div",{"class":"rui-resizable-handle"}).insertTo(this),this.content.setWidth(this.size().x-parseInt(this.getStyle("borderLeftWidth"),10)-parseInt(this.getStyle("borderRightWidth"),10)),this.options.direction!=="left"&&this.options.direction!=="right"&&this.content.setHeight(this.size().y-parseInt(this.getStyle("borderTopWidth"),10)-parseInt(this.getStyle("borderBottomWidth"),10))},destroy:function(){this.removeClass("rui-resizable").removeClass("rui-resizable-top").removeClass("rui-resizable-left").removeClass("rui-resizable-right").removeClass("rui-resizable-bottom").insert(this.content._.childNodes),this.content.remove(),this.handle.remove(),this.old_inst&&(Wrapper.Cache[$uid(this._)]=this.old_inst);return this},setOptions:function(a,b){a=a||{},f("top left right bottom").each(function(b){this.hasClass("rui-resizable-"+b)&&(a.direction=b)},this);return this.$super(a,b)},start:function(a){this.prevSizes=this.size(),this.prevEvPos=a.position(),this.contXDiff=this.size().x-this.content.size().x,this.contYDiff=this.size().y-this.content.size().y,f("minWidth maxWidth minHeight maxHeight").each(function(a){this[a]=this.findDim(a)},this);return this.fire("start",{original:a})},track:function(a){var b=a.position(),c=this.prevEvPos,d=this.handle.dimensions(),e=this.prevSizes,f=e.x,g=e.y,h=c.x-b.x,i=c.y-b.y,j=this.minWidth,k=this.maxWidth,l=this.minHeight,m=this.maxHeight,n=this.options,o=n.direction;f+=(o==="left"?1:-1)*h,g+=(o==="top"?1:-1)*i,f<j&&(f=j),f>k&&(f=k),g<l&&(g=l),g>m&&(g=m),e.x!==f&&o!=="top"&&o!=="bottom"&&this.setWidth(f),e.y!==g&&o!=="left"&&o!=="right"&&this.setHeight(g);if(f==j||f==k)b.x=d.left+d.width/2;if(g==l||g==m)b.y=d.top+d.height/2;this.prevEvPos=b,this.prevSizes=this.size(),this.fire("resize",{original:a})},setWidth:function(a){this.content.setWidth(a-this.contXDiff);return this.$super(a)},setHeight:function(a){this.content.setHeight(a-this.contYDiff);return this.$super(a)},release:function(a){return this.fire("release",{original:a})},findDim:function(a){var b=this.options[a]||this.getStyle(a);if(b&&/\d+/.test(b)&&parseFloat(b)>0){var c=d(a).include("Width")?"width":"height",e=(this._dummy||(this._dummy=g("div",{style:"visibility:hidden;z-index:-1"}))).setStyle(c,b).insertTo(this,"before"),f=e._["offset"+d(c).capitalize()];e.remove();return f}}});e(a).on({mousedown:function(a){var b=a.find(".rui-resizable-handle");if(b){var c=b.parent();c instanceof j||(c=new j(c)),j.current=c.start(a.stop())}},mousemove:function(a){var b=j.current;b&&b.track(a)},mouseup:function(a){var b=j.current;b&&(b.release(a),j.current=null)}}),e(window).onBlur(function(a){var b=j.current;b&&(b.release(a),j.current=null)}),i.include({makeResizable:function(a){return new j(this,a)},undoResizable:function(){this instanceof j&&this.destroy();return this}}),"Draggable"in b&&b.Draggable.include({dragStart:function(a){a.target.hasClass("rui-resizable-handle")||this.$super(a)}});var k=a.createElement("style"),l=a.createTextNode(".rui-resizable,.rui-resizable-top,.rui-resizable-left,.rui-resizable-right,.rui-resizable-bottom,.rui-resizable-content .rui-resizable-handle{margin:0;padding:0;overflow:none;border:none;background:none;width:auto;height:auto;min-width:none;max-width:none;min-height:none;max-height:none}.rui-resizable,.rui-resizable-top,.rui-resizable-left,.rui-resizable-right,.rui-resizable-bottom{position:relative;min-width:8em;min-height:8em;border:1px solid #DDD}.rui-resizable-content{overflow:auto;padding:.5em;position:relative}.rui-resizable-handle{position:absolute;background-image:url(/images/rightjs-ui/resizable.png);background-repeat:no-repeat;background-color:#DDD;cursor:move}.rui-resizable .rui-resizable-handle{right:0;bottom:0;background-position:-2px -2px;background-color:transparent;width:16px;height:16px}.rui-resizable-top .rui-resizable-handle,.rui-resizable-bottom .rui-resizable-handle{height:8px;width:100%;background-position:center -26px;cursor:row-resize}.rui-resizable-left .rui-resizable-handle,.rui-resizable-right .rui-resizable-handle{top:0px;width:8px;height:100%;background-position:-26px center;cursor:col-resize}.rui-resizable-top .rui-resizable-content{padding-top:1em}.rui-resizable-top .rui-resizable-handle{top:0}.rui-resizable-bottom .rui-resizable-content{padding-bottom:1em}.rui-resizable-bottom .rui-resizable-handle{bottom:0}.rui-resizable-left .rui-resizable-content{padding-left:1em}.rui-resizable-left .rui-resizable-handle{left:0}.rui-resizable-right .rui-resizable-content{padding-right:1em}.rui-resizable-right .rui-resizable-handle{right:0}");k.type="text/css",a.getElementsByTagName("head")[0].appendChild(k),k.styleSheet?k.styleSheet.cssText=l.nodeValue:k.appendChild(l);return j}(document,RightJS)
@@ -1,2685 +0,0 @@
1
- /**
2
- * RightJS-UI RTE v2.2.0
3
- * http://rightjs.org/ui/rte
4
- *
5
- * Copyright (C) 2010-2011 Nikolay Nemshilov
6
- */
7
- var Rte = RightJS.Rte = (function(RightJS, document, window) {
8
- /**
9
- * This module defines the basic widgets constructor
10
- * it creates an abstract proxy with the common functionality
11
- * which then we reuse and override in the actual widgets
12
- *
13
- * Copyright (C) 2010-2011 Nikolay Nemshilov
14
- */
15
-
16
- /**
17
- * The widget units constructor
18
- *
19
- * @param String tag-name or Object methods
20
- * @param Object methods
21
- * @return Widget wrapper
22
- */
23
- function Widget(tag_name, methods) {
24
- if (!methods) {
25
- methods = tag_name;
26
- tag_name = 'DIV';
27
- }
28
-
29
- /**
30
- * An Abstract Widget Unit
31
- *
32
- * Copyright (C) 2010 Nikolay Nemshilov
33
- */
34
- var AbstractWidget = new RightJS.Class(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
35
- /**
36
- * The common constructor
37
- *
38
- * @param Object options
39
- * @param String optional tag name
40
- * @return void
41
- */
42
- initialize: function(key, options) {
43
- this.key = key;
44
- var args = [{'class': 'rui-' + key}];
45
-
46
- // those two have different constructors
47
- if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
48
- args.unshift(tag_name);
49
- }
50
- this.$super.apply(this, args);
51
-
52
- if (RightJS.isString(options)) {
53
- options = RightJS.$(options);
54
- }
55
-
56
- // if the options is another element then
57
- // try to dynamically rewrap it with our widget
58
- if (options instanceof RightJS.Element) {
59
- this._ = options._;
60
- if ('$listeners' in options) {
61
- options.$listeners = options.$listeners;
62
- }
63
- options = {};
64
- }
65
- this.setOptions(options, this);
66
-
67
- return (RightJS.Wrapper.Cache[RightJS.$uid(this._)] = this);
68
- },
69
-
70
- // protected
71
-
72
- /**
73
- * Catches the options
74
- *
75
- * @param Object user-options
76
- * @param Element element with contextual options
77
- * @return void
78
- */
79
- setOptions: function(options, element) {
80
- if (element) {
81
- options = RightJS.Object.merge(options, new Function("return "+(
82
- element.get('data-'+ this.key) || '{}'
83
- ))());
84
- }
85
-
86
- if (options) {
87
- RightJS.Options.setOptions.call(this, RightJS.Object.merge(this.options, options));
88
- }
89
-
90
- return this;
91
- }
92
- });
93
-
94
- /**
95
- * Creating the actual widget class
96
- *
97
- */
98
- var Klass = new RightJS.Class(AbstractWidget, methods);
99
-
100
- // creating the widget related shortcuts
101
- RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || RightJS([]));
102
-
103
- return Klass;
104
- }
105
-
106
-
107
- /**
108
- * RTE's initialization script
109
- *
110
- * Copyright (C) 2010-2011 Nikolay Nemshilov
111
- */
112
-
113
- var R = RightJS,
114
- $ = RightJS.$,
115
- $$ = RightJS.$$,
116
- $w = RightJS.$w,
117
- $E = RightJS.$E,
118
- $A = RightJS.$A,
119
- isArray = RightJS.isArray,
120
- RegExp = RightJS.RegExp,
121
- Class = RightJS.Class,
122
- Element = RightJS.Element,
123
- Input = RightJS.Input;
124
-
125
-
126
-
127
-
128
- /**
129
- * The Right Text Editor
130
- *
131
- * Copyright (C) 2010-2011 Nikolay Nemshilov
132
- */
133
- var Rte = new Widget({
134
-
135
- extend: {
136
- version: '2.2.0',
137
-
138
- EVENTS: $w('change focus blur'),
139
-
140
- // checking if the 'contentEditable' feature is supported at all
141
- supported: 'contentEditable' in document.createElement('div'),
142
-
143
- Options: {
144
- toolbar: 'small', // toolbar, the name or an array of your own
145
-
146
- autoresize: true, // automatically resize the editor's height to fit the text
147
-
148
- showToolbar: true, // show the toolbar
149
- showStatus: true, // show the status bar
150
-
151
- videoSize: '425x344', // flash-video blocks default size
152
-
153
- cssRule: 'textarea[data-rte]'
154
- },
155
-
156
- // predefined toolbars set
157
- Toolbars: {
158
- small: ['Bold Italic Underline Strike Ttext|Cut Copy Paste|Header Code Quote|Link Image Video|Source'],
159
- basic: [
160
- 'Save Clear|Cut Copy Paste|Bold Italic Underline Strike Ttext|Left Center Right Justify',
161
- 'Undo Redo|Header Code Quote|Link Image Video|Dotlist Numlist|Indent Outdent|Source'
162
- ],
163
- extra: [
164
- 'Save Clear|Cut Copy Paste|Bold Italic Underline Strike Ttext|Left Center Right Justify',
165
- 'Undo Redo|Header Code Quote|Link Image Video|Subscript Superscript|Dotlist Numlist|Indent Outdent',
166
- 'Format|Fontname Fontsize|Forecolor Backcolor|Source'
167
- ]
168
- },
169
-
170
- Tools: {}, // the index of available tools will be here
171
-
172
- // the keyboard bindings
173
- Shortcuts: {
174
- Bold: 'b',
175
- Italic: 'i',
176
- Underline: 'u',
177
- // Ttext: 't',
178
- Header: 'h',
179
- Link: 'l',
180
- Cut: 'x',
181
- Copy: 'c',
182
- Paste: 'v',
183
- Undo: 'z',
184
- Redo: 'shift+z',
185
- Source: 'e',
186
- // Quote: 'q',
187
- Code: 'p',
188
- Save: 's'
189
- },
190
-
191
- // tags used by default with formatting tools
192
- Tags: {
193
- Bold: 'b',
194
- Italic: 'i',
195
- Underline: 'u',
196
- Strike: 's',
197
- Ttext: 'tt',
198
- Code: 'pre',
199
- Quote: 'blockquote',
200
- Header: 'h2'
201
- },
202
-
203
- // the formatting options, you can use simply tag names
204
- // or you can also specify tag + class like 'div.blue'
205
- Formats: {
206
- 'h1': 'Header 1',
207
- 'h2': 'Header 2',
208
- 'h3': 'Header 3',
209
- 'h4': 'Header 4',
210
- 'p': 'Paragraph',
211
- 'pre': 'Preformatted',
212
- 'blockquote': 'Blockquote',
213
- 'tt': 'Typetext',
214
- 'address': 'Address'
215
- },
216
-
217
- // the font-name options
218
- FontNames: {
219
- 'Andale Mono': 'andale mono,times',
220
- 'Arial': 'arial,helvetica,sans-serif',
221
- 'Arial Black': 'arial black,avant garde',
222
- 'Book Antiqua': 'book antiqua,palatino',
223
- 'Comic Sans MS': 'comic sans ms,sans-serif',
224
- 'Courier New': 'courier new,courier',
225
- 'Georgia': 'georgia,palatino',
226
- 'Helvetica': 'helvetica',
227
- 'Impact': 'impact,chicago',
228
- 'Symbol': 'symbol',
229
- 'Tahoma': 'tahoma,arial,helvetica,sans-serif',
230
- 'Terminal': 'terminal,monaco',
231
- 'Times New Roman': 'times new roman,times',
232
- 'Trebuchet MS': 'trebuchet ms,geneva',
233
- 'Verdana': 'verdana,geneva',
234
- 'Webdings': 'webdings',
235
- 'Wingdings': 'wingdings,zapf dingbats'
236
- },
237
-
238
- // the font-size options
239
- FontSizes: '6pt 7pt 8pt 9pt 10pt 11pt 12pt 14pt 18pt 24pt 36pt',
240
-
241
- Videos: [
242
- // supported swf video resources
243
- [/(http:\/\/.*?youtube\.[a-z]+)\/watch\?v=([^&]+)/, '$1/v/$2'],
244
- [/(http:\/\/video.google.com)\/videoplay\?docid=([^&]+)/, '$1/googleplayer.swf?docId=$2'],
245
- [/(http:\/\/vimeo\.[a-z]+)\/([0-9]+).*?/, '$1/moogaloop.swf?clip_id=$2']
246
- ],
247
-
248
- i18n: {
249
- Clear: 'Clear',
250
- Save: 'Save',
251
- Source: 'Source',
252
- Bold: 'Bold',
253
- Italic: 'Italic',
254
- Underline: 'Underline',
255
- Strike: 'Strike through',
256
- Ttext: 'Typetext',
257
- Header: 'Header',
258
- Cut: 'Cut',
259
- Copy: 'Copy',
260
- Paste: 'Paste',
261
- Left: 'Left',
262
- Center: 'Center',
263
- Right: 'Right',
264
- Justify: 'Justify',
265
- Undo: 'Undo',
266
- Redo: 'Redo',
267
- Code: 'Code block',
268
- Quote: 'Block quote',
269
- Link: 'Add link',
270
- Image: 'Insert image',
271
- Video: 'Insert video',
272
- Dotlist: 'List with dots',
273
- Numlist: 'List with numbers',
274
- Indent: 'Indent',
275
- Outdent: 'Outdent',
276
- Forecolor: 'Text color',
277
- Backcolor: 'Background color',
278
- Select: 'Select',
279
- Remove: 'Remove',
280
- Format: 'Format',
281
- Fontname: 'Font name',
282
- Fontsize: 'Size',
283
- Subscript: 'Subscript',
284
- Superscript: 'Superscript',
285
- UrlAddress: 'URL Address'
286
- },
287
-
288
- current: null
289
- },
290
-
291
- /**
292
- * Basic constructor
293
- *
294
- * @param Input textarea reference
295
- * @param Object additional options
296
- * @return void
297
- */
298
- initialize: function(textarea, options) {
299
- this
300
- .$super('rte', {})
301
- .setOptions(options, textarea)
302
- .append(
303
- this.toolbar = new Rte.Toolbar(this),
304
- this.editor = new Rte.Editor(this),
305
- this.status = new Rte.Status(this)
306
- );
307
-
308
- if (!this.options.showToolbar) {
309
- this.toolbar.hide();
310
- }
311
-
312
- if (!this.options.showStatus) {
313
- this.status.hide();
314
- }
315
-
316
- if (textarea) {
317
- this.assignTo(textarea);
318
- }
319
-
320
- this.undoer = new Rte.Undoer(this);
321
- this.selection = new Rte.Selection(this);
322
-
323
- // updating the initial state
324
- this.selection.exec('styleWithCss', false);
325
- this.status.update();
326
- },
327
-
328
- /**
329
- * Sets the value
330
- *
331
- * @param String value
332
- * @return Rte this
333
- */
334
- setValue: function(value) {
335
- if (this.textarea) {
336
- this.textarea.value(value);
337
- }
338
- this.editor.update(value);
339
- return this;
340
- },
341
-
342
- /**
343
- * Returns the current value
344
- *
345
- * @return String current value
346
- */
347
- getValue: function() {
348
- return this.editor._.innerHTML;
349
- },
350
-
351
- /**
352
- * Bidirectional method to set/get the value
353
- *
354
- * @param String value
355
- * @return Rte this or String value
356
- */
357
- value: function(value) {
358
- return this[value === undefined ? 'getValue' : 'setValue'](value);
359
- },
360
-
361
- /**
362
- * Disables the editor
363
- *
364
- * @return Rte this
365
- */
366
- disable: function() {
367
- this.disabled = true;
368
- return this.addClass('rui-rte-disabled');
369
- },
370
-
371
- /**
372
- * Enables the editor
373
- *
374
- * @return Rte this
375
- */
376
- enable: function() {
377
- this.disabled = false;
378
- return this.removeClass('rui-rte-disabled');
379
- },
380
-
381
- /**
382
- * Puts the focus into the editor
383
- *
384
- * @return Rte this
385
- */
386
- focus: function() {
387
- if (Rte.current !== this) {
388
- Rte.current = this;
389
- this.editor.focus();
390
- }
391
-
392
- return this;
393
- },
394
-
395
- /**
396
- * Looses focus from the editor
397
- *
398
- * @return Rte this
399
- */
400
- blur: function() {
401
- Rte.current = null;
402
-
403
- this.editor.blur();
404
-
405
- return this;
406
- },
407
-
408
- /**
409
- * Assigns this Rte to work with this textarea
410
- *
411
- * @param mixed textarea reference
412
- * @return Rte this
413
- */
414
- assignTo: function(element) {
415
- var textarea = $(element),
416
- size = textarea.size();
417
-
418
- // displaying self only if the 'contentEditable' feature is supported
419
- // otherwise keeping original textarea where it is
420
- if (Rte.supported) {
421
- this.insertTo(textarea.setStyle(
422
- 'position:absolute;left:-9999em;'
423
- ), 'before');
424
-
425
- this.editor.resize(size);
426
- this.setWidth(size.x);
427
-
428
- if (this.options.autoresize) {
429
- this.editor.setStyle({
430
- minHeight: size.y + 'px',
431
- height: 'auto'
432
- });
433
- }
434
- } else {
435
- textarea.setStyle('visibility:visible');
436
- }
437
-
438
- this.setValue(textarea.value());
439
- this.onChange(function() {
440
- textarea._.value = this.editor._.innerHTML;
441
- });
442
-
443
- this.textarea = textarea;
444
-
445
- return this;
446
- }
447
-
448
- });
449
-
450
- /**
451
- * Rte's toolbar unit
452
- *
453
- * Copyright (C) 2010 Nikolay Nemshilov
454
- */
455
- Rte.Toolbar = new Class(Element, {
456
-
457
- initialize: function(rte) {
458
- this.$super('div', {'class': 'rui-rte-toolbar'});
459
-
460
- this.rte = rte;
461
- rte.tools = {};
462
-
463
- var options = rte.options, toolbar = options.toolbar;
464
-
465
- R(Rte.Toolbars[toolbar] || (isArray(toolbar) ? toolbar : [toolbar])).each(function(line_s) {
466
- var line = $E('div', {'class': 'line'}).insertTo(this);
467
-
468
- R(line_s.split('|')).each(function(bar_s) {
469
- if (!R(bar_s).blank()) {
470
- var bar = $E('div', {'class': 'bar'}).insertTo(line);
471
-
472
- R(bar_s.split(' ')).each(function(tool) {
473
- tool = R(tool).capitalize();
474
- bar.insert(new Rte.Tools[tool](rte));
475
- });
476
- }
477
- });
478
- }, this);
479
-
480
- // adding hidden undo/redo tools if they are not on the toolbar
481
- // so that the undoer kicked in on the keybindings
482
- rte.tools.Undo || new Rte.Tools.Undo(rte);
483
- rte.tools.Redo || new Rte.Tools.Redo(rte);
484
- },
485
-
486
- /**
487
- * Finds a tool for the keyboard event
488
- *
489
- * @param {Event} event
490
- * @return {Rte.Tool} wired tool or false
491
- */
492
- shortcut: function(event) {
493
- var raw = event._, key, tool;
494
-
495
- for (key in this.rte.tools) {
496
- tool = this.rte.tools[key];
497
-
498
- if (tool.shortcut === raw.keyCode && tool.shiftKey === raw.shiftKey) {
499
- return tool;
500
- }
501
- }
502
-
503
- return null;
504
- }
505
-
506
- });
507
-
508
- /**
509
- * The actual Editor unit for the Rte
510
- *
511
- * Copyright (C) 2010 Nikolay Nemshilov
512
- */
513
- Rte.Editor = new Class(Element, {
514
-
515
- /**
516
- * Basic constructor
517
- *
518
- * @param Rte rte
519
- * @return void
520
- */
521
- initialize: function(rte) {
522
- // IE won't allow us to set 'contenteditable' progarmatically
523
- // so we put it as a textual content and then find it manually
524
- this.$super(rte
525
- .append('<div contenteditable="true" class="rui-rte-editor"></div>')
526
- .first('div.rui-rte-editor')._
527
- );
528
-
529
- this.rte = rte;
530
-
531
- this.on({
532
- focus: this._focus,
533
- blur: this._blur,
534
- mouseup: this._mouseup,
535
- keypress: this._keypress,
536
- keydown: this._keydown,
537
- keyup: this._keyup
538
- });
539
- },
540
-
541
- /**
542
- * Updates the editor's content
543
- *
544
- * @param String text
545
- * @return Rte.Editor this
546
- */
547
- update: function(text) {
548
- this.$super(text);
549
- return this;
550
- },
551
-
552
- /**
553
- * puts focus on the editing area
554
- *
555
- * @return Rte.Editor this
556
- */
557
- focus: function() {
558
- this._.focus();
559
- return this;
560
- },
561
-
562
- /**
563
- * removes focus out of the editing area
564
- *
565
- * @return Rte.Editor this
566
- */
567
- blur: function() {
568
- this._.blur();
569
- return this;
570
- },
571
-
572
- /**
573
- * Removes the element from the editor, placing all its content
574
- * in its place
575
- *
576
- * @param raw dom element
577
- * @return void
578
- */
579
- removeElement: function(element) {
580
- if (element !== null) {
581
- var parent = element.parentNode;
582
- while (element.firstChild) {
583
- parent.insertBefore(element.firstChild, element);
584
- }
585
- parent.removeChild(element);
586
- }
587
- },
588
-
589
- // protected
590
-
591
- _focus: function() {
592
- this.rte.selection.restore();
593
- this.rte.status.update();
594
- this.rte.focused = true;
595
- },
596
-
597
- _blur: function() {
598
- this.rte.focused = false;
599
- this.rte.status.update();
600
- },
601
-
602
- _mouseup: function() {
603
- this._focus();
604
- },
605
-
606
- _keypress: function(event) {
607
- if (this.__stopped) {
608
- event.stop();
609
- }
610
- },
611
-
612
- _keydown: function(event) {
613
- var raw = event._, stopped = false, tool;
614
-
615
- if (raw.metaKey || raw.ctrlKey) {
616
- if ((tool = this.rte.toolbar.shortcut(event))) {
617
- tool.call(event);
618
- }
619
-
620
- stopped = event.stopped;
621
- }
622
-
623
- // an internal marker to lock the 'keypress' event later on
624
- this.__stopped = stopped;
625
- },
626
-
627
- _keyup: function(event) {
628
- switch (event.keyCode) {
629
- case 37: // arrow
630
- case 38: // arrow
631
- case 39: // arrow
632
- case 40: // arrow
633
- this.rte.status.update();
634
- break;
635
-
636
- default:
637
- // watching the typing pauses to fire 'change' events
638
- var rte = this.rte, editor = this._;
639
-
640
- if (this._timer !== false) { window.clearTimeout(this._timer); }
641
-
642
- this._timer = window.setTimeout(function() {
643
- if (rte.__old_value !== editor.innerHTML) {
644
- rte.__old_value = editor.innerHTML;
645
- rte.fire('change');
646
- }
647
- }, this._delay);
648
- }
649
- },
650
-
651
- _timer: false,
652
- _delay: 400
653
-
654
- });
655
-
656
- /**
657
- * The Rte's status bar block
658
- *
659
- * Copyright (C) 2010-2011 Nikolay Nemshilov
660
- */
661
- Rte.Status = new Class(Element, {
662
-
663
- /**
664
- * Basic constructor
665
- *
666
- * @param Rte
667
- * @return void
668
- */
669
- initialize: function(rte) {
670
- this.$super('div', {'class': 'rui-rte-status'});
671
- this.rte = rte;
672
- this.nodes = [];
673
- this.tags = [];
674
-
675
- this.onMousedown(this._mousedown);
676
- },
677
-
678
- /**
679
- * Updates the current status
680
- *
681
- * @return Rte.Status this
682
- */
683
- update: function() {
684
- this._findNodes();
685
- this._checkTools();
686
-
687
- return this.$super(this.nodes.map(function(node, index) {
688
- var name = node.tagName.toLowerCase();
689
-
690
- if (node.id) {
691
- name += "#"+ node.id;
692
- }
693
-
694
- if (node.className) {
695
- name += "."+ node.className;
696
- }
697
-
698
- return '<a href="" data-index="'+ index +
699
- '" onclick="return false;" title="'+
700
- Rte.i18n.Select +
701
- '">'+ name +'</a>';
702
-
703
- }).join(' &rsaquo; '));
704
- },
705
-
706
- /**
707
- * Finds an element in the current status stack
708
- *
709
- * @param String tag name
710
- * @param Object optional attributes
711
- * @return raw element or null if nothing found
712
- */
713
- findElement: function(tag, attributes) {
714
- if (tag) {
715
- for (var i = this.nodes.length - 1, key, match; i > -1; i--) {
716
- if (this.nodes[i].tagName === tag) {
717
- match = true;
718
-
719
- for (key in attributes) {
720
- if (attributes[key] instanceof RegExp) {
721
- match &= attributes[key].test(this.nodes[i].getAttribute(key));
722
- } else {
723
- match &= this.nodes[i].getAttribute(key) == attributes[key];
724
- }
725
- }
726
-
727
- if (match) {
728
- return this.nodes[i];
729
- }
730
- }
731
- }
732
- }
733
-
734
- return null;
735
- },
736
-
737
- // protected
738
-
739
- // runs the tools check
740
- _checkTools: function() {
741
- var tools = this.rte.tools, key;
742
- for (key in tools) {
743
- tools[key].check();
744
- }
745
- },
746
-
747
- // finds the nodes from the current selection to the bottom
748
- _findNodes: function() {
749
- var node = this.rte.selection.element(),
750
- editor = this.rte.editor._,
751
- rte = this.rte._,
752
- nodes = [],
753
- tags = [];
754
-
755
- this.nodes = [];
756
- this.tags = [];
757
-
758
- while (node && node !== rte) {
759
- if (node.tagName) { // skipping the textual nodes
760
- nodes.unshift(node);
761
- tags.unshift(node.tagName);
762
- }
763
-
764
- node = node.parentNode;
765
-
766
- if (node === editor) {
767
- this.nodes = nodes;
768
- this.tags = tags;
769
- break;
770
- }
771
- }
772
- },
773
-
774
- // catches the mousedown on the links
775
- _mousedown: function(event) {
776
- var link = event.target;
777
-
778
- if (link._.tagName === 'A') {
779
- event.stop();
780
- var index = link.get('data-index').toInt(),
781
- node = this.nodes[index];
782
-
783
- this.rte.selection.wrap(node);
784
- }
785
- }
786
-
787
- });
788
-
789
- /**
790
- * Custom undo/redo manager
791
- *
792
- * The basic trouble is that the native undo manager
793
- * dosn't support manual changes in the editable block
794
- * plus it lacks an ability to save some things under IE
795
- *
796
- * So we manage our undo/redo states manually by whatching
797
- * the 'change' event in the RTE instance
798
- *
799
- * Copyright (C) 2010-2011 Nikolay Nemshilov
800
- */
801
- Rte.Undoer = new Class({
802
-
803
- /**
804
- * Basic constructor
805
- *
806
- * @param Rte rte
807
- * @return void
808
- */
809
- initialize: function(rte) {
810
- this.rte = rte;
811
-
812
- function save() { this.undoer.save(); }
813
- this.rte.on({ focus: save, change: save });
814
-
815
- this.clear();
816
- },
817
-
818
- /**
819
- * Clears up the undo history
820
- *
821
- * @return void
822
- */
823
- clear: function() {
824
- this.stash = [];
825
- this.index = -1;
826
- },
827
-
828
- /**
829
- * Checks if there are undo steps
830
- *
831
- * @return boolean check result
832
- */
833
- hasUndo: function() {
834
- return this.stash.length > 0 && this.index > 0;
835
- },
836
-
837
- /**
838
- * Checks if there are redo steps
839
- *
840
- * @return boolean check result
841
- */
842
- hasRedo: function() {
843
- return (this.stash.length - this.index) > 1;
844
- },
845
-
846
- /**
847
- * Moves the history one step back
848
- *
849
- * @return void
850
- */
851
- undo: function() {
852
- if (this.hasUndo()) {
853
- this.set(-- this.index);
854
- }
855
- },
856
-
857
- /**
858
- * Moves the histor one step forward
859
- *
860
- * @return void
861
- */
862
- redo: function() {
863
- if (this.hasRedo()) {
864
- this.set(++ this.index);
865
- }
866
- },
867
-
868
- /**
869
- * Sets the history to the given step
870
- *
871
- * @param Integer step index
872
- */
873
- set: function(index) {
874
- if (this.stash[this.index]) {
875
- this.rte.editor.update(this.stash[this.index]);
876
- this.rte.selection.restore();
877
- }
878
- },
879
-
880
- /**
881
- * Saves the current state of the editor
882
- *
883
- * @param Event the RTE's 'change' event with the 'tool' reference
884
- * @return void
885
- */
886
- save: function(event) {
887
- var tool = event && event.tool,
888
- tools = this.rte.tools,
889
- html, html1, html2;
890
-
891
- if (!tool || (tool !== tools.Undo && tool !== tools.Redo)) {
892
- this.rte.selection.store();
893
-
894
- html = this.rte.editor._.innerHTML;
895
-
896
- // stripping off the selection markers
897
- html1 = html
898
- .replace(SELECTION_START_RE, '')
899
- .replace(SELECTION_END_RE, '');
900
-
901
- html2 = (this.stash[this.index]||'')
902
- .replace(SELECTION_START_RE, '')
903
- .replace(SELECTION_END_RE, '');
904
-
905
- if (html1 !== html2) {
906
- // cutting loose possible redo steps
907
- this.stash.length = this.index + 1;
908
- this.stash.push(html);
909
- this.index = this.stash.length - 1;
910
-
911
- tools.Undo.check();
912
- tools.Redo.check();
913
- }
914
-
915
- this.rte.selection.restore();
916
- }
917
- }
918
-
919
- });
920
-
921
- /**
922
- * This class handles the selection ranges
923
- *
924
- * Copyright (C) 2010-2011 Nikolay Nemshilov
925
- */
926
- Rte.Selection = new Class({
927
-
928
- /**
929
- * Basic constructor
930
- *
931
- * @param Rte rte
932
- * @return void
933
- */
934
- initialize: function(rte) {
935
- this.rte = rte;
936
- },
937
-
938
- /**
939
- * gets/sets the current range object
940
- *
941
- * @param {Range} to set
942
- * @return TextRange range
943
- */
944
- range: function(range) {
945
- var selection = window.getSelection && window.getSelection();
946
-
947
- if (range) {
948
- if (selection) { // w3c
949
- selection.removeAllRanges();
950
- selection.addRange(range);
951
- } else if (range._) { // IE
952
- range._.select();
953
- }
954
-
955
- } else {
956
- try {
957
- range = selection.getRangeAt(0); // FF, Opera, IE9
958
- } catch (e) {
959
- try {
960
- range = document.createRange(); // WebKit
961
- } catch (ee) {
962
- range = new IERangeEmulator(); // Old IE
963
- }
964
- }
965
-
966
- return range;
967
- }
968
- },
969
-
970
- /**
971
- * Returns the dom-node that's currently in focus
972
- *
973
- * @return raw dom-element
974
- */
975
- element: function() {
976
- var range = this.range(), node = range.commonAncestorContainer;
977
-
978
- // if there is a selection, trying those
979
- if (!range.collapsed) {
980
- if (
981
- range.startContainer === node &&
982
- range.startOffset - range.endOffset < 2 &&
983
- range.startContainer.hasChildNodes()
984
- ) {
985
- node = range.startContainer.childNodes[range.startOffset];
986
- }
987
- }
988
-
989
- node = node && node.nodeType === 3 ? node.parentNode : node;
990
-
991
- return node || null;
992
- },
993
-
994
- /**
995
- * Puts current selection over the given raw dom-node
996
- *
997
- * @param raw dom-node
998
- * @return void
999
- */
1000
- wrap: function(node) {
1001
- var range = this.range();
1002
- range.selectNode(node);
1003
- this.range(range);
1004
- },
1005
-
1006
- /**
1007
- * Returns the selection text
1008
- *
1009
- * @return String selection text
1010
- */
1011
- text: function() {
1012
- return this.range().toString();
1013
- },
1014
-
1015
- /**
1016
- * Cheks if the selection is empty
1017
- *
1018
- * @return boolean check result
1019
- */
1020
- empty: function() {
1021
- return this.text() === '';
1022
- },
1023
-
1024
- /**
1025
- * Returns the HTML content of the selection
1026
- *
1027
- * @return String html content
1028
- */
1029
- html: function() {
1030
- var range = this.range(), tmp, fragment;
1031
-
1032
- if (range._) {
1033
- return range._.htmlText;
1034
- } else {
1035
- tmp = document.createElement('div');
1036
- fragment = range.cloneContents();
1037
-
1038
- while (fragment.firstChild) {
1039
- tmp.appendChild(fragment.firstChild);
1040
- }
1041
-
1042
- return tmp.innerHTML;
1043
- }
1044
- },
1045
-
1046
- /**
1047
- * executes a command on this editing area
1048
- *
1049
- * @param String command name
1050
- * @param mixed command value
1051
- * @return void
1052
- */
1053
- exec: function(command, value) {
1054
- try {
1055
- // it throws errors in some cases in the non-design mode
1056
- document.execCommand(command, false, value);
1057
- } catch(e) {
1058
- // emulating insert html under IE
1059
- if (command === 'inserthtml') {
1060
- this.range()._.pasteHTML(value);
1061
- }
1062
- }
1063
- },
1064
-
1065
- /**
1066
- * Saves the selection by inserting special SPAN elements
1067
- * in places where the selection starts and ends so that
1068
- * it could be restored later, even if the editor innerHTML
1069
- * property was manipulated directly
1070
- *
1071
- * @return {Rte.Selection} this
1072
- */
1073
- store: function() {
1074
- var range = this.range();
1075
-
1076
- // reclonning the data so it wasn't lost on changes
1077
- range = {
1078
- startContainer: range.startContainer,
1079
- startOffset: range.startOffset,
1080
- endContainer: range.endContainer,
1081
- endOffset: range.endOffset,
1082
- collapsed: range.collapsed
1083
- };
1084
-
1085
- /**
1086
- * Places the selection markers into the editor's structure
1087
- *
1088
- * @param String name 'end' or 'start'
1089
- * @return void
1090
- */
1091
- function place_marker(name) {
1092
- var node = range[name + 'Container'],
1093
- offset = range[name + 'Offset'],
1094
- marker = document.createElement('span'),
1095
- parent = node.parentNode,
1096
- text = node.nodeValue,
1097
- ending = document.createTextNode((''+text).substr(offset));
1098
-
1099
- marker.setAttribute('rrte-'+name, '1');
1100
-
1101
- function insert_after(content, anchor) {
1102
- if (anchor.nextSibling) {
1103
- anchor.parentNode.insertBefore(content, anchor.nextSibling);
1104
- } else {
1105
- anchor.parentNode.appendChild(content);
1106
- }
1107
- }
1108
-
1109
- if (node.nodeType === 3) { // text-node
1110
- if (offset === 0) {
1111
- parent.insertBefore(marker,
1112
- // in case both of the markers are at the beginning of
1113
- // the same node, the 'end' marker will be already there
1114
- // and we will need to insert the 'start' one before it.
1115
- name === 'start' && range.collapsed ? node.previousSibling : node
1116
- );
1117
- } else if (offset === text.length) {
1118
- insert_after(marker, node);
1119
- } else { // splitting the text node in two
1120
- node.nodeValue = text.substr(0, offset);
1121
- insert_after(ending, node);
1122
- parent.insertBefore(marker, ending);
1123
- }
1124
-
1125
- } else if (node.nodeType === 1) { // elements
1126
- if (offset === 0) {
1127
- if (node.firstChild) {
1128
- node.insertBefore(marker, node.firstChild);
1129
- } else if (node.hasChildNodes()) {
1130
- node.appendChild(marker);
1131
- }
1132
- } else if (offset === node.childNodes.length) {
1133
- node.appendChild(marker);
1134
- } else {
1135
- node.insertBefore(marker, node.childNodes[offset]);
1136
- }
1137
- }
1138
- }
1139
-
1140
- // NOTE: the 'end' should be before the 'start' in case both of them
1141
- // are in the same node, so that the offest didn't shift after
1142
- // we insert the marker nodes
1143
- place_marker('end');
1144
- place_marker('start');
1145
- },
1146
-
1147
- /**
1148
- * Restores the selection by previously placed
1149
- * special SPAN elements and removes them afterwards
1150
- *
1151
- * @return {Rte.Selection} this
1152
- */
1153
- restore: function() {
1154
- var elements = $A(this.rte.editor._.getElementsByTagName('span')),
1155
- i=0, method, parent, offset, range = this.range();
1156
-
1157
- for (; i < elements.length; i++) {
1158
- method = elements[i].getAttribute('rrte-start') ? 'setStart' :
1159
- elements[i].getAttribute('rrte-end') ? 'setEnd' : false;
1160
-
1161
- if (method) {
1162
- parent = elements[i].parentNode;
1163
-
1164
- if (range._) {
1165
- range[method](elements[i]);
1166
- } else {
1167
- offset = IER_getIndex(elements[i]);
1168
- range[method](parent, offset);
1169
- }
1170
-
1171
- parent.removeChild(elements[i]);
1172
- }
1173
- }
1174
-
1175
- this.range(range);
1176
- }
1177
- });
1178
-
1179
- var
1180
-
1181
- SELECTION_START_MARKER = '<span rrte-start="1"></span>',
1182
- SELECTION_END_MARKER = '<span rrte-end="1"></span>',
1183
- SELECTION_START_RE = new RegExp(RegExp.escape(SELECTION_START_MARKER), 'i'),
1184
- SELECTION_END_RE = new RegExp(RegExp.escape(SELECTION_END_MARKER), 'i');
1185
-
1186
-
1187
- /**
1188
- * W3C ranges API emulator for the old IE browsers
1189
- *
1190
- * Based on the `InternetExplorerRange` implementation
1191
- * from the http://mozile.mozdev.org project
1192
- * by James A. Overton <james@overton.ca>
1193
- *
1194
- * Originally licensed under MPL/GPL2/LGPL2 licenses
1195
- *
1196
- * Copyrgiht (C) 2011 Nikolay Nemshilov
1197
- */
1198
- var IERangeEmulator = new Class({
1199
-
1200
- // standard w3c attributes
1201
- collapsed: null,
1202
- startContainer: null,
1203
- startOffset: null,
1204
- endContainer: null,
1205
- endOffset: null,
1206
- commonAncestorContainer: null,
1207
-
1208
- /**
1209
- * Basic constructor
1210
- *
1211
- * @return void
1212
- */
1213
- initialize: function() {
1214
- this._ = document.selection.createRange();
1215
-
1216
- if (document.selection.type === 'Control') {
1217
- this.startContainer = this.endContainer = this.commonAncestorContainer = this._(0);
1218
- this.startOffset = this.endOffset = 0;
1219
- } else {
1220
- //startPoint
1221
- var range = this._.duplicate();
1222
- range.collapse(true);
1223
- range = IER_getPosition(range);
1224
-
1225
- this.startContainer = range.node;
1226
- this.startOffset = range.offset;
1227
-
1228
- //endPoint
1229
- range = this._.duplicate();
1230
- range.collapse(false);
1231
- range = IER_getPosition(range);
1232
-
1233
- this.endContainer = range.node;
1234
- this.endOffset = range.offset;
1235
-
1236
- // the rest of the properties
1237
- IER_commonAncestorContainer(this);
1238
- }
1239
-
1240
- IER_collapsed(this);
1241
- },
1242
-
1243
- /**
1244
- * Sets the starting point for the range
1245
- *
1246
- * @param {Node} node
1247
- * @param {Number} offset
1248
- * @return void
1249
- */
1250
- setStart: function(node, offset) {
1251
- var range = this._.duplicate();
1252
-
1253
- range.moveToElementText(node);
1254
- range.collapse(true);
1255
-
1256
- this._.setEndPoint('StartToStart', range);
1257
-
1258
- this.startContainer = node;
1259
- this.startOffset = offset;
1260
-
1261
- if (this.endContainer === null && this.endOffset === null) {
1262
- this.endContainer = node;
1263
- this.endOffset = offset;
1264
- }
1265
-
1266
- IER_commonAncestorContainer(this);
1267
- IER_collapsed(this);
1268
- },
1269
-
1270
- /**
1271
- * Setting the end point for the range
1272
- *
1273
- * @param {Node} node
1274
- * @param {Number} offset
1275
- * @return void
1276
- */
1277
- setEnd: function (node, offset) {
1278
- var range = this._.duplicate();
1279
-
1280
- range.moveToElementText(node);
1281
- range.collapse(true);
1282
-
1283
- this._.setEndPoint('EndToEnd', range);
1284
-
1285
- this.endContainer = node;
1286
- this.endOffset = offset;
1287
-
1288
- if (this.startContainer === null && this.startOffset === null) {
1289
- this.startContainer = node;
1290
- this.startOffset = offset;
1291
- }
1292
-
1293
- IER_commonAncestorContainer(this);
1294
- IER_collapsed(this);
1295
- },
1296
-
1297
- /**
1298
- * Wrapps the range around the given node
1299
- *
1300
- * @param {Node} node
1301
- * @return void
1302
- */
1303
- selectNode: function (node) {
1304
- this._.moveToElementText(node);
1305
- },
1306
-
1307
- /**
1308
- * Selection text emulation
1309
- *
1310
- * @return {String} text
1311
- */
1312
- toString: function() {
1313
- return ''+ this._.text;
1314
- }
1315
- });
1316
-
1317
-
1318
- //////////////////////////////////////////////////////////////////////////////
1319
- // Some private methods for the IERangeEmaulator
1320
- //////////////////////////////////////////////////////////////////////////////
1321
-
1322
-
1323
- /**
1324
- * Finds the standard node/offset pair out of the
1325
- * IE range object
1326
- *
1327
- * @param {TextRange} ie text range object
1328
- * @return {Object} 'node' and 'offset' pairs
1329
- */
1330
- function IER_getPosition(original_range) {
1331
- var element = original_range.parentElement(),
1332
- range, range_size, direction, node, node_size;
1333
-
1334
- range = document.body.createTextRange();
1335
- range.moveToElementText(element);
1336
- range.setEndPoint("EndToStart", original_range);
1337
-
1338
- range_size = range.text.length;
1339
-
1340
- // Choose Direction
1341
- if (range_size < element.innerText.length / 2) {
1342
- direction = 1;
1343
- node = element.firstChild;
1344
- } else {
1345
- direction = -1;
1346
- node = element.lastChild;
1347
- range.moveToElementText(element);
1348
- range.setEndPoint("StartToStart", original_range);
1349
- range_size = range.text.length;
1350
- }
1351
-
1352
- // Loop through child nodes
1353
- while (node) {
1354
- switch (node.nodeType) {
1355
- case 3: // text-node
1356
- node_size = node.data.length;
1357
- if(node_size < range_size) {
1358
- range_size -= node_size;
1359
-
1360
- if (direction === 1) {
1361
- range.moveStart("character", range_size);
1362
- } else {
1363
- range.moveEnd("character", -range_size);
1364
- }
1365
-
1366
- } else {
1367
- return direction === 1 ?
1368
- {node: node, offset: range_size} :
1369
- {node: node, offset: node_size - range_size};
1370
- }
1371
- break;
1372
-
1373
- case 1: // element-node
1374
- node_size = node.innerText.length;
1375
-
1376
- if (direction === 1) {
1377
- range.moveStart("character", node_size);
1378
- } else {
1379
- range.moveEnd("character", -node_size);
1380
- }
1381
-
1382
- range_size = range_size - node_size;
1383
- break;
1384
- }
1385
-
1386
- node = direction === 1 ? node.nextSibling : node.previousSibling;
1387
- }
1388
-
1389
- // The TextRange was not found. Return a reasonable value instead.
1390
- return {node: element, offset: 0};
1391
- }
1392
-
1393
- /**
1394
- * Assigns a suitable `commonAncestorContainer` property for the range
1395
- *
1396
- * @param {IERangeEmulator} range
1397
- * @return void
1398
- */
1399
- function IER_commonAncestorContainer(range) {
1400
- range.commonAncestorContainer = range._.parentElement();
1401
- }
1402
-
1403
- /**
1404
- * Sets the `collapsed` property for the range
1405
- *
1406
- * @param {IERangeEmulator} range
1407
- * return void
1408
- */
1409
- function IER_collapsed(range) {
1410
- range.collapsed =
1411
- range.startContainer === range.endContainer &&
1412
- range.startOffset === range.endOffset;
1413
- }
1414
-
1415
- /**
1416
- * Finds out the node's index among it's siblings
1417
- *
1418
- * @param {Node} node
1419
- * @return {Number} index
1420
- */
1421
- function IER_getIndex(node) {
1422
- var index = 0;
1423
-
1424
- while ((node = node.previousSibling)) {
1425
- index ++;
1426
- }
1427
-
1428
- return index;
1429
- }
1430
-
1431
-
1432
- /**
1433
- * The basic tools class
1434
- *
1435
- * Copyright (C) 2010-2011 Nikolay Nemshilov
1436
- */
1437
- Rte.Tool = new Class(Element, {
1438
-
1439
- block: true, // should the 'keypress' event be blocked
1440
- blip: false, // whether it should be highlighted when used
1441
- changes: true, // if this tool should fire 'change' on the rte
1442
-
1443
- shortuct: null, // the shortuct key-code
1444
- shiftKey: false, // if it should trigger with a shift-key only
1445
-
1446
- /**
1447
- * Basic constructor
1448
- *
1449
- * @param Rte rte reference
1450
- * @return Rte.Tool this
1451
- */
1452
- initialize: function(rte) {
1453
- var name;
1454
-
1455
- // searching for the tool-name
1456
- for (name in Rte.Tools) {
1457
- if (Rte.Tools[name] === this.constructor) { break; }
1458
- }
1459
-
1460
- this.name = name;
1461
- this.shortcut = this.shortcut || Rte.Shortcuts[name];
1462
-
1463
- this.$super('div', {
1464
- 'html': '<div class="icon"></div>', // <- icon container
1465
- 'class': 'tool '+ name.toLowerCase(),
1466
- 'title': (Rte.i18n[name] || name) + (
1467
- this.shortcut ? " ("+ this.shortcut + ")" : ""
1468
- )
1469
- });
1470
-
1471
- // registering the tool
1472
- this.rte = rte;
1473
- rte.tools[name] = this;
1474
-
1475
- // hooking up the shortcuts
1476
- this.shortcut = this.shortcut && this.shortcut.toLowerCase();
1477
- this.shiftKey = this.shortcut && this.shortcut.indexOf('shift') > -1;
1478
- this.shortcut = this.shortcut && this.shortcut.toUpperCase().charCodeAt(this.shortcut.length - 1);
1479
-
1480
- // connecting the mousedown the way that the editor din't loose the focus
1481
- this.onMousedown(function(e) {
1482
- e.stop(); this.mousedown();
1483
- });
1484
-
1485
- // allowing some nice chains in the subclass
1486
- return this;
1487
- },
1488
-
1489
- // those three methods should be implemented in subclasses
1490
- exec: function() { }, /// the actual process
1491
- active: function() { return false; }, // all tools not active by default
1492
- enabled: function() { return true; }, // all tools enabled by default
1493
-
1494
- /**
1495
- * The entry point for all the tools, if you need to call a tool,
1496
- * call this method. __DON'T CALL__ the #exec method directly!
1497
- *
1498
- * @param {Event} 'keydown' event
1499
- * @return void
1500
- */
1501
- call: function(event) {
1502
- if (!this.disabled) {
1503
- if (event && this.block) { event.stop(); }
1504
-
1505
- this.exec();
1506
- this.rte.status.update();
1507
- this.rte.fire('change', {tool: this});
1508
-
1509
- if (this.blip) { this.highlight(); }
1510
- }
1511
- },
1512
-
1513
- /**
1514
- * Checks the command's status
1515
- *
1516
- * @return void
1517
- */
1518
- check: function() {
1519
- this._.className = this._.className.replace(' disabled', '');
1520
- this.disabled = false;
1521
-
1522
- if ((this.name === 'Source' || this.rte.srcMode !== true) && this.enabled()) {
1523
- this._.className = this._.className.replace(' active', '');
1524
- if (this.active()) {
1525
- this._.className += ' active';
1526
- }
1527
-
1528
- } else {
1529
- this._.className += ' disabled';
1530
- this.disabled = true;
1531
- }
1532
- },
1533
-
1534
- /**
1535
- * Replacing the highlight method with some css stuff instead of an Fx
1536
- *
1537
- * @return Rte.Tool this
1538
- */
1539
- highlight: function() {
1540
- R(this.addClass('highlight').removeClass).bind(this, 'highlight').delay(100);
1541
- },
1542
-
1543
- // protected
1544
-
1545
- // mousedown event receiver (might be replaced in subclasses)
1546
- mousedown: function() {
1547
- this.call();
1548
- }
1549
-
1550
- });
1551
-
1552
- /**
1553
- * Native command related abstract tool
1554
- *
1555
- * Copyright (C) 2010-2011 Nikolay Nemshilov
1556
- */
1557
- Rte.Tool.Command = new Class(Rte.Tool, {
1558
- command: null, // execCommand name
1559
- value: null, // execCommand value
1560
-
1561
- /**
1562
- * calling the command exec
1563
- *
1564
- * @return void
1565
- */
1566
- exec: function() {
1567
- this.rte.selection.exec(this.command, this.value);
1568
- },
1569
-
1570
- /**
1571
- * Checks if the command is enabled at all
1572
- *
1573
- * @return boolean check result
1574
- */
1575
- enabled: function() {
1576
- try {
1577
- return document.queryCommandEnabled(this.command);
1578
- } catch(e) {
1579
- return false;
1580
- }
1581
- },
1582
-
1583
- /**
1584
- * Queries if the command is in active state
1585
- *
1586
- * @return boolean check result
1587
- */
1588
- active: function() {
1589
- try { // copy/paste commands cause errors under FF by default
1590
- return this.value === null ?
1591
- document.queryCommandState(this.command) :
1592
- document.queryCommandValue(this.command) == this.value;
1593
- } catch(e) {
1594
- return false;
1595
- }
1596
- }
1597
- });
1598
-
1599
- /**
1600
- * Text formatting specific abstract tool
1601
- *
1602
- * Copyright (C) 2010-2011 Nikolay Nemshilov
1603
- */
1604
- Rte.Tool.Format = new Class(Rte.Tool, {
1605
- tag: null, // element's tag name
1606
- atts: {}, // element's attributes
1607
-
1608
- /**
1609
- * Formatting tools basic constructor
1610
- *
1611
- * @param Rte rte
1612
- * @return Rte.ToolFormat this
1613
- */
1614
- initialize: function(rte) {
1615
- this.$super(rte);
1616
- this.tag = (this.tag || Rte.Tags[this.name] || '').toUpperCase();
1617
- return this;
1618
- },
1619
-
1620
- /**
1621
- * triggering the formatting
1622
- *
1623
- * @return void
1624
- */
1625
- exec: function() {
1626
- this[this.active() ? 'unformat' : 'format']();
1627
- },
1628
-
1629
- /**
1630
- * Overloading the activity checks
1631
- *
1632
- * @return boolean check result
1633
- */
1634
- active: function() {
1635
- return this.element() !== null;
1636
- },
1637
-
1638
- // protected
1639
-
1640
- /**
1641
- * Tries to find a currently active element
1642
- *
1643
- * @return raw dom element or null
1644
- */
1645
- element: function() {
1646
- return this.rte.status.findElement(this.tag, this.attrs);
1647
- },
1648
-
1649
- /**
1650
- * Removes the formatting
1651
- *
1652
- * @return void
1653
- */
1654
- unformat: function() {
1655
- this._format(false);
1656
- },
1657
-
1658
- /**
1659
- * Formats the block according to the settings
1660
- *
1661
- * @return void
1662
- */
1663
- format: function() {
1664
- this._format(true);
1665
- },
1666
-
1667
- // private
1668
-
1669
- /**
1670
- * The actual formatting/unformatting process mumbo-jumbo
1671
- *
1672
- * @param boolean formatting direction true/false
1673
- * @return void
1674
- */
1675
- _format: function(formatting) {
1676
- var open_tag = '<'+ this.tag,
1677
- close_tag = '</'+ this.tag + '>',
1678
- editor = this.rte.editor,
1679
- selection = this.rte.selection,
1680
- range = selection.range(),
1681
- selected = selection.text(),
1682
- element = this.element(),
1683
- content = element && (element.textContent || element.innerText);
1684
-
1685
- // building the open-tag attributes
1686
- for (var attr in this.attrs) {
1687
- open_tag += ' '+ attr +'="'+ this.attrs[attr]+ '"';
1688
- }
1689
- open_tag += ">";
1690
-
1691
- selection.store();
1692
-
1693
- // Old IEs screw with the starting position
1694
- // placing it before the open tag, so here we switch it back
1695
- if (!formatting && range._) {
1696
- editor.html(editor.html().replace(
1697
- new RegExp(RegExp.escape(SELECTION_START_MARKER + open_tag), 'i'),
1698
- open_tag + SELECTION_START_MARKER
1699
- ));
1700
- }
1701
-
1702
-
1703
- if (formatting) {
1704
- editor.html(editor.html()
1705
- .replace(SELECTION_START_RE, open_tag + SELECTION_START_MARKER)
1706
- .replace(SELECTION_END_RE, SELECTION_END_MARKER + close_tag)
1707
- );
1708
- } else if (element && selected === content) {
1709
- // plainly remove the element if it was fully selected
1710
- // in case there are several nested elements so that
1711
- // we didn't get screwed with the regexps manipulations
1712
- editor.removeElement(element);
1713
- } else {
1714
- editor.html(editor.html()
1715
- .replace(SELECTION_START_RE, close_tag + SELECTION_START_MARKER)
1716
- .replace(SELECTION_END_RE, SELECTION_END_MARKER + open_tag)
1717
-
1718
- // cleaning up empty tags that might left
1719
- .replace(/<([a-z]+)[^>]*?>\s*?<\/\1>/ig, '')
1720
- );
1721
- }
1722
-
1723
- selection.restore();
1724
- }
1725
-
1726
- });
1727
-
1728
- /**
1729
- * A _shared module_ to provide the `options` list functionality
1730
- * for the tools
1731
- *
1732
- * Copyright (C) 2010 Nikolay Nemshilov
1733
- */
1734
- Rte.Tool.Options = {
1735
-
1736
- /**
1737
- * Builds the options list
1738
- *
1739
- * @param Object key -> value hash
1740
- */
1741
- build: function(options) {
1742
- this.trigger = $E('div', {'class': 'trigger', 'html': '&middot;'});
1743
- this.display = $E('div', {'class': 'display'});
1744
- this.options = $E('ul', {'class': 'options'});
1745
-
1746
- this
1747
- .addClass('with-options')
1748
- .append(this.display, this.options)
1749
- .insert(this.trigger, 'top');
1750
-
1751
- this.items = {};
1752
-
1753
- for (var value in options) {
1754
- this.items[value] = $E('li').insert(options[value]);
1755
- this.items[value].insertTo(this.options).value = value;
1756
- }
1757
-
1758
- // creating an the reset value
1759
- this.items[''] = $E('li', {'class': 'remove', 'html': '--', 'title': Rte.i18n.Remove});
1760
- this.items[''].insertTo(this.options, 'top').value = '';
1761
-
1762
- // catching the clicks
1763
- this.options.onMousedown(R(this.pick).bind(this));
1764
-
1765
- // hidding the menu when the user interacts with the document outside of the document
1766
- var hide = R(this.options.hide).bind(this.options, null);
1767
- $(document).on({mousedown: hide,
1768
- keydown: function(event) {
1769
- if (event.keyCode === 27) { hide(); }
1770
- }
1771
- });
1772
-
1773
- this.value = '';
1774
- this.updateDisplay(null);
1775
-
1776
- return this;
1777
- },
1778
-
1779
- // protected
1780
-
1781
- // handling an option pick
1782
- pick: function(event) {
1783
- var target = event.stop().target;
1784
-
1785
- if (target._.tagName !== 'LI') {
1786
- target = target.parent('LI');
1787
- }
1788
-
1789
- if (target.value !== undefined) {
1790
- this.options.hide();
1791
- this.value = target.value;
1792
- this.updateDisplay(this.value || null);
1793
- this.markActive();
1794
- this.exec();
1795
- }
1796
- },
1797
-
1798
- // toggling the menu on the icon-click
1799
- mousedown: function() {
1800
- if (!this.disabled) {
1801
- $$('.rui-rte-toolbar div.with-options ul.options')
1802
- .without(this.options).each('hide');
1803
-
1804
- // marking the current value so it could be seen
1805
- if (this.options.hidden() && this.value !== null) {
1806
- this.markActive();
1807
- }
1808
-
1809
- this.options.toggle('fade', {duration: 'short'});
1810
- }
1811
- },
1812
-
1813
- // marks the currently active item
1814
- markActive: function() {
1815
- for (var item in this.items) {
1816
- this.items[item][
1817
- item === this.value ? 'addClass' : 'removeClass'
1818
- ]('active');
1819
- }
1820
- },
1821
-
1822
- // updates the display
1823
- updateDisplay: function(value) {
1824
- this.display.update(
1825
- value !== null && value in this.items ?
1826
- this.items[value].text() : this._.title
1827
- );
1828
- }
1829
-
1830
- };
1831
-
1832
- /**
1833
- * An abstract formatting tool that works with styles
1834
- * basically it wraps a selection with a 'span' tag and then
1835
- * handles the 'style' attribute, adds/removes various styles, etc.
1836
- *
1837
- * Copyright (C) 2010 Nikolay Nemshilov
1838
- */
1839
- Rte.Tool.Style = new Class(Rte.Tool.Format, {
1840
- include: Rte.Tool.Options,
1841
-
1842
- tag: 'span', // tag name of the element to be used
1843
- style: null, // the style property name (dashed)
1844
-
1845
- /**
1846
- * Joint constructor
1847
- *
1848
- * @param Rte rte
1849
- * @return Rte.Tool.StyleOptions
1850
- */
1851
- initialize: function(rte, options) {
1852
- // a regular expression to process the `style` property
1853
- this.re = new RegExp("(^|;)\\s*"+ RegExp.escape(this.style + ":")+ "\\s*(.+?)\\s*(;|$)");
1854
- this.attrs = { style: this.re };
1855
-
1856
- this.$super(rte).build(options);
1857
-
1858
- return this;
1859
- },
1860
-
1861
- /**
1862
- * Triggers the action
1863
- *
1864
- * @return void
1865
- */
1866
- exec: function() {
1867
- // unformatting if there is a value
1868
- if (this.active()) {
1869
- this.attrs = {style: this.style + ":" + this._value};
1870
- this.unformat();
1871
- }
1872
-
1873
- // formatting if some value was asked
1874
- if (this.value) {
1875
- this.attrs = {style: this.style + ":" + this.value};
1876
- this.format();
1877
- }
1878
-
1879
- // getting back the RE checker
1880
- this.attrs = {style: this.re};
1881
- },
1882
-
1883
- /**
1884
- * Overloading the original method so that we could do some additional
1885
- * features with the actual current value
1886
- *
1887
- * @return void
1888
- */
1889
- active: function() {
1890
- var element = this.element(), active = false, value = null;
1891
-
1892
- if (element !== null) {
1893
- this._value = value = this.getStyleValue();
1894
- active = true;
1895
- }
1896
-
1897
- this.updateDisplay(value);
1898
-
1899
- return active;
1900
- },
1901
-
1902
- // protected
1903
-
1904
- /**
1905
- * Finds the current style value (if any)
1906
- *
1907
- * @return string style value or null if nothing
1908
- */
1909
- getStyleValue: function() {
1910
- var element = this.element();
1911
- var attribute = element !== null ? element.getAttribute('style') : null;
1912
-
1913
- if (attribute !== null) {
1914
- if ((attribute = attribute.match(this.re)) !== null) {
1915
- attribute = attribute[2];
1916
- }
1917
- }
1918
-
1919
- return attribute;
1920
- }
1921
- });
1922
-
1923
- /**
1924
- * an abstract color-picking tool
1925
- *
1926
- * Copyright (C) 2010-2011 Nikolay Nemshilov
1927
- */
1928
- Rte.Tool.Color = new Class(Rte.Tool.Style, {
1929
-
1930
- extend: {
1931
- COLORS: R([
1932
- // TODO that's ain't no cool hacker's approach!
1933
- '000000 444444 666666 999999 cccccc eeeeee f4f4f4 ffffff',
1934
- 'f24020 f79c33 fff84c 6af244 5ef9fd 0048f7 8950f7 ee5ff8',
1935
- 'e39e9b f5cba1 fee3a1 bcd3ab a6c3c8 a2c6e5 b1abd3 d0aabc '+
1936
- 'd77169 f1b374 fdd675 9cbe83 7ca4ae 74aad8 8983bf bb839f '+
1937
- 'cc0100 e79138 f1c332 69a84f 45818e 3d85c6 674ea7 a64d79 '+
1938
- '990000 b45f05 bf9000 38761c 134f5c 0b5394 351b75 751a47 '+
1939
- '660000 783e03 7f6000 264e13 0b333d 063763 1f124c 4c1030'
1940
- ])
1941
- },
1942
-
1943
- /**
1944
- * Basic constructor, builds the colors picking panel
1945
- *
1946
- * @param Rte rte
1947
- * @return Rte.Tool.Color this
1948
- */
1949
- initialize: function(rte) {
1950
- this.$super(rte, {}).addClass('color');
1951
- this.display.clean();
1952
-
1953
- // building the color picker menu
1954
- Rte.Tool.Color.COLORS.each(function(line) {
1955
- var group = $E('li', {'class': 'group'}),
1956
- list = $E('ul').insertTo(group),
1957
- colors = line.split(' '), i = 0, color, forecolor;
1958
-
1959
- for (; i < colors.length; i++) {
1960
- color = '#' + colors[i];
1961
- forecolor = (parseInt('ffffff', 16) - parseInt(colors[i], 16)).toString(16);
1962
-
1963
- // IE will get screwed if the length of the color is less than 6
1964
- while (forecolor.length < 6) {
1965
- forecolor += '0';
1966
- }
1967
-
1968
- this.items[color] = $E('li', {
1969
- html: '&bull;',
1970
- style: {
1971
- background: color,
1972
- color: '#'+ forecolor
1973
- }
1974
- });
1975
-
1976
- this.items[color].insertTo(list).value = color;
1977
- }
1978
-
1979
- this.options.append(group);
1980
- }, this);
1981
-
1982
- return this;
1983
- },
1984
-
1985
- // protected
1986
-
1987
- /**
1988
- * Overloading the property so that it converted any color formats
1989
- * into a six chars hex value
1990
- *
1991
- * @return String current color or null
1992
- */
1993
- getStyleValue: function() {
1994
- var color = this.$super(), match;
1995
-
1996
- if (color !== null) {
1997
- if ((match = /^#(\w)(\w)(\w)$/.exec(color))) {
1998
- color = "#"+ match[1]+match[1]+match[2]+match[2]+match[3]+match[3];
1999
- } else if ((match = /^\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)\s*$/.exec(color))) {
2000
- color = "#"+ R(match.slice(1)).map(function(bit) {
2001
- bit = (bit-0).toString(16);
2002
- return bit.length === 1 ? '0'+bit : bit;
2003
- }).join('');
2004
- }
2005
- }
2006
-
2007
- return color;
2008
- },
2009
-
2010
- /**
2011
- * Replacing the original method so that
2012
- * it changed the color of the display thing
2013
- * instead of text
2014
- *
2015
- * @param String value
2016
- * @return void
2017
- */
2018
- updateDisplay: function(value) {
2019
- this.display._.style.background = value === null ?
2020
- 'transparent' : value;
2021
- }
2022
- });
2023
-
2024
- /**
2025
- * An abstract URL tool, used with the links, images, videos, etc.
2026
- *
2027
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2028
- */
2029
- Rte.Tool.Url = new Class(Rte.Tool, {
2030
- attr: null, // the url-attribute 'src', 'href', etc.
2031
-
2032
- exec: function(url) {
2033
- if (url === undefined) {
2034
- this.prompt();
2035
- } else {
2036
- if (url) {
2037
- this[this.element() ? 'url' : 'create'](url);
2038
- } else {
2039
- this.rte.editor.removeElement(this.element());
2040
- }
2041
- }
2042
- },
2043
-
2044
- active: function() {
2045
- return this.element() !== null;
2046
- },
2047
-
2048
- prompt: function() {
2049
- var url = prompt(Rte.i18n.UrlAddress, this.url() || 'http://some.url.com');
2050
-
2051
- if (url !== null) {
2052
- this.exec(url);
2053
- }
2054
- },
2055
-
2056
- // protected
2057
-
2058
- url: function(url) {
2059
- if (this.element()) {
2060
- if (url !== undefined) {
2061
- this.element()[this.attr] = url;
2062
- } else {
2063
- return this.element()[this.attr];
2064
- }
2065
- }
2066
- },
2067
-
2068
- create: function(url) {
2069
- this.rte.selection.exec(this.command, url);
2070
- }
2071
- });
2072
-
2073
- /**
2074
- * Making the things bold tool
2075
- *
2076
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2077
- */
2078
- Rte.Tools.Bold = new Class(Rte.Tool.Format, {
2079
- });
2080
-
2081
- /**
2082
- * Making the things italic
2083
- *
2084
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2085
- */
2086
- Rte.Tools.Italic = new Class(Rte.Tool.Format, {
2087
- });
2088
-
2089
- /**
2090
- * Making the things underline tool
2091
- *
2092
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2093
- */
2094
- Rte.Tools.Underline = new Class(Rte.Tool.Format, {
2095
- });
2096
-
2097
- /**
2098
- * Making the things strike through
2099
- *
2100
- * Copyright (C) 2010 Nikolay Nemshilov
2101
- */
2102
- Rte.Tools.Strike = new Class(Rte.Tool.Format, {
2103
- });
2104
-
2105
- /**
2106
- * The cut tool
2107
- *
2108
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2109
- */
2110
- Rte.Tools.Cut = new Class(Rte.Tool.Command, {
2111
- command: 'cut',
2112
- block: false,
2113
- blip: true
2114
- });
2115
-
2116
- /**
2117
- * The copy tool
2118
- *
2119
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2120
- */
2121
- Rte.Tools.Copy = new Class(Rte.Tools.Cut, {
2122
- command: 'copy'
2123
- });
2124
-
2125
- /**
2126
- * The paste action
2127
- *
2128
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2129
- */
2130
- Rte.Tools.Paste = new Class(Rte.Tools.Cut, {
2131
- command: 'paste'
2132
- });
2133
-
2134
- /**
2135
- * the 'left' tool
2136
- *
2137
- * Copyright (C) 2010 Nikolay Nemshilov
2138
- */
2139
- Rte.Tools.Left = new Class(Rte.Tool.Command, {
2140
- command: 'justifyleft'
2141
- });
2142
-
2143
- /**
2144
- * the 'center' tool
2145
- *
2146
- * Copyright (C) 2010 Nikolay Nemshilov
2147
- */
2148
- Rte.Tools.Center = new Class(Rte.Tool.Command, {
2149
- command: 'justifycenter'
2150
- });
2151
-
2152
- /**
2153
- * the 'right' tool
2154
- *
2155
- * Copyright (C) 2010 Nikolay Nemshilov
2156
- */
2157
- Rte.Tools.Right = new Class(Rte.Tool.Command, {
2158
- command: 'justifyright'
2159
- });
2160
-
2161
- /**
2162
- * the 'justify' tool
2163
- *
2164
- * Copyright (C) 2010 Nikolay Nemshilov
2165
- */
2166
- Rte.Tools.Justify = new Class(Rte.Tool.Command, {
2167
- command: 'justifyfull'
2168
- });
2169
-
2170
- /**
2171
- * The undo tool
2172
- *
2173
- * The actual magic happens in the Rte.Undoer class
2174
- * here we just show the status and blip it when used
2175
- *
2176
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2177
- */
2178
- Rte.Tools.Undo = new Class(Rte.Tool, {
2179
- blip: true,
2180
-
2181
- exec: function() {
2182
- this.rte.undoer.undo();
2183
- },
2184
-
2185
- enabled: function() {
2186
- return this.rte.undoer.hasUndo();
2187
- }
2188
- });
2189
-
2190
- /**
2191
- * the 'redo' tool
2192
- *
2193
- * The actual magic happens in the Rte.Undoer class
2194
- * here we just show the status and blip it when used
2195
- *
2196
- * Copyright (C) 2010 Nikolay Nemshilov
2197
- */
2198
- Rte.Tools.Redo = new Class(Rte.Tool, {
2199
- blip: true,
2200
-
2201
- exec: function() {
2202
- this.rte.undoer.redo();
2203
- },
2204
-
2205
- enabled: function() {
2206
- return this.rte.undoer.hasRedo();
2207
- }
2208
-
2209
- });
2210
-
2211
- /**
2212
- * The code block tool
2213
- *
2214
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2215
- */
2216
- Rte.Tools.Code = new Class(Rte.Tool.Format, {
2217
- });
2218
-
2219
- /**
2220
- * The block quote tool
2221
- *
2222
- * Copyrigth (C) 2010 Nikolay Nemshilov
2223
- */
2224
- Rte.Tools.Quote = new Class(Rte.Tool.Format, {
2225
- });
2226
-
2227
- /**
2228
- * the 'ttext' tool
2229
- *
2230
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2231
- */
2232
- Rte.Tools.Ttext = new Class(Rte.Tool.Format, {
2233
- });
2234
-
2235
- /**
2236
- * The header block tool
2237
- *
2238
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2239
- */
2240
- Rte.Tools.Header = new Class(Rte.Tool.Format, {
2241
- });
2242
-
2243
- /**
2244
- * The the url link tool
2245
- *
2246
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2247
- */
2248
- Rte.Tools.Link = new Class(Rte.Tool.Url, {
2249
- command: 'createlink',
2250
- attr: 'href',
2251
-
2252
- enabled: function() {
2253
- return !this.rte.selection.empty() || this.active();
2254
- },
2255
-
2256
- element: function() {
2257
- return this.rte.status.findElement('A', {});
2258
- }
2259
- });
2260
-
2261
- /**
2262
- * The image tool
2263
- *
2264
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2265
- */
2266
- Rte.Tools.Image = new Class(Rte.Tool.Url, {
2267
- command: 'insertimage',
2268
- attr: 'src',
2269
-
2270
- element: function() {
2271
- var image = this.rte.selection.element();
2272
- return image !== null && image.tagName === "IMG" ? image : null;
2273
- }
2274
-
2275
- });
2276
-
2277
- /**
2278
- * the 'video' tool
2279
- *
2280
- * Copyright (C) 2010 Nikolay Nemshilov
2281
- */
2282
- Rte.Tools.Video = new Class(Rte.Tool.Url, {
2283
- command: 'inserthtml',
2284
-
2285
- enabled: function() {
2286
- return true; // always enabled
2287
- },
2288
-
2289
- element: function() {
2290
- return this.rte.status.findElement('OBJECT', {});
2291
- },
2292
-
2293
- // works with url address of the embedded object
2294
- url: function(url) {
2295
- var element = this.element() && this.element().getElementsByTagName('embed')[0];
2296
-
2297
- if (element) {
2298
- if (url !== undefined) {
2299
- element.src = this.swfUrl(url);
2300
- } else {
2301
- return element.src;
2302
- }
2303
- }
2304
- },
2305
-
2306
- // creates the actual object block
2307
- create: function(url) {
2308
- var swf_url = this.swfUrl(url),
2309
- size = 'width="'+ this.rte.options.videoSize.split('x')[0] +
2310
- '" height="'+ this.rte.options.videoSize.split('x')[1] + '"';
2311
-
2312
- this.$super('<object '+ size +'>'+
2313
- '<param name="src" value="'+ swf_url +'" />'+
2314
- '<embed src="'+ swf_url +'" type="application/x-shockwave-flash" '+ size + ' />' +
2315
- '</object>');
2316
- },
2317
-
2318
- // making the actual 'swf' url
2319
- swfUrl: function(url) {
2320
- return R(Rte.Videos).map(function(desc) {
2321
- return url.match(desc[0]) ?
2322
- url.replace(desc[0], desc[1]) : null;
2323
- }).compact()[0] || url;
2324
- }
2325
- });
2326
-
2327
- /**
2328
- * the 'dotlist' tool
2329
- *
2330
- * Copyright (C) 2010 Nikolay Nemshilov
2331
- */
2332
- Rte.Tools.Dotlist = new Class(Rte.Tool.Command, {
2333
- command: 'insertunorderedlist'
2334
- });
2335
-
2336
- /**
2337
- * the 'numlist' tool
2338
- *
2339
- * Copyright (C) 2010 Nikolay Nemshilov
2340
- */
2341
- Rte.Tools.Numlist = new Class(Rte.Tool.Command, {
2342
- command: 'insertorderedlist'
2343
- });
2344
-
2345
- /**
2346
- * the 'indent' tool
2347
- *
2348
- * Copyright (C) 2010 Nikolay Nemshilov
2349
- */
2350
- Rte.Tools.Indent = new Class(Rte.Tool.Command, {
2351
- command: 'indent'
2352
- });
2353
-
2354
- /**
2355
- * the 'Outdent' tool
2356
- *
2357
- * Copyright (C) 2010 Nikolay Nemshilov
2358
- */
2359
- Rte.Tools.Outdent = new Class(Rte.Tool.Command, {
2360
- command: 'outdent'
2361
- });
2362
-
2363
- /**
2364
- * the 'forecolor' tool
2365
- *
2366
- * Copyright (C) 2010 Nikolay Nemshilov
2367
- */
2368
- Rte.Tools.Forecolor = new Class(Rte.Tool.Color, {
2369
- style: 'color'
2370
- });
2371
-
2372
- /**
2373
- * the 'backcolor' tool
2374
- *
2375
- * Copyright (C) 2010 Nikolay Nemshilov
2376
- */
2377
- Rte.Tools.Backcolor = new Class(Rte.Tool.Color, {
2378
- style: 'background-color'
2379
- });
2380
-
2381
- /**
2382
- * The source tool
2383
- *
2384
- * Copyrigth (C) 2010-2011 Nikolay Nemshilov
2385
- */
2386
- Rte.Tools.Source = new Class(Rte.Tool, {
2387
- source: false, // the textarea element reference
2388
-
2389
- exec: function() {
2390
- this[this.rte.srcMode ? 'showPreview' : 'showSource']();
2391
- this.rte.srcMode = !this.rte.srcMode;
2392
- },
2393
-
2394
- active: function() {
2395
- return this.rte.srcMode;
2396
- },
2397
-
2398
- // protected
2399
-
2400
- showPreview: function() {
2401
- this.rte.editor.setStyle('visibility:visible');
2402
- if (this.source) {
2403
- this.rte.value(this.source.value());
2404
- this.source.remove();
2405
- }
2406
-
2407
- this.rte.editor.focus();
2408
- },
2409
-
2410
- showSource: function() {
2411
- this.rte.editor.setStyle('visibility:hidden;');
2412
-
2413
- (
2414
- this.source = this.source ||
2415
- $E('textarea', {'class': 'rui-rte-source'})
2416
- )
2417
- .insertTo(this.rte.editor, 'before')
2418
- .resize(this.rte.editor.size())
2419
- .setValue('' + this.rte.value())
2420
- .focus();
2421
-
2422
- this.rte.focused = true;
2423
-
2424
- this.rte.status.update();
2425
-
2426
- // locking all the tools
2427
- for (var name in this.rte.tools) {
2428
- if (this.rte.tools[name] !== this) {
2429
- this.rte.tools[name].addClass('disabled');
2430
- }
2431
- }
2432
- }
2433
- });
2434
-
2435
- /**
2436
- * the 'clear' tool
2437
- *
2438
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2439
- */
2440
- Rte.Tools.Clear = new Class(Rte.Tool, {
2441
-
2442
- exec: function() {
2443
- this.rte.editor.clean();
2444
- }
2445
-
2446
- });
2447
-
2448
- /**
2449
- * the 'save' tool
2450
- *
2451
- * Copyright (C) 2010-2011 Nikolay Nemshilov
2452
- */
2453
- Rte.Tools.Save = new Class(Rte.Tool, {
2454
-
2455
- initialize: function(rte) {
2456
- this.$super(rte);
2457
- if (!(rte.textarea && rte.textarea.form())) {
2458
- this.disabled = true;
2459
- this.addClass('disabled');
2460
- }
2461
- },
2462
-
2463
- exec: function() {
2464
- if (!this.disabled) {
2465
- this.rte.textarea.form().submit();
2466
- }
2467
- },
2468
-
2469
- check: function() {} // checked in the constructor
2470
- });
2471
-
2472
- /**
2473
- * Formatting style tool
2474
- *
2475
- * Copyright (C) 2010 Nikolay Nemshilov
2476
- */
2477
- Rte.Tools.Format = new Class(Rte.Tool.Format, {
2478
- include: Rte.Tool.Options,
2479
-
2480
- /**
2481
- * Constructor, builds the options list and
2482
- * defines the formats index for quick access
2483
- *
2484
- * @param Rte rte
2485
- */
2486
- initialize: function(rte) {
2487
- var options = {}, rule, tag, match;
2488
-
2489
- this.formats = {};
2490
-
2491
- for (rule in Rte.Formats) {
2492
- if ((match = rule.match(/^([a-z0-9]+)(\.([a-z0-9_\-]+))?$/))) {
2493
- tag = match[1];
2494
-
2495
- this.formats[rule] = { tag: tag.toUpperCase(), attrs: {}, match: {} };
2496
-
2497
- if (match[3]) {
2498
- this.formats[rule]['attrs']['class'] = match[3];
2499
- this.formats[rule]['match']['class'] = new RegExp(
2500
- '(^|\\s+)'+ RegExp.escape(match[3]) + '(\\s+|$)'
2501
- );
2502
- }
2503
-
2504
- options[rule] = '<'+ tag + ' class="'+ match[3] + '">'+
2505
- Rte.Formats[rule] + '</'+ tag + '>';
2506
- }
2507
- }
2508
-
2509
- this.$super(rte).build(options);
2510
-
2511
- return this;
2512
- },
2513
-
2514
- /**
2515
- * Handling the formatting
2516
- *
2517
- * @return void
2518
- */
2519
- exec: function() {
2520
- // removing the formatting first
2521
- if (this.active() && this.rule) {
2522
- this.tag = this.formats[this.rule].tag;
2523
- this.attrs = this.formats[this.rule].attrs;
2524
- this.unformat();
2525
- }
2526
-
2527
- // applying a new formatting if needed
2528
- if (this.value && this.formats[this.value]) {
2529
- this.tag = this.formats[this.value].tag;
2530
- this.attrs = this.formats[this.value].attrs;
2531
- this.format();
2532
- }
2533
- },
2534
-
2535
- /**
2536
- * Overloading the original method so that it updated the
2537
- * currently used formatting style in the display area
2538
- *
2539
- * @return boolean check result
2540
- */
2541
- active: function() {
2542
- var active = this.element() !== null;
2543
- this.updateDisplay(this.rule);
2544
- return active;
2545
- },
2546
-
2547
- // protected
2548
-
2549
- // overloading the original method to handle multiple options
2550
- element: function() {
2551
- var rule, element, status = this.rte.status;
2552
-
2553
- for (rule in this.formats) {
2554
- element = status.findElement(
2555
- this.formats[rule]['tag'],
2556
- this.formats[rule]['match']
2557
- );
2558
-
2559
- if (element !== null) {
2560
- this.rule = rule;
2561
- return element;
2562
- }
2563
- }
2564
-
2565
- return (this.rule = null);
2566
- }
2567
-
2568
-
2569
-
2570
- });
2571
-
2572
- /**
2573
- * Font-name options tool
2574
- *
2575
- * Copyright (C) 2010 Nikolay Nemshilov
2576
- */
2577
- Rte.Tools.Fontname = new Class(Rte.Tool.Style, {
2578
- style: 'font-family',
2579
-
2580
- /**
2581
- * Basic constructor
2582
- *
2583
- * @param Rte rte
2584
- */
2585
- initialize: function(rte) {
2586
- var options = {}, name, fonts = Rte.FontNames;
2587
-
2588
- for (name in fonts) {
2589
- options[fonts[name]] = '<div style="font-family:'+
2590
- fonts[name]+ '">' + name + '</div>';
2591
- }
2592
-
2593
- return this.$super(rte, options);
2594
- }
2595
- });
2596
-
2597
-
2598
- /**
2599
- * The font-size tool
2600
- *
2601
- * Copyright (C) 2010 Nikolay Nemshilov
2602
- */
2603
- Rte.Tools.Fontsize = new Class(Rte.Tool.Style, {
2604
- style: 'font-size',
2605
-
2606
- /**
2607
- * Basic constructor
2608
- *
2609
- * @param Rte rte
2610
- */
2611
- initialize: function(rte) {
2612
- var options = {}, i=0, sizes = Rte.FontSizes.split(/\s+/);
2613
-
2614
- for (; i < sizes.length; i++) {
2615
- options[sizes[i]] = '<div style="font-size:'+
2616
- sizes[i] +'">'+ sizes[i] + '</div>';
2617
- }
2618
-
2619
- return this.$super(rte, options);
2620
- }
2621
- });
2622
-
2623
- /**
2624
- * The subscript tool
2625
- *
2626
- * Copyright (C) 2010 Nikolay Nemshilov
2627
- */
2628
- Rte.Tools.Subscript = new Class(Rte.Tool.Command, {
2629
- command: 'subscript'
2630
- });
2631
-
2632
- /**
2633
- * The superscript tool
2634
- *
2635
- * Copyright (C) 2010 Nikolay Nemshilov
2636
- */
2637
- Rte.Tools.Superscript = new Class(Rte.Tool.Command, {
2638
- command: 'superscript'
2639
- });
2640
-
2641
- /**
2642
- * Document level hooks for the Rte widget
2643
- *
2644
- * Copyright (C) 2010 Nikolay Nemshilov
2645
- */
2646
- $(document).onReady(function() {
2647
- $$(Rte.Options.cssRule).each('getRich');
2648
- });
2649
-
2650
- /**
2651
- * Input level hooks to convert textareas into RTE
2652
- *
2653
- * Copyright (C) 2010 Nikolay Nemshilov
2654
- */
2655
- Input.include({
2656
- /**
2657
- * converts an input field into a RTE
2658
- *
2659
- * @param Object options
2660
- * @return Rte editor
2661
- */
2662
- getRich: function(options) {
2663
- if (this._.type === 'textarea' && !this.rte) {
2664
- this.rte = new Rte(this, options);
2665
- }
2666
-
2667
- return this.rte;
2668
- }
2669
- });
2670
-
2671
- var embed_style = document.createElement('style'),
2672
- embed_rules = document.createTextNode("div.rui-rte,div.rui-rte-toolbar,div.rui-rte-toolbar *,div.rui-rte-editor,div.rui-rte-status,div.rui-rte-status *{margin:0;padding:0;background:none;border:none;width:auto;height:auto}textarea[data-rte]{visibility:hidden}div.rui-rte{display:inline-block; *display:inline; *zoom:1;position:relative}div.rui-rte-toolbar{padding:.15em .3em;background:#eee;border-radius:.25em .25em 0 0;-moz-border-radius:.25em .25em 0 0;-webkit-border-radius:.25em .25em 0 0;border:1px solid #ccc;border-bottom:none}div.rui-rte-toolbar div.line{display:inline-block; *display:inline; *zoom:1;margin-bottom:1px}div.rui-rte-toolbar div.bar{display:inline-block; *display:inline; *zoom:1;margin-right:2px}div.rui-rte-toolbar div.tool{display:inline-block; *display:inline; *zoom:1;margin-right:1px;vertical-align:middle;position:relative;cursor:pointer;border:1px solid #bbb;background-image:url(/images/rightjs-ui/rte.png);background-position:0px 0px;background-color:#fff;border-radius:.25em;-moz-border-radius:.25em;-webkit-border-radius:.25em}div.rui-rte-toolbar div.tool:hover{background-color:#ddd;border-color:#777}div.rui-rte-toolbar div.active{background-position:-20px 0px;background-color:#eee;border-color:#666;box-shadow:#aaa .025em .025em .5em;-moz-box-shadow:#aaa .025em .025em .5em;-webkit-box-shadow:#aaa .025em .025em .5em}div.rui-rte-toolbar div.disabled,div.rui-rte-toolbar div.disabled:hover{opacity:.4;filter:alpha(opacity=40);background-position:-40px 0px;background-color:#eee;border-color:#aaa;cursor:default}div.rui-rte-toolbar div.highlight{background-color:#BBB;border-color:#666}div.rui-rte-toolbar div.icon{height:20px;width:20px;background-image:url(/images/rightjs-ui/rte.png);background-repeat:no-repeat;background-position:20px 20px}div.rui-rte-toolbar div.save div.icon{background-position:0px -20px}div.rui-rte-toolbar div.clear div.icon{background-position:-20px -20px}div.rui-rte-toolbar div.source div.icon{background-position:-40px -20px}div.rui-rte-toolbar div.bold div.icon{background-position:0px -40px}div.rui-rte-toolbar div.italic div.icon{background-position:-20px -40px}div.rui-rte-toolbar div.underline div.icon{background-position:-40px -40px}div.rui-rte-toolbar div.strike div.icon{background-position:-60px -40px}div.rui-rte-toolbar div.cut div.icon{background-position:0px -60px}div.rui-rte-toolbar div.copy div.icon{background-position:-20px -60px}div.rui-rte-toolbar div.paste div.icon{background-position:-40px -60px}div.rui-rte-toolbar div.left div.icon{background-position:0px -80px}div.rui-rte-toolbar div.center div.icon{background-position:-20px -80px}div.rui-rte-toolbar div.right div.icon{background-position:-40px -80px}div.rui-rte-toolbar div.justify div.icon{background-position:-60px -80px}div.rui-rte-toolbar div.undo div.icon{background-position:0px -100px}div.rui-rte-toolbar div.redo div.icon{background-position:-20px -100px}div.rui-rte-toolbar div.quote div.icon{background-position:0px -120px}div.rui-rte-toolbar div.code div.icon{background-position:-20px -120px}div.rui-rte-toolbar div.ttext div.icon{background-position:-40px -120px}div.rui-rte-toolbar div.header div.icon{background-position:-60px -120px}div.rui-rte-toolbar div.image div.icon{background-position:0px -140px}div.rui-rte-toolbar div.link div.icon{background-position:-20px -140px}div.rui-rte-toolbar div.video div.icon{background-position:-40px -140px}div.rui-rte-toolbar div.dotlist div.icon{background-position:0px -160px}div.rui-rte-toolbar div.numlist div.icon{background-position:-20px -160px}div.rui-rte-toolbar div.indent div.icon{background-position:-40px -160px}div.rui-rte-toolbar div.outdent div.icon{background-position:-60px -160px}div.rui-rte-toolbar div.forecolor div.icon{background-position:0px -180px}div.rui-rte-toolbar div.backcolor div.icon{background-position:-20px -180px}div.rui-rte-toolbar div.symbol div.icon{background-position:0px -200px}div.rui-rte-toolbar div.subscript div.icon{background-position:-20px -200px}div.rui-rte-toolbar div.superscript div.icon{background-position:-40px -200px}div.rui-rte-toolbar div.with-options{padding-right:8px}div.rui-rte-toolbar div.with-options div.trigger{position:absolute;right:0;height:100%;width:7px;text-align:center;background:#ccc;border-left:1px solid #bbb}div.rui-rte-toolbar div.bar div:hover div.trigger,div.rui-rte-toolbar div.bar div.active div.trigger{background:#aaa;border-color:#888}div.rui-rte-toolbar div.with-options div.icon{display:none}div.rui-rte-toolbar div.with-options div.display{display:block;line-height:20px;padding:0 6px;margin:0;color:#222;font-size:12px;background:#f8f8f8}div.rui-rte-toolbar div.with-options ul.options,div.rui-rte-toolbar div.with-options ul.options li{list-style:none;margin:0;padding:0}div.rui-rte-toolbar div.with-options ul.options{display:none;cursor:default;position:absolute;margin-bottom:1px;margin-left:-1px;background:#fff;border:1px solid #aaa;border-radius:.25em;-moz-border-radius:.25em;-webkit-border-radius:.25em;box-shadow:#bbb .1em .1em .25em;-moz-box-shadow:#bbb .1em .1em .25em;-webkit-box-shadow:#bbb .1em .1em .25em}div.rui-rte-toolbar div.with-options ul.options li{padding:.2em .5em;white-space:nowrap;cursor:pointer}div.rui-rte-toolbar div.with-options ul.options li:hover{background-color:#eee}div.rui-rte-toolbar div.with-options ul.options li> *{margin:0;padding:0;border:none;position:static}div.rui-rte-toolbar div.color div.icon{display:block}div.rui-rte-toolbar div.color ul.options{padding-bottom:.5em}div.rui-rte-toolbar div.color ul.options li.group,div.rui-rte-toolbar div.color ul.options li.group:hover{background:none}div.rui-rte-toolbar div.color ul.options li.group ul{width:144px;clear:both;padding-top:.5em}div.rui-rte-toolbar div.color ul.options li.group ul li{float:left;width:16px;height:16px;line-height:16px;font-size:80%;text-align:center;text-indent:-9999em;padding:0;cursor:pointer;border:1px solid transparent}div.rui-rte-toolbar div.color ul.options li.group ul li:hover,div.rui-rte-toolbar div.color ul.options li.group ul li.active{background:none;border-color:#444;border-radius:.1em;-moz-border-radius:.1em;-webkit-border-radius:.1em}div.rui-rte-toolbar div.color ul.options li.group ul li.active{text-indent:0}div.rui-rte-toolbar div.color div.display{position:absolute;text-indent:-9999em;bottom:2px;left:3px;margin:0;padding:0;width:14px;height:4px;border-radius:.1em;-moz-border-radius:.1em;-webkit-border-radius:.1em}div.rui-rte-toolbar div.color ul.options li.group ul li.none{border-color:#444}div.rui-rte-toolbar div.color ul.options li.group ul li.label,div.rui-rte-toolbar div.color ul.options li.group ul li.label:hover{text-indent:0;border:none;margin-left:.5em;font-size:1em;cursor:default}div.rui-rte-editor{outline:none;outline:hidden;padding:.1em .3em;overflow:auto;background:white;border:1px solid #ccc}div.rui-rte-editor:focus{border-color:#aaa}div.rui-rte-editor> *:first-child{margin-top:0}div.rui-rte-editor> *:last-child{margin-bottom:0}div.rui-rte textarea.rui-rte-source{position:absolute;outline:none;resize:none}div.rui-rte-status{font-size:90%;height:1.4em;padding:0 .5em;color:#888;background:#eee;border:1px solid #ccc;border-top:none;border-radius:0 0 .25em .25em;-moz-border-radius:0 0 .25em .25em;-webkit-border-radius:0 0 .25em .25em}");
2673
-
2674
- embed_style.type = 'text/css';
2675
- document.getElementsByTagName('head')[0].appendChild(embed_style);
2676
-
2677
- if(embed_style.styleSheet) {
2678
- embed_style.styleSheet.cssText = embed_rules.nodeValue;
2679
- } else {
2680
- embed_style.appendChild(embed_rules);
2681
- }
2682
-
2683
-
2684
- return Rte;
2685
- })(RightJS, document, window);