comet-cpp 0.9.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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/bin/comet-html +69 -0
  3. data/bin/comet-make +53 -0
  4. data/bin/comet-new +62 -0
  5. data/bin/comet-web +14 -0
  6. data/lib/comet-html/generator.rb +220 -0
  7. data/lib/comet-html/header-generator.rb +145 -0
  8. data/lib/comet-html/parser-binding.rb +42 -0
  9. data/lib/comet-html/parser-class.rb +168 -0
  10. data/lib/comet-html/parser-context.rb +61 -0
  11. data/lib/comet-html/parser-reference.rb +98 -0
  12. data/lib/comet-html/parser-repeater.rb +58 -0
  13. data/lib/comet-html/parser-slot.rb +108 -0
  14. data/lib/comet-html/source-generator.rb +285 -0
  15. data/lib/comet-html/utils.rb +88 -0
  16. data/lib/guard/comet-html.rb +32 -0
  17. data/lib/guard/comet.rb +36 -0
  18. data/vendor/project/Gemfile +4 -0
  19. data/vendor/project/Guardfile +5 -0
  20. data/vendor/project/app/application.hpp +29 -0
  21. data/vendor/project/app/collections/.gitkeep +0 -0
  22. data/vendor/project/app/controllers/.gitkeep +0 -0
  23. data/vendor/project/app/main.cpp +6 -0
  24. data/vendor/project/app/models/.gitkeep +0 -0
  25. data/vendor/project/app/routes.cpp +7 -0
  26. data/vendor/project/app/views/layouts/.gitkeep +0 -0
  27. data/vendor/project/public/index.html +7 -0
  28. data/vendor/src/anchorable_element.hpp +79 -0
  29. data/vendor/src/append_semantics.hpp +73 -0
  30. data/vendor/src/bindable.cpp +99 -0
  31. data/vendor/src/bindable.hpp +106 -0
  32. data/vendor/src/cheerp_parse_cookie_values.cpp +58 -0
  33. data/vendor/src/comment_element.cpp +11 -0
  34. data/vendor/src/comment_element.hpp +17 -0
  35. data/vendor/src/cookies.cpp +94 -0
  36. data/vendor/src/cookies.hpp +60 -0
  37. data/vendor/src/custom_element.hpp +61 -0
  38. data/vendor/src/datatree.cpp +198 -0
  39. data/vendor/src/datatree.hpp +233 -0
  40. data/vendor/src/document.cpp +62 -0
  41. data/vendor/src/document.hpp +31 -0
  42. data/vendor/src/element.cpp +358 -0
  43. data/vendor/src/element.hpp +138 -0
  44. data/vendor/src/events.hpp +76 -0
  45. data/vendor/src/exception.cpp +13 -0
  46. data/vendor/src/exception.hpp +11 -0
  47. data/vendor/src/from_string.cpp +99 -0
  48. data/vendor/src/from_string.hpp +37 -0
  49. data/vendor/src/globals.cpp +6 -0
  50. data/vendor/src/globals.hpp +15 -0
  51. data/vendor/src/http.cpp +93 -0
  52. data/vendor/src/http.hpp +72 -0
  53. data/vendor/src/lexical_cast.hpp +51 -0
  54. data/vendor/src/local_storage.cpp +75 -0
  55. data/vendor/src/local_storage.hpp +53 -0
  56. data/vendor/src/mvc/collection.hpp +154 -0
  57. data/vendor/src/mvc/controller.hpp +59 -0
  58. data/vendor/src/mvc/id_type.hpp +9 -0
  59. data/vendor/src/mvc/layout.hpp +44 -0
  60. data/vendor/src/mvc/model.cpp +89 -0
  61. data/vendor/src/mvc/model.hpp +50 -0
  62. data/vendor/src/object.cpp +71 -0
  63. data/vendor/src/object.hpp +298 -0
  64. data/vendor/src/parse_cookie_values.hpp +12 -0
  65. data/vendor/src/promise.cpp +50 -0
  66. data/vendor/src/promise.hpp +43 -0
  67. data/vendor/src/repeater.hpp +116 -0
  68. data/vendor/src/router.cpp +62 -0
  69. data/vendor/src/router.hpp +34 -0
  70. data/vendor/src/router_base.hpp +107 -0
  71. data/vendor/src/signal.hpp +150 -0
  72. data/vendor/src/slot_element.hpp +61 -0
  73. data/vendor/src/url.cpp +19 -0
  74. data/vendor/src/url.hpp +15 -0
  75. data/vendor/src/window.cpp +22 -0
  76. data/vendor/src/window.hpp +24 -0
  77. metadata +134 -0
