condo_interface 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +5 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/images/condo_interface/close.png +0 -0
  5. data/app/assets/images/condo_interface/close.svg +71 -0
  6. data/app/assets/images/condo_interface/document.png +0 -0
  7. data/app/assets/images/condo_interface/document.svg +108 -0
  8. data/app/assets/images/condo_interface/pause.png +0 -0
  9. data/app/assets/images/condo_interface/pause.svg +75 -0
  10. data/app/assets/images/condo_interface/play.png +0 -0
  11. data/app/assets/images/condo_interface/play.svg +79 -0
  12. data/app/assets/javascripts/condo_interface/directives.js +308 -0
  13. data/app/assets/javascripts/condo_interface.js +1 -0
  14. data/app/assets/stylesheets/condo_interface/images.css.erb +51 -0
  15. data/app/assets/stylesheets/condo_interface/uploads.css +475 -0
  16. data/app/assets/stylesheets/condo_interface.css +16 -0
  17. data/app/assets/templates/_upload.html +59 -0
  18. data/app/views/condo_interface/_upload.html +4 -0
  19. data/lib/condo_interface/engine.rb +5 -0
  20. data/lib/condo_interface/version.rb +3 -0
  21. data/lib/condo_interface.rb +4 -0
  22. data/lib/tasks/condo_interface_tasks.rake +4 -0
  23. data/test/condo_interface_test.rb +7 -0
  24. data/test/dummy/README.rdoc +261 -0
  25. data/test/dummy/Rakefile +7 -0
  26. data/test/dummy/app/assets/javascripts/application.js +15 -0
  27. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  28. data/test/dummy/app/controllers/application_controller.rb +3 -0
  29. data/test/dummy/app/helpers/application_helper.rb +2 -0
  30. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/test/dummy/config/application.rb +59 -0
  32. data/test/dummy/config/boot.rb +10 -0
  33. data/test/dummy/config/database.yml +25 -0
  34. data/test/dummy/config/environment.rb +5 -0
  35. data/test/dummy/config/environments/development.rb +37 -0
  36. data/test/dummy/config/environments/production.rb +67 -0
  37. data/test/dummy/config/environments/test.rb +37 -0
  38. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  39. data/test/dummy/config/initializers/inflections.rb +15 -0
  40. data/test/dummy/config/initializers/mime_types.rb +5 -0
  41. data/test/dummy/config/initializers/secret_token.rb +7 -0
  42. data/test/dummy/config/initializers/session_store.rb +8 -0
  43. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  44. data/test/dummy/config/locales/en.yml +5 -0
  45. data/test/dummy/config/routes.rb +4 -0
  46. data/test/dummy/config.ru +4 -0
  47. data/test/dummy/public/404.html +26 -0
  48. data/test/dummy/public/422.html +26 -0
  49. data/test/dummy/public/500.html +25 -0
  50. data/test/dummy/public/favicon.ico +0 -0
  51. data/test/dummy/script/rails +6 -0
  52. data/test/integration/navigation_test.rb +10 -0
  53. data/test/test_helper.rb +15 -0
  54. metadata +161 -0
