- /*
- * BGPlay.js #9660
- * A web-based service for the visualization of the Internet routing
- *
- * Copyright (c) 2012 Roma Tre University and RIPE NCC
- *
- * See the file LICENSE.txt for copying permission.
- */
-
- /**
- * This is a module specific for BGP.
- * It provides the query form.
- * Template: controller.html
- * @class ControllerView
- * @module modules
- */
- var ControllerView=Backbone.View.extend({
- events:function(){
- return {
- "click .bgplayControlAnimationStartPause":"toggle",
- "click .bgplayControlAnimationStop":"stopButton",
- "click .bgplayControlAnimationPrev":"previousEvent",
- "click .bgplayControlAnimationNext":"nextEvent",
- "mouseover .bgplayControlPanelDivFlagIco":"mouseOverFlag",
- "mouseout .bgplayControlPanelDivFlagIco":"mouseOutFlag",
- "click .bgplayControlPanelDivFlagIco":"clickOnFlag",
- "change input[name=bgplayControlPrefixValues]":"validateIp",
- "click .bgplayControlDiscardButton":"discardConfig",
- "click .bgplayControlApplyButton":"updateConfig",
- "click .bgplayControlPrefixMore":"morePrefixTextbox",
- "click .bgplayControlPrefixDelete":"lessPrefixTextbox"
- }
- },
-
- /**
- * The initialization method of this object.
- * @method initialize
- * @param {Map} A map of parameters
- */
- initialize:function(){
- this.environment=this.options.environment;
- this.bgplay=this.environment.bgplay;
- this.fileRoot=this.environment.fileRoot;
- this.eventAggregator=this.environment.eventAggregator;
-
- this.eventAggregator.trigger("moduleLoading", true);
- this.animation=false;
- this.allEvents=this.bgplay.get("allEvents");
- this.prefixes=stringToArray(this.environment.params.targets);
- this.selectedRrcs=stringToArray(this.environment.params.selectedRrcs);
- this.selectableRrcs=this.environment.config.selectableRrcs;
- this.possibleRrcs=this.environment.config.possibleRrcs.removeSubArray(this.selectedRrcs);
- this.slideOpened=false;
- this.ignoreReannouncements= this.environment.params.ignoreReannouncements || this.environment.config.ignoreReannouncementsByDefault;
- this.releasedPlayButton=true;
- this.environment.dynamicParams.push('instant');
- this.startAnimationInstant=new Instant({id:0,timestamp:this.bgplay.get("starttimestamp")});
- this.stopAnimationInstant=new Instant({id:0,timestamp:this.bgplay.get("endtimestamp")});
-
- this.eventAggregator.on("destroyAll", function(){
- this.destroyMe();
- },this);
-
- this.bgplay.on("change:cur_instant",function(){
- if (this.environment.config.controller.keepTrackCurrentInstant==true){
- var instant=this.bgplay.get("cur_instant");
- this.environment.params.instant = instant.toString();
- try{
- if (this.environment.paramsInUrl==true && this.environment.instances==1){
- setUrlParam('instant',instant.toString(),false);
- window.history.replaceState({"html":this.bgplay.html,"pageTitle":'BGPlayjs'},"", currentUrl);
- }
- }catch(e){
- log("This browser does not support the replaceState function.");
- }
- }
- },this);
-
- this.eventAggregator.trigger("autoStartFunction",
- {func:
- function(){
- var initialInstant = this.environment.params.instant || getUrlParam("instant");
- if (initialInstant != null && initialInstant!="" && this.environment.instances==1){
- initialInstant = initialInstant.split(',');
- this.environment.bgplay.set({"cur_instant":new Instant({id:initialInstant[0],timestamp:initialInstant[1]})});
- }
- }
- , context:this});
-
- this.eventAggregator.on("animationEnd", function(){
- this.stop();
- },this);
-
- this.eventAggregator.on("animationReload", function(){
- this.reload();
- },this);
-
- this.eventAggregator.on("newSelectionStart", function(value){
- this.startAnimationInstant=value;
- },this);
-
- this.eventAggregator.on("releasePlayButton", function(release){
- this.releasedPlayButton=release;
- if (this.releasedPlayButton==true){
- this.controlAnimationStartPause.css('cursor','auto');
- }else{
- this.controlAnimationStartPause.css('cursor','wait');
- }
- },this);
-
- this.eventAggregator.on("newSelectionEnd", function(value){
- this.stopAnimationInstant=value;
- },this);
-
- this.render();
- log("Controller view loaded.");
- this.eventAggregator.trigger("moduleLoading", false);
- },
-
- /*
- * This method creates the pointers to the DOM elements.
- */
- getDomElements:function(){
- this.dom = this.$el;
- this.controlAnimationStartPause = this.dom.find('.bgplayControlAnimationStartPause');
- this.controlAnimationStop = this.dom.find('.bgplayControlAnimationStop');
- this.controlAnimationNext = this.dom.find('.bgplayControlAnimationNext');
- this.controlAnimationPrevImage = this.dom.find('.bgplayControlAnimationPrev img');
- this.controlPrefixDiv = this.dom.find('.bgplayControlPrefixDiv');
- this.starttimestampPicker = this.dom.find('.bgplayStarttimestampPicker');
- this.endtimestampPicker = this.dom.find('.bgplayEndtimestampPicker');
- this.controlPanelDivFlagIco = this.dom.find('.bgplayControlPanelDivFlagIco');
- this.controlPanelDivComplete = this.dom.find('.bgplayControlPanelDivComplete');
- this.suppressReannounce = this.dom.find('.bgplaySuppressReannounce');
- },
-
- /**
- * This method draws this module (eg. inject the DOM and elements).
- * @method render
- */
- render:function(){
- parseTemplate('controller.html',this,this.el);
- this.getDomElements();
- this.update();
- this.controlPrefixDiv.tinyscrollbar({axis:'y'});
-
- this.starttimestampPicker.datetimepicker({
- changeMonth: true,
- changeYear: true,
- hideIfNoPrevNext:true,
- timeFormat:'HH:mm:ss',
- separator:' ',
- dateFormat:'yy/mm/dd',
- showSecond: true,
- maxDate: "+0"
- });
-
- this.starttimestampPicker.datetimepicker("setDate",new Date(this.bgplay.get("starttimestamp")*1000));
-
- this.endtimestampPicker.datetimepicker({
- changeMonth: true,
- changeYear: true,
- defaultDate:new Date(this.bgplay.get("endtimestamp")*1000),
- hideIfNoPrevNext:true,
- timeFormat:'HH:mm:ss',
- separator:' ',
- dateFormat:'yy/mm/dd',
- showSecond: true,
- maxDate: "+0"
- });
-
- this.endtimestampPicker.datetimepicker("setDate",new Date(this.bgplay.get("endtimestamp")*1000));
-
- return this;
- },
-
- /**
- * This method updates the DOM of the Control Panel without render it again.
- * @method update
- */
- update:function(){
- var startStopImages;
- startStopImages = this.controlAnimationStartPause.find('img');
- if (this.animation==true){
- this.controlAnimationPrevImage.hide();
- this.controlAnimationNext.hide();
- startStopImages.eq(1).hide();
-
- startStopImages.eq(0).show();
- this.controlAnimationStop.show();
-
- }else{
- this.controlAnimationStop.hide();
- startStopImages.eq(0).hide();
-
- startStopImages.eq(1).show();
- this.controlAnimationPrevImage.show();
- this.controlAnimationNext.show();
- }
-
-
- },
-
- /**
- * If this method is invoked during an animation then the animation pauses otherwise the animation starts.
- * @method toggle
- */
- toggle:function(){
- if (!this.releasedPlayButton){
- return;
- }
-
- this.closeFlag();
- if (this.bgplay.get("cur_instant").get("timestamp") < this.stopAnimationInstant.get("timestamp")){
- this.animation=!this.animation;
- this.update();
- this.eventAggregator.trigger("animate", this.animation);
- }
- },
-
- /**
- * This method reloads the animation.
- * @method reload
- */
- reload:function(){
- this.bgplay.setCurInstant(this.startAnimationInstant);
- this.eventAggregator.trigger("checkPathPosition");
- },
-
- /**
- * This method stops and reloads the animation.
- * @method stopButton
- */
- stopButton:function(){
- this.stop();
- this.reload();
- },
-
- /**
- * This method stops the animation.
- * @method stop
- */
- stop:function(){
- this.animation=false;
- this.eventAggregator.trigger("animate", false);
- this.update();
- },
-
- /**
- * This method applies the previous event.
- * @method previousEvent
- */
- previousEvent:function(){
- var prevInstant, prevEvent, instant;
- instant = this.bgplay.get("cur_instant");
- prevEvent = this.allEvents.nearest(instant,false,false);
- if (prevEvent!=null){
- prevInstant = prevEvent.get("instant");
- if (!this.environment.config.controller.disableNotSelectedInstants || this.allEvents.compare(prevInstant,this.startAnimationInstant)>=0){
- this.bgplay.setCurInstant(prevInstant);
- }
- }
- },
-
- /**
- * This method applies the next event.
- * @method nextEvent
- */
- nextEvent:function(){
- var nextInstant, nextEvent, instant;
- instant = this.bgplay.get("cur_instant");
- nextEvent = this.allEvents.nearest(instant,true,false);
- if (nextEvent!=null){
- nextInstant = nextEvent.get("instant");
- if (!this.environment.config.controller.disableNotSelectedInstants || this.allEvents.compare(nextInstant,this.stopAnimationInstant)<=0){
- this.bgplay.setCurInstant(nextInstant);
- }
- }
- },
-
- /**
- * This method validates an IP/prefix inserted in the query form.
- * @method validateIp
- * @return {Boolean} True if the given IP is valid
- */
- validateIp:function(){
- var out, val, $this;
- out=true;
- $this=this;
- this.dom.find("input[name=bgplayControlPrefixValues]").each(function(){
- val=$(this).val();
- if (! (validateIpv4and6Prefix(val) || validateIpv4and6Address(val))){
- $this.environment.cssAlert.alert('Malformed prefix/ip.<br/>A valid ip for ipv4 or ipv6 possibly with netmask is required.','validation');
- out=false;
- }
- });
- return out;
- },
-
- /**
- * This method validates the query form.
- * @method validateAll
- * @return {Boolean} True if the data inserted in the query form is valid
- */
- validateAll:function(){
- //A trick to solve a bug of the timepicker add-on (I'm triggering a keyUp to force the update of the date)
- this.starttimestampPicker.keyup();
- this.endtimestampPicker.keyup();
-
- return this.validateIp() && this.validateInterval() && this.validateRrcs();
- },
-
- /**
- * This method validates the time interval.
- * @method validateInterval
- * @return {Boolean} True if the time interval is valid
- */
- validateInterval:function(){
- if (this.starttimestampPicker.datepicker("getDate").getTime()>this.endtimestampPicker.datepicker("getDate").getTime()){
- this.environment.cssAlert.alert("The end date is before the start date.<br/>Wait a minute, Doc. Ah... Are you telling me that you built a time machine... out of a DeLorean?","validation");
- return false;
- }
- return true;
- },
-
- /**
- * This method validates a set of route collectors
- * @method validateRrcs
- * @return {Boolean} True if the set of RRCs is valid
- */
- validateRrcs:function(){
- if (this.selectableRrcs){
- var rrcSelected=[];
- this.dom.find('input[name=bgplayRrcSelect]:checked').each(function(){
- rrcSelected.push($(this).val());
- });
- if (rrcSelected.length==0){
- this.environment.cssAlert.alert("You must select at least one rrc.","validation");
- return false;
- }
- }
- return true;
-
- },
- mouseOverFlag:function(){
- if (this.slideOpened==false)
- this.controlPanelDivFlagIco.attr('src',this.fileRoot+'view/html/img/openSlide.png');
- },
- mouseOutFlag:function(){
- if (this.slideOpened==false)
- this.controlPanelDivFlagIco.attr('src',this.fileRoot+'view/html/img/config.png');
- },
- clickOnFlag:function(){
- if (this.slideOpened==false){
- this.openFlag();
- }else{
- this.discardConfig();
- }
- },
- openFlag:function(){
- if (this.slideOpened==false){
- var $this=this;
- this.dom.animate({height:'+=380'}, 600, function() {
- $this.dom.animate({width:'+=210'},300,function(){
- $this.controlPanelDivComplete.show();
- $this.controlPanelDivFlagIco.attr('src',$this.fileRoot+'view/html/img/closeSlide.png');
- $this.controlPrefixDiv.tinyscrollbar_update();
- });
- });
- this.slideOpened=true;
- }
- },
- closeFlag:function(){
- if (this.slideOpened==true){
- var $this=this;
- this.controlPanelDivComplete.hide();
- this.dom.animate({height:'-=380'}, 600, function() {
- $this.dom.animate({width:'-=210'},300,function(){
- $this.controlPanelDivFlagIco.attr('src',$this.fileRoot+'view/html/img/config.png');
- });
- });
- this.slideOpened=false;
- }
- },
- morePrefixTextbox:function(){
- var element=this.dom.find(".bgplayControlPrefixValue>div>div").first();
- var parent=element.parent();
- element.clone().appendTo(parent).find('input').val("");
- this.controlPrefixDiv.tinyscrollbar_update('bottom');
- },
- lessPrefixTextbox:function(event){
- var element=$(event.target);
- if (this.dom.find(".bgplayControlPrefixValue>div>div").length>1){
- element.parent().remove();
- this.controlPrefixDiv.tinyscrollbar_update();
- }else{
- element.parent().find('input').val("");
- }
- },
-
- /**
- * This method discards the new query parameters
- * @method discardConfig
- */
- discardConfig:function(){
- this.closeFlag();
- this.render();
- },
-
- /**
- * This method applies the new query parameters
- * @method updateConfig
- */
- updateConfig:function(){
- if (!this.environment.params.preventNewQueries==false){
- this.discardConfig();
- return;
- }
- var internalParams, rrcSelected, $this, externalParams;
- if (this.validateAll()==true){
- $this = this;
- this.prefixes = new Array();
- this.dom.find(".bgplayControlPrefixValue input[type=text]").each(function(){
- $this.prefixes.push($(this).val());
- });
-
- rrcSelected=[];
- this.dom.find('input[name=bgplayRrcSelect]:checked').each(function(){
- rrcSelected.push($(this).val());
- });
-
- this.ignoreReannouncements = this.suppressReannounce.is(':checked');
-
- if (this.environment.thisWidget!=null){
- internalParams={
- starttimestamp:this.starttimestampPicker.datetimepicker("getDate").getTime()/1000,
- endtimestamp:this.endtimestampPicker.datetimepicker("getDate").getTime()/1000,
- targets:arrayToString(this.prefixes),
- ignoreReannouncements:this.ignoreReannouncements,
- selectedRrcs:arrayToString(rrcSelected)
- };
-
-
- externalParams = this.environment.jsonWrap.setParams(internalParams);
- try{
- setUrlParam('instant',"",false);
-
- if (this.environment.paramsInUrl == true && this.environment.instances==1){
- setUrlParam("starttime",externalParams.starttime,false);
- setUrlParam("endtime",externalParams.endtime,false);
- setUrlParam("resource",externalParams.resource,false);
- setUrlParam("ignoreReannouncements",externalParams.ignoreReannouncements,false);
- setUrlParam("selectedRrcs",externalParams.selectedRrcs,false);
- }
- window.history.replaceState({"html":this.bgplay.html,"pageTitle":'BGPlayjs'},"", currentUrl);
- }catch(e){
- log('This browser does not support the replaceState function.');
- }
-
- if (!areMapsEquals(internalParams, this.environment.params)){
- this.environment.oldParams=this.environment.params;
- this.environment.thisWidget.update(externalParams);
- this.closeFlag(); //If the widget was not updated then the query parameters are the same, close the flag
- this.eventAggregator.trigger("destroyAll");
- }else{
- this.discardConfig();
- }
- }else{
- setUrlParam("starttimestamp",this.starttimestampPicker.datetimepicker("getDate").getTime()/1000,false);
- setUrlParam("endtimestamp",this.endtimestampPicker.datetimepicker("getDate").getTime()/1000,false);
- setUrlParam("targets",arrayToString(this.prefixes),false); //If the last parameter is true, the new url will be loaded
- setUrlParam("ignoreReannouncements",this.ignoreReannouncements,false);
- setUrlParam("selectedRrcs",stringToArray(rrcSelected),true);
- }
- }
- }
-
- });
-