stormfront-rails 0.1.0 → 0.2.3
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/stormfront/rails/version.rb +2 -2
- data/lib/stormfront/rails.rb +2 -0
- data/stormfront-rails.gemspec +3 -3
- data/vendor/assets/javascripts/src/handlebars.js +4604 -0
- data/vendor/assets/javascripts/src/stormfront.js +1137 -0
- data/vendor/assets/javascripts/stormfront.js +3 -32
- metadata +24 -47
- data/vendor/assets/javascripts/stormfront/Alert.js +0 -17
- data/vendor/assets/javascripts/stormfront/Container.js +0 -31
- data/vendor/assets/javascripts/stormfront/Entity.js +0 -53
- data/vendor/assets/javascripts/stormfront/Errors.js +0 -25
- data/vendor/assets/javascripts/stormfront/KeyboardEvents.js +0 -52
- data/vendor/assets/javascripts/stormfront/Layout.js +0 -60
- data/vendor/assets/javascripts/stormfront/List.js +0 -123
- data/vendor/assets/javascripts/stormfront/MouseEvents.js +0 -146
- data/vendor/assets/javascripts/stormfront/Namespaces.js +0 -5
- data/vendor/assets/javascripts/stormfront/Overlay.js +0 -178
- data/vendor/assets/javascripts/stormfront/Reducer.js +0 -9
- data/vendor/assets/javascripts/stormfront/Request.js +0 -39
- data/vendor/assets/javascripts/stormfront/View.js +0 -55
- data/vendor/assets/javascripts/stormfront/ViewBase.js +0 -57
- data/vendor/assets/javascripts/stormfront/mixin/Dispatch.js +0 -19
- data/vendor/assets/javascripts/stormfront/mixin/Other.js +0 -25
- data/vendor/assets/javascripts/stormfront/support/Chaperone.js +0 -69
- data/vendor/assets/javascripts/stormfront/support/Template.js +0 -75
- data/vendor/assets/javascripts/stormfront/types/Arguments.js +0 -27
- data/vendor/assets/javascripts/stormfront/types/Class.js +0 -25
- data/vendor/assets/javascripts/stormfront/types/Hash.js +0 -23
- data/vendor/assets/javascripts/stormfront/types/Number.js +0 -15
- data/vendor/assets/javascripts/stormfront/types/Response.js +0 -31
- data/vendor/assets/javascripts/stormfront/types/String.js +0 -44
- data/vendor/assets/javascripts/stormfront/types/Time.js +0 -29
@@ -0,0 +1,1137 @@
|
|
1
|
+
var stormfront = { };
|
2
|
+
var Stormfront = { Mixin: { } };
|
3
|
+
|
4
|
+
Stormfront.VERSION = '1.0.0';
|
5
|
+
|
6
|
+
Stormfront.Class = function(options) {
|
7
|
+
if (this.initialize)
|
8
|
+
this.initialize.apply(this, arguments);
|
9
|
+
};
|
10
|
+
|
11
|
+
Stormfront.Class.extend = function(protoProps, staticProps) {
|
12
|
+
var parent = this;
|
13
|
+
var child;
|
14
|
+
|
15
|
+
if (protoProps && _.has(protoProps, 'constructor'))
|
16
|
+
child = protoProps.constructor;
|
17
|
+
else
|
18
|
+
child = function(){ return parent.apply(this, arguments); };
|
19
|
+
|
20
|
+
_.extend(child, parent, staticProps);
|
21
|
+
|
22
|
+
var Surrogate = function(){ this.constructor = child; };
|
23
|
+
Surrogate.prototype = parent.prototype;
|
24
|
+
child.prototype = new Surrogate;
|
25
|
+
|
26
|
+
if (protoProps) _.extend(child.prototype, protoProps);
|
27
|
+
child.__super__ = parent.prototype;
|
28
|
+
|
29
|
+
return child;
|
30
|
+
};
|
31
|
+
|
32
|
+
|
33
|
+
stormfront.arguments = function(args){
|
34
|
+
return new Stormfront.Arguments(args);
|
35
|
+
};
|
36
|
+
|
37
|
+
Stormfront.Arguments = Stormfront.Class.extend({
|
38
|
+
initialize: function(array){
|
39
|
+
if (array)
|
40
|
+
this.array = [].slice.call(array);
|
41
|
+
else
|
42
|
+
this.array = [];
|
43
|
+
},
|
44
|
+
skip: function(start) {
|
45
|
+
this.array = this.array.slice(start);
|
46
|
+
return this;
|
47
|
+
},
|
48
|
+
prepend: function(item){
|
49
|
+
this.array.unshift(item);
|
50
|
+
return this;
|
51
|
+
},
|
52
|
+
at: function(index, value){
|
53
|
+
this.array[index] = value;
|
54
|
+
return this;
|
55
|
+
},
|
56
|
+
get: function(){
|
57
|
+
return this.array;
|
58
|
+
}
|
59
|
+
});
|
60
|
+
|
61
|
+
stormfront.hash = function(hash){
|
62
|
+
return new Stormfront.Hash(hash);
|
63
|
+
};
|
64
|
+
|
65
|
+
Stormfront.Hash = Stormfront.Class.extend({
|
66
|
+
initialize: function(hash){
|
67
|
+
this.hash = hash;
|
68
|
+
},
|
69
|
+
findNestedValue: function(keys){
|
70
|
+
function retrieve(keys, context){
|
71
|
+
if (!context)
|
72
|
+
return null;
|
73
|
+
if (keys.length === 0)
|
74
|
+
return context;
|
75
|
+
var current = keys.shift();
|
76
|
+
return retrieve(keys, context[current]);
|
77
|
+
}
|
78
|
+
return retrieve(keys, this.hash);
|
79
|
+
},
|
80
|
+
subtract: function(values){
|
81
|
+
return _.omit(this.hash, _.keys(values));
|
82
|
+
}
|
83
|
+
});
|
84
|
+
|
85
|
+
stormfront.number = function(number){
|
86
|
+
return new Stormfront.Number(number);
|
87
|
+
};
|
88
|
+
|
89
|
+
Stormfront.Number = Stormfront.Class.extend({
|
90
|
+
initialize: function(number){
|
91
|
+
this.number = number;
|
92
|
+
},
|
93
|
+
isWithin: function(range){
|
94
|
+
return range[0] < this.number && range[1] > this.number;
|
95
|
+
},
|
96
|
+
compare: function(value){
|
97
|
+
return this.number < value ? -1 : this.number > value ? 1 : 0;
|
98
|
+
}
|
99
|
+
});
|
100
|
+
|
101
|
+
Stormfront.Response = Stormfront.Class.extend({
|
102
|
+
initialize: function(xhr){
|
103
|
+
this.xhr = xhr;
|
104
|
+
},
|
105
|
+
isActionable: function(){
|
106
|
+
return !(this.hasBeenHandled() || this.isUserUnauthorized() || this.hasBeenAborted());
|
107
|
+
},
|
108
|
+
hasBeenHandled: function(){
|
109
|
+
return this.xhr.handled === true;
|
110
|
+
},
|
111
|
+
markAsHandled: function(){
|
112
|
+
this.xhr.handled = true;
|
113
|
+
},
|
114
|
+
isUserUnauthorized: function(){
|
115
|
+
return this.xhr.status === 401;
|
116
|
+
},
|
117
|
+
hasBeenAborted: function(){
|
118
|
+
//TODO: consider xhr.status === 'abort'?
|
119
|
+
return this.xhr.readyState != 4;
|
120
|
+
},
|
121
|
+
getError: function(){
|
122
|
+
try {
|
123
|
+
var message = JSON.parse(this.xhr.responseText);
|
124
|
+
return message.error || message.message;
|
125
|
+
}
|
126
|
+
catch (e){
|
127
|
+
console.warn('Unhandled error', this.xhr, e);
|
128
|
+
return Stormfront.Errors.FEEDBACK;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
});
|
132
|
+
|
133
|
+
stormfront.string = function(text){
|
134
|
+
return new Stormfront.String(text);
|
135
|
+
};
|
136
|
+
|
137
|
+
Stormfront.String = Stormfront.Class.extend({
|
138
|
+
initialize: function(text){
|
139
|
+
this.text = text;
|
140
|
+
},
|
141
|
+
title: function(){
|
142
|
+
var sentence = _.str.capitalize(_.str.camelize(this.text)).split(/(?=[A-Z\d])/);
|
143
|
+
var displaySentence = "";
|
144
|
+
function processCharacter(character, i){
|
145
|
+
function whenPreviousWordIsNotAnAcronym() {
|
146
|
+
return i > 0 && sentence[i - 1].length > 1;
|
147
|
+
}
|
148
|
+
function whenPreviousWordISAnAcronymAndCurrentWordIsNotAnAcronym() {
|
149
|
+
return i > 0 && sentence[i - 1].length == 1 && sentence[i].length > 1;
|
150
|
+
}
|
151
|
+
if (whenPreviousWordIsNotAnAcronym() || whenPreviousWordISAnAcronymAndCurrentWordIsNotAnAcronym())
|
152
|
+
displaySentence += " ";
|
153
|
+
displaySentence += character;
|
154
|
+
}
|
155
|
+
_.each(sentence, processCharacter);
|
156
|
+
return displaySentence;
|
157
|
+
},
|
158
|
+
decimal: function(places, placeholder){
|
159
|
+
placeholder = placeholder || '';
|
160
|
+
places = places || 3;
|
161
|
+
var candidate = parseFloat(this.text);
|
162
|
+
return isNaN(candidate) ? placeholder : candidate.toFixed(places);
|
163
|
+
},
|
164
|
+
scientific: function(){
|
165
|
+
return this.text === null || $.trim(this.text) === '' ? '' : parseFloat(this.text).toExponential(3);
|
166
|
+
},
|
167
|
+
decimal_format: function(){
|
168
|
+
return this.decimal(this.text);
|
169
|
+
},
|
170
|
+
scientific_notation: function(){
|
171
|
+
return this.scientific(this.text);
|
172
|
+
},
|
173
|
+
firstWord: function(){
|
174
|
+
return this.text ? this.text.split(' ')[0] : '';
|
175
|
+
}
|
176
|
+
});
|
177
|
+
|
178
|
+
stormfront.time = function(datetime){
|
179
|
+
return new Stormfront.Time(datetime);
|
180
|
+
};
|
181
|
+
|
182
|
+
Stormfront.Time = Stormfront.Class.extend({
|
183
|
+
initialize: function(datetime){
|
184
|
+
this.time = moment(datetime || (new Date()).getTime());
|
185
|
+
},
|
186
|
+
now: function(){
|
187
|
+
return this.time;
|
188
|
+
},
|
189
|
+
getDiff: function(unit){
|
190
|
+
unit = unit || 'hours';
|
191
|
+
var now = moment().format();
|
192
|
+
return this.time.diff(now, unit);
|
193
|
+
},
|
194
|
+
getTimeAgo: function(){
|
195
|
+
return this.time.fromNow();
|
196
|
+
},
|
197
|
+
getLongDate: function(){
|
198
|
+
return this.time.format('MMMM D, YYYY h:mm:ss a');
|
199
|
+
},
|
200
|
+
getShortDate: function(){
|
201
|
+
return this.time.format('MMMM D, YYYY');
|
202
|
+
}
|
203
|
+
});
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
Stormfront.Chaperone = Stormfront.Class.extend({
|
211
|
+
initialize: function(){
|
212
|
+
this.children = {};
|
213
|
+
_.extend(this, Backbone.Events);
|
214
|
+
this.throttle('create', 'created', Stormfront.Errors.INITIALIZING);
|
215
|
+
this.throttle('render', 'rendered', Stormfront.Errors.RENDERING);
|
216
|
+
this.throttle('attach', 'attached', Stormfront.Errors.ATTACHING);
|
217
|
+
this.wrap('add', 'added', Stormfront.Errors.ADDING);
|
218
|
+
this.wrap('remove', 'removed', Stormfront.Errors.CLOSING);
|
219
|
+
},
|
220
|
+
|
221
|
+
create: function(childClass, options, context){
|
222
|
+
return new window[childClass](options.call(context));
|
223
|
+
},
|
224
|
+
find: function(identity){
|
225
|
+
return this.children[identity];
|
226
|
+
},
|
227
|
+
add: function(child){
|
228
|
+
var identity = child.getIdentity();
|
229
|
+
this.remove(this.find(identity));
|
230
|
+
this.children[identity] = child;
|
231
|
+
return child;
|
232
|
+
},
|
233
|
+
remove: function(child){
|
234
|
+
if (child)
|
235
|
+
this.children = _.omit(this.children, child.getIdentity());
|
236
|
+
return child;
|
237
|
+
},
|
238
|
+
render: function(child){
|
239
|
+
return child.render();
|
240
|
+
},
|
241
|
+
attach: function(child, location, method){
|
242
|
+
if (location.size() === 0)
|
243
|
+
throw Stormfront.Errors.NO_LOCATION(child);
|
244
|
+
else if (location.size() > 1)
|
245
|
+
throw Stormfront.Errors.MULTIPLE_LOCATIONS(child);
|
246
|
+
|
247
|
+
location[method](child.$el);
|
248
|
+
return child;
|
249
|
+
},
|
250
|
+
|
251
|
+
wrap: function(field, event, error){
|
252
|
+
var implementation = this[field];
|
253
|
+
this[field] = function(){
|
254
|
+
try {
|
255
|
+
var result = implementation.apply(this, arguments);
|
256
|
+
result && this.trigger(event, result);
|
257
|
+
} catch (e) {
|
258
|
+
this.trigger('error', error(arguments[0].toString()), e);
|
259
|
+
}
|
260
|
+
}
|
261
|
+
},
|
262
|
+
throttle: function(field, event, error){
|
263
|
+
this.wrap(field, event, error);
|
264
|
+
var implementation = this[field];
|
265
|
+
this[field] = function(){
|
266
|
+
var self = this;
|
267
|
+
var capturedArguments = arguments;
|
268
|
+
function func(){
|
269
|
+
implementation.apply(self, capturedArguments);
|
270
|
+
}
|
271
|
+
setTimeout(func, 5);
|
272
|
+
}
|
273
|
+
},
|
274
|
+
|
275
|
+
close: function(){
|
276
|
+
_.each(this.children, this.remove, this);
|
277
|
+
}
|
278
|
+
});
|
279
|
+
|
280
|
+
Stormfront.Template = Stormfront.Class.extend({
|
281
|
+
initialize: function(view){
|
282
|
+
this.view = view;
|
283
|
+
},
|
284
|
+
render: function(){
|
285
|
+
function renderTemplate(view){
|
286
|
+
function getTemplate(view){
|
287
|
+
var selector = view.getIdentity();
|
288
|
+
return $('#' + selector + '_template');
|
289
|
+
}
|
290
|
+
function compileTemplate(selection){
|
291
|
+
return Handlebars.compile(selection.html());
|
292
|
+
}
|
293
|
+
function expandTemplate(template){
|
294
|
+
return template(view.getViewModel());
|
295
|
+
}
|
296
|
+
return expandTemplate(compileTemplate(getTemplate(view)))
|
297
|
+
}
|
298
|
+
function findError(view){
|
299
|
+
function getTemplate(view){
|
300
|
+
if (!view.className)
|
301
|
+
throw Stormfront.Errors.NO_SELECTOR();
|
302
|
+
var selector = view.getIdentity();
|
303
|
+
return $('#' + selector + '_template');
|
304
|
+
}
|
305
|
+
function compileTemplate(template){
|
306
|
+
if (template.size() === 1)
|
307
|
+
return template;
|
308
|
+
if (template.size() === 0)
|
309
|
+
throw Stormfront.Errors.NO_TEMPLATE(view.getIdentity());
|
310
|
+
|
311
|
+
return Handlebars.compile(template.html());
|
312
|
+
}
|
313
|
+
function expandTemplate(template, vm){
|
314
|
+
try {
|
315
|
+
return template(vm);
|
316
|
+
}
|
317
|
+
catch(e) {
|
318
|
+
throw Stormfront.Errors.INCOMPATIBLE_TEMPLATE(view.getIdentity());
|
319
|
+
}
|
320
|
+
}
|
321
|
+
function getViewModel(view){
|
322
|
+
try {
|
323
|
+
return view.getViewModel();
|
324
|
+
}
|
325
|
+
catch (e){
|
326
|
+
throw Stormfront.Errors.VIEW_MODEL(view.getIdentity());
|
327
|
+
}
|
328
|
+
}
|
329
|
+
try {
|
330
|
+
return expandTemplate(compileTemplate(getTemplate(view)), getViewModel(view));
|
331
|
+
}
|
332
|
+
catch(e) {
|
333
|
+
return e;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
try {
|
337
|
+
return renderTemplate(this.view);
|
338
|
+
}
|
339
|
+
catch(e) {
|
340
|
+
throw new TemplateError(findError(this.view), e.message);
|
341
|
+
}
|
342
|
+
}
|
343
|
+
});
|
344
|
+
|
345
|
+
function TemplateError(message, innerException) {
|
346
|
+
var error = Error.call(this, message);
|
347
|
+
this.name = 'TemplateError';
|
348
|
+
this.message = error.message;
|
349
|
+
this.stack = error.stack;
|
350
|
+
this.innerException = innerException;
|
351
|
+
}
|
352
|
+
|
353
|
+
TemplateError.prototype = Object.create(Error.prototype);
|
354
|
+
TemplateError.prototype.constructor = TemplateError;
|
355
|
+
|
356
|
+
|
357
|
+
Stormfront.Mixin.Dispatch = {
|
358
|
+
hasEvents: function(){
|
359
|
+
return this.trigger;
|
360
|
+
},
|
361
|
+
addEvents: function(){
|
362
|
+
$.extend(this, Backbone.Events);
|
363
|
+
},
|
364
|
+
streamlineDispatch: function(event){
|
365
|
+
this.dispatch = function(){
|
366
|
+
this.trigger('dispatch', event)
|
367
|
+
};
|
368
|
+
this.dispatch(event);
|
369
|
+
},
|
370
|
+
dispatch: function(event){
|
371
|
+
if (!this.hasEvents())
|
372
|
+
this.addEvents();
|
373
|
+
this.streamlineDispatch(event);
|
374
|
+
}
|
375
|
+
};
|
376
|
+
|
377
|
+
Stormfront.Mixin.Other = {
|
378
|
+
unauthorized: function(entity){
|
379
|
+
function propagateUnauthorized(source, response, options){
|
380
|
+
if (response.status === 403)
|
381
|
+
this.trigger('unauthorized', source, response, options);
|
382
|
+
}
|
383
|
+
entity.on('error', propagateUnauthorized);
|
384
|
+
},
|
385
|
+
invalid: function(entity){
|
386
|
+
function propagateInvalid(source, response, options){
|
387
|
+
if (response.status === 400)
|
388
|
+
this.trigger('invalid', source, response, options);
|
389
|
+
}
|
390
|
+
entity.on('error', propagateInvalid);
|
391
|
+
},
|
392
|
+
empty: function(collection){
|
393
|
+
function determineEmpty(collection, response, options){
|
394
|
+
if (collection.isEmpty())
|
395
|
+
this.trigger('empty', collection, response, options);
|
396
|
+
else
|
397
|
+
this.trigger('populated', collection, response, options);
|
398
|
+
}
|
399
|
+
collection.on('sync', determineEmpty);
|
400
|
+
}
|
401
|
+
};
|
402
|
+
|
403
|
+
|
404
|
+
Keys = {
|
405
|
+
Enter: 13,
|
406
|
+
LeftArrow: 37,
|
407
|
+
DownArrow: 40,
|
408
|
+
RightArrow: 39,
|
409
|
+
UpArrow: 38,
|
410
|
+
C: 67,
|
411
|
+
R: 82,
|
412
|
+
M: 77,
|
413
|
+
Tab: 9,
|
414
|
+
Override: 1000,
|
415
|
+
Shift: 2000
|
416
|
+
};
|
417
|
+
|
418
|
+
KeyboardEvents = Stormfront.Class.extend({
|
419
|
+
initialize: function(){
|
420
|
+
_.bindAll(this, 'onKeyDown');
|
421
|
+
_.extend(this, Backbone.Events);
|
422
|
+
$(window).on('keydown', this.onKeyDown);
|
423
|
+
},
|
424
|
+
onKeyDown: function(event){
|
425
|
+
function isInput(node){
|
426
|
+
switch(node){
|
427
|
+
case 'SELECT':
|
428
|
+
return true;
|
429
|
+
case 'TEXTAREA':
|
430
|
+
return true;
|
431
|
+
case 'INPUT':
|
432
|
+
return true;
|
433
|
+
case 'BUTTON':
|
434
|
+
return true;
|
435
|
+
default:
|
436
|
+
return false;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
var shift = event.shiftKey ? Keys.Shift : 0;
|
440
|
+
var override = isInput(document.activeElement.nodeName) ? Keys.Override : 0;
|
441
|
+
this.trigger(shift + override + event.which, event);
|
442
|
+
},
|
443
|
+
enterState: function(bindings){
|
444
|
+
var self = this;
|
445
|
+
this.off();
|
446
|
+
function addBinding(value, key) {
|
447
|
+
self.on(key, value);
|
448
|
+
}
|
449
|
+
_.each(bindings, addBinding);
|
450
|
+
},
|
451
|
+
close: function(){
|
452
|
+
$(window).off('keydown', this.onKeyDown);
|
453
|
+
this.off('all');
|
454
|
+
}
|
455
|
+
});
|
456
|
+
|
457
|
+
MouseEvents = Stormfront.Class.extend({
|
458
|
+
initialize: function(options){
|
459
|
+
options = _.extend({delay: 175}, options);
|
460
|
+
this.delay = options.delay ? options.delay : 175;
|
461
|
+
this.public = _.clone(Backbone.Events);
|
462
|
+
this.internal = _.clone(Backbone.Events);
|
463
|
+
},
|
464
|
+
listen: function(target){
|
465
|
+
this.$el = target;
|
466
|
+
this.$el.global = $(document);
|
467
|
+
this.el = this.$el[0];
|
468
|
+
|
469
|
+
var self = this;
|
470
|
+
function enterStandardEventMode() {
|
471
|
+
self.$el.on('wheel.me', handleMouseWheel);
|
472
|
+
self.$el.on('mousewheel.me', handleMouseWheel);
|
473
|
+
self.$el.one('mousedown.me', handleFirstMouseDown);
|
474
|
+
|
475
|
+
function handleFirstMouseDown(eventArgs) {
|
476
|
+
self.$el.one('mousemove.me', enterDraggingMode);
|
477
|
+
|
478
|
+
self.$el.one('mousedown.me', handleSubsequentMouseDown);
|
479
|
+
self.internal.once("special:single-click:down", function() { handleSpecialMouseDown(eventArgs)});
|
480
|
+
self.$el.global.one('mouseup.me', handleFirstMouseUp);
|
481
|
+
delay("special:single-click:down", eventArgs);
|
482
|
+
}
|
483
|
+
|
484
|
+
function handleFirstMouseUp(eventArgs) {
|
485
|
+
self.$el.off('mousemove.me');
|
486
|
+
self.internal.once("special:single-click:up", function() { handleSpecialMouseUp(eventArgs); });
|
487
|
+
delay("special:single-click:up", eventArgs);
|
488
|
+
}
|
489
|
+
|
490
|
+
function delay(event, eventArgs){
|
491
|
+
setTimeout(function() { publishInternalEvent(event, eventArgs);}, self.delay);
|
492
|
+
}
|
493
|
+
|
494
|
+
function handleSpecialMouseDown(eventArgs) {
|
495
|
+
self.$el.off('mousedown.me');
|
496
|
+
self.$el.one('mousedown.me', handleFirstMouseDown);
|
497
|
+
publishExternalEvent("single-click:down", eventArgs);
|
498
|
+
}
|
499
|
+
|
500
|
+
function handleSpecialMouseUp(eventArgs) {
|
501
|
+
publishExternalEvent("single-click:up", eventArgs);
|
502
|
+
}
|
503
|
+
|
504
|
+
function handleSubsequentMouseDown(eventArgs) {
|
505
|
+
self.internal.off("special:single-click:down");
|
506
|
+
self.$el.one('mousedown.me', handleFirstMouseDown);
|
507
|
+
self.$el.global.one('mouseup.me', handleSubsequentMouseUp);
|
508
|
+
publishExternalEvent("double-click:down", eventArgs);
|
509
|
+
}
|
510
|
+
|
511
|
+
function handleSubsequentMouseUp(eventArgs) {
|
512
|
+
self.internal.off("special:single-click:up");
|
513
|
+
publishExternalEvent("double-click:up", eventArgs);
|
514
|
+
}
|
515
|
+
|
516
|
+
function handleMouseWheel(eventArgs) {
|
517
|
+
publishExternalEvent("mousewheel", eventArgs);
|
518
|
+
}
|
519
|
+
}
|
520
|
+
|
521
|
+
function exitStandardEventMode() {
|
522
|
+
self.$el.off('mousedown.me');
|
523
|
+
self.$el.global.off('mouseup.me');
|
524
|
+
self.$el.off('mousemove.me');
|
525
|
+
self.$el.off('wheel.me');
|
526
|
+
self.$el.off('mousewheel.me');
|
527
|
+
self.internal.off("special:single-click:down");
|
528
|
+
self.internal.off("special:single-click:up");
|
529
|
+
}
|
530
|
+
|
531
|
+
function enterDraggingMode(eventArgs) {
|
532
|
+
function handleMouseMove(eventArgs) {
|
533
|
+
publishExternalEvent("dragging:move", eventArgs);
|
534
|
+
}
|
535
|
+
|
536
|
+
function handleMouseUp(eventArgs) {
|
537
|
+
publishExternalEvent("dragging:end", eventArgs);
|
538
|
+
exitDraggingMode();
|
539
|
+
enterStandardEventMode();
|
540
|
+
}
|
541
|
+
|
542
|
+
exitStandardEventMode();
|
543
|
+
publishExternalEvent("dragging:start", eventArgs);
|
544
|
+
self.$el.global.on('mousemove.me', handleMouseMove);
|
545
|
+
self.$el.global.one('mouseup.me', handleMouseUp);
|
546
|
+
}
|
547
|
+
|
548
|
+
function exitDraggingMode() {
|
549
|
+
self.$el.off('mouseup.me');
|
550
|
+
self.$el.global.off('mousemove.me');
|
551
|
+
self.$el.global.off('mousedown.me');
|
552
|
+
}
|
553
|
+
|
554
|
+
function disableUnsupportedEvents() {
|
555
|
+
self.$el.global.on('selectstart.me', function(eventArgs) {
|
556
|
+
eventArgs.preventDefault();
|
557
|
+
eventArgs.stopPropagation();
|
558
|
+
return false; });
|
559
|
+
self.$el.on("contextmenu.me", function(eventArgs) {
|
560
|
+
eventArgs.preventDefault();
|
561
|
+
eventArgs.stopPropagation();
|
562
|
+
return false; });
|
563
|
+
}
|
564
|
+
|
565
|
+
function publishInternalEvent(event, eventArgs){
|
566
|
+
publishEvent(self.internal, event, eventArgs);
|
567
|
+
}
|
568
|
+
function publishExternalEvent(event, eventArgs){
|
569
|
+
publishEvent(self.public, event, eventArgs);
|
570
|
+
}
|
571
|
+
function publishEvent(publisher, event, eventArgs){
|
572
|
+
function getMousePosition(eventArgs) {
|
573
|
+
var offset = self.$el.offset();
|
574
|
+
var relativeX = eventArgs.originalEvent.pageX - offset.left;
|
575
|
+
var relativeY = eventArgs.originalEvent.pageY - offset.top;
|
576
|
+
eventArgs.preventDefault();
|
577
|
+
eventArgs.stopPropagation();
|
578
|
+
return {
|
579
|
+
x: relativeX,
|
580
|
+
y: relativeY
|
581
|
+
};
|
582
|
+
}
|
583
|
+
var position = getMousePosition(eventArgs);
|
584
|
+
publisher.trigger(event, position, eventArgs.originalEvent);
|
585
|
+
}
|
586
|
+
|
587
|
+
enterStandardEventMode();
|
588
|
+
disableUnsupportedEvents();
|
589
|
+
},
|
590
|
+
on: function(event, callback){
|
591
|
+
this.public.on(event, callback);
|
592
|
+
return this;
|
593
|
+
},
|
594
|
+
off: function(event ,callback){
|
595
|
+
this.public.off(event, callback);
|
596
|
+
return this;
|
597
|
+
},
|
598
|
+
stopListening: function(){
|
599
|
+
this.$el && this.$el.off('.me');
|
600
|
+
this.$el.global && this.$el.global.off('.me');
|
601
|
+
}
|
602
|
+
});
|
603
|
+
|
604
|
+
|
605
|
+
Stormfront.ViewBase = Backbone.View.extend({
|
606
|
+
initialize: function(){
|
607
|
+
this.errors = [];
|
608
|
+
},
|
609
|
+
render: function(){
|
610
|
+
try {
|
611
|
+
this.$el.html(new Stormfront.Template(this).render());
|
612
|
+
}
|
613
|
+
catch(e) {
|
614
|
+
this.handleException(e);
|
615
|
+
}
|
616
|
+
return this;
|
617
|
+
},
|
618
|
+
getViewModel: function(){
|
619
|
+
return this.model ? this.model.toJSON ? this.model.toJSON() : this.model : {};
|
620
|
+
},
|
621
|
+
handleException: function(exception){
|
622
|
+
if (exception.innerException)
|
623
|
+
console.warn(exception.message, exception.innerException);
|
624
|
+
else
|
625
|
+
console.warn(exception.message);
|
626
|
+
|
627
|
+
this.handleError(exception.message);
|
628
|
+
},
|
629
|
+
handleError: function(message){
|
630
|
+
if (_.contains(this.errors, message))
|
631
|
+
return;
|
632
|
+
this.notifyUser(message);
|
633
|
+
},
|
634
|
+
notifyUser: function(message){
|
635
|
+
this.alert && this.alert.close();
|
636
|
+
|
637
|
+
this.errors.push(message);
|
638
|
+
this.alert = new Stormfront.Alert({
|
639
|
+
model: {
|
640
|
+
summary: Stormfront.Errors.FEEDBACK,
|
641
|
+
details: this.errors.join(', ')
|
642
|
+
}
|
643
|
+
});
|
644
|
+
|
645
|
+
this.listenTo(this.alert, 'closing', this.removeNotification);
|
646
|
+
this.$el.append(this.alert.render().$el);
|
647
|
+
},
|
648
|
+
removeNotification: function(){
|
649
|
+
this.errors = [];
|
650
|
+
this.stopListening(this.alert);
|
651
|
+
},
|
652
|
+
getIdentity: function(){
|
653
|
+
return stormfront.string(this.className).firstWord();
|
654
|
+
},
|
655
|
+
toString: function(){
|
656
|
+
return this.getIdentity();
|
657
|
+
},
|
658
|
+
close: function(){
|
659
|
+
this.remove();
|
660
|
+
}
|
661
|
+
});
|
662
|
+
|
663
|
+
Stormfront.View = Stormfront.ViewBase.extend({
|
664
|
+
initialize: function(options){
|
665
|
+
Stormfront.ViewBase.prototype.initialize.call(this, options);
|
666
|
+
this.when = this.when || { };
|
667
|
+
this.addPublisher(this);
|
668
|
+
this.addSubscriber(this.when);
|
669
|
+
this.transition.apply(this, stormfront.arguments(arguments).prepend('initializing').get());
|
670
|
+
},
|
671
|
+
render: function(){
|
672
|
+
Stormfront.ViewBase.prototype.render.call(this);
|
673
|
+
this.transition.apply(this, stormfront.arguments(arguments).prepend('rendering').get());
|
674
|
+
return this;
|
675
|
+
},
|
676
|
+
addPublisher: function(publisher, identity){
|
677
|
+
function notify(event){
|
678
|
+
var args = stormfront.arguments(arguments).skip(1).get();
|
679
|
+
function executeHandler(subscriber){
|
680
|
+
var handler = stormfront.hash(subscriber).findNestedValue(event.split(':'));
|
681
|
+
if (_.isFunction(handler))
|
682
|
+
handler.apply(this, args);
|
683
|
+
}
|
684
|
+
_.each(this._subscribers, executeHandler, this);
|
685
|
+
}
|
686
|
+
function prepend(identity){
|
687
|
+
return function(event){
|
688
|
+
var newEvent = identity + ':' + event;
|
689
|
+
var args = stormfront.arguments(arguments).skip(1).prepend(newEvent).get();
|
690
|
+
notify.apply(this, args);
|
691
|
+
}
|
692
|
+
}
|
693
|
+
if (publisher === this)
|
694
|
+
this.listenTo(publisher, 'transition', notify);
|
695
|
+
else if (this.model && publisher === this.model)
|
696
|
+
this.listenTo(publisher, 'all', prepend('model'));
|
697
|
+
else if (this.collection && publisher === this.collection)
|
698
|
+
this.listenTo(publisher, 'all', prepend('collection'));
|
699
|
+
else if (publisher.className)
|
700
|
+
this.listenTo(publisher, 'transition', prepend(publisher.getIdentity()));
|
701
|
+
else
|
702
|
+
this.listenTo(publisher, 'all', prepend(identity));
|
703
|
+
},
|
704
|
+
addSubscriber: function(whenBlock){
|
705
|
+
this._subscribers = this._subscribers || [];
|
706
|
+
if (whenBlock)
|
707
|
+
this._subscribers.push(whenBlock);
|
708
|
+
},
|
709
|
+
transition: function(){
|
710
|
+
var args = stormfront.arguments(arguments).prepend('transition').get();
|
711
|
+
this.trigger.apply(this, args);
|
712
|
+
},
|
713
|
+
close: function(){
|
714
|
+
this.transition.apply(this, stormfront.arguments(arguments).prepend('closing').get());
|
715
|
+
Stormfront.ViewBase.prototype.close.call(this);
|
716
|
+
}
|
717
|
+
});
|
718
|
+
|
719
|
+
Stormfront.Errors = {
|
720
|
+
FEEDBACK: 'An unexpected error was encountered',
|
721
|
+
/** @return {string} */
|
722
|
+
NO_SELECTOR: function() { return 'A template selector was not provided for your view' },
|
723
|
+
/** @return {string} */
|
724
|
+
NO_TEMPLATE: function(name) { return name +'\'s template was not found'; },
|
725
|
+
/** @return {string} */
|
726
|
+
INCOMPATIBLE_TEMPLATE: function(name) { return name +'\'s template and view model for your view are not compatible'; },
|
727
|
+
/** @return {string} */
|
728
|
+
VIEW_MODEL: function(name) { return name + '\'s view model for the child generated an error'; },
|
729
|
+
/** @return {string} */
|
730
|
+
NO_LOCATION: function(name) { return name + ' has no locations available to render'; },
|
731
|
+
/** @return {string} */
|
732
|
+
MULTIPLE_LOCATIONS: function(name) { return name + ' has multiple locations available to render'; },
|
733
|
+
/** @return {string} */
|
734
|
+
INITIALIZING: function(name) { return name + ' failed to initialize'; },
|
735
|
+
/** @return {string} */
|
736
|
+
RENDERING: function(name) { return name + ' failed to render'; },
|
737
|
+
/** @return {string} */
|
738
|
+
ATTACHING: function(name) { return name + ' failed to attach'; },
|
739
|
+
/** @return {string} */
|
740
|
+
CLOSING: function(name) { return name + ' failed to close'; },
|
741
|
+
/** @return {string} */
|
742
|
+
ADDING: function(name) { return name + ' failed to add'; }
|
743
|
+
};
|
744
|
+
|
745
|
+
//TODO: This whole class depends on Bootstrap
|
746
|
+
Stormfront.Alert = Stormfront.View.extend({
|
747
|
+
className: 'alert',
|
748
|
+
when: {
|
749
|
+
rendering: function(){
|
750
|
+
this.$el.attr('role', 'alert').
|
751
|
+
addClass('alert-warning').
|
752
|
+
addClass('alert-dismissible');
|
753
|
+
|
754
|
+
var self = this;
|
755
|
+
this.$el.on('closed.bs.alert', function(){
|
756
|
+
self.trigger('closing');
|
757
|
+
self.close();
|
758
|
+
});
|
759
|
+
}
|
760
|
+
}
|
761
|
+
});
|
762
|
+
|
763
|
+
Stormfront.Container = Stormfront.View.extend({
|
764
|
+
reducers: [],
|
765
|
+
store: null,
|
766
|
+
root: null,
|
767
|
+
when: {
|
768
|
+
initializing: function(){
|
769
|
+
this._reducers = _.map(this.reducers, this.createReducer, this);
|
770
|
+
},
|
771
|
+
rendering: function(){
|
772
|
+
this.store = new this.store();
|
773
|
+
this.root = new this.root({model: this.store});
|
774
|
+
this.listenToDispatches(this.root);
|
775
|
+
this.$el.append(this.root.render().$el);
|
776
|
+
}
|
777
|
+
},
|
778
|
+
createReducer: function(interaction){
|
779
|
+
var useCase = new interaction();
|
780
|
+
this.listenToDispatches(useCase);
|
781
|
+
return this.addReducer(useCase);
|
782
|
+
},
|
783
|
+
addReducer: function(useCase){
|
784
|
+
this._reducers[useCase.type] = useCase;
|
785
|
+
return useCase;
|
786
|
+
},
|
787
|
+
executeUseCase: function(event){
|
788
|
+
this._reducers[event.type].execute(this.store, event);
|
789
|
+
},
|
790
|
+
listenToDispatches: function(publisher){
|
791
|
+
this.listenTo(publisher, 'dispatch', this.executeUseCase);
|
792
|
+
}
|
793
|
+
});
|
794
|
+
|
795
|
+
Stormfront.Entity = Stormfront.View.extend({
|
796
|
+
exceptions: {
|
797
|
+
model: {
|
798
|
+
error: function(collection, xhr){
|
799
|
+
var response = new Stormfront.Response(xhr);
|
800
|
+
if (response.isActionable()) {
|
801
|
+
this.handleException({error: response.getError()});
|
802
|
+
response.markAsHandled();
|
803
|
+
}
|
804
|
+
},
|
805
|
+
invalid: function(model, error){
|
806
|
+
this.handleException({error: error});
|
807
|
+
}
|
808
|
+
}
|
809
|
+
},
|
810
|
+
overlays: {
|
811
|
+
model: {
|
812
|
+
request: function(){
|
813
|
+
this.addOverlay();
|
814
|
+
},
|
815
|
+
sync: function(){
|
816
|
+
this.removeOverlay();
|
817
|
+
},
|
818
|
+
error: function(){
|
819
|
+
this.removeOverlay();
|
820
|
+
}
|
821
|
+
}
|
822
|
+
},
|
823
|
+
change: {
|
824
|
+
model: {
|
825
|
+
change: function(){
|
826
|
+
this.render();
|
827
|
+
}
|
828
|
+
}
|
829
|
+
},
|
830
|
+
initialize: function(){
|
831
|
+
this.addSubscriber(this.overlays);
|
832
|
+
this.addSubscriber(this.exceptions);
|
833
|
+
this.addSubscriber(this.change);
|
834
|
+
this.addPublisher(this.model);
|
835
|
+
Stormfront.View.prototype.initialize.apply(this, arguments);
|
836
|
+
},
|
837
|
+
addOverlay: function(){
|
838
|
+
this.removeOverlay();
|
839
|
+
this.overlay = new Stormfront.Overlay({selector: this.$el});
|
840
|
+
},
|
841
|
+
removeOverlay: function(){
|
842
|
+
if (this.overlay) {
|
843
|
+
this.overlay.close();
|
844
|
+
this.overlay = null;
|
845
|
+
}
|
846
|
+
}
|
847
|
+
});
|
848
|
+
|
849
|
+
Stormfront.Layout = Stormfront.View.extend({
|
850
|
+
base: {
|
851
|
+
initializing: function(){
|
852
|
+
this._children = new Stormfront.Chaperone();
|
853
|
+
this.addPublisher(this._children, 'child');
|
854
|
+
},
|
855
|
+
rendering: function(){
|
856
|
+
_.each(this.children, this.composeChild, this);
|
857
|
+
},
|
858
|
+
closing: function(){
|
859
|
+
this._children.close();
|
860
|
+
},
|
861
|
+
child: {
|
862
|
+
created: function(child){
|
863
|
+
this._children.add(child);
|
864
|
+
},
|
865
|
+
added: function(child){
|
866
|
+
this.addPublisher(child);
|
867
|
+
this._children.render(child);
|
868
|
+
},
|
869
|
+
rendered: function(child){
|
870
|
+
var location = this.$('.' + child.getIdentity());
|
871
|
+
this._children.attach(child, location, 'replaceWith');
|
872
|
+
},
|
873
|
+
attached: function(child){
|
874
|
+
child.transition('rendered', child);
|
875
|
+
},
|
876
|
+
removed: function(child){
|
877
|
+
child.close();
|
878
|
+
this.stopListening(child);
|
879
|
+
},
|
880
|
+
error: function(error, innerException){
|
881
|
+
this.handleException(
|
882
|
+
new LayoutError(error, innerException)
|
883
|
+
);
|
884
|
+
}
|
885
|
+
}
|
886
|
+
},
|
887
|
+
initialize: function(){
|
888
|
+
this.addSubscriber(this.base);
|
889
|
+
Stormfront.View.prototype.initialize.apply(this, arguments);
|
890
|
+
},
|
891
|
+
composeChild: function(childOptions, childClass){
|
892
|
+
this._children.create(childClass, childOptions, this);
|
893
|
+
},
|
894
|
+
findChild: function(identity){
|
895
|
+
return this._children.find(identity);
|
896
|
+
}
|
897
|
+
});
|
898
|
+
|
899
|
+
function LayoutError(message, innerException) {
|
900
|
+
var error = Error(message);
|
901
|
+
this.name = 'LayoutError';
|
902
|
+
this.message = error.message;
|
903
|
+
this.stack = error.stack;
|
904
|
+
this.innerException = innerException;
|
905
|
+
}
|
906
|
+
|
907
|
+
LayoutError.prototype = Object.create(Error.prototype);
|
908
|
+
LayoutError.prototype.constructor = LayoutError;
|
909
|
+
|
910
|
+
Stormfront.Overlay = Stormfront.Class.extend({
|
911
|
+
initialize: function(options){
|
912
|
+
var selector = options.selector;
|
913
|
+
|
914
|
+
if (!selector)
|
915
|
+
this.overlay = new Stormfront.FullScreenOverlay({model: options});
|
916
|
+
else if (options.saveRequest)
|
917
|
+
this.overlay = new Stormfront.InlineOverlay();
|
918
|
+
else
|
919
|
+
this.overlay = new Stormfront.AnonymousOverlay();
|
920
|
+
|
921
|
+
selector = selector ? selector : document.body;
|
922
|
+
this.location = selector.size ? selector : $(selector);
|
923
|
+
this.render();
|
924
|
+
},
|
925
|
+
render: function(){
|
926
|
+
this.location.append(this.overlay.render().$el);
|
927
|
+
this.overlay.transition('attached');
|
928
|
+
return this;
|
929
|
+
},
|
930
|
+
close: function(){
|
931
|
+
this.overlay.close();
|
932
|
+
this.location = null;
|
933
|
+
},
|
934
|
+
error: function(){
|
935
|
+
this.overlay.error.apply(this.overlay, arguments);
|
936
|
+
}
|
937
|
+
});
|
938
|
+
|
939
|
+
Stormfront.OverlayBase = Stormfront.View.extend({
|
940
|
+
className: 'overlay',
|
941
|
+
activated: false,
|
942
|
+
PAUSE_DURATION: 0,
|
943
|
+
MINIMUM_DURATION: 0,
|
944
|
+
base_css: {
|
945
|
+
overlay_background: {
|
946
|
+
top: '0px', left: '0px',
|
947
|
+
width: '100%', height: '100%'
|
948
|
+
},
|
949
|
+
overlay_panel: {
|
950
|
+
position: 'absolute',
|
951
|
+
top: '50%', left: '50%'
|
952
|
+
}
|
953
|
+
},
|
954
|
+
base: {
|
955
|
+
rendering: function(){
|
956
|
+
function applyCss(value, key){
|
957
|
+
var selector = '.' + key;
|
958
|
+
this.$(selector).css(value);
|
959
|
+
}
|
960
|
+
this.startTime = stormfront.time().now();
|
961
|
+
_.each(this.base_css, applyCss, this);
|
962
|
+
_.each(this.css, applyCss, this);
|
963
|
+
this.$el.css({opacity: '0', 'pointer-events': 'none'});
|
964
|
+
},
|
965
|
+
attached: function(){
|
966
|
+
var self = this;
|
967
|
+
function activate(){
|
968
|
+
self.$el.css({opacity: '1', 'pointer-events': 'auto'});
|
969
|
+
self.activated = true;
|
970
|
+
}
|
971
|
+
function setDimensions(panel){
|
972
|
+
var content = self.$('.content');
|
973
|
+
var position = {
|
974
|
+
'margin-left': - content.outerWidth() / 2,
|
975
|
+
'margin-top': - content.outerHeight() / 2
|
976
|
+
};
|
977
|
+
panel.css(position);
|
978
|
+
}
|
979
|
+
setDimensions(this.$('.overlay_panel'));
|
980
|
+
if (this.PAUSE_DURATION)
|
981
|
+
setTimeout(activate, this.PAUSE_DURATION);
|
982
|
+
else
|
983
|
+
activate();
|
984
|
+
},
|
985
|
+
closing: function(){
|
986
|
+
var self = this;
|
987
|
+
function remove(){
|
988
|
+
self.remove();
|
989
|
+
}
|
990
|
+
if (!this.activated)
|
991
|
+
this.remove();
|
992
|
+
|
993
|
+
var currentDuration = stormfront.time().now() - this.startTime;
|
994
|
+
var remainingDuration = this.MINIMUM_DURATION - currentDuration;
|
995
|
+
if (remainingDuration > 0)
|
996
|
+
setTimeout(remove, remainingDuration);
|
997
|
+
else
|
998
|
+
this.remove();
|
999
|
+
}
|
1000
|
+
},
|
1001
|
+
initialize: function(){
|
1002
|
+
this.addSubscriber(this.base);
|
1003
|
+
Stormfront.View.prototype.initialize.apply(this, arguments);
|
1004
|
+
},
|
1005
|
+
error: function(){
|
1006
|
+
this.remove();
|
1007
|
+
},
|
1008
|
+
close: function(){
|
1009
|
+
this.transition.apply(this, stormfront.arguments(arguments).prepend('closing').get());
|
1010
|
+
}
|
1011
|
+
});
|
1012
|
+
|
1013
|
+
Stormfront.FullScreenOverlay = Stormfront.OverlayBase.extend({
|
1014
|
+
MINIMUM_DURATION: 900,
|
1015
|
+
css: {
|
1016
|
+
overlay_background: {
|
1017
|
+
position: 'fixed',
|
1018
|
+
'z-index': '100000'
|
1019
|
+
},
|
1020
|
+
overlay_panel: {
|
1021
|
+
'z-index': '100001'
|
1022
|
+
}
|
1023
|
+
},
|
1024
|
+
when: {
|
1025
|
+
rendering: function(){
|
1026
|
+
this.$el.addClass('blocking');
|
1027
|
+
}
|
1028
|
+
}
|
1029
|
+
});
|
1030
|
+
|
1031
|
+
Stormfront.AnonymousOverlay = Stormfront.OverlayBase.extend({
|
1032
|
+
PAUSE_DURATION: 200,
|
1033
|
+
MINIMUM_DURATION: 450,
|
1034
|
+
css: {
|
1035
|
+
overlay_background: {
|
1036
|
+
position: 'absolute',
|
1037
|
+
'z-index': 'auto'
|
1038
|
+
},
|
1039
|
+
overlay_panel: {
|
1040
|
+
'z-index': 'auto'
|
1041
|
+
}
|
1042
|
+
},
|
1043
|
+
when: {
|
1044
|
+
rendering: function(){
|
1045
|
+
this.$el.addClass('anonymous');
|
1046
|
+
}
|
1047
|
+
}
|
1048
|
+
});
|
1049
|
+
|
1050
|
+
Stormfront.InlineOverlay = Stormfront.OverlayBase.extend({
|
1051
|
+
className: 'input_overlay',
|
1052
|
+
MINIMUM_DURATION: 1500,
|
1053
|
+
MAXIMUM_WIDTH: 1200,
|
1054
|
+
base_css: {
|
1055
|
+
input: {
|
1056
|
+
position: 'absolute',
|
1057
|
+
top: '2px',
|
1058
|
+
right: '10px',
|
1059
|
+
width:'16px',
|
1060
|
+
'z-index':'10000'
|
1061
|
+
}
|
1062
|
+
},
|
1063
|
+
when: {
|
1064
|
+
rendering: function () {
|
1065
|
+
this.$el.find('.error').hide();
|
1066
|
+
this.$el.find('.confirm').hide();
|
1067
|
+
},
|
1068
|
+
closing: function(){
|
1069
|
+
this.$el.find('.spinner').hide();
|
1070
|
+
this.$el.find('.confirm').show();
|
1071
|
+
}
|
1072
|
+
},
|
1073
|
+
error: function (xhr) {
|
1074
|
+
//TODO: Elevate this code up a level to the Request
|
1075
|
+
try {
|
1076
|
+
var response = JSON.parse(xhr.responseText);
|
1077
|
+
var error = response.error || response.message;
|
1078
|
+
this.$el.find('.spinner').hide();
|
1079
|
+
this.$el.find('.error').show().attr('title', error);
|
1080
|
+
xhr.handled = true;
|
1081
|
+
}
|
1082
|
+
catch (e) {
|
1083
|
+
console.warn('Could not parse error', arguments);
|
1084
|
+
this.remove();
|
1085
|
+
}
|
1086
|
+
}
|
1087
|
+
});
|
1088
|
+
|
1089
|
+
Stormfront.Reducer = Stormfront.Class.extend({
|
1090
|
+
type: Stormfront.Errors.NOT_IMPLEMENTED,
|
1091
|
+
initialize: function(){
|
1092
|
+
_.extend(this, Stormfront.Mixin.Dispatch);
|
1093
|
+
},
|
1094
|
+
execute: function(model, event){
|
1095
|
+
throw Stormfront.Errors.UseCases.NOT_IMPLEMENTED;
|
1096
|
+
}
|
1097
|
+
});
|
1098
|
+
|
1099
|
+
Stormfront.Request = function(model, request, options){
|
1100
|
+
var startTime = stormfront.time.now();
|
1101
|
+
var overlay = new Stormfront.Overlay(options);
|
1102
|
+
function tryRequest(){
|
1103
|
+
return shouldWait() ? delayRequest() : sendRequest();
|
1104
|
+
}
|
1105
|
+
function shouldWait(){
|
1106
|
+
//TODO: This is a dependency upon the Indigo behavior
|
1107
|
+
return options.wait && $.xhrPool.length > 0;
|
1108
|
+
}
|
1109
|
+
function delayRequest(){
|
1110
|
+
if (stormfront.time.now() - startTime < 5000)
|
1111
|
+
setTimeout(tryRequest, 1000);
|
1112
|
+
else
|
1113
|
+
overlay.error('Request timed out. Please try again soon.');
|
1114
|
+
return null;
|
1115
|
+
}
|
1116
|
+
function sendRequest(){
|
1117
|
+
function onComplete(){
|
1118
|
+
removeListeners();
|
1119
|
+
overlay.close();
|
1120
|
+
}
|
1121
|
+
function onError(model, xhr){
|
1122
|
+
removeListeners();
|
1123
|
+
overlay.error(xhr);
|
1124
|
+
}
|
1125
|
+
function removeListeners(){
|
1126
|
+
model.off('error', onError);
|
1127
|
+
model.off('sync', onComplete);
|
1128
|
+
model.off('invalid', onComplete);
|
1129
|
+
}
|
1130
|
+
model.once('invalid', onError);
|
1131
|
+
model.once('error', onError);
|
1132
|
+
model.once('sync', onComplete);
|
1133
|
+
|
1134
|
+
return request.call(model, options.args, options.options);
|
1135
|
+
}
|
1136
|
+
return tryRequest();
|
1137
|
+
};
|