prez 0.0.2 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9566ac0764fadc9bfd46520d7a5ab5accd03095
4
- data.tar.gz: 2107dba528cc10fcf9caf3c74192f2c8308f2f94
3
+ metadata.gz: 82d042197610a8de84aefe9c5d966f5d5c218eba
4
+ data.tar.gz: 67e617fa968d220c919ddeea986ca007f3a2e55c
5
5
  SHA512:
6
- metadata.gz: 27ea96591daee1b5a597453f3c17ee810bb266821244b7a62c156eb9d20c8f6e3f449535189a4772fa1a6c1f149d8dec5bbb30ac1a95f91956cb94af6d921bbc
7
- data.tar.gz: cb71ef8a94917acbd27b72418e6b9486b1f981f3d9b6e420581c00afb0bc9a2974252a39166392cbe6a979e9ee75a72745950db2cbb4e1a1b7f0298764cfd32e
6
+ metadata.gz: 25b2fddcb34be8dd5a376698d011bc9cfd1c949700c5af3eb9a82500c1be6c438d0ded954caaca8c956a713a6a504c1fde5eb407d1beb2f34444ece76985c62e
7
+ data.tar.gz: 9888f3403ac1575ba470643ee616e7471db98caef858dd6eed70eb3844a9e5933a63b0339878d79e53361af7a79913c1ef2065993aa1ffc1b2081c07b050a249
data/bin/prez CHANGED
@@ -2,7 +2,7 @@
2
2
  require "rubygems"
3
3
  gem "coffee-script", "~> 2.3"
4
4
  gem "launchy", "~> 2.4"
5
- gem "prez", "= 0.0.2"
5
+ gem "prez", "= 0.0.3"
6
6
  gem "sass", "~> 3.4"
7
7
  gem "therubyracer", "~> 0.12"
8
8
  gem "thor", "~> 0.19"
data/lib/prez/assets.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require "coffee-script"
2
+ require "prez/data_uri"
3
+ require "prez/error"
2
4
  require "prez/files"
3
5
  require "prez/sass_extensions"
4
6
  require "sass"
@@ -7,17 +9,21 @@ require "uglifier"
7
9
  module Prez
8
10
  module Assets
9
11
  class Tagged
10
- attr_reader :name, :contents, :file
12
+ attr_reader :name, :contents, :file, :options
11
13
 
12
14
  def initialize(name, options = {})
13
15
  @name = name
14
16
  @contents = Prez::Files.contents name, extension
15
17
  @file = Prez::Files.find name, extension
16
- @dev = options.fetch :dev, false
18
+ @options = options
17
19
  end
18
20
 
19
21
  def dev?
20
- @dev
22
+ options.fetch :dev, false
23
+ end
24
+
25
+ def self_closing?
26
+ false
21
27
  end
22
28
 
23
29
  def minified_contents
@@ -29,7 +35,7 @@ module Prez
29
35
  end
30
36
 
31
37
  def to_tag
32
- if dev?
38
+ if dev? && !self_closing?
33
39
  "#{open}\n#{contents}#{close}"
34
40
  else
35
41
  "#{open}#{minified_contents.strip}#{close}"
@@ -37,6 +43,57 @@ module Prez
37
43
  end
38
44
  end
39
45
 
