short 0.2.1

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.
Files changed (43) hide show
  1. data/.gitignore +4 -0
  2. data/README.md +9 -0
  3. data/Rakefile +3 -0
  4. data/bin/shortener +115 -0
  5. data/config.ru +2 -0
  6. data/lib/shortener/client.rb +69 -0
  7. data/lib/shortener/configuration.rb +76 -0
  8. data/lib/shortener/server/Gemfile +6 -0
  9. data/lib/shortener/server/Gemfile.lock +23 -0
  10. data/lib/shortener/server/config.ru.template +2 -0
  11. data/lib/shortener/server/public/delete-icon.png +0 -0
  12. data/lib/shortener/server/public/flash/Jplayer.swf +0 -0
  13. data/lib/shortener/server/public/flash/clippy.swf +0 -0
  14. data/lib/shortener/server/public/flash/swfupload.swf +0 -0
  15. data/lib/shortener/server/public/images/XPButtonUploadText_61x22.png +0 -0
  16. data/lib/shortener/server/public/jquery-swfupload-min.js +1 -0
  17. data/lib/shortener/server/public/jquery-swfupload.js +64 -0
  18. data/lib/shortener/server/public/jquery.jplayer.min.js +97 -0
  19. data/lib/shortener/server/public/jquery.min.js +18 -0
  20. data/lib/shortener/server/public/patched.bootstrap.min.css +370 -0
  21. data/lib/shortener/server/public/site.js +36 -0
  22. data/lib/shortener/server/public/skin/blue.monday/jplayer.blue.monday.css +623 -0
  23. data/lib/shortener/server/public/skin/blue.monday/jplayer.blue.monday.jpg +0 -0
  24. data/lib/shortener/server/public/skin/blue.monday/jplayer.blue.monday.seeking.gif +0 -0
  25. data/lib/shortener/server/public/skin/blue.monday/jplayer.blue.monday.video.play.png +0 -0
  26. data/lib/shortener/server/public/swfupload.js +980 -0
  27. data/lib/shortener/server/views/add.haml +22 -0
  28. data/lib/shortener/server/views/display.haml +5 -0
  29. data/lib/shortener/server/views/index.haml +25 -0
  30. data/lib/shortener/server/views/layout.haml +21 -0
  31. data/lib/shortener/server/views/s3/audio.haml +75 -0
  32. data/lib/shortener/server/views/s3/image.haml +27 -0
  33. data/lib/shortener/server/views/s3/layout.haml +23 -0
  34. data/lib/shortener/server/views/s3/video.haml +71 -0
  35. data/lib/shortener/server/views/upload.haml +130 -0
  36. data/lib/shortener/server.rb +346 -0
  37. data/lib/shortener/version.rb +6 -0
  38. data/lib/shortener.rb +9 -0
  39. data/tasks/heroku.rake +46 -0
  40. data/test/test_client.rb +26 -0
  41. data/test/test_configuration.rb +23 -0
  42. data/test/test_server.rb +0 -0
  43. metadata +102 -0
