card 1.16.14 → 1.16.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +4 -2
- data/lib/card/auth.rb +15 -10
- data/lib/card/codename.rb +25 -21
- data/lib/card/content.rb +100 -68
- data/lib/card/format.rb +158 -129
- data/lib/card/query.rb +15 -9
- data/lib/card/query/attributes.rb +41 -49
- data/lib/card/set.rb +15 -12
- data/lib/card/set_pattern.rb +4 -5
- data/lib/card/spec_helper.rb +54 -16
- data/lib/cardio.rb +43 -25
- data/mod/01_core/chunk/include.rb +1 -1
- data/mod/01_core/set/all/collection.rb +76 -73
- data/mod/01_core/set/all/content.rb +0 -4
- data/mod/01_core/set/all/fetch.rb +35 -42
- data/mod/01_core/set/all/name.rb +17 -7
- data/mod/01_core/set/all/pattern.rb +12 -11
- data/mod/01_core/set/all/permissions.rb +51 -42
- data/mod/01_core/set/all/phases.rb +2 -1
- data/mod/01_core/set/all/references.rb +2 -2
- data/mod/01_core/set/all/rules.rb +28 -35
- data/mod/01_core/set/all/subcards.rb +12 -12
- data/mod/01_core/set/all/tracked_attributes.rb +1 -1
- data/mod/01_core/set/all/type.rb +11 -11
- data/mod/01_core/set/all/utils.rb +6 -1
- data/mod/01_core/spec/set/all/fetch_spec.rb +6 -6
- data/mod/01_core/spec/set/all/permissions_spec.rb +11 -11
- data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
- data/mod/01_history/lib/card/action.rb +52 -47
- data/mod/01_history/set/all/actions.rb +20 -16
- data/mod/01_history/set/all/history.rb +18 -13
- data/mod/02_basic_types/set/all/base.rb +23 -2
- data/mod/02_basic_types/set/type/pointer.rb +45 -36
- data/mod/02_basic_types/spec/set/all/base_spec.rb +40 -24
- data/mod/02_basic_types/spec/set/type/pointer_spec.rb +87 -0
- data/mod/03_machines/set/right/machine_output.rb +10 -6
- data/mod/04_settings/set/abstract/permission.rb +10 -5
- data/mod/04_settings/set/type/setting.rb +4 -1
- data/mod/05_email/set/all/follow.rb +39 -44
- data/mod/05_email/set/all/notify.rb +4 -1
- data/mod/05_email/set/right/followers.rb +16 -14
- data/mod/05_email/set/self/follow_defaults.rb +22 -19
- data/mod/05_standard/lib/carrier_wave/cardmount.rb +1 -0
- data/mod/05_standard/set/abstract/attachment.rb +85 -58
- data/mod/05_standard/set/all/comment.rb +35 -19
- data/mod/05_standard/set/all/error.rb +124 -98
- data/mod/05_standard/set/all/list_changes.rb +27 -22
- data/mod/05_standard/set/all/rich_html/editing.rb +96 -70
- data/mod/05_standard/set/all/rich_html/form.rb +123 -81
- data/mod/05_standard/set/all/rich_html/modal.rb +15 -58
- data/mod/05_standard/set/right/account.rb +2 -2
- data/mod/05_standard/set/right/email.rb +3 -2
- data/mod/05_standard/set/rstar/rules.rb +3 -3
- data/mod/05_standard/set/self/search.rb +45 -22
- data/mod/05_standard/set/type/cardtype.rb +13 -11
- data/mod/05_standard/set/type/listed_by.rb +3 -2
- data/mod/05_standard/set/type/set.rb +17 -13
- data/mod/05_standard/set/type/signup.rb +1 -2
- data/mod/05_standard/set/type/user.rb +1 -1
- data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
- data/mod/05_standard/spec/set/all/history_spec.rb +1 -1
- data/mod/05_standard/spec/set/type/email_template_spec.rb +140 -134
- data/mod/05_standard/spec/set/type/image_spec.rb +2 -1
- data/mod/05_standard/spec/set/type/signup_spec.rb +2 -2
- data/spec/models/card/trash_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fb48f7c5eaa598c5193c212c044e187141188a8
|
4
|
+
data.tar.gz: e665cf776166d89cc00abdca8c2b51dab22db866
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a43a81fe986265ecd892f73f7c7e71726c02c038755dcb046d4c9f08fec8920bfc7e5c97063c1c890268810b1c0dae6afa2bfb9255e112df426f06d212a3185
|
7
|
+
data.tar.gz: bb876b6fc2b96a645747115ade4f95676b6f77ba0c6c450658eeafbfcea1b8377e349c3cadf67c3466e968facfc6be0609e2323bccc982cddd94e2f1ba538cd1
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.16.
|
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',
|
6
|
-
|
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?
|
data/lib/card/auth.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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 =
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
data/lib/card/codename.rb
CHANGED
@@ -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
|
14
|
-
|
15
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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$/
|
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
|
data/lib/card/content.rb
CHANGED
@@ -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
|
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
|
36
|
-
when String
|
37
|
-
when NilClass
|
38
|
-
else
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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.
|
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
|
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(
|
75
|
-
prefix = prefix_match[0]
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
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]
|
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[
|
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
|
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 = [
|
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!(
|
154
|
-
string.gsub(
|
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
|
-
|
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)
|
165
|
-
re = ATTR_VALUE_RE[
|
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 =
|
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
|
185
|
-
clean_without_space_last!(string, tags)
|
204
|
+
def clean_with_space_last! string, tags=ALLOWED_TAGS
|
205
|
+
cwo = clean_without_space_last!(string, tags)
|
206
|
+
cwo.gsub(/(?:^|\b) ((?: )+)/, '\1 ')
|
186
207
|
end
|
187
208
|
alias_method_chain :clean!, :space_last
|
188
209
|
end
|
189
|
-
|
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(
|
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
|
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
|
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
|
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
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|