46
+ class Image < Prez::Assets::Tagged
47
+ def self_closing?
48
+ true
49
+ end
50
+
51
+ def extension
52
+ "image"
53
+ end
54
+
55
+ def open
56
+ attributes = []
57
+
58
+ if options[:width]
59
+ attributes << %{width="#{options[:width]}"}
60
+ end
61
+
62
+ if options[:height]
63
+ attributes << %{height="#{options[:height]}"}
64
+ end
65
+
66
+ %{<img #{attributes.join " "} src="}
67
+ end
68
+
69
+ def close
70
+ %{" />}
71
+ end
72
+
73
+ def image_type
74
+ extension = file[/\.([^.]*)$/, 1]
75
+
76
+ case extension
77
+ when "gif"
78
+ "image/gif"
79
+ when "jpeg", "jpg"
80
+ "image/jpeg"
81
+ when "png"
82
+ "image/png"
83
+ when "svg"
84
+ "image/svg+xml"
85
+ when "tif", "tiff"
86
+ "image/tiff"
87
+ else
88
+ raise Prez::Error.new("Unknown image extension '#{extension}'")
89
+ end
90
+ end
91
+
92
+ def minify(contents)
93
+ Prez::DataUri.new(image_type, contents).to_s
94
+ end
95
+ end
96
+
40
97
  class Javascript < Prez::Assets::Tagged
41
98
  def extension
42
99
  "js"
@@ -78,6 +135,10 @@ module Prez
78
135
  end
79
136
 
80
137
  class << self
138
+ def image(name, options = {})
139
+ Prez::Assets::Image.new(name, options).to_tag
140
+ end
141
+
81
142
  def javascript(name, options = {})
82
143
  Prez::Assets::Javascript.new(name, options).to_tag
83
144
  end
@@ -0,0 +1,17 @@
1
+ require "base64"
2
+
3
+ module Prez
4
+ class DataUri
5
+ attr_reader :type, :contents
6
+
7
+ def initialize(type, contents)
8
+ @type = type
9
+ @contents = Base64.encode64 contents
10
+ @contents.gsub! "\n", ""
11
+ end
12
+
13
+ def to_s
14
+ "data:#{type};base64,#{contents}"
15
+ end
16
+ end
17
+ end
data/lib/prez/files.rb CHANGED
@@ -50,7 +50,8 @@ module Prez
50
50
  SEARCH_PATHS = {
51
51
  "js" => Prez::Files::Paths.new("js", ["js.coffee", "coffee", "js"], "javascripts"),
52
52
  "css" => Prez::Files::Paths.new("css", ["css.scss", "scss", "css"], "stylesheets"),
53
- "font" => Prez::Files::Paths.new("font", ["eot", "svg", "ttf", "woff", "woff2"], "fonts", binary: true)
53
+ "font" => Prez::Files::Paths.new("font", ["eot", "svg", "ttf", "woff", "woff2"], "fonts", binary: true),
54
+ "image" => Prez::Files::Paths.new("image", ["gif", "jpeg", "jpg", "png", "svg", "tif", "tiff"], "images", binary: true)
54
55
  }
55
56
 
56
57
  def contents(name, extension)
data/lib/prez/helpers.rb CHANGED
@@ -6,12 +6,72 @@ module Prez
6
6
  module Helpers
7
7
  protected
8
8
 
9
+ def duration(value)
10
+ if @duration
11
+ raise Prez::Error.new("The duration helper can only be called once!")
12
+ end
13
+
14
+ if value.kind_of?(String) && value.split(":").size > 3
15
+ raise Prez::Eror.new("Only hours:minutes:seconds are supported for the duration!")
16
+ end
17
+
18
+ @duration = value
19
+ nil
20
+ end
21
+
22
+ def duration_amount
23
+ return if @duration.nil? || @duration.to_i <= 0
24
+
25
+ # Ensure it is an integer first... then we can normalize based
26
+ # on standard times (ie, no 70 seconds, or 100 minutes)
27
+ if @duration.kind_of? String
28
+ @duration = @duration.split ":"
29
+ @duration.map! &:to_i
30
+ value = @duration.pop || 0
31
+ value += (@duration.pop || 0) * 60
32
+ value += (@duration.pop || 0) * 60 * 60
33
+ @duration = value
34
+ end
35
+
36
+ # Ensure we don't have a floating point number
37
+ @duration = @duration.to_i
38
+ seconds = @duration % 60
39
+ minutes = (@duration / 60) % 60
40
+ hours = @duration / 60 / 60
41
+
42
+ if hours > 0
43
+ "%d:%02d:%02d" % [hours, minutes, seconds]
44
+ elsif minutes > 0
45
+ "%2d:%02d" % [minutes, seconds]
46
+ else
47
+ seconds.to_s
48
+ end
49
+ end
50
+
9
51
  def html_escape(value)
10
52
  CGI.escape_html value
11
53
  end
12
54
 
13
- def slide
14
- concat %{<div class="prez-slide">}
55
+ def slide(options = {})
56
+ classes = ["prez-slide"]
57
+ align = options.fetch :align, :center
58
+
59
+ case align
60
+ when :left
61
+ classes << "left-aligned"
62
+ when :right
63
+ classes << "right-aligned"
64
+ when :center
65
+ # Nothing needed
66
+ else
67
+ raise Prez::Error.new("Invalid slide align: #{align.inspect}")
68
+ end
69
+
70
+ if options[:duration]
71
+ duration_attribute = %{ data-duration="#{options[:duration]}"}
72
+ end
73
+
74
+ concat %{<div class="#{classes.join " "}"#{duration_attribute}>}
15
75
  yield
16
76
  concat %{</div>}
17
77
  end
@@ -22,6 +82,12 @@ module Prez
22
82
  concat %{</div>}
23
83
  end
24
84
 
85
+ def image(name, options = {})
86
+ Prez::Assets.image name, options
87
+ rescue Prez::Files::MissingError
88
+ raise Prez::Error.new("Could not find image file: '#{name}'")
89
+ end
90
+
25
91
  def javascript(name)
26
92
  Prez::Assets.javascript name
27
93
  rescue Prez::Files::MissingError
@@ -1,4 +1,4 @@
1
- require "base64"
1
+ require "prez/data_uri"
2
2
  require "prez/error"
3
3
  require "prez/files"
4
4
  require "sass"
@@ -7,8 +7,7 @@ module Sass::Script::Functions
7
7
  def twbs_font_path(path)
8
8
  assert_type path, :String
9
9
  path = path.value.sub /[?#].*/, ""
10
- font_data = Base64.encode64 Prez::Files.contents(path, "font")
11
- font_data.gsub! "\n", ""
10
+ contents = Prez::Files.contents path, "font"
12
11
  extension = path[/\.([^.]*)$/, 1]
13
12
 
14
13
  case extension
@@ -26,7 +25,7 @@ module Sass::Script::Functions
26
25
  raise Prez::Error.new("Unknown font extension '#{extension}'")
27
26
  end
28
27
 
29
- Sass::Script::Value::String.new("data:#{font_type};base64,#{font_data}")
28
+ Sass::Script::Value::String.new Prez::DataUri.new(font_type, contents).to_s
30
29
  rescue Prez::Files::MissingError => e
31
30
  raise Prez::Error.new("Could not find font: '#{path}'")
32
31
  end
data/lib/prez/version.rb CHANGED
@@ -2,7 +2,7 @@ module Prez
2
2
  module Version
3
3
  class << self
4
4
  def to_s
5
- "0.0.2"
5
+ "0.0.3"
6
6
  end
7
7
  end
8
8
  end
@@ -4,7 +4,6 @@
4
4
  <meta charset="utf-8">
5
5
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <%= stylesheet "bootstrap" %>
8
7
  <%= stylesheet "prez-controller" %>
9
8
  <%= javascript "jquery" %>
10
9
  <%= javascript "prez-controller" %>
@@ -16,6 +15,15 @@
16
15
  <div id="pre-launch">
17
16
  <div id="filler"></div>
18
17
 
18
+ <div class="row">
19
+ <div class="col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6">
20
+ <div class="form-group">
21
+ <label for="prez-duration">Duration</label>
22
+ <input type="text" id="prez-duration" class="form-control" placeholder="hours:minutes:seconds" value="<%= duration_amount %>" />
23
+ </div>
24
+ </div>
25
+ </div>
26
+
19
27
  <div class="row">
20
28
  <div class="col-xs-6 col-md-offset-2 col-md-4 col-lg-offset-3 col-lg-3">
21
29
  <button id="new-window" type="button" class="btn btn-default btn-block btn-lg active" data-toggle="button">
@@ -47,9 +55,25 @@
47
55
  </div>
48
56
  </div>
49
57
 
50
- <p class="lead text-center">
51
- <strong>Current slide: <span class="current-slide-number"></span></strong>
52
- </p>
58
+ <div class="row">
59
+ <div class="col-xs-2">
60
+ <div>
61
+ <span class="prez-total-duration"></span>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="col-xs-8">
66
+ <p class="lead text-center">
67
+ <strong>Current slide: <span class="current-slide-number"></span> of <span class="total-slides"></span></strong>
68
+ </p>
69
+ </div>
70
+
71
+ <div class="col-xs-2">
72
+ <div class="text-right">
73
+ <span class="prez-current-slide-duration"></span>
74
+ </div>
75
+ </div>
76
+ </div>
53
77
 
54
78
  <iframe id="preview-frame"></iframe>
55
79
  <div id="preview-frame-padding"></div>
@@ -1,6 +1,13 @@
1
+ $.setTimeout = (t, fn) -> setTimeout fn, t
2
+ $.setInterval = (t, fn) -> setInterval fn, t
3
+
4
+ $.fn.slideDuration = ->
5
+ parseInt(@data("duration") || "0", 10)
6
+
1
7
  class Prez
2
8
  DEFAULT_OPTIONS =
3
9
  useHash: true
10
+ duration: 0
4
11
 
5
12
  constructor: (options) ->
6
13
  @options = $.extend {}, DEFAULT_OPTIONS, options
@@ -22,6 +29,7 @@ class Prez
22
29
  false
23
30
 
24
31
  $(".prez-slide", @document).each (i) -> $(@).attr "data-slide", "#{i + 1}"
32
+ @startTime = Date.now()
25
33
  @changeSlideTo 1 unless changeToHashSlide()
26
34
  $(@window).on "hashchange", changeToHashSlide
27
35
  $(@document).on "keydown", Prez.handlers.keyDown
@@ -31,6 +39,18 @@ class Prez
31
39
  return false if $next.size() == 0
32
40
  $(".prez-slide", @document).hide()
33
41
  $next.show()
42
+ @slideStartTime = Date.now()
43
+ @slideDuration = $next.slideDuration()
44
+
45
+ # When unspecified, the slide duration is an even amount based
46
+ # on the remaining slides that don't have a specific duration
47
+ if @slideDuration <= 0
48
+ $remainingUntimed = $next.nextAll(".prez-slide").filter -> $(@).slideDuration() <= 0
49
+ @slideDuration = @remainingPresentationSeconds() / ($remainingUntimed.size() + 1)
50
+
51
+ if @slideDuration < 0
52
+ @slideDuration = 0
53
+
34
54
  @options.slideChanged? $next, nextValue
35
55
  true
36
56
 
@@ -45,6 +65,55 @@ class Prez
45
65
  prevSlide: -> @changeSlideBy -1
46
66
  end: -> @window.close()
47
67
 
68
+ remainingPresentationSeconds: ->
69
+ Math.floor(@options.duration - ((Date.now() - @startTime) / 1000))
70
+
71
+ remainingPresentationTime: ->
72
+ Prez.secondsToTime @remainingPresentationSeconds(), Prez.timeLevels(@options.duration)
73
+
74
+ remainingSlideSeconds: ->
75
+ Math.floor(@slideDuration - ((Date.now() - @slideStartTime) / 1000))
76
+
77
+ remainingSlideTime: ->
78
+ Prez.secondsToTime @remainingSlideSeconds(), Prez.timeLevels(@slideDuration)
79
+
80
+ @timeLevels: (s) ->
81
+ if s >= (60 * 60)
82
+ 3
83
+ else if s >= 60
84
+ 2
85
+ else
86
+ 1
87
+
88
+ @timeToSeconds: (t) ->
89
+ values = t.split ":"
90
+ result = parseInt(values.pop() || "0", 10)
91
+ result += parseInt(values.pop() || "0", 10) * 60
92
+ result += parseInt(values.pop() || "0", 10) * 60 * 60
93
+ result
94
+
95
+ @secondsToTime: (s, minLevels = 1) ->
96
+ pad = (n, size) ->
97
+ result = "#{n}"
98
+
99
+ while result.length < size
100
+ result = "0#{result}"
101
+
102
+ result
103
+
104
+ s = Math.floor s
105
+ s = Math.abs s
106
+ seconds = s % 60
107
+ minutes = Math.floor(s / 60) % 60
108
+ hours = Math.floor(s / 60 / 60)
109
+
110
+ if hours > 0 || minLevels >= 3
111
+ "#{hours}:#{pad minutes, 2}:#{pad seconds, 2}"
112
+ else if minutes > 0 || minLevels == 2
113
+ "#{minutes}:#{pad seconds, 2}"
114
+ else
115
+ "#{seconds}"
116
+
48
117
  KEY_ENTER = 13
49
118
  KEY_SPACE = 32
50
119
  KEY_LEFT = 37
@@ -62,10 +131,30 @@ class Prez
62
131
  e.preventDefault()
63
132
  Prez.current?.nextSlide()
64
133
 
134
+ timeChange: ->
135
+ return unless Prez.current
136
+ $(".prez-total-duration").text Prez.current.remainingPresentationTime()
137
+ seconds = Prez.current.remainingPresentationSeconds()
138
+ $(".prez-total-duration").toggleClass("prez-danger-time", seconds <= 60 && seconds >= 0)
139
+ $(".prez-total-duration").toggleClass("prez-over-time", seconds < 0)
140
+ $(".prez-current-slide-duration").text Prez.current.remainingSlideTime()
141
+ seconds = Prez.current.remainingSlideSeconds()
142
+ $(".prez-current-slide-duration").toggleClass("prez-danger-time", seconds <= 3 && seconds >= 0)
143
+ $(".prez-current-slide-duration").toggleClass("prez-over-time", seconds < 0)
144
+
145
+ if Math.floor(Date.now() / 250) % 2 == 0
146
+ $(".prez-danger-time").hide()
147
+ else
148
+ $(".prez-danger-time").show()
149
+
150
+ # Ensure transitions stay shown
151
+ $(".prez-total-duration:not(.prez-danger-time)").show()
152
+ $(".prez-current-slide-duration:not(.prez-danger-time)").show()
153
+
65
154
  $(document).on "click", "#new-window", (e) ->
66
155
  return if Prez.current
67
156
 
68
- callback = =>
157
+ $.setTimeout 1, =>
69
158
  if $(this).is(".active")
70
159
  $("#new-window #launch-message").text "Launch in new window"
71
160
  $("#new-window .glyphicon").addClass("glyphicon-new-window").removeClass("glyphicon-unchecked")
@@ -73,8 +162,6 @@ $(document).on "click", "#new-window", (e) ->
73
162
  $("#new-window #launch-message").text "Launch in this window"
74
163
  $("#new-window .glyphicon").removeClass("glyphicon-new-window").addClass("glyphicon-unchecked")
75
164
 
76
- setTimeout callback, 1
77
-
78
165
  $(document).on "click", "#launch", (e) ->
79
166
  e.preventDefault()
80
167
  return if Prez.current
@@ -97,13 +184,16 @@ $(document).on "click", "#launch", (e) ->
97
184
  useHash: false
98
185
 
99
186
  Prez.current = new Prez
187
+ duration: Prez.timeToSeconds($("#prez-duration").val())
100
188
  window: window.open("", "prez", "width=640,height=480")
101
189
  slideChanged: ($slide, slideNumber) ->
102
190
  notes = $slide.find(".prez-notes").html() || ""
103
191
  $("#slide-notes").html notes
104
192
  $(".current-slide-number").text $slide.data("slide")
193
+ Prez.handlers.timeChange()
105
194
  iframePrez.changeSlideTo slideNumber
106
195
 
196
+ $(".total-slides").text $(".prez-slide", Prez.current.document).size()
107
197
  $("#pre-launch").hide()
108
198
  $("#post-launch").show()
109
199
 
@@ -126,6 +216,7 @@ $(document).on "click", ".end-prez", (e) ->
126
216
  Prez.current?.end()
127
217
 
128
218
  $(document).on "keydown", Prez.handlers.keyDown
219
+ $.setInterval 50, Prez.handlers.timeChange
129
220
 
130
221
  $ ->
131
222
  $("#in-window-not-implemented-modal").modal show: false
@@ -1,3 +1,5 @@
1
+ $bootstrap-sass-asset-helper: true;
2
+ @import "bootstrap";
1
3
  @import "prez/variables";
2
4
 
3
5
  html, body, #container, #pre-launch, #post-launch {
@@ -11,6 +13,15 @@ html, body, #container, #pre-launch, #post-launch {
11
13
  #post-launch {
12
14
  display: none;
13
15
 
16
+ .prez-total-duration, .prez-current-slide-duration {
17
+ font-size: 2em;
18
+ }
19
+
20
+ .prez-danger-time, .prez-over-time {
21
+ font-weight: bold;
22
+ color: $brand-danger;
23
+ }
24
+
14
25
  iframe {
15
26
  display: block;
16
27
  position: absolute;
@@ -22,18 +22,22 @@ body {
22
22
  font-weight: bold;
23
23
  }
24
24
 
25
- .prez-slide, .prez-slide input {
26
- font-size: 50;
27
- }
28
-
29
25
  .prez-slide {
26
+ &, & input {
27
+ font-size: 50;
28
+ }
29
+
30
30
  display: none;
31
31
  min-height: $prez-slide-min-height;
32
32
  text-align: center;
33
- }
34
33
 
35
- .prez-slide.left-aligned {
36
- text-align: left;
34
+ &.left-aligned {
35
+ text-align: left;
36
+ }
37
+
38
+ &.right-aligned {
39
+ text-align: right;
40
+ }
37
41
  }
38
42
 
39
43
  .smaller {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prez
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Virata-Stone
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-24 00:00:00.000000000 Z
11
+ date: 2015-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coffee-script
@@ -136,6 +136,7 @@ files:
136
136
  - lib/prez/build.rb
137
137
  - lib/prez/builder.rb
138
138
  - lib/prez/cli.rb
139
+ - lib/prez/data_uri.rb
139
140
  - lib/prez/error.rb
140
141
  - lib/prez/files.rb
141
142
  - lib/prez/helpers.rb
@@ -154,7 +155,6 @@ files:
154
155
  - vendor/javascripts/jquery.js
155
156
  - vendor/javascripts/prez-controller.js.coffee
156
157
  - vendor/stylesheets/_bootstrap.scss
157
- - vendor/stylesheets/bootstrap.scss
158
158
  - vendor/stylesheets/bootstrap/_alerts.scss
159
159
  - vendor/stylesheets/bootstrap/_badges.scss
160
160
  - vendor/stylesheets/bootstrap/_breadcrumbs.scss
@@ -1,2 +0,0 @@
1
- $bootstrap-sass-asset-helper: true;
2
- @import "_bootstrap";