typeout 1.4.5 → 1.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/typeout.js +60 -60
  2. data/lib/typeout.rb +34 -33
  3. metadata +5 -5
data/lib/typeout.js CHANGED
@@ -5,39 +5,39 @@ var regexpEscape = function(text) {
5
5
  var Typeout = new Class({
6
6
  initialize: function(content) {
7
7
  var self = this;
8
-
8
+
9
9
  self.content = content;
10
10
  },
11
-
11
+
12
12
  toHTML: function() {
13
13
  var self = this;
14
-
14
+
15
15
  var text = self.content;
16
-
16
+
17
17
  text = self.cleanWhitespace(text);
18
18
  text = '\n\n' + text + '\n\n'; // a few guaranteed newlines
19
-
19
+
20
20
  self.archive = [];
21
-
21
+
22
22
  text = self.archiveHtml(text);
23
-
23
+
24
24
  text = self.htmlEscape(text);
25
-
25
+
26
26
  text = self.archiveCode(text);
27
-
27
+
28
28
  text = self.makeBlockquotes(text);
29
29
  text = self.makeHeadings(text);
30
30
  text = self.makeLists(text);
31
31
  text = self.makeParagraphs(text);
32
32
  text = self.makeInlines(text);
33
-
33
+
34
34
  text = self.removeExcessNewlines(text);
35
-
35
+
36
36
  text = self.retrieveArchive(text);
37
-
37
+
38
38
  return text;
39
39
  },
40
-
40
+
41
41
  htmlEscape: function(text) {
42
42
  return text.
43
43
  replace(/&/g, '&').
@@ -45,107 +45,107 @@ var Typeout = new Class({
45
45
  replace(/>/g, '>').
46
46
  replace(/"/g, '"')
47
47
  },
48
-
48
+
49
49
  cleanWhitespace: function(text) {
50
50
  return text.
51
51
  replace(/\r\n/g, '\n').
52
52
  replace(/\r/g, '\n').
53
53
  replace(/^ +$/gm, '');
54
54
  },
55
-
55
+
56
56
  removeExcessNewlines: function(text) {
57
57
  return text.replace(/\n{3,}/g, '\n\n');
58
58
  },
59
-
59
+
60
60
  archiveHtml: function(text) {
61
61
  var self = this;
62
-
62
+
63
63
  return text.replace(/\[html\]([\s\S]*?)\[\/html\]/gmi, function(wholeMatch, m1) {
64
64
  return self.addToArchive(m1);
65
65
  });
66
66
  },
67
-
67
+
68
68
  archiveCode: function(text) {
69
69
  var self = this;
70
-
70
+
71
71
  text = text.replace(/^-{3,}\n([\s\S]+?)\n-{3,}$/gm, function(wholeMatch, m1) {
72
72
  return self.addToArchive('<pre><code>' + m1 +'</code></pre>');
73
73
  });
74
-
74
+
75
75
  return text.replace(/`(?!\s)((?:\s*\S)+?)`/g, function(wholeMatch, m1) {
76
76
  return self.addToArchive('<code>' + m1 + '</code>');
77
77
  });
78
78
  },
79
-
79
+
80
80
  addToArchive: function(text) {
81
81
  var self = this;
82
-
82
+
83
83
  var index = self.archive.push(text) - 1;
84
84
  return '!a!r!c!h!i!v!e!' + index + '!a!r!c!h!i!v!e!'; // nobody's going to type that!
85
85
  },
86
-
86
+
87
87
  retrieveArchive: function(text) {
88
88
  var self = this;
89
-
89
+
90
90
  self.archive.each(function(content, index) {
91
91
  text = text.replace(new RegExp('!a!r!c!h!i!v!e!' + index + '!a!r!c!h!i!v!e!'), content); // the block is so gsub won't substitute \&
92
92
  });
93
93
  return text;
94
94
  },
95
-
95
+
96
96
  makeBlockquotes: function(text) {
97
97
  return text.replace(/^~{3,}\n([\s\S]+?)\n~{3,}$/gm, '\n\n<blockquote>\n\n$1\n\n</blockquote>\n\n');
98
98
  },
99
-
99
+
100
100
  makeHeadings: function(text) {
101
101
  return text.replace(/^(={1,6})(.+?)=*?$/gm, function(wholeMatch, m1, m2) {
102
102
  var depth = m1.length;
103
103
  return '\n\n<h' + depth + '>' + m2.trim() + '</h' + depth + '>\n\n';
104
104
  });
105
105
  },
106
-
106
+
107
107
  makeLists: function(text, baseLevel) {
108
108
  var self = this;
109
-
109
+
110
110
  if (baseLevel == undefined) {
111
111
  baseLevel = '';
112
112
  }
113
-
113
+
114
114
  return text.replace(new RegExp('^(' + regexpEscape(baseLevel) + '[\\*\\#])[\\*\\#]* [^\n]+?\n(?:\\1[\\*\\#]* (?:[^\n])+?\n)*', 'gm'), function(content, level) {
115
115
  content = self.makeLists(content, level);
116
116
  content = content.replace(new RegExp('^' + regexpEscape(level) + ' (.+)$', 'gm'), '<li>$1</li>');
117
117
  content = content.replace(/<\/li>\n<([uo])l>/gm, '<$1l>');
118
-
118
+
119
119
  if (level.slice(-1) == '*') { // its an unordered list
120
120
  content = '<ul>\n' + content + '</ul>';
121
121
  } else {
122
122
  content = '<ol>\n' + content + '</ol>';
123
123
  }
124
-
124
+
125
125
  if (baseLevel) {
126
126
  content += '</li>\n';
127
127
  } else {
128
128
  content += '\n';
129
129
  }
130
130
  return content;
131
- });
131
+ });
132
132
  },
133
-
133
+
134
134
  makeParagraphs: function(text) {
135
135
  var self = this;
136
-
136
+
137
137
  return text.replace(/^(?!<|!a!r!c!h!i!v!e!)([^\n]+\n)+\n/gm, function(content) {
138
138
  return '\n\n<p>\n' + self.makeBreaks(content.trim()) + '</p>\n\n';
139
139
  });
140
140
  },
141
-
141
+
142
142
  makeBreaks: function(text) {
143
143
  return text.replace(/([^\n])\n(?!\n)/gm, '$1<br />\n');
144
144
  },
145
-
145
+
146
146
  makeInlines: function(text) {
147
147
  var self = this;
148
-
148
+
149
149
  text = text.
150
150
  replace(/^((?: ?[\w\(\)']){3,}:) (?!\s*$)/gm, '<b>$1</b> '). // spaces are not allowed directly in front of the colon, there must be a space after it, and the rest of the line can't be blank
151
151
  replace(/!\((.+?)\)(?:\:([a-zA-Z0-9\_]+))?/g, function(wholeMatch, m1, m2) {
@@ -165,7 +165,7 @@ var Typeout = new Class({
165
165
  replace(/([a-z0-9\.\-\_\+]+)@((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)/gi, function(wholeMatch, address, subdomain, domain, tld) {
166
166
  return '<a href="mailto:' + self.addToArchive(address + '@' + subdomain + domain + tld) + '">' + self.addToArchive(address + '@' + subdomain + domain + tld) + '</a>';
167
167
  }).
168
- replace(/(https?:\/\/)?((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)((?:\/[a-z0-9\-\._=\?&;\%#]+)*\/?)/gi, function(wholeMatch, protocol, subdomain, domain, tld, file) {
168
+ replace(/(https?:\/\/)?((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)((?:\/(?:\.?[a-z0-9\-_=\?&;\%#]+)+)*\/?)/gi, function(wholeMatch, protocol, subdomain, domain, tld, file) {
169
169
  if (!protocol) {
170
170
  protocol = 'http://';
171
171
  }
@@ -179,77 +179,77 @@ var Typeout = new Class({
179
179
  ['^', 'sup'],
180
180
  ['~', 'sub']
181
181
  ];
182
-
182
+
183
183
  inlines.each(function(pair) {
184
184
  var char = regexpEscape(pair[0]);
185
185
  var tag = pair[1];
186
186
  text = text.replace(new RegExp(char + '(?!\\s)((?:\\s*\\S)+?)' + char, 'g'), '<' + tag + '>$1</' + tag + '>');
187
187
  });
188
-
188
+
189
189
  return text;
190
190
  }
191
191
  });
192
192
 
193
193
  var TypeoutPreview = new Class({
194
194
  Implements: Options,
195
-
195
+
196
196
  options: {
197
197
  frequency: 500
198
198
  },
199
-
199
+
200
200
  initialize: function(textArea, previewDiv, options) {
201
201
  var self = this;
202
-
202
+
203
203
  self.textArea = $(textArea);
204
204
  self.previewDiv = $(previewDiv);
205
-
205
+
206
206
  self.setOptions(options);
207
-
207
+
208
208
  self.typeOut = new Typeout;
209
209
  self.dirty = true;
210
210
  self.ready = false;
211
-
211
+
212
212
  self.textArea.addEvent('keyup', self.setDirty.bind(self));
213
213
  self.setReady();
214
214
  },
215
-
215
+
216
216
  setDirty: function() {
217
217
  var self = this;
218
-
218
+
219
219
  self.dirty = true;
220
220
  if (self.ready) {
221
221
  self.setUnReady();
222
222
  self.preview();
223
223
  }
224
224
  },
225
-
225
+
226
226
  setUnReady: function() {
227
227
  var self = this;
228
-
228
+
229
229
  self.ready = false;
230
230
  self.setReady.delay(self.options.frequency, self);
231
231
  },
232
-
232
+
233
233
  setReady: function() {
234
234
  var self = this;
235
-
235
+
236
236
  self.ready = true;
237
237
  if (self.dirty) {
238
238
  self.setUnReady();
239
239
  self.preview();
240
240
  }
241
241
  },
242
-
242
+
243
243
  render: function(text) {
244
244
  var self = this;
245
-
245
+
246
246
  self.typeOut.content = text;
247
247
  return self.typeOut.toHTML();
248
248
  },
249
-
249
+
250
250
  preview: function() {
251
251
  var self = this;
252
-
252
+
253
253
  self.previewDiv.set('html', self.render(self.textArea.value));
254
254
  self.dirty = false;
255
255
  }
@@ -257,17 +257,17 @@ var TypeoutPreview = new Class({
257
257
 
258
258
  TypeoutTemplatePreview = new Class({
259
259
  Extends: TypeoutPreview,
260
-
260
+
261
261
  initialize: function(textArea, previewDiv, template, options) {
262
262
  var self = this;
263
-
263
+
264
264
  self.template = template;
265
265
  self.parent(textArea, previewDiv, options);
266
266
  },
267
-
267
+
268
268
  render: function(content) {
269
269
  var self = this;
270
-
270
+
271
271
  self.template.tags.each(function(tag) {
272
272
  content = content.replace(RegExp(regexpEscape(tag.name), 'gi'), tag.example);
273
273
  });
data/lib/typeout.rb CHANGED
@@ -1,43 +1,44 @@
1
1
  require 'sanitize'
2
+ require 'erb'
2
3
 
3
4
  class Typeout < String
4
5
  VERSION = '1.4.5'
5
-
6
+
6
7
  include ERB::Util
7
-
8
+
8
9
  def self.convert(text, sanitize = true)
9
10
  self.new(text.to_s).to_html(sanitize)
10
11
  end
11
-
12
+
12
13
  def to_html(sanitize = true)
13
14
  @sanitize = sanitize
14
-
15
+
15
16
  text = self.dup
16
-
17
+
17
18
  text = clean_whitespace text
18
19
  text = "\n\n#{text}\n\n" # a few guaranteed newlines
19
-
20
+
20
21
  @archive = []
21
-
22
+
22
23
  text = archive_html text
23
-
24
+
24
25
  text = html_escape text
25
-
26
+
26
27
  text = archive_code text
27
28
  text = archive_blockquotes text
28
-
29
+
29
30
  text = make_headings text
30
31
  text = make_lists text
31
32
  text = make_paragraphs text
32
33
  text = make_inlines text
33
-
34
+
34
35
  text = remove_excess_newlines text
35
-
36
+
36
37
  text = retrieve_archive text
37
-
38
+
38
39
  text
39
40
  end
40
-
41
+
41
42
  def sanitize_html(text)
42
43
  if @sanitize
43
44
  Sanitize.clean(text, Sanitize::Config::RELAXED)
@@ -45,66 +46,66 @@ class Typeout < String
45
46
  text
46
47
  end
47
48
  end
48
-
49
+
49
50
  def clean_whitespace(text)
50
51
  text.gsub(/\r\n/, "\n").
51
52
  gsub(/\r/, "\n").
52
53
  gsub(/^ +$/, '')
53
54
  end
54
-
55
+
55
56
  def remove_excess_newlines(text)
56
57
  text.gsub(/\n{3,}/, "\n\n")
57
58
  end
58
-
59
+
59
60
  def archive_html(text)
60
61
  text.gsub(/\[html\](.*?)\[\/html\]/mi) { archive(sanitize_html($1)) }
61
62
  end
62
-
63
+
63
64
  def archive_code(text)
64
65
  text = text.gsub(/^-{3,}\n(.+?)\n-{3,}$/m) { archive("<pre><code>#{$1}</code></pre>") }
65
66
  text.gsub(/`(?!\s)((?:\s*\S)+?)`/) { archive("<code>#{$1}</code>") }
66
67
  end
67
-
68
+
68
69
  def archive_blockquotes(text)
69
70
  text.gsub(/^~{3,}\n(.+?)\n~{3,}$/m) do
70
71
  content = remove_excess_newlines(make_paragraphs(make_lists("\n\n#{$1}\n\n"))) # blockquotes support paragraphs and lists
71
72
  archive("<blockquote>#{content}</blockquote>")
72
73
  end
73
74
  end
74
-
75
+
75
76
  def archive(text)
76
77
  @archive << text
77
78
  "!a!r!c!h!i!v!e!#{@archive.length-1}!a!r!c!h!i!v!e!" # nobody's going to type that!
78
79
  end
79
-
80
+
80
81
  def retrieve_archive(text)
81
82
  @archive.each_with_index do |content, index|
82
83
  text = text.sub("!a!r!c!h!i!v!e!#{index}!a!r!c!h!i!v!e!") { content } # the block is so gsub won't substitute \&
83
84
  end
84
85
  text
85
86
  end
86
-
87
+
87
88
  def make_headings(text)
88
89
  text.gsub(/^(={1,6})(.+?)=*?$/) do
89
90
  depth = $1.length
90
91
  "\n\n<h#{depth}>#{$2.strip}</h#{depth}>\n\n"
91
92
  end
92
93
  end
93
-
94
+
94
95
  def make_lists(text, base_level = nil)
95
96
  text.gsub(/^(#{Regexp.escape(base_level.to_s)}[\*\#])[\*\#]* [^\n]+?\n(?:\1[\*\#]* (?:[^\n])+?\n)*/m) do |content|
96
97
  level = $1
97
-
98
+
98
99
  content = make_lists(content, level)
99
100
  content = content.gsub(/^#{Regexp.escape(level)} (.+)$/, '<li>\1</li>')
100
101
  content = content.gsub(/<\/li>\n<([uo])l>/m, '<\1l>')
101
-
102
+
102
103
  if level.last == "*" # its an unordered list
103
104
  content = "<ul>\n#{content}</ul>"
104
105
  else
105
106
  content = "<ol>\n#{content}</ol>"
106
107
  end
107
-
108
+
108
109
  if base_level
109
110
  content += "</li>\n"
110
111
  else
@@ -113,15 +114,15 @@ class Typeout < String
113
114
  content
114
115
  end
115
116
  end
116
-
117
+
117
118
  def make_paragraphs(text)
118
119
  text.gsub(/^(?!<|!a!r!c!h!i!v!e!)([^\n]+\n)+\n/m) { |content| "\n\n<p>\n#{make_breaks(content.strip)}</p>\n\n" }
119
120
  end
120
-
121
+
121
122
  def make_breaks(text)
122
123
  text.gsub(/([^\n])\n(?!\n)/m, "\\1<br />\n")
123
124
  end
124
-
125
+
125
126
  def make_inlines(text)
126
127
  text = text.
127
128
  gsub(/^((?: ?[\w\(\)']){3,}:) (?!\s*$)/, '<b>\1</b> '). # spaces are not allowed directly in front of the colon, there must be a space after it, and the rest of the line can't be blank
@@ -142,7 +143,7 @@ class Typeout < String
142
143
  gsub(/([a-z0-9\.\-\_\+]+)@((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)/i) do
143
144
  "<a href=\"mailto:#{archive($1 + '@' + $2 + $3 + $4)}\">#{archive($1 + '@' + $2 + $3 + $4)}</a>"
144
145
  end.
145
- gsub(/(https?:\/\/)?((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)((?:\/[a-z0-9\-\._=\?&;\%#]+)*\/?)/i) do
146
+ gsub(/(https?:\/\/)?((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)((?:\/(?:\.?[a-z0-9\-_=\?&;\%#]+)+)*\/?)/i) do # some of the magic in here is to not grab periods at the end of URLs
146
147
  if $1.nil?
147
148
  protocol = 'http://'
148
149
  else
@@ -150,7 +151,7 @@ class Typeout < String
150
151
  end
151
152
  "<a href=\"#{archive(protocol + $2 + $3 + $4 + $5)}\">#{archive(protocol + $2 + $3 + $4 + $5)}</a>"
152
153
  end
153
-
154
+
154
155
  inlines = [
155
156
  ['*', 'strong'],
156
157
  ['_', 'em'],
@@ -158,7 +159,7 @@ class Typeout < String
158
159
  ['^', 'sup'],
159
160
  ['~', 'sub']
160
161
  ]
161
-
162
+
162
163
  inlines.each do |char, tag|
163
164
  char = Regexp.escape(char)
164
165
  re = /#{char} # the opening character
@@ -170,7 +171,7 @@ class Typeout < String
170
171
  #re = /#{char}(.+?)#{char}/
171
172
  text.gsub!(re, "<#{tag}>\\1</#{tag}>")
172
173
  end
173
-
174
+
174
175
  text
175
176
  end
176
177
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typeout
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 4
9
- - 5
10
- version: 1.4.5
9
+ - 6
10
+ version: 1.4.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - Connor McKay
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-26 00:00:00 Z
18
+ date: 2013-09-15 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: sanitize
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  requirements: []
77
77
 
78
78
  rubyforge_project: typeout
79
- rubygems_version: 1.8.6
79
+ rubygems_version: 1.8.24
80
80
  signing_key:
81
81
  specification_version: 3
82
82
  summary: Dead simple plain text to HTML converter