@@ -0,0 +1,308 @@
1
+ /**
2
+ * CoTag Condo
3
+ * Direct to cloud resumable uploads
4
+ *
5
+ * Copyright (c) 2012 CoTag Media.
6
+ *
7
+ * @author Stephen von Takach <steve@cotag.me>
8
+ * @copyright 2012 cotag.me
9
+ *
10
+ *
11
+ * References:
12
+ * * https://github.com/umdjs/umd
13
+ * * https://github.com/addyosmani/jquery-plugin-patterns
14
+ * * http://ie.microsoft.com/testdrive/ieblog/2011/oct/PointerDraw.js.source.html (detect click, touch etc on all platforms)
15
+ * * http://docs.angularjs.org/guide/directive
16
+ * * http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java/3758880
17
+ *
18
+ **/
19
+
20
+ (function (factory) {
21
+ if (typeof define === 'function' && define.amd) {
22
+ // AMD
23
+ define(['jquery', 'condo_uploader'], factory);
24
+ } else {
25
+ // Browser globals
26
+ factory(jQuery, window.CondoUploader);
27
+ }
28
+ }(function ($, uploads, undefined) {
29
+ 'use strict';
30
+
31
+
32
+ var safeApply = function(scope, fn) {
33
+ var phase = scope.$root.$$phase;
34
+ if(phase == '$apply' || phase == '$digest') {
35
+ fn();
36
+ } else {
37
+ scope.$apply(fn);
38
+ }
39
+ };
40
+
41
+
42
+ //
43
+ // Allow for both mobile and desktop events or both
44
+ // Overkill?
45
+ //
46
+ uploads.directive('coTap', function() {
47
+
48
+
49
+ //
50
+ // Opera doesn't have Object.keys so we use this wrapper
51
+ //
52
+ var NumberOfKeys = function(theObject) {
53
+ if (Object.keys)
54
+ return Object.keys(theObject).length;
55
+
56
+ var n = 0;
57
+ for (var key in theObject)
58
+ ++n;
59
+
60
+ return n;
61
+ };
62
+
63
+ return function(scope, element, attrs) {
64
+ var tracker = {},
65
+
66
+ // common event handler for the mouse/pointer/touch models and their down/start, move, up/end, and cancel events
67
+ DoEvent = function(event) {
68
+
69
+ //
70
+ // Optimise rejecting clicks (iOS) that are most likely triggered by a touch
71
+ //
72
+ if (event.originalEvent.type == "click" && NumberOfKeys(tracker) == 0)
73
+ return;
74
+
75
+ var theEvtObj = event.originalEvent,
76
+ pointerList = theEvtObj.changedTouches ? theEvtObj.changedTouches : [theEvtObj];
77
+ for (var i = 0; i < pointerList.length; ++i) {
78
+ var pointerObj = pointerList[i],
79
+ pointerId = (typeof pointerObj.identifier != 'undefined') ? pointerObj.identifier : (typeof pointerObj.pointerId != 'undefined') ? pointerObj.pointerId : 1;
80
+
81
+ if (theEvtObj.type.match(/(start|down)$/i)) {
82
+ // clause for processing MSPointerDown, touchstart, and mousedown
83
+
84
+ //
85
+ // Track the element the event started on and if we should execute the attached action
86
+ //
87
+ tracker[pointerId] = {element: this, execute: true};
88
+
89
+ //
90
+ // in the Microsoft pointer model, set the capture for this pointer
91
+ // in the mouse model, set the capture or add a document-level event handlers if this is our first down point
92
+ // nothing is required for the iOS touch model because capture is implied on touchstart
93
+ //
94
+ if (this.msSetPointerCapture)
95
+ this.msSetPointerCapture(pointerId);
96
+
97
+
98
+ } else if (theEvtObj.type.match(/move$/i)) {
99
+ // clause handles MSPointerMove and touchmove
100
+
101
+ if(tracker[pointerId])
102
+ tracker[pointerId].execute = false;
103
+
104
+
105
+ } else if (tracker[pointerId] && theEvtObj.type.match(/(up|end|cancel|click)$/i)) {
106
+ // clause handles up/end/cancel/click
107
+ var target = tracker[pointerId].element;
108
+
109
+ if (!theEvtObj.type.match(/cancel$/i) && tracker[pointerId].execute === true)
110
+ safeApply(scope, attrs['coTap']); // Apply the click, touch, point event
111
+
112
+ delete tracker[pointerId];
113
+
114
+ //
115
+ // in the Microsoft pointer model, release the capture for this pointer
116
+ // in the mouse model, release the capture or remove document-level event handlers if there are no down points
117
+ // nothing is required for the iOS touch model because capture is implied on touchstart
118
+ //
119
+ if (target.msReleasePointerCapture)
120
+ target.msReleasePointerCapture(pointerId);
121
+ }
122
+ }
123
+ };
124
+
125
+ if (window.navigator.msPointerEnabled) {
126
+ // Microsoft pointer model
127
+ element.on('MSPointerDown.condo MSPointerMove.condo MSPointerUp.condo MSPointerCancel.condo', DoEvent);
128
+ } else {
129
+ // iOS touch model & mouse model
130
+ element.on('touchstart.condo touchmove.condo touchend.condo touchcancel.condo mousedown.condo click.condo', DoEvent);
131
+ }
132
+
133
+
134
+ //
135
+ // Clean up any event handlers
136
+ //
137
+ scope.$on('$destroy', function() {
138
+ element.off('.condo');
139
+ });
140
+
141
+
142
+ };
143
+ });
144
+
145
+ //
146
+ // create a directive for attaching the input events
147
+ //
148
+ uploads.directive('coUploads', ['Condo.Broadcast', function(broadcast) {
149
+ return function(scope, element, attrs) {
150
+ var options = {
151
+ delegate: attrs['coDelegate'] || element,
152
+ drop_targets: attrs['coTargets'] || element,
153
+ hover_class: attrs['coHoverClass'] || 'drag-hover',
154
+ pre_check: attrs['coAccepts'] || '/./i',
155
+ size_limit: attrs['coLimit'] || 0
156
+ };
157
+
158
+
159
+ if(!!attrs['coEndpoint'])
160
+ scope.endpoint = attrs['coEndpoint'];
161
+
162
+
163
+ scope.options = options;
164
+
165
+
166
+ //
167
+ // Determine how to draw the element
168
+ //
169
+ if(document.implementation.hasFeature("org.w3c.svg", "1.0")) {
170
+ element.addClass('supports-svg');
171
+ } else {
172
+ element.addClass('no-svg');
173
+ }
174
+
175
+
176
+ //
177
+ // Detect file drops
178
+ //
179
+ options.drop_targets = $(options.drop_targets);
180
+ options.delegate = $(options.delegate).on('drop.condo', options.drop_targets, function(event) {
181
+ options.drop_targets.removeClass(options.hover_class);
182
+
183
+ //
184
+ // Prevent propagation early (so any errors don't cause unwanted behaviour)
185
+ //
186
+ event.preventDefault();
187
+ event.stopPropagation();
188
+
189
+ safeApply(scope, function() {
190
+ scope.add(event.originalEvent.dataTransfer.files);
191
+ });
192
+ }).on('dragover.condo', options.drop_targets, function(event) {
193
+ $(this).addClass(options.hover_class);
194
+
195
+ return false;
196
+ }).on('dragleave.condo', options.drop_targets, function(event) {
197
+ $(this).removeClass(options.hover_class);
198
+
199
+ return false;
200
+ }).
201
+
202
+
203
+ //
204
+ // Detect manual file uploads
205
+ //
206
+ on('change.condo', ':file', function(event) {
207
+ var self = $(this);
208
+ safeApply(scope, function() {
209
+ scope.add(self[0].files);
210
+ self.parents('form')[0].reset();
211
+ });
212
+ });
213
+
214
+
215
+ //
216
+ // Clean up any event handlers
217
+ //
218
+ scope.$on('$destroy', function() {
219
+ options.drop_targets.off('.condo');
220
+ options.delegate.off('.condo');
221
+ element.removeClass('supports-svg').removeClass('no-svg');
222
+ });
223
+
224
+
225
+ scope.$on('coFileAddFailed', function() {
226
+ alert('Failed to add file: ' + broadcast.message.reason);
227
+ });
228
+
229
+
230
+ scope.humanReadableByteCount = function(bytes, si) {
231
+ var unit = si ? 1000.0 : 1024.0;
232
+ if (bytes < unit) return bytes + (si ? ' iB' : ' B');
233
+ var exp = Math.floor(Math.log(bytes) / Math.log(unit)),
234
+ pre = (si ? 'kMGTPE' : 'KMGTPE').charAt(exp-1) + (si ? 'iB' : 'B');
235
+ return (bytes / Math.pow(unit, exp)).toFixed(1) + ' ' + pre;
236
+ }
237
+ }
238
+ }]);
239
+
240
+
241
+ //
242
+ // The individual upload events
243
+ // Triggers the pause, resume, abort functions
244
+ //
245
+ uploads.directive('coUpload', function() {
246
+ var PENDING = 0,
247
+ STARTED = 1,
248
+ PAUSED = 2,
249
+ UPLOADING = 3,
250
+ COMPLETED = 4,
251
+ ABORTED = 5;
252
+
253
+ return function(scope, element, attrs) {
254
+
255
+ scope.size = scope.humanReadableByteCount(scope.upload.size, false);
256
+ scope.progress = 0;
257
+ scope.paused = true;
258
+
259
+ scope.$watch('upload.state', function(newValue, oldValue) {
260
+ switch(newValue) {
261
+ case STARTED:
262
+ scope.paused = false;
263
+ scope.upload.message = 'starting...';
264
+ break;
265
+
266
+ case UPLOADING:
267
+ element.find('div.bar').addClass('animate');
268
+ scope.upload.message = undefined;
269
+ scope.paused = false;
270
+ break;
271
+
272
+ case COMPLETED:
273
+ scope.upload.message = 'complete';
274
+ element.find('td.controls').replaceWith( '<td class="blank" />' );
275
+ element.find('div.bar').removeClass('animate');
276
+
277
+ scope.check_autostart();
278
+ break;
279
+
280
+ case PAUSED:
281
+ element.find('div.bar').removeClass('animate');
282
+ if (scope.upload.message === undefined)
283
+ scope.upload.message = 'paused';
284
+
285
+ scope.paused = true;
286
+ // No need for break
287
+ }
288
+ });
289
+
290
+ scope.$watch('upload.progress', function(newValue, oldValue) {
291
+ scope.progress = newValue / scope.upload.size * 100;
292
+ });
293
+
294
+
295
+ scope.animate_remove = function() {
296
+ scope.abort(scope.upload);
297
+
298
+ element.fadeOut(800, function() {
299
+ safeApply(scope, function() {
300
+ scope.remove(scope.upload);
301
+ });
302
+ });
303
+ };
304
+
305
+ };
306
+ });
307
+
308
+ }));
@@ -0,0 +1 @@
1
+ //= require condo_interface/directives
@@ -0,0 +1,51 @@
1
+
2
+
3
+
4
+ .supports-svg div.condo-upload > div.description td.icon {
5
+ background: url(<%= asset_path('condo_interface/document.svg') %>) no-repeat center center;
6
+ }
7
+
8
+ .supports-svg div.condo-upload > div.stats td.controls.paused {
9
+ background: url(<%= asset_path('condo_interface/play.svg') %>) no-repeat center center;
10
+ }
11
+
12
+ .supports-svg div.condo-upload > div.stats td.controls.uploading {
13
+ background: url(<%= asset_path('condo_interface/pause.svg') %>) no-repeat center center;
14
+ }
15
+
16
+ .supports-svg div.condo-upload > div.stats td.abort {
17
+ background: url(<%= asset_path('condo_interface/close.svg') %>) no-repeat center center;
18
+ }
19
+
20
+
21
+
22
+
23
+
24
+ .no-svg div.condo-upload > div.description td.icon {
25
+ background: url(<%= asset_path('condo_interface/document.png') %>) no-repeat center center;
26
+ }
27
+
28
+ .no-svg div.condo-upload > div.stats td.controls.paused {
29
+ background: url(<%= asset_path('condo_interface/play.png') %>) no-repeat center center;
30
+ }
31
+
32
+ .no-svg div.condo-upload > div.stats td.controls.uploading {
33
+ background: url(<%= asset_path('condo_interface/pause.png') %>) no-repeat center center;
34
+ }
35
+
36
+ .no-svg div.condo-upload > div.stats td.abort {
37
+ background: url(<%= asset_path('condo_interface/close.png') %>) no-repeat center center;
38
+ }
39
+
40
+
41
+
42
+
43
+ div.condo-upload td.image {
44
+ -webkit-background-size: contain !important;
45
+ -moz-background-size: contain !important;
46
+ -ms-background-size: contain !important;
47
+ -o-background-size: contain !important;
48
+ background-size: contain !important;
49
+ }
50
+
51
+