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