card 1.16.14 → 1.16.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +4 -2
  4. data/lib/card/auth.rb +15 -10
  5. data/lib/card/codename.rb +25 -21
  6. data/lib/card/content.rb +100 -68
  7. data/lib/card/format.rb +158 -129
  8. data/lib/card/query.rb +15 -9
  9. data/lib/card/query/attributes.rb +41 -49
  10. data/lib/card/set.rb +15 -12
  11. data/lib/card/set_pattern.rb +4 -5
  12. data/lib/card/spec_helper.rb +54 -16
  13. data/lib/cardio.rb +43 -25
  14. data/mod/01_core/chunk/include.rb +1 -1
  15. data/mod/01_core/set/all/collection.rb +76 -73
  16. data/mod/01_core/set/all/content.rb +0 -4
  17. data/mod/01_core/set/all/fetch.rb +35 -42
  18. data/mod/01_core/set/all/name.rb +17 -7
  19. data/mod/01_core/set/all/pattern.rb +12 -11
  20. data/mod/01_core/set/all/permissions.rb +51 -42
  21. data/mod/01_core/set/all/phases.rb +2 -1
  22. data/mod/01_core/set/all/references.rb +2 -2
  23. data/mod/01_core/set/all/rules.rb +28 -35
  24. data/mod/01_core/set/all/subcards.rb +12 -12
  25. data/mod/01_core/set/all/tracked_attributes.rb +1 -1
  26. data/mod/01_core/set/all/type.rb +11 -11
  27. data/mod/01_core/set/all/utils.rb +6 -1
  28. data/mod/01_core/spec/set/all/fetch_spec.rb +6 -6
  29. data/mod/01_core/spec/set/all/permissions_spec.rb +11 -11
  30. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
  31. data/mod/01_history/lib/card/action.rb +52 -47
  32. data/mod/01_history/set/all/actions.rb +20 -16
  33. data/mod/01_history/set/all/history.rb +18 -13
  34. data/mod/02_basic_types/set/all/base.rb +23 -2
  35. data/mod/02_basic_types/set/type/pointer.rb +45 -36
  36. data/mod/02_basic_types/spec/set/all/base_spec.rb +40 -24
  37. data/mod/02_basic_types/spec/set/type/pointer_spec.rb +87 -0
  38. data/mod/03_machines/set/right/machine_output.rb +10 -6
  39. data/mod/04_settings/set/abstract/permission.rb +10 -5
  40. data/mod/04_settings/set/type/setting.rb +4 -1
  41. data/mod/05_email/set/all/follow.rb +39 -44
  42. data/mod/05_email/set/all/notify.rb +4 -1
  43. data/mod/05_email/set/right/followers.rb +16 -14
  44. data/mod/05_email/set/self/follow_defaults.rb +22 -19
  45. data/mod/05_standard/lib/carrier_wave/cardmount.rb +1 -0
  46. data/mod/05_standard/set/abstract/attachment.rb +85 -58
  47. data/mod/05_standard/set/all/comment.rb +35 -19
  48. data/mod/05_standard/set/all/error.rb +124 -98
  49. data/mod/05_standard/set/all/list_changes.rb +27 -22
  50. data/mod/05_standard/set/all/rich_html/editing.rb +96 -70
  51. data/mod/05_standard/set/all/rich_html/form.rb +123 -81
  52. data/mod/05_standard/set/all/rich_html/modal.rb +15 -58
  53. data/mod/05_standard/set/right/account.rb +2 -2
  54. data/mod/05_standard/set/right/email.rb +3 -2
  55. data/mod/05_standard/set/rstar/rules.rb +3 -3
  56. data/mod/05_standard/set/self/search.rb +45 -22
  57. data/mod/05_standard/set/type/cardtype.rb +13 -11
  58. data/mod/05_standard/set/type/listed_by.rb +3 -2
  59. data/mod/05_standard/set/type/set.rb +17 -13
  60. data/mod/05_standard/set/type/signup.rb +1 -2
  61. data/mod/05_standard/set/type/user.rb +1 -1
  62. data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
  63. data/mod/05_standard/spec/set/all/history_spec.rb +1 -1
  64. data/mod/05_standard/spec/set/type/email_template_spec.rb +140 -134
  65. data/mod/05_standard/spec/set/type/image_spec.rb +2 -1
  66. data/mod/05_standard/spec/set/type/signup_spec.rb +2 -2
  67. data/spec/models/card/trash_spec.rb +1 -1
  68. data/spec/spec_helper.rb +0 -1
  69. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5bff967a00719608171fe172a88f9e1d6771217a
