summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ccc_conventions.rb53
-rw-r--r--lib/html_word_diff.rb74
-rw-r--r--lib/tasks/assets.rake19
3 files changed, 146 insertions, 0 deletions
diff --git a/lib/ccc_conventions.rb b/lib/ccc_conventions.rb
new file mode 100644
index 0000000..352dd3c
--- /dev/null
+++ b/lib/ccc_conventions.rb
@@ -0,0 +1,53 @@
1module CccConventions
2 ERFA_PARENT_NAME = "club/erfas"
3 CHAOSTREFF_PARENT_NAME = "club/chaostreffs"
4 SITEMAP_COLLAPSED_PATHS = %w[updates club/erfas club/chaostreffs disclosure].freeze
5
6 NODE_KINDS = {
7 "top_level" => {
8 parent: -> { Node.root },
9 parent_match: ->(path) { path == [] },
10 path_prefix: "",
11 label: "Top Level"
12 },
13 "generic" => {
14 parent_match: ->(path) { true },
15 label: "Generic",
16 hint: "Can be created anywhere - choose the parent below."
17 },
18 "update" => {
19 parent: -> { Update.find_or_create_parent },
20 parent_match: ->(path) { path[0] == "updates" && (path.length == 1 || path[1] =~ /\A\d{4}\z/) },
21 tags: ["update"],
22 path_prefix: -> { "updates/#{Time.now.year}" },
23 label: "Update",
24 hint: -> { "Automatically created in /updates/#{Time.now.year}/, gets tag \"update\", and inherits the update template." }
25 },
26 "press_release" => {
27 parent: -> { Update.find_or_create_parent },
28 parent_match: ->(path) { path[0] == "updates" && (path.length == 1 || path[1] =~ /\A\d{4}\z/) },
29 tags: ["update", "pressemitteilung"],
30 path_prefix: -> { "updates/#{Time.now.year}" },
31 label: "Pressemitteilung",
32 hint: -> { "Automatically created in /updates/#{Time.now.year}/, gets tags \"update, pressemitteilung\", and inherits the update template." }
33 },
34 "erfa" => {
35 parent: -> { Node.find_by_unique_name!(ERFA_PARENT_NAME) },
36 parent_match: ->(path) { path == ["club", "erfas"] },
37 tags: ["erfa-detail"],
38 template: "chapter_detail",
39 path_prefix: ERFA_PARENT_NAME,
40 label: "Erfa",
41 hint: "Automatically created under the Erfa-Kreise overview page, gets tag \"erfa-detail\", and uses the chapter detail template."
42 },
43 "chaostreff" => {
44 parent: -> { Node.find_by_unique_name!(CHAOSTREFF_PARENT_NAME) },
45 parent_match: ->(path) { path == ["club", "chaostreffs"] },
46 tags: ["chaostreff-detail"],
47 template: "chapter_detail",
48 path_prefix: CHAOSTREFF_PARENT_NAME,
49 label: "Chaostreff",
50 hint: "Automatically created under the Chaostreffs overview page, gets tag \"chaostreff-detail\", and uses the chapter detail template."
51 }
52 }.freeze
53end
diff --git a/lib/html_word_diff.rb b/lib/html_word_diff.rb
new file mode 100644
index 0000000..aa0cb86
--- /dev/null
+++ b/lib/html_word_diff.rb
@@ -0,0 +1,74 @@
1require 'diff/lcs'
2require 'cgi'
3
4module HtmlWordDiff
5 TOKEN_REGEXP = /<[^>]*>|[[:space:]]+|[[:alnum:]]+|[^[:space:][:alnum:]<>]/
6
7 def self.inline(old_html, new_html)
8 html = +''
9 each_change(old_html, new_html) do |action, old_token, new_token|
10 case action
11 when '='
12 html << new_token
13 when '-'
14 html << wrap_removed(old_token)
15 when '+'
16 html << wrap_inserted(new_token)
17 when '!'
18 html << wrap_removed(old_token)
19 html << wrap_inserted(new_token)
20 end
21 end
22 html
23 end
24
25 def self.side_by_side(old_html, new_html)
26 old_out = +''
27 new_out = +''
28 each_change(old_html, new_html) do |action, old_token, new_token|
29 case action
30 when '='
31 old_out << old_token
32 new_out << new_token
33 when '-'
34 old_out << wrap_removed(old_token)
35 when '+'
36 new_out << wrap_inserted(new_token)
37 when '!'
38 old_out << wrap_removed(old_token)
39 new_out << wrap_inserted(new_token)
40 end
41 end
42 [old_out, new_out]
43 end
44
45 def self.each_change(old_html, new_html)
46 Diff::LCS.sdiff(tokenize(old_html), tokenize(new_html)).each do |change|
47 yield change.action, change.old_element, change.new_element
48 end
49 end
50
51 def self.tokenize(html)
52 html.to_s.scan(TOKEN_REGEXP)
53 end
54
55 def self.tag_token?(token)
56 token.to_s.match?(/\A<[^>]*>\z/)
57 end
58
59 def self.wrap_removed(token)
60 if tag_token?(token)
61 %(<del class="diff_structural" title="removed: #{CGI.escapeHTML(token)}">\u00b6</del>)
62 else
63 "<del>#{token}</del>"
64 end
65 end
66
67 def self.wrap_inserted(token)
68 if tag_token?(token)
69 %(<ins class="diff_structural" title="added: #{CGI.escapeHTML(token)}">\u00b6</ins>)
70 else
71 "<ins>#{token}</ins>"
72 end
73 end
74end
diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake
new file mode 100644
index 0000000..563dfad
--- /dev/null
+++ b/lib/tasks/assets.rake
@@ -0,0 +1,19 @@
1namespace :assets do
2 desc "Regenerate ImageMagick variants for every image asset from its stored original -- rerun whenever a new style is added to FileAttachment::STYLES after assets already exist. Scope to one asset first with ASSET_ID=123."
3 task :regenerate_variants => :environment do
4 scope = Asset.images
5 scope = scope.where(id: ENV["ASSET_ID"]) if ENV["ASSET_ID"].present?
6
7 scope.find_each do |asset|
8 original_path = asset.send(:file_path, :original)
9
10 unless File.exist?(original_path)
11 puts "Skipping Asset##{asset.id} (#{asset.name}) -- no original file at #{original_path}"
12 next
13 end
14
15 asset.send(:generate_variants, original_path)
16 puts "Regenerated variants for Asset##{asset.id} (#{asset.name})"
17 end
18 end
19end