condo_interface 0.0.1 → 1.0.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.textile +7 -1
- data/app/assets/javascripts/condo_interface/directives.js +292 -81
- data/app/assets/stylesheets/condo_interface.css +1 -0
- data/app/assets/stylesheets/condo_interface/bootstrap/components.txt +17 -0
- data/app/assets/stylesheets/condo_interface/bootstrap/condo_custom.css +1346 -0
- data/app/assets/stylesheets/condo_interface/uploads.css +23 -70
- data/app/assets/templates/_upload.html +27 -15
- data/lib/condo_interface/version.rb +1 -1
- metadata +4 -2
data/README.textile
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
-
h1.
|
1
|
+
h1. Condo Interface
|
2
2
|
|
3
3
|
The default UI for the Condo project. Feel free to use, extend, adapt or write your own.
|
4
|
+
Condo Interface is under the terms of the MIT License.
|
4
5
|
|
5
6
|
|
7
|
+
h2. Usage
|
8
|
+
|
9
|
+
"Condo":https://github.com/cotag/Condominios is built as an "AngularJS application":http://angularjs.org/ which implements "models":http://docs.angularjs.org/guide/concepts#model and a "controller":http://docs.angularjs.org/guide/concepts#controller for a "Rails backend":http://rubyonrails.org/
|
10
|
+
Condo Interface is an example "view":http://docs.angularjs.org/guide/concepts#view with an associated "directive":http://docs.angularjs.org/guide/concepts#directives that interface with the Condo controller.
|
11
|
+
|
@@ -20,10 +20,10 @@
|
|
20
20
|
(function (factory) {
|
21
21
|
if (typeof define === 'function' && define.amd) {
|
22
22
|
// AMD
|
23
|
-
define(['jquery', '
|
23
|
+
define(['jquery', 'condo_controller'], factory);
|
24
24
|
} else {
|
25
25
|
// Browser globals
|
26
|
-
factory(jQuery, window.
|
26
|
+
factory(jQuery, window.CondoController);
|
27
27
|
}
|
28
28
|
}(function ($, uploads, undefined) {
|
29
29
|
'use strict';
|
@@ -43,7 +43,10 @@
|
|
43
43
|
// Allow for both mobile and desktop events or both
|
44
44
|
// Overkill?
|
45
45
|
//
|
46
|
-
|
46
|
+
var condoInterface = angular.module('CondoInterface', ['CondoUploader'])
|
47
|
+
|
48
|
+
|
49
|
+
condoInterface.directive('coTap', function() {
|
47
50
|
|
48
51
|
|
49
52
|
//
|
@@ -145,94 +148,238 @@
|
|
145
148
|
//
|
146
149
|
// create a directive for attaching the input events
|
147
150
|
//
|
148
|
-
|
149
|
-
return
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
151
|
+
condoInterface.directive('coUploads', ['Condo.Broadcast', '$timeout', function(broadcast, $timeout) {
|
152
|
+
return {
|
153
|
+
controller: 'Condo.Controller',
|
154
|
+
link: function(scope, element, attrs) {
|
155
|
+
var options = {
|
156
|
+
delegate: attrs['coDelegate'] || element,
|
157
|
+
drop_targets: attrs['coTargets'] || element,
|
158
|
+
hover_class: attrs['coHoverClass'] || 'drag-hover',
|
159
|
+
pre_check: attrs['coAccepts'] || '/./i',
|
160
|
+
size_limit: attrs['coLimit'] || 0
|
161
|
+
},
|
162
|
+
|
163
|
+
//
|
164
|
+
// Add files with their path information to the system
|
165
|
+
// Queue items here until we decide they should be added to the view
|
166
|
+
//
|
167
|
+
processPending = function() {
|
168
|
+
var avaliable = view_limit - scope.upload_count;
|
169
|
+
|
170
|
+
if(avaliable > 0 && pending_items.length > 0) {
|
171
|
+
|
172
|
+
var item = pending_items.shift(),
|
173
|
+
items = item.items,
|
174
|
+
length = items.length;
|
175
|
+
|
176
|
+
if(item.folders) {
|
177
|
+
var i = 0,
|
178
|
+
entry,
|
179
|
+
obj,
|
180
|
+
count = 0,
|
181
|
+
new_items = [],
|
182
|
+
processEntry = function(entry, path) {
|
183
|
+
//
|
184
|
+
// If it is a directory we add it to the pending queue
|
185
|
+
//
|
186
|
+
try {
|
187
|
+
if (entry.isDirectory) {
|
188
|
+
entry.createReader().readEntries(function(entries) {
|
189
|
+
|
190
|
+
pending_items.push({
|
191
|
+
items: entries,
|
192
|
+
folders: true,
|
193
|
+
path: path + entry.name + '/'
|
194
|
+
});
|
195
|
+
checkCount();
|
196
|
+
});
|
197
|
+
} else if (entry.isFile) { // Files are added to a file queue
|
198
|
+
entry.file(function(file) {
|
199
|
+
if(path.length > 0)
|
200
|
+
file.dir_path = path;
|
201
|
+
|
202
|
+
new_items.push(file);
|
203
|
+
|
204
|
+
checkCount();
|
205
|
+
});
|
206
|
+
} else {
|
207
|
+
checkCount();
|
208
|
+
}
|
209
|
+
} catch(err) {
|
210
|
+
//
|
211
|
+
// TODO:: hmmmm
|
212
|
+
//
|
213
|
+
checkCount();
|
214
|
+
}
|
215
|
+
|
216
|
+
},
|
217
|
+
checkCount = function() {
|
218
|
+
//
|
219
|
+
// Counts the entries processed so we can add any files to the queue
|
220
|
+
//
|
221
|
+
count += 1;
|
222
|
+
if (count >= length) {
|
223
|
+
if(new_items.length > 0) {
|
224
|
+
pending_items.unshift({ // add any files to the start of the queue
|
225
|
+
items: new_items,
|
226
|
+
folders: false
|
227
|
+
});
|
228
|
+
}
|
229
|
+
safeApply(scope, function() {
|
230
|
+
$timeout(processPending);
|
231
|
+
});
|
232
|
+
}
|
233
|
+
};
|
234
|
+
|
235
|
+
for (; i < length; i++) {
|
236
|
+
|
237
|
+
//
|
238
|
+
// first layer of DnD folders require you to getAsEntry
|
239
|
+
//
|
240
|
+
if(item.path.length == 0) {
|
241
|
+
obj = items[i];
|
242
|
+
obj.getAsEntry = obj.getAsEntry || obj.webkitGetAsEntry || obj.mozGetAsEntry;
|
243
|
+
entry = obj.getAsEntry();
|
244
|
+
} else {
|
245
|
+
entry = items[i];
|
246
|
+
}
|
247
|
+
processEntry(entry, item.path);
|
248
|
+
}
|
249
|
+
} else if(length <= avaliable) { // Regular files where we can add them all at once
|
250
|
+
scope.add(items);
|
251
|
+
$timeout(processPending); // Delay until next tick (delay and invoke apply are optional)
|
252
|
+
} else { // Regular file where we can't add them all at once
|
253
|
+
scope.add(items.splice(0, avaliable));
|
254
|
+
pending_items.unshift(item);
|
255
|
+
}
|
256
|
+
}
|
257
|
+
},
|
258
|
+
view_limit = 50, // Number of uploads that should be displayed at once
|
259
|
+
pending_items = []; // These are files or folders that have not been processed yet as we are at the view port limit
|
161
260
|
|
162
261
|
|
163
|
-
|
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
|
-
}
|
262
|
+
if(!!attrs['coEndpoint'])
|
263
|
+
scope.endpoint = attrs['coEndpoint'];
|
264
|
+
|
174
265
|
|
266
|
+
scope.options = options;
|
267
|
+
scope.remove_completed = false; // Remove completed uploads automatically
|
175
268
|
|
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
269
|
|
183
270
|
//
|
184
|
-
//
|
271
|
+
// Determine how to draw the element
|
185
272
|
//
|
186
|
-
|
187
|
-
|
273
|
+
if(document.implementation.hasFeature("org.w3c.svg", "1.0")) {
|
274
|
+
element.addClass('supports-svg');
|
275
|
+
} else {
|
276
|
+
element.addClass('no-svg');
|
277
|
+
}
|
278
|
+
|
279
|
+
|
280
|
+
//
|
281
|
+
// Detect file drops
|
282
|
+
//
|
283
|
+
options.drop_targets = $(options.drop_targets);
|
284
|
+
options.delegate = $(options.delegate).on('drop.condo', options.drop_targets, function(event) {
|
285
|
+
options.drop_targets.removeClass(options.hover_class);
|
286
|
+
|
287
|
+
//
|
288
|
+
// Prevent propagation early (so any errors don't cause unwanted behaviour)
|
289
|
+
//
|
290
|
+
event.preventDefault();
|
291
|
+
event.stopPropagation();
|
292
|
+
|
293
|
+
|
294
|
+
if (!!event.originalEvent.dataTransfer.items) {
|
295
|
+
pending_items.push({
|
296
|
+
items: event.originalEvent.dataTransfer.items,
|
297
|
+
folders: true,
|
298
|
+
path: ''
|
299
|
+
});
|
300
|
+
} else if(!!event.originalEvent.dataTransfer.files) {
|
301
|
+
var files = event.originalEvent.dataTransfer.files,
|
302
|
+
copy = [],
|
303
|
+
i = 0;
|
304
|
+
|
305
|
+
for (; i < files.length; i += 1)
|
306
|
+
copy.push(files[i]);
|
307
|
+
|
308
|
+
pending_items.push({
|
309
|
+
items: copy,
|
310
|
+
folders: false
|
311
|
+
});
|
312
|
+
}
|
313
|
+
|
314
|
+
safeApply(scope, function() {
|
315
|
+
processPending();
|
316
|
+
});
|
317
|
+
}).on('dragover.condo', options.drop_targets, function(event) {
|
318
|
+
$(this).addClass(options.hover_class);
|
319
|
+
|
320
|
+
return false;
|
321
|
+
}).on('dragleave.condo', options.drop_targets, function(event) {
|
322
|
+
$(this).removeClass(options.hover_class);
|
323
|
+
|
324
|
+
return false;
|
325
|
+
}).
|
326
|
+
|
188
327
|
|
189
|
-
|
190
|
-
|
328
|
+
//
|
329
|
+
// Detect manual file uploads
|
330
|
+
//
|
331
|
+
on('change.condo', ':file', function(event) {
|
332
|
+
var files = $(this)[0].files,
|
333
|
+
copy = [],
|
334
|
+
i = 0;
|
335
|
+
|
336
|
+
for (; i < files.length; i += 1)
|
337
|
+
copy.push(files[i]);
|
338
|
+
|
339
|
+
$(this).parents('form')[0].reset();
|
340
|
+
|
341
|
+
pending_items.push({
|
342
|
+
items: copy,
|
343
|
+
folders: false
|
344
|
+
});
|
345
|
+
|
346
|
+
safeApply(scope, function() {
|
347
|
+
processPending();
|
348
|
+
});
|
191
349
|
});
|
192
|
-
}).on('dragover.condo', options.drop_targets, function(event) {
|
193
|
-
$(this).addClass(options.hover_class);
|
194
350
|
|
195
|
-
return false;
|
196
|
-
}).on('dragleave.condo', options.drop_targets, function(event) {
|
197
|
-
$(this).removeClass(options.hover_class);
|
198
351
|
|
199
|
-
|
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();
|
352
|
+
//
|
353
|
+
// Add new uploads if possible
|
354
|
+
//
|
355
|
+
scope.$watch('upload_count', function(newValue, oldValue) {
|
356
|
+
processPending();
|
211
357
|
});
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
358
|
+
|
359
|
+
|
360
|
+
//
|
361
|
+
// Clean up any event handlers
|
362
|
+
//
|
363
|
+
scope.$on('$destroy', function() {
|
364
|
+
options.drop_targets.off('.condo');
|
365
|
+
options.delegate.off('.condo');
|
366
|
+
element.removeClass('supports-svg').removeClass('no-svg');
|
367
|
+
});
|
368
|
+
|
369
|
+
|
370
|
+
scope.$on('coFileAddFailed', function() {
|
371
|
+
// TODO:: need an unobtrusive notification system for failed adds
|
372
|
+
// alert('Failed to add file: ' + broadcast.message.reason);
|
373
|
+
});
|
374
|
+
|
375
|
+
|
376
|
+
scope.humanReadableByteCount = function(bytes, si) {
|
377
|
+
var unit = si ? 1000.0 : 1024.0;
|
378
|
+
if (bytes < unit) return bytes + (si ? ' iB' : ' B');
|
379
|
+
var exp = Math.floor(Math.log(bytes) / Math.log(unit)),
|
380
|
+
pre = (si ? 'kMGTPE' : 'KMGTPE').charAt(exp-1) + (si ? 'iB' : 'B');
|
381
|
+
return (bytes / Math.pow(unit, exp)).toFixed(1) + ' ' + pre;
|
382
|
+
}
|
236
383
|
}
|
237
384
|
}
|
238
385
|
}]);
|
@@ -242,7 +389,7 @@
|
|
242
389
|
// The individual upload events
|
243
390
|
// Triggers the pause, resume, abort functions
|
244
391
|
//
|
245
|
-
|
392
|
+
condoInterface.directive('coUpload', function() {
|
246
393
|
var PENDING = 0,
|
247
394
|
STARTED = 1,
|
248
395
|
PAUSED = 2,
|
@@ -274,7 +421,10 @@
|
|
274
421
|
element.find('td.controls').replaceWith( '<td class="blank" />' );
|
275
422
|
element.find('div.bar').removeClass('animate');
|
276
423
|
|
277
|
-
scope.
|
424
|
+
if(scope.remove_completed)
|
425
|
+
scope.animate_remove();
|
426
|
+
else
|
427
|
+
scope.check_autostart(); // Couldn't work out how to put this into the controller
|
278
428
|
break;
|
279
429
|
|
280
430
|
case PAUSED:
|
@@ -284,6 +434,9 @@
|
|
284
434
|
|
285
435
|
scope.paused = true;
|
286
436
|
// No need for break
|
437
|
+
|
438
|
+
if (scope.ignore_errors && scope.upload.error)
|
439
|
+
scope.check_autostart(); // Couldn't work out how to put this into the controller
|
287
440
|
}
|
288
441
|
});
|
289
442
|
|
@@ -305,4 +458,62 @@
|
|
305
458
|
};
|
306
459
|
});
|
307
460
|
|
461
|
+
|
462
|
+
//
|
463
|
+
// Toggling options
|
464
|
+
// based on: https://github.com/angular-ui/bootstrap/tree/master/src/dropdownToggle
|
465
|
+
//
|
466
|
+
condoInterface.directive('dropdownToggle', ['$document', '$location', '$window', function ($document, $location, $window) {
|
467
|
+
var openElement = null, close;
|
468
|
+
return {
|
469
|
+
restrict: 'CA',
|
470
|
+
link: function(scope, element, attrs) {
|
471
|
+
scope.$watch(function dropdownTogglePathWatch() {return $location.path();}, function dropdownTogglePathWatchAction() {
|
472
|
+
if (close) { close(); }
|
473
|
+
});
|
474
|
+
|
475
|
+
element.parent().bind('click', function(event) {
|
476
|
+
event.stopPropagation();
|
477
|
+
});
|
478
|
+
|
479
|
+
element.bind('click', function(event) {
|
480
|
+
event.preventDefault();
|
481
|
+
event.stopPropagation();
|
482
|
+
|
483
|
+
var iWasOpen = false;
|
484
|
+
|
485
|
+
if (openElement) {
|
486
|
+
iWasOpen = openElement === element;
|
487
|
+
close();
|
488
|
+
}
|
489
|
+
|
490
|
+
if (!iWasOpen){
|
491
|
+
element.parent().addClass('open');
|
492
|
+
openElement = element;
|
493
|
+
|
494
|
+
close = function (event) {
|
495
|
+
if (event) {
|
496
|
+
event.preventDefault();
|
497
|
+
event.stopPropagation();
|
498
|
+
}
|
499
|
+
$document.unbind('click', close);
|
500
|
+
element.parent().removeClass('open');
|
501
|
+
close = null;
|
502
|
+
openElement = null;
|
503
|
+
};
|
504
|
+
|
505
|
+
$document.bind('click', close);
|
506
|
+
}
|
507
|
+
});
|
508
|
+
|
509
|
+
|
510
|
+
//
|
511
|
+
// Center the pop-up, based on CSS location of the button
|
512
|
+
//
|
513
|
+
var popup = element.next('ul.dropdown-menu');
|
514
|
+
popup.css('margin-left', -(popup.width() / 2) + 'px');
|
515
|
+
}
|
516
|
+
};
|
517
|
+
}]);
|
518
|
+
|
308
519
|
}));
|