redcloth-rails 0.1.0

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 (41) hide show
  1. data/Gemfile +8 -0
  2. data/LICENSE +21 -0
  3. data/README.textile +58 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/images/textile-editor/background.png +0 -0
  6. data/app/assets/images/textile-editor/blockquote.png +0 -0
  7. data/app/assets/images/textile-editor/bold.png +0 -0
  8. data/app/assets/images/textile-editor/center.png +0 -0
  9. data/app/assets/images/textile-editor/h1.png +0 -0
  10. data/app/assets/images/textile-editor/h2.png +0 -0
  11. data/app/assets/images/textile-editor/h3.png +0 -0
  12. data/app/assets/images/textile-editor/h4.png +0 -0
  13. data/app/assets/images/textile-editor/h5.png +0 -0
  14. data/app/assets/images/textile-editor/h6.png +0 -0
  15. data/app/assets/images/textile-editor/indent.png +0 -0
  16. data/app/assets/images/textile-editor/italic.png +0 -0
  17. data/app/assets/images/textile-editor/justify.png +0 -0
  18. data/app/assets/images/textile-editor/left.png +0 -0
  19. data/app/assets/images/textile-editor/list_bullets.png +0 -0
  20. data/app/assets/images/textile-editor/list_numbers.png +0 -0
  21. data/app/assets/images/textile-editor/omega.png +0 -0
  22. data/app/assets/images/textile-editor/outdent.png +0 -0
  23. data/app/assets/images/textile-editor/paragraph.png +0 -0
  24. data/app/assets/images/textile-editor/right.png +0 -0
  25. data/app/assets/images/textile-editor/strikethrough.png +0 -0
  26. data/app/assets/images/textile-editor/underline.png +0 -0
  27. data/app/assets/javascripts/textile-editor-config.js.coffee.erb +23 -0
  28. data/app/assets/javascripts/textile-editor.js.coffee +521 -0
  29. data/app/assets/stylesheets/textile-editor.css.scss +44 -0
  30. data/lib/rails/generators/textile_editor_config/USAGE +11 -0
  31. data/lib/rails/generators/textile_editor_config/templates/textile-editor-config.js.coffee.erb +23 -0
  32. data/lib/rails/generators/textile_editor_config/textile_editor_config_generator.rb +9 -0
  33. data/lib/redcloth-rails/engine.rb +18 -0
  34. data/lib/redcloth-rails/helpers/form_builder.rb +14 -0
  35. data/lib/redcloth-rails/helpers/form_helper.rb +137 -0
  36. data/lib/redcloth-rails/helpers/form_tag_helper.rb +49 -0
  37. data/lib/redcloth-rails/helpers.rb +9 -0
  38. data/lib/redcloth-rails/version.rb +5 -0
  39. data/lib/redcloth-rails.rb +15 -0
  40. data/redcloth-rails.gemspec +20 -0
  41. metadata +138 -0
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'RedCloth', '>= 4.2.0'
4
+ gem 'rails', '>= 3.1.0'
5
+ gem 'rdoc'
6
+ gem 'bundler'
7
+
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2013 emjot GmbH & Co. KG
2
+ Copyright (c) 2011 Thor Johnson
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,58 @@
1
+ h2. redcloth-rails
2
+
3
+ bq. Homepage: "Github":https://github.com/emjot/redcloth-rails
4
+ Author: emjot GmbH & Co. KG
5
+
6
+ p. The redcloth-rails gem enables "RedCloth":http://redcloth.org for rails (>= 3.1).
7
+ It provides helpers to integrate the _TextileEditor_ toolbar and its assets are pipeline ready ...
8
+
9
+ h4. History
10
+
11
+ p. The _TextileEditor_ was created by Dave Olsen (Javascript) and Chris Scharf (Ruby/Rails) of "West Virginia University Web Services":http://webservices.wvu.edu .
12
+ The rails 3.0 support and gemification was realized by ryanfelton (https://github.com/ryanfelton/textile-editor-helper).
13
+
14
+ h4. Dependencies
15
+
16
+ * RedCloth (>= 4.2)
17
+ * Rails (>= 3.1)
18
+ * Rails Asset Pipeline
19
+ * JQuery
20
+
21
+ h4. Installation (via Bundler)
22
+
23
+ pre. Gemfile:
24
+ gem "redcloth-rails"
25
+
26
+ h4. Setup
27
+
28
+ Generate a config file
29
+
30
+ pre. rails g textile_editor_config
31
+
32
+ Include the coffees script and scss files in your asset pipeline
33
+
34
+ pre. app/assets/javascripts/application.js:
35
+ (...)
36
+ //= require textile-editor
37
+ //= require ./textile-editor-config
38
+
39
+ pre. app/assets/stylesheets/application.css:
40
+ (...)
41
+ *= require textile-editor
42
+
43
+ h4. Usage
44
+
45
+ Enable the _TextileEditor_ for your attributes via:
46
+
47
+ pre. <%= textile_editor :content %>
48
+
49
+ Initialize the _TextileEditor_ afterwards via:
50
+
51
+ pre. <%= textile_editor_initialize %>
52
+
53
+ h4. Links
54
+
55
+ p(. "redcloth.org":http://redcloth.org
56
+ "textile_editor_helper (original)":http://slatecms.wvu.edu/open_source
57
+ "textile_editor_helper (upadated for rails 3)":https://github.com/ryanfelton/textile-editor-helper
58
+ "more info on textile":http://www.textism.com/tools/textile/
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+ require 'RedCloth'
3
+
4
+ Rake::TestTask.new do |test|
5
+ test.pattern = 'test/**/*_test.rb'
6
+ test.libs << 'test'
7
+ end
8
+
@@ -0,0 +1,23 @@
1
+ TextileEditor.setButtons(
2
+ [
3
+ new TextileEditorButton("ed_strong", "<%= asset_path('textile-editor/bold.png') %>", "*", "*", "b", "Bold", "s"),
4
+ new TextileEditorButton("ed_emphasis", "<%= asset_path('textile-editor/italic.png') %>", "_", "_", "i", "Italicize", "s"),
5
+ new TextileEditorButton("ed_underline", "<%= asset_path('textile-editor/underline.png') %>", "+", "+", "u", "Underline", "s"),
6
+ new TextileEditorButton("ed_strike", "<%= asset_path('textile-editor/strikethrough.png') %>", "-", "-", "s", "Strikethrough", "s"),
7
+ new TextileEditorButton("ed_ol", "<%= asset_path('textile-editor/list_numbers.png') %>", " # ", "\n", ",", "Numbered List"),
8
+ new TextileEditorButton("ed_ul", "<%= asset_path('textile-editor/list_bullets.png') %>", " * ", "\n", ".", "Bulleted List"),
9
+ new TextileEditorButton("ed_p", "<%= asset_path('textile-editor/paragraph.png') %>", "p", "\n", "p", "Paragraph"),
10
+ new TextileEditorButton("ed_h1", "<%= asset_path('textile-editor/h1.png') %>", "h1", "\n", "1", "Header 1"),
11
+ new TextileEditorButton("ed_h2", "<%= asset_path('textile-editor/h2.png') %>", "h2", "\n", "2", "Header 2"),
12
+ new TextileEditorButton("ed_h3", "<%= asset_path('textile-editor/h3.png') %>", "h3", "\n", "3", "Header 3"),
13
+ new TextileEditorButton("ed_h4", "<%= asset_path('textile-editor/h4.png') %>", "h4", "\n", "4", "Header 4"),
14
+ new TextileEditorButton("ed_block", "<%= asset_path('textile-editor/blockquote.png') %>", "bq", "\n", "q", "Blockquote"),
15
+ new TextileEditorButton("ed_outdent", "<%= asset_path('textile-editor/outdent.png') %>", ")", "\n", "]", "Outdent"),
16
+ new TextileEditorButton("ed_indent", "<%= asset_path('textile-editor/indent.png') %>", "(", "\n", "[", "Indent"),
17
+ new TextileEditorButton("ed_justifyl", "<%= asset_path('textile-editor/left.png') %>", "<", "\n", "l", "Left Justify"),
18
+ new TextileEditorButton("ed_justifyc", "<%= asset_path('textile-editor/center.png') %>", "=", "\n", "e", "Center Text"),
19
+ new TextileEditorButton("ed_justifyr", "<%= asset_path('textile-editor/right.png') %>", ">", "\n", "r", "Right Justify"),
20
+ new TextileEditorButton("ed_justify", "<%= asset_path('textile-editor/justify.png') %>", "<>", "\n", "j", "Justify"),
21
+ # new TextileEditorButton('ed_code','code','@','@','c','Code')
22
+ ]
23
+ )
@@ -0,0 +1,521 @@
1
+ #Textile Editor v0.2
2
+ #created by: dave olsen, wvu web services
3
+ #created on: march 17, 2007
4
+ #project page: slateinfo.blogs.wvu.edu
5
+ #
6
+ #inspired by:
7
+ # - Patrick Woods, http://www.hakjoon.com/code/38/textile-quicktags-redirect &
8
+ # - Alex King, http://alexking.org/projects/js-quicktags
9
+ #
10
+ #features:
11
+ # - supports: IE7, FF2, Safari2
12
+ # - ability to use "simple" vs. "extended" editor
13
+ # - supports all block elements in textile except footnote
14
+ # - supports all block modifier elements in textile
15
+ # - supports simple ordered and unordered lists
16
+ # - supports most of the phrase modifiers, very easy to add the missing ones
17
+ # - supports multiple-paragraph modification
18
+ # - can have multiple "editors" on one page, access key use in this environment is flaky
19
+ # - access key support
20
+ # - select text to add and remove tags, selection stays highlighted
21
+ # - seamlessly change between tags and modifiers
22
+ # - doesn't need to be in the body onload tag
23
+ # - can supply your own, custom IDs for the editor to be drawn around
24
+ #
25
+ #todo:
26
+ # - a clean way of providing image and link inserts
27
+ # - get the selection to properly show in IE
28
+ #
29
+ #more on textile:
30
+ # - Textism, http://www.textism.com/tools/textile/index.php
31
+ # - Textile Reference, http://hobix.com/textile/
32
+
33
+
34
+ class TextileEditorButton
35
+
36
+ constructor: (id, display, tagStart, tagEnd, access, title, sve, open) ->
37
+ @id = id # used to name the toolbar button
38
+ @display = display # label on button
39
+ @tagStart = tagStart # open tag
40
+ @tagEnd = tagEnd # close tag
41
+ @access = access # set to -1 if tag does not need to be closed
42
+ @title = title # sets the title attribute of the button to give 'tool tips'
43
+ @sve = sve # sve = simple vs. extended. add an 's' to make it show up in the simple toolbar
44
+ @open = open # set to -1 if tag does not need to be closed
45
+ @standard = true # this is a standard button
46
+ # this.framework = 'prototype'; // the JS framework used
47
+
48
+ window.TextileEditorButton = TextileEditorButton
49
+
50
+
51
+ class TextileEditorButtonSeparator
52
+
53
+ constructor: (sve) ->
54
+ @separator = true
55
+ @sve = sve
56
+
57
+ window.TextileEditorButtonSeparator = TextileEditorButtonSeparator
58
+
59
+ class TextileEditor
60
+
61
+ @setButtons: (buttons) ->
62
+ TextileEditor.buttons = buttons
63
+
64
+ @addButton: (button) ->
65
+ @getButtons().push(button)
66
+
67
+ @getButtons: () ->
68
+ TextileEditor.buttons || new Array()
69
+
70
+ constructor: (canvas, view) ->
71
+
72
+ toolbar = document.createElement("div")
73
+ toolbar.id = "textile-toolbar-" + canvas
74
+ toolbar.className = "textile-toolbar"
75
+ @canvas = document.getElementById(canvas)
76
+ @canvas.parentNode.insertBefore toolbar, @canvas
77
+ @openTags = new Array()
78
+
79
+ # Create the local Button array by assigning theButtons array to edButtons
80
+ edButtons = new Array()
81
+ edButtons = TextileEditor.getButtons()
82
+ standardButtons = new Array()
83
+ i = 0
84
+
85
+ while i < edButtons.length
86
+ thisButton = @prepareButton(edButtons[i])
87
+ if view is "s"
88
+ if edButtons[i].sve is "s"
89
+ toolbar.appendChild thisButton
90
+ standardButtons.push thisButton
91
+ else
92
+ if typeof thisButton is "string"
93
+ toolbar.innerHTML += thisButton
94
+ else
95
+ toolbar.appendChild thisButton
96
+ standardButtons.push thisButton
97
+ i++
98
+ # end for
99
+ te = this
100
+ buttons = toolbar.getElementsByTagName("button")
101
+ i = 0
102
+
103
+ while i < buttons.length
104
+
105
+ #$A(toolbar.getElementsByTagName('button')).each(function(button) {
106
+ unless buttons[i].onclick
107
+ buttons[i].onclick = ->
108
+ te.insertTag this
109
+ false
110
+ # end if
111
+ buttons[i].tagStart = buttons[i].getAttribute("tagStart")
112
+ buttons[i].tagEnd = buttons[i].getAttribute("tagEnd")
113
+ buttons[i].open = buttons[i].getAttribute("open")
114
+ buttons[i].textile_editor = te
115
+ buttons[i].canvas = te.canvas
116
+ i++
117
+
118
+ # draw individual buttons (edShowButton)
119
+ prepareButton: (button) ->
120
+ if button.separator
121
+ theButton = document.createElement("span")
122
+ theButton.className = "ed_sep"
123
+ return theButton
124
+ if button.standard
125
+ theButton = document.createElement("button")
126
+ theButton.id = button.id
127
+ theButton.setAttribute "class", "standard"
128
+ theButton.setAttribute "tagStart", button.tagStart
129
+ theButton.setAttribute "tagEnd", button.tagEnd
130
+ theButton.setAttribute "open", button.open
131
+ img = document.createElement("img")
132
+ img.src = button.display
133
+ theButton.appendChild img
134
+ else
135
+ return button
136
+ # end if !custom
137
+ theButton.accessKey = button.access
138
+ theButton.title = button.title
139
+ theButton
140
+
141
+ # if clicked, no selected text, tag not open highlight button
142
+ # (edAddTag)
143
+ addTag: (button) ->
144
+ unless button.tagEnd is ""
145
+ @openTags[@openTags.length] = button
146
+
147
+ #var el = document.getElementById(button.id);
148
+ #el.className = 'selected';
149
+ button.className = "selected"
150
+
151
+ # if clicked, no selected text, tag open lowlight button
152
+ # (edRemoveTag)
153
+ removeTag: (button) ->
154
+ i = 0
155
+ while i < @openTags.length
156
+ if @openTags[i] is button
157
+ @openTags.splice button, 1
158
+
159
+ #var el = document.getElementById(button.id);
160
+ #el.className = 'unselected';
161
+ button.className = "unselected"
162
+ i++
163
+
164
+ # see if there are open tags. for the remove tag bit...
165
+ # (edCheckOpenTags)
166
+ checkOpenTags: (button) ->
167
+ tag = 0
168
+ i = 0
169
+ while i < @openTags.length
170
+ tag++ if @openTags[i] is button
171
+ i++
172
+ if tag > 0
173
+ true # tag found
174
+ else
175
+ false # tag not found
176
+
177
+ # insert the tag. this is the bulk of the code.
178
+ # (edInsertTag)
179
+ insertTag: (button, tagStart, tagEnd) ->
180
+
181
+ #console.log(button);
182
+ myField = button.canvas
183
+ myField.focus()
184
+ if tagStart
185
+ button.tagStart = tagStart
186
+ button.tagEnd = (if tagEnd then tagEnd else "\n")
187
+ textSelected = false
188
+ finalText = ""
189
+ FF = false
190
+
191
+ # grab the text that's going to be manipulated, by browser
192
+ if document.selection # IE support
193
+ sel = document.selection.createRange()
194
+
195
+ # set-up the text vars
196
+ beginningText = ""
197
+ followupText = ""
198
+ selectedText = sel.text
199
+
200
+ # check if text has been selected
201
+ textSelected = true if sel.text.length > 0
202
+
203
+ # set-up newline regex's so we can swap tags across multiple paragraphs
204
+ newlineReplaceRegexClean = /\r\n\s\n/g
205
+ newlineReplaceRegexDirty = "\\r\\n\\s\\n"
206
+ newlineReplaceClean = "\r\n\n"
207
+ else if myField.selectionStart or myField.selectionStart is "0" # MOZ/FF/NS/S support
208
+
209
+ # figure out cursor and selection positions
210
+ startPos = myField.selectionStart
211
+ endPos = myField.selectionEnd
212
+ cursorPos = endPos
213
+ scrollTop = myField.scrollTop
214
+ FF = true # note that is is a FF/MOZ/NS/S browser
215
+
216
+ # set-up the text vars
217
+ beginningText = myField.value.substring(0, startPos)
218
+ followupText = myField.value.substring(endPos, myField.value.length)
219
+
220
+ # check if text has been selected
221
+ unless startPos is endPos
222
+ textSelected = true
223
+ selectedText = myField.value.substring(startPos, endPos)
224
+
225
+ # set-up newline regex's so we can swap tags across multiple paragraphs
226
+ newlineReplaceRegexClean = /\n\n/g
227
+ newlineReplaceRegexDirty = "\\n\\n"
228
+ newlineReplaceClean = "\n\n"
229
+
230
+ # if there is text that has been highlighted...
231
+ if textSelected
232
+
233
+ # set-up some defaults for how to handle bad new line characters
234
+ newlineStart = ""
235
+ newlineStartPos = 0
236
+ newlineEnd = ""
237
+ newlineEndPos = 0
238
+ newlineFollowup = ""
239
+
240
+ # set-up some defaults for how to handle placing the beginning and end of selection
241
+ posDiffPos = 0
242
+ posDiffNeg = 0
243
+ mplier = 1
244
+
245
+ # remove newline from the beginning of the selectedText.
246
+ if selectedText.match(/^\n/)
247
+ selectedText = selectedText.replace(/^\n/, "")
248
+ newlineStart = "\n"
249
+ newlineStartpos = 1
250
+
251
+ # remove newline from the end of the selectedText.
252
+ if selectedText.match(/\n$/g)
253
+ selectedText = selectedText.replace(/\n$/g, "")
254
+ newlineEnd = "\n"
255
+ newlineEndPos = 1
256
+
257
+ # no clue, i'm sure it made sense at the time i wrote it
258
+ if followupText.match(/^\n/)
259
+ newlineFollowup = ""
260
+ else
261
+ newlineFollowup = "\n\n"
262
+
263
+ # first off let's check if the user is trying to mess with lists
264
+ if (button.tagStart is " * ") or (button.tagStart is " # ")
265
+ listItems = 0 # sets up a default to be able to properly manipulate final selection
266
+
267
+ # set-up all of the regex's
268
+ re_start = new RegExp("^ (\\*|\\#) ", "g")
269
+ if button.tagStart is " # "
270
+ 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
271
+ else
272
+ re_tag = new RegExp(" \\* ", "g")
273
+ re_replace = new RegExp(" (\\*|\\#) ", "g")
274
+
275
+ # try to remove bullets in text copied from ms word **Mac Only!**
276
+ re_word_bullet_m_s = new RegExp("• ", "g") # mac/safari
277
+ re_word_bullet_m_f = new RegExp("∑ ", "g") # mac/firefox
278
+ selectedText = selectedText.replace(re_word_bullet_m_s, "").replace(re_word_bullet_m_f, "")
279
+
280
+ # if the selected text starts with one of the tags we're working with...
281
+ if selectedText.match(re_start)
282
+
283
+ # if tag that begins the selection matches the one clicked, remove them all
284
+ if selectedText.match(re_tag)
285
+ finalText = beginningText + newlineStart + selectedText.replace(re_replace, "") + newlineEnd + followupText
286
+ listItems = matches.length if matches = selectedText.match(RegExp(" (\\*|\\#) ", "g"))
287
+ posDiffNeg = listItems * 3 # how many list items were there because that's 3 spaces to remove from final selection
288
+
289
+ # else replace the current tag type with the selected tag type
290
+ else
291
+ finalText = beginningText + newlineStart + selectedText.replace(re_replace, button.tagStart) + newlineEnd + followupText
292
+
293
+ # else try to create the list type
294
+ # NOTE: the items in a list will only be replaced if a newline starts with some character, not a space
295
+ else
296
+ finalText = beginningText + newlineStart + button.tagStart + selectedText.replace(newlineReplaceRegexClean, newlineReplaceClean + button.tagStart).replace(/\n(\S)/g, "\n" + button.tagStart + "$1") + newlineEnd + followupText
297
+ listItems = matches.length if matches = selectedText.match(/\n(\S)/g)
298
+ posDiffPos = 3 + listItems * 3
299
+
300
+ # now lets look and see if the user is trying to muck with a block or block modifier
301
+ else if button.tagStart.match(/^(h1|h2|h3|h4|h5|h6|bq|p|\>|\<\>|\<|\=|\(|\))/g)
302
+ insertTag = ""
303
+ insertModifier = ""
304
+ tagPartBlock = ""
305
+ tagPartModifier = ""
306
+ tagPartModifierOrig = "" # ugly hack but it's late
307
+ drawSwitch = ""
308
+ captureIndentStart = false
309
+ captureListStart = false
310
+ periodAddition = "\\. "
311
+ periodAdditionClean = ". "
312
+ listItemsAddition = 0
313
+ re_list_items = new RegExp("(\\*+|\\#+)", "g") # need this regex later on when checking indentation of lists
314
+ re_block_modifier = new RegExp("^(h1|h2|h3|h4|h5|h6|bq|p| [\\*]{1,} | [\\#]{1,} |)(\\>|\\<\\>|\\<|\\=|[\\(]{1,}|[\\)]{1,6}|)", "g")
315
+ if tagPartMatches = re_block_modifier.exec(selectedText)
316
+ tagPartBlock = tagPartMatches[1]
317
+ tagPartModifier = tagPartMatches[2]
318
+ tagPartModifierOrig = tagPartMatches[2]
319
+ tagPartModifierOrig = tagPartModifierOrig.replace(/\(/g, "\\(")
320
+
321
+ # if tag already up is the same as the tag provided replace the whole tag
322
+ if tagPartBlock is button.tagStart
323
+ insertTag = tagPartBlock + tagPartModifierOrig # use Orig because it's escaped for regex
324
+ drawSwitch = 0
325
+
326
+ # else if let's check to add/remove block modifier
327
+ else if (tagPartModifier is button.tagStart) or (newm = tagPartModifier.match(/[\(]{2,}/g))
328
+ if (button.tagStart is "(") or (button.tagStart is ")")
329
+ indentLength = tagPartModifier.length
330
+ if button.tagStart is "("
331
+ indentLength = indentLength + 1
332
+ else
333
+ indentLength = indentLength - 1
334
+ i = 0
335
+
336
+ while i < indentLength
337
+ insertModifier = insertModifier + "("
338
+ i++
339
+ insertTag = tagPartBlock + insertModifier
340
+ else
341
+ if button.tagStart is tagPartModifier
342
+ insertTag = tagPartBlock
343
+ # going to rely on the default empty insertModifier
344
+ else
345
+ if button.tagStart.match(/(\>|\<\>|\<|\=)/g)
346
+ insertTag = tagPartBlock + button.tagStart
347
+ else
348
+ insertTag = button.tagStart + tagPartModifier
349
+ drawSwitch = 1
350
+
351
+ # indentation of list items
352
+ else if listPartMatches = re_list_items.exec(tagPartBlock)
353
+ listTypeMatch = listPartMatches[1]
354
+ indentLength = tagPartBlock.length - 2
355
+ listInsert = ""
356
+ if button.tagStart is "("
357
+ indentLength = indentLength + 1
358
+ else
359
+ indentLength = indentLength - 1
360
+ if listTypeMatch.match(/[\*]{1,}/g)
361
+ listType = "*"
362
+ listReplace = "\\*"
363
+ else
364
+ listType = "#"
365
+ listReplace = "\\#"
366
+ i = 0
367
+
368
+ while i < indentLength
369
+ listInsert = listInsert + listType
370
+ i++
371
+ unless listInsert is ""
372
+ insertTag = " " + listInsert + " "
373
+ else
374
+ insertTag = ""
375
+ tagPartBlock = tagPartBlock.replace(/(\*|\#)/g, listReplace)
376
+ drawSwitch = 1
377
+ captureListStart = true
378
+ periodAddition = ""
379
+ periodAdditionClean = ""
380
+ listItemsAddition = matches.length if matches = selectedText.match(/\n\s/g)
381
+
382
+ # must be a block modification e.g. p>. to p<.
383
+ else
384
+
385
+ # if this is a block modification/addition
386
+ if button.tagStart.match(/(h1|h2|h3|h4|h5|h6|bq|p)/g)
387
+ if tagPartBlock is ""
388
+ drawSwitch = 2
389
+ else
390
+ drawSwitch = 1
391
+ insertTag = button.tagStart + tagPartModifier
392
+
393
+ # else this is a modifier modification/addition
394
+ else
395
+ if (tagPartModifier is "") and (tagPartBlock isnt "")
396
+ drawSwitch = 1
397
+ else if tagPartModifier is ""
398
+ drawSwitch = 2
399
+ else
400
+ drawSwitch = 1
401
+
402
+ # if no tag part block but a modifier we need at least the p tag
403
+ tagPartBlock = "p" if tagPartBlock is ""
404
+
405
+ #make sure to swap out outdent
406
+ if button.tagStart is ")"
407
+ tagPartModifier = ""
408
+ else
409
+ tagPartModifier = button.tagStart
410
+ captureIndentStart = true # ugly hack to fix issue with proper selection handling
411
+ insertTag = tagPartBlock + tagPartModifier
412
+ mplier = 0
413
+ if captureListStart or (tagPartModifier.match(/[\(\)]{1,}/g))
414
+ re_start = new RegExp(insertTag.escape + periodAddition, "g") # for tags that mimic regex properties, parens + list tags
415
+ else
416
+ re_start = new RegExp(insertTag + periodAddition, "g") # for tags that don't, why i can't just escape everything i have no clue
417
+ re_old = new RegExp(tagPartBlock + tagPartModifierOrig + periodAddition, "g")
418
+ re_middle = new RegExp(newlineReplaceRegexDirty + insertTag.escape + periodAddition.escape, "g")
419
+ re_tag = new RegExp(insertTag.escape + periodAddition.escape, "g")
420
+
421
+ # *************************************************************************************************************************
422
+ # this is where everything gets swapped around or inserted, bullets and single options have their own if/else statements
423
+ # *************************************************************************************************************************
424
+ if (drawSwitch is 0) or (drawSwitch is 1)
425
+ if drawSwitch is 0 # completely removing a tag
426
+ finalText = beginningText + newlineStart + selectedText.replace(re_start, "").replace(re_middle, newlineReplaceClean) + newlineEnd + followupText
427
+ mplier = mplier + matches.length if matches = selectedText.match(newlineReplaceRegexClean)
428
+ posDiffNeg = insertTag.length + 2 + (mplier * 4)
429
+ else # modifying a tag, though we do delete bullets here
430
+ finalText = beginningText + newlineStart + selectedText.replace(re_old, insertTag + periodAdditionClean) + newlineEnd + followupText
431
+ mplier = mplier + matches.length if matches = selectedText.match(newlineReplaceRegexClean)
432
+
433
+ # figure out the length of various elements to modify the selection position
434
+ if captureIndentStart # need to double-check that this wasn't the first indent
435
+ tagPreviousLength = tagPartBlock.length
436
+ tagCurrentLength = insertTag.length
437
+ else if captureListStart # if this is a list we're manipulating
438
+ if button.tagStart is "(" # if indenting
439
+ tagPreviousLength = listTypeMatch.length + 2
440
+ tagCurrentLength = insertTag.length + listItemsAddition
441
+ else if insertTag.match(/(\*|\#)/g) # if removing but still has bullets
442
+ tagPreviousLength = insertTag.length + listItemsAddition
443
+ tagCurrentLength = listTypeMatch.length
444
+ else # if removing last bullet
445
+ tagPreviousLength = insertTag.length + listItemsAddition
446
+ tagCurrentLength = listTypeMatch.length - (3 * listItemsAddition) - 1
447
+ else # everything else
448
+ tagPreviousLength = tagPartBlock.length + tagPartModifier.length
449
+ tagCurrentLength = insertTag.length
450
+ if tagCurrentLength > tagPreviousLength
451
+ posDiffPos = (tagCurrentLength - tagPreviousLength) + (mplier * (tagCurrentLength - tagPreviousLength))
452
+ else
453
+ posDiffNeg = (tagPreviousLength - tagCurrentLength) + (mplier * (tagPreviousLength - tagCurrentLength))
454
+ else # for adding tags other then bullets (have their own statement)
455
+ finalText = beginningText + newlineStart + insertTag + ". " + selectedText.replace(newlineReplaceRegexClean, button.tagEnd + "\n" + insertTag + ". ") + newlineFollowup + newlineEnd + followupText
456
+ mplier = mplier + matches.length if matches = selectedText.match(newlineReplaceRegexClean)
457
+ posDiffPos = insertTag.length + 2 + (mplier * 4)
458
+
459
+ # swap in and out the simple tags around a selection like bold
460
+ else
461
+ mplier = 1 # the multiplier for the tag length
462
+ re_start = new RegExp("^\\" + button.tagStart, "g")
463
+ re_end = new RegExp("\\" + button.tagEnd + "$", "g")
464
+ re_middle = new RegExp("\\" + button.tagEnd + newlineReplaceRegexDirty + "\\" + button.tagStart, "g")
465
+ if selectedText.match(re_start) and selectedText.match(re_end)
466
+ finalText = beginningText + newlineStart + selectedText.replace(re_start, "").replace(re_end, "").replace(re_middle, newlineReplaceClean) + newlineEnd + followupText
467
+ mplier = mplier + matches.length if matches = selectedText.match(newlineReplaceRegexClean)
468
+ posDiffNeg = button.tagStart.length * mplier + button.tagEnd.length * mplier
469
+ else
470
+ finalText = beginningText + newlineStart + button.tagStart + selectedText.replace(newlineReplaceRegexClean, button.tagEnd + newlineReplaceClean + button.tagStart) + button.tagEnd + newlineEnd + followupText
471
+ mplier = mplier + matches.length if matches = selectedText.match(newlineReplaceRegexClean)
472
+ posDiffPos = (button.tagStart.length * mplier) + (button.tagEnd.length * mplier)
473
+ cursorPos += button.tagStart.length + button.tagEnd.length
474
+
475
+ # just swap in and out single values, e.g. someone clicks b they'll get a *
476
+ else
477
+ buttonStart = ""
478
+ buttonEnd = ""
479
+ re_p = new RegExp("(\\<|\\>|\\=|\\<\\>|\\(|\\))", "g")
480
+ re_h = new RegExp("^(h1|h2|h3|h4|h5|h6|p|bq)", "g")
481
+ if not @checkOpenTags(button) or button.tagEnd is "" # opening tag
482
+ if button.tagStart.match(re_h)
483
+ buttonStart = button.tagStart + ". "
484
+ else
485
+ buttonStart = button.tagStart
486
+ if button.tagStart.match(re_p) # make sure that invoking block modifiers don't do anything
487
+ finalText = beginningText + followupText
488
+ cursorPos = startPos
489
+ else
490
+ finalText = beginningText + buttonStart + followupText
491
+ @addTag button
492
+ cursorPos = startPos + buttonStart.length
493
+ else # closing tag
494
+ if button.tagStart.match(re_p)
495
+ buttonEnd = "\n\n"
496
+ else if button.tagStart.match(re_h)
497
+ buttonEnd = "\n\n"
498
+ else
499
+ buttonEnd = button.tagEnd
500
+ finalText = beginningText + button.tagEnd + followupText
501
+ @removeTag button
502
+ cursorPos = startPos + button.tagEnd.length
503
+
504
+ # set the appropriate DOM value with the final text
505
+ if FF is true
506
+ myField.value = finalText
507
+ myField.scrollTop = scrollTop
508
+ else
509
+ sel.text = finalText
510
+
511
+ # build up the selection capture, doesn't work in IE
512
+ if textSelected
513
+ myField.selectionStart = startPos + newlineStartPos
514
+ myField.selectionEnd = endPos + posDiffPos - posDiffNeg - newlineEndPos
515
+
516
+ #alert('s: ' + myField.selectionStart + ' e: ' + myField.selectionEnd + ' sp: ' + startPos + ' ep: ' + endPos + ' pdp: ' + posDiffPos + ' pdn: ' + posDiffNeg)
517
+ else
518
+ myField.selectionStart = cursorPos
519
+ myField.selectionEnd = cursorPos
520
+
521
+ window.TextileEditor = TextileEditor
@@ -0,0 +1,44 @@
1
+ div.textile-toolbar {
2
+ span.ed_sep {
3
+ xposition: relative;
4
+ xtop: -4px;
5
+ padding: 0;
6
+ height: 6px;
7
+ width: 2px;
8
+ margin: 0 2px;
9
+ border-left: solid 1px #d5d5d5;
10
+ border-right: solid 1px #f5f5f5;
11
+ }
12
+ button {
13
+ margin: 0;
14
+ background-color: #f0f0ee;
15
+ background-repeat: no-repeat;
16
+ border: 1px solid #f0f0ee;
17
+ padding: 2px 0;
18
+ &.standard {
19
+ text-align: center;
20
+ width: 24px;
21
+ }
22
+ img {
23
+ vertical-align: text-bottom;
24
+ }
25
+ &:hover, &.unselected:hover {
26
+ border: 1px solid #999;
27
+ }
28
+ &.selected {
29
+ border: 1px solid #ce9100;
30
+ background-color: #ffffff;
31
+ }
32
+ &.unselected {
33
+ border: 1px solid #f0f0ee;
34
+ background-color: #f0f0ee;
35
+ }
36
+ &.publish {
37
+ padding: 5px;
38
+ display: block;
39
+ }
40
+ }
41
+ background-color: #f0f0ee;
42
+ padding: 3px;
43
+ margin-bottom: 4px;
44
+ }
@@ -0,0 +1,11 @@
1
+
2
+ Description:
3
+ The textile_editor_config generator creates a config file for the textile editor.
4
+
5
+ Example:
6
+ rails generate textile_editor_config
7
+
8
+ This will create:
9
+ A Javascript config file located at app/assets/javascripts/textile-editor-config.js.coffee.erb
10
+
11
+ More info on textile_editor_config can be found here: https://github.com/emjot/redcloth-rails
@@ -0,0 +1,23 @@
1
+ TextileEditor.setButtons(
2
+ [
3
+ new TextileEditorButton("ed_strong", "<%= asset_path('textile-editor/bold.png') %>", "*", "*", "b", "Bold", "s"),
4
+ new TextileEditorButton("ed_emphasis", "<%= asset_path('textile-editor/italic.png') %>", "_", "_", "i", "Italicize", "s"),
5
+ new TextileEditorButton("ed_underline", "<%= asset_path('textile-editor/underline.png') %>", "+", "+", "u", "Underline", "s"),
6
+ new TextileEditorButton("ed_strike", "<%= asset_path('textile-editor/strikethrough.png') %>", "-", "-", "s", "Strikethrough", "s"),
7
+ new TextileEditorButton("ed_ol", "<%= asset_path('textile-editor/list_numbers.png') %>", " # ", "\n", ",", "Numbered List"),
8
+ new TextileEditorButton("ed_ul", "<%= asset_path('textile-editor/list_bullets.png') %>", " * ", "\n", ".", "Bulleted List"),
9
+ new TextileEditorButton("ed_p", "<%= asset_path('textile-editor/paragraph.png') %>", "p", "\n", "p", "Paragraph"),
10
+ new TextileEditorButton("ed_h1", "<%= asset_path('textile-editor/h1.png') %>", "h1", "\n", "1", "Header 1"),
11
+ new TextileEditorButton("ed_h2", "<%= asset_path('textile-editor/h2.png') %>", "h2", "\n", "2", "Header 2"),
12
+ new TextileEditorButton("ed_h3", "<%= asset_path('textile-editor/h3.png') %>", "h3", "\n", "3", "Header 3"),
13
+ new TextileEditorButton("ed_h4", "<%= asset_path('textile-editor/h4.png') %>", "h4", "\n", "4", "Header 4"),
14
+ new TextileEditorButton("ed_block", "<%= asset_path('textile-editor/blockquote.png') %>", "bq", "\n", "q", "Blockquote"),
15
+ new TextileEditorButton("ed_outdent", "<%= asset_path('textile-editor/outdent.png') %>", ")", "\n", "]", "Outdent"),
16
+ new TextileEditorButton("ed_indent", "<%= asset_path('textile-editor/indent.png') %>", "(", "\n", "[", "Indent"),
17
+ new TextileEditorButton("ed_justifyl", "<%= asset_path('textile-editor/left.png') %>", "<", "\n", "l", "Left Justify"),
18
+ new TextileEditorButton("ed_justifyc", "<%= asset_path('textile-editor/center.png') %>", "=", "\n", "e", "Center Text"),
19
+ new TextileEditorButton("ed_justifyr", "<%= asset_path('textile-editor/right.png') %>", ">", "\n", "r", "Right Justify"),
20
+ new TextileEditorButton("ed_justify", "<%= asset_path('textile-editor/justify.png') %>", "<>", "\n", "j", "Justify"),
21
+ new TextileEditorButton("ed_code", "code", "@", "@", "c", "Code")
22
+ ]
23
+ )
@@ -0,0 +1,9 @@
1
+ class TextileEditorConfigGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('../templates', __FILE__)
3
+
4
+ def copy_javascript
5
+ copy_file 'textile-editor-config.js.coffee.erb', 'app/assets/javascripts/textile-editor-config.js.coffee.erb'
6
+ end
7
+
8
+ end
9
+
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), 'helpers.rb')
2
+
3
+ module RedCloth
4
+ module Rails
5
+
6
+ class Engine < ::Rails::Engine
7
+ initializer "redcloth-rails.action_controller" do |app|
8
+ ActiveSupport.on_load :action_view do
9
+ ActionView::Helpers::FormBuilder.send :include, RedCloth::Rails::Helpers::FormBuilder
10
+
11
+ ActionView::Base.send :include, RedCloth::Rails::Helpers::FormHelper
12
+ ActionView::Base.send :include, RedCloth::Rails::Helpers::FormTagHelper
13
+ end
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module RedCloth
2
+ module Rails
3
+ module Helpers
4
+
5
+ module FormBuilder
6
+ # @see RedCloth::Rails::Helpers::FormHelper#textile_editor
7
+ def textile_editor(method, options = {})
8
+ @template.textile_editor(@object_name, method, options.merge(:object => @object))
9
+ end
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,137 @@
1
+ module RedCloth
2
+ module Rails
3
+ module Helpers
4
+
5
+ module FormHelper
6
+ # Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
7
+ # on an object assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
8
+ # hash with +options+ and places the textile toolbar above it
9
+ #
10
+ # @param [Symbol] object_name name of the model
11
+ # @param [Symbol] method_name name of the models attribute
12
+ # @param [Hash] options HTML options to customize the textarea element
13
+ #
14
+ # Samples:
15
+ # textile_editor(:post, :body, :cols => 20, :rows => 40)
16
+ # # => <textarea cols="20" rows="40" id="post_body" name="post[body]">
17
+ # # #{@post.body}
18
+ # # </textarea>
19
+ #
20
+ # textile_editor(:comment, :text, :size => "20x30")
21
+ # # => <textarea cols="20" rows="30" id="comment_text" name="comment[text]">
22
+ # # #{@comment.text}
23
+ # # </textarea>
24
+ #
25
+ # textile_editor(:application, :notes, :cols => 40, :rows => 15, :class => 'app_input')
26
+ # # => <textarea cols="40" rows="15" id="application_notes" name="application[notes]" class="app_input">
27
+ # # #{@application.notes}
28
+ # # </textarea>
29
+ #
30
+ # textile_editor(:entry, :body, :size => "20x20", :disabled => 'disabled')
31
+ # # => <textarea cols="20" rows="20" id="entry_body" name="entry[body]" disabled="disabled">
32
+ # # #{@entry.body}
33
+ # # </textarea>
34
+ #
35
+ def textile_editor(object_name, method, options = {})
36
+ editor_id = options[:id] || '%s_%s' % [object_name, method]
37
+ mode = options.delete(:simple) ? 'simple' : 'extended'
38
+ (@textile_editor_ids ||= []) << [editor_id.to_s, mode.to_s]
39
+
40
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, options.delete(:object)).to_text_area_tag(options)
41
+ end
42
+
43
+ # Registers a further button on the TextileEditor toolbar.
44
+ # Must be called before the TextileEditor gets initialized.
45
+ #
46
+ # @param [String] text text to display (contents of button tag, so HTML is valid as well)
47
+ # @param [Hash] options options Hash as supported by +content_tag+ helper in Rails
48
+ #
49
+ # Example:
50
+ # Add a button labeled 'Greeting' which triggers an alert dialog.
51
+ #
52
+ # <% textile_editor_button 'Greeting', :onclick => "alert('Hello!')" %>
53
+ #
54
+ def textile_editor_button(text, options={})
55
+ return textile_editor_button_separator if text == :separator
56
+ button = content_tag(:button, text, options)
57
+ button = "TextileEditor.addButton(\"%s\");" % escape_javascript(button)
58
+ (@textile_editor_buttons ||= []) << button
59
+ return nil
60
+ end
61
+
62
+ # Registers a separator on the TextileEditor toolbar.
63
+ # Must be called before the TextileEditor gets initialized.
64
+ #
65
+ # @param [Hash] options
66
+ #
67
+ def textile_editor_button_separator(options={})
68
+ button = "TextileEditor.addButton(new TextileEditorButtonSeparator('%s'));" % (options[:simple] || '')
69
+ (@textile_editor_buttons ||= []) << button
70
+ return nil
71
+ end
72
+
73
+ # Initialize the TextileEditor. after the DOM was loaded.
74
+ #
75
+ # @param [Array] dom_ids
76
+ # @param [Hash] options
77
+ #
78
+ # Sample with jQuery DOM ready event:
79
+ # <script type="text/javascript">
80
+ # jQuery(document).ready(function() {
81
+ # TextileEditor.initialize('article_body', 'extended');
82
+ # TextileEditor.initialize('article_body_excerpt', 'simple');
83
+ # });
84
+ # </script>
85
+ #
86
+ # Sample for AJAX requests, the TextileEditor gets initialized without waiting for DOM.
87
+ # <script type="text/javascript">
88
+ # TextileEditor.initialize('article_body', 'extended');
89
+ # TextileEditor.initialize('article_body_excerpt', 'simple');
90
+ # </script>
91
+ #
92
+ def textile_editor_initialize(*dom_ids)
93
+ options = {}
94
+
95
+ # extract options from last argument if it's a hash
96
+ if dom_ids.last.is_a?(Hash)
97
+ hash = dom_ids.last.dup
98
+ options.merge! hash
99
+ end
100
+
101
+ editor_ids = (@textile_editor_ids || []) + textile_extract_dom_ids(*dom_ids)
102
+ editor_buttons = (@textile_editor_buttons || [])
103
+ output = []
104
+
105
+ output << '<script type="text/javascript">'
106
+ output << '/* <![CDATA[ */'
107
+
108
+ unless request.xhr?
109
+ output << %{jQuery(document).ready(function($) \{}
110
+ end
111
+
112
+ output << editor_buttons.join("\n") if editor_buttons.any?
113
+
114
+ editor_ids.each do |editor_id, mode|
115
+ output << %q{new TextileEditor('%s', '%s');} % [editor_id, mode || 'extended']
116
+ end
117
+
118
+ unless request.xhr?
119
+ output << '});'
120
+ end
121
+
122
+ output << '/* ]]> */'
123
+ output << '</script>'
124
+ output.join("\n").html_safe
125
+ end
126
+
127
+ def textile_extract_dom_ids(*dom_ids)
128
+ hash = dom_ids.last.is_a?(Hash) ? dom_ids.pop : {}
129
+ hash.inject(dom_ids) do |ids, (object, fields)|
130
+ ids + Array(fields).map { |field| "%s_%s" % [object, field] }
131
+ end
132
+ end
133
+ end
134
+
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,49 @@
1
+ module RedCloth
2
+ module Rails
3
+ module Helpers
4
+
5
+ module FormTagHelper
6
+ # Creates a text input area; use a textarea for longer text inputs such as blog posts or descriptions
7
+ # and includes the textile toolbar above it.
8
+ #
9
+ # @param [String] name
10
+ # @param [String] content
11
+ # @param [Hash] options
12
+ # @option options [String] :size String to specify the column and row dimensions (e.g., "25x10").
13
+ # @option options [Integer] :rows Specify the number of rows in the textarea
14
+ # @option options [Integer] :cols Specify the number of columns in the textarea
15
+ # @option options [Boolean] :disabled If set to true, the user will not be able to use this input.
16
+ #
17
+ # Any other option (key/value pair) will be used to create HTML attributes for the tag.
18
+ #
19
+ # Samples:
20
+ # textile_editor_tag 'post'
21
+ # # => <textarea id="post" name="post"></textarea>
22
+ #
23
+ # textile_editor_tag 'bio', @user.bio
24
+ # # => <textarea id="bio" name="bio">This is my biography.</textarea>
25
+ #
26
+ # textile_editor_tag 'body', nil, :rows => 10, :cols => 25
27
+ # # => <textarea cols="25" id="body" name="body" rows="10"></textarea>
28
+ #
29
+ # textile_editor_tag 'body', nil, :size => "25x10"
30
+ # # => <textarea name="body" id="body" cols="25" rows="10"></textarea>
31
+ #
32
+ # textile_editor_tag 'description', "Description goes here.", :disabled => true
33
+ # # => <textarea disabled="disabled" id="description" name="description">Description goes here.</textarea>
34
+ #
35
+ # textile_editor_tag 'comment', nil, :class => 'comment_input'
36
+ # # => <textarea class="comment_input" id="comment" name="comment"></textarea>
37
+ #
38
+ def textile_editor_tag(name, content = nil, options = {})
39
+ editor_id = options[:id] || name
40
+ mode = options.delete(:simple) ? 'simple' : 'extended'
41
+ (@textile_editor_ids ||= []) << [editor_id.to_s, mode.to_s]
42
+
43
+ text_area_tag(name, content, options)
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), 'helpers/form_builder.rb')
2
+ require File.join(File.dirname(__FILE__), 'helpers/form_helper.rb')
3
+ require File.join(File.dirname(__FILE__), 'helpers/form_tag_helper.rb')
4
+
5
+ module RedCloth
6
+ module Rails
7
+ module Helpers; end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module RedCloth
2
+ module Rails
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ unless defined?(RedCloth::Rails::Version)
2
+ require File.join(File.dirname(__FILE__), 'redcloth-rails/version.rb')
3
+ end
4
+
5
+ module RedCloth
6
+ module Rails
7
+
8
+ if defined?(::Rails) && ::Rails.version.to_f >= 3.1
9
+ require File.join(File.dirname(__FILE__), 'redcloth-rails/engine.rb')
10
+ else
11
+ raise 'Rails >= 3.1 is required'
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require File.join(File.dirname(__FILE__), "lib/redcloth-rails/version.rb")
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "redcloth-rails"
7
+ s.version = RedCloth::Rails::VERSION
8
+ s.authors = ["emjot"]
9
+ s.email = ["kontakt@emjot.de"]
10
+ s.homepage = "https://github.com/emjot/redcloth-rails"
11
+ s.summary = %q{rails 3 engine which enables RedCloth and provides helpers for the awesome TextileEditor.}
12
+
13
+ s.add_dependency('RedCloth', '>= 4.2.0')
14
+ s.add_dependency('rails', '>= 3.1.0')
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redcloth-rails
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - emjot
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-03-04 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: RedCloth
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 55
30
+ segments:
31
+ - 4
32
+ - 2
33
+ - 0
34
+ version: 4.2.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rails
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 3
48
+ - 1
49
+ - 0
50
+ version: 3.1.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description:
54
+ email:
55
+ - kontakt@emjot.de
56
+ executables: []
57
+
58
+ extensions: []
59
+
60
+ extra_rdoc_files: []
61
+
62
+ files:
63
+ - Gemfile
64
+ - LICENSE
65
+ - README.textile
66
+ - Rakefile
67
+ - app/assets/images/textile-editor/background.png
68
+ - app/assets/images/textile-editor/blockquote.png
69
+ - app/assets/images/textile-editor/bold.png
70
+ - app/assets/images/textile-editor/center.png
71
+ - app/assets/images/textile-editor/h1.png
72
+ - app/assets/images/textile-editor/h2.png
73
+ - app/assets/images/textile-editor/h3.png
74
+ - app/assets/images/textile-editor/h4.png
75
+ - app/assets/images/textile-editor/h5.png
76
+ - app/assets/images/textile-editor/h6.png
77
+ - app/assets/images/textile-editor/indent.png
78
+ - app/assets/images/textile-editor/italic.png
79
+ - app/assets/images/textile-editor/justify.png
80
+ - app/assets/images/textile-editor/left.png
81
+ - app/assets/images/textile-editor/list_bullets.png
82
+ - app/assets/images/textile-editor/list_numbers.png
83
+ - app/assets/images/textile-editor/omega.png
84
+ - app/assets/images/textile-editor/outdent.png
85
+ - app/assets/images/textile-editor/paragraph.png
86
+ - app/assets/images/textile-editor/right.png
87
+ - app/assets/images/textile-editor/strikethrough.png
88
+ - app/assets/images/textile-editor/underline.png
89
+ - app/assets/javascripts/textile-editor-config.js.coffee.erb
90
+ - app/assets/javascripts/textile-editor.js.coffee
91
+ - app/assets/stylesheets/textile-editor.css.scss
92
+ - lib/rails/generators/textile_editor_config/USAGE
93
+ - lib/rails/generators/textile_editor_config/templates/textile-editor-config.js.coffee.erb
94
+ - lib/rails/generators/textile_editor_config/textile_editor_config_generator.rb
95
+ - lib/redcloth-rails.rb
96
+ - lib/redcloth-rails/engine.rb
97
+ - lib/redcloth-rails/helpers.rb
98
+ - lib/redcloth-rails/helpers/form_builder.rb
99
+ - lib/redcloth-rails/helpers/form_helper.rb
100
+ - lib/redcloth-rails/helpers/form_tag_helper.rb
101
+ - lib/redcloth-rails/version.rb
102
+ - redcloth-rails.gemspec
103
+ has_rdoc: true
104
+ homepage: https://github.com/emjot/redcloth-rails
105
+ licenses: []
106
+
107
+ post_install_message:
108
+ rdoc_options: []
109
+
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: 3
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ requirements: []
131
+
132
+ rubyforge_project:
133
+ rubygems_version: 1.3.7
134
+ signing_key:
135
+ specification_version: 3
136
+ summary: rails 3 engine which enables RedCloth and provides helpers for the awesome TextileEditor.
137
+ test_files: []
138
+