card 1.16.14 → 1.16.15

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