card-mod-format 0.11.0

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/lib/card/format/css_format.rb +17 -0
  3. data/lib/card/format/csv_format.rb +19 -0
  4. data/lib/card/format/data_format.rb +6 -0
  5. data/lib/card/format/file_format.rb +8 -0
  6. data/lib/card/format/html_format.rb +45 -0
  7. data/lib/card/format/js_format.rb +17 -0
  8. data/lib/card/format/json_format.rb +24 -0
  9. data/lib/card/format/rss_format.rb +9 -0
  10. data/lib/card/format/text_format.rb +16 -0
  11. data/lib/card/format/xml_format.rb +13 -0
  12. data/lib/card/path.rb +127 -0
  13. data/set/all/active_card.rb +6 -0
  14. data/set/all/base.rb +137 -0
  15. data/set/all/css.rb +37 -0
  16. data/set/all/csv.rb +93 -0
  17. data/set/all/error.rb +79 -0
  18. data/set/all/export.rb +68 -0
  19. data/set/all/file.rb +9 -0
  20. data/set/all/frame.rb +53 -0
  21. data/set/all/haml.rb +75 -0
  22. data/set/all/head.rb +148 -0
  23. data/set/all/header.rb +62 -0
  24. data/set/all/header/header_wrap.haml +4 -0
  25. data/set/all/html_content.rb +168 -0
  26. data/set/all/html_content/labeled.haml +4 -0
  27. data/set/all/html_error.rb +193 -0
  28. data/set/all/html_error/debug_server_error.haml +1015 -0
  29. data/set/all/html_error/not_found.haml +7 -0
  30. data/set/all/html_error/server_error.haml +5 -0
  31. data/set/all/html_show.rb +53 -0
  32. data/set/all/html_title.rb +47 -0
  33. data/set/all/html_wrapper.rb +159 -0
  34. data/set/all/js.rb +10 -0
  35. data/set/all/json.rb +166 -0
  36. data/set/all/links.rb +149 -0
  37. data/set/all/menu.rb +129 -0
  38. data/set/all/meta_tags.haml +4 -0
  39. data/set/all/path.rb +78 -0
  40. data/set/all/rich_html.rb +4 -0
  41. data/set/all/rss.rb +76 -0
  42. data/set/all/text.rb +7 -0
  43. data/set/self/home.rb +9 -0
  44. data/set/type/html.rb +27 -0
  45. data/set/type/json.rb +41 -0
  46. data/set/type/number.rb +22 -0
  47. data/set/type/phrase.rb +5 -0
  48. data/set/type/plain_text.rb +9 -0
  49. data/set/type/toggle.rb +38 -0
  50. data/set/type/uri.rb +15 -0
  51. metadata +123 -0
