Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_invitations_view.js @ 33299f73

History | View | Annotate | Download (15.5 kB)

1
// Copyright 2011 GRNET S.A. All rights reserved.
2
// 
3
// Redistribution and use in source and binary forms, with or
4
// without modification, are permitted provided that the following
5
// conditions are met:
6
// 
7
//   1. Redistributions of source code must retain the above
8
//      copyright notice, this list of conditions and the following
9
//      disclaimer.
10
// 
11
//   2. Redistributions in binary form must reproduce the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer in the documentation and/or other materials
14
//      provided with the distribution.
15
// 
16
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
// POSSIBILITY OF SUCH DAMAGE.
28
// 
29
// The views and conclusions contained in the software and
30
// documentation are those of the authors and should not be
31
// interpreted as representing official policies, either expressed
32
// or implied, of GRNET S.A.
33
// 
34

    
35
;(function(root){
36

    
37
    // root
38
    var root = root;
39
    
40
    // setup namepsaces
41
    var snf = root.synnefo = root.synnefo || {};
42
    var api = snf.api = snf.api || {};
43
    var models = snf.models = snf.models || {}
44
    var storage = snf.storage = snf.storage || {};
45
    var ui = snf.ui = snf.ui || {};
46
    var util = snf.util = snf.util || {};
47

    
48
    var views = snf.views = snf.views || {}
49

    
50
    // shortcuts
51
    var bb = root.Backbone;
52

    
53
    views.InvitationsView = views.Overlay.extend({
54
        
55
        view_id: "invitations_view",
56
        content_selector: "#invitations-overlay-content",
57
        css_class: 'overlay-invitations overlay-info',
58
        overlay_id: "invitations-overlay",
59

    
60
        subtitle: "",
61
        title: "Invite friends",
62

    
63
        initialize: function(options) {
64
            views.InvitationsView.__super__.initialize.apply(this, arguments);
65

    
66
            _.bindAll(this);
67

    
68
            this.entry_tpl = this.$(".form-entry-tpl");
69
            this.form_entries = this.$(".form-entries");
70
            this.add = this.$(".add-new-invitation");
71
            this.remove = this.$(".remove-invitation");
72
            this.send = this.$(".send-invitations");
73
            this.top_info = this.$(".top-info");
74
            this.sent = this.$(".invitations-sent-cont");
75
            this.sent_pages = this.$(".invitations-sent-pages");
76
            this.sent_tpl = this.$(".invitation-sent-tpl");
77
            this.entry_tpl.hide();
78

    
79
            this.inv_sent_per_page = 9;
80

    
81
            this.init_handlers();
82

    
83
            this.invitations_retrieved = false;
84
            this.loading_invitations = this.$(".loading-invitations");
85
        },
86

    
87
        init_handlers: function() {
88
            var self = this;
89
            this.add.click(function(){
90
                self.add_new_entry().find("input.name").focus();
91
            });
92
            this.send.click(this.send_entries);
93
            this.remove.live('click', function() {
94
                return self.remove_entry($(this).parent().parent());
95
            });
96

    
97
        },
98
        
99
        remove_entry: function(entry) {
100
            if (entry.hasClass("sending")) { return };
101
            entry.remove();
102
            this.fix_entries();
103
        },
104

    
105
        add_new_entry: function() {
106
            var new_entry = this.create_form_entry().show()
107

    
108
            var name = "inv-entry-" + this.get_entries().length;
109
            new_entry.find("input.name").attr("name", "name-" + name);
110
            new_entry.find("input.email").attr("name", "email-" + name);
111
            
112
            var self = this;
113
            new_entry.find("input").bind("keydown", function(e){
114
                e.keyCode = e.keyCode || e.which;
115
                if (e.keyCode == 13) { self.send_entries() };
116
            })
117

    
118
            this.form_entries.append(new_entry).show();
119
            this.fix_entries();
120
            return new_entry;
121
        },
122
        
123
        show_entry_error: function(entry, error) {
124
            entry.find(".send-error").text(error)
125
            entry.find(".send-error").show();
126
            entry.addClass("error");
127
            entry.find("input").attr("disabled", false);
128
        },
129
        
130
        get_entry_data: function(entry) {
131
            var data = {name: entry.find("input.name").val(), email:entry.find("input.email").val()};
132
            return data;
133
        },
134

    
135
        entry_is_valid: function(entry) {
136
            var data = this.get_entry_data(entry);
137

    
138
            if (data.name == "" && data.email == "") {
139
                return false;
140
            }
141

    
142
            entry.find(".send-error").hide();
143
            entry.removeClass("error");
144
            entry.find("input").removeClass("has-errors");
145

    
146
            error = false;
147
            if (!data.name || data.name.split(" ").length == 1) {
148
                error = "Invalid name";
149
                entry.find("input.name").addClass("has-errors");
150
                entry.find("input.name").focus();
151
            }
152

    
153
            var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
154
            if (!data.email || reg.test(data.email) == false) {
155
                error = "Invalid email";
156
                entry.find("input.email").addClass("has-errors");
157
                entry.find("input.email").focus();
158
            }
159
            
160
            if (error) { this.show_entry_error(entry, error) };
161
            return error
162
        },
163
        
164
        send_entries: function() {
165
            var self = this;
166
            this.form_entries.find(".form-entry").each(function(index, el) { self.entry_is_valid($(el)) });
167
            var entries_to_send = this.form_entries.find(".form-entry:not(.error):not(.sending)");
168

    
169
            entries = _.filter(entries_to_send, function(e){
170
                var data = self.get_entry_data($(e));
171
                if (data.name == "" && data.email == "") {
172
                    return false;
173
                }
174
                return true;
175
            })
176
            this._send_entries(entries);
177
        },
178

    
179
        _send_entries: function(entries) {
180
            $(entries).addClass("sending").find("input").attr("disabled", true);
181
            var self = this;
182
            _.each(entries, function(e) {
183
                var e = $(e);
184
                var data = self.get_entry_data(e);
185
                self.send_invitation(data.name, 
186
                                     data.email,
187
                                     _.bind(self.invitation_send, this, e), 
188
                                     _.bind(self.invitation_failed, this, e));
189
            });
190
        },
191

    
192
        invitation_send: function(entry, data) {
193
            entry.removeClass("sending");
194
            if (data.errors && data.errors.length > 0) {
195
                this.show_entry_error($(entry), data.errors[0].msg);
196
                return;
197
            } else {
198
                entry.remove();
199
                this.show_send_success(entry.find("input.name").val(), data);
200
            }
201
        },
202

    
203
        show_send_success: function(to, data) {
204
            var msg = 'Invitation to <span class="email">' + to + '</span> was sent.';
205
            var msg_el = $('<div class="msg">{0}</div>'.format(msg));
206

    
207
            this.top_info.append(msg_el);
208

    
209
            window.setTimeout(function(){
210
                msg_el.fadeOut(600, function(){$(this).remove()});
211
            }, 5000);
212

    
213
            this.fix_entries();
214
            this.reset_invitations_sent();
215
        },
216

    
217
        invitation_failed: function(entry) {
218
            entry.removeClass("sending");
219
            this.show_entry_error(entry, "Cannot send email, please try again later");
220
        },
221

    
222
        send_invitation: function(name, email, success, fail) {
223
            var url = snf.config.invitations_url;
224
            var payload = {name_1: name, email_1: email, csrftoken: $.cookie('csrftoken')};
225
            params = {
226
                success: success,
227
                error: fail,
228
                url: url,
229
                data: $.param(payload),
230
                skip_api_error: true
231
            }
232
            snf.api.sync("create", undefined, params);
233
        },
234

    
235
        get_entries: function() {
236
            return this.form_entries.find(".form-entry");
237
        },
238

    
239
        fix_entries: function() {
240
            this.$(".remove-invitation").hide();
241
            if (this.get_entries().length == 0) {
242
                this.add_new_entry();
243
                this.add_new_entry();
244
            }
245

    
246
            if (this.get_entries().length > 1) {
247
                this.$(".remove-invitation").show();
248
            }
249
            this.$(".form-entry:first-child label").show();
250
            this.$(".form-entry:not(:first-child) label").hide();
251
        },
252
        
253
        show: function() {
254
            views.InvitationsView.__super__.show.apply(this, arguments);
255
            this.current_page = 0;
256
            this.reset_sent();
257
            this.reset();
258

    
259
            this.add_new_entry();
260
            this.add_new_entry();
261

    
262
            if (this.invitations_retrieved) {
263
                this.loading_invitations.hide();
264
            }
265
        },
266

    
267
        reset_sent: function() {
268
            this.reset_invitations_sent();
269
            this.add_invitations_sent([]);
270
        },
271

    
272
        create_form_entry: function() {
273
            return this.entry_tpl.clone().removeClass("form-entry-tpl").addClass("form-entry").removeClass("hidden");
274
        },
275
            
276
        reset: function() {
277
            this.get_entries().remove();
278
            this.add_new_entry();
279
        },
280
        
281
        new_invitation_sent_el: function() {
282
            return this.sent_tpl.clone().removeClass("invitation-sent-tpl").addClass("invitation-sent");
283
        },
284
        
285
        show_invitations_sent_error: function() {
286
            this.sent.hide();
287
            this.$(".invitations-sent-error").show();
288
        },
289

    
290
        reset_invitations_sent: function() {
291
            var self = this;
292
            var url = snf.config.invitations_url;
293
            params = {
294
                success: function(data) {
295
                    self.invitations_retrieved = true;
296
                    self.loading_invitations.hide();
297

    
298
                    if (!data || !data.invitations) {
299
                        self.show_invitations_sent_error();
300
                    } else {
301
                        self.sent.empty();
302
                        self.add_invitations_sent(data.invitations);
303
                    }
304
                    
305
                    //data.invitations_left = 0;
306
                    self.$(".description .left").text(data.invitations_left);
307
                    if(data.invitations_left > 0) {
308
                        self.$(".invitations-form").show();
309
                        self.$(".description .left").removeClass("none");
310
                        self.el.removeClass("none-left");
311
                    } else {
312
                        self.$(".invitations-form").hide();
313
                        self.$(".description .left").addClass("none");
314
                        self.el.addClass("none-left");
315
                    }
316
                },
317
                error: _.bind(this.show_invitations_sent_error, this),
318
                url: url,
319
                skip_api_error: true
320
            }
321

    
322
            snf.api.sync("read", undefined, params);
323
        },
324
        
325
        resend_succeed: function(inv, el) {
326
            el.find(".status.sent").removeClass("hidden").hide();
327
            el.find(".status.resend").removeClass("hidden").show();
328
            el.find(".status.sending").removeClass("hidden").hide();
329

    
330
            var msg = $('<div class="msg success">Invitation has been resent to <span class="email">{0}</span>.</div>'.format(inv.target));
331
            this.$(".resent-info").append(msg);
332
            setTimeout(function(){ $(msg).fadeOut(600)}, 5000);
333
        },
334

    
335
        resend_failed: function(inv, el) {
336
            el.find(".status.sent").removeClass("hidden").hide();
337
            el.find(".status.resend").removeClass("hidden").show();
338
            el.find(".status.sending").removeClass("hidden").hide();
339
            
340
            var msg = $('<div class="msg err-msg">Resend to <span class="email">{0}</span> failed.</div>'.format(inv.target));
341
            this.$(".resent-info").append(msg);
342
            setTimeout(function(){ $(msg).fadeOut(600)}, 5000);
343
        },
344

    
345
        resend_invitation: function(id, el, inv) {
346
            var self = this;
347
            var inv = inv;
348
            var id = id;
349
            var el = el;
350

    
351
            el.find(".status.sent").removeClass("hidden").hide();
352
            el.find(".status.resend").removeClass("hidden").hide();
353
            el.find(".status.sending").removeClass("hidden").show();
354

    
355
            var url = snf.config.invitations_url + "/resend/";
356
            var payload = "invid=" + id;
357
            params = {
358
                success: function(data) {
359
                    self.resend_succeed(inv, el);
360
                },
361
                error: function() {
362
                    self.resend_failed(inv, el);
363
                },
364
                data: payload,
365
                url: url,
366
                skip_api_error: true
367
            }
368

    
369
            snf.api.sync("create", undefined, params);
370
        },
371

    
372
        add_invitations_sent: function(invs) {
373
            var self = this;
374
            _.each(invs, _.bind(function(inv) {
375
                var el = this.new_invitation_sent_el();
376
                var invitation = inv;
377

    
378
                el.find(".name").text(inv.targetname);
379
                el.find(".email").text(inv.target);
380
                
381
                el.find(".status.sent").removeClass("hidden").show();
382
                el.find(".status.resend").removeClass("hidden").hide();
383
                el.find(".status.sending").removeClass("hidden").hide();
384

    
385
                if (!inv.accepted) {
386
                    el.find(".status.resend").show();
387
                    el.find(".status.sent").hide();
388
                    el.find(".status.sending").hide();
389
                }
390

    
391
                el.find(".status.resend").click(function(){
392
                    self.resend_invitation(invitation.id, el, invitation);
393
                })
394

    
395
                el.removeClass("hidden");
396
                this.sent.append(el);
397
            }, this));
398
            this.update_pagination();
399
            this.sent_pages.trigger("setPage", this.current_page || 0);
400
        },
401

    
402
        onOpen: function() {
403
            views.InvitationsView.__super__.onOpen.apply(this, arguments);
404
            setTimeout(function(){$(this.$("input.name:visible").get(0)).focus()}, 100);
405
        },
406
        
407
        inv_sent_per_page: 5,
408
        update_pagination: function() {
409
            this.sent.css({minHeight:this.inv_sent_per_page * 35 + "px"})
410
            this.sent_pages.pagination(this.sent.children().length, 
411
                                       {items_per_page:this.inv_sent_per_page, callback: this.page_cb});
412
        },
413

    
414
        page_cb: function(index, pager) {
415
            this.current_page = index;
416
            var start = index * this.inv_sent_per_page;
417
            var end = start + this.inv_sent_per_page -1;
418
            var items = this.sent.children();
419
            items.hide().removeClass("last");
420
            for (var i = start; i<=end; i++) {
421
                $(items.get(i)).show();
422
            }
423
            $(items.get(end)).addClass("last");
424
            return false;
425
        }
426
        
427
    });
428
})(this);
429