4
- data.tar.gz: 4d71791152c3662e0412e41986a395171bd457e3
3
+ metadata.gz: 7fb48f7c5eaa598c5193c212c044e187141188a8
4
+ data.tar.gz: e665cf776166d89cc00abdca8c2b51dab22db866
5
5
  SHA512:
6
- metadata.gz: 86f5d9f8cb45509e260ffc05f38c2fb6af60c5f855ef90d285df72ffe18b4ce94aeeb4a4e8bb89397bec239bc97aecfd1026a758c1fa16e388156866019c1e63
7
- data.tar.gz: 4fc615ab61f11cbe7afba28a165430e8bc833651e1cf537181963fffaf74cafea1f90a89a01b87658d0f7579ea659102cb9980f7bb7860c50ec3a74573d6413a
6
+ metadata.gz: 6a43a81fe986265ecd892f73f7c7e71726c02c038755dcb046d4c9f08fec8920bfc7e5c97063c1c890268810b1c0dae6afa2bfb9255e112df426f06d212a3185
7
+ data.tar.gz: bb876b6fc2b96a645747115ade4f95676b6f77ba0c6c450658eeafbfcea1b8377e349c3cadf67c3466e968facfc6be0609e2323bccc982cddd94e2f1ba538cd1
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.16.14
1
+ 1.16.15
@@ -2,8 +2,10 @@
2
2
 
3
3
  class AttachmentUploadCards < Card::CoreMigration
4
4
  def up
5
- Card.create! name: '*new file', type: 'File', codename: 'new_file'
6
- Card.create! name: '*new image', type: 'Image', codename: 'new_image'
5
+ Card.create! name: '*new file', type: 'File',
6
+ codename: 'new_file', empty_ok: true
7
+ Card.create! name: '*new image', type: 'Image',
8
+ codename: 'new_image', empty_ok: true
7
9
 
8
10
  if js_output = Card['*all+*script+*machine output']
9
11
  #perhaps too narrow?
@@ -54,8 +54,9 @@ class Card
54
54
  def find_by_token token
55
55
  Auth.as_bot do
56
56
  Card.search(
57
- right_id: Card::AccountID,
58
- right_plus: [{ id: Card::TokenID }, { content: token.strip }]
57
+ { right_id: Card::AccountID,
58
+ right_plus: [{ id: Card::TokenID }, { content: token.strip }]
59
+ }, 'find +*account card by token'
59
60
  ).first
60
61
  end
61
62
  end
@@ -70,8 +71,9 @@ class Card
70
71
  email = email.strip.downcase
71
72
  Auth.as_bot do
72
73
  Card.search(
73
- right_id: Card::AccountID,
74
- right_plus: [{ id: Card::EmailID }, { content: email }]
74
+ { right_id: Card::AccountID,
75
+ right_plus: [{ id: Card::EmailID }, { content: email }]
76
+ }, "find +*account for email(#{email})"
75
77
  ).first
76
78
  end
77
79
  end
@@ -211,12 +213,15 @@ class Card
211
213
  # PERMISSIONS
212
214
 
213
215
  def createable_types
214
- type_names = Auth.as_bot do
215
- Card.search type: Card::CardtypeID, return: :name,
216
- not: {
217
- codename: ['in'] + Card.config.non_createable_types
218
- }
219
- end
216
+ type_names =
217
+ Auth.as_bot do
218
+ Card.search(
219
+ { type: Card::CardtypeID, return: :name,
220
+ not: { codename: ['in'] + Card.config.non_createable_types } },
221
+ 'find createable types'
222
+ )
223
+ end
224
+
220
225
  type_names.select do |name|
221
226
  Card.new(type: name).ok? :create
222
227
  end.sort
@@ -4,16 +4,14 @@ require_dependency 'card/name'
4
4
 
5
5
  class Card
6
6
  class Codename
7
-
8
- @@codehash=nil
7
+ @@codehash = nil
9
8
 
10
9
  class << self
11
10
  # returns codename for id and vice versa. not in love with this api --efm
12
11
  def [] key