@@ -0,0 +1,149 @@
1
+ RESOURCE_TYPE_REGEXP = /^([a-zA-Z][\-+\.a-zA-Z\d]*):/
2
+
3
+ # The #link_to methods support smart formatting of links in multiple formats.
4
+ format do
5
+ # Creates a "link", the meaning of which depends upon the format. In this base
6
+ # format, the link looks like [text][absolute path]
7
+ #
8
+ # @param text [String] optional string associated with link
9
+ # @param opts [Hash] optional Hash. In simple formats, :path is usually the only key
10
+ def link_to text=nil, opts={}
11
+ path = path((opts.delete(:path) || {}))
12
+ if text && path != text
13
+ "#{text}[#{path}]"
14
+ else
15
+ path
16
+ end
17
+ end
18
+
19
+ # link to a different view of the current card
20
+ # @param view [Symbol,String]
21
+ # @param text [String]
22
+ # @param opts [Hash]
23
+ def link_to_view view, text=nil, opts={}
24
+ add_to_path opts, view: view unless view == :home
25
+ link_to text, opts
26
+ end
27
+
28
+ # link to a card other than the current card.
29
+ # @param cardish [Integer, Symbol, String, Card] a card identifier
30
+ # @param text [String]
31
+ # @param opts [Hash]
32
+ def link_to_card cardish, text=nil, opts={}
33
+ add_to_path opts, mark: Card::Name[cardish]
34
+ link_to text, opts
35
+ end
36
+
37
+ # a "resource" is essentially a reference to something that
38
+ # decko doesn't recognize to be a card. Can be a remote url,
39
+ # a local url (that decko hasn't parsed) or a local path.
40
+ # @param resource [String]
41
+ # @param text [String]
42
+ # @param opts [Hash]
43
+ def link_to_resource resource, text=nil, opts={}
44
+ resource = clean_resource resource, resource_type(resource)
45
+ link_to text, opts.merge(path: resource)
46
+ end
47
+
48
+ # smart_link_to is wrapper method for #link_to, #link_to_card, #link_to_view, and
49
+ # #link_to_resource. If the opts argument contains :view, :related, :card, or
50
+ # :resource, it will use the respective method to render a link.
51
+ #
52
+ # This is usually most useful when writing views that generate many different
53
+ # kinds of links.
54
+ def smart_link_to text, opts={}
55
+ if (linktype = %i[view card resource].find { |key| opts[key] })
56
+ send "link_to_#{linktype}", opts.delete(linktype), text, opts
57
+ else
58
+ send :link_to, text, opts
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def resource_type resource
65
+ case resource
66
+ when /^https?\:/ then "external-link"
67
+ when %r{^/} then "internal-link"
68
+ when /^mailto\:/ then "email-link"
69
+ when RESOURCE_TYPE_REGEXP then Regexp.last_match(1) + "-link"
70
+ end
71
+ end
72
+
73
+ def clean_resource resource, resource_type
74
+ if resource_type == "internal-link"
75
+ contextualize_path resource[1..-1]
76
+ else
77
+ resource
78
+ end
79
+ end
80
+
81
+ def add_to_path opts, new_hash
82
+ opts[:path] = (opts[:path] || {}).merge new_hash
83
+ end
84
+ end
85
+
86
+ public
87
+
88
+ format :html do
89
+ # in HTML, #link_to renders an anchor tag <a>
90
+ # it treats opts other than "path" as html opts for that tag,
91
+ # and it adds special handling of "remote" and "method" opts
92
+ # (changes them into data attributes)
93
+ def link_to text=nil, opts={}
94
+ opts[:href] ||= path opts.delete(:path)
95
+ text = raw(text || opts[:href])
96
+ interpret_data_opts_to_link_to opts
97
+ wrap_with :a, text, opts
98
+ end
99
+
100
+ # in HTML, #link_to_card adds special css classes indicated whether a
101
+ # card is "known" (real or virtual) or "wanted" (unknown)
102
+ # TODO: upgrade from (known/wanted)-card to (real/virtual/unknown)-card
103
+ def link_to_card cardish, text=nil, opts={}
104
+ name = Card::Name[cardish]
105
+ slotterify opts if opts[:slotter]
106
+ add_known_or_wanted_class opts, name
107
+ super name, (text || name), opts
108
+ end
109
+
110
+ # in HTML, #link_to_view defaults to a remote link with rel="nofollow".
111
+ def link_to_view view, text=nil, opts={}
112
+ slotterify opts
113
+ super view, (text || view), opts
114
+ end
115
+
116
+ # in HTML, #link_to_resource automatically adds a target to external resources
117
+ # so they will open in another tab. It also adds css classes indicating whether
118
+ # the resource is internal or external
119
+ def link_to_resource resource, text=nil, opts={}
120
+ add_resource_opts opts, resource_type(resource)
121
+ super
122
+ end
123
+
124
+ private
125
+
126
+ def slotterify opts
127
+ opts.delete(:slotter)
128
+ opts.reverse_merge! remote: true, rel: "nofollow"
129
+ add_class opts, "slotter"
130
+ end
131
+
132
+ def add_known_or_wanted_class opts, name
133
+ known = opts.delete :known
134
+ known = Card.known?(name) if known.nil?
135
+ add_class opts, (known ? "known-card" : "wanted-card")
136
+ end
137
+
138
+ def interpret_data_opts_to_link_to opts
139
+ %i[remote method].each do |key|
140
+ next unless (val = opts.delete key)
141
+ opts["data-#{key}"] = val
142
+ end
143
+ end
144
+
145
+ def add_resource_opts opts, resource_type
146
+ opts[:target] ||= "_blank" if resource_type == "external-link"
147
+ add_class opts, resource_type
148
+ end
149
+ end
@@ -0,0 +1,129 @@
1
+ format :html do
2
+ view :menu, denial: :blank, unknown: true do
3
+ return "" if card.unknown?
4
+
5
+ wrap_with :div, class: "card-menu #{menu_link_classes}" do
6
+ [render_help_link,
7
+ menu_link,
8
+ (voo.show?(:bridge_link) ? bridge_link(false) : nil)]
9
+ end
10
+ end
11
+
12
+ def menu_link
13
+ case voo.edit
14
+ when :inline
15
+ edit_inline_link
16
+ when :full
17
+ edit_in_bridge_link
18
+ else # :standard
19
+ edit_link
20
+ end
21
+ end
22
+
23
+ def edit_view
24
+ case voo.edit
25
+ when :inline
26
+ :edit_inline
27
+ when :full
28
+ :edit
29
+ else # :standard
30
+ edit_link
31
+ end
32
+ end
33
+
34
+ view :edit_link, unknown: true, denial: :blank do
35
+ edit_link edit_link_view
36
+ end
37
+
38
+ def edit_link_view
39
+ :edit
40
+ end
41
+
42
+ view :full_page_link do
43
+ full_page_link
44
+ end
45
+
46
+ view :bridge_link, unknown: true do
47
+ bridge_link
48
+ end
49
+
50
+ def bridge_link in_modal=true
51
+ opts = { class: "bridge-link" }
52
+ if in_modal
53
+ # add_class opts, "close"
54
+ opts["data-slotter-mode"] = "modal-replace"
55
+ end
56
+ link_to_view :bridge, material_icon(:more_horiz), opts
57
+ end
58
+
59
+ # no caching because help_text view doesn't cache, and we can't have a
60
+ # stub in the data-content attribute or it will get html escaped.
61
+ view :help_link, cache: :never, unknown: true do
62
+ help_link render_help_text, help_title
63
+ end
64
+
65
+ def help_link text=nil, title=nil
66
+ opts = help_popover_opts text, title
67
+ add_class opts, "_card-menu-popover"
68
+ link_to help_icon, opts
69
+ end
70
+
71
+ def help_popover_opts text=nil, title=nil
72
+ text ||= render_help_text
73
+ opts = { "data-placement": :left, class: "help-link" }
74
+ popover_opts text, title, opts
75
+ end
76
+
77
+ def help_icon
78
+ material_icon("help")
79
+ end
80
+
81
+ def help_title
82
+ "#{name_parts_links} (#{render_type}) #{full_page_link unless card.simple?}"
83
+ end
84
+
85
+ def name_parts_links
86
+ card.name.parts.map do |part|
87
+ link_to_card part
88
+ end.join Card::Name.joint
89
+ end
90
+
91
+ def full_page_link
92
+ link_to_card full_page_card, full_page_icon, class: classy("full-page-link")
93
+ end
94
+
95
+ def full_page_card
96
+ card
97
+ end
98
+
99
+ def edit_in_bridge_link opts={}
100
+ edit_link :bridge, opts
101
+ end
102
+
103
+ def edit_link view=:edit, opts={}
104
+ link_to_view view, opts.delete(:link_text) || menu_icon,
105
+ edit_link_opts(opts.reverse_merge(modal: :lg))
106
+ end
107
+
108
+ # @param modal [Symbol] modal size
109
+ def edit_link_opts modal: nil
110
+ opts = { class: classy("edit-link") }
111
+ if modal
112
+ opts[:"data-slotter-mode"] = "modal"
113
+ opts[:"data-modal-class"] = "modal-#{modal}"
114
+ end
115
+ opts
116
+ end
117
+
118
+ def menu_link_classes
119
+ "nodblclick" + (show_view?(:hover_link) ? " _show-on-hover" : "")
120
+ end
121
+
122
+ def menu_icon
123
+ material_icon "edit"
124
+ end
125
+
126
+ def full_page_icon
127
+ icon_tag :open_in_new
128
+ end
129
+ end
@@ -0,0 +1,4 @@
1
+ %meta{ charset: "UTF-8" }
2
+ %meta{ content: "width=device-width, initial-scale=1.0", name: "viewport" }
3
+ - if card.unknown?
4
+ %meta{ content: "noindex", name: "robots"}
@@ -0,0 +1,78 @@
1
+ format do
2
+ # Decko uses the term "path" a bit unusually.
3
+ #
4
+ # In most formats, #path returns a full url. In HTML, it provides everything after
5
+ # the domain/port.
6
+ #
7
+ # If you're feeling saucy, you might point out that typically "paths" don't
8
+ # include queries and fragment identifiers, much less protocols, domains, and ports.
9
+ # 10 pedantry points to you! But "path" is easy to type and the method is smart about
10
+ # format needs, so using it will lead you down the right ... something or other.
11
+
12
+ # Format#path is for generating standard card routes, eg, assuming the card
13
+ # associated with the current format is named "current", it will generate paths like
14
+ # these:
15
+
16
+ # path view: :bar -> "current?view=bar"
17
+ # path mark: [mycardid] -> "mycardname"
18
+ # path format: :csv) -> "current.csv"
19
+ # path action: :update -> "update/current"
20
+
21
+ # #path produces paths that follow one of three main patterns:
22
+
23
+ # 1. mark[.format][?query] # standard GET request
24
+ # 2. action/mark[?query] # GET variant of standard actions
25
+ # 3. new/mark # shortcut for "new" view of cardtype
26
+
27
+ # @param opts [Hash, String] a String is treated as a complete path and
28
+ # bypasses all processing
29
+ # @option opts [String, Card::Name, Integer, Symbol, Card] :mark
30
+ # @option opts [Symbol] :action card action (:create, :update, :delete)
31
+ # @option opts [Symbol] :format
32
+ # @option opts [Hash] :card
33
+ # @option opts [TrueClass] :no_mark
34
+
35
+ def path opts={}
36
+ return opts unless opts.is_a? Hash
37
+ path = Card::Path.new(card, opts)&.render
38
+ contextualize_path path
39
+ end
40
+
41
+ # in base format (and therefore most other formats), even internal paths
42
+ # are rendered as absolute urls.
43
+ def contextualize_path relative_path
44
+ card_url relative_path
45
+ end
46
+ end
47
+
48
+ format :json do
49
+ def add_unknown_name_to_opts name, opts
50
+ # noop
51
+ end
52
+ end
53
+
54
+ format :css do
55
+ def contextualize_path relative_path
56
+ if Card.config.file_storage == :local
57
+ # absolute paths lead to invalid assets path in css for cukes
58
+ card_path relative_path
59
+ else
60
+ # ...but relative paths are problematic when machine output and
61
+ # hard-coded assets (like fonts) are on different servers
62
+ card_url relative_path
63
+ end
64
+ end
65
+ end
66
+
67
+ format :html do
68
+ # in HTML, decko paths rendered as relative to the site's root.
69
+ def contextualize_path relative_path
70
+ card_path relative_path
71
+ end
72
+ end
73
+
74
+ format :email_html do
75
+ def contextualize_path relative_path
76
+ card_url relative_path
77
+ end
78
+ end
@@ -0,0 +1,4 @@
1
+ format :html do
2
+ delegate :class_up, :class_down, :with_class_up, :without_upped_class, :classy,
3
+ to: :voo
4
+ end
@@ -0,0 +1,76 @@
1
+ format :rss do
2
+ attr_accessor :xml
3
+
4
+ def initialize card, args
5
+ super
6
+ @xml = @parent ? @parent.xml : ::Builder::XmlMarkup.new
7
+ end
8
+
9
+ def show view, args
10
+ view ||= :feed
11
+ render! view, args
12
+ end
13
+
14
+ # FIXME: integrate this with common XML features when it is added
15
+ view :feed, cache: :never do
16
+ return "RSS feeds disabled" unless Cardio.config.rss_enabled
17
+ begin
18
+ @xml.instruct! :xml, version: "1.0", standalone: "yes"
19
+ @xml.rss version: "2.0",
20
+ "xmlns:content" => "http://purl.org/rss/1.0/modules/content/" do
21
+ @xml.channel do
22
+ @xml.title render_feed_title
23
+ @xml.description render_feed_description
24
+ @xml.link render_url
25
+ render_feed_body
26
+ end
27
+ end
28
+ rescue => e
29
+ @xml.error "\n\nERROR rendering RSS: #{e.inspect}\n\n #{e.backtrace}"
30
+ end
31
+ end
32
+
33
+ def raw_feed_items
34
+ [card]
35
+ end
36
+
37
+ view :feed_body, cache: :never do
38
+ raw_feed_items.each do |item|
39
+ @xml.item do
40
+ subformat(item).render! :feed_item
41
+ end
42
+ end
43
+ end
44
+
45
+ view :feed_title do
46
+ Card::Rule.global_setting(:title) + " : " + card.name.gsub(/^\*/, "")
47
+ end
48
+
49
+ view :feed_item do
50
+ @xml.title card.name
51
+ add_name_context
52
+ @xml.description render_feed_item_description
53
+ @xml.pubDate pub_date
54
+ @xml.link render_url
55
+ @xml.guid render_url
56
+ end
57
+
58
+ def pub_date
59
+ (card.updated_at || Time.zone.now).to_s(:rfc822)
60
+ # updated_at fails on virtual
61
+ # cards, because not all to_s's take args (just actual dates)
62
+ end
63
+
64
+ view :feed_item_description do
65
+ render_open_content
66
+ end
67
+
68
+ view(:feed_description) { "" }
69
+ view(:comment_box) { "" }
70
+ view(:menu) { "" }
71
+
72
+ view :open, :titled, mod: All::Base::Format
73
+ view :content, :core, mod: All::Base::Format
74
+ view :open_content, :core, mod: All::Base::Format
75
+ view :closed, :link, mod: All::Base::Format
76
+ end
@@ -0,0 +1,7 @@
1
+
2
+ format :text do
3
+ view :core do
4
+ HTMLEntities.new.decode strip_tags(super()).to_s
5
+ # need this string method to get out of html_safe mode
6
+ end
7
+ end