condo_interface 0.0.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.
- data/MIT-LICENSE +20 -0
- data/README.textile +5 -0
- data/Rakefile +40 -0
- data/app/assets/images/condo_interface/close.png +0 -0
- data/app/assets/images/condo_interface/close.svg +71 -0
- data/app/assets/images/condo_interface/document.png +0 -0
- data/app/assets/images/condo_interface/document.svg +108 -0
- data/app/assets/images/condo_interface/pause.png +0 -0
- data/app/assets/images/condo_interface/pause.svg +75 -0
- data/app/assets/images/condo_interface/play.png +0 -0
- data/app/assets/images/condo_interface/play.svg +79 -0
- data/app/assets/javascripts/condo_interface/directives.js +308 -0
- data/app/assets/javascripts/condo_interface.js +1 -0
- data/app/assets/stylesheets/condo_interface/images.css.erb +51 -0
- data/app/assets/stylesheets/condo_interface/uploads.css +475 -0
- data/app/assets/stylesheets/condo_interface.css +16 -0
- data/app/assets/templates/_upload.html +59 -0
- data/app/views/condo_interface/_upload.html +4 -0
- data/lib/condo_interface/engine.rb +5 -0
- data/lib/condo_interface/version.rb +3 -0
- data/lib/condo_interface.rb +4 -0
- data/lib/tasks/condo_interface_tasks.rake +4 -0
- data/test/condo_interface_test.rb +7 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/test_helper.rb +15 -0
- 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
|
+
|