prez 0.0.2 → 0.0.3

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