@@ -0,0 +1,285 @@
1
+ module Comet
2
+ class SourceGenerator
3
+ attr_reader :object, :source
4
+
5
+ def initialize object
6
+ @object = object
7
+ end
8
+
9
+ def generate
10
+ @source = generate_constructor_header
11
+ @source += generate_constructor_body
12
+ @source += generate_constructor_footer + "\n"
13
+ @source += generate_method_bind_attributes + "\n"
14
+ @source += generate_method_trigger_binding_updates
15
+ @source
16
+ end
17
+
18
+ def tag_name
19
+ if @object.parent.nil?
20
+ if @object.el.first["tag-name"].nil?
21
+ @object.typename.dasherize
22
+ else
23
+ @object.el.first["tag-name"]
24
+ end
25
+ else
26
+ @object.el.name
27
+ end
28
+ end
29
+
30
+ def root_ptr
31
+ if object.parent.nil? then "this" else "root" end
32
+ end
33
+
34
+ def get_root_from_parent_code parent_symbol
35
+ if object.is_root?
36
+ "this"
37
+ else
38
+ result = parent_symbol
39
+ current_parent = object.parent
40
+ until current_parent.parent.nil?
41
+ result += "->parent"
42
+ current_parent = current_parent.parent
43
+ end
44
+ result
45
+ end
46
+ end
47
+
48
+ def make_parent_to_root_initializer parent_symbol
49
+ "root(#{get_root_from_parent_code(parent_symbol)})"
50
+ end
51
+
52
+ def generate_constructor_header
53
+ initializers = []
54
+ parent_symbol = "__p"
55
+ root_getter = get_root_from_parent_code parent_symbol
56
+
57
+ case object.superclass
58
+ when object.context.template_base_type then
59
+ initializers << "#{object.context.template_base_type}(\"#{tag_name}\")"
60
+ # when object.context.template_base_subtype then
61
+ # initializers << "#{object.context.template_base_subtype}(\"#{tag_name}\", #{parent_symbol}->signaler)"
62
+ end
63
+
64
+ # Constructor
65
+ result = "HtmlTemplate::#{object.typename}::#{object.typename}("
66
+ unless object.is_root?
67
+ initializers << make_parent_to_root_initializer(parent_symbol)
68
+ result += "#{object.parent.typename}* #{parent_symbol}"
69
+ else
70
+ initializers << "root(this)"
71
+ end
72
+ (object.refs.select{|r| r.has_initializer?}).each do |ref|
73
+ initializers << "#{ref.name}(#{ref.initializer root_getter})"
74
+ end
75
+ unless object.is_root?
76
+ initializers << "signaler(#{parent_symbol}->signaler)" unless object.implements_ibindable_view?
77
+ initializers << "parent(#{parent_symbol})"
78
+ end
79
+ if object.class == Repeater
80
+ initializers << "#{object.value_name}(__i)"
81
+ result += ", #{object.value_type} __i"
82
+ end
83
+ unless object.is_root?
84
+ object.slots.each do |slot|
85
+ initializers << "#{slot.slot_ref}(#{root_getter}->#{slot.slot_ref})"
86
+ end
87
+ end
88
+ result += ")"
89
+ result += " : " + initializers.join(", ") if initializers.count > 0
90
+ result += "\n"
91
+ result += "{\n"
92
+ result
93
+ end
94
+
95
+ def generate_constructor_body
96
+ result = generate_element_initializers
97
+ result += generate_binding_initializers
98
+ result += generate_dom_constructor
99
+ result += generate_anchors_initializers
100
+ result
101
+ end
102
+
103
+ def generate_constructor_footer
104
+ result = ""
105
+ result += "}\n"
106
+ result
107
+ end
108
+
109
+ def generate_element_initializers
110
+ result = ""
111
+ object.refs.each do |ref|
112
+ if ref.type == "Comet::Element"
113
+ result += " #{ref.name} = Comet::Element(\"#{ref.el.name}\");\n"
114
+ end
115
+ end
116
+ result
117
+ end
118
+
119
+ def generate_binding_initializers
120
+ result = ""
121
+ object.bindings.each do |binding|
122
+ ref = object.find_reference_for binding.el
123
+ initializer = if binding.binds_to_cpp_property?
124
+ "Comet::Bindable([this]() { #{ref.name}.set_#{binding.attribute_name}(#{binding.code}); })"
125
+ elsif binding.attribute_name == "show"
126
+ "Comet::Bindable([this]() { #{ref.name}.visible(#{binding.code}); })"
127
+ elsif binding.attribute_name == "text"
128
+ "Comet::Bindable([this]() { #{ref.name}.text(#{binding.code}); })"
129
+ elsif binding.attribute_name == "innerhtml"
130
+ "Comet::Bindable([this]() { #{ref.name}.html(#{binding.code}); })"
131
+ else
132
+ "Comet::Bindable(#{ref.name}, \"#{binding.attribute_name}\", [this]() -> std::string { return Comet::lexical_cast<std::string>(#{binding.code}); })"
133
+ end
134
+ result += " bound_attributes.push_back(#{initializer}#{binding.bind_mode});\n"
135
+ end
136
+
137
+ object.repeaters.each do |repeater|
138
+ refresh_code = "#{repeater.repeater_name}.refresh(this, #{repeater.list_name});"
139
+ initializer = "Comet::Bindable([this]() { #{refresh_code} })"
140
+ result += " bound_attributes.push_back(#{initializer}#{repeater.bind_mode});\n"
141
+ end
142
+
143
+ object.event_listeners.each do |event_listener|
144
+ ref = object.find_reference_for event_listener.el
145
+ unless event_listener.is_cpp
146
+ result += " #{ref.name}.events->on(\"#{event_listener.attribute_name}\", [this](client::Event* _event) { #{event_listener.code}; });\n"
147
+ else
148
+ result += " #{ref.name}.signaler.connect([this](std::string signal_name)\n"
149
+ result += " {\n"
150
+ result += " if (signal_name == \"#{event_listener.attribute_name}\")\n"
151
+ result += " {\n"
152
+ result += " #{event_listener.code};\n"
153
+ result += " }\n"
154
+ result += " });\n"
155
+ end
156
+ end
157
+ result
158
+ end
159
+
160
+ def generate_dom_constructor
161
+ result = ""
162
+ source_el = if object.is_root? then object.el.first else object.el end
163
+ html_attributes = make_attr_from_el source_el
164
+ result += " attr({#{html_attributes.join ','}});\n" if html_attributes.length > 0
165
+ dom_code = dom_generator object.el, 4
166
+ result += " inner({#{dom_code}\n });\n" unless dom_code.empty?
167
+ result
168
+ end
169
+
170
+ def dom_generator el, indent
171
+ result = ""
172
+ count = 0
173
+ el.children.each do |el|
174
+ sub_object = object.find_class_for el
175
+ if !sub_object.nil? && sub_object.is_anchorable?
176
+ result += "," if count > 0
177
+ result += "\n" + (" " * indent)
178
+ result += sub_object.anchor_name
179
+ count += 1
180
+ elsif !(el["_cheerp_class"].nil?)
181
+ next
182
+ elsif el.name != "text" && el.name != "comment"
183
+ reference = object.find_reference_for(el)
184
+ html_attributes = make_attr_from_el el
185
+
186
+ result += "," if count > 0
187
+ result += "\n" + (" " * indent)
188
+
189
+ result += if reference.nil? then "Comet::Element(\"#{el.name}\")" else reference.name end
190
+ result += ".attr({#{html_attributes.join ','}})" if html_attributes.count > 0
191
+ children_result = dom_generator el, indent + 2
192
+ result += ".inner({#{children_result}\n#{" " * indent}})" if children_result.length > 0
193
+
194
+ count += 1
195
+ elsif el.name == "text" && !(el.text.strip.empty?)
196
+ escaped_text = el.text.gsub /"/, "\\\""
197
+ escaped_text.gsub! "\n", '\n'
198
+ result += "," if count > 0
199
+ result += "\n" + (" " * indent)
200
+ result += "Comet::Element(\"span\").text(\"#{escaped_text}\")"
201
+ count += 1
202
+ end
203
+ end
204
+ result
205
+ end
206
+
207
+ def generate_anchors_initializers
208
+ result = ""
209
+ object.repeaters.each do |repeater|
210
+ result += " #{repeater.repeater_name}.set_anchor(#{repeater.anchor_name}, #{anchor_symbol_to_enum :append});\n"
211
+ end
212
+
213
+ object.slots.each do |slot|
214
+ result += " #{slot.slot_ref}.set_anchor(#{slot.anchor_name}, #{anchor_symbol_to_enum :append});\n"
215
+ result += " #{slot.slot_ref}.set_element(std::make_shared<#{slot.typename}>(this));\n"
216
+ end
217
+
218
+ object.slot_plugins.each do |slot_plugin|
219
+ ref = object.find_reference_for(slot_plugin.on_element)
220
+ initializer = if slot_plugin.has_ref?
221
+ "root->#{slot_plugin.el["ref"]}"
222
+ else
223
+ "std::make_shared<#{slot_plugin.typename}>(#{slot_plugin.constructor_params})"
224
+ end
225
+ result += " #{ref.name}.slot_#{slot_plugin.slot_name}.set_element(#{initializer});\n"
226
+ end
227
+ result
228
+ end
229
+
230
+ def inherits_binding_methods?
231
+ !([object.context.template_base_type, object.context.template_base_subtype].include? object.superclass)
232
+ end
233
+
234
+ def generate_method_bind_attributes
235
+ result = ""
236
+ result += "void HtmlTemplate::#{object.typename}::bind_attributes()\n"
237
+ result += "{\n"
238
+ if inherits_binding_methods?
239
+ result += " #{object.superclass}::bind_attributes();\n"
240
+ else
241
+ result += " bound_attributes.enable(signaler);\n"
242
+ end
243
+ object.refs.each do |ref|
244
+ if ref.el && object.context.has_cpp_type?(ref.el)
245
+ result += " #{ref.name}.bind_attributes();\n"
246
+ result += " signaler.connect([this](std::string _event) { #{ref.name}.signaler.trigger(_event); });\n"
247
+ end
248
+ end
249
+ object.repeaters.each do |repeater|
250
+ result += " #{repeater.repeater_name}.bind_attributes();\n"
251
+ end
252
+ object.slots.each do |slot|
253
+ result += " if (#{slot.slot_ref}.has_element())\n"
254
+ result += " #{slot.slot_ref}.get_element()->bind_attributes();\n"
255
+ end
256
+ result += "}\n"
257
+ result
258
+ end
259
+
260
+ def generate_method_trigger_binding_updates
261
+ result = ""
262
+ result += "void HtmlTemplate::#{object.typename}::trigger_binding_updates()\n"
263
+ result += "{\n"
264
+ if inherits_binding_methods?
265
+ result += " #{object.superclass}::trigger_binding_updates();\n"
266
+ else
267
+ result += " bound_attributes.update();\n"
268
+ end
269
+ object.refs.each do |ref|
270
+ if ref.el && object.context.has_cpp_type?(ref.el)
271
+ result += " #{ref.name}.trigger_binding_updates();\n"
272
+ end
273
+ end
274
+ object.repeaters.each do |repeater|
275
+ result += " #{repeater.repeater_name}.trigger_binding_updates();\n"
276
+ end
277
+ object.slots.each do |slot|
278
+ result += " if (#{slot.slot_ref}.has_element())\n"
279
+ result += " #{slot.slot_ref}.get_element()->trigger_binding_updates();\n"
280
+ end
281
+ result += "}\n"
282
+ result
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,88 @@
1
+ class String
2
+ def camelize
3
+ parts = self.split(/_+|-+|\W+/)
4
+ (parts.map do |part| part.capitalize end).join
5
+ end
6
+
7
+ def dasherize
8
+ tmp = self.gsub(/([A-Z]+)/, '_\1')
9
+ parts = tmp.split(/_+|-+|\W+/)
10
+ parts.select! {|item| item != ""}
11
+ (parts.map do |part| part.downcase end).join '-'
12
+ end
13
+ end
14
+
15
+ #module Comet
16
+ def find_anchorable_anchor el
17
+ it = el
18
+ loop do
19
+ it = it.previous
20
+ break if it.nil? || it.name != "text" || it.name == "comment"
21
+ end
22
+ unless it.nil?
23
+ { el: it, mode: :append }
24
+ else
25
+ it = el
26
+ loop do
27
+ it = it.next
28
+ break if it.nil? || it.name != "text" || it.name == "comment"
29
+ end
30
+ unless it.nil?
31
+ { el: it, mode: :prepend }
32
+ else
33
+ { el: el.parent, mode: :children }
34
+ end
35
+ end
36
+ end
37
+
38
+ def anchor_symbol_to_enum anchor_name
39
+ "Comet::" + case anchor_name
40
+ when :append then "AppendAnchor"
41
+ when :prepend then "PrependAnchor"
42
+ when :children then "ChildrenAnchor"
43
+ end
44
+ end
45
+
46
+ def has_trigger_attributes? el
47
+ result = false
48
+ el.attributes.each do |key,value|
49
+ result = true if key.end_with?(".trigger")
50
+ end
51
+ result
52
+ end
53
+
54
+ def make_attr_from_el el
55
+ hard_attributes = []
56
+ el.attributes.each do |key, value|
57
+ reserved_keywords = ["ref", "slot", "_cheerp_class", "_cheerp_ref"]
58
+ if !reserved_keywords.include?(key) && !(key.end_with? ".bind") && !(key.end_with? ".trigger") && !(key.end_with? ".for")
59
+ hard_attributes << "{\"#{key}\",\"#{value}\"}"
60
+ end
61
+ end
62
+ hard_attributes
63
+ end
64
+
65
+ def extract_bind_mode_from value
66
+ bind_mode_match = value.to_s.match(/\s*&\s*(throttle|signal):([a-zA-Z0-9_-]+)$/)
67
+ if bind_mode_match.nil?
68
+ bind_mode = ""
69
+ else
70
+ value = value.to_s.delete_suffix bind_mode_match[0]
71
+ bind_mode_enum = case bind_mode_match[1]
72
+ when 'signal' then "SignalBind"
73
+ when 'throttle' then "ThrottleBind"
74
+ else "StaticBind"
75
+ end
76
+ bind_mode = ".use_mode(Comet::Bindable::#{bind_mode_enum}, \"#{bind_mode_match[2]}\")"
77
+ end
78
+ [value, bind_mode]
79
+ end
80
+
81
+ def is_valid_cpp_variable_name? value
82
+ if value.length <= 255
83
+ not (value.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/).nil?)
84
+ else
85
+ false
86
+ end
87
+ end
88
+ #end
@@ -0,0 +1,32 @@
1
+ module ::Guard
2
+ class CometHtml < Plugin
3
+ def initialize options = {}
4
+ @options = options
5
+ super
6
+ end
7
+
8
+ def run_on_modifications(paths)
9
+ run_all
10
+ end
11
+
12
+ def generate_command
13
+ gemspec = Gem::Specification.find_all_by_name("comet-cpp").first
14
+ command = "#{gemspec.bin_dir}/comet-html"
15
+ command += " -i '#{@options[:source]}'" unless @options[:source].nil?
16
+ command += " -o '#{@options[:output]}'" unless @options[:output].nil?
17
+ command += " -c '#{@options[:config]}'" unless @options[:config].nil?
18
+ command
19
+ end
20
+
21
+ def run_all
22
+ PTY.spawn(generate_command) do |stdout,stdin,pid|
23
+ begin
24
+ stdout.each {|line| print line}
25
+ rescue Errno::EIO
26
+ end
27
+ Process.wait(pid)
28
+ end
29
+ if $?.success? then :success else :failure end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ require 'pty'
2
+
3
+ module ::Guard
4
+ class Comet < Plugin
5
+ def initialize options = {}
6
+ @options = options
7
+ super
8
+ end
9
+
10
+ def run_on_modifications(paths)
11
+ run_all
12
+ end
13
+
14
+ def compile_command
15
+ gemspec = Gem::Specification.find_all_by_name("comet-cpp").first
16
+ compiler = "#{gemspec.bin_dir}/comet-make"
17
+ command = "#{compiler}"
18
+ command += " -c '#{@options[:cheerp_path]}'" unless @options[:cheerp_path].nil?
19
+ command += " -i '#{@options[:cmakelists]}'" unless @options[:cmakelists].nil?
20
+ command += " -o '#{@options[:output]}'" unless @options[:output].nil?
21
+ command += " -g" if @options[:debug] == true
22
+ command
23
+ end
24
+
25
+ def run_all
26
+ PTY.spawn(compile_command) do |stdout,stdin,pid|
27
+ begin
28
+ stdout.each {|line| print line}
29
+ rescue Errno::EIO
30
+ end
31
+ Process.wait(pid)
32
+ end
33
+ if $?.success? then :success else :failure end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'guard'
4
+ gem 'comet-cpp'
@@ -0,0 +1,5 @@
1
+ guard 'comet-html' do
2
+ watch(%r{^app/.+\.html$})
3
+ end
4
+
5
+ guard 'comet'
@@ -0,0 +1,29 @@
1
+ #ifndef MY_APPLICATION_HPP
2
+ # define MY_APPLICATION_HPP
3
+
4
+ # include <comet/router.hpp>
5
+
6
+ class Application
7
+ {
8
+ Application() {}
9
+ Application(const Application&) = delete;
10
+ void operator=(const Application&) = delete;
11
+
12
+ public:
13
+ static Application& get()
14
+ {
15
+ static Application instance;
16
+ return instance;
17
+ }
18
+
19
+ static void start()
20
+ {
21
+ auto& app = get();
22
+
23
+ app.router.start();
24
+ }
25
+
26
+ Comet::Router router;
27
+ };
28
+
29
+ #endif
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ #include "application.hpp"
2
+
3
+ void webMain()
4
+ {
5
+ Application::start();
6
+ }
File without changes
@@ -0,0 +1,7 @@
1
+ #include <comet/router.hpp>
2
+
3
+ using namespace Comet;
4
+
5
+ void Router::initialize()
6
+ {
7
+ }
File without changes
@@ -0,0 +1,7 @@
1
+ <html>
2
+ <head>
3
+ <title>Hello comet</title>
4
+ <script src="/application.js"></script>
5
+ </head>
6
+ <body comet-app="main"></body>
7
+ </html>
@@ -0,0 +1,79 @@
1
+ #ifndef COMET_ANCHORABLE_ELEMENT_HPP
2
+ # define COMET_ANCHORABLE_ELEMENT_HPP
3
+
4
+ # include "element.hpp"
5
+ # include "exception.hpp"
6
+
7
+ namespace Comet
8
+ {
9
+ enum AnchorMode
10
+ {
11
+ ChildrenAnchor,
12
+ AppendAnchor,
13
+ PrependAnchor,
14
+ AnchorsEnd
15
+ };
16
+
17
+ struct AnchorableElement
18
+ {
19
+ Comet::Element anchor;
20
+ AnchorMode anchor_mode = AnchorsEnd;
21
+
22
+ inline void set_anchor(Comet::Element el, AnchorMode mode)
23
+ {
24
+ anchor = el;
25
+ anchor_mode = mode;
26
+ }
27
+
28
+ inline bool is_anchorable() const
29
+ {
30
+ return anchor_mode != AnchorsEnd;
31
+ }
32
+
33
+ template<typename LIST>
34
+ void attach_elements(const LIST& elements)
35
+ {
36
+ switch (anchor_mode)
37
+ {
38
+ case ChildrenAnchor:
39
+ for (auto el : elements)
40
+ el->append_to(anchor);
41
+ break ;
42
+ case AppendAnchor:
43
+ append_to_anchor(elements);
44
+ break ;
45
+ case PrependAnchor:
46
+ prepend_to_anchor(elements);
47
+ break ;
48
+ case AnchorsEnd:
49
+ raise(std::logic_error("AnchorableElement::attach_element called with unset anchor"));
50
+ break ;
51
+ }
52
+ }
53
+
54
+ private:
55
+ template<typename LIST>
56
+ void append_to_anchor(const LIST& elements)
57
+ {
58
+ auto current_anchor = anchor;
59
+ for (auto it = elements.begin() ; it != elements.end() ; ++it)
60
+ {
61
+ (*it)->insert_after(current_anchor);
62
+ current_anchor = Comet::Element(*(*it));
63
+ }
64
+ }
65
+
66
+ template<typename LIST>
67
+ void prepend_to_anchor(const LIST& elements)
68
+ {
69
+ auto current_anchor = anchor;
70
+ for (auto it = elements.rbegin() ; it != elements.rend() ; ++it)
71
+ {
72
+ (*it)->insert_before(current_anchor);
73
+ current_anchor = Comet::Element(*(*it));
74
+ }
75
+ }
76
+ };
77
+ }
78
+
79
+ #endif
@@ -0,0 +1,73 @@
1
+ #ifndef CRAILS_FRONT_APPEND_SEMANTICS_HPP
2
+ # define CRAILS_FRONT_APPEND_SEMANTICS_HPP
3
+
4
+ # include <cheerp/clientlib.h>
5
+ # include <vector>
6
+ # include <list>
7
+ # include <memory>
8
+ # include <type_traits>
9
+
10
+ /*
11
+ * Type solving tools for the `inner` and `operator>` methods of Comet::Element
12
+ * - support std::list and std::vector containers, or passing by value
13
+ * - support pointer and non-pointer value types (including shared_ptr)
14
+ */
15
+ namespace Comet
16
+ {
17
+ class Element;
18
+
19
+ template<typename Test, template<typename...> class Ref>
20
+ struct is_specialization : std::false_type {};
21
+
22
+ template<template<typename...> class Ref, typename... Args>
23
+ struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
24
+
25
+ template<typename Test>
26
+ struct is_array_container
27
+ {
28
+ static const bool value = is_specialization<Test, std::vector>::value || is_specialization<Test, std::list>::value;
29
+ };
30
+
31
+ template<typename ELEMENT, bool is_pointer>
32
+ struct ElementAppender
33
+ {
34
+ static void append_a_to_b(const ELEMENT& a, client::HTMLElement* b)
35
+ {
36
+ b->appendChild(*a);
37
+ }
38
+ };
39
+
40
+ template<typename ELEMENT>
41
+ struct ElementAppender<ELEMENT, true>
42
+ {
43
+ static void append_a_to_b(const ELEMENT& a, client::HTMLElement* b)
44
+ {
45
+ b->appendChild(**a);
46
+ }
47
+ };
48
+
49
+ template<typename CONTAINER, bool is_array>
50
+ struct ElementListAppender
51
+ {
52
+ static void append_list(const CONTAINER& container, client::HTMLElement* ptr)
53
+ {
54
+ constexpr bool is_ptr = std::is_pointer<typename CONTAINER::value_type>::value || std::is_same<typename CONTAINER::value_type, std::shared_ptr<Comet::Element> >::value;
55
+
56
+ for (const auto& i : container)
57
+ ElementAppender<typename CONTAINER::value_type, is_ptr>::append_a_to_b(i, ptr);
58
+ }
59
+ };
60
+
61
+ template<typename CONTAINER>
62
+ struct ElementListAppender<CONTAINER, false>
63
+ {
64
+ static void append_list(const CONTAINER& container, client::HTMLElement* ptr)
65
+ {
66
+ constexpr bool is_ptr = std::is_pointer<CONTAINER>::value || std::is_same<CONTAINER, std::shared_ptr<Comet::Element> >::value;
67
+
68
+ ElementAppender<CONTAINER, is_ptr>::append_a_to_b(container, ptr);
69
+ }
70
+ };
71
+ }
72
+
73
+ #endif