redmine_api_helper 0.3.35
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.
Potentially problematic release.
This version of redmine_api_helper might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitattributes +2 -0
- data/.gitignore +11 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +339 -0
- data/README.md +30 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/date_helper/date.rb +311 -0
- data/lib/odf_writer/bookmark.rb +110 -0
- data/lib/odf_writer/bookmark_reader.rb +77 -0
- data/lib/odf_writer/document.rb +371 -0
- data/lib/odf_writer/field.rb +174 -0
- data/lib/odf_writer/field_reader.rb +78 -0
- data/lib/odf_writer/image.rb +176 -0
- data/lib/odf_writer/image_reader.rb +76 -0
- data/lib/odf_writer/images.rb +89 -0
- data/lib/odf_writer/list_style.rb +336 -0
- data/lib/odf_writer/nested.rb +156 -0
- data/lib/odf_writer/odf_helper.rb +57 -0
- data/lib/odf_writer/parser/default.rb +691 -0
- data/lib/odf_writer/path_finder.rb +114 -0
- data/lib/odf_writer/section.rb +120 -0
- data/lib/odf_writer/section_reader.rb +61 -0
- data/lib/odf_writer/style.rb +483 -0
- data/lib/odf_writer/table.rb +135 -0
- data/lib/odf_writer/table_reader.rb +61 -0
- data/lib/odf_writer/template.rb +234 -0
- data/lib/odf_writer/text.rb +97 -0
- data/lib/odf_writer/text_reader.rb +77 -0
- data/lib/odf_writer/version.rb +29 -0
- data/lib/redmine_api_helper/api_helper.rb +333 -0
- data/lib/redmine_api_helper/args_helper.rb +106 -0
- data/lib/redmine_api_helper/attachments_api_helper.rb +52 -0
- data/lib/redmine_api_helper/define_api_helpers.rb +78 -0
- data/lib/redmine_api_helper/document_categories_api_helper.rb +38 -0
- data/lib/redmine_api_helper/groups_api_helper.rb +80 -0
- data/lib/redmine_api_helper/helpers.rb +50 -0
- data/lib/redmine_api_helper/issue_priorities_api_helper.rb +38 -0
- data/lib/redmine_api_helper/issue_relations_api_helper.rb +66 -0
- data/lib/redmine_api_helper/issue_statuses_api_helper.rb +36 -0
- data/lib/redmine_api_helper/issues_api_helper.rb +124 -0
- data/lib/redmine_api_helper/my_account_api_helper.rb +45 -0
- data/lib/redmine_api_helper/news_api_helper.rb +73 -0
- data/lib/redmine_api_helper/project_memberships_api_helper.rb +77 -0
- data/lib/redmine_api_helper/projects_api_helper.rb +73 -0
- data/lib/redmine_api_helper/roles_api_helper.rb +52 -0
- data/lib/redmine_api_helper/scripts_api_helper.rb +87 -0
- data/lib/redmine_api_helper/search_api_helper.rb +38 -0
- data/lib/redmine_api_helper/time_entries_api_helper.rb +73 -0
- data/lib/redmine_api_helper/time_entry_activities_api_helper.rb +38 -0
- data/lib/redmine_api_helper/trackers_api_helper.rb +38 -0
- data/lib/redmine_api_helper/users_api_helper.rb +73 -0
- data/lib/redmine_api_helper/version.rb +24 -0
- data/lib/redmine_api_helper/wiki_pages_api_helper.rb +66 -0
- data/lib/redmine_api_helper.rb +88 -0
- data/redmine_api_helper.gemspec +36 -0
- metadata +162 -0
@@ -0,0 +1,311 @@
|
|
1
|
+
##
|
2
|
+
# encoding: utf-8
|
3
|
+
#
|
4
|
+
# Extension for Date to calculate a forward date with compressed syntax
|
5
|
+
#
|
6
|
+
# Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or
|
9
|
+
# modify it under the terms of the GNU General Public License
|
10
|
+
# as published by the Free Software Foundation; either version 2
|
11
|
+
# of the License, or (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program; if not, write to the Free Software
|
20
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
21
|
+
#
|
22
|
+
|
23
|
+
class Date
|
24
|
+
|
25
|
+
####################################################################################
|
26
|
+
#
|
27
|
+
# Date.today.calc(<rule>) -> [<new_date>, <new_rule>]
|
28
|
+
# Date.today.forward(<rule) -> <new_date>
|
29
|
+
#
|
30
|
+
# <rule>: [DWmMqY][n][FMLWX][-!W*]
|
31
|
+
#
|
32
|
+
# 1. parameter: epoch-identifier (necessary)
|
33
|
+
#
|
34
|
+
# D - stands for _D_ays
|
35
|
+
# W - stands for _W_eeks
|
36
|
+
# m - stands for _m_ondays
|
37
|
+
# M - stands for _M_onths
|
38
|
+
# q - stands for _q_uarters
|
39
|
+
# Y - stands for _Y_ears
|
40
|
+
#
|
41
|
+
# 2. parameter: integer (necessary)
|
42
|
+
#
|
43
|
+
# n - stands for the number of epochs
|
44
|
+
#
|
45
|
+
# 3. position of day within epoch
|
46
|
+
#
|
47
|
+
# F - stands for _F_irst day of epoch, like first day of month, monday, first day of
|
48
|
+
# quarter, or January 1st
|
49
|
+
# M - stands for _M_id of epoch, like 15th day of month, wednesday, 15th of
|
50
|
+
# mid-of-quarter or June 30th
|
51
|
+
# L - stands for _L_ast of epoch, like last day of month, friday (last working day),
|
52
|
+
# last day of quarter or December 31st
|
53
|
+
# W - stands for _W_eekday (Monday), if calculated day falls on a Saturday or Sunday
|
54
|
+
# X - stands for no correction
|
55
|
+
#
|
56
|
+
# 3. control of date calculation
|
57
|
+
#
|
58
|
+
# - - the sign "-" is a killswitch. After one date calculation the resubmission rule is
|
59
|
+
# deleted, so no further resubmissions happen
|
60
|
+
# ! - the sign "!" is a force sign to force date calculation even if a resubmission date
|
61
|
+
# present
|
62
|
+
# W - the sign "W" in this position corrects the date to the next working day
|
63
|
+
# * - the sign "*" is a mock switch. The mock-switch is deleted from the resubmission-rule
|
64
|
+
# and no resubmission-date is calculated. Needed for Redmine Attribute-Quickie plugin
|
65
|
+
#
|
66
|
+
# Example: W1F - one week further, first day, so monday
|
67
|
+
# Example: M3M - three months further from today, mid-term, so 15th of month
|
68
|
+
# Example: q1- - next quarter, first day of quarter, so 1st Jan., Apr., Jul. or Oct., after
|
69
|
+
# one calculation further calculations are stopped, rule is deleted.
|
70
|
+
# Example: D1- - tomorrow, then delete rule
|
71
|
+
# Example: D1-! - tomorrow!, regardsless of date
|
72
|
+
#
|
73
|
+
# Resubmission dates are always calculated for the future, never for the past.
|
74
|
+
# So W0F would calculate "next monday"", if calculated on a friday, though W0 stands for
|
75
|
+
# this week (W0 zero weeks further, first day, monday) and would calculate last monday.
|
76
|
+
# In this case, the calculated date is advanced monday further into the future.
|
77
|
+
# So q0M would calculate "this quarter mid-term" if calculated near to lapse of current
|
78
|
+
# quarter. In this case the calculated date is advanced one quarter into the future.
|
79
|
+
####################################################################################
|
80
|
+
|
81
|
+
####################################################################################
|
82
|
+
# calc
|
83
|
+
####################################################################################
|
84
|
+
def calc( rule )
|
85
|
+
|
86
|
+
new_date = nil
|
87
|
+
new_rule = nil
|
88
|
+
|
89
|
+
if rule.present?
|
90
|
+
|
91
|
+
m = parse_rule( rule )
|
92
|
+
|
93
|
+
if m['mockswitch']
|
94
|
+
|
95
|
+
# mockswitch does not calculate anything
|
96
|
+
# mockswitch is removed from new_rule, however
|
97
|
+
new_rule = unmock( rule, m )
|
98
|
+
|
99
|
+
elsif self <= Date.today || m['force']
|
100
|
+
|
101
|
+
if( m['epoch'] && m['num'] )
|
102
|
+
|
103
|
+
new_date = move( m['epoch'], m['num'] )
|
104
|
+
new_date = new_date.adjust( m['epoch'], m['pos'], self )
|
105
|
+
new_date = new_date.adjust("D", "W", new_date) if m["workingday"] # adjust working day
|
106
|
+
|
107
|
+
if m['killswitch']
|
108
|
+
new_rule = ""
|
109
|
+
else
|
110
|
+
new_rule = rule
|
111
|
+
end
|
112
|
+
|
113
|
+
end #if
|
114
|
+
end #if
|
115
|
+
end #if
|
116
|
+
|
117
|
+
[new_date, new_rule]
|
118
|
+
|
119
|
+
end #def
|
120
|
+
|
121
|
+
####################################################################################
|
122
|
+
# forward
|
123
|
+
####################################################################################
|
124
|
+
def forward( rule )
|
125
|
+
calc( rule ).first
|
126
|
+
end #def
|
127
|
+
|
128
|
+
####################################################################################
|
129
|
+
# calculate num times advance of epoch
|
130
|
+
# epoch: D - n days
|
131
|
+
# epoch: W - n weeks
|
132
|
+
# epoch: M - n months
|
133
|
+
# epoch: Y - n years
|
134
|
+
#
|
135
|
+
# epoch: C - n calendar weeks (absolute, within this year, not relative)
|
136
|
+
# epoch: m - n mondays
|
137
|
+
# epoch: q - q quarters
|
138
|
+
####################################################################################
|
139
|
+
def move( epoch, num )
|
140
|
+
case epoch
|
141
|
+
when "D"
|
142
|
+
self + num.to_i
|
143
|
+
when "W"
|
144
|
+
self + num.to_i * 7
|
145
|
+
when "M"
|
146
|
+
self >> num.to_i
|
147
|
+
when "Y"
|
148
|
+
self >> num.to_i * 12
|
149
|
+
when "m"
|
150
|
+
(self + num.to_i * 7).monday
|
151
|
+
when "q"
|
152
|
+
(self >> num.to_i * 3).beginning_of_quarter
|
153
|
+
when "C"
|
154
|
+
# calendar week 1 is the week containing Jan. 4th
|
155
|
+
change(:month => 1, :day => 4).advance( :weeks => (num.to_i - 1))
|
156
|
+
else
|
157
|
+
self
|
158
|
+
end #case
|
159
|
+
end #def
|
160
|
+
|
161
|
+
####################################################################################
|
162
|
+
# calculate time adjustmentfor pos in epoch (_F_irst, _M_id, _L_ast, _W_orking day)
|
163
|
+
# epoch: D - day: W - Monday
|
164
|
+
# epoch: W - week: F - Monday, M - Wednesday, L - Friday, W - Monday
|
165
|
+
# epoch: M - month: F - 1st, M - 15th, L - last, W - Monday
|
166
|
+
# epoch: Y - year: F - 01/01, M - 06/30, L - 12/31, W - Monday
|
167
|
+
# epoch: q - quarter: W - Monday
|
168
|
+
####################################################################################
|
169
|
+
def adjust( epoch, pos, ref=self )
|
170
|
+
|
171
|
+
case epoch
|
172
|
+
when "D"
|
173
|
+
case pos
|
174
|
+
when "W"
|
175
|
+
# if saturday or sunday, fall back to last monday, then add one week for monday coming up
|
176
|
+
(wday % 6) != 0 ? self : monday.advance(:days => 7)
|
177
|
+
else
|
178
|
+
self
|
179
|
+
end #case
|
180
|
+
|
181
|
+
when "W", "C"
|
182
|
+
# week
|
183
|
+
case pos
|
184
|
+
when "F"
|
185
|
+
# Monday
|
186
|
+
monday < ref ? advance( :weeks => 1).monday : monday
|
187
|
+
|
188
|
+
when "M"
|
189
|
+
# Wednesday = Monday + 2 days
|
190
|
+
monday.advance(:days => 2) < ref ? advance( :weeks => 1).monday.advance(:days => 2) : monday.advance(:days => 2)
|
191
|
+
|
192
|
+
when "L"
|
193
|
+
# Friday = Monday + 4 days
|
194
|
+
monday.advance(:days => 4) < ref ? advance( :weeks => 1).monday.advance(:days => 4) : monday.advance(:days => 4)
|
195
|
+
|
196
|
+
when "W"
|
197
|
+
# if saturday or sunday, fall back to last monday, then add one week for monday coming up
|
198
|
+
(wday % 6) != 0 ? self : monday.advance(:days => 7)
|
199
|
+
|
200
|
+
else
|
201
|
+
self
|
202
|
+
end #case
|
203
|
+
|
204
|
+
when "M"
|
205
|
+
# month
|
206
|
+
case pos
|
207
|
+
when "F"
|
208
|
+
# 1st
|
209
|
+
change(:day => 1) < ref ? advance( :months => 1).beginning_of_month.change(:day => 1) : change(:day => 1)
|
210
|
+
|
211
|
+
when "M"
|
212
|
+
# 15th
|
213
|
+
change(:day => 15) < ref ? advance( :months => 1).beginning_of_month.change(:day => 15) : change(:day => 15)
|
214
|
+
|
215
|
+
when "L"
|
216
|
+
# last day
|
217
|
+
end_of_month
|
218
|
+
|
219
|
+
when "W"
|
220
|
+
# if saturday or sunday, fall back to last monday, then add one week for monday coming up
|
221
|
+
(wday % 6) != 0 ? self : monday.advance(:days => 7)
|
222
|
+
else
|
223
|
+
self
|
224
|
+
end #case
|
225
|
+
|
226
|
+
when "Y"
|
227
|
+
# year
|
228
|
+
case pos
|
229
|
+
when "F"
|
230
|
+
# Jan. 1st
|
231
|
+
beginning_of_year < ref ? advanve(:years => 1).beginning_of_year : beginning_of_year
|
232
|
+
|
233
|
+
when "M"
|
234
|
+
# Jun. 30th
|
235
|
+
change(:month => 5, :day => 30) < ref ? advance(:years => 1).change(:month => 5, :day => 30) : change(:month => 5, :day => 30)
|
236
|
+
|
237
|
+
when "L"
|
238
|
+
# Dec. 31st
|
239
|
+
change(:month => 12, :day => 31)
|
240
|
+
|
241
|
+
when "W"
|
242
|
+
# if saturday or sunday, fall back to last monday, then add one week for monday coming up
|
243
|
+
(wday % 6) != 0 ? self : monday.advance(:days => 7)
|
244
|
+
else
|
245
|
+
self
|
246
|
+
end #case
|
247
|
+
|
248
|
+
when "q"
|
249
|
+
case pos
|
250
|
+
when "F"
|
251
|
+
# Jan. 1st
|
252
|
+
beginning_of_quarter < ref ? advance( :months => 3).beginning_of_quarter : beginning_of_quarter
|
253
|
+
|
254
|
+
when "M"
|
255
|
+
# mid quarter
|
256
|
+
beginning_of_quarter.advance(:months => 1).advance(:days => 14) < ref ? advance(:quarters => 1).beginning_of_quarter.advance(:months => 1).advance(:days => 14) : beginning_of_quarter.advance(:months => 1).advance(:days => 14)
|
257
|
+
|
258
|
+
when "L"
|
259
|
+
# end quarter
|
260
|
+
end_of_quarter
|
261
|
+
|
262
|
+
when "W"
|
263
|
+
# if saturday or sunday, fall back to last monday, then add one week for monday coming up
|
264
|
+
(wday % 6) != 0 ? self : monday.advance(:days => 7)
|
265
|
+
else
|
266
|
+
self
|
267
|
+
end #case
|
268
|
+
|
269
|
+
else
|
270
|
+
self
|
271
|
+
end #case epoch
|
272
|
+
end #def
|
273
|
+
|
274
|
+
|
275
|
+
####################################################################################
|
276
|
+
# private
|
277
|
+
####################################################################################
|
278
|
+
private
|
279
|
+
|
280
|
+
####################################################################################
|
281
|
+
# parse_rule
|
282
|
+
####################################################################################
|
283
|
+
def parse_rule(rule)
|
284
|
+
|
285
|
+
m = {}
|
286
|
+
matches = /(?<epoch>[DWMYCmq])(?<num>[0-9]+)(?<pos>[XFMLW]?)(?<kfmw>[-!W\*]*)(?<trailing_rest>.*)/.match(rule)
|
287
|
+
|
288
|
+
if matches.present?
|
289
|
+
m.merge!(Hash[ matches.names.zip( matches.captures ) ])
|
290
|
+
m.merge!('killswitch' => m['kfmw'].match(/-/).to_s.presence)
|
291
|
+
m.merge!('force' => m['kfmw'].match(/!/).to_s.presence)
|
292
|
+
m.merge!('mockswitch' => m['kfmw'].match(/\*/).to_s.presence)
|
293
|
+
m.merge!('workingday' => m['kfmw'].match(/W/).to_s.presence)
|
294
|
+
end
|
295
|
+
m.compact
|
296
|
+
end #def
|
297
|
+
|
298
|
+
####################################################################################
|
299
|
+
# parse_rule
|
300
|
+
####################################################################################
|
301
|
+
def unmock( rule, m=nil )
|
302
|
+
m = parse_rule( rule ) unless m
|
303
|
+
if m['mockswitch'].present?
|
304
|
+
"#{m['epoch']}#{m['num']}#{m['pos']}#{m['killswitch']}#{m['force']}#{m['trailing_rest']}"
|
305
|
+
else
|
306
|
+
nil
|
307
|
+
end
|
308
|
+
end #def
|
309
|
+
|
310
|
+
end #class
|
311
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Ruby Gem to create a self populating Open Document Format (.odf) text file.
|
4
|
+
#
|
5
|
+
# Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License
|
9
|
+
# as published by the Free Software Foundation; either version 2
|
10
|
+
# of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20
|
+
#
|
21
|
+
|
22
|
+
module ODFWriter
|
23
|
+
|
24
|
+
########################################################################################
|
25
|
+
#
|
26
|
+
# Bookmark: replace bookmarks with given name
|
27
|
+
#
|
28
|
+
########################################################################################
|
29
|
+
class Bookmark < Field
|
30
|
+
|
31
|
+
######################################################################################
|
32
|
+
#
|
33
|
+
# replace!
|
34
|
+
#
|
35
|
+
######################################################################################
|
36
|
+
def replace!(doc, item = nil)
|
37
|
+
|
38
|
+
nodes = find_bookmark_nodes(doc)
|
39
|
+
return if nodes.blank?
|
40
|
+
|
41
|
+
text = value(item)
|
42
|
+
text = text.encode(universal_newline: true)
|
43
|
+
|
44
|
+
text_node_array = text.split(/\n/).map{|a| Nokogiri::XML::Text.new(a, doc) }
|
45
|
+
unless text_node_array.length == 1
|
46
|
+
text_node_array = text_node_array.inject([]) do |collector, node|
|
47
|
+
collector << Nokogiri::XML::Node.new("line-break", doc) unless collector.empty?
|
48
|
+
collector << node
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
nodes.each do |node|
|
53
|
+
|
54
|
+
case node.name
|
55
|
+
|
56
|
+
when "bookmark"
|
57
|
+
text_node_array.each {|tn| node.before(tn)}
|
58
|
+
|
59
|
+
#
|
60
|
+
# find bookmark
|
61
|
+
#
|
62
|
+
bm = "text:bookmark[@text:name='#{@name}']"
|
63
|
+
bmn = doc.xpath(".//.//*[self::#{bm}]")
|
64
|
+
#
|
65
|
+
# delete bookmark
|
66
|
+
#
|
67
|
+
bmn.each {|b| b.remove }
|
68
|
+
|
69
|
+
when "bookmark-start"
|
70
|
+
text_node_array.each {|tn| node.before(tn)}
|
71
|
+
|
72
|
+
#
|
73
|
+
# find bookmark-start
|
74
|
+
#
|
75
|
+
bms = "text:bookmark-start[@text:name='#{@name}']"
|
76
|
+
bmsn = doc.xpath(".//.//*[self::#{bms}]")
|
77
|
+
#
|
78
|
+
# find bookmark text
|
79
|
+
#
|
80
|
+
bme = "text:bookmark-end[@text:name='#{@name}']"
|
81
|
+
bmen = doc.xpath(".//.//*[self::#{bme}]")
|
82
|
+
#
|
83
|
+
# find bookmark-end
|
84
|
+
#
|
85
|
+
bmn = doc.xpath(".//text()[preceding-sibling::#{bms} and following-sibling::#{bme}]")
|
86
|
+
#
|
87
|
+
# delete bookmark -start, text and -end
|
88
|
+
#
|
89
|
+
bmn.each {|b| b.remove }
|
90
|
+
bmsn.each {|b| b.remove }
|
91
|
+
bmen.each {|b| b.remove }
|
92
|
+
|
93
|
+
end #case
|
94
|
+
end #each
|
95
|
+
|
96
|
+
end #def
|
97
|
+
|
98
|
+
######################################################################################
|
99
|
+
#
|
100
|
+
# private
|
101
|
+
#
|
102
|
+
######################################################################################
|
103
|
+
private
|
104
|
+
|
105
|
+
def find_bookmark_nodes(doc)
|
106
|
+
doc.xpath(".//*[self::text:bookmark[@text:name='#{@name}'] or self::text:bookmark-start[@text:name='#{@name}']]")
|
107
|
+
end #def
|
108
|
+
|
109
|
+
end #class
|
110
|
+
end #module
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Ruby Gem to create a self populating Open Document Format (.odf) text file.
|
4
|
+
#
|
5
|
+
# Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License
|
9
|
+
# as published by the Free Software Foundation; either version 2
|
10
|
+
# of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
20
|
+
#
|
21
|
+
|
22
|
+
module ODFWriter
|
23
|
+
|
24
|
+
########################################################################################
|
25
|
+
#
|
26
|
+
# BookmarkReader: find all bookmarks and set name
|
27
|
+
#
|
28
|
+
########################################################################################
|
29
|
+
class BookmarkReader
|
30
|
+
|
31
|
+
attr_accessor :name
|
32
|
+
|
33
|
+
######################################################################################
|
34
|
+
#
|
35
|
+
# initialize
|
36
|
+
#
|
37
|
+
######################################################################################
|
38
|
+
def initialize(opts={})
|
39
|
+
@name = opts[:name]
|
40
|
+
end #def
|
41
|
+
|
42
|
+
######################################################################################
|
43
|
+
#
|
44
|
+
# get_paths: limit to paths with ancestors 'text '(content.xml) and master-styles (styles.xml)
|
45
|
+
#
|
46
|
+
######################################################################################
|
47
|
+
def paths( root, doc)
|
48
|
+
|
49
|
+
# find nodes with matching field elements matching [BOOKMARK] pattern
|
50
|
+
nodes = doc.xpath("//*[self::text:bookmark or self::text:bookmark-start]").select{|node| scan(node).present? }
|
51
|
+
|
52
|
+
# find path for each field
|
53
|
+
paths = nil
|
54
|
+
nodes.each do |node|
|
55
|
+
leaf = {:bookmarks => scan(node)}
|
56
|
+
paths = PathFinder.trail(node, leaf, :root => root, :paths => paths)
|
57
|
+
end #each
|
58
|
+
paths.to_h
|
59
|
+
|
60
|
+
end #def
|
61
|
+
|
62
|
+
######################################################################################
|
63
|
+
# private
|
64
|
+
######################################################################################
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def scan(node)
|
69
|
+
if name
|
70
|
+
node.attr("text:name") == name.upcase ? [node.attr("text:name")] : []
|
71
|
+
else
|
72
|
+
[node.attr("text:name")]
|
73
|
+
end
|
74
|
+
end #def
|
75
|
+
|
76
|
+
end #class
|
77
|
+
end #module
|