13
- if !key.nil?
14
- key = key.to_sym unless Integer===key
15
- codehash[key]
16
- end
12
+ return if key.nil?
13
+ key = key.to_sym unless key.is_a? Integer
14
+ codehash[key]
17
15
  end
18
16
 
19
17
  def codehash
@@ -25,41 +23,48 @@ class Card
25
23
  cache.write 'CODEHASH', nil
26
24
  end
27
25
 
28
- #only used in migration
26
+ # only used in migration
29
27
  def bootdata hash
30
28
  @@codehash = hash
31
29
  end
32
30
 
33
-
34
31
  private
35
32
 
36
33
  def cache
37
34
  Card::Cache[Codename]
38
35
  end
39
36
 
37
+ def each_codenamed_card
38
+ sql = 'select id, codename from cards where codename is not NULL'
39
+ ActiveRecord::Base.connection.select_all(sql).each do |row|
40
+ yield row['codename'].to_sym, row['id'].to_i
41
+ end
42
+ end
43
+
44
+ def check_duplicates codehash, codename, card_id
45
+ # FIXME: remove duplicate checks here; should be caught upon creation
46
+ return unless codehash.has_key?(codename) || codehash.has_key?(card_id)
47
+ warn "dup code ID:#{card_id} (#{codehash[codename]}), " \
48
+ "CD:#{codename} (#{codehash[card_id]})"
49
+ end
50
+
40
51
  def load_hash
41
52
  @@codehash = cache.read('CODEHASH') || begin
42
53
  codehash = {}
43
- sql = 'select id, codename from cards where codename is not NULL'
44
- ActiveRecord::Base.connection.select_all(sql).each do |row|
45
- #FIXME: remove duplicate checks, put them in other tools
46
- code, cid = row['codename'].to_sym, row['id'].to_i
47
- if codehash.has_key?(code) or codehash.has_key?(cid)
48
- warn "dup code ID:#{cid} (#{codehash[code]}), CD:#{code} (#{codehash[cid]})"
49
- end
50
- codehash[code] = cid; codehash[cid] = code
54
+ each_codenamed_card do |codename, card_id|
55
+ check_duplicates codehash, codename, card_id
56
+ codehash[codename] = card_id
57
+ codehash[card_id] = codename
51
58
  end
52
59
  cache.write 'CODEHASH', codehash
53
60
  end
54
61
  end
55
62
  end
56
-
57
63
  end
58
64
 
59
-
60
65
  def self.const_missing const
61
- if const.to_s =~ /^([A-Z]\S*)ID$/ and code=$1.underscore.to_sym
62
- if card_id = Codename[code]
66
+ if const.to_s =~ /^([A-Z]\S*)ID$/ && (code = $1.underscore.to_sym)
67
+ if (card_id = Codename[code])
63
68
  const_set const, card_id
64
69
  else
65
70
  raise "Missing codename #{code} (#{const})"
@@ -68,5 +73,4 @@ class Card
68
73
  super
69
74
  end
70
75
  end
71
-
72
76
  end
@@ -1,6 +1,6 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
- # TODO move Card::Chunk to Card::Content::Chunk...
3
+ # TODO: move Card::Chunk to Card::Content::Chunk...
4
4
  require_dependency 'card/chunk'
5
5
 
6
6
  class Card
@@ -9,7 +9,7 @@ class Card
9
9
 
10
10
  def initialize content, format_or_card, opts={}
11
11
  @format =
12
- if Card===format_or_card
12
+ if format_or_card.is_a?(Card)
13
13
  Format.new format_or_card, format: nil
14
14
  else
15
15
  format_or_card
@@ -32,10 +32,10 @@ class Card
32
32
 
33
33
  def to_s
34
34
  case __getobj__
35
- when Array; map(&:to_s)*''
36
- when String; __getobj__
37
- when NilClass; '' #raise "Nil Card::Content"
38
- else __getobj__.to_s
35
+ when Array then map(&:to_s) * ''
36
+ when String then __getobj__
37
+ when NilClass then '' # raise "Nil Card::Content"
38
+ else __getobj__.to_s
39
39
  end
40
40
  end
41
41
 
@@ -46,16 +46,17 @@ class Card
46
46
  def each_chunk
47
47
  return enum_for(:each_chunk) unless block_given?
48
48
  case __getobj__
