beef-admin_area 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +7 -0
  5. data/Rakefile +59 -0
  6. data/VERSION +1 -0
  7. data/admin_area.gemspec +168 -0
  8. data/app/controllers/admin/base_controller.rb +8 -0
  9. data/app/controllers/admin/settings_controller.rb +43 -0
  10. data/app/controllers/admin/users_controller.rb +74 -0
  11. data/app/helpers/admin/base_helper.rb +59 -0
  12. data/app/helpers/admin/settings_helper.rb +8 -0
  13. data/app/helpers/admin/users_helper.rb +2 -0
  14. data/app/models/settings.rb +92 -0
  15. data/app/views/admin/base/index.html.erb +2 -0
  16. data/app/views/admin/settings/_form.html.erb +31 -0
  17. data/app/views/admin/settings/update.js.rjs +1 -0
  18. data/app/views/admin/users/index.html.erb +39 -0
  19. data/app/views/admin/users/show.html.erb +37 -0
  20. data/app/views/layouts/admin.html.erb +68 -0
  21. data/config/routes.rb +8 -0
  22. data/generators/admin_area_files/USAGE +8 -0
  23. data/generators/admin_area_files/admin_area_files_generator.rb +114 -0
  24. data/generators/admin_area_files/lib/insert_commands.rb +47 -0
  25. data/generators/admin_area_files/templates/app/models/content_sweeper.rb +43 -0
  26. data/generators/admin_area_files/templates/app/views/admin/settings/show.html.erb +52 -0
  27. data/generators/admin_area_files/templates/config/initializers/admin_area.rb +2 -0
  28. data/generators/admin_area_files/templates/config/initializers/settings.rb +8 -0
  29. data/generators/admin_area_files/templates/lib/tasks/admin_area.rake +10 -0
  30. data/generators/admin_area_files/templates/migration.rb +21 -0
  31. data/generators/admin_area_files/templates/public/images/admin/accept_button.gif +0 -0
  32. data/generators/admin_area_files/templates/public/images/admin/add.png +0 -0
  33. data/generators/admin_area_files/templates/public/images/admin/application_cascade.png +0 -0
  34. data/generators/admin_area_files/templates/public/images/admin/arrow_left.gif +0 -0
  35. data/generators/admin_area_files/templates/public/images/admin/arrow_right.gif +0 -0
  36. data/generators/admin_area_files/templates/public/images/admin/button_bg.gif +0 -0
  37. data/generators/admin_area_files/templates/public/images/admin/cancel_button.gif +0 -0
  38. data/generators/admin_area_files/templates/public/images/admin/cursor_arrow.gif +0 -0
  39. data/generators/admin_area_files/templates/public/images/admin/delete_button.gif +0 -0
  40. data/generators/admin_area_files/templates/public/images/admin/down_icon.gif +0 -0
  41. data/generators/admin_area_files/templates/public/images/admin/edit_button.gif +0 -0
  42. data/generators/admin_area_files/templates/public/images/admin/file-uploads.png +0 -0
  43. data/generators/admin_area_files/templates/public/images/admin/folder.png +0 -0
  44. data/generators/admin_area_files/templates/public/images/admin/folder_image.png +0 -0
  45. data/generators/admin_area_files/templates/public/images/admin/head_bg.gif +0 -0
  46. data/generators/admin_area_files/templates/public/images/admin/image_add.png +0 -0
  47. data/generators/admin_area_files/templates/public/images/admin/images-pointer.png +0 -0
  48. data/generators/admin_area_files/templates/public/images/admin/info_bg.gif +0 -0
  49. data/generators/admin_area_files/templates/public/images/admin/nav_bg.gif +0 -0
  50. data/generators/admin_area_files/templates/public/images/admin/over_button_bg.gif +0 -0
  51. data/generators/admin_area_files/templates/public/images/admin/page_bg.gif +0 -0
  52. data/generators/admin_area_files/templates/public/images/admin/page_white.png +0 -0
  53. data/generators/admin_area_files/templates/public/images/admin/page_white_get.png +0 -0
  54. data/generators/admin_area_files/templates/public/images/admin/page_white_link.png +0 -0
  55. data/generators/admin_area_files/templates/public/images/admin/page_white_stack.png +0 -0
  56. data/generators/admin_area_files/templates/public/images/admin/picture.png +0 -0
  57. data/generators/admin_area_files/templates/public/images/admin/picture_medium.png +0 -0
  58. data/generators/admin_area_files/templates/public/images/admin/picture_square.png +0 -0
  59. data/generators/admin_area_files/templates/public/images/admin/picture_thumb.png +0 -0
  60. data/generators/admin_area_files/templates/public/images/admin/pictures.png +0 -0
  61. data/generators/admin_area_files/templates/public/images/admin/unapproved.png +0 -0
  62. data/generators/admin_area_files/templates/public/images/admin/up_icon.gif +0 -0
  63. data/generators/admin_area_files/templates/public/images/lightwindow/Thumbs.db +0 -0
  64. data/generators/admin_area_files/templates/public/images/lightwindow/ajax-loading.gif +0 -0
  65. data/generators/admin_area_files/templates/public/images/lightwindow/arrow-down.gif +0 -0
  66. data/generators/admin_area_files/templates/public/images/lightwindow/arrow-up.gif +0 -0
  67. data/generators/admin_area_files/templates/public/images/lightwindow/black-70.png +0 -0
  68. data/generators/admin_area_files/templates/public/images/lightwindow/black.png +0 -0
  69. data/generators/admin_area_files/templates/public/images/lightwindow/nextlabel.gif +0 -0
  70. data/generators/admin_area_files/templates/public/images/lightwindow/pattern_148-70.png +0 -0
  71. data/generators/admin_area_files/templates/public/images/lightwindow/pattern_148.gif +0 -0
  72. data/generators/admin_area_files/templates/public/images/lightwindow/prevlabel.gif +0 -0
  73. data/generators/admin_area_files/templates/public/images/textile-editor/background.png +0 -0
  74. data/generators/admin_area_files/templates/public/images/textile-editor/blockquote.png +0 -0
  75. data/generators/admin_area_files/templates/public/images/textile-editor/bold.png +0 -0
  76. data/generators/admin_area_files/templates/public/images/textile-editor/center.png +0 -0
  77. data/generators/admin_area_files/templates/public/images/textile-editor/h1.png +0 -0
  78. data/generators/admin_area_files/templates/public/images/textile-editor/h2.png +0 -0
  79. data/generators/admin_area_files/templates/public/images/textile-editor/h3.png +0 -0
  80. data/generators/admin_area_files/templates/public/images/textile-editor/h4.png +0 -0
  81. data/generators/admin_area_files/templates/public/images/textile-editor/h5.png +0 -0
  82. data/generators/admin_area_files/templates/public/images/textile-editor/h6.png +0 -0
  83. data/generators/admin_area_files/templates/public/images/textile-editor/indent.png +0 -0
  84. data/generators/admin_area_files/templates/public/images/textile-editor/italic.png +0 -0
  85. data/generators/admin_area_files/templates/public/images/textile-editor/justify.png +0 -0
  86. data/generators/admin_area_files/templates/public/images/textile-editor/left.png +0 -0
  87. data/generators/admin_area_files/templates/public/images/textile-editor/link.png +0 -0
  88. data/generators/admin_area_files/templates/public/images/textile-editor/list_bullets.png +0 -0
  89. data/generators/admin_area_files/templates/public/images/textile-editor/list_numbers.png +0 -0
  90. data/generators/admin_area_files/templates/public/images/textile-editor/omega.png +0 -0
  91. data/generators/admin_area_files/templates/public/images/textile-editor/outdent.png +0 -0
  92. data/generators/admin_area_files/templates/public/images/textile-editor/paragraph.png +0 -0
  93. data/generators/admin_area_files/templates/public/images/textile-editor/preview.png +0 -0
  94. data/generators/admin_area_files/templates/public/images/textile-editor/right.png +0 -0
  95. data/generators/admin_area_files/templates/public/images/textile-editor/strikethrough.png +0 -0
  96. data/generators/admin_area_files/templates/public/images/textile-editor/underline.png +0 -0
  97. data/generators/admin_area_files/templates/public/javascripts/admin/application.js +185 -0
  98. data/generators/admin_area_files/templates/public/javascripts/lightwindow.js +1921 -0
  99. data/generators/admin_area_files/templates/public/javascripts/textile-editor-config.js +107 -0
  100. data/generators/admin_area_files/templates/public/javascripts/textile-editor.js +788 -0
  101. data/generators/admin_area_files/templates/public/stylesheets/admin/handheld.css +6 -0
  102. data/generators/admin_area_files/templates/public/stylesheets/admin/ie.css +21 -0
  103. data/generators/admin_area_files/templates/public/stylesheets/admin/print.css +27 -0
  104. data/generators/admin_area_files/templates/public/stylesheets/admin/screen.css +996 -0
  105. data/generators/admin_area_files/templates/public/stylesheets/admin/theme-1.0.css +131 -0
  106. data/generators/admin_area_files/templates/public/stylesheets/lightwindow.css +376 -0
  107. data/generators/admin_area_files/templates/public/stylesheets/textile-editor.css +60 -0
  108. data/generators/admin_scaffold/USAGE +8 -0
  109. data/generators/admin_scaffold/admin_scaffold_generator.rb +53 -0
  110. data/generators/admin_scaffold/lib/insert_commands.rb +61 -0
  111. data/generators/admin_scaffold/templates/admin_controller.rb +83 -0
  112. data/generators/admin_scaffold/templates/admin_index.html.erb +38 -0
  113. data/generators/admin_scaffold/templates/admin_show.html.erb +16 -0
  114. data/generators/admin_scaffold/templates/helper.rb +2 -0
  115. data/generators/admin_scaffold/templates/helper_test.rb +4 -0
  116. data/generators/admin_scaffold/templates/layout.html.erb +17 -0
  117. data/generators/admin_scaffold/templates/style.css +54 -0
  118. data/generators/admin_scaffold/templates/view_controller.rb +14 -0
  119. data/generators/admin_scaffold/templates/view_index.html.erb +17 -0
  120. data/lib/admin_area.rb +82 -0
  121. data/rails/init.rb +4 -0
  122. data/test/admin_area_test.rb +7 -0
  123. data/test/test_helper.rb +10 -0
  124. metadata +206 -0
