wunderbar 0.18.3 → 0.19.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 (32) hide show
  1. data/README.md +6 -0
  2. data/lib/wunderbar/{angular-resource.rb → angularjs/resource.rb} +1 -1
  3. data/lib/wunderbar/{angular-route.rb → angularjs/route.rb} +1 -1
  4. data/lib/wunderbar/angularjs.rb +1 -1
  5. data/lib/wunderbar/asset.rb +17 -6
  6. data/lib/wunderbar/builder.rb +8 -11
  7. data/lib/wunderbar/cgi-methods.rb +4 -5
  8. data/lib/wunderbar/cssproxy.rb +4 -0
  9. data/lib/wunderbar/html-methods.rb +9 -5
  10. data/lib/wunderbar/job-control.rb +2 -0
  11. data/lib/wunderbar/jquery/stupidtable.rb +5 -0
  12. data/lib/wunderbar/jquery.rb +2 -1
  13. data/lib/wunderbar/markdown.rb +1 -0
  14. data/lib/wunderbar/node.rb +34 -12
  15. data/lib/wunderbar/{opal-browser.rb → opal/browser.rb} +0 -0
  16. data/lib/wunderbar/{opal-jquery.rb → opal/jquery.rb} +0 -0
  17. data/lib/wunderbar/pagedown.rb +5 -0
  18. data/lib/wunderbar/polymer.rb +1 -1
  19. data/lib/wunderbar/script.rb +16 -3
  20. data/lib/wunderbar/sinatra.rb +7 -2
  21. data/lib/wunderbar/vendor/Markdown.Converter.js +1412 -0
  22. data/lib/wunderbar/{angular-resource.min.js → vendor/angular-resource.min.js} +0 -0
  23. data/lib/wunderbar/{angular-route.min.js → vendor/angular-route.min.js} +0 -0
  24. data/lib/wunderbar/{angular.min.js → vendor/angular.min.js} +0 -0
  25. data/lib/wunderbar/{jquery-1.10.2.min.js → vendor/jquery-1.10.2.min.js} +0 -0
  26. data/lib/wunderbar/{polymer-v0.0.20131003.min.js → vendor/polymer-v0.0.20131003.min.js} +0 -0
  27. data/lib/wunderbar/vendor/stupidtable.min.js +1 -0
  28. data/lib/wunderbar/version.rb +2 -2
  29. data/lib/wunderbar/websocket.rb +1 -1
  30. data/lib/wunderbar.rb +0 -1
  31. data/wunderbar.gemspec +3 -3
  32. metadata +17 -13
data/README.md CHANGED
@@ -16,6 +16,8 @@ the element id and class id syntax and based on the implementation from
16
16
  Wunderbar's JSON support is inspired by David Heinemeier Hansson's
