showoff 0.1.4 → 0.2.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.
- data/README.rdoc +280 -0
- data/bin/showoff +111 -15
- data/lib/showoff.rb +56 -18
- data/lib/showoff_utils.rb +189 -52
- data/public/css/onepage.css +33 -0
- data/public/css/showoff.css +57 -0
- data/public/css/spinner_bar.gif +0 -0
- data/public/favicon.ico +0 -0
- data/public/js/jquery.cookie.js +96 -0
- data/public/js/jquery.doubletap-0.1.js +105 -0
- data/public/js/jquery.uuid.js +24 -0
- data/public/js/jquery.ws-0.3pre.js +201 -0
- data/public/js/showoff.client.js +80 -0
- data/public/js/showoff.js +46 -5
- data/views/index.erb +23 -14
- data/views/onepage.erb +1 -2
- metadata +20 -3
- data/README.txt +0 -233
data/lib/showoff_utils.rb
CHANGED
@@ -1,40 +1,35 @@
|
|
1
1
|
class ShowOffUtils
|
2
|
+
SHOWOFF_JSON_FILE = 'showoff.json'
|
2
3
|
|
3
|
-
def self.create
|
4
|
-
dirname = ARGV[1]
|
5
|
-
return help('create') if !dirname
|
4
|
+
def self.create(dirname,create_samples,dir='one')
|
6
5
|
Dir.mkdir(dirname) if !File.exists?(dirname)
|
7
6
|
Dir.chdir(dirname) do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
f.puts "# Bullet Points #"
|
18
|
-
f.puts
|
19
|
-
f.puts "* first point"
|
20
|
-
f.puts "* second point"
|
21
|
-
f.puts "* third point"
|
7
|
+
if create_samples
|
8
|
+
# create section
|
9
|
+
Dir.mkdir(dir)
|
10
|
+
|
11
|
+
# create markdown file
|
12
|
+
File.open("#{dir}/01_slide.md", 'w+') do |f|
|
13
|
+
f.puts make_slide("My Presentation")
|
14
|
+
f.puts make_slide("Bullet Points","bullets incremental",["first point","second point","third point"])
|
15
|
+
end
|
22
16
|
end
|
23
17
|
|
24
18
|
# create showoff.json
|
25
|
-
File.open(
|
26
|
-
f.puts
|
19
|
+
File.open(SHOWOFF_JSON_FILE, 'w+') do |f|
|
20
|
+
f.puts "[ {\"section\":\"#{dir}\"} ]"
|
27
21
|
end
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
if create_samples
|
24
|
+
puts "done. run 'showoff serve' in #{dirname}/ dir to see slideshow"
|
25
|
+
else
|
26
|
+
puts "done. add slides, modify #{SHOWOFF_JSON_FILE} and then run 'showoff serve' in #{dirname}/ dir to see slideshow"
|
27
|
+
end
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
34
|
-
def self.heroku
|
35
|
-
|
36
|
-
return help('heroku') if !name
|
37
|
-
if !File.exists?('showoff.json')
|
31
|
+
def self.heroku(name)
|
32
|
+
if !File.exists?(SHOWOFF_JSON_FILE)
|
38
33
|
puts "fail. not a showoff directory"
|
39
34
|
return false
|
40
35
|
end
|
@@ -43,6 +38,7 @@ class ShowOffUtils
|
|
43
38
|
f.puts "bluecloth"
|
44
39
|
f.puts "nokogiri"
|
45
40
|
f.puts "showoff"
|
41
|
+
f.puts "gli"
|
46
42
|
end if !File.exists?('.gems')
|
47
43
|
|
48
44
|
# create config.ru file
|
@@ -60,38 +56,179 @@ class ShowOffUtils
|
|
60
56
|
"
|
61
57
|
end
|
62
58
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
59
|
+
# Makes a slide as a string.
|
60
|
+
# [title] title of the slide
|
61
|
+
# [classes] any "classes" to include, such as 'smaller', 'transition', etc.
|
62
|
+
# [content] slide content. Currently, if this is an array, it will make a bullet list. Otherwise
|
63
|
+
# the string value of this will be put in the slide as-is
|
64
|
+
def self.make_slide(title,classes="",content=nil)
|
65
|
+
slide = "!SLIDE #{classes}\n"
|
66
|
+
slide << "# #{title} #\n"
|
67
|
+
slide << "\n"
|
68
|
+
if content
|
69
|
+
if content.kind_of? Array
|
70
|
+
content.each { |x| slide << "* #{x.to_s}\n" }
|
71
|
+
else
|
72
|
+
slide << content.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
slide
|
76
|
+
end
|
77
|
+
|
78
|
+
TYPES = {
|
79
|
+
:default => lambda { |t,size,source,type| make_slide(t,"#{size} #{type}",source) },
|
80
|
+
'title' => lambda { |t,size,dontcare| make_slide(t,size) },
|
81
|
+
'bullets' => lambda { |t,size,dontcare| make_slide(t,"#{size} bullets incremental",["bullets","go","here"])},
|
82
|
+
'smbullets' => lambda { |t,size,dontcare| make_slide(t,"#{size} smbullets incremental",["bullets","go","here","and","here"])},
|
83
|
+
'code' => lambda { |t,size,src| make_slide(t,size,blank?(src) ? " @@@ Ruby\n code_here()" : src) },
|
84
|
+
'commandline' => lambda { |t,size,dontcare| make_slide(t,"#{size} commandline"," $ command here\n output here")},
|
85
|
+
'full-page' => lambda { |t,size,dontcare| make_slide(t,"#{size} full-page","")},
|
86
|
+
}
|
69
87
|
|
70
|
-
creates the .gems file and config.ru file needed to push a showoff pres to
|
71
|
-
heroku. it will then run 'heroku create' for you to register the new project
|
72
|
-
on heroku and add the remote for you. then all you need to do is commit the
|
73
|
-
new created files and run 'git push heroku' to deploy.
|
74
88
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
# Adds a new slide to a given dir, giving it a number such that it falls after all slides
|
90
|
+
# in that dir.
|
91
|
+
# Options are:
|
92
|
+
# [:dir] - dir where we put the slide (if omitted, slide is output to $stdout)
|
93
|
+
# [:name] - name of the file, without the number prefix. (if omitted, a default is used)
|
94
|
+
# [:title] - title in the slide. If not specified the source file name is
|
95
|
+
# used. If THAT is not specified, uses the value of +:name+. If THAT is not
|
96
|
+
# specified, a suitable default is used
|
97
|
+
# [:code] - path to a source file to use as content (force :type to be 'code')
|
98
|
+
# [:number] - true if numbering should be done, false if not
|
99
|
+
# [:type] - the type of slide to create
|
100
|
+
def self.add_slide(options)
|
79
101
|
|
80
|
-
|
81
|
-
proper directory structure for you. it takes the directory name you would
|
82
|
-
like showoff to create for you.
|
102
|
+
add_new_dir(options[:dir]) if options[:dir] && !File.exists?(options[:dir])
|
83
103
|
|
84
|
-
|
104
|
+
options[:type] = 'code' if options[:code]
|
105
|
+
|
106
|
+
title = determine_title(options[:title],options[:name],options[:code])
|
107
|
+
|
108
|
+
options[:name] = 'new_slide' if !options[:name]
|
109
|
+
|
110
|
+
size,source = determine_size_and_source(options[:code])
|
111
|
+
type = options[:type] || :default
|
112
|
+
slide = TYPES[type].call(title,size,source)
|
113
|
+
|
114
|
+
if options[:dir]
|
115
|
+
filename = determine_filename(options[:dir],options[:name],options[:number])
|
116
|
+
write_file(filename,slide)
|
85
117
|
else
|
86
|
-
puts
|
87
|
-
|
88
|
-
|
89
|
-
commands:
|
90
|
-
serve serves a showoff presentation from the current directory
|
91
|
-
create generates a new showoff presentation layout
|
92
|
-
heroku sets up your showoff presentation to push to heroku
|
93
|
-
HELP
|
118
|
+
puts slide
|
119
|
+
puts
|
94
120
|
end
|
121
|
+
|
95
122
|
end
|
96
123
|
|
97
|
-
|
124
|
+
# Adds the given directory to this presentation, appending it to
|
125
|
+
# the end of showoff.json as well
|
126
|
+
def self.add_new_dir(dir)
|
127
|
+
puts "Creating #{dir}..."
|
128
|
+
Dir.mkdir dir
|
129
|
+
|
130
|
+
showoff_json = JSON.parse(File.read(SHOWOFF_JSON_FILE))
|
131
|
+
showoff_json << { "section" => dir }
|
132
|
+
File.open(SHOWOFF_JSON_FILE,'w') do |file|
|
133
|
+
file.puts JSON.generate(showoff_json)
|
134
|
+
end
|
135
|
+
puts "#{SHOWOFF_JSON_FILE} updated"
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.blank?(string)
|
139
|
+
string.nil? || string.strip.length == 0
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.determine_size_and_source(code)
|
143
|
+
size = ""
|
144
|
+
source = ""
|
145
|
+
if code
|
146
|
+
source,lines,width = read_code(code)
|
147
|
+
size = adjust_size(lines,width)
|
148
|
+
end
|
149
|
+
[size,source]
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.write_file(filename,slide)
|
153
|
+
File.open(filename,'w') do |file|
|
154
|
+
file.puts slide
|
155
|
+
end
|
156
|
+
puts "Wrote #{filename}"
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.determine_filename(slide_dir,slide_name,number)
|
160
|
+
filename = "#{slide_dir}/#{slide_name}.md"
|
161
|
+
if number
|
162
|
+
max = find_next_number(slide_dir)
|
163
|
+
filename = "#{slide_dir}/#{max}_#{slide_name}.md"
|
164
|
+
end
|
165
|
+
filename
|
166
|
+
end
|
167
|
+
|
168
|
+
# Finds the next number in the given dir to
|
169
|
+
# name a slide as the last slide in the dir.
|
170
|
+
def self.find_next_number(slide_dir)
|
171
|
+
max = 0
|
172
|
+
Dir.open(slide_dir).each do |file|
|
173
|
+
if file =~ /(\d+).*\.md/
|
174
|
+
num = $1.to_i
|
175
|
+
max = num if num > max
|
176
|
+
end
|
177
|
+
end
|
178
|
+
max += 1
|
179
|
+
max = "0#{max}" if max < 10
|
180
|
+
max
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.determine_title(title,slide_name,code)
|
184
|
+
if blank?(title)
|
185
|
+
title = slide_name
|
186
|
+
title = File.basename(code) if code
|
187
|
+
end
|
188
|
+
title = "Title here" if blank?(title)
|
189
|
+
title
|
190
|
+
end
|
191
|
+
|
192
|
+
# Determines a more optimal value for the size (e.g. small vs. smaller)
|
193
|
+
# based upon the size of the code being formatted.
|
194
|
+
def self.adjust_size(lines,width)
|
195
|
+
size = ""
|
196
|
+
# These values determined empircally
|
197
|
+
size = "small" if width > 50
|
198
|
+
size = "small" if lines > 15
|
199
|
+
size = "smaller" if width > 57
|
200
|
+
size = "smaller" if lines > 19
|
201
|
+
puts "warning, some lines are too long and the code may be cut off" if width > 65
|
202
|
+
puts "warning, your code is too long and the code may be cut off" if lines > 23
|
203
|
+
size
|
204
|
+
end
|
205
|
+
|
206
|
+
# Reads the code from the source file, returning
|
207
|
+
# the code, indented for markdown, as well as the number of lines
|
208
|
+
# and the width of the largest line
|
209
|
+
def self.read_code(source_file)
|
210
|
+
code = " @@@ #{lang(source_file)}\n"
|
211
|
+
lines = 0
|
212
|
+
width = 0
|
213
|
+
File.open(source_file) do |code_file|
|
214
|
+
code_file.readlines.each do |line|
|
215
|
+
code += " #{line}"
|
216
|
+
lines += 1
|
217
|
+
width = line.length if line.length > width
|
218
|
+
end
|
219
|
+
end
|
220
|
+
[code,lines,width]
|
221
|
+
end
|
222
|
+
|
223
|
+
EXTENSIONS = {
|
224
|
+
'pl' => 'perl',
|
225
|
+
'rb' => 'ruby',
|
226
|
+
'erl' => 'erlang',
|
227
|
+
# so not exhaustive, but probably good enough for now
|
228
|
+
}
|
229
|
+
|
230
|
+
def self.lang(source_file)
|
231
|
+
ext = File.extname(source_file).gsub(/^\./,'')
|
232
|
+
EXTENSIONS[ext] || ext
|
233
|
+
end
|
234
|
+
end
|
data/public/css/onepage.css
CHANGED
@@ -9,3 +9,36 @@
|
|
9
9
|
border: 1px solid #333;
|
10
10
|
page-break-after: always
|
11
11
|
}
|
12
|
+
|
13
|
+
/* iPhone */
|
14
|
+
/* Portrait */
|
15
|
+
@media screen and (max-width: 320px)
|
16
|
+
{
|
17
|
+
.preso {
|
18
|
+
margin: 10px;
|
19
|
+
padding: 0;
|
20
|
+
width: 320px;
|
21
|
+
min-height: 480px;
|
22
|
+
margin-left:auto;
|
23
|
+
margin-right:auto;
|
24
|
+
/* overflow:hidden;*/
|
25
|
+
border: 1px solid #333;
|
26
|
+
page-break-after: always
|
27
|
+
}
|
28
|
+
}
|
29
|
+
/* Landscape */
|
30
|
+
@media screen and (min-width: 321px)
|
31
|
+
{
|
32
|
+
.preso {
|
33
|
+
margin: 10px;
|
34
|
+
padding: 0;
|
35
|
+
width: 480px;
|
36
|
+
min-height: 320px;
|
37
|
+
margin-left:auto;
|
38
|
+
margin-right:auto;
|
39
|
+
/* overflow:hidden;*/
|
40
|
+
border: 1px solid #333;
|
41
|
+
page-break-after: always
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
data/public/css/showoff.css
CHANGED
@@ -20,12 +20,69 @@ body {
|
|
20
20
|
margin-right:auto;
|
21
21
|
}
|
22
22
|
|
23
|
+
/* iPhone */
|
24
|
+
/* Portrait */
|
25
|
+
@media screen and (max-width: 320px)
|
26
|
+
{
|
27
|
+
#preso {
|
28
|
+
margin: 0;
|
29
|
+
padding: 0;
|
30
|
+
width: 320px;
|
31
|
+
max-height: 356px;
|
32
|
+
margin-left:auto;
|
33
|
+
margin-right:auto;
|
34
|
+
/* overflow:hidden;*/
|
35
|
+
}
|
36
|
+
#footer {
|
37
|
+
background: #eee;
|
38
|
+
margin: 0;
|
39
|
+
padding: 2px;
|
40
|
+
width: 320px;
|
41
|
+
height: 20px;
|
42
|
+
margin-left:auto;
|
43
|
+
margin-right:auto;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
/* Landscape */
|
47
|
+
@media screen and (max-width: 480px)
|
48
|
+
{
|
49
|
+
#preso {
|
50
|
+
margin: 0;
|
51
|
+
padding: 0;
|
52
|
+
/* min-height: 320px;*/
|
53
|
+
width: 480px;
|
54
|
+
margin-left:auto;
|
55
|
+
margin-right:auto;
|
56
|
+
}
|
57
|
+
#footer {
|
58
|
+
background: #eee;
|
59
|
+
margin: 0;
|
60
|
+
padding: 2px;
|
61
|
+
width: 480px;
|
62
|
+
height: 20px;
|
63
|
+
margin-left:auto;
|
64
|
+
margin-right:auto;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
.slide {
|
69
|
+
border: 1px solid #fff;
|
70
|
+
}
|
71
|
+
|
23
72
|
.center img {
|
24
73
|
display:block;
|
25
74
|
margin-left:auto;
|
26
75
|
margin-right:auto;
|
27
76
|
}
|
28
77
|
|
78
|
+
.slide .center {
|
79
|
+
height: 740px;
|
80
|
+
width: 1020px;
|
81
|
+
display: table-cell;
|
82
|
+
text-align: center;
|
83
|
+
vertical-align: middle;
|
84
|
+
}
|
85
|
+
|
29
86
|
.bullets ul {
|
30
87
|
font-size: 3em;
|
31
88
|
}
|
Binary file
|
data/public/favicon.ico
ADDED
Binary file
|
@@ -0,0 +1,96 @@
|
|
1
|
+
/**
|
2
|
+
* Cookie plugin
|
3
|
+
*
|
4
|
+
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
|
5
|
+
* Dual licensed under the MIT and GPL licenses:
|
6
|
+
* http://www.opensource.org/licenses/mit-license.php
|
7
|
+
* http://www.gnu.org/licenses/gpl.html
|
8
|
+
*
|
9
|
+
*/
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Create a cookie with the given name and value and other optional parameters.
|
13
|
+
*
|
14
|
+
* @example $.cookie('the_cookie', 'the_value');
|
15
|
+
* @desc Set the value of a cookie.
|
16
|
+
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
|
17
|
+
* @desc Create a cookie with all available options.
|
18
|
+
* @example $.cookie('the_cookie', 'the_value');
|
19
|
+
* @desc Create a session cookie.
|
20
|
+
* @example $.cookie('the_cookie', null);
|
21
|
+
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
|
22
|
+
* used when the cookie was set.
|
23
|
+
*
|
24
|
+
* @param String name The name of the cookie.
|
25
|
+
* @param String value The value of the cookie.
|
26
|
+
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
|
27
|
+
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
|
28
|
+
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
|
29
|
+
* If set to null or omitted, the cookie will be a session cookie and will not be retained
|
30
|
+
* when the the browser exits.
|
31
|
+
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
|
32
|
+
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
|
33
|
+
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
|
34
|
+
* require a secure protocol (like HTTPS).
|
35
|
+
* @type undefined
|
36
|
+
*
|
37
|
+
* @name $.cookie
|
38
|
+
* @cat Plugins/Cookie
|
39
|
+
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
40
|
+
*/
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Get the value of a cookie with the given name.
|
44
|
+
*
|
45
|
+
* @example $.cookie('the_cookie');
|
46
|
+
* @desc Get the value of a cookie.
|
47
|
+
*
|
48
|
+
* @param String name The name of the cookie.
|
49
|
+
* @return The value of the cookie.
|
50
|
+
* @type String
|
51
|
+
*
|
52
|
+
* @name $.cookie
|
53
|
+
* @cat Plugins/Cookie
|
54
|
+
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
55
|
+
*/
|
56
|
+
jQuery.cookie = function(name, value, options) {
|
57
|
+
if (typeof value != 'undefined') { // name and value given, set cookie
|
58
|
+
options = options || {};
|
59
|
+
if (value === null) {
|
60
|
+
value = '';
|
61
|
+
options.expires = -1;
|
62
|
+
}
|
63
|
+
var expires = '';
|
64
|
+
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
|
65
|
+
var date;
|
66
|
+
if (typeof options.expires == 'number') {
|
67
|
+
date = new Date();
|
68
|
+
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
|
69
|
+
} else {
|
70
|
+
date = options.expires;
|
71
|
+
}
|
72
|
+
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
|
73
|
+
}
|
74
|
+
// CAUTION: Needed to parenthesize options.path and options.domain
|
75
|
+
// in the following expressions, otherwise they evaluate to undefined
|
76
|
+
// in the packed version for some reason...
|
77
|
+
var path = options.path ? '; path=' + (options.path) : '';
|
78
|
+
var domain = options.domain ? '; domain=' + (options.domain) : '';
|
79
|
+
var secure = options.secure ? '; secure' : '';
|
80
|
+
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
|
81
|
+
} else { // only name given, get cookie
|
82
|
+
var cookieValue = null;
|
83
|
+
if (document.cookie && document.cookie != '') {
|
84
|
+
var cookies = document.cookie.split(';');
|
85
|
+
for (var i = 0; i < cookies.length; i++) {
|
86
|
+
var cookie = jQuery.trim(cookies[i]);
|
87
|
+
// Does this cookie string begin with the name we want?
|
88
|
+
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
89
|
+
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
90
|
+
break;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
return cookieValue;
|
95
|
+
}
|
96
|
+
};
|
@@ -0,0 +1,105 @@
|
|
1
|
+
(function($) {
|
2
|
+
var touchStatus = function(target, touch) {
|
3
|
+
this.target = $(target);
|
4
|
+
this.touch = touch;
|
5
|
+
this.startX = this.currentX = touch.screenX;
|
6
|
+
this.startY = this.currentY = touch.screenY;
|
7
|
+
this.eventType = null;
|
8
|
+
}
|
9
|
+
touchStatus.latestTap = null;
|
10
|
+
|
11
|
+
touchStatus.prototype.move = function(touch) {
|
12
|
+
this.currentX = touch.screenX;
|
13
|
+
this.currentY = touch.screenY;
|
14
|
+
}
|
15
|
+
|
16
|
+
touchStatus.prototype.process = function() {
|
17
|
+
var offsetX = this.currentX - this.startX;
|
18
|
+
var offsetY = this.currentY - this.startY;
|
19
|
+
if(offsetX == 0 && offsetY == 0) {
|
20
|
+
this.checkForDoubleTap()
|
21
|
+
} else if(Math.abs(offsetY) > Math.abs(offsetX)) {
|
22
|
+
this.eventType = offsetY > 0 ? 'swipedown' : 'swipeup';
|
23
|
+
this.target.trigger('swipe', [this])
|
24
|
+
} else {
|
25
|
+
this.eventType = offsetX > 0 ? 'swiperight' : 'swipeleft';
|
26
|
+
this.target.trigger('swipe', [this])
|
27
|
+
}
|
28
|
+
this.target.trigger(this.eventType, [this])
|
29
|
+
this.target.trigger('touch', [this])
|
30
|
+
}
|
31
|
+
|
32
|
+
touchStatus.prototype.checkForDoubleTap = function() {
|
33
|
+
if(touchStatus.latestTap) {
|
34
|
+
if((new Date() - touchStatus.latestTap) < 400)
|
35
|
+
this.eventType = 'doubletap'
|
36
|
+
}
|
37
|
+
if(!this.eventType) this.eventType = 'tap'
|
38
|
+
touchStatus.latestTap = new Date()
|
39
|
+
}
|
40
|
+
|
41
|
+
var swipeEvents = function(elements) {
|
42
|
+
elements.bind('touchstart', this.touchStart);
|
43
|
+
elements.bind('touchmove', this.touchMove);
|
44
|
+
elements.bind('touchcancel', this.touchCancel);
|
45
|
+
elements.bind('touchend', this.touchEnd);
|
46
|
+
}
|
47
|
+
|
48
|
+
swipeEvents.prototype.touchStart = function(evt) {
|
49
|
+
var target = this;
|
50
|
+
swipeEvents.eachTouch(evt, function(touch) {
|
51
|
+
swipeEvents.touches[touch.identifier] = new touchStatus(target, touch);
|
52
|
+
})
|
53
|
+
}
|
54
|
+
|
55
|
+
swipeEvents.prototype.touchMove = function(evt) {
|
56
|
+
swipeEvents.eachTouch(evt, function(touch) {
|
57
|
+
var loc = swipeEvents.touches[touch.identifier]
|
58
|
+
if(loc) loc.move(touch)
|
59
|
+
})
|
60
|
+
}
|
61
|
+
|
62
|
+
swipeEvents.prototype.touchCancel = function(evt) {
|
63
|
+
swipeEvents.eachTouch(evt, function(touch) {
|
64
|
+
swipeEvents.purge(touch, true)
|
65
|
+
})
|
66
|
+
}
|
67
|
+
|
68
|
+
swipeEvents.prototype.touchEnd = function(evt) {
|
69
|
+
swipeEvents.eachTouch(evt, function(touch) {
|
70
|
+
swipeEvents.purge(touch)
|
71
|
+
})
|
72
|
+
}
|
73
|
+
|
74
|
+
swipeEvents.touches = {}
|
75
|
+
swipeEvents.purge = function(touch, cancelled) {
|
76
|
+
if(!cancelled) {
|
77
|
+
var loc = swipeEvents.touches[touch.identifier]
|
78
|
+
if(loc) loc.process()
|
79
|
+
}
|
80
|
+
delete swipeEvents.touches[touch.identifier]
|
81
|
+
}
|
82
|
+
|
83
|
+
swipeEvents.eachTouch = function(evt, callback) {
|
84
|
+
var evt = evt.originalEvent;
|
85
|
+
var num = evt.changedTouches.length;
|
86
|
+
for(var i = 0; i < num; i++) {
|
87
|
+
callback(evt.changedTouches[i])
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
// adds custom events:
|
92
|
+
// touch // all events
|
93
|
+
// swipe // only swipe* events
|
94
|
+
// swipeleft
|
95
|
+
// swiperight
|
96
|
+
// swipeup
|
97
|
+
// swipedown
|
98
|
+
// tap
|
99
|
+
// doubletap
|
100
|
+
$.fn.addSwipeEvents = function(callback) {
|
101
|
+
new swipeEvents(this);
|
102
|
+
if(callback) this.bind('touch', callback)
|
103
|
+
return this;
|
104
|
+
}
|
105
|
+
})(jQuery);
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
Usage 1: define the default prefix by using an object with the property prefix as a parameter which contains a string value; {prefix: 'id'}
|
3
|
+
Usage 2: call the function jQuery.uuid() with a string parameter p to be used as a prefix to generate a random uuid;
|
4
|
+
Usage 3: call the function jQuery.uuid() with no parameters to generate a uuid with the default prefix; defaul prefix: '' (empty string)
|
5
|
+
*/
|
6
|
+
|
7
|
+
/*
|
8
|
+
Generate fragment of random numbers
|
9
|
+
*/
|
10
|
+
jQuery._uuid_default_prefix = '';
|
11
|
+
jQuery._uuidlet = function () {
|
12
|
+
return(((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
13
|
+
};
|
14
|
+
/*
|
15
|
+
Generates random uuid
|
16
|
+
*/
|
17
|
+
jQuery.uuid = function (p) {
|
18
|
+
if (typeof(p) == 'object' && typeof(p.prefix) == 'string') {
|
19
|
+
jQuery._uuid_default_prefix = p.prefix;
|
20
|
+
} else {
|
21
|
+
p = p || jQuery._uuid_default_prefix || '';
|
22
|
+
return(p+jQuery._uuidlet()+jQuery._uuidlet()+"-"+jQuery._uuidlet()+"-"+jQuery._uuidlet()+"-"+jQuery._uuidlet()+"-"+jQuery._uuidlet()+jQuery._uuidlet()+jQuery._uuidlet());
|
23
|
+
};
|
24
|
+
};
|