@@ -0,0 +1,107 @@
1
+ var teButtons = TextileEditor.buttons;
2
+
3
+ /*
4
+ Link button.
5
+ */
6
+ link_button = TextileEditor.prepareButton(new TextileEditorButton('ed_link','link.png','"', '":', 'l', 'Link'));
7
+ link_button.onclick = function() {
8
+ this.standard = false;
9
+ if (!this.textile_editor.checkOpenTags(this)) {
10
+ this.tagEnd = '":' + prompt("Add your link", "");
11
+ }
12
+ this.textile_editor.insertTag(this);
13
+ return false;
14
+ };
15
+ // Preview button
16
+ // preview_button = TextileEditor.prepareButton(new TextileEditorButton('ed_preview','preview.png',null,null,null,'Preview'));
17
+ // preview_button.onclick = function() {
18
+ //
19
+ // var myField = this.textile_editor.canvas;
20
+ // var preview_id = myField.id + '-preview';
21
+ // var preview_div = $(preview_id);
22
+ // if (preview_div) {
23
+ // Effect.BlindUp(preview_div, {afterFinish:function() {
24
+ // myField.style.overflow = 'auto';
25
+ // preview_div.remove();
26
+ // }});
27
+ // } else {
28
+ //
29
+ // html = '<div id="'+preview_id+'" class="preview-area">';
30
+ // html += this.textile_editor.preview_text();
31
+ // html += '</div>';
32
+ //
33
+ // $(myField.parentNode).insert(html);
34
+ // preview_div = $(preview_id);
35
+ //
36
+ // preview_div.setStyle({
37
+ // position: 'absolute'
38
+ // });
39
+ //
40
+ // // Clone textarea's position
41
+ // preview_div.clonePosition(myField);
42
+ // // Fix top if textarea scrolled
43
+ // preview_div.style.top = $(myField).offsetTop + 'px';
44
+ //
45
+ // Effect.BlindDown(preview_div);
46
+ //
47
+ // myField.style.overflow = 'hidden';
48
+ //
49
+ // }
50
+ // return false;
51
+ // };
52
+
53
+
54
+ teButtons.push(new TextileEditorButton('ed_strong', 'bold.png', '*', '*', 'b', 'Bold','s'));
55
+ teButtons.push(new TextileEditorButton('ed_emphasis', 'italic.png', '_', '_', 'i', 'Italicize','s'));
56
+ teButtons.push(new TextileEditorButton('ed_underline', 'underline.png', '+', '+', 'u', 'Underline','s'));
57
+ teButtons.push(new TextileEditorButton('ed_strike', 'strikethrough.png', '-', '-', 's', 'Strikethrough','s'));
58
+ teButtons.push(link_button);
59
+ teButtons.push(new TextileEditorButton('ed_ol', 'list_numbers.png', '# ', '\n', ',', 'Numbered List'));
60
+ teButtons.push(new TextileEditorButton('ed_ul', 'list_bullets.png', '* ', '\n', '.', 'Bulleted List'));
61
+ teButtons.push(new TextileEditorButton('ed_p', 'paragraph.png', 'p', '\n', 'p', 'Paragraph'));
62
+ // teButtons.push(new TextileEditorButton('ed_h1', 'h1.png', 'h1', '\n', '1', 'Header 1'));
63
+ //teButtons.push(new TextileEditorButton('ed_h2', 'h2.png', 'h2', '\n', '2', 'Header 2'));
64
+ //teButtons.push(new TextileEditorButton('ed_h3', 'h3.png', 'h3', '\n', '3', 'Header 3'));
65
+ teButtons.push(new TextileEditorButton('ed_h4', 'h4.png', 'h4', '\n', '4', 'Header 4'));
66
+ //teButtons.push(new TextileEditorButton('ed_block', 'blockquote.png', 'bq', '\n', 'q', 'Blockquote'));
67
+ //teButtons.push(new TextileEditorButton('ed_outdent', 'outdent.png', ')', '\n', ']', 'Outdent'));
68
+ //teButtons.push(new TextileEditorButton('ed_indent', 'indent.png', '(', '\n', '[', 'Indent'));
69
+ //teButtons.push(new TextileEditorButton('ed_justifyl', 'left.png', '<', '\n', 'l', 'Left Justify'));
70
+ //teButtons.push(new TextileEditorButton('ed_justifyc', 'center.png', '=', '\n', 'e', 'Center Text'));
71
+ //teButtons.push(new TextileEditorButton('ed_justifyr', 'right.png', '>', '\n', 'r', 'Right Justify'));
72
+ //teButtons.push(new TextileEditorButton('ed_justify', 'justify.png', '<>', '\n', 'j', 'Justify'));
73
+ //teButtons.push(preview_button);
74
+
75
+ // teButtons.push(new TextileEditorButton('ed_code','code','@','@','c','Code'));
76
+
77
+ // Add image. insertAtCursor function in apllcation.js
78
+ addImage = function(imageurl,size) {
79
+ alt = alt.replace("(","").replace(")","");
80
+ insertAtCursor(TextileEditor.canvas, '\n\n!'+imageurl+'('+alt+')!\n\n');
81
+ };
82
+
83
+ addLinkedImage = function(imageurl,alt) {
84
+ alt = alt.replace("(","").replace(")","");
85
+ insertAtCursor(TextileEditor.canvas, '\n\n!'+imageurl+'('+alt+')!:'+imageurl+'\n\n');
86
+ };
87
+
88
+ addLink = function(text, url) {
89
+ insertAtCursor(TextileEditor.canvas, '"'+ text +'":'+ url + ' ');
90
+ };
91
+
92
+ addAsset = function(asset_id, size) {
93
+ if (size && size != 'fullsize') {
94
+ size = '|'+size;
95
+ } else {
96
+ size = ''
97
+ }
98
+ insertAtCursor(TextileEditor.canvas, '[asset('+asset_id+size+')]');
99
+ };
100
+
101
+ // Iittialise textile editor
102
+ document.observe('dom:loaded',function(){
103
+ $$('textarea.editor').each(function(ta){
104
+ // alert(ta.id);
105
+ TextileEditor.initialize(ta.id);
106
+ });
107
+ });
@@ -0,0 +1,788 @@
1
+ /*
2
+
3
+ Textile Editor v0.2
4
+ created by: dave olsen, wvu web services
5
+ created on: march 17, 2007
6
+ project page: slateinfo.blogs.wvu.edu
7
+
8
+ inspired by:
9
+ - Patrick Woods, http://www.hakjoon.com/code/38/textile-quicktags-redirect &
10
+ - Alex King, http://alexking.org/projects/js-quicktags
11
+
12
+ features:
13
+ - supports: IE7, FF2, Safari2
14
+ - ability to use "simple" vs. "extended" editor
15
+ - supports all block elements in textile except footnote
16
+ - supports all block modifier elements in textile
17
+ - supports simple ordered and unordered lists
18
+ - supports most of the phrase modifiers, very easy to add the missing ones
19
+ - supports multiple-paragraph modification
20
+ - can have multiple "editors" on one page, access key use in this environment is flaky
21
+ - access key support
22
+ - select text to add and remove tags, selection stays highlighted
23
+ - seamlessly change between tags and modifiers
24
+ - doesn't need to be in the body onload tag
25
+ - can supply your own, custom IDs for the editor to be drawn around
26
+
27
+ todo:
28
+ - a clean way of providing image and link inserts
29
+ - get the selection to properly show in IE
30
+
31
+ more on textile:
32
+ - Textism, http://www.textism.com/tools/textile/index.php
33
+ - Textile Reference, http://hobix.com/textile/
34
+
35
+ */
36
+
37
+ // Define Button Object
38
+ function TextileEditorButton(id, display, tagStart, tagEnd, access, title, sve, open) {
39
+ this.id = id; // used to name the toolbar button
40
+ this.display = display; // label on button
41
+ this.tagStart = tagStart; // open tag
42
+ this.tagEnd = tagEnd; // close tag
43
+ this.access = access; // set to -1 if tag does not need to be closed
44
+ this.title = title; // sets the title attribute of the button to give 'tool tips'
45
+ this.sve = sve; // sve = simple vs. extended. add an 's' to make it show up in the simple toolbar
46
+ this.open = open; // set to -1 if tag does not need to be closed
47
+ this.standard = true; // this is a standard button
48
+ }
49
+
50
+ function TextileEditorButtonSeparator(sve) {
51
+ this.separator = true;
52
+ this.sve = sve;
53
+ }
54
+
55
+ var TextileEditor = Class.create();
56
+ TextileEditor.buttons = new Array();
57
+ TextileEditor.Methods = {
58
+ // class methods
59
+
60
+ // create the toolbar (edToolbar)
61
+ initialize: function(canvas, view) {
62
+ var toolbar = document.createElement("div");
63
+ toolbar.id = "textile-toolbar-" + canvas;
64
+ toolbar.className = 'textile-toolbar';
65
+ this.canvas = document.getElementById(canvas);
66
+ this.canvas.parentNode.insertBefore(toolbar, this.canvas);
67
+ this.openTags = new Array();
68
+
69
+ // Create the local Button array by assigning theButtons array to edButtons
70
+ var edButtons = new Array();
71
+ edButtons = this.buttons;
72
+
73
+ var standardButtons = new Array();
74
+ for(var i = 0; i < edButtons.length; i++) {
75
+ var thisButton = this.prepareButton(edButtons[i]);
76
+ if (view == 's') {
77
+ if (edButtons[i].sve == 's') {
78
+ toolbar.appendChild(thisButton);
79
+ standardButtons.push(thisButton);
80
+ }
81
+ } else {
82
+ if (typeof thisButton == 'string') {
83
+ toolbar.innerHTML += thisButton;
84
+ } else {
85
+ toolbar.appendChild(thisButton);
86
+ standardButtons.push(thisButton);
87
+ }
88
+ }
89
+ } // end for
90
+
91
+ var te = this;
92
+ $A(toolbar.getElementsByTagName('button')).each(function(button) {
93
+ if (!button.onclick) {
94
+ button.onclick = function() { te.insertTag(button); return false; };
95
+ } // end if
96
+
97
+ button.tagStart = button.getAttribute('tagStart');
98
+ button.tagEnd = button.getAttribute('tagEnd');
99
+ button.open = button.getAttribute('open');
100
+ button.textile_editor = te;
101
+ button.canvas = te.canvas;
102
+ });
103
+ }, // end initialize
104
+
105
+ // draw individual buttons (edShowButton)
106
+ prepareButton: function(button) {
107
+ if (button.separator) {
108
+ var theButton = document.createElement('span');
109
+ theButton.className = 'ed_sep';
110
+ return theButton;
111
+ }
112
+
113
+ if (button.standard) {
114
+ var theButton = document.createElement("button");
115
+ theButton.id = button.id;
116
+ theButton.setAttribute('class', 'standard');
117
+ theButton.setAttribute('tagStart', button.tagStart);
118
+ theButton.setAttribute('tagEnd', button.tagEnd);
119
+ theButton.setAttribute('open', button.open);
120
+
121
+ var img = document.createElement('img');
122
+ img.src = '/images/textile-editor/' + button.display;
123
+ theButton.appendChild(img);
124
+ } else {
125
+ return button;
126
+ } // end if !custom
127
+
128
+ theButton.accessKey = button.access;
129
+ theButton.title = button.title;
130
+ return theButton;
131
+ }, // end prepareButton
132
+
133
+ // if clicked, no selected text, tag not open highlight button
134
+ // (edAddTag)
135
+ addTag: function(button) {
136
+ if (button.tagEnd != '') {
137
+ this.openTags[this.openTags.length] = button;
138
+ //var el = document.getElementById(button.id);
139
+ //el.className = 'selected';
140
+ button.className = 'selected';
141
+ }
142
+ }, // end addTag
143
+
144
+ // if clicked, no selected text, tag open lowlight button
145
+ // (edRemoveTag)
146
+ removeTag: function(button) {
147
+ for (i = 0; i < this.openTags.length; i++) {
148
+ if (this.openTags[i] == button) {
149
+ this.openTags.splice(button, 1);
150
+ //var el = document.getElementById(button.id);
151
+ //el.className = 'unselected';
152
+ button.className = 'unselected';
153
+ }
154
+ }
155
+ }, // end removeTag
156
+
157
+ // see if there are open tags. for the remove tag bit...
158
+ // (edCheckOpenTags)
159
+ checkOpenTags: function(button) {
160
+ var tag = 0;
161
+ for (i = 0; i < this.openTags.length; i++) {
162
+ if (this.openTags[i] == button) {
163
+ tag++;
164
+ }
165
+ }
166
+ if (tag > 0) {
167
+ return true; // tag found
168
+ }
169
+ else {
170
+ return false; // tag not found
171
+ }
172
+ }, // end checkOpenTags
173
+
174
+ // insert the tag. this is the bulk of the code.
175
+ // (edInsertTag)
176
+ insertTag: function(button, tagStart, tagEnd) {
177
+ var myField = button.canvas;
178
+ myField.focus();
179
+
180
+ if (tagStart) {
181
+ button.tagStart = tagStart;
182
+ button.tagEnd = tagEnd ? tagEnd : '\n';
183
+ }
184
+
185
+ var textSelected = false;
186
+ var finalText = '';
187
+ var FF = false;
188
+
189
+ // grab the text that's going to be manipulated, by browser
190
+ if (document.selection) { // IE support
191
+ sel = document.selection.createRange();
192
+
193
+ // set-up the text vars
194
+ var beginningText = '';
195
+ var followupText = '';
196
+
197
+ //remove any extra spaces caught on the end of the selection
198
+ var selectedText = sel.text.replace(/( +)$/, '');
199
+ var matches = sel.text.match(/( +)$/);
200
+ if(matches){
201
+ followupText += matches[1];
202
+ }
203
+
204
+ // check if text has been selected
205
+ if (sel.text.length > 0) {
206
+ textSelected = true;
207
+ }
208
+
209
+ // set-up newline regex's so we can swap tags across multiple paragraphs
210
+ var newlineReplaceRegexClean = /\r\n\s\n/g;
211
+ var newlineReplaceRegexDirty = '\\r\\n\\s\\n';
212
+ var newlineReplaceClean = '\r\n\n';
213
+ }
214
+ else if (myField.selectionStart || myField.selectionStart == '0') { // MOZ/FF/NS/S support
215
+
216
+ // figure out cursor and selection positions
217
+ var startPos = myField.selectionStart;
218
+ var endPos = myField.selectionEnd;
219
+ var cursorPos = endPos;
220
+ var scrollTop = myField.scrollTop;
221
+ FF = true; // note that is is a FF/MOZ/NS/S browser
222
+
223
+ // set-up the text vars
224
+ var beginningText = myField.value.substring(0, startPos);
225
+ var followupText = myField.value.substring(endPos, myField.value.length);
226
+
227
+ // check if text has been selected
228
+ if (startPos != endPos) {
229
+ textSelected = true;
230
+ var selectedText = myField.value.substring(startPos, endPos);
231
+ }
232
+
233
+ // set-up newline regex's so we can swap tags across multiple paragraphs
234
+ var newlineReplaceRegexClean = /\n\n/g;
235
+ var newlineReplaceRegexDirty = '\\n\\n';
236
+ var newlineReplaceClean = '\n\n';
237
+ }
238
+
239
+
240
+ // if there is text that has been highlighted...
241
+ if (textSelected) {
242
+
243
+ // set-up some defaults for how to handle bad new line characters
244
+ var newlineStart = '';
245
+ var newlineStartPos = 0;
246
+ var newlineEnd = '';
247
+ var newlineEndPos = 0;
248
+ var newlineFollowup = '';
249
+
250
+ // set-up some defaults for how to handle placing the beginning and end of selection
251
+ var posDiffPos = 0;
252
+ var posDiffNeg = 0;
253
+ var mplier = 1;
254
+
255
+ // remove newline from the beginning of the selectedText.
256
+ if (selectedText.match(/^\n/)) {
257
+ selectedText = selectedText.replace(/^\n/,'');
258
+ newlineStart = '\n';
259
+ newlineStartpos = 1;
260
+ }
261
+
262
+ // remove newline from the end of the selectedText.
263
+ if (selectedText.match(/\n$/g)) {
264
+ selectedText = selectedText.replace(/\n$/g,'');
265
+ newlineEnd = '\n';
266
+ newlineEndPos = 1;
267
+ }
268
+
269
+ // no clue, i'm sure it made sense at the time i wrote it
270
+ if (followupText.match(/^\n/)) {
271
+ newlineFollowup = '';
272
+ }
273
+ else {
274
+ newlineFollowup = '\n\n';
275
+ }
276
+
277
+ // first off let's check if the user is trying to mess with lists
278
+ if ((button.tagStart == '* ') || (button.tagStart == '# ')) {
279
+
280
+ listItems = 0; // sets up a default to be able to properly manipulate final selection
281
+
282
+ // set-up all of the regex's
283
+ re_start = new RegExp('^(\\*|\\#) ','g');
284
+ if (button.tagStart == '# ') {
285
+ re_tag = new RegExp('\\# ','g'); // because of JS regex stupidity i need an if/else to properly set it up, could have done it with a regex replace though
286
+ }
287
+ else {
288
+ re_tag = new RegExp('\\* ','g');
289
+ }
290
+ re_replace = new RegExp('(\\*|\\#) ','g');
291
+
292
+ // try to remove bullets in text copied from ms word **Mac Only!**
293
+ re_word_bullet_m_s = new RegExp('• ','g'); // mac/safari
294
+ re_word_bullet_m_f = new RegExp('∑ ','g'); // mac/firefox
295
+ selectedText = selectedText.replace(re_word_bullet_m_s,'').replace(re_word_bullet_m_f,'');
296
+
297
+ // if the selected text starts with one of the tags we're working with...
298
+ if (selectedText.match(re_start)) {
299
+
300
+ // if tag that begins the selection matches the one clicked, remove them all
301
+ if (selectedText.match(re_tag)) {
302
+ finalText = beginningText
303
+ + newlineStart
304
+ + selectedText.replace(re_replace,'')
305
+ + newlineEnd
306
+ + followupText;
307
+ if (matches = selectedText.match(/(\*|\#) /g)) {
308
+ listItems = matches.length;
309
+ }
310
+ posDiffNeg = (listItems*2); // how many list items were there because that's 3 spaces to remove from final selection
311
+ }
312
+
313
+ // else replace the current tag type with the selected tag type
314
+ else {
315
+ finalText = beginningText
316
+ + newlineStart
317
+ + selectedText.replace(re_replace,button.tagStart)
318
+ + newlineEnd
319
+ + followupText;
320
+ }
321
+ }
322
+
323
+ // else try to create the list type
324
+ // NOTE: the items in a list will only be replaced if a newline starts with some character, not a space
325
+ else {
326
+ finalText = beginningText
327
+ + newlineStart
328
+ + button.tagStart
329
+ + selectedText.replace(newlineReplaceRegexClean,newlineReplaceClean + button.tagStart).replace(/\n(\S)/g,'\n' + button.tagStart + '$1')
330
+ + newlineEnd
331
+ + followupText;
332
+ if (matches = selectedText.match(/\n(\S)/g)) {
333
+ listItems = matches.length;
334
+ }
335
+ posDiffPos = (listItems*2) + 2;
336
+ }
337
+ }
338
+
339
+ // now lets look and see if the user is trying to muck with a block or block modifier
340
+ else if (button.tagStart.match(/^(h1|h2|h3|h4|h5|h6|bq|p|\>|\<\>|\<|\=|\(|\))/g)) {
341
+
342
+ var insertTag = '';
343
+ var insertModifier = '';
344
+ var tagPartBlock = '';
345
+ var tagPartModifier = '';
346
+ var tagPartModifierOrig = ''; // ugly hack but it's late
347
+ var drawSwitch = '';
348
+ var captureIndentStart = false;
349
+ var captureListStart = false;
350
+ var periodAddition = '\\. ';
351
+ var periodAdditionClean = '. ';
352
+ var listItemsAddition = 0;
353
+
354
+ var re_list_items = new RegExp('(\\*+|\\#+)','g'); // need this regex later on when checking indentation of lists
355
+
356
+ var re_block_modifier = new RegExp('^(h1|h2|h3|h4|h5|h6|bq|p| [\\*]{1,} | [\\#]{1,} |)(\\>|\\<\\>|\\<|\\=|[\\(]{1,}|[\\)]{1,6}|)','g');
357
+ if (tagPartMatches = re_block_modifier.exec(selectedText)) {
358
+ tagPartBlock = tagPartMatches[1];
359
+ tagPartModifier = tagPartMatches[2];
360
+ tagPartModifierOrig = tagPartMatches[2];
361
+ tagPartModifierOrig = tagPartModifierOrig.replace(/\(/g,"\\(");
362
+ }
363
+
364
+ // if tag already up is the same as the tag provided replace the whole tag
365
+ if (tagPartBlock == button.tagStart) {
366
+ insertTag = tagPartBlock + tagPartModifierOrig; // use Orig because it's escaped for regex
367
+ drawSwitch = 0;
368
+ }
369
+ // else if let's check to add/remove block modifier
370
+ else if ((tagPartModifier == button.tagStart) || (newm = tagPartModifier.match(/[\(]{2,}/g))) {
371
+ if ((button.tagStart == '(') || (button.tagStart == ')')) {
372
+ var indentLength = tagPartModifier.length;
373
+ if (button.tagStart == '(') {
374
+ indentLength = indentLength + 1;
375
+ }
376
+ else {
377
+ indentLength = indentLength - 1;
378
+ }
379
+ for (var i = 0; i < indentLength; i++) {
380
+ insertModifier = insertModifier + '(';
381
+ }
382
+ insertTag = tagPartBlock + insertModifier;
383
+ }
384
+ else {
385
+ if (button.tagStart == tagPartModifier) {
386
+ insertTag = tagPartBlock;
387
+ } // going to rely on the default empty insertModifier
388
+ else {
389
+
390
+ if (button.tagStart.match(/(\>|\<\>|\<|\=)/g)) {
391
+ insertTag = tagPartBlock + button.tagStart;
392
+ }
393
+ else {
394
+ insertTag = button.tagStart + tagPartModifier;
395
+ }
396
+ }
397
+
398
+ }
399
+ drawSwitch = 1;
400
+ }
401
+ // indentation of list items
402
+ else if (listPartMatches = re_list_items.exec(tagPartBlock)) {
403
+ var listTypeMatch = listPartMatches[1];
404
+ var indentLength = tagPartBlock.length - 2;
405
+ var listInsert = '';
406
+ if (button.tagStart == '(') {
407
+ indentLength = indentLength + 1;
408
+ }
409
+ else {
410
+ indentLength = indentLength - 1;
411
+ }
412
+ if (listTypeMatch.match(/[\*]{1,}/g)) {
413
+ var listType = '*';
414
+ var listReplace = '\\*';
415
+ }
416
+ else {
417
+ var listType = '#';
418
+ var listReplace = '\\#';
419
+ }
420
+ for (var i = 0; i < indentLength; i++) {
421
+ listInsert = listInsert + listType;
422
+ }
423
+ if (listInsert != '') {
424
+ insertTag = ' ' + listInsert + ' ';
425
+ }
426
+ else {
427
+ insertTag = '';
428
+ }
429
+ tagPartBlock = tagPartBlock.replace(/(\*|\#)/g,listReplace);
430
+ drawSwitch = 1;
431
+ captureListStart = true;
432
+ periodAddition = '';
433
+ periodAdditionClean = '';
434
+ if (matches = selectedText.match(/\n\s/g)) {
435
+ listItemsAddition = matches.length;
436
+ }
437
+ }
438
+ // must be a block modification e.g. p>. to p<.
439
+ else {
440
+
441
+ // if this is a block modification/addition
442
+ if (button.tagStart.match(/(h1|h2|h3|h4|h5|h6|bq|p)/g)) {
443
+ if (tagPartBlock == '') {
444
+ drawSwitch = 2;
445
+ }
446
+ else {
447
+ drawSwitch = 1;
448
+ }
449
+
450
+ insertTag = button.tagStart + tagPartModifier;
451
+ }
452
+
453
+ // else this is a modifier modification/addition
454
+ else {
455
+ if ((tagPartModifier == '') && (tagPartBlock != '')) {
456
+ drawSwitch = 1;
457
+ }
458
+ else if (tagPartModifier == '') {
459
+ drawSwitch = 2;
460
+ }
461
+ else {
462
+ drawSwitch = 1;
463
+ }
464
+
465
+ // if no tag part block but a modifier we need at least the p tag
466
+ if (tagPartBlock == '') {
467
+ tagPartBlock = 'p';
468
+ }
469
+
470
+ //make sure to swap out outdent
471
+ if (button.tagStart == ')') {
472
+ tagPartModifier = '';
473
+ }
474
+ else {
475
+ tagPartModifier = button.tagStart;
476
+ captureIndentStart = true; // ugly hack to fix issue with proper selection handling
477
+ }
478
+
479
+ insertTag = tagPartBlock + tagPartModifier;
480
+ }
481
+ }
482
+
483
+ mplier = 0;
484
+ if (captureListStart || (tagPartModifier.match(/[\(\)]{1,}/g))) {
485
+ re_start = new RegExp(insertTag.escape + periodAddition,'g'); // for tags that mimic regex properties, parens + list tags
486
+ }
487
+ else {
488
+ re_start = new RegExp(insertTag + periodAddition,'g'); // for tags that don't, why i can't just escape everything i have no clue
489
+ }
490
+ re_old = new RegExp(tagPartBlock + tagPartModifierOrig + periodAddition,'g');
491
+ re_middle = new RegExp(newlineReplaceRegexDirty + insertTag.escape + periodAddition.escape,'g');
492
+ re_tag = new RegExp(insertTag.escape + periodAddition.escape,'g');
493
+
494
+ // *************************************************************************************************************************
495
+ // this is where everything gets swapped around or inserted, bullets and single options have their own if/else statements
496
+ // *************************************************************************************************************************
497
+ if ((drawSwitch == 0) || (drawSwitch == 1)) {
498
+ if (drawSwitch == 0) { // completely removing a tag
499
+ finalText = beginningText
500
+ + newlineStart
501
+ + selectedText.replace(re_start,'').replace(re_middle,newlineReplaceClean)
502
+ + newlineEnd
503
+ + followupText;
504
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
505
+ mplier = mplier + matches.length;
506
+ }
507
+ posDiffNeg = insertTag.length + 2 + (mplier*4);
508
+ }
509
+ else { // modifying a tag, though we do delete bullets here
510
+ finalText = beginningText
511
+ + newlineStart
512
+ + selectedText.replace(re_old,insertTag + periodAdditionClean)
513
+ + newlineEnd
514
+ + followupText;
515
+
516
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
517
+ mplier = mplier + matches.length;
518
+ }
519
+ // figure out the length of various elements to modify the selection position
520
+ if (captureIndentStart) { // need to double-check that this wasn't the first indent
521
+ tagPreviousLength = tagPartBlock.length;
522
+ tagCurrentLength = insertTag.length;
523
+ }
524
+ else if (captureListStart) { // if this is a list we're manipulating
525
+ if (button.tagStart == '(') { // if indenting
526
+ tagPreviousLength = listTypeMatch.length + 2;
527
+ tagCurrentLength = insertTag.length + listItemsAddition;
528
+ }
529
+ else if (insertTag.match(/(\*|\#)/g)) { // if removing but still has bullets
530
+ tagPreviousLength = insertTag.length + listItemsAddition;
531
+ tagCurrentLength = listTypeMatch.length;
532
+ }
533
+ else { // if removing last bullet
534
+ tagPreviousLength = insertTag.length + listItemsAddition;
535
+ tagCurrentLength = listTypeMatch.length - (3*listItemsAddition) - 1;
536
+ }
537
+ }
538
+ else { // everything else
539
+ tagPreviousLength = tagPartBlock.length + tagPartModifier.length;
540
+ tagCurrentLength = insertTag.length;
541
+ }
542
+ if (tagCurrentLength > tagPreviousLength) {
543
+ posDiffPos = (tagCurrentLength - tagPreviousLength) + (mplier*(tagCurrentLength - tagPreviousLength));
544
+ }
545
+ else {
546
+ posDiffNeg = (tagPreviousLength - tagCurrentLength) + (mplier*(tagPreviousLength - tagCurrentLength));
547
+ }
548
+ }
549
+ }
550
+ else { // for adding tags other then bullets (have their own statement)
551
+ finalText = beginningText
552
+ + newlineStart
553
+ + insertTag + '. '
554
+ + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + '\n' + insertTag + '. ')
555
+ + newlineFollowup
556
+ + newlineEnd
557
+ + followupText;
558
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
559
+ mplier = mplier + matches.length;
560
+ }
561
+ posDiffPos = insertTag.length + 2 + (mplier*4);
562
+ }
563
+ }
564
+
565
+ // swap in and out the simple tags around a selection like bold
566
+ else {
567
+
568
+ mplier = 1; // the multiplier for the tag length
569
+ re_start = new RegExp('^\\' + button.tagStart,'g');
570
+ re_end = new RegExp('\\' + button.tagEnd + '$','g');
571
+ re_middle = new RegExp('\\' + button.tagEnd + newlineReplaceRegexDirty + '\\' + button.tagStart,'g');
572
+ if (selectedText.match(re_start) && selectedText.match(re_end)) {
573
+ finalText = beginningText
574
+ + newlineStart
575
+ + selectedText.replace(re_start,'').replace(re_end,'').replace(re_middle,newlineReplaceClean)
576
+ + newlineEnd
577
+ + followupText;
578
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
579
+ mplier = mplier + matches.length;
580
+ }
581
+ posDiffNeg = button.tagStart.length*mplier + button.tagEnd.length*mplier;
582
+ }
583
+ else {
584
+ finalText = beginningText
585
+ + newlineStart
586
+ + button.tagStart
587
+ + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + newlineReplaceClean + button.tagStart)
588
+ + button.tagEnd
589
+ + newlineEnd
590
+ + followupText;
591
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
592
+ mplier = mplier + matches.length;
593
+ }
594
+ posDiffPos = (button.tagStart.length*mplier) + (button.tagEnd.length*mplier);
595
+ }
596
+ }
597
+
598
+ cursorPos += button.tagStart.length + button.tagEnd.length;
599
+
600
+ }
601
+
602
+ // just swap in and out single values, e.g. someone clicks b they'll get a *
603
+ else {
604
+ var buttonStart = '';
605
+ var buttonEnd = '';
606
+ var re_p = new RegExp('(\\<|\\>|\\=|\\<\\>|\\(|\\))','g');
607
+ var re_h = new RegExp('^(h1|h2|h3|h4|h5|h6|p|bq)','g');
608
+ if (!this.checkOpenTags(button) || button.tagEnd == '') { // opening tag
609
+
610
+ if (button.tagStart.match(re_h)) {
611
+ buttonStart = button.tagStart + '. ';
612
+ }
613
+ else {
614
+ buttonStart = button.tagStart;
615
+ }
616
+ if (button.tagStart.match(re_p)) { // make sure that invoking block modifiers don't do anything
617
+ finalText = beginningText
618
+ + followupText;
619
+ cursorPos = startPos;
620
+ }
621
+ else {
622
+ finalText = beginningText
623
+ + buttonStart
624
+ + followupText;
625
+ this.addTag(button);
626
+ cursorPos = startPos + buttonStart.length;
627
+ }
628
+
629
+ }
630
+ else { // closing tag
631
+ if (button.tagStart.match(re_p)) {
632
+ buttonEnd = '\n\n';
633
+ }
634
+ else if (button.tagStart.match(re_h)) {
635
+ buttonEnd = '\n\n';
636
+ }
637
+ else {
638
+ buttonEnd = button.tagEnd;
639
+ }
640
+ finalText = beginningText
641
+ + button.tagEnd
642
+ + followupText;
643
+ this.removeTag(button);
644
+ cursorPos = startPos + button.tagEnd.length;
645
+ }
646
+ }
647
+
648
+ // set the appropriate DOM value with the final text
649
+ if (FF == true) {
650
+ myField.value = finalText;
651
+ myField.scrollTop = scrollTop;
652
+ }
653
+ else {
654
+ sel.text = finalText;
655
+ }
656
+
657
+ // build up the selection capture, doesn't work in IE
658
+ if (textSelected) {
659
+ myField.selectionStart = startPos + newlineStartPos;
660
+ myField.selectionEnd = endPos + posDiffPos - posDiffNeg - newlineEndPos;
661
+ //alert('s: ' + myField.selectionStart + ' e: ' + myField.selectionEnd + ' sp: ' + startPos + ' ep: ' + endPos + ' pdp: ' + posDiffPos + ' pdn: ' + posDiffNeg)
662
+ }
663
+ else {
664
+ myField.selectionStart = cursorPos;
665
+ myField.selectionEnd = cursorPos;
666
+ }
667
+ }, // end insertTag
668
+
669
+ preview_text: function() {
670
+
671
+ var r = this.canvas.value;
672
+
673
+ // quick tags first
674
+ qtags = [['\\*', 'strong'],
675
+ ['\\?\\?', 'cite'],
676
+ ['\\+', 'ins'], //fixed
677
+ ['~', 'sub'],
678
+ ['\\^', 'sup'], // me
679
+ ['@', 'code']];
680
+ for (var i=0;i<qtags.length;i++) {
681
+ ttag = qtags[i][0]; htag = qtags[i][1];
682
+ re = new RegExp(ttag+'\\b(.+?)\\b'+ttag,'g');
683
+ r = r.replace(re,'<'+htag+'>'+'$1'+'</'+htag+'>');
684
+ }
685
+ // underscores count as part of a word, so do them separately
686
+ re = new RegExp('\\b_(.+?)_\\b','g');
687
+ r = r.replace(re,'<em>$1</em>');
688
+
689
+ //jeff: so do dashes
690
+ re = new RegExp('[\s\n]-(.+?)-[\s\n]','g');
691
+ r = r.replace(re,'<del>$1</del>');
692
+
693
+ // links
694
+ re = new RegExp('"\\b(.+?)\\(\\b(.+?)\\b\\)":([^\\s]+)','g');
695
+ r = r.replace(re,'<a href="$3" title="$2">$1</a>');
696
+ re = new RegExp('"\\b(.+?)\\b":([^\\s]+)','g');
697
+ r = r.replace(re,'<a href="$2">$1</a>');
698
+
699
+ // BenL: Various special characters etc
700
+ re = new RegExp('\\(c\\)','g');
701
+ r = r.replace(re,'&copy;');
702
+ re = new RegExp('\\(tm\\)','g');
703
+ r = r.replace(re,'&trade;');
704
+ re = new RegExp('\\(r\\)','g');
705
+ r = r.replace(re,'&reg;');
706
+ re = new RegExp('\\.\\.\\.','g');
707
+ r = r.replace(re,'&#8230;');
708
+ re = new RegExp('"(.+?)"([\\s:,;])','g');
709
+ r = r.replace(re,'&#8220;$1&#8221;$2');
710
+ re = new RegExp('\\-\\-','g');
711
+ r = r.replace(re,'&#8212');
712
+ re = new RegExp(' \\- ','g');
713
+ r = r.replace(re,' &#8212 ');
714
+
715
+ // Beef: images with links
716
+ re = new RegExp('!\\b(.+?)\\(\\b(.+?)\\b\\)!:([^\\s]+)','g');
717
+ r = r.replace(re,'<a href="$3" title="$2"><img src="$1" alt="$2"/></a>');
718
+ re = new RegExp('!\\b(.+?)\\b!:([^\\s]+)','g');
719
+ r = r.replace(re,'<a href="$2"><img src="$1"/></a>');
720
+
721
+
722
+ // images
723
+ re = new RegExp('!\\b(.+?)\\(\\b(.+?)\\b\\)!','g');
724
+ r = r.replace(re,'<img src="$1" alt="$2"/>');
725
+ re = new RegExp('!\\b(.+?)\\b!','g');
726
+ r = r.replace(re,'<img src="$1"/>');
727
+
728
+ // block level formatting
729
+
730
+ // Jeff's hack to show single line breaks as they should.
731
+ // insert breaks - but you get some....stupid ones
732
+ re = new RegExp('(.*)\n([^#\*\n].*)','g');
733
+ r = r.replace(re,'$1<br />$2');
734
+ // remove the stupid breaks.
735
+ re = new RegExp('\n<br />','g');
736
+ r = r.replace(re,'\n');
737
+
738
+ lines = r.split('\n');
739
+ nr = '';
740
+ for (var i=0;i<lines.length;i++) {
741
+ line = lines[i].replace(/\s*$/,'');
742
+ changed = 0;
743
+ if (line.search(/^\s*bq\.\s+/) != -1) {
744
+ line = line.replace(/^\s*bq\.\s+/,'\t<blockquote>')+'</blockquote>';
745
+ changed = 1;
746
+ }
747
+
748
+ // jeff adds h#.
749
+ if (line.search(/^\s*h[1|2|3|4|5|6]\.\s+/) != -1) {
750
+ re = new RegExp('h([1|2|3|4|5|6])\.(.+)','g');
751
+ line = line.replace(re,'<h$1>$2</h$1>');
752
+ changed = 1;
753
+ }
754
+
755
+ if (line.search(/^\s*\*\s+/) != -1) { line = line.replace(/^\s*\*\s+/,'\t<liu>') + '</liu>'; changed = 1; } // * for bullet list; make up an liu tag to be fixed later
756
+ if (line.search(/^\s*#\s+/) != -1) { line = line.replace(/^\s*#\s+/,'\t<lio>') + '</lio>'; changed = 1; } // # for numeric list; make up an lio tag to be fixed later
757
+ if (!changed && (line.replace(/\s/g,'').length > 0)) line = '<p>'+line+'</p>';
758
+ lines[i] = line + '\n';
759
+ }
760
+
761
+ // Second pass to do lists
762
+ inlist = 0;
763
+ listtype = '';
764
+ for (var i=0;i<lines.length;i++) {
765
+ line = lines[i];
766
+ if (inlist && listtype == 'ul' && !line.match(/^\t<liu/)) { line = '</ul>\n' + line; inlist = 0; }
767
+ if (inlist && listtype == 'ol' && !line.match(/^\t<lio/)) { line = '</ol>\n' + line; inlist = 0; }
768
+ if (!inlist && line.match(/^\t<liu/)) { line = '<ul>' + line; inlist = 1; listtype = 'ul'; }
769
+ if (!inlist && line.match(/^\t<lio/)) { line = '<ol>' + line; inlist = 1; listtype = 'ol'; }
770
+ lines[i] = line;
771
+ }
772
+
773
+ r = lines.join('\n');
774
+ // jeff added : will correctly replace <li(o|u)> AND </li(o|u)>
775
+ r = r.replace(/li[o|u]>/g,'li>');
776
+
777
+ return r;
778
+
779
+
780
+
781
+ } // End preview text
782
+
783
+
784
+ }; // end class
785
+
786
+ // add class methods
787
+ Object.extend(TextileEditor, TextileEditor.Methods);
788
+ document.write('<script src="/javascripts/textile-editor-config.js" type="text/javascript"></script>');