rtextile 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. data/.project +26 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +44 -0
  5. data/Rakefile +8 -0
  6. data/lib/rails/generators/rtextile/USAGE +18 -0
  7. data/lib/rails/generators/rtextile/rtextile_generator.rb +80 -0
  8. data/lib/rails/generators/rtextile/templates/_form.html.erb +12 -0
  9. data/lib/rails/generators/rtextile/templates/_show.html.erb +3 -0
  10. data/lib/rails/generators/rtextile/templates/controller.rb +64 -0
  11. data/lib/rails/generators/rtextile/templates/edit.html.erb +10 -0
  12. data/lib/rails/generators/rtextile/templates/index.html.erb +8 -0
  13. data/lib/rails/generators/rtextile/templates/migration.rb +9 -0
  14. data/lib/rails/generators/rtextile/templates/model.rb +4 -0
  15. data/lib/rails/generators/rtextile/templates/new.html.erb +3 -0
  16. data/lib/rails/generators/rtextile/templates/schema.rb +14 -0
  17. data/lib/rails/generators/rtextile/templates/show.html.erb +8 -0
  18. data/lib/rails/generators/textile_editor_helper/USAGE +23 -0
  19. data/lib/rails/generators/textile_editor_helper/templates/background.png +0 -0
  20. data/lib/rails/generators/textile_editor_helper/templates/blockquote.png +0 -0
  21. data/lib/rails/generators/textile_editor_helper/templates/bold.png +0 -0
  22. data/lib/rails/generators/textile_editor_helper/templates/center.png +0 -0
  23. data/lib/rails/generators/textile_editor_helper/templates/h1.png +0 -0
  24. data/lib/rails/generators/textile_editor_helper/templates/h2.png +0 -0
  25. data/lib/rails/generators/textile_editor_helper/templates/h3.png +0 -0
  26. data/lib/rails/generators/textile_editor_helper/templates/h4.png +0 -0
  27. data/lib/rails/generators/textile_editor_helper/templates/h5.png +0 -0
  28. data/lib/rails/generators/textile_editor_helper/templates/h6.png +0 -0
  29. data/lib/rails/generators/textile_editor_helper/templates/indent.png +0 -0
  30. data/lib/rails/generators/textile_editor_helper/templates/italic.png +0 -0
  31. data/lib/rails/generators/textile_editor_helper/templates/justify.png +0 -0
  32. data/lib/rails/generators/textile_editor_helper/templates/left.png +0 -0
  33. data/lib/rails/generators/textile_editor_helper/templates/list_bullets.png +0 -0
  34. data/lib/rails/generators/textile_editor_helper/templates/list_numbers.png +0 -0
  35. data/lib/rails/generators/textile_editor_helper/templates/omega.png +0 -0
  36. data/lib/rails/generators/textile_editor_helper/templates/outdent.png +0 -0
  37. data/lib/rails/generators/textile_editor_helper/templates/paragraph.png +0 -0
  38. data/lib/rails/generators/textile_editor_helper/templates/right.png +0 -0
  39. data/lib/rails/generators/textile_editor_helper/templates/strikethrough.png +0 -0
  40. data/lib/rails/generators/textile_editor_helper/templates/textile-editor-config.js +22 -0
  41. data/lib/rails/generators/textile_editor_helper/templates/textile-editor.css +53 -0
  42. data/lib/rails/generators/textile_editor_helper/templates/textile-editor.js +676 -0
  43. data/lib/rails/generators/textile_editor_helper/templates/underline.png +0 -0
  44. data/lib/rails/generators/textile_editor_helper/textile_editor_helper_generator.rb +39 -0
  45. data/lib/rtextile/version.rb +3 -0
  46. data/lib/rtextile.rb +3 -0
  47. data/lib/textile_editor_helper.rb +185 -0
  48. data/rtextile.gemspec +22 -0
  49. metadata +126 -0
