textile_editor_helper 0.0.12

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 (46) hide show
  1. data/.gitignore +20 -0
  2. data/Gemfile +5 -0
  3. data/README.md +130 -0
  4. data/Rakefile +7 -0
  5. data/features/copy_assets.feature +17 -0
  6. data/features/step_definitions/common_steps.rb +66 -0
  7. data/features/step_definitions/rails_setup_steps.rb +9 -0
  8. data/features/support/env.rb +0 -0
  9. data/features/support/setup.rb +0 -0
  10. data/lib/generators/textile_editor_helper/install_generator.rb +54 -0
  11. data/lib/textile_editor_helper.rb +204 -0
  12. data/lib/textile_editor_helper/version.rb +3 -0
  13. data/test/abstract_unit.rb +16 -0
  14. data/test/textile_editor_helper_test.rb +195 -0
  15. data/textile_editor_helper.gemspec +27 -0
  16. data/travis.yml +5 -0
  17. data/vendor/README +95 -0
  18. data/vendor/app/controllers/textile_preview_controller.rb +14 -0
  19. data/vendor/app/helpers/textile_preview_helper.rb +14 -0
  20. data/vendor/app/views/textile_preview/show.js.coffee +2 -0
  21. data/vendor/assets/images/textile-editor/background.png +0 -0
  22. data/vendor/assets/images/textile-editor/blockquote.png +0 -0
  23. data/vendor/assets/images/textile-editor/bold.png +0 -0
  24. data/vendor/assets/images/textile-editor/center.png +0 -0
  25. data/vendor/assets/images/textile-editor/h1.png +0 -0
  26. data/vendor/assets/images/textile-editor/h2.png +0 -0
  27. data/vendor/assets/images/textile-editor/h3.png +0 -0
  28. data/vendor/assets/images/textile-editor/h4.png +0 -0
  29. data/vendor/assets/images/textile-editor/h5.png +0 -0
  30. data/vendor/assets/images/textile-editor/h6.png +0 -0
  31. data/vendor/assets/images/textile-editor/indent.png +0 -0
  32. data/vendor/assets/images/textile-editor/italic.png +0 -0
  33. data/vendor/assets/images/textile-editor/justify.png +0 -0
  34. data/vendor/assets/images/textile-editor/left.png +0 -0
  35. data/vendor/assets/images/textile-editor/list_bullets.png +0 -0
  36. data/vendor/assets/images/textile-editor/list_numbers.png +0 -0
  37. data/vendor/assets/images/textile-editor/omega.png +0 -0
  38. data/vendor/assets/images/textile-editor/outdent.png +0 -0
  39. data/vendor/assets/images/textile-editor/paragraph.png +0 -0
  40. data/vendor/assets/images/textile-editor/right.png +0 -0
  41. data/vendor/assets/images/textile-editor/strikethrough.png +0 -0
  42. data/vendor/assets/images/textile-editor/underline.png +0 -0
  43. data/vendor/assets/javascripts/textile-editor-config.js +22 -0
  44. data/vendor/assets/javascripts/textile-editor.js +687 -0
  45. data/vendor/assets/stylesheets/textile-editor.css +53 -0
  46. metadata +186 -0
