Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_networks_view.js @ 126a01f2

History | View | Annotate | Download (41.4 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 models = snf.models = snf.models || {}
43
    var storage = snf.storage = snf.storage || {};
44
    var ui = snf.ui = snf.ui || {};
45
    var util = snf.util || {};
46
    var views = snf.views = snf.views || {}
47

    
48
    // shortcuts
49
    var bb = root.Backbone;
50
    
51
    // logging
52
    var logger = new snf.logging.logger("SNF-VIEWS");
53
    var debug = _.bind(logger.debug, logger);
54
    
55
    
56
    views.NetworkConnectVMsOverlay = views.Overlay.extend({
57
        title: "Connect machine",
58
        overlay_id: "overlay-select-vms",
59
        content_selector: "#network-vms-select-content",
60
        css_class: "overlay-info",
61

    
62
        initialize: function() {
63
            views.NetworkConnectVMsOverlay.__super__.initialize.apply(this);
64
            this.list = this.$(".vms-list ul");
65
            this.empty_message = this.$(".empty-message");
66

    
67
            // flag for submit handler to avoid duplicate bindings
68
            this.submit_handler_set = false;
69
        },
70
        
71
        init_handlers: function() {
72
            var self = this;
73
            this.list.find("li").click(function(){
74
                $(this).toggleClass("selected");
75
            });
76
            
77
            if (!this.submit_handler_set) {
78
                // avoid duplicate submits
79
                this.el.find(".create").click(_.bind(function() {
80
                    this.submit();
81
                }, this));
82
                this.submit_handler_set = true;
83
            }
84
        },
85

    
86
        reset: function() {
87
            this.list.find("li").remove();
88
        },
89

    
90
        beforeOpen: function() {
91
            this.reset();
92
            this.update_layout();
93
        },
94
        
95
        vm: function(vm) {
96
            if (vm.id) { var id = vm.id } else {var id = vm}
97
            return this.list.find(".vm-" + id);
98
        },
99

    
100
        get_selected: function() {
101
            return this.list.find(".selected").map(function() {return $(this).data('vm')})
102
        },
103

    
104
        update_layout: function() {
105
            if (this.vms.length == 0) {
106
                this.empty_message.show();
107
            } else {
108
                this.empty_message.hide();
109
            }
110

    
111
            _.each(this.vms, _.bind(function(vm){
112
                
113
                var html = '<li class="vm option options-object vm-{0}">' +
114
                           '<div class="options-object-cont">' +
115
                           '{2}' + 
116
                           '<span class="title">{1}</span>' + 
117
                           '<span class="value">{3}</span></div>' + 
118
                           '</li>';
119
                var el = $(html.format(vm.id, 
120
                                       util.truncate(_.escape(vm.get("name")), 23), 
121
                                       snf.ui.helpers.vm_icon_tag(vm, "small", {'class':'os'}),
122
                                       _.escape(vm.get_os())
123
                                      ))
124
                el.data({vm:vm, vm_id:vm.id})
125
                this.list.append(el);
126

    
127
                vm.bind("remove", function(){ el.remove()})
128
                vm.bind("change:name", function(i,v){el.find(".title").text(v)})
129
            }, this));
130
            
131
            this.init_handlers();
132
            this.set_selected();
133
        },
134

    
135
        set_selected: function() {
136
            _.each(this.selected, _.bind(function(el){
137
                this.vm(el).addClass("selected");
138
            }, this));
139
        },
140

    
141
        show_vms: function(network, vms, selected, callback) {
142
            this.network = network;
143
            this.reset();
144
            this.set_subtitle(network.escape("name"));
145
            this.vms = vms;
146
            if (!synnefo.config.network_allow_duplicate_vm_nics) {
147
                this.vms = _.filter(this.vms, function(vm) {
148
                    return !vm.connected_to(this.network);
149
                }, this);
150
            }
151

    
152
            this.selected = selected;
153
            this.cb = callback;
154
            this.show();
155
        },
156

    
157
        submit: function() {
158
            this.cb(this.get_selected());
159
        }
160
    })
161

    
162
    views.NetworkActionsView = views.View.extend({
163
        
164
        initialize: function(view, net, el, opts) {
165
            this.parent = view
166
            this.network = net;
167
            this.el = el;
168
            
169
            this.actions = this.$(".actions");
170
            this.selected = undefined;
171

    
172
            this.destroy = this.$(".actions .destroy a");
173
            this.connect = this.$(".actions .add");
174

    
175
            this.init_handlers();
176
            this.update_layout();
177
        },
178

    
179
        init_handlers: function() {
180
            this.connect.click(_.bind(function(e){
181
                e.preventDefault();
182
            }))
183
        },
184

    
185
        update_layout: function() {
186
        }
187
    });
188

    
189
    views.NetworkCreateView = views.Overlay.extend({
190
        view_id: "network_create_view",
191
        content_selector: "#networks-create-content",
192
        css_class: 'overlay-networks-create overlay-info',
193
        overlay_id: "network-create-overlay",
194

    
195
        title: "Create new private network",
196
        subtitle: "Networks",
197

    
198
        initialize: function(options) {
199
            views.NetworkCreateView.__super__.initialize.apply(this);
200

    
201
            this.create_button = this.$("form .form-action.create");
202
            this.text = this.$(".network-create-name");
203
            this.form = this.$("form");
204

    
205
            this.dhcp_select = this.$("#network-create-dhcp");
206
            this.type_select = this.$("#network-create-type");
207
            this.subnet_select = this.$("#network-create-subnet");
208
            this.subnet_custom = this.$("#network-create-subnet-custom");
209
                
210
            this.dhcp_form = this.$("#network-create-dhcp-fields");
211
            
212
            this.subnet_select.find(".subnet").remove();
213
            _.each(synnefo.config.network_suggested_subnets, function(subnet){
214
                this.subnet_select.append($('<option value='+subnet+' class="subnet">'+subnet+'</option>'));
215
            }, this);
216

    
217
            this.type_select.find(".subnet").remove();
218
            _.each(synnefo.config.network_available_types, function(name, value){
219
                this.type_select.append($('<option value='+value+' class="subnet">'+name+'</option>'));
220
            }, this);
221
            
222
            this.disable_network_type = false;
223
            if (_.keys(synnefo.config.network_available_types).length <= 1) {
224
                this.disable_network_type = true;
225
                this.type_select.closest(".form-field").hide();
226
            }
227

    
228
            this.check_dhcp_form();
229
            this.init_handlers();
230
        },
231

    
232
        check_dhcp_form: function() {
233
            if (this.dhcp_select.is(":checked")) {
234
                this.dhcp_form.show();
235
            } else {
236
                this.dhcp_form.hide();
237
            }
238
            
239
            if (this.subnet_select.val() == "custom") {
240
                this.subnet_custom.show();
241
            } else {
242
                this.subnet_custom.hide();
243
            }
244
        },
245

    
246
        init_handlers: function() {
247

    
248
            this.dhcp_select.click(_.bind(function(e){
249
                this.check_dhcp_form();
250
            }, this));
251

    
252
            this.subnet_select.change(_.bind(function(e){
253
                this.check_dhcp_form();
254
                if (this.subnet_custom.is(":visible")) {
255
                    this.subnet_custom.focus();
256
                }
257
            }, this));
258

    
259
            this.create_button.click(_.bind(function(e){
260
                this.submit();
261
            }, this));
262

    
263
            this.form.submit(_.bind(function(e){
264
                e.preventDefault();
265
                this.submit;
266
                return false;
267
            }, this))
268

    
269
            this.text.keypress(_.bind(function(e){
270
                if (e.which == 13) {this.submit()};
271
            },this))
272
        },
273

    
274
        submit: function() {
275
            if (this.validate()) {
276
                this.create();
277
            };
278
        },
279
        
280
        validate: function() {
281
            // sanitazie
282
            var t = this.text.val();
283
            t = t.replace(/^\s+|\s+$/g,"");
284
            this.text.val(t);
285

    
286
            if (this.text.val() == "") {
287
                this.text.closest(".form-field").addClass("error");
288
                this.text.focus();
289
                return false;
290
            } else {
291
                this.text.closest(".form-field").removeClass("error");
292
            }
293
            
294
            if (this.dhcp_select.is(":checked")) {
295
                if (this.subnet_select.val() == "custom") {
296
                    var sub = this.subnet_custom.val();
297
                    sub = sub.replace(/^\s+|\s+$/g,"");
298
                    this.subnet_custom.val(sub);
299
                        
300
                    if (!synnefo.util.IP_REGEX.exec(this.subnet_custom.val())) {
301
                        this.subnet_custom.closest(".form-field").prev().addClass("error");
302
                        return false;
303
                    } else {
304
                        this.subnet_custom.closest(".form-field").prev().removeClass("error");
305
                    }
306
                };
307
            }
308

    
309
            return true;
310
        },
311

    
312
        create: function() {
313
            this.create_button.addClass("in-progress");
314

    
315
            var name = this.text.val();
316
            var dhcp = this.dhcp_select.is(":checked");
317
            var subnet = null;
318
            var type = this.type_select.val();
319

    
320
            if (this.disable_network_type) { type = null };
321

    
322
            if (dhcp) {
323
                if (this.subnet_select.val() == "custom") {
324
                    subnet = this.subnet_custom.val();
325
                } else if (this.subnet_select.val() == "auto") {
326
                    subnet = null;
327
                } else {
328
                    subnet = this.subnet_select.val();
329
                }
330
                
331
            }
332

    
333
            snf.storage.networks.create(name, type, subnet, dhcp, _.bind(function(){
334
                this.hide();
335
            }, this));
336
        },
337

    
338
        beforeOpen: function() {
339
            this.create_button.removeClass("in-progress")
340
            this.text.closest(".form-field").removeClass("error");
341
            this.text.val("");
342
            this.text.show();
343
            this.text.focus();
344
            this.subnet_custom.val("");
345
            this.subnet_select.val("auto");
346
            this.dhcp_select.attr("checked", true);
347
            this.type_select.val(_.keys(synnefo.config.network_available_types)[0]);
348
            this.check_dhcp_form();
349
        },
350

    
351
        onOpen: function() {
352
            this.text.focus();
353
        }
354
    });
355

    
356
    views.NetworkNICView = views.View.extend({
357

    
358
        initialize: function(nic, parent, firewall_controls, el) {
359
            this.firewall_controls = firewall_controls || false;
360
            this.nic = nic;
361
            this.vm = nic.get_vm();
362
            // parent view di
363
            this.parent = parent;
364
            // TODO make it better
365
            this.el = el || this.parent.get_nic_view(nic);
366

    
367
            this.init_layout();
368
            this.update_layout();
369

    
370
            this.disconnect = this.$(".action-disconnect");
371
            this.confirm_el = this.$(".confirm_single");
372
            this.cancel = this.$("button.no");
373
            this.confirm = this.$("button.yes");
374
            this.details = this.$(".action-details");
375
            this.vm_connect = this.$(".machine-connect");
376

    
377
            this.init_handlers();
378
            this.connect_overlay = new views.VMConnectView();
379
            
380
            this.firewall_view = undefined;
381
            if (this.firewall_controls) {
382
                this.firewall_view = new views.FirewallEditView(this.nic, this.parent.network, this);
383
            }
384

    
385
        },
386
        
387
        reset_all_net_actions: function(act_types) {
388
            synnefo.storage.networks.each(function(n){
389
                var actions = n.get('actions');
390
                _.each(act_types, function(type){
391
                    actions.remove_all(type);
392
                })
393
            })
394
        },
395

    
396
        init_handlers: function() {
397
            if (!this.parent.network.is_public()) {
398
                this.disconnect.click(_.bind(function(e){
399
                    e.preventDefault();
400
                    this.reset_all_net_actions(['destroy','disconnect']);
401
                    this.parent.network.get("actions").remove_all("disconnect");
402
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
403
                    this.parent.network.get("actions").remove("destroy");
404
                }, this));
405
                this.cancel.click(_.bind(function(e){
406
                    this.parent.network.get("actions").remove("disconnect", this.nic.id);
407
                    e.preventDefault()
408
                }, this));
409

    
410
                this.confirm.click(_.bind(function(e){
411
                    e.preventDefault()
412
                    this.disconnect_nic();
413
                    this.confirm_el.hide();
414
                    this.disconnect.removeClass("selected");
415
                }, this));
416

    
417
                snf.ui.main.bind("view:change", _.bind(function(v) {
418
                    if (v == "networks" ){ return }
419
                    this.confirm_el.hide();
420
                    this.disconnect.removeClass("selected");
421
                }, this));
422

    
423
                this.$(".remove-icon").click(_.bind(function(){
424
                    this.reset_all_net_actions(['destroy','disconnect']);
425
                    this.parent.network.get("actions").remove_all("disconnect");
426
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
427
                    this.parent.network.get("actions").remove("destroy");
428
                }, this));
429

    
430
                this.vm_connect.click(_.bind(function() {
431
                    this.connect_overlay.show(this.vm);
432
                }, this));
433
                
434
                this.parent.network.bind("change:actions", _.bind(function(model, action){
435
                    if (this.parent.network.get("actions").contains("disconnect", this.nic.id)) {
436
                        this.confirm_disconnect();
437
                    } else {
438
                        this.cancel_disconnect();
439
                    }
440
                }, this));
441
            }
442
            
443
            var vm = this.vm;
444
            this.details.click(function(e){
445
                e.preventDefault();
446
                snf.ui.main.show_vm_details(vm);
447
            });
448

    
449
        },
450

    
451
        cancel_disconnect: function() {
452
            this.confirm_el.hide();
453
            this.disconnect.removeClass("selected");
454
            this.$(".net-vm-actions a").removeClass("visible");
455
        },
456

    
457
        confirm_disconnect: function() {
458
            this.confirm_el.show();
459
            this.disconnect.addClass("selected");
460
            this.$(".net-vm-actions a").addClass("visible");
461
        },
462

    
463
        init_layout: function() {
464
            if (!this.firewall_controls) { return };
465
        },
466

    
467
        update_layout: function() {
468
            this.$(".vm-name").text(snf.util.truncate(this.vm.get("name"), 40));
469
            this.$("img.logo").attr("src", ui.helpers.vm_icon_path(this.vm, "medium"));
470

    
471
            if (this.firewall_view) {
472
                this.$(".ipv4-text").text(this.nic.get_v4_address());
473
                this.$(".ipv6-text").text(this.nic.get_v6_address());
474
            }
475

    
476
            if (this.firewall_view) {
477
                this.firewall_view.update_layout();
478
            }
479

    
480
            if (!this.firewall_view) {
481
                this.$(".ip4-container").hide();
482
                this.$(".ip6-container").hide();
483
                
484
                if (this.nic.get("ipv4")) {
485
                    this.$(".ipv4-text").text(this.nic.get_v4_address());
486
                    this.$(".ip4-container").show();
487
                    this.$(".machine-connect .content").hide();
488
                } else if (this.nic.get("ipv6")) {
489
                    this.$(".ipv6-text").text(this.nic.get_v6_address());
490
                    this.$(".ip6-container").show();
491
                    this.$(".machine-connect .content").hide();
492
                } else {
493
                    this.$(".machine-connect .content").show();
494
                }
495
            } else {
496
            }
497
        },
498

    
499
        disconnect_nic: function() {
500
            this.$("a.selected").removeClass("selected");
501
            this.parent.network.remove_nic(this.nic);
502
        },
503
    })
504

    
505
    views.NetworkModelRenameView = views.View.extend({
506
        initialize: function(parent, network) {
507
            this.parent = parent;
508
            this.network = network;
509
            this.el = this.parent.el.find(".name-div");
510

    
511
            this.icon = this.$(".rename-network");
512
            this.save = this.$("span.save");
513
            this.cancel = this.$("span.cancel");
514
            this.buttons = this.$(".editbuttons");
515
            this.name = this.$("span.name");
516
            this.editing = false;
517
            this.init_handlers();
518
            this.update_layout();
519
        },
520

    
521
        init_handlers: function() {
522
            this.icon.click(_.bind(function(){
523
                this.editing = true;
524
                this.update_layout();
525
            }, this));
526
            this.cancel.click(_.bind(function(){
527
                this.editing = false;
528
                this.update_layout();
529
            }, this));
530
            this.save.click(_.bind(function(){
531
                this.submit();
532
            }, this))
533
        },
534
        
535
        submit: function() {
536
            var value = _(this.input.val()).trim();
537
            if (value == "") { return }
538

    
539
            this.network.rename(value, _.bind(function(){
540
                this.editing = false;
541
                this.update_layout();
542
            }, this));
543
        },
544

    
545
        create_input: function() {
546
            this.input = $('<input type="text" class="network-rename-input" />');
547
            this.input.val(this.network.get("name"));
548
            this.el.append(this.input);
549
            this.input.focus();
550
            this.input.bind("keydown", _.bind(function(ev){
551
                ev.keyCode = ev.keyCode || ev.which;
552
                if (ev.keyCode == 13) { this.submit(); };
553
                if (ev.keyCode == 27) {this.editing = false; this.update_layout()};
554
            }, this));
555
        },
556

    
557
        remove_input: function() {
558
            if (!this.input) { return }
559
            this.input.remove();
560
        },
561

    
562
        update_layout: function() {
563
            if (this.editing) {
564
                if (this.buttons.is(":visible")) { return }
565
                this.icon.hide();
566
                this.buttons.show();
567
                this.create_input();
568
                this.name.hide();
569
            } else {
570
                this.buttons.hide();
571
                this.remove_input();
572
                this.name.show();
573
                this.icon.show();
574
            }
575
        }
576
    })
577

    
578
    views.FirewallEditView = views.View.extend({
579
        initialize: function(nic, network, parent) {
580
            this.parent = parent;
581
            this.vm = nic.get_vm();
582
            this.nic = nic;
583
            this.network = network;
584
            this.el = this.parent.el;
585

    
586
            views.FirewallEditView.__super__.initialize.apply(this);
587

    
588
            // elements
589
            this.toggler = this.$(".firewall-toggle");
590
            this.indicator = this.$(".machines-label span");
591
            this.progress = this.$(".network-progress-indicator");
592
            this.content = this.$(".firewall-content");
593
            this.inputs = this.$("input[type=radio]");
594
            this.labels = this.$("span.checkbox-legends, label.checkbox-legends");
595
            this.apply = this.$(".firewall-apply");
596

    
597
            this.$(".firewall-content").hide();
598
            this.$(".firewall-content input[type=radio]").attr("name", "firewall-opt-for-{0}".format(this.vm.id))
599
            var mode = this.vm.get_firewall_profile();
600
            this.$(".firewall-content input[value={0}]".format(mode)).attr("checked", true);
601

    
602
            this.init_handlers();
603
            this.update_layout();
604

    
605
            var self = this;
606
            this.nic.bind("change:pending_firewall_sending", function(nic, value) {
607
                if (value) {
608
                    self.apply.addClass("in-progress");       
609
                    self.progress.show();
610
                } else {
611
                    self.apply.removeClass("in-progress");       
612
                    self.progress.hide();
613
                    self.toggler.click();
614
                }
615
            });
616

    
617
            this.nic.bind("change:firewallProfile", function(nic){
618
                self.update_layout();
619
                self.reset_value();
620
            })
621

    
622
        },
623
        
624
        _get_selected: function() {
625
            return this.inputs.filter(":checked");
626
        },
627

    
628
        reset_selected: function() {
629
        },
630

    
631
        submit: function() {
632
        },
633

    
634
        reset_value: function() {
635
            this.inputs.filter("[value={0}]".format(
636
              this.nic.get('firewallProfile'))).attr("checked", true);
637
        },
638

    
639
        init_handlers: function() {
640
            this.toggler.click(_.bind(function(){
641
                cont = this.content;
642
                if (cont.is(":visible")) {
643
                    this.hide_firewall();
644
                    this.reset_value();
645
                } else {
646
                    this.show_firewall();
647
                }
648

    
649
                $(window).trigger("resize");
650
            }, this))
651
            
652
            this.apply.click(_.bind(function(){
653
                this.nic.set_firewall(this.value());
654
            }, this))
655

    
656
            this.inputs.change(_.bind(function(){
657
                this.update_selected();
658
            }, this))
659
            
660
            var self = this;
661
            this.$(".checkbox-legends").click(function(el) {
662
                var el = $(this);
663
                el.prev().click();
664
                self.update_selected();
665
            })
666
        },
667

    
668
        update_selected: function() {
669
            this.update_layout();
670
        },
671

    
672
        show_firewall: function() {
673
            this.content.slideDown(100, function(){$(window).trigger("resize")});
674
            this.toggler.addClass("open");
675
        },
676

    
677
        hide_firewall: function() {
678
            this.content.slideUp(100, function(){$(window).trigger("resize")});
679
            this.toggler.removeClass("open");
680
        },
681

    
682
        value: function() {
683
            return this._get_selected().val();
684
        },
685

    
686
        update_layout: function() {
687
            if (this.value() == this.vm.get_firewall_profile()) {
688
                this.apply.hide();
689
            } else {
690
                this.apply.show();
691
            }
692

    
693
            var profile = this.vm.get_firewall_profile();
694
            if (this.vm.has_firewall(this.network.id)) {
695
                this.$(".firewall-toggle .label span").text("On");
696
                this.$(".firewall-toggle .label span").removeClass("firewall-off");
697
                this.$(".firewall-toggle .label span").addClass("firewall-on");
698
            } else {
699
                this.$(".firewall-toggle .label span").text("Off");
700
                this.$(".firewall-toggle .label span").removeClass("firewall-on");
701
                this.$(".firewall-toggle .label span").addClass("firewall-off");
702
            }
703
            
704
            this.$("span.checkbox-legends").removeClass("current");
705
            this.inputs.filter("[value={0}]".format(profile)).next().addClass("current");
706
            
707
        }
708
    })
709

    
710
    views.NetworkModelView = views.View.extend({
711
        
712
        firewall: false,
713

    
714
        initialize: function(network, view) {
715
            this.parent_view = view;
716
            this.network = network;
717
            this.is_public = network.is_public();
718

    
719
            this.init_nics_handlers();
720

    
721
            this.view_id = "networks_view_" + network.id;
722
            views.NetworkModelView.__super__.initialize.call(this);
723

    
724
            this.nics_views = {};
725

    
726
            this.el = this.create_el();
727

    
728
            // element helpers
729
            this.nics_list = this.$(".machines-list");
730
            this.nics_list_toggler = this.$(".list-toggle");
731
            
732
            this.init_handlers();
733
            this.update_nics();
734
            this.update_layout();
735

    
736
            this.hide_nics_list();
737
            this.nics_list.hide();
738

    
739
            this.rename_view = undefined;
740
            if (!this.network.is_public()) {
741
                // allow network rename for non public networks only
742
                this.rename_view = new views.NetworkModelRenameView(this, network);
743
            }
744
            
745
            var self = this;
746
            this.network.bind('change:status', function() {
747
                self.update_layout();
748
            })
749
        },
750

    
751
        init_nics_handlers: function() {
752
            storage.nics.bind("add", _.bind(this.nic_added_handler, this, "add"));
753
            storage.nics.bind("change", _.bind(this.nic_changed_handler, this, "change"));
754
            storage.nics.bind("reset", _.bind(this.nic_changed_handler, this, "reset"));
755
            storage.nics.bind("remove", _.bind(this.nic_removed_handler, this, "remove"));
756
        },
757

    
758

    
759
        show_nics_list: function() {
760
            if (this.nics_empty()) { return }
761
            this.nics_list_toggler.addClass("open");
762
            this.nics_list.slideDown(function(){
763
                $(window).trigger("resize");
764
            }).closest(".network").addClass("expand");
765
            this.$(".empty-network-slot").show();
766
            this.nics_visible = true;
767
        },
768

    
769
        hide_nics_list: function() {
770
            this.nics_list_toggler.removeClass("open");
771
            this.nics_list.slideUp(function(){
772
                $(window).trigger("resize");
773
            }).closest(".network").removeClass("expand");
774
            this.$(".empty-network-slot").hide();
775
            this.nics_visible = false;
776
        },
777
        
778
        init_handlers: function() {
779
            var self = this;
780

    
781
            this.nics_list_toggler.click(_.bind(function(){
782
                if (this.nics_list.is(":visible")) {
783
                    this.hide_nics_list();
784
                } else {
785
                    this.fix_left_border();
786
                    this.show_nics_list();
787
                }
788

    
789
                this.check_empty_nics();
790
            }, this));
791

    
792
            this.$(".action-add").click(_.bind(function(e){
793
                e.preventDefault();
794
                this.network.get("actions").remove("destroy");
795
                this.show_connect_vms();
796
            }, this))
797

    
798
            this.$(".add-icon").click(_.bind(function(e){
799
                e.preventDefault();
800
                this.show_connect_vms();
801
            }, this))
802

    
803
            this.$(".net-actions .destroy a").click(_.bind(function(e){
804
                e.preventDefault();
805
                synnefo.storage.networks.each(function(n) {
806
                    n.get('actions').remove_all("disconnect");
807
                    if (!synnefo.config.network_allow_multiple_destory) {
808
                        n.get('actions').remove_all("destroy");
809
                    }
810
                });
811
                self.network.get("actions").add("destroy");
812
                self.network.get("actions").remove_all("disconnect");
813
            }, this));
814

    
815
            self.network.bind("change:actions", _.bind(function(net, action) {
816
                if (this.network.get("actions").contains("destroy")) {
817
                    this.confirm_destroy();
818
                } else {
819
                    this.cancel_destroy();
820
                }
821
            }, this))
822

    
823
            this.$(".net-actions button.no").click(function(e){
824
                e.preventDefault();
825
                self.network.get("actions").remove("destroy");
826
            });
827

    
828
            this.$(".net-actions button.yes").click(function(e){
829
                e.preventDefault();
830
                var el = $(this);
831
                el.closest(".confirm_single").hide();
832
                el.parent().parent().find(".selected").removeClass("selected");
833
                self.network.call('destroy', {}, function(){
834
                    el.closest(".confirm_single").removeClass("in-progress");
835
                });
836
                el.closest(".confirm_single").addClass("in-progress");
837
            });
838

    
839
            snf.ui.main.bind("view:change", _.bind(function(v) {
840
                if (v == "networks" ){ return }
841
                this.$(".confirm_single").hide();
842
                this.$("a.selected").removeClass("selected");
843
            }, this));
844

    
845
            $(window).bind("resize", _.bind(function() {
846
                this.fix_left_border();
847
            }, this));
848
        },
849

    
850
        show_connect_vms: function() {
851
            this.$(".confirm_single").hide();
852
            this.$("a.selected").removeClass("selected");
853
            var vms = this.network.get_connectable_vms();
854
            this.parent_view.connect_machines_view.show_vms(this.network,
855
                                                            vms, [], 
856
                                                            _.bind(this.connect_vms, this));
857
        },
858

    
859
        cancel_destroy: function() {
860
            this.$(".net-actions .destroy .confirm_single").hide();
861
            this.$(".net-actions .destroy a.selected").removeClass("selected");
862
            this.$(".net-actions a").removeClass("visible");
863
        },
864

    
865
        confirm_destroy: function() {
866
            this.$(".destroy .confirm_single").show();
867
            this.$(".destroy a").addClass("selected");
868
            this.$(".net-actions a").addClass("visible");
869
        },
870

    
871
        connect_vms: function(vms) {
872
            _.each(vms, _.bind(function(vm){
873
                this.network.add_vm(vm);
874
            }, this));
875

    
876
            this.parent_view.connect_machines_view.hide();
877
        },
878

    
879
        create_el: function() {
880
            var el = this.$(this.tpl).clone().attr("id", "network-" + this.network.id);
881
            return el;
882
        },
883

    
884
        get_nic_id: function(nic) {
885
            return this.nic_id_tpl.format(nic.id);
886
        },
887

    
888
        get_nic_view: function(nic) {
889
            return $(this.get_nic_id(nic));
890
        },
891

    
892
        nic_added_handler: function(action, nic) {
893
            if (nic.get_network().id != this.network.id) { return };
894
            this.add_or_update_nic(nic);
895
            this.update_layout();
896
            this.fix_left_border();
897
        },
898

    
899
        nic_changed_handler: function(action, nics, model, changes) {
900
            var nics = nics || [];
901

    
902
            // reset or update
903
            if (action == "reset") {
904
                nics = nics;
905
            } else {
906
                if (!_.isArray(nics)) {
907
                    nics = [nics]
908
                }
909
            }
910
            
911
            _.each(nics, _.bind(function(nic) {
912
                if (nic.get_network().id != this.network.id) { return };
913
                this.add_or_update_nic(nic);
914
            }, this));
915

    
916
            this.update_layout();
917
        },
918

    
919
        nic_removed_handler: function(action, nic, model) {
920
            if (nic.get_network().id != this.network.id) { return };
921
            this.fix_left_border();
922
            this.remove_nic(nic);
923
            this.update_layout();
924
        },
925

    
926
        remove_nic: function(nic) {
927
            var nic_view = this.get_nic_view(nic);
928
            if (nic_view.length) {
929
                nic_view.remove();
930
                try {
931
                    delete this.nics_views[nic.id]
932
                } catch (err) {
933
                }
934
            }
935
        },
936
        
937
        create_nic_view: function(nic) {
938
            var nic_el = $(this.nic_tpl).clone().attr({
939
                id: this.get_nic_id(nic).replace("#","")
940
            });
941
            this.nics_list.append(nic_el);
942
            this.post_nic_add(nic);
943

    
944
            if (!this.nics_views[nic.id]) {
945
                var nic_view = this.nics_views[nic.id] = new views.NetworkNICView(nic, this, this.firewall, nic_el);
946
            }
947
        },
948

    
949
        add_or_update_nic: function(nic) {
950
            if (!nic) { return };
951
                
952
            var nic_el = this.get_nic_view(nic);
953
            var nic_view = this.nics_views[nic.id];
954

    
955
            if (nic_el.length == 0) {
956
                nic_view = this.create_nic_view(nic);
957
            }
958
            
959
            if (nic_view) { nic_view.update_layout() };
960

    
961
            this.update_nic(nic);
962
            this.post_nic_update(nic);
963
        },
964

    
965
        update_nic: function(vm){},
966
        post_nic_add: function(vm){},
967
        post_nic_update: function(vm){},
968

    
969
        update_nics: function(nics) {
970
            if (!nics) { nics = this.network.get_nics() };
971
            _.each(nics, _.bind(function(nic){
972
                this.add_or_update_nic(nic);
973
            }, this));
974
        },
975

    
976
        check_empty_nics: function() {
977
            if (this.network.get_nics() == 0) {
978
                this.hide_nics_list();
979
            }
980
        },
981

    
982
        nics_empty: function() {
983
            return this.network.get_nics().length == 0;
984
        },
985

    
986
        remove: function() {
987
            $(this.el).remove();
988
        },
989

    
990
        update_layout: function() {
991
            // has vms ???
992
            this.check_empty_nics(this.network.get_nics());
993

    
994
            // is expanded ???
995
            //
996
            // whats the network status ???
997
            //
998
            this.$(".machines-count").text(this.network.get_nics().length);
999

    
1000
            var net_name = this.network.get("name");
1001
            if (net_name == "public") { net_name = "Internet" }
1002
            this.$(".name-div span.name").text(net_name);
1003

    
1004
            if (this.rename_view) {
1005
                this.rename_view.update_layout();
1006
            }
1007
            
1008
            this.$(".net-status").text(this.network.state_message());
1009

    
1010
            if (this.network.in_progress())  {
1011
                this.$(".spinner").show();
1012
                this.$(".network-indicator").addClass("in-progress");
1013
            } else {
1014
                this.$(".spinner").hide();
1015
                this.$(".network-indicator").removeClass("in-progress");
1016
            }
1017
                
1018
            if (this.network.get('state') == 'PENDING') {
1019
                this.el.addClass("pending");
1020
            } else {
1021
                this.el.removeClass("pending");
1022
            }
1023

    
1024
            if (this.network.get('state') == 'ERROR') {
1025
                this.el.addClass("in-error");
1026
                this.$(".network-indicator").addClass("error-state");
1027
            } else {
1028
                this.el.removeClass("in-error");
1029
                this.$(".network-indicator").removeClass("error-state");
1030
            }
1031

    
1032
            if (synnefo.config.network_strict_destroy) {
1033
                if (this.network.get_nics().length == 0) {
1034
                    this.el.removeClass("disable-destroy");
1035
                } else {
1036
                    this.el.addClass("disable-destroy");
1037
                }
1038
            }
1039

    
1040
            if (this.network.get("state") == "DESTROY") {
1041
                this.$(".spinner").show();
1042
                this.$(".state").addClass("destroying-state");
1043
                this.$(".actions").hide();
1044
            }
1045
        },
1046

    
1047
        // fix left border position
1048
        fix_left_border: function() {
1049
            if (!this.nics_visible) { return };
1050
            
1051
            var imgheight = 2783;
1052
            var opened_vm_height = 133 + 20;
1053
            var closed_vm_height = 61 + 20;
1054
            var additional_height = 25;
1055

    
1056
            if (!this.is_public) { 
1057
                imgheight = 2700;
1058
                additional_height = 65;
1059
            };
1060
            
1061
            var contents = this.$(".network-contents");
1062
            var last_vm = this.$(".network-machine:last .cont-toggler.open").length;
1063
            var last_vm_height = closed_vm_height;
1064
            if (last_vm > 0){
1065
                last_vm_height = opened_vm_height;
1066
            }
1067

    
1068
            var nics_opened = this.$(".network-machine .cont-toggler.open").length;
1069
            var nics_closed = this.$(".network-machine").length - nics_opened;
1070

    
1071
            var calc_height = (nics_opened * opened_vm_height) + (nics_closed * closed_vm_height) + additional_height; 
1072
            var bgpos = imgheight - calc_height + last_vm_height - 30;
1073
            this.$(".network-contents").css({'background-position':'33px ' + (-bgpos) + 'px'});
1074
        }
1075
    })
1076

    
1077
    views.PublicNetworkView = views.NetworkModelView.extend({
1078
        firewall: true,
1079
        tpl: "#public-template",
1080
        nic_tpl: "#public-nic-template",
1081
        nic_id_tpl: "#nic-{0}",
1082

    
1083
        update_vm: function(vm) {
1084
        }
1085
    })
1086
    
1087
    views.PrivateNetworkView = views.NetworkModelView.extend({
1088
        tpl: "#private-template",
1089
        nic_tpl: "#private-nic-template",
1090
        nic_id_tpl: "#nic-{0}"
1091
    })
1092

    
1093
    views.NetworksView = views.View.extend({
1094
        
1095
        view_id: "networks",
1096
        pane: "#networks-pane",
1097
        el: "#networks-pane",
1098

    
1099
        initialize: function() {
1100
            // elements shortcuts
1101
            this.create_cont = this.$("#networks-createcontainer");
1102
            this.container = this.$("#networks-container");
1103
            this.public_list = this.$(".public-networks");
1104
            this.private_list = this.$(".private-networks");
1105
            views.NetworksView.__super__.initialize.call(this);
1106
            this.init_handlers();
1107
            this.network_views = {};
1108
            this.update_networks(storage.networks.models);
1109
            this.create_view = new views.NetworkCreateView();
1110
            this.connect_machines_view = new views.NetworkConnectVMsOverlay();
1111
        },
1112
        
1113
        exists: function(net) {
1114
            return this.network_views[net.id];
1115
        },
1116

    
1117
        add_or_update: function(net) {
1118
            var nv = this.exists(net);
1119
            if (!nv) {
1120
                nv = this.create_network_view(net);
1121
                this.network_views[net.id] = nv;
1122
                
1123
                if (net.is_public()) {
1124
                    this.public_list.append(nv.el);
1125
                    this.public_list.show();
1126
                } else {
1127
                    this.private_list.append(nv.el);
1128
                    this.private_list.show();
1129
                }
1130
            }
1131

    
1132
            // update vms
1133
            // for cases where network servers list
1134
            // get updated after vm addition and
1135
            // vm_added_handler fails to append the
1136
            // vm to the list
1137
            nv.update_nics();
1138
            nv.update_layout();
1139
        },
1140
        
1141
        create_network_view: function(net) {
1142
            if (net.is_public()) {
1143
                return new views.PublicNetworkView(net, this);
1144
            }
1145
            return new views.PrivateNetworkView(net, this);
1146
        },
1147
        
1148
        init_handlers: function() {
1149
            storage.networks.bind("add", _.bind(this.network_added_handler, this, "add"));
1150
            storage.networks.bind("change", _.bind(this.network_changed_handler, this, "change"));
1151
            storage.networks.bind("reset", _.bind(this.network_changed_handler, this, "reset"));
1152
            storage.networks.bind("remove", _.bind(this.network_removed_handler, this, "remove"));
1153

    
1154
            this.$("#networkscreate").click(_.bind(function(e){
1155
                e.preventDefault();
1156
                this.create_view.show();
1157
            }, this));
1158
            
1159
        },
1160

    
1161
        update_networks: function(nets) {
1162
            _.each(nets, _.bind(function(net){
1163
                if (net.get("status") == "DELETED") { return };
1164
                view = this.add_or_update(net);
1165
            }, this));
1166
        },
1167

    
1168
        show: function() {
1169
            this.container.show();
1170
            $(this.el).show();
1171
        },
1172

    
1173
        network_added_handler: function(type, net) {
1174
            this.update_networks([net]);
1175
        },
1176

    
1177
        network_changed_handler: function(type, models) {
1178
            var nets = [];
1179
            if (type == "change") {
1180
                nets = [models]
1181
            } else {
1182
                nets = models.models;
1183
            }
1184

    
1185
            this.update_networks(nets)
1186
        },
1187

    
1188
        network_removed_handler: function(type, net) {
1189
            this.remove_net(net)
1190
            if (this.private_list.find(".network").length == 0) {
1191
                this.private_list.hide();
1192
            }
1193
        },
1194

    
1195
        network_added: function(net) {
1196
            return this.network_views[net.id];
1197
        },
1198

    
1199
        get_network_view: function(net) {
1200
            return this.network_views[net.id];
1201
        },
1202

    
1203
        remove_net: function(net) {
1204
            if (this.network_added(net)) {
1205
                var view = this.get_network_view(net);
1206
                view.remove();
1207
                delete this.network_views[net.id];
1208
            }
1209
        },
1210

    
1211
        __update_layout: function() {
1212
        }
1213
    });
1214

    
1215
})(this);