@@ -0,0 +1,676 @@
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
+ // this.framework = 'prototype'; // the JS framework used
49
+ }
50
+
51
+ function TextileEditorButtonSeparator(sve) {
52
+ this.separator = true;
53
+ this.sve = sve;
54
+ }
55
+
56
+ var TextileEditor = function() {};
57
+ TextileEditor.buttons = new Array();
58
+ TextileEditor.Methods = {
59
+ // class methods
60
+
61
+ // create the toolbar (edToolbar)
62
+ initialize: function(canvas, view) {
63
+ var toolbar = document.createElement("div");
64
+ toolbar.id = "textile-toolbar-" + canvas;
65
+ toolbar.className = 'textile-toolbar';
66
+ this.canvas = document.getElementById(canvas);
67
+ this.canvas.parentNode.insertBefore(toolbar, this.canvas);
68
+ this.openTags = new Array();
69
+
70
+ // Create the local Button array by assigning theButtons array to edButtons
71
+ var edButtons = new Array();
72
+ edButtons = this.buttons;
73
+
74
+ var standardButtons = new Array();
75
+ for(var i = 0; i < edButtons.length; i++) {
76
+ var thisButton = this.prepareButton(edButtons[i]);
77
+ if (view == 's') {
78
+ if (edButtons[i].sve == 's') {
79
+ toolbar.appendChild(thisButton);
80
+ standardButtons.push(thisButton);
81
+ }
82
+ } else {
83
+ if (typeof thisButton == 'string') {
84
+ toolbar.innerHTML += thisButton;
85
+ } else {
86
+ toolbar.appendChild(thisButton);
87
+ standardButtons.push(thisButton);
88
+ }
89
+ }
90
+ } // end for
91
+
92
+ var te = this;
93
+ var buttons = toolbar.getElementsByTagName('button');
94
+ for(var i = 0; i < buttons.length; i++) {
95
+ //$A(toolbar.getElementsByTagName('button')).each(function(button) {
96
+ if (!buttons[i].onclick) {
97
+ buttons[i].onclick = function() { te.insertTag(this); return false; }
98
+ } // end if
99
+
100
+ buttons[i].tagStart = buttons[i].getAttribute('tagStart');
101
+ buttons[i].tagEnd = buttons[i].getAttribute('tagEnd');
102
+ buttons[i].open = buttons[i].getAttribute('open');
103
+ buttons[i].textile_editor = te;
104
+ buttons[i].canvas = te.canvas;
105
+ // console.log(buttons[i].canvas);
106
+ //});
107
+ }
108
+ }, // end initialize
109
+
110
+ // draw individual buttons (edShowButton)
111
+ prepareButton: function(button) {
112
+ if (button.separator) {
113
+ var theButton = document.createElement('span');
114
+ theButton.className = 'ed_sep';
115
+ return theButton;
116
+ }
117
+
118
+ if (button.standard) {
119
+ var theButton = document.createElement("button");
120
+ theButton.id = button.id;
121
+ theButton.setAttribute('class', 'standard');
122
+ theButton.setAttribute('tagStart', button.tagStart);
123
+ theButton.setAttribute('tagEnd', button.tagEnd);
124
+ theButton.setAttribute('open', button.open);
125
+
126
+ var img = document.createElement('img');
127
+ img.src = '/images/textile-editor/' + button.display;
128
+ theButton.appendChild(img);
129
+ } else {
130
+ return button;
131
+ } // end if !custom
132
+
133
+ theButton.accessKey = button.access;
134
+ theButton.title = button.title;
135
+ return theButton;
136
+ }, // end prepareButton
137
+
138
+ // if clicked, no selected text, tag not open highlight button
139
+ // (edAddTag)
140
+ addTag: function(button) {
141
+ if (button.tagEnd != '') {
142
+ this.openTags[this.openTags.length] = button;
143
+ //var el = document.getElementById(button.id);
144
+ //el.className = 'selected';
145
+ button.className = 'selected';
146
+ }
147
+ }, // end addTag
148
+
149
+ // if clicked, no selected text, tag open lowlight button
150
+ // (edRemoveTag)
151
+ removeTag: function(button) {
152
+ for (i = 0; i < this.openTags.length; i++) {
153
+ if (this.openTags[i] == button) {
154
+ this.openTags.splice(button, 1);
155
+ //var el = document.getElementById(button.id);
156
+ //el.className = 'unselected';
157
+ button.className = 'unselected';
158
+ }
159
+ }
160
+ }, // end removeTag
161
+
162
+ // see if there are open tags. for the remove tag bit...
163
+ // (edCheckOpenTags)
164
+ checkOpenTags: function(button) {
165
+ var tag = 0;
166
+ for (i = 0; i < this.openTags.length; i++) {
167
+ if (this.openTags[i] == button) {
168
+ tag++;
169
+ }
170
+ }
171
+ if (tag > 0) {
172
+ return true; // tag found
173
+ }
174
+ else {
175
+ return false; // tag not found
176
+ }
177
+ }, // end checkOpenTags
178
+
179
+ // insert the tag. this is the bulk of the code.
180
+ // (edInsertTag)
181
+ insertTag: function(button, tagStart, tagEnd) {
182
+ //console.log(button);
183
+ var myField = button.canvas;
184
+ myField.focus();
185
+
186
+ if (tagStart) {
187
+ button.tagStart = tagStart;
188
+ button.tagEnd = tagEnd ? tagEnd : '\n';
189
+ }
190
+
191
+ var textSelected = false;
192
+ var finalText = '';
193
+ var FF = false;
194
+
195
+ // grab the text that's going to be manipulated, by browser
196
+ if (document.selection) { // IE support
197
+ sel = document.selection.createRange();
198
+
199
+ // set-up the text vars
200
+ var beginningText = '';
201
+ var followupText = '';
202
+ var selectedText = sel.text;
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*3; // 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 = 3 + listItems*3;
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
+ }; // end class
669
+
670
+ // add class methods
671
+ // Object.extend(TextileEditor, TextileEditor.Methods);
672
+ destination = TextileEditor
673
+ source = TextileEditor.Methods
674
+ for(var property in source) destination[property] = source[property];
675
+
676
+ document.write('<script src="/javascripts/textile-editor-config.js" type="text/javascript"></script>');