deckrb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +63 -0
- data/bin/deck +59 -0
- data/deck/GPL-license.txt +278 -0
- data/deck/MIT-license.txt +21 -0
- data/deck/README.md +57 -0
- data/deck/core/deck.core.css +404 -0
- data/deck/core/deck.core.html +39 -0
- data/deck/core/deck.core.js +498 -0
- data/deck/core/deck.core.scss +447 -0
- data/deck/extensions/goto/deck.goto.css +41 -0
- data/deck/extensions/goto/deck.goto.html +7 -0
- data/deck/extensions/goto/deck.goto.js +134 -0
- data/deck/extensions/goto/deck.goto.scss +46 -0
- data/deck/extensions/hash/deck.hash.css +13 -0
- data/deck/extensions/hash/deck.hash.html +2 -0
- data/deck/extensions/hash/deck.hash.js +129 -0
- data/deck/extensions/hash/deck.hash.scss +15 -0
- data/deck/extensions/menu/deck.menu.css +47 -0
- data/deck/extensions/menu/deck.menu.js +187 -0
- data/deck/extensions/menu/deck.menu.scss +58 -0
- data/deck/extensions/navigation/deck.navigation.css +43 -0
- data/deck/extensions/navigation/deck.navigation.html +3 -0
- data/deck/extensions/navigation/deck.navigation.js +91 -0
- data/deck/extensions/navigation/deck.navigation.scss +56 -0
- data/deck/extensions/scale/deck.scale.css +16 -0
- data/deck/extensions/scale/deck.scale.js +155 -0
- data/deck/extensions/scale/deck.scale.scss +17 -0
- data/deck/extensions/status/deck.status.css +18 -0
- data/deck/extensions/status/deck.status.html +6 -0
- data/deck/extensions/status/deck.status.js +95 -0
- data/deck/extensions/status/deck.status.scss +22 -0
- data/deck/extensions/theme-picker/deck.theme-picker.css +55 -0
- data/deck/extensions/theme-picker/deck.theme-picker.js +13 -0
- data/deck/introduction/index.html +221 -0
- data/deck/introduction/index.rb +101 -0
- data/deck/jquery-1.7.min.js +4 -0
- data/deck/modernizr.custom.js +4 -0
- data/deck/test/fixtures/complex.html +24 -0
- data/deck/test/fixtures/empty.html +19 -0
- data/deck/test/fixtures/iframe_simple.html +10 -0
- data/deck/test/fixtures/iframes.html +32 -0
- data/deck/test/fixtures/nesteds.html +36 -0
- data/deck/test/fixtures/standard.html +42 -0
- data/deck/test/index.html +39 -0
- data/deck/test/lib/jasmine-html.js +190 -0
- data/deck/test/lib/jasmine-jquery.js +288 -0
- data/deck/test/lib/jasmine.css +166 -0
- data/deck/test/lib/jasmine.js +2477 -0
- data/deck/test/settings.js +3 -0
- data/deck/test/spec.core.js +434 -0
- data/deck/test/spec.goto.js +119 -0
- data/deck/test/spec.hash.js +81 -0
- data/deck/test/spec.menu.js +66 -0
- data/deck/test/spec.navigation.js +51 -0
- data/deck/test/spec.scale.js +57 -0
- data/deck/test/spec.status.js +58 -0
- data/deck/themes/style/neon.css +114 -0
- data/deck/themes/style/neon.scss +139 -0
- data/deck/themes/style/swiss.css +75 -0
- data/deck/themes/style/swiss.scss +91 -0
- data/deck/themes/style/web-2.0.css +205 -0
- data/deck/themes/style/web-2.0.scss +236 -0
- data/deck/themes/transition/fade.css +44 -0
- data/deck/themes/transition/fade.scss +70 -0
- data/deck/themes/transition/horizontal-slide.css +79 -0
- data/deck/themes/transition/horizontal-slide.scss +94 -0
- data/deck/themes/transition/vertical-slide.css +97 -0
- data/deck/themes/transition/vertical-slide.scss +116 -0
- data/lib/deck.rb +7 -0
- data/lib/deck/app.rb +16 -0
- data/lib/deck/deck.rb +166 -0
- data/lib/deck/rack_static_patch.rb +13 -0
- data/lib/deck/slide.rb +120 -0
- data/lib/deck/version.rb +3 -0
- data/spec/deck_spec.rb +98 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/spec/slide_spec.rb +285 -0
- data/spec/spec_helper.rb +7 -0
- metadata +172 -0
data/lib/deck.rb
ADDED
data/lib/deck/app.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Deck
|
2
|
+
class App
|
3
|
+
def initialize root, files
|
4
|
+
@root, @files = root, files
|
5
|
+
end
|
6
|
+
|
7
|
+
def call env
|
8
|
+
slides = []
|
9
|
+
@files.each do |file|
|
10
|
+
slides += Slide.from_file "#{@root}/#{file}"
|
11
|
+
end
|
12
|
+
deck = Deck.new :slides => slides
|
13
|
+
[200, {}, deck.to_pretty]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/deck/deck.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'erector'
|
2
|
+
require 'redcarpet'
|
3
|
+
|
4
|
+
require "deck/slide"
|
5
|
+
|
6
|
+
module Deck
|
7
|
+
class Deck < Erector::Widgets::Page
|
8
|
+
needs :title => "deck.rb presentation",
|
9
|
+
:description => nil,
|
10
|
+
:author => nil
|
11
|
+
|
12
|
+
needs :slides => nil
|
13
|
+
|
14
|
+
def page_title
|
15
|
+
@title
|
16
|
+
end
|
17
|
+
|
18
|
+
# todo: promote into Text
|
19
|
+
# todo: support numbers a la 'Ӓ'
|
20
|
+
def entity entity_id
|
21
|
+
raw("&#{entity_id};")
|
22
|
+
end
|
23
|
+
|
24
|
+
# left over from deck.js' introduction/index.html
|
25
|
+
|
26
|
+
# <!DOCTYPE html>
|
27
|
+
# <!--[if lt IE 7]> <html class="no-js ie6" lang="en"> <![endif]-->
|
28
|
+
# <!--[if IE 7]> <html class="no-js ie7" lang="en"> <![endif]-->
|
29
|
+
# <!--[if IE 8]> <html class="no-js ie8" lang="en"> <![endif]-->
|
30
|
+
# <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
|
31
|
+
|
32
|
+
# todo: promote into Page
|
33
|
+
def stylesheet src, attributes = {}
|
34
|
+
link({:rel => "stylesheet", :href => src}.merge(attributes))
|
35
|
+
end
|
36
|
+
|
37
|
+
def head_content
|
38
|
+
super
|
39
|
+
meta 'charset' => 'utf-8'
|
40
|
+
meta 'http-equiv'=>"X-UA-Compatible", 'content'=>"IE=edge,chrome=1"
|
41
|
+
meta :name=>"viewport", :content=>"width=1024, user-scalable=no"
|
42
|
+
meta :name => "description", :content=> @description if @description
|
43
|
+
meta :name => "author", :content=> @author if @author
|
44
|
+
|
45
|
+
# <!-- Core and extension CSS files -->
|
46
|
+
stylesheet "deck/core/deck.core.css"
|
47
|
+
|
48
|
+
stylesheet "deck/extensions/goto/deck.goto.css"
|
49
|
+
stylesheet "deck/extensions/menu/deck.menu.css"
|
50
|
+
stylesheet "deck/extensions/navigation/deck.navigation.css"
|
51
|
+
stylesheet "deck/extensions/status/deck.status.css"
|
52
|
+
stylesheet "deck/extensions/hash/deck.hash.css"
|
53
|
+
stylesheet "deck/extensions/scale/deck.scale.css"
|
54
|
+
|
55
|
+
stylesheet "deck/extensions/theme-picker/deck.theme-picker.css"
|
56
|
+
|
57
|
+
# <!-- Theme CSS files (menu swaps these out) -->
|
58
|
+
stylesheet "deck/themes/style/web-2.0.css", :id=>"style-theme-link"
|
59
|
+
stylesheet "deck/themes/transition/horizontal-slide.css", :id => "transition-theme-link"
|
60
|
+
|
61
|
+
script :src=>"deck/modernizr.custom.js"
|
62
|
+
end
|
63
|
+
|
64
|
+
def scripts
|
65
|
+
# comment 'Grab CDN jQuery, with a protocol relative URL; fall back to local if offline'
|
66
|
+
# script :src => '//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.min.js'
|
67
|
+
script :src => './deck/jquery-1.7.min.js'
|
68
|
+
|
69
|
+
comment 'Deck Core and extensions'
|
70
|
+
script :type => "text/javascript", :src => 'deck/core/deck.core.js'
|
71
|
+
|
72
|
+
script :type => "text/javascript", :src => 'deck/extensions/hash/deck.hash.js'
|
73
|
+
script :type => "text/javascript", :src => 'deck/extensions/menu/deck.menu.js'
|
74
|
+
script :type => "text/javascript", :src => 'deck/extensions/goto/deck.goto.js'
|
75
|
+
script :type => "text/javascript", :src => 'deck/extensions/status/deck.status.js'
|
76
|
+
script :type => "text/javascript", :src => 'deck/extensions/navigation/deck.navigation.js'
|
77
|
+
script :type => "text/javascript", :src => 'deck/extensions/scale/deck.scale.js'
|
78
|
+
|
79
|
+
|
80
|
+
# fire up deck.js
|
81
|
+
script "$(function(){$.deck('.slide');});"
|
82
|
+
|
83
|
+
script :type => "text/javascript", :src => 'deck/extensions/theme-picker/deck.theme-picker.js'
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def body_attributes
|
88
|
+
{:class=>"deck-container"}
|
89
|
+
end
|
90
|
+
|
91
|
+
def body_content
|
92
|
+
slides
|
93
|
+
slide_navigation
|
94
|
+
deck_status
|
95
|
+
goto_slide
|
96
|
+
permalink
|
97
|
+
scripts
|
98
|
+
end
|
99
|
+
|
100
|
+
def slide slide_id
|
101
|
+
# todo: use Slide object, but without markdown
|
102
|
+
# slide = Slide.new(:slide_id => slide_id)
|
103
|
+
section.slide :id => slide_id do
|
104
|
+
yield
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def slides
|
109
|
+
if @slides
|
110
|
+
@slides.each do |slide|
|
111
|
+
widget slide
|
112
|
+
end
|
113
|
+
else
|
114
|
+
default_slide
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def default_slide
|
119
|
+
slide 'readme' do
|
120
|
+
h2 "deck.rb"
|
121
|
+
ul {
|
122
|
+
li "based on deck.js"
|
123
|
+
li "create a subclass of Deck (see introduction.rb)"
|
124
|
+
li "run erector to build it"
|
125
|
+
}
|
126
|
+
pre "erector --to-html ./deck.rb # generates deck.html"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def slide_navigation
|
131
|
+
a :href => '#', :class => 'deck-prev-link', :title => 'Previous' do
|
132
|
+
character 8592
|
133
|
+
end
|
134
|
+
a :href => '#', :class => 'deck-next-link', :title => 'Next' do
|
135
|
+
character 8594
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def deck_status
|
140
|
+
p :class => 'deck-status' do
|
141
|
+
span :class => 'deck-status-current' do
|
142
|
+
end
|
143
|
+
text '/'
|
144
|
+
span :class => 'deck-status-total' do
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def goto_slide
|
150
|
+
form :action => '.', :method => 'get', :class => 'goto-form' do
|
151
|
+
label :for => 'goto-slide' do
|
152
|
+
text 'Go to slide:'
|
153
|
+
end
|
154
|
+
input :type => 'text', :name => 'slidenum', :id => 'goto-slide', :list => 'goto-datalist'
|
155
|
+
datalist :id => 'goto-datalist' do
|
156
|
+
end
|
157
|
+
input :type => 'submit', :value => 'Go'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def permalink
|
162
|
+
a "#", :href => '.', :title => 'Permalink to this slide', :class => 'deck-permalink'
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Fix Rack bug https://github.com/rack/rack/issues/301
|
2
|
+
module Rack
|
3
|
+
class Static
|
4
|
+
def initialize(app, options={})
|
5
|
+
@app = app
|
6
|
+
@urls = options[:urls] || ["/favicon.ico"]
|
7
|
+
@index = options[:index]
|
8
|
+
root = options[:root] || Dir.pwd
|
9
|
+
cache_control = options[:cache_control]
|
10
|
+
@file_server = Rack::File.new(root, cache_control)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/deck/slide.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# based on work by Alex and others in Showoff
|
2
|
+
require 'redcarpet'
|
3
|
+
|
4
|
+
|
5
|
+
module Deck
|
6
|
+
class Slide < Erector::Widget
|
7
|
+
|
8
|
+
# todo: test this method
|
9
|
+
def self.from_file markdown_file
|
10
|
+
split File.read(markdown_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
# given a chunk of Markdown text, splits it into an array of Slide objects
|
14
|
+
def self.split content
|
15
|
+
unless content =~ /^\<?!SLIDE/m
|
16
|
+
content = content.gsub(/^# /m, "<!SLIDE>\n# ")
|
17
|
+
end
|
18
|
+
|
19
|
+
lines = content.split("\n")
|
20
|
+
slides = []
|
21
|
+
slides << (slide = Slide.new)
|
22
|
+
until lines.empty?
|
23
|
+
line = lines.shift
|
24
|
+
if line =~ /^<?!SLIDE(.*)>?/
|
25
|
+
slides << (slide = Slide.new(:classes => $1))
|
26
|
+
|
27
|
+
elsif line =~ /^# / and !slide.empty?
|
28
|
+
# every H1 defines a new slide, unless there's a !SLIDE before it
|
29
|
+
slides << (slide = Slide.new)
|
30
|
+
slide << line
|
31
|
+
|
32
|
+
else
|
33
|
+
slide << line
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
slides.delete_if {|slide| slide.empty? }
|
38
|
+
|
39
|
+
slides
|
40
|
+
end
|
41
|
+
|
42
|
+
####
|
43
|
+
|
44
|
+
attr_reader :classes, :markdown_text
|
45
|
+
|
46
|
+
needs :classes => nil, :markdown_text => nil, :slide_id => nil
|
47
|
+
|
48
|
+
|
49
|
+
def initialize options = {}
|
50
|
+
super options
|
51
|
+
|
52
|
+
@classes = process_classes
|
53
|
+
@markdown_text = ""
|
54
|
+
end
|
55
|
+
|
56
|
+
def process_classes
|
57
|
+
["slide"] + case @classes
|
58
|
+
when NilClass
|
59
|
+
[]
|
60
|
+
when String
|
61
|
+
@classes.strip.chomp('>').split
|
62
|
+
when Array
|
63
|
+
@classes
|
64
|
+
else
|
65
|
+
raise "can't deal with :classes => #{@classes.inspect}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def markdown
|
70
|
+
@@markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML,
|
71
|
+
:no_intra_emphasis => true,
|
72
|
+
:tables => true,
|
73
|
+
:fenced_code_blocks => true,
|
74
|
+
:no_intra_emphasis => true,
|
75
|
+
:autolink => true,
|
76
|
+
:strikethrough => true,
|
77
|
+
:lax_html_blocks => false,
|
78
|
+
:space_after_headers => true,
|
79
|
+
:superscript => false
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def <<(s)
|
84
|
+
@markdown_text << s
|
85
|
+
@markdown_text << "\n"
|
86
|
+
end
|
87
|
+
|
88
|
+
def empty?
|
89
|
+
@markdown_text.strip == ""
|
90
|
+
end
|
91
|
+
|
92
|
+
def slide_id
|
93
|
+
@slide_id ||= begin
|
94
|
+
lines = @markdown_text.split("\n")
|
95
|
+
raise "an empty slide has no id" if lines.empty?
|
96
|
+
lines.first.gsub(/^#*/, '').strip.downcase.gsub(/[^\w\s]/, '').gsub(/\s/, '_')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def header_only?
|
101
|
+
markdown_text.strip =~ /^# / and markdown_text.strip.split("\n").size == 1
|
102
|
+
end
|
103
|
+
|
104
|
+
def massaged_markdown_text
|
105
|
+
unless header_only?
|
106
|
+
"##{markdown_text.strip}"
|
107
|
+
else
|
108
|
+
markdown_text
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def content
|
113
|
+
section :class => @classes, :id => slide_id do
|
114
|
+
text "\n" # markdown HTML should be left-aligned, in case of PRE blocks and other quirks
|
115
|
+
html = markdown.render(massaged_markdown_text)
|
116
|
+
rawtext html
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/deck/version.rb
ADDED
data/spec/deck_spec.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
here = File.expand_path File.dirname(__FILE__)
|
2
|
+
require "#{here}/spec_helper"
|
3
|
+
|
4
|
+
require "deck/deck"
|
5
|
+
|
6
|
+
module Deck
|
7
|
+
describe Deck do
|
8
|
+
def temp_dir options = {:remove => true}
|
9
|
+
@temp_dir ||= begin
|
10
|
+
require 'tmpdir'
|
11
|
+
require 'fileutils'
|
12
|
+
called_from = File.basename caller.first.split(':').first, ".rb"
|
13
|
+
path = File.join(Dir::tmpdir, "#{called_from}_#{Time.now.to_i}_#{rand(1000)}")
|
14
|
+
Dir.mkdir(path)
|
15
|
+
at_exit {FileUtils.rm_rf(path) if File.exists?(path)} if options[:remove]
|
16
|
+
path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_html nokogiri_node
|
21
|
+
nokogiri_node.serialize(:save_with => 0).chomp
|
22
|
+
end
|
23
|
+
|
24
|
+
def as_html_page snippet
|
25
|
+
snippet =~ /<html/ ? snippet : "<html>#{snippet}</html>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def deck_widget options = {}
|
29
|
+
@deck_widget ||= Deck.new options
|
30
|
+
end
|
31
|
+
|
32
|
+
def doc
|
33
|
+
@doc ||= begin
|
34
|
+
@html = deck_widget.to_html
|
35
|
+
Nokogiri.parse(as_html_page(@html))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def write name, contents = "contents of #{name}"
|
40
|
+
path = "#{temp_dir}/#{name}"
|
41
|
+
File.open(path, "w") do |f|
|
42
|
+
f.write contents
|
43
|
+
end
|
44
|
+
File.new path
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#write" do
|
48
|
+
before do
|
49
|
+
@hello = write "hello.txt"
|
50
|
+
@goodbye = write "goodbye.txt", "farewell"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "uses temp_dir" do
|
54
|
+
File.dirname(@hello).should == temp_dir
|
55
|
+
File.dirname(@goodbye).should == temp_dir
|
56
|
+
end
|
57
|
+
|
58
|
+
it "writes a default value" do
|
59
|
+
File.read(@hello).should == "contents of hello.txt"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "writes a given value" do
|
63
|
+
# since write returns a File instance, we can call read on it
|
64
|
+
@goodbye.read.should == "farewell"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "writes a file" do
|
68
|
+
file = write("hello.md", "# hello")
|
69
|
+
assert { File.read(file) == "# hello" }
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
it "renders a basic deck.js HTML page" do
|
76
|
+
assert { doc }
|
77
|
+
assert { @html.include? '<link href="deck/core/deck.core.css" rel="stylesheet" />' }
|
78
|
+
end
|
79
|
+
|
80
|
+
it "contains a single dummy slide" do
|
81
|
+
assert { doc.css('section.slide').size == 1 }
|
82
|
+
end
|
83
|
+
|
84
|
+
it "renders a markdown file with one slide" do
|
85
|
+
file = write("hello.md", "# hello")
|
86
|
+
|
87
|
+
deck_widget :slides => Slide.split(File.read file)
|
88
|
+
assert { doc.css('section.slide').size == 1 }
|
89
|
+
slide = doc.css('section.slide').first
|
90
|
+
assert { slide["id"] == "hello" }
|
91
|
+
assert { to_html(slide) == "<section class=\"slide\" id=\"hello\">" +
|
92
|
+
"<h1>hello</h1>\n" +
|
93
|
+
"</section>"
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Jasmine
|
2
|
+
class Config
|
3
|
+
|
4
|
+
# Add your overrides or custom config code here
|
5
|
+
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# Note - this is necessary for rspec2, which has removed the backtrace
|
11
|
+
module Jasmine
|
12
|
+
class SpecBuilder
|
13
|
+
def declare_spec(parent, spec)
|
14
|
+
me = self
|
15
|
+
example_name = spec["name"]
|
16
|
+
@spec_ids << spec["id"]
|
17
|
+
backtrace = @example_locations[parent.description + " " + example_name]
|
18
|
+
parent.it example_name, {} do
|
19
|
+
me.report_spec(spec["id"])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|