typeout 1.4.5 → 1.4.6

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 (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