17
17
  [jbuilder](https://github.com/rails/jbuilder).
18
18
 
19
+ A [tutorial](https://github.com/rubys/wunderbar/blob/master/docs/Introduction1.md) is under development.
20
+
19
21
  Overview
20
22
  ---
21
23
 
@@ -76,6 +78,10 @@ Element with boolean attributes:
76
78
 
77
79
  _input 'Cheese', type: 'checkbox', name: 'cheese', checked: true
78
80
 
81
+ Element with boolean attributes (alternate form):
82
+
83
+ _input 'Cheese', :checked, type: 'checkbox', name: 'cheese'
84
+
79
85
  Element with optional (omitted) attributes:
80
86
 
81
87
  _tr class: nil
@@ -1,6 +1,6 @@
1
1
  require 'wunderbar/angularjs'
2
2
  require 'ruby2js/filter/angular-resource'
3
3
 
4
- source = File.expand_path('../angular-resource.min.js', __FILE__)
4
+ source = File.expand_path('../../vendor/angular-resource.min.js', __FILE__)
5
5
 
6
6
  Wunderbar::Asset.script :name => 'angular-resource.min.js', :file => source
@@ -1,6 +1,6 @@
1
1
  require 'wunderbar/angularjs'
2
2
  require 'ruby2js/filter/angular-route'
3
3
 
4
- source = File.expand_path('../angular-route.min.js', __FILE__)
4
+ source = File.expand_path('../../vendor/angular-route.min.js', __FILE__)
5
5
 
6
6
  Wunderbar::Asset.script :name => 'angular-route.min.js', :file => source
@@ -1,6 +1,6 @@
1
1
  require 'wunderbar/script'
2
2
  require 'ruby2js/filter/angularrb'
3
3
 
4
- source = File.expand_path('../angular.min.js', __FILE__)
4
+ source = File.expand_path('../vendor/angular.min.js', __FILE__)
5
5
 
6
6
  Wunderbar::Asset.script :name => 'angular-min.js', :file => source
@@ -21,10 +21,21 @@ module Wunderbar
21
21
  @@stylesheets = []
22
22
  end
23
23
 
24
+ def self.content_type_for(path)
25
+ if @@scripts.any? {|script| script.path == path}
26
+ 'application/javascript'
27
+ elsif @@stylesheets.any? {|script| script.path == path}
28
+ 'text/css'
29
+ else
30
+ 'application/octet-stream'
31
+ end
32
+ end
33
+
24
34
  clear
25
35
 
26
- @path = '../' * ENV['PATH_INFO'].to_s.count('/')
36
+ @path = '../' * ENV['PATH_INFO'].to_s.count('/') + 'assets'
27
37
  @root = File.dirname(ENV['SCRIPT_FILENAME']) if ENV['SCRIPT_FILENAME']
38
+ @root = File.expand_path((@root || Dir.pwd) + "/assets")
28
39
 
29
40
  # Options: typically :name plus either :file or :contents
30
41
  # :name => name to be used for the asset
@@ -37,8 +48,8 @@ module Wunderbar
37
48
  options[:name] ||= File.basename(options[:file]) if source
38
49
 
39
50
  if options[:name]
40
- @path = "assets/#{options[:name]}"
41
- dest = File.expand_path(@path, Asset.root || Dir.pwd)
51
+ @path = options[:name]
52
+ dest = File.expand_path(@path, Asset.root)
42
53
 
43
54
  if not File.exist?(dest) or File.mtime(dest) < File.mtime(source)
44
55
  begin
@@ -69,7 +80,7 @@ module Wunderbar
69
80
  Proc.new do
70
81
  @@scripts.each do |script|
71
82
  if script.path
72
- _script :src => Asset.path+script.path
83
+ _script src: "#{Asset.path}/#{script.path}"
73
84
  elsif script.contents
74
85
  _script script.contents
75
86
  end
@@ -77,8 +88,8 @@ module Wunderbar
77
88
 
78
89
  @@stylesheets.each do |stylesheet|
79
90
  if stylesheet.path
80
- _link :rel => "stylesheet", :href => Asset.path+stylesheet.path,
81
- :type => "text/css"
91
+ _link rel: "stylesheet", href: "#{Asset.path}/#{stylesheet.path}",
92
+ type: "text/css"
82
93
  elsif stylesheet.contents
83
94
  _style stylesheet.contents
84
95
  end
@@ -37,6 +37,8 @@ module Wunderbar
37
37
  @spaced = false
38
38
  end
39
39
 
40
+ attr_accessor :width
41
+
40
42
  # forward to Wunderbar or @_scope
41
43
  def method_missing(method, *args, &block)
42
44
  if Wunderbar.respond_to? method
@@ -81,7 +83,7 @@ module Wunderbar
81
83
  end
82
84
 
83
85
  def target!
84
- "#{@doc.serialize(indent: ' ' * @_indent).join("\n")}\n"
86
+ "#{@doc.serialize(indent: ' ' * @_indent, width: @width).join("\n")}\n"
85
87
  end
86
88
 
87
89
  def clear!
@@ -89,9 +91,8 @@ module Wunderbar
89
91
  @node = @doc
90
92
  end
91
93
 
92
- def compact!(width, &block)
94
+ def compact!(&block)
93
95
  begin
94
- @width = width
95
96
  @indentation_enabled = false
96
97
  block.call
97
98
  ensure
@@ -118,8 +119,7 @@ module Wunderbar
118
119
  attributes.merge!(node.namespaces) if node.namespaces
119
120
  args.push attributes
120
121
  if node.namespace and node.namespace.prefix
121
- args.unshift node.name.to_sym
122
- sym = node.namespace.prefix
122
+ sym = "#{node.namespace.prefix}:#{node.name}"
123
123
  else
124
124
  sym = node.name
125
125
  end
@@ -131,10 +131,7 @@ module Wunderbar
131
131
  node = Node.new sym, *args
132
132
  end
133
133
 
134
- unless @indentation_enabled
135
- node.extend CompactNode
136
- node.width = @width
137
- end
134
+ node.extend CompactNode unless @indentation_enabled
138
135
 
139
136
  if @spaced
140
137
  node.extend SpacedNode
@@ -320,7 +317,7 @@ module Wunderbar
320
317
  end
321
318
  else
322
319
  # disable indentation on the entire element
323
- compact!(nil) do
320
+ compact! do
324
321
  tag!(child) {self[*child.children]}
325
322
  end
326
323
  end
@@ -331,7 +328,7 @@ module Wunderbar
331
328
  elsif child.children.any?(&:cdata?) and child.text =~ /[<&]/
332
329
  self << child
333
330
  elsif child.name == 'pre'
334
- compact!(nil) { tag!(child) {self[*child.children]} }
331
+ compact! { tag!(child) {self[*child.children]} }
335
332
  elsif child.name == 'head'
336
333
  head = tag!(child) {self[*child.children]}
337
334
  html = @doc.children.last
@@ -131,10 +131,9 @@ module Wunderbar
131
131
  path_info = env['PATH_INFO'].to_s
132
132
 
133
133
  # implied request types
134
- xhr_json = Wunderbar::Options::XHR_JSON || (accept =~ /json/) ||
135
- env['HTTP_X_REQUESTED_WITH'].to_s == 'XMLHttpRequest'
136
- text = Wunderbar::Options::TEXT ||
137
- (accept =~ /plain/ and accept !~ /html/)
134
+ text = Wunderbar::Options::TEXT || (accept =~ /plain/ && accept !~ /html/)
135
+ xhr_json = Wunderbar::Options::XHR_JSON || (accept =~ /json/)
136
+ xhr_json ||= !text && env['HTTP_X_REQUESTED_WITH'].to_s=='XMLHttpRequest'
138
137
  @xhtml = (accept =~ /xhtml/ or accept == '')
139
138
  @pdf = (accept =~ /pdf/)
140
139
 
@@ -151,7 +150,7 @@ module Wunderbar
151
150
  @pdf ||= ARGV.include?('--pdf')
152
151
 
153
152
  # overrides via the uri query parameter
154
- xhr_json ||= (path_info.end_with? '.json')
153
+ # xhr_json ||= (path_info.end_with? '.json')
155
154
  text ||= (path_info.end_with? '.text')
156
155
  @pdf ||= (path_info.end_with? '.pdf')
157
156
  xhtml_override ||= (path_info.end_with? '.xhtml')
@@ -9,6 +9,10 @@ module Wunderbar
9
9
  @node = node
10
10
  end
11
11
 
12
+ def node?
13
+ @node
14
+ end
15
+
12
16
  private
13
17
 
14
18
  # Adds attributes to an element. Bang methods set the :id attribute.
@@ -49,7 +49,7 @@ module Wunderbar
49
49
  args << {} if args.empty?
50
50
  if Hash === args.first
51
51
  args.first[:xmlns] ||= 'http://www.w3.org/1999/xhtml'
52
- @_width = args.first.delete(:_width).to_i if args.first[:_width]
52
+ @x.width = args.first.delete(:_width).to_i if args.first[:_width]
53
53
  end
54
54
 
55
55
  if ''.respond_to? :encoding
@@ -150,7 +150,7 @@ module Wunderbar
150
150
  end
151
151
 
152
152
  if flag == '!'
153
- @x.compact!(@_width) { tag! name, *args, &block }
153
+ @x.compact! { tag! name, *args, &block }
154
154
  elsif flag == '?'
155
155
  # capture exceptions, produce filtered tracebacks
156
156
  tag!(name, *args) do
@@ -266,7 +266,7 @@ module Wunderbar
266
266
 
267
267
  def _pre(*args, &block)
268
268
  args.first.chomp! if String === args.first and args.first.end_with? "\n"
269
- @x.compact!(nil) { tag! :pre, *args, &block }
269
+ @x.compact! { tag! :pre, *args, &block }
270
270
  end
271
271
 
272
272
  def _ul(*args, &block)
@@ -321,9 +321,13 @@ module Wunderbar
321
321
  safe = !children.tainted?
322
322
  safe ||= children.html_safe? if children.respond_to? :html_safe?
323
323
  safe &&= defined? Nokogiri
324
+ ok = safe || defined? Sanitize
325
+ safe = true
324
326
 
325
- if safe and (children.include? '<' or children.include? '&')
326
- children = Nokogiri::HTML::fragment(children.to_s).children.to_a
327
+ if ok and (children.include? '<' or children.include? '&')
328
+ doc = Nokogiri::HTML::fragment(children.to_s)
329
+ Sanitize.new.clean_node! doc.dup.untaint if not safe
330
+ children = doc.children.to_a
327
331
 
328
332
  # ignore leading whitespace
329
333
  while not children.empty? and children.first.text?
@@ -1,3 +1,5 @@
1
+ require 'wunderbar'
2
+
1
3
  # run command/block as a background daemon
2
4
  module Wunderbar
3
5
  def self.submit(cmd=nil)
@@ -0,0 +1,5 @@
1
+ require 'wunderbar/jquery'
2
+
3
+ source = File.expand_path('../../vendor/stupidtable.min.js', __FILE__)
4
+
5
+ Wunderbar::Asset.script :name => 'stupidtable.min.js', :file => source
@@ -2,10 +2,11 @@ require 'wunderbar'
2
2
 
3
3
  begin
4
4
  require 'ruby2js/filter/jquery'
5
+ require 'wunderbar/script'
5
6
  rescue LoadError
6
7
  end
7
8
 
8
- source = Dir[File.expand_path('../jquery-*.min.js', __FILE__)].
9
+ source = Dir[File.expand_path('../vendor/jquery-*.min.js', __FILE__)].
9
10
  sort_by {|name| name[/-([.\d]*)\.min.js$/,1].split('.').map(&:to_i)}.last
10
11
 
11
12
  Wunderbar::Asset.script :name => 'jquery-min.js', :file => source
@@ -1,6 +1,7 @@
1
1
  require 'wunderbar'
2
2
  require 'kramdown'
3
3
  require 'nokogiri'
4
+ require 'sanitize'
4
5
 
5
6
  module Wunderbar
6
7
  class HtmlMarkup
@@ -20,9 +20,10 @@ module Wunderbar
20
20
  @text = nil
21
21
  @attrs = {}
22
22
  @children = []
23
- @name += args.shift.inspect if Symbol === args.first
23
+ args -= symbols = args.find_all {|arg| Symbol === arg}
24
24
  @attrs = args.pop.to_hash if args.last.respond_to? :to_hash
25
25
  @text = args.shift.to_s unless args.empty?
26
+ symbols.each {|sym| @attrs[sym] = true}
26
27
  end
27
28
 
28
29
  def method_missing(*args)
@@ -73,7 +74,13 @@ module Wunderbar
73
74
  if options[:pre]
74
75
  line += ">#{options[:pre]}#{text}#{options[:post]}</#{name}>"
75
76
  else
77
+ width = options[:width] if name != :pre
76
78
  line += ">#{text.to_s.gsub(/[&<>]/,ESCAPE)}</#{name}>"
79
+ if width and line.length > width
80
+ reflowed = IndentedTextNode.reflow(indent, line, width)
81
+ line = reflowed.pop
82
+ result.push *reflowed
83
+ end
77
84
  end
78
85
  elsif VOID.include? name.to_s
79
86
  line += "/>"
@@ -83,12 +90,19 @@ module Wunderbar
83
90
  elsif CompactNode === self
84
91
  work = []
85
92
  walk(work, nil, options)
86
- if @width
93
+ width = options[:width]
94
+ if width
87
95
  line += ">"
88
96
  (work+["</#{name}>"]).each do |node|
89
- if line.length + node.length > @width
97
+ if line.length + node.length > width
90
98
  result << line.rstrip
91
99
  line = indent.to_s
100
+ if line.length + node.length > width and !node.include? '<'
101
+ reflowed = IndentedTextNode.reflow(indent.to_s,
102
+ "#{indent}#{node}", width)
103
+ node = reflowed.pop.sub(/^#{indent}/, '')
104
+ result.push *reflowed
105
+ end
92
106
  end
93
107
  line += node
94
108
  end
@@ -175,6 +189,20 @@ module Wunderbar
175
189
  end
176
190
 
177
191
  class IndentedTextNode < TextNode
192
+ def self.reflow(indent, line, width)
193
+ return [line] if line.include? "\n" or not width
194
+
195
+ result = []
196
+ while line.length > width
197
+ split = line.rindex(' ', width)
198
+ break if not split or split <= indent.to_s.length
199
+ result << line[0...split]
200
+ line = "#{indent}#{line[split+1..-1]}"
201
+ end
202
+
203
+ result << line
204
+ end
205
+
178
206
  def serialize(options, result, indent)
179
207
  if indent
180
208
  text = CDATANode.normalize(@text, indent)
@@ -182,7 +210,8 @@ module Wunderbar
182
210
  text = @text
183
211
  end
184
212
 
185
- result << text.to_s.gsub(/[&<>]/,ESCAPE)
213
+ result.push *IndentedTextNode.reflow(indent,
214
+ text.to_s.gsub(/[&<>]/,ESCAPE), options[:width])
186
215
  end
187
216
  end
188
217
 
@@ -196,14 +225,7 @@ module Wunderbar
196
225
  def post; "/*]]>*/"; end
197
226
  end
198
227
 
199
- module CompactNode
200
- def width=(value)
201
- @width = value
202
- end
203
- def width
204
- @width
205
- end
206
- end
228
+ module CompactNode; end
207
229
 
208
230
  module SpacedNode; end
209
231
 
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ require 'wunderbar'
2
+
3
+ source = File.expand_path('../vendor/Markdown.Converter.js', __FILE__)
4
+
5
+ Wunderbar::Asset.script name: 'Markdown.Converter.js', file: source
@@ -1,6 +1,6 @@
1
1
  require 'wunderbar'
2
2
 
3
- source = Dir[File.expand_path('../polymer-*.min.js', __FILE__)].
3
+ source = Dir[File.expand_path('../vendor/polymer-*.min.js', __FILE__)].
4
4
  sort_by {|name| name[/-v?([.\d]*)\.min.js$/,1].split('.').map(&:to_i)}.last
5
5
 
6
6
  Wunderbar::Asset.script :name => 'polymer-min.js', :file => source
@@ -6,16 +6,29 @@ require 'ruby2js'
6
6
  # by execute strings (`` or %x()).
7
7
 
8
8
  module Wunderbar
9
+ class ScriptNode
10
+ attr_accessor :block, :binding
11
+ def serialize(options, result, indent)
12
+ if @block
13
+ width = options[:width]
14
+ width -= indent.to_s.length if width
15
+ @text = Ruby2JS.convert(@block, binding: @binding, width: width)
16
+ end
17
+ super
18
+ end
19
+ end
20
+
9
21
  class HtmlMarkup
10
22
  def _script(*args, &block)
11
23
  if block
24
+ node = super(*args, &nil).node?
25
+ node.block = block
12
26
  if binding.respond_to? :of_caller
13
27
  # provided by require 'binding_of_caller'
14
- args.unshift Ruby2JS.convert(block, binding: binding.of_caller(1))
28
+ node.binding = binding.of_caller(1)
15
29
  else
16
- args.unshift Ruby2JS.convert(block, binding: binding)
30
+ node.binding = binding
17
31
  end
18
- super *args, &nil
19
32
  else
20
33
  super
21
34
  end
@@ -181,6 +181,11 @@ Tilt.register '_xhtml', Wunderbar::Template::Xhtml
181
181
 
182
182
  helpers Wunderbar::SinatraHelpers
183
183
 
184
- get '/assets/:name' do
185
- File.read("assets/#{params[:name]}")
184
+ get "/#{Wunderbar::Asset.path}/:name" do
185
+ begin
186
+ content_type Wunderbar::Asset.content_type_for(params[:name])
187
+ File.read("#{Wunderbar::Asset.root}/#{params[:name]}")
188
+ rescue Errno::ENOENT
189
+ raise Sinatra::NotFound
190
+ end
186
191
  end