wunderbar 0.18.3 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
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