@@ -0,0 +1,687 @@
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
+
67
+ this.canvas = document.getElementById(canvas);
68
+ this.canvas.parentNode.insertBefore(toolbar, this.canvas);
69
+ this.openTags = new Array();
70
+
71
+
72
+ // Create the local Button array by assigning theButtons array to edButtons
73
+ var edButtons = new Array();
74
+ edButtons = this.buttons;
75
+
76
+ var standardButtons = new Array();
77
+ for(var i = 0; i < edButtons.length; i++) {
78
+ var thisButton = this.prepareButton(edButtons[i]);
79
+ if (view == 's') {
80
+ if (edButtons[i].sve == 's') {
81
+ toolbar.appendChild(thisButton);
82
+ standardButtons.push(thisButton);
83
+ }
84
+ } else {
85
+ if (typeof thisButton == 'string') {
86
+ toolbar.innerHTML += thisButton;
87
+ } else {
88
+ toolbar.appendChild(thisButton);
89
+ standardButtons.push(thisButton);
90
+ }
91
+ }
92
+ } // end for
93
+
94
+ var te = this;
95
+ var buttons = toolbar.getElementsByTagName('button');
96
+ for(var i = 0; i < buttons.length; i++) {
97
+ //$A(toolbar.getElementsByTagName('button')).each(function(button) {
98
+ if (!buttons[i].onclick) {
99
+ buttons[i].onclick = function() { te.insertTag(this); return false; }
100
+ } // end if
101
+
102
+ buttons[i].tagStart = buttons[i].getAttribute('tagStart');
103
+ buttons[i].tagEnd = buttons[i].getAttribute('tagEnd');
104
+ buttons[i].open = buttons[i].getAttribute('open');
105
+ buttons[i].textile_editor = te;
106
+ buttons[i].canvas = te.canvas;
107
+ // console.log(buttons[i].canvas);
108
+ //});
109
+ }
110
+ }, // end initialize
111
+
112
+ // draw individual buttons (edShowButton)
113
+ prepareButton: function(button) {
114
+ if (button.separator) {
115
+ var theButton = document.createElement('span');
116
+ theButton.className = 'ed_sep';
117
+ return theButton;
118
+ }
119
+
120
+ if (button.standard) {
121
+ var theButton = document.createElement("button");
122
+ theButton.id = button.id;
123
+ theButton.setAttribute('class', 'standard');
124
+ theButton.setAttribute('tagStart', button.tagStart);
125
+ theButton.setAttribute('tagEnd', button.tagEnd);
126
+ theButton.setAttribute('open', button.open);
127
+
128
+ var img = document.createElement('img');
129
+ img.src = '/images/textile-editor/' + button.display;
130
+ theButton.appendChild(img);
131
+ } else {
132
+ return button;
133
+ } // end if !custom
134
+
135
+ theButton.accessKey = button.access;
136
+ theButton.title = button.title;
137
+ return theButton;
138
+ }, // end prepareButton
139
+
140
+ // if clicked, no selected text, tag not open highlight button
141
+ // (edAddTag)
142
+ addTag: function(button) {
143
+ if (button.tagEnd != '') {
144
+ this.openTags[this.openTags.length] = button;
145
+ //var el = document.getElementById(button.id);
146
+ //el.className = 'selected';
147
+ button.className = 'selected';
148
+ }
149
+ }, // end addTag
150
+
151
+ // if clicked, no selected text, tag open lowlight button
152
+ // (edRemoveTag)
153
+ removeTag: function(button) {
154
+ for (i = 0; i < this.openTags.length; i++) {
155
+ if (this.openTags[i] == button) {
156
+ this.openTags.splice(button, 1);
157
+ //var el = document.getElementById(button.id);
158
+ //el.className = 'unselected';
159
+ button.className = 'unselected';
160
+ }
161
+ }
162
+ }, // end removeTag
163
+
164
+ // see if there are open tags. for the remove tag bit...
165
+ // (edCheckOpenTags)
166
+ checkOpenTags: function(button) {
167
+ var tag = 0;
168
+ for (i = 0; i < this.openTags.length; i++) {
169
+ if (this.openTags[i] == button) {
170
+ tag++;
171
+ }
172
+ }
173
+ if (tag > 0) {
174
+ return true; // tag found
175
+ }
176
+ else {
177
+ return false; // tag not found
178
+ }
179
+ }, // end checkOpenTags
180
+
181
+ // insert the tag. this is the bulk of the code.
182
+ // (edInsertTag)
183
+ insertTag: function(button, tagStart, tagEnd) {
184
+ // console.log(button);
185
+ var myField = button.canvas;
186
+ myField.focus();
187
+
188
+ if (tagStart) {
189
+ button.tagStart = tagStart;
190
+ button.tagEnd = tagEnd ? tagEnd : '\n';
191
+ }
192
+
193
+ var textSelected = false;
194
+ var finalText = '';
195
+ var FF = false;
196
+
197
+ // grab the text that's going to be manipulated, by browser
198
+ if (document.selection) { // IE support
199
+ sel = document.selection.createRange();
200
+
201
+ // set-up the text vars
202
+ var beginningText = '';
203
+ var followupText = '';
204
+ var selectedText = sel.text;
205
+
206
+ // check if text has been selected
207
+ if (sel.text.length > 0) {
208
+ textSelected = true;
209
+ }
210
+
211
+ // set-up newline regex's so we can swap tags across multiple paragraphs
212
+ var newlineReplaceRegexClean = /\r\n\s\n/g;
213
+ var newlineReplaceRegexDirty = '\\r\\n\\s\\n';
214
+ var newlineReplaceClean = '\r\n\n';
215
+ }
216
+ else if (myField.selectionStart || myField.selectionStart == '0') { // MOZ/FF/NS/S support
217
+
218
+ // figure out cursor and selection positions
219
+ var startPos = myField.selectionStart;
220
+ var endPos = myField.selectionEnd;
221
+ var cursorPos = endPos;
222
+ var scrollTop = myField.scrollTop;
223
+ FF = true; // note that is is a FF/MOZ/NS/S browser
224
+
225
+ // set-up the text vars
226
+ var beginningText = myField.value.substring(0, startPos);
227
+ var followupText = myField.value.substring(endPos, myField.value.length);
228
+
229
+ // check if text has been selected
230
+ if (startPos != endPos) {
231
+ textSelected = true;
232
+ var selectedText = myField.value.substring(startPos, endPos);
233
+ }
234
+
235
+ // set-up newline regex's so we can swap tags across multiple paragraphs
236
+ var newlineReplaceRegexClean = /\n\n/g;
237
+ var newlineReplaceRegexDirty = '\\n\\n';
238
+ var newlineReplaceClean = '\n\n';
239
+ }
240
+
241
+
242
+ // if there is text that has been highlighted...
243
+ if (textSelected) {
244
+
245
+ // set-up some defaults for how to handle bad new line characters
246
+ var newlineStart = '';
247
+ var newlineStartPos = 0;
248
+ var newlineEnd = '';
249
+ var newlineEndPos = 0;
250
+ var newlineFollowup = '';
251
+
252
+ // set-up some defaults for how to handle placing the beginning and end of selection
253
+ var posDiffPos = 0;
254
+ var posDiffNeg = 0;
255
+ var mplier = 1;
256
+
257
+ // remove newline from the beginning of the selectedText.
258
+ if (selectedText.match(/^\n/)) {
259
+ selectedText = selectedText.replace(/^\n/,'');
260
+ newlineStart = '\n';
261
+ newlineStartpos = 1;
262
+ }
263
+
264
+ // remove newline from the end of the selectedText.
265
+ if (selectedText.match(/\n$/g)) {
266
+ selectedText = selectedText.replace(/\n$/g,'');
267
+ newlineEnd = '\n';
268
+ newlineEndPos = 1;
269
+ }
270
+
271
+ // remove space from the end of the selectedText.
272
+ // Fixes a bug that causes any browser running under Microsoft Internet Explorer
273
+ // to append an additional space before the closing element.
274
+ // *Bold text *here => *Bold text*
275
+ if (selectedText.match(/\s$/g)) {
276
+ selectedText = selectedText.replace(/\s$/g,'');
277
+ followupText = ' ';
278
+ }
279
+
280
+ // no clue, i'm sure it made sense at the time i wrote it
281
+ if (followupText.match(/^\n/)) {
282
+ newlineFollowup = '';
283
+ }
284
+ else {
285
+ newlineFollowup = '\n\n';
286
+ }
287
+
288
+ // first off let's check if the user is trying to mess with lists
289
+ if ((button.tagStart == ' * ') || (button.tagStart == ' # ')) {
290
+
291
+ listItems = 0; // sets up a default to be able to properly manipulate final selection
292
+
293
+ // set-up all of the regex's
294
+ re_start = new RegExp('^ (\\*|\\#) ','g');
295
+ if (button.tagStart == ' # ') {
296
+ 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
297
+ }
298
+ else {
299
+ re_tag = new RegExp(' \\* ','g');
300
+ }
301
+ re_replace = new RegExp(' (\\*|\\#) ','g');
302
+
303
+ // try to remove bullets in text copied from ms word **Mac Only!**
304
+ re_word_bullet_m_s = new RegExp('• ','g'); // mac/safari
305
+ re_word_bullet_m_f = new RegExp('∑ ','g'); // mac/firefox
306
+ selectedText = selectedText.replace(re_word_bullet_m_s,'').replace(re_word_bullet_m_f,'');
307
+
308
+ // if the selected text starts with one of the tags we're working with...
309
+ if (selectedText.match(re_start)) {
310
+
311
+ // if tag that begins the selection matches the one clicked, remove them all
312
+ if (selectedText.match(re_tag)) {
313
+ finalText = beginningText
314
+ + newlineStart
315
+ + selectedText.replace(re_replace,'')
316
+ + newlineEnd
317
+ + followupText;
318
+ if (matches = selectedText.match(/ (\*|\#) /g)) {
319
+ listItems = matches.length;
320
+ }
321
+ posDiffNeg = listItems*3; // how many list items were there because that's 3 spaces to remove from final selection
322
+ }
323
+
324
+ // else replace the current tag type with the selected tag type
325
+ else {
326
+ finalText = beginningText
327
+ + newlineStart
328
+ + selectedText.replace(re_replace,button.tagStart)
329
+ + newlineEnd
330
+ + followupText;
331
+ }
332
+ }
333
+
334
+ // else try to create the list type
335
+ // NOTE: the items in a list will only be replaced if a newline starts with some character, not a space
336
+ else {
337
+ finalText = beginningText
338
+ + newlineStart
339
+ + button.tagStart
340
+ + selectedText.replace(newlineReplaceRegexClean,newlineReplaceClean + button.tagStart).replace(/\n(\S)/g,'\n' + button.tagStart + '$1')
341
+ + newlineEnd
342
+ + followupText;
343
+ if (matches = selectedText.match(/\n(\S)/g)) {
344
+ listItems = matches.length;
345
+ }
346
+ posDiffPos = 3 + listItems*3;
347
+ }
348
+ }
349
+
350
+ // now lets look and see if the user is trying to muck with a block or block modifier
351
+ else if (button.tagStart.match(/^(h1|h2|h3|h4|h5|h6|bq|p|\>|\<\>|\<|\=|\(|\))/g)) {
352
+
353
+ var insertTag = '';
354
+ var insertModifier = '';
355
+ var tagPartBlock = '';
356
+ var tagPartModifier = '';
357
+ var tagPartModifierOrig = ''; // ugly hack but it's late
358
+ var drawSwitch = '';
359
+ var captureIndentStart = false;
360
+ var captureListStart = false;
361
+ var periodAddition = '\\. ';
362
+ var periodAdditionClean = '. ';
363
+ var listItemsAddition = 0;
364
+
365
+ var re_list_items = new RegExp('(\\*+|\\#+)','g'); // need this regex later on when checking indentation of lists
366
+
367
+ var re_block_modifier = new RegExp('^(h1|h2|h3|h4|h5|h6|bq|p| [\\*]{1,} | [\\#]{1,} |)(\\>|\\<\\>|\\<|\\=|[\\(]{1,}|[\\)]{1,6}|)','g');
368
+ if (tagPartMatches = re_block_modifier.exec(selectedText)) {
369
+ tagPartBlock = tagPartMatches[1];
370
+ tagPartModifier = tagPartMatches[2];
371
+ tagPartModifierOrig = tagPartMatches[2];
372
+ tagPartModifierOrig = tagPartModifierOrig.replace(/\(/g,"\\(");
373
+ }
374
+
375
+ // if tag already up is the same as the tag provided replace the whole tag
376
+ if (tagPartBlock == button.tagStart) {
377
+ insertTag = tagPartBlock + tagPartModifierOrig; // use Orig because it's escaped for regex
378
+ drawSwitch = 0;
379
+ }
380
+ // else if let's check to add/remove block modifier
381
+ else if ((tagPartModifier == button.tagStart) || (newm = tagPartModifier.match(/[\(]{2,}/g))) {
382
+ if ((button.tagStart == '(') || (button.tagStart == ')')) {
383
+ var indentLength = tagPartModifier.length;
384
+ if (button.tagStart == '(') {
385
+ indentLength = indentLength + 1;
386
+ }
387
+ else {
388
+ indentLength = indentLength - 1;
389
+ }
390
+ for (var i = 0; i < indentLength; i++) {
391
+ insertModifier = insertModifier + '(';
392
+ }
393
+ insertTag = tagPartBlock + insertModifier;
394
+ }
395
+ else {
396
+ if (button.tagStart == tagPartModifier) {
397
+ insertTag = tagPartBlock;
398
+ } // going to rely on the default empty insertModifier
399
+ else {
400
+
401
+ if (button.tagStart.match(/(\>|\<\>|\<|\=)/g)) {
402
+ insertTag = tagPartBlock + button.tagStart;
403
+ }
404
+ else {
405
+ insertTag = button.tagStart + tagPartModifier;
406
+ }
407
+ }
408
+
409
+ }
410
+ drawSwitch = 1;
411
+ }
412
+ // indentation of list items
413
+ else if (listPartMatches = re_list_items.exec(tagPartBlock)) {
414
+ var listTypeMatch = listPartMatches[1];
415
+ var indentLength = tagPartBlock.length - 2;
416
+ var listInsert = '';
417
+ if (button.tagStart == '(') {
418
+ indentLength = indentLength + 1;
419
+ }
420
+ else {
421
+ indentLength = indentLength - 1;
422
+ }
423
+ if (listTypeMatch.match(/[\*]{1,}/g)) {
424
+ var listType = '*';
425
+ var listReplace = '\\*';
426
+ }
427
+ else {
428
+ var listType = '#';
429
+ var listReplace = '\\#';
430
+ }
431
+ for (var i = 0; i < indentLength; i++) {
432
+ listInsert = listInsert + listType;
433
+ }
434
+ if (listInsert != '') {
435
+ insertTag = ' ' + listInsert + ' ';
436
+ }
437
+ else {
438
+ insertTag = '';
439
+ }
440
+ tagPartBlock = tagPartBlock.replace(/(\*|\#)/g,listReplace);
441
+ drawSwitch = 1;
442
+ captureListStart = true;
443
+ periodAddition = '';
444
+ periodAdditionClean = '';
445
+ if (matches = selectedText.match(/\n\s/g)) {
446
+ listItemsAddition = matches.length;
447
+ }
448
+ }
449
+ // must be a block modification e.g. p>. to p<.
450
+ else {
451
+
452
+ // if this is a block modification/addition
453
+ if (button.tagStart.match(/(h1|h2|h3|h4|h5|h6|bq|p)/g)) {
454
+ if (tagPartBlock == '') {
455
+ drawSwitch = 2;
456
+ }
457
+ else {
458
+ drawSwitch = 1;
459
+ }
460
+
461
+ insertTag = button.tagStart + tagPartModifier;
462
+ }
463
+
464
+ // else this is a modifier modification/addition
465
+ else {
466
+ if ((tagPartModifier == '') && (tagPartBlock != '')) {
467
+ drawSwitch = 1;
468
+ }
469
+ else if (tagPartModifier == '') {
470
+ drawSwitch = 2;
471
+ }
472
+ else {
473
+ drawSwitch = 1;
474
+ }
475
+
476
+ // if no tag part block but a modifier we need at least the p tag
477
+ if (tagPartBlock == '') {
478
+ tagPartBlock = 'p';
479
+ }
480
+
481
+ //make sure to swap out outdent
482
+ if (button.tagStart == ')') {
483
+ tagPartModifier = '';
484
+ }
485
+ else {
486
+ tagPartModifier = button.tagStart;
487
+ captureIndentStart = true; // ugly hack to fix issue with proper selection handling
488
+ }
489
+
490
+ insertTag = tagPartBlock + tagPartModifier;
491
+ }
492
+ }
493
+
494
+ mplier = 0;
495
+ if (captureListStart || (tagPartModifier.match(/[\(\)]{1,}/g))) {
496
+ re_start = new RegExp(insertTag.escape + periodAddition,'g'); // for tags that mimic regex properties, parens + list tags
497
+ }
498
+ else {
499
+ re_start = new RegExp(insertTag + periodAddition,'g'); // for tags that don't, why i can't just escape everything i have no clue
500
+ }
501
+ re_old = new RegExp(tagPartBlock + tagPartModifierOrig + periodAddition,'g');
502
+ re_middle = new RegExp(newlineReplaceRegexDirty + insertTag.escape + periodAddition.escape,'g');
503
+ re_tag = new RegExp(insertTag.escape + periodAddition.escape,'g');
504
+
505
+ // *************************************************************************************************************************
506
+ // this is where everything gets swapped around or inserted, bullets and single options have their own if/else statements
507
+ // *************************************************************************************************************************
508
+ if ((drawSwitch == 0) || (drawSwitch == 1)) {
509
+ if (drawSwitch == 0) { // completely removing a tag
510
+ finalText = beginningText
511
+ + newlineStart
512
+ + selectedText.replace(re_start,'').replace(re_middle,newlineReplaceClean)
513
+ + newlineEnd
514
+ + followupText;
515
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
516
+ mplier = mplier + matches.length;
517
+ }
518
+ posDiffNeg = insertTag.length + 2 + (mplier*4);
519
+ }
520
+ else { // modifying a tag, though we do delete bullets here
521
+ finalText = beginningText
522
+ + newlineStart
523
+ + selectedText.replace(re_old,insertTag + periodAdditionClean)
524
+ + newlineEnd
525
+ + followupText;
526
+
527
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
528
+ mplier = mplier + matches.length;
529
+ }
530
+ // figure out the length of various elements to modify the selection position
531
+ if (captureIndentStart) { // need to double-check that this wasn't the first indent
532
+ tagPreviousLength = tagPartBlock.length;
533
+ tagCurrentLength = insertTag.length;
534
+ }
535
+ else if (captureListStart) { // if this is a list we're manipulating
536
+ if (button.tagStart == '(') { // if indenting
537
+ tagPreviousLength = listTypeMatch.length + 2;
538
+ tagCurrentLength = insertTag.length + listItemsAddition;
539
+ }
540
+ else if (insertTag.match(/(\*|\#)/g)) { // if removing but still has bullets
541
+ tagPreviousLength = insertTag.length + listItemsAddition;
542
+ tagCurrentLength = listTypeMatch.length;
543
+ }
544
+ else { // if removing last bullet
545
+ tagPreviousLength = insertTag.length + listItemsAddition;
546
+ tagCurrentLength = listTypeMatch.length - (3*listItemsAddition) - 1;
547
+ }
548
+ }
549
+ else { // everything else
550
+ tagPreviousLength = tagPartBlock.length + tagPartModifier.length;
551
+ tagCurrentLength = insertTag.length;
552
+ }
553
+ if (tagCurrentLength > tagPreviousLength) {
554
+ posDiffPos = (tagCurrentLength - tagPreviousLength) + (mplier*(tagCurrentLength - tagPreviousLength));
555
+ }
556
+ else {
557
+ posDiffNeg = (tagPreviousLength - tagCurrentLength) + (mplier*(tagPreviousLength - tagCurrentLength));
558
+ }
559
+ }
560
+ }
561
+ else { // for adding tags other then bullets (have their own statement)
562
+ finalText = beginningText
563
+ + newlineStart
564
+ + insertTag + '. '
565
+ + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + '\n' + insertTag + '. ')
566
+ + newlineFollowup
567
+ + newlineEnd
568
+ + followupText;
569
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
570
+ mplier = mplier + matches.length;
571
+ }
572
+ posDiffPos = insertTag.length + 2 + (mplier*4);
573
+ }
574
+ }
575
+
576
+ // swap in and out the simple tags around a selection like bold
577
+ else {
578
+
579
+ mplier = 1; // the multiplier for the tag length
580
+ re_start = new RegExp('^\\' + button.tagStart,'g');
581
+ re_end = new RegExp('\\' + button.tagEnd + '$','g');
582
+ re_middle = new RegExp('\\' + button.tagEnd + newlineReplaceRegexDirty + '\\' + button.tagStart,'g');
583
+ if (selectedText.match(re_start) && selectedText.match(re_end)) {
584
+ finalText = beginningText
585
+ + newlineStart
586
+ + selectedText.replace(re_start,'').replace(re_end,'').replace(re_middle,newlineReplaceClean)
587
+ + newlineEnd
588
+ + followupText;
589
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
590
+ mplier = mplier + matches.length;
591
+ }
592
+ posDiffNeg = button.tagStart.length*mplier + button.tagEnd.length*mplier;
593
+ }
594
+ else {
595
+ finalText = beginningText
596
+ + newlineStart
597
+ + button.tagStart
598
+ + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + newlineReplaceClean + button.tagStart)
599
+ + button.tagEnd
600
+ + newlineEnd
601
+ + followupText;
602
+ if (matches = selectedText.match(newlineReplaceRegexClean)) {
603
+ mplier = mplier + matches.length;
604
+ }
605
+ posDiffPos = (button.tagStart.length*mplier) + (button.tagEnd.length*mplier);
606
+ }
607
+ }
608
+
609
+ cursorPos += button.tagStart.length + button.tagEnd.length;
610
+
611
+ }
612
+
613
+ // just swap in and out single values, e.g. someone clicks b they'll get a *
614
+ else {
615
+ var buttonStart = '';
616
+ var buttonEnd = '';
617
+ var re_p = new RegExp('(\\<|\\>|\\=|\\<\\>|\\(|\\))','g');
618
+ var re_h = new RegExp('^(h1|h2|h3|h4|h5|h6|p|bq)','g');
619
+ if (!this.checkOpenTags(button) || button.tagEnd == '') { // opening tag
620
+
621
+ if (button.tagStart.match(re_h)) {
622
+ buttonStart = button.tagStart + '. ';
623
+ }
624
+ else {
625
+ buttonStart = button.tagStart;
626
+ }
627
+ if (button.tagStart.match(re_p)) { // make sure that invoking block modifiers don't do anything
628
+ finalText = beginningText
629
+ + followupText;
630
+ cursorPos = startPos;
631
+ }
632
+ else {
633
+ finalText = beginningText
634
+ + buttonStart
635
+ + followupText;
636
+ this.addTag(button);
637
+ cursorPos = startPos + buttonStart.length;
638
+ }
639
+
640
+ }
641
+ else { // closing tag
642
+ if (button.tagStart.match(re_p)) {
643
+ buttonEnd = '\n\n';
644
+ }
645
+ else if (button.tagStart.match(re_h)) {
646
+ buttonEnd = '\n\n';
647
+ }
648
+ else {
649
+ buttonEnd = button.tagEnd
650
+ }
651
+ finalText = beginningText
652
+ + button.tagEnd
653
+ + followupText;
654
+ this.removeTag(button);
655
+ cursorPos = startPos + button.tagEnd.length;
656
+ }
657
+ }
658
+
659
+ // set the appropriate DOM value with the final text
660
+ if (FF == true) {
661
+ myField.value = finalText;
662
+ myField.scrollTop = scrollTop;
663
+ }
664
+ else {
665
+ sel.text = finalText;
666
+ }
667
+
668
+ // build up the selection capture, doesn't work in IE
669
+ if (textSelected) {
670
+ myField.selectionStart = startPos + newlineStartPos;
671
+ myField.selectionEnd = endPos + posDiffPos - posDiffNeg - newlineEndPos;
672
+ //alert('s: ' + myField.selectionStart + ' e: ' + myField.selectionEnd + ' sp: ' + startPos + ' ep: ' + endPos + ' pdp: ' + posDiffPos + ' pdn: ' + posDiffNeg)
673
+ }
674
+ else {
675
+ myField.selectionStart = cursorPos;
676
+ myField.selectionEnd = cursorPos;
677
+ }
678
+ } // end insertTag
679
+ }; // end class
680
+
681
+ // add class methods
682
+ // Object.extend(TextileEditor, TextileEditor.Methods);
683
+ destination = TextileEditor
684
+ source = TextileEditor.Methods
685
+ for(var property in source) destination[property] = source[property];
686
+
687
+ document.write('<script src="/assets/textile-editor-config.js" type="text/javascript"></script>');