@@ -0,0 +1,22 @@
1
+ #shortener.row(style="margin-top: 40px;")
2
+ %form{:id => 'add-form',:name => "shortener", :action => "/add", :method => "post", :class => 'offset3 form'}
3
+ %label{:for => "shortener[url]"} Url to Shorten:
4
+ %input{:type => "text", :name => "shortener[url]", :class => "text"}
5
+ %input{:type => "submit", :value => "Shorten", :class => "btn primary"}
6
+ %a{:onClick => '$(".advanced").fadeIn();'} Show Advanced Options
7
+ %br
8
+ %label{:for => 'shortener[expire]', :class => 'advanced'} Time till Expired:
9
+ %input{:type => 'text', :name => 'shortener[expire]', :class => 'text advanced'}
10
+ %br
11
+ %label{:for => 'shortener[max-clicks]', :class => 'advanced'} Max Clicks:
12
+ %input{:type => 'text', :name => 'shortener[max-clicks]', :class => 'text advanced'}
13
+ %br
14
+ %label{:for => 'shortener[desired-short]', :class => 'advanced'} Desired Short:
15
+ %input{:type => 'text', :name => 'shortener[desired-short]', :class => 'text advanced'}
16
+ %br
17
+ %label{:for => 'shortener[allow-override]', :class => 'advanced'} Allow Random Override:
18
+ %input{:type => 'checkbox', :name => 'shortener[allow-override]', :class => 'text advanced', :value => 'true'}
19
+ :javascript
20
+ $(function(){
21
+ $('.advanced').hide();
22
+ })
@@ -0,0 +1,5 @@
1
+ #link_display.row
2
+ %div.offset5.span4
3
+ %h4= @url
4
+ %div.span2
5
+ = clippy(@url)
@@ -0,0 +1,25 @@
1
+ #shorterner-index
2
+ %table
3
+ %thead
4
+ %tr
5
+ %th Shortened
6
+ %th Full Url
7
+ %th Set Count
8
+ %th Click Count
9
+ %th TTL
10
+ %th Max Clicks
11
+ %tbody
12
+ - @shortens.each do |short|
13
+ %tr
14
+ %td= short['shortened']
15
+ %td
16
+ %a{href: short['url']}= short['url'][0..50] + ((short['url'].length > 50) ? '...' : '')
17
+ %td= short['set-count']
18
+ %td= short['click-count'] || 0
19
+ %td= ttl_display(short['expire'])
20
+ %td= short['max-clicks'] || "∞"
21
+ %td
22
+ %a{href: "/delete/#{short['shortened']}", class: 'delete-button'}
23
+ %img{src: 'delete-icon.png', alt: 'delete!', width: '16px', height: '16px'}
24
+ %td= clippy("#{base_url}/#{short['shortened']}")
25
+
@@ -0,0 +1,21 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Shortener
5
+ %link{rel: 'stylesheet', type: 'text/css', href: '/patched.bootstrap.min.css'}
6
+ %script{src: '/jquery.min.js', type: 'text/javascript'}
7
+ %script{src: 'site.js', type: 'text/javascript'}
8
+ %body{:'padding-top' => '60px'}
9
+
10
+ %div.topbar
11
+ %div.topbar-inner
12
+ %div.container
13
+ %a{class: 'brand', href: "/"} Shortener
14
+ %ul.nav
15
+ %li
16
+ %a{href: '/index'} Index
17
+ %li
18
+ %a{href: '/add'} Add
19
+
20
+ #main.container(style="margin-top: 40px;")
21
+ = yield
@@ -0,0 +1,75 @@
1
+ %link{href: "skin/blue.monday/jplayer.blue.monday.css", rel: 'stylesheet', type: 'text/css'}
2
+ %script{src: 'jquery.jplayer.min.js', type: 'text/javascript'}
3
+
4
+ %br
5
+ %br
6
+ .row
7
+ #jquery_jplayer_1.jp-jplayer.center
8
+ #jp_container_1.jp-audio.center
9
+ .jp-type-single
10
+ .jp-gui.jp-interface
11
+ %ul.jp-controls
12
+ %li
13
+ %a.jp-play{:href => "javascript:;", :tabindex => "1"} play
14
+ %li
15
+ %a.jp-pause{:href => "javascript:;", :tabindex => "1"} pause
16
+ %li
17
+ %a.jp-stop{:href => "javascript:;", :tabindex => "1"} stop
18
+ %li
19
+ %a.jp-mute{:href => "javascript:;", :tabindex => "1", :title => "mute"} mute
20
+ %li
21
+ %a.jp-unmute{:href => "javascript:;", :tabindex => "1", :title => "unmute"} unmute
22
+ %li
23
+ %a.jp-volume-max{:href => "javascript:;", :tabindex => "1", :title => "max volume"} max volume
24
+ .jp-progress
25
+ .jp-seek-bar
26
+ .jp-play-bar
27
+ .jp-volume-bar
28
+ .jp-volume-bar-value
29
+ .jp-time-holder
30
+ .jp-current-time
31
+ .jp-duration
32
+ %ul.jp-toggles
33
+ %li
34
+ %a.jp-repeat{:href => "javascript:;", :tabindex => "1", :title => "repeat"} repeat
35
+ %li
36
+ %a.jp-repeat-off{:href => "javascript:;", :tabindex => "1", :title => "repeat off"} repeat off
37
+ .jp-title
38
+ %ul
39
+ %li= @short['name']
40
+ %li= @short['description']
41
+ .jp-no-solution
42
+ %span Update Required
43
+ To play the media you will need to either update your browser to a recent version or update your
44
+ = succeed "." do
45
+ %a{:href => "http://get.adobe.com/flashplayer/", :target => "_blank"} Flash plugin
46
+
47
+ :javascript
48
+
49
+ $("#jquery_jplayer_1").jPlayer({
50
+ ready: function () {
51
+ $(this).jPlayer("setMedia", {
52
+ #{@short['extension']}: "#{@short['url']}",
53
+ });
54
+ },
55
+ play: function() { // To avoid both jPlayers playing together.
56
+ $(this).jPlayer("pauseOthers");
57
+ },
58
+ repeat: function(event) { // Override the default jPlayer repeat event handler
59
+ if(event.jPlayer.options.loop) {
60
+ $(this).unbind(".jPlayerRepeat").unbind(".jPlayerNext");
61
+ $(this).bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() {
62
+ $(this).jPlayer("play");
63
+ });
64
+ } else {
65
+ $(this).unbind(".jPlayerRepeat").unbind(".jPlayerNext");
66
+ $(this).bind($.jPlayer.event.ended + ".jPlayer.jPlayerNext", function() {
67
+ $("#jquery_jplayer_2").jPlayer("play", 0);
68
+ });
69
+ }
70
+ },
71
+ swfPath: "js",
72
+ supplied: "#{@short['extension']}",
73
+ wmode: "window"
74
+ });
75
+
@@ -0,0 +1,27 @@
1
+ %br
2
+ %br
3
+ :css
4
+ img {
5
+ max-width: 100%;
6
+ }
7
+
8
+ .row
9
+ %a.center{href: @short['url']}
10
+ %img{src: @short['url']}
11
+
12
+ .row
13
+ %p
14
+ %b Name:
15
+ = @short['name']
16
+
17
+ .row
18
+ %p
19
+ %b Descrtiption:
20
+ %br
21
+ = @short['description']
22
+
23
+ :css
24
+ .center {
25
+ margin: 0 auto;
26
+ padding: 0;
27
+ }
@@ -0,0 +1,23 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Shortener
5
+ %link{rel: 'stylesheet', type: 'text/css', href: '/patched.bootstrap.min.css'}
6
+ %script{src: 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js', type: 'text/javascript'}
7
+ %script{src: 'site.js', type: 'text/javascript'}
8
+ %body{:'padding-top' => '60px'}
9
+
10
+ #main.container(style="margin-top: 40px;")
11
+ = yield
12
+ .row
13
+ %a.center{href: "#{@short['url']}"} Download
14
+ :css
15
+ body {
16
+ background-color: #787171;
17
+ }
18
+
19
+ .center {
20
+ margin: 0 auto;
21
+ padding: 0;
22
+ }
23
+
@@ -0,0 +1,71 @@
1
+ %link{href: "skin/blue.monday/jplayer.blue.monday.css", rel: 'stylesheet', type: 'text/css'}
2
+ %script{src: 'jquery.jplayer.min.js', type: 'text/javascript'}
3
+
4
+ #jp_container_1.jp-video.jp-video-360p.center
5
+ .jp-type-single
6
+ #jquery_jplayer_1.jp-jplayer
7
+ .jp-gui
8
+ .jp-video-play
9
+ %a.jp-video-play-icon{:href => "javascript:;", :tabindex => "1"} play
10
+ .jp-interface
11
+ .jp-progress
12
+ .jp-seek-bar
13
+ .jp-play-bar
14
+ .jp-current-time
15
+ .jp-duration
16
+ .jp-controls-holder
17
+ %ul.jp-controls
18
+ %li
19
+ %a.jp-play{:href => "javascript:;", :tabindex => "1"} play
20
+ %li
21
+ %a.jp-pause{:href => "javascript:;", :tabindex => "1"} pause
22
+ %li
23
+ %a.jp-stop{:href => "javascript:;", :tabindex => "1"} stop
24
+ %li
25
+ %a.jp-mute{:href => "javascript:;", :tabindex => "1", :title => "mute"} mute
26
+ %li
27
+ %a.jp-unmute{:href => "javascript:;", :tabindex => "1", :title => "unmute"} unmute
28
+ %li
29
+ %a.jp-volume-max{:href => "javascript:;", :tabindex => "1", :title => "max volume"} max volume
30
+ .jp-volume-bar
31
+ .jp-volume-bar-value
32
+ %ul.jp-toggles
33
+ %li
34
+ %a.jp-full-screen{:href => "javascript:;", :tabindex => "1", :title => "full screen"} full screen
35
+ %li
36
+ %a.jp-restore-screen{:href => "javascript:;", :tabindex => "1", :title => "restore screen"} restore screen
37
+ %li
38
+ %a.jp-repeat{:href => "javascript:;", :tabindex => "1", :title => "repeat"} repeat
39
+ %li
40
+ %a.jp-repeat-off{:href => "javascript:;", :tabindex => "1", :title => "repeat off"} repeat off
41
+ .jp-title
42
+ %ul
43
+ %li= @short['name']
44
+ %li= @short['description']
45
+ .jp-no-solution
46
+ %span Update Required
47
+ To play the media you will need to either update your browser to a recent version or update your
48
+ = succeed "." do
49
+ %a{:href => "http://get.adobe.com/flashplayer/", :target => "_blank"} Flash plugin
50
+
51
+
52
+ :javascript
53
+
54
+ $("#jquery_jplayer_1").jPlayer({
55
+ ready: function () {
56
+ $(this).jPlayer("setMedia", { #{@short['extension']}: "#{@short['url']}" });
57
+ },
58
+ swfPath: "js",
59
+ supplied: "#{@short['extension']}",
60
+ size: {
61
+ width: "640px",
62
+ height: "360px",
63
+ cssClass: "jp-video-360p"
64
+ }
65
+ });
66
+
67
+ :css
68
+ .center {
69
+ margin: 0 auto;
70
+ padding: 0;
71
+ }
@@ -0,0 +1,130 @@
1
+ %script{src: "swfupload.js"}
2
+ %script{src: "jquery-swfupload-min.js"}
3
+ :erb
4
+ <script>
5
+ $(function(){
6
+ $('#swfupload-control').swfupload({
7
+ // Backend Settings
8
+ upload_url: "<%= @upload_url %>", // Relative to the SWF file (or you can use absolute paths)
9
+ http_success : [ 200, 201, 204 ], // FOR AWS
10
+
11
+ // File Upload Settings
12
+ file_size_limit : "102400", // 100MB
13
+ file_types : "*.*",
14
+ file_types_description : "All Files",
15
+ file_upload_limit : "10",
16
+ file_queue_limit : "0",
17
+ file_post_name : "file", // FOR AWS
18
+
19
+ // Button settings
20
+ button_image_url : "/images/XPButtonUploadText_61x22.png",
21
+ button_placeholder_id : "span-button-placeholder",
22
+ button_width: 61,
23
+ button_height: 22,
24
+
25
+ // Flash Settings
26
+ flash_url : "/flash/swfupload.swf",
27
+ //debug: true,
28
+ post_params: <%= @post.to_json %> // FOR AWS
29
+
30
+ })
31
+ .bind('fileQueued', function(event, file){
32
+ // start the upload since it's queued
33
+ //$(this).swfupload('startUpload');
34
+ $(this).swfupload('setButtonDisabled', true);
35
+ $('#file-name-placeholder').text(file.name);
36
+ })
37
+ .bind('fileQueueError', function(event, file, errorCode, message){
38
+ //$('#log').append('<li>File queue error - '+message+'</li>');
39
+ //$(this).show();
40
+ })
41
+ .bind('uploadStart', function(event, file){
42
+ $('#progressbar').show();
43
+ })
44
+ .bind('uploadProgress', function(event, file, bytesLoaded){
45
+ var avg = bytesLoaded / file.size * 100;
46
+ //$('#log').append('<li>Upload progress - '+bytesLoaded+ ' ' + avg + '</li>');
47
+ $('#progressbar .bar').css('width', avg + '%' );
48
+ })
49
+ .bind('uploadSuccess', function(event, file, serverData){
50
+ //$('#log').append('<li>Upload success - '+file.name+'</li>');
51
+ })
52
+ .bind('uploadComplete', function(event, file){
53
+ //$('#log').append('<li>Upload complete - '+file.name+'</li>');
54
+ $('#progressbar .active').removeClass('active');
55
+
56
+ var values = $('#upload-form').serialize();
57
+ values += '&shortener%5bfile_name%5d=' + file.name;
58
+ // Change this callback function to suite your needs
59
+ // $.ajax({
60
+ // type: "POST",
61
+ // url: '/upload',
62
+ // data: "name=" + file.name,
63
+ // async: false,
64
+ // });
65
+ $.post('/upload', values, function(data){
66
+ $('#shortener-display').text(data.url)
67
+ .removeClass('hide');
68
+ });
69
+
70
+ // upload has completed, lets try the next one in the queue
71
+ $(this).swfupload('startUpload');
72
+ })
73
+ .bind('uploadError', function(event, file, errorCode, message){
74
+ //$('#log').append('<li>Upload error - '+message+'</li>');
75
+ });
76
+
77
+ });
78
+ </script>
79
+
80
+ .row
81
+ #progressbar.span8{style: 'display:none;'}
82
+ .progress.danger.active.striped
83
+ .bar{style: "width: 0%"}
84
+
85
+ .row
86
+ %div.offset1{:id=> "swfupload-control"}
87
+ %ol{:id=> "log"}
88
+ %span{:id=> "span-button-placeholder"}
89
+ %span{id: 'file-name-placeholder'}
90
+ %br
91
+
92
+ .row
93
+ %form.form{id: 'upload-form', action: '/upload', method: 'post'}
94
+ .row
95
+ %ul.offset2
96
+ %li.radio
97
+ %input{name: 'shortener[type]', type: 'radio', value: 'video'} Video
98
+ %li.radio
99
+ %input{name: 'shortener[type]', type: 'radio', value: 'audio'} Audio
100
+ %li.radio
101
+ %input{name: 'shortener[type]', type: 'radio', value: 'image'} Image
102
+ %li.radio
103
+ %input{name: 'shortener[type]', type: 'radio', value: 'download'} Download
104
+ .row
105
+ %label.offset8.hide{id: 'shortener-display'}
106
+ .field
107
+ %label{for: 'shorterner[name]'} Name
108
+ %input{type: 'text', name: 'shortener[name]'}
109
+ .field
110
+ %label{for: 'shorterner[description]'} Description
111
+ %input{type: 'text', name: 'shortener[description]'}
112
+ .row
113
+ .actions
114
+ %input.btn.primary{type: 'submit', value: 'Shorten'}
115
+
116
+ .row
117
+
118
+ :css
119
+ .radio {
120
+ display: inline;
121
+ margin-right: 20px;
122
+ }
123
+
124
+ :javascript
125
+ $('#upload-form').submit(function(e){
126
+ e.preventDefault();
127
+ $('#swfupload-control').swfupload('startUpload');
128
+ });
129
+
130
+