49
- when Hash; each { |k,v| yield v if Chunk::Abstract===v }
50
- when Array; each { |e| yield e if Chunk::Abstract===e }
51
- when String; # strings are all parsed in self, so no chunks in a String
52
- else
53
- Rails.logger.warn "error self is unrecognized type #{self.class} #{self.__getobj__.class}"
49
+ when Hash then each_value { |v| yield v if v.is_a?(Chunk::Abstract) }
50
+ when Array then each { |e| yield e if e.is_a?(Chunk::Abstract) }
51
+ when String # noop. strings are parsed in self, so no chunks in a String
52
+ else
53
+ Rails.logger.warn msg, 'error self is unrecognized type'\
54
+ " #{self.class} #{__getobj__.class}"
54
55
  end
55
56
  end
56
57
 
57
58
  def find_chunks chunk_type
58
- each_chunk.select { |chunk| chunk.kind_of?(chunk_type) }
59
+ each_chunk.select { |chunk| chunk.is_a?(chunk_type) }
59
60
  end
60
61
 
61
62
  def process_content_object &block
@@ -66,45 +67,65 @@ class Card
66
67
  def parse_content content
67
68
  @chunks = []
68
69
 
69
- if String===content
70
+ if content.is_a? String
70
71
  position = last_position = 0
71
72
  prefix_regexp = Chunk.get_prefix_regexp chunk_list
72
73
  interval_string = ''
73
74
 
74
- while prefix_match = content[position..-1].match( prefix_regexp )
75
- prefix = prefix_match[0] # prefix of matched chunk
76
- chunk_start = prefix_match.begin(0) + position # content index of beginning of chunk
77
-
78
- if prefix_match.begin(0) > 0 # if matched chunk is not beginning of test string
79
- interval_string += content[ position..chunk_start-1 ] # hold onto the non-chunk part of the string
75
+ while (prefix_match = content[position..-1].match(prefix_regexp))
76
+ prefix = prefix_match[0]
77
+ # prefix of matched chunk
78
+ chunk_start = prefix_match.begin(0) + position
79
+ # content index of beginning of chunk
80
+ if prefix_match.begin(0) > 0
81
+ # if matched chunk is not beginning of test string
82
+ interval_string += content[position..chunk_start - 1]
83
+ # hold onto the non-chunk part of the string
80
84
  end
81
85
 
82
- chunk_class = Chunk.find_class_by_prefix prefix # get the chunk class from the prefix
83
- match, offset = chunk_class.full_match content[chunk_start..-1], prefix # see whether the full chunk actually matches (as opposed to bogus prefix)
84
- context_ok = chunk_class.context_ok? content, chunk_start # make sure there aren't contextual reasons for ignoring this chunk
85
- position = chunk_start # move scanning position up to beginning of chunk
86
-
87
- if match # we have a chunk match
88
- position += ( match.end(0) - offset.to_i ) # move scanning position up to end of chunk
89
- if context_ok #
90
- @chunks << interval_string if interval_string.size > 0 # add the nonchunk string to the chunk list
91
- @chunks << chunk_class.new( match, self ) # add the chunk to the chunk list
92
- interval_string = '' # reset interval string for next go-round
93
- last_position = position # note that the end of the chunk was the last place where a chunk was found (so far)
86
+ chunk_class = Chunk.find_class_by_prefix prefix
87
+ # get the chunk class from the prefix
88
+ match, offset =
89
+ chunk_class.full_match content[chunk_start..-1], prefix
90
+ # see whether the full chunk actually matches
91
+ # (as opposed to bogus prefix)
92
+ context_ok = chunk_class.context_ok? content, chunk_start
93
+ # make sure there aren't contextual reasons for ignoring this chunk
94
+ position = chunk_start
95
+ # move scanning position up to beginning of chunk
96
+
97
+ if match
98
+ # we have a chunk match
99
+ position += (match.end(0) - offset.to_i)
100
+ # move scanning position up to end of chunk
101
+ if context_ok
102
+ @chunks << interval_string if interval_string.size > 0
103
+ # add the nonchunk string to the chunk list
104
+ @chunks << chunk_class.new(match, self)
105
+ # add the chunk to the chunk list
106
+ interval_string = ''
107
+ # reset interval string for next go-round
108
+ last_position = position
109
+ # note that the end of the chunk was the last place where a
110
+ # chunk was found (so far)
94
111
  end
95
112
  else
96
- position += 1 # no match. look at the next character
113
+ position += 1
114
+ # no match. look at the next character
97
115
  end
98
116
 
99
117
  if !match || !context_ok
100
- interval_string += content[chunk_start..position-1] # moving beyond the alleged chunk. append failed string to "nonchunk" string
118
+ interval_string += content[chunk_start..position - 1]
119
+ # moving beyond the alleged chunk.
120
+ # append failed string to "nonchunk" string
101
121
  end
102
122
  end
103
123
  end
104
124
 
105
125
  if chunks.any?
106
126
  if last_position < content.size
107
- remainder = content[ last_position..-1] # handle any leftover nonchunk string at the end of content
127
+ remainder = content[last_position..-1]
128
+ # handle any leftover nonchunk string at the end of content
108
129
  @chunks << remainder
109
130
  end
110
131
  chunks
@@ -113,9 +134,6 @@ class Card
113
134
  end
114
135
  end
115
136
 
116
-
117
-
118
-
119
137
  ALLOWED_TAGS = {}
120
138
  %w{
121
139
  br i b pre cite caption strong em ins sup sub del ol hr ul li p
@@ -124,7 +142,7 @@ class Card
124
142
 
125
143
  # allowed attributes
126
144
  ALLOWED_TAGS.merge!(
127
- 'a' => ['href', 'title', 'target' ],
145
+ 'a' => ['href', 'title', 'target'],
128
146
  'img' => ['src', 'alt', 'title'],
129
147
  'code' => ['lang'],
130
148
  'blockquote' => ['cite']
@@ -134,85 +152,99 @@ class Card
134
152
  ALLOWED_TAGS['table'] += %w[ cellpadding align border cellspacing ]
135
153
  end
136
154
 
137
- ALLOWED_TAGS.each_key {|k|
155
+ ALLOWED_TAGS.each_key do |k|
138
156
  ALLOWED_TAGS[k] << 'class'
139
157
  ALLOWED_TAGS[k] << 'style' if Card.config.allow_inline_styles
140
158
  ALLOWED_TAGS[k]
141
- }
159
+ end
142
160
  ALLOWED_TAGS
143
161
 
144
- ATTR_VALUE_RE = [ /(?<=^')[^']+(?=')/, /(?<=^")[^"]+(?=")/, /\S+/ ]
162
+ ATTR_VALUE_RE = [/(?<=^')[^']+(?=')/, /(?<=^")[^"]+(?=")/, /\S+/]
145
163
 
146
164
  class << self
147
-
148
165
  ## Method that cleans the String of HTML tags
149
166
  ## and attributes outside of the allowed list.
150
167
 
151
168
  # this has been hacked for card to allow classes if
152
169
  # the class begins with "w-"
153
- def clean!( string, tags = ALLOWED_TAGS )
154
- string.gsub( /<(\/*)(\w+)([^>]*)>/ ) do
170
+ def clean!(string, tags=ALLOWED_TAGS)
171
+ string.gsub(/<(\/*)(\w+)([^>]*)>/) do
155
172
  raw = $~
156
173
  tag = raw[2].downcase
157
- if attrs = tags[tag]
158
- "<#{raw[1]}#{
174
+ if (attrs = tags[tag])
175
+ html_attribs =
159
176
  attrs.inject([tag]) do |pcs, attr|
160
- q='"'
161
- rest_value=nil
177
+ q = '"'
178
+ rest_value = nil
162
179
  if raw[3] =~ /\b#{attr}\s*=\s*(?=(.))/i
163
180
  rest_value = $'
164
- idx = %w{' "}.index($1) and q = $1
165
- re = ATTR_VALUE_RE[ idx || 2 ]
166
- if match = rest_value.match(re)
181
+ (idx = %w{' "}.index($1)) && (q = $1)
182
+ re = ATTR_VALUE_RE[idx || 2]
183
+ if (match = rest_value.match(re))
167
184
  rest_value = match[0]
168
185
  if attr == 'class'
169
- rest_value = rest_value.split(/\s+/).find_all {|s| s=~/^w-/i}*' '
186
+ rest_value =
187
+ rest_value.split(/\s+/).select do |s|
188
+ s =~ /^w-/i
189
+ end * ' '
170
190
  end
171
191
  end
172
192
  end
173
193
  pcs << "#{attr}=#{q}#{rest_value}#{q}" unless rest_value.blank?
174
194
  pcs
175
195
  end * ' '
176
- }>"
196
+ "<#{raw[1]}#{html_attribs}>"
177
197
  else
178
- " "
198
+ ' '
179
199
  end
180
200
  end.gsub(/<\!--.*?-->/, '')
181
201
  end
182
202
 
183
203
  if Card.config.space_last_in_multispace
184
- def clean_with_space_last! string, tags = ALLOWED_TAGS
185
- clean_without_space_last!(string, tags).gsub(/(?:^|\b) ((?:&nbsp;)+)/, '\1 ')
204
+ def clean_with_space_last! string, tags=ALLOWED_TAGS
205
+ cwo = clean_without_space_last!(string, tags)
206
+ cwo.gsub(/(?:^|\b) ((?:&nbsp;)+)/, '\1 ')
186
207
  end
187
208
  alias_method_chain :clean!, :space_last
188
209
  end
189
- def truncatewords_with_closing_tags(input, words = 25, truncate_string = "...")
210
+
211
+ def truncatewords_with_closing_tags input, words=25, truncate_string='...'
190
212
  if input.nil? then return end
191
213
  wordlist = input.to_s.split
192
214
  l = words.to_i - 1
193
215
  l = 0 if l < 0
194
- wordstring = wordlist.length > l ? wordlist[0..l].join(" ") : input.to_s
216
+ wordstring = wordlist.length > l ? wordlist[0..l].join(' ') : input.to_s
195
217
  # nuke partial tags at end of snippet
196
- wordstring.gsub!(/(<[^\>]+)$/,'')
218
+ wordstring.gsub!(/(<[^\>]+)$/, '')
197
219
 
198
220
  tags = []
199
221
 
200
222
  # match tags with or without self closing (ie. <foo />)
201
- wordstring.scan(/\<([^\>\s\/]+)[^\>]*?\>/).each { |t| tags.unshift(t[0]) }
223
+ wordstring.scan(/\<([^\>\s\/]+)[^\>]*?\>/).each do |t|
224
+ tags.unshift(t[0])
225
+ end
202
226
  # match tags with self closing and mark them as closed
203
- wordstring.scan(/\<([^\>\s\/]+)[^\>]*?\/\>/).each { |t| if !(x=tags.index(t[0])).nil? then tags.slice!(x) end }
227
+ wordstring.scan(/\<([^\>\s\/]+)[^\>]*?\/\>/).each do |t|
228
+ if !(x = tags.index(t[0])).nil? then tags.slice!(x) end
229
+ end
204
230
  # match close tags
205
- wordstring.scan(/\<\/([^\>\s\/]+)[^\>]*?\>/).each { |t| if !(x=tags.rindex(t[0])).nil? then tags.slice!(x) end }
231
+ wordstring.scan(/\<\/([^\>\s\/]+)[^\>]*?\>/).each do |t|
232
+ if !(x = tags.rindex(t[0])).nil? then tags.slice!(x) end
233
+ end
206
234
 
207
- tags.each {|t| wordstring += "</#{t}>" }
235
+ tags.each { |t| wordstring += "</#{t}>" }
208
236
 
209
- wordstring +='<span class="closed-content-ellipses">...</span>' if wordlist.length > l
210
- # wordstring += '...' if wordlist.length > l
211
- wordstring.gsub! /<[\/]?br[\s\/]*>/, ' ' ## Also a hack -- get rid of <br>'s -- they make line view ugly.
212
- wordstring.gsub! /<[\/]?p[^>]*>/, ' ' ## Also a hack -- get rid of <br>'s -- they make line view ugly.
237
+ if wordlist.length > l
238
+ wordstring += '<span class="closed-content-ellipses">...</span>'
239
+ end
240
+
241
+ # wordstring += '...' if wordlist.length > l
242
+ wordstring.gsub! /<[\/]?br[\s\/]*>/, ' '
243
+ # Also a hack -- get rid of <br>'s -- they make line view ugly.
244
+ wordstring.gsub! /<[\/]?p[^>]*>/, ' '
245
+ ## Also a hack -- get rid of <br>'s -- they make line view ugly.
213
246
  wordstring
214
247
  end
215
-
216
248
  end
217
249
  end
218
250
  end