API Docs for:
Show:

File: view\ControllerView.js

  1. /*
  2. * BGPlay.js #9660
  3. * A web-based service for the visualization of the Internet routing
  4. *
  5. * Copyright (c) 2012 Roma Tre University and RIPE NCC
  6. *
  7. * See the file LICENSE.txt for copying permission.
  8. */
  9.  
  10. /**
  11. * This is a module specific for BGP.
  12. * It provides the query form.
  13. * Template: controller.html
  14. * @class ControllerView
  15. * @module modules
  16. */
  17. var ControllerView=Backbone.View.extend({
  18. events:function(){
  19. return {
  20. "click .bgplayControlAnimationStartPause":"toggle",
  21. "click .bgplayControlAnimationStop":"stopButton",
  22. "click .bgplayControlAnimationPrev":"previousEvent",
  23. "click .bgplayControlAnimationNext":"nextEvent",
  24. "mouseover .bgplayControlPanelDivFlagIco":"mouseOverFlag",
  25. "mouseout .bgplayControlPanelDivFlagIco":"mouseOutFlag",
  26. "click .bgplayControlPanelDivFlagIco":"clickOnFlag",
  27. "change input[name=bgplayControlPrefixValues]":"validateIp",
  28. "click .bgplayControlDiscardButton":"discardConfig",
  29. "click .bgplayControlApplyButton":"updateConfig",
  30. "click .bgplayControlPrefixMore":"morePrefixTextbox",
  31. "click .bgplayControlPrefixDelete":"lessPrefixTextbox"
  32. }
  33. },
  34.  
  35. /**
  36. * The initialization method of this object.
  37. * @method initialize
  38. * @param {Map} A map of parameters
  39. */
  40. initialize:function(){
  41. this.environment=this.options.environment;
  42. this.bgplay=this.environment.bgplay;
  43. this.fileRoot=this.environment.fileRoot;
  44. this.eventAggregator=this.environment.eventAggregator;
  45.  
  46. this.eventAggregator.trigger("moduleLoading", true);
  47. this.animation=false;
  48. this.allEvents=this.bgplay.get("allEvents");
  49. this.prefixes=stringToArray(this.environment.params.targets);
  50. this.selectedRrcs=stringToArray(this.environment.params.selectedRrcs);
  51. this.selectableRrcs=this.environment.config.selectableRrcs;
  52. this.possibleRrcs=this.environment.config.possibleRrcs.removeSubArray(this.selectedRrcs);
  53. this.slideOpened=false;
  54. this.ignoreReannouncements= this.environment.params.ignoreReannouncements || this.environment.config.ignoreReannouncementsByDefault;
  55. this.releasedPlayButton=true;
  56. this.environment.dynamicParams.push('instant');
  57. this.startAnimationInstant=new Instant({id:0,timestamp:this.bgplay.get("starttimestamp")});
  58. this.stopAnimationInstant=new Instant({id:0,timestamp:this.bgplay.get("endtimestamp")});
  59.  
  60. this.eventAggregator.on("destroyAll", function(){
  61. this.destroyMe();
  62. },this);
  63.  
  64. this.bgplay.on("change:cur_instant",function(){
  65. if (this.environment.config.controller.keepTrackCurrentInstant==true){
  66. var instant=this.bgplay.get("cur_instant");
  67. this.environment.params.instant = instant.toString();
  68. try{
  69. if (this.environment.paramsInUrl==true && this.environment.instances==1){
  70. setUrlParam('instant',instant.toString(),false);
  71. window.history.replaceState({"html":this.bgplay.html,"pageTitle":'BGPlayjs'},"", currentUrl);
  72. }
  73. }catch(e){
  74. log("This browser does not support the replaceState function.");
  75. }
  76. }
  77. },this);
  78.  
  79. this.eventAggregator.trigger("autoStartFunction",
  80. {func:
  81. function(){
  82. var initialInstant = this.environment.params.instant || getUrlParam("instant");
  83. if (initialInstant != null && initialInstant!="" && this.environment.instances==1){
  84. initialInstant = initialInstant.split(',');
  85. this.environment.bgplay.set({"cur_instant":new Instant({id:initialInstant[0],timestamp:initialInstant[1]})});
  86. }
  87. }
  88. , context:this});
  89.  
  90. this.eventAggregator.on("animationEnd", function(){
  91. this.stop();
  92. },this);
  93.  
  94. this.eventAggregator.on("animationReload", function(){
  95. this.reload();
  96. },this);
  97.  
  98. this.eventAggregator.on("newSelectionStart", function(value){
  99. this.startAnimationInstant=value;
  100. },this);
  101.  
  102. this.eventAggregator.on("releasePlayButton", function(release){
  103. this.releasedPlayButton=release;
  104. if (this.releasedPlayButton==true){
  105. this.controlAnimationStartPause.css('cursor','auto');
  106. }else{
  107. this.controlAnimationStartPause.css('cursor','wait');
  108. }
  109. },this);
  110.  
  111. this.eventAggregator.on("newSelectionEnd", function(value){
  112. this.stopAnimationInstant=value;
  113. },this);
  114.  
  115. this.render();
  116. log("Controller view loaded.");
  117. this.eventAggregator.trigger("moduleLoading", false);
  118. },
  119.  
  120. /*
  121. * This method creates the pointers to the DOM elements.
  122. */
  123. getDomElements:function(){
  124. this.dom = this.$el;
  125. this.controlAnimationStartPause = this.dom.find('.bgplayControlAnimationStartPause');
  126. this.controlAnimationStop = this.dom.find('.bgplayControlAnimationStop');
  127. this.controlAnimationNext = this.dom.find('.bgplayControlAnimationNext');
  128. this.controlAnimationPrevImage = this.dom.find('.bgplayControlAnimationPrev img');
  129. this.controlPrefixDiv = this.dom.find('.bgplayControlPrefixDiv');
  130. this.starttimestampPicker = this.dom.find('.bgplayStarttimestampPicker');
  131. this.endtimestampPicker = this.dom.find('.bgplayEndtimestampPicker');
  132. this.controlPanelDivFlagIco = this.dom.find('.bgplayControlPanelDivFlagIco');
  133. this.controlPanelDivComplete = this.dom.find('.bgplayControlPanelDivComplete');
  134. this.suppressReannounce = this.dom.find('.bgplaySuppressReannounce');
  135. },
  136.  
  137. /**
  138. * This method draws this module (eg. inject the DOM and elements).
  139. * @method render
  140. */
  141. render:function(){
  142. parseTemplate('controller.html',this,this.el);
  143. this.getDomElements();
  144. this.update();
  145. this.controlPrefixDiv.tinyscrollbar({axis:'y'});
  146.  
  147. this.starttimestampPicker.datetimepicker({
  148. changeMonth: true,
  149. changeYear: true,
  150. hideIfNoPrevNext:true,
  151. timeFormat:'HH:mm:ss',
  152. separator:' ',
  153. dateFormat:'yy/mm/dd',
  154. showSecond: true,
  155. maxDate: "+0"
  156. });
  157.  
  158. this.starttimestampPicker.datetimepicker("setDate",new Date(this.bgplay.get("starttimestamp")*1000));
  159.  
  160. this.endtimestampPicker.datetimepicker({
  161. changeMonth: true,
  162. changeYear: true,
  163. defaultDate:new Date(this.bgplay.get("endtimestamp")*1000),
  164. hideIfNoPrevNext:true,
  165. timeFormat:'HH:mm:ss',
  166. separator:' ',
  167. dateFormat:'yy/mm/dd',
  168. showSecond: true,
  169. maxDate: "+0"
  170. });
  171.  
  172. this.endtimestampPicker.datetimepicker("setDate",new Date(this.bgplay.get("endtimestamp")*1000));
  173.  
  174. return this;
  175. },
  176.  
  177. /**
  178. * This method updates the DOM of the Control Panel without render it again.
  179. * @method update
  180. */
  181. update:function(){
  182. var startStopImages;
  183. startStopImages = this.controlAnimationStartPause.find('img');
  184. if (this.animation==true){
  185. this.controlAnimationPrevImage.hide();
  186. this.controlAnimationNext.hide();
  187. startStopImages.eq(1).hide();
  188.  
  189. startStopImages.eq(0).show();
  190. this.controlAnimationStop.show();
  191.  
  192. }else{
  193. this.controlAnimationStop.hide();
  194. startStopImages.eq(0).hide();
  195.  
  196. startStopImages.eq(1).show();
  197. this.controlAnimationPrevImage.show();
  198. this.controlAnimationNext.show();
  199. }
  200.  
  201.  
  202. },
  203.  
  204. /**
  205. * If this method is invoked during an animation then the animation pauses otherwise the animation starts.
  206. * @method toggle
  207. */
  208. toggle:function(){
  209. if (!this.releasedPlayButton){
  210. return;
  211. }
  212.  
  213. this.closeFlag();
  214. if (this.bgplay.get("cur_instant").get("timestamp") < this.stopAnimationInstant.get("timestamp")){
  215. this.animation=!this.animation;
  216. this.update();
  217. this.eventAggregator.trigger("animate", this.animation);
  218. }
  219. },
  220.  
  221. /**
  222. * This method reloads the animation.
  223. * @method reload
  224. */
  225. reload:function(){
  226. this.bgplay.setCurInstant(this.startAnimationInstant);
  227. this.eventAggregator.trigger("checkPathPosition");
  228. },
  229.  
  230. /**
  231. * This method stops and reloads the animation.
  232. * @method stopButton
  233. */
  234. stopButton:function(){
  235. this.stop();
  236. this.reload();
  237. },
  238.  
  239. /**
  240. * This method stops the animation.
  241. * @method stop
  242. */
  243. stop:function(){
  244. this.animation=false;
  245. this.eventAggregator.trigger("animate", false);
  246. this.update();
  247. },
  248.  
  249. /**
  250. * This method applies the previous event.
  251. * @method previousEvent
  252. */
  253. previousEvent:function(){
  254. var prevInstant, prevEvent, instant;
  255. instant = this.bgplay.get("cur_instant");
  256. prevEvent = this.allEvents.nearest(instant,false,false);
  257. if (prevEvent!=null){
  258. prevInstant = prevEvent.get("instant");
  259. if (!this.environment.config.controller.disableNotSelectedInstants || this.allEvents.compare(prevInstant,this.startAnimationInstant)>=0){
  260. this.bgplay.setCurInstant(prevInstant);
  261. }
  262. }
  263. },
  264.  
  265. /**
  266. * This method applies the next event.
  267. * @method nextEvent
  268. */
  269. nextEvent:function(){
  270. var nextInstant, nextEvent, instant;
  271. instant = this.bgplay.get("cur_instant");
  272. nextEvent = this.allEvents.nearest(instant,true,false);
  273. if (nextEvent!=null){
  274. nextInstant = nextEvent.get("instant");
  275. if (!this.environment.config.controller.disableNotSelectedInstants || this.allEvents.compare(nextInstant,this.stopAnimationInstant)<=0){
  276. this.bgplay.setCurInstant(nextInstant);
  277. }
  278. }
  279. },
  280.  
  281. /**
  282. * This method validates an IP/prefix inserted in the query form.
  283. * @method validateIp
  284. * @return {Boolean} True if the given IP is valid
  285. */
  286. validateIp:function(){
  287. var out, val, $this;
  288. out=true;
  289. $this=this;
  290. this.dom.find("input[name=bgplayControlPrefixValues]").each(function(){
  291. val=$(this).val();
  292. if (! (validateIpv4and6Prefix(val) || validateIpv4and6Address(val))){
  293. $this.environment.cssAlert.alert('Malformed prefix/ip.<br/>A valid ip for ipv4 or ipv6 possibly with netmask is required.','validation');
  294. out=false;
  295. }
  296. });
  297. return out;
  298. },
  299.  
  300. /**
  301. * This method validates the query form.
  302. * @method validateAll
  303. * @return {Boolean} True if the data inserted in the query form is valid
  304. */
  305. validateAll:function(){
  306. //A trick to solve a bug of the timepicker add-on (I'm triggering a keyUp to force the update of the date)
  307. this.starttimestampPicker.keyup();
  308. this.endtimestampPicker.keyup();
  309.  
  310. return this.validateIp() && this.validateInterval() && this.validateRrcs();
  311. },
  312.  
  313. /**
  314. * This method validates the time interval.
  315. * @method validateInterval
  316. * @return {Boolean} True if the time interval is valid
  317. */
  318. validateInterval:function(){
  319. if (this.starttimestampPicker.datepicker("getDate").getTime()>this.endtimestampPicker.datepicker("getDate").getTime()){
  320. 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");
  321. return false;
  322. }
  323. return true;
  324. },
  325.  
  326. /**
  327. * This method validates a set of route collectors
  328. * @method validateRrcs
  329. * @return {Boolean} True if the set of RRCs is valid
  330. */
  331. validateRrcs:function(){
  332. if (this.selectableRrcs){
  333. var rrcSelected=[];
  334. this.dom.find('input[name=bgplayRrcSelect]:checked').each(function(){
  335. rrcSelected.push($(this).val());
  336. });
  337. if (rrcSelected.length==0){
  338. this.environment.cssAlert.alert("You must select at least one rrc.","validation");
  339. return false;
  340. }
  341. }
  342. return true;
  343.  
  344. },
  345. mouseOverFlag:function(){
  346. if (this.slideOpened==false)
  347. this.controlPanelDivFlagIco.attr('src',this.fileRoot+'view/html/img/openSlide.png');
  348. },
  349. mouseOutFlag:function(){
  350. if (this.slideOpened==false)
  351. this.controlPanelDivFlagIco.attr('src',this.fileRoot+'view/html/img/config.png');
  352. },
  353. clickOnFlag:function(){
  354. if (this.slideOpened==false){
  355. this.openFlag();
  356. }else{
  357. this.discardConfig();
  358. }
  359. },
  360. openFlag:function(){
  361. if (this.slideOpened==false){
  362. var $this=this;
  363. this.dom.animate({height:'+=380'}, 600, function() {
  364. $this.dom.animate({width:'+=210'},300,function(){
  365. $this.controlPanelDivComplete.show();
  366. $this.controlPanelDivFlagIco.attr('src',$this.fileRoot+'view/html/img/closeSlide.png');
  367. $this.controlPrefixDiv.tinyscrollbar_update();
  368. });
  369. });
  370. this.slideOpened=true;
  371. }
  372. },
  373. closeFlag:function(){
  374. if (this.slideOpened==true){
  375. var $this=this;
  376. this.controlPanelDivComplete.hide();
  377. this.dom.animate({height:'-=380'}, 600, function() {
  378. $this.dom.animate({width:'-=210'},300,function(){
  379. $this.controlPanelDivFlagIco.attr('src',$this.fileRoot+'view/html/img/config.png');
  380. });
  381. });
  382. this.slideOpened=false;
  383. }
  384. },
  385. morePrefixTextbox:function(){
  386. var element=this.dom.find(".bgplayControlPrefixValue>div>div").first();
  387. var parent=element.parent();
  388. element.clone().appendTo(parent).find('input').val("");
  389. this.controlPrefixDiv.tinyscrollbar_update('bottom');
  390. },
  391. lessPrefixTextbox:function(event){
  392. var element=$(event.target);
  393. if (this.dom.find(".bgplayControlPrefixValue>div>div").length>1){
  394. element.parent().remove();
  395. this.controlPrefixDiv.tinyscrollbar_update();
  396. }else{
  397. element.parent().find('input').val("");
  398. }
  399. },
  400.  
  401. /**
  402. * This method discards the new query parameters
  403. * @method discardConfig
  404. */
  405. discardConfig:function(){
  406. this.closeFlag();
  407. this.render();
  408. },
  409.  
  410. /**
  411. * This method applies the new query parameters
  412. * @method updateConfig
  413. */
  414. updateConfig:function(){
  415. if (!this.environment.params.preventNewQueries==false){
  416. this.discardConfig();
  417. return;
  418. }
  419. var internalParams, rrcSelected, $this, externalParams;
  420. if (this.validateAll()==true){
  421. $this = this;
  422. this.prefixes = new Array();
  423. this.dom.find(".bgplayControlPrefixValue input[type=text]").each(function(){
  424. $this.prefixes.push($(this).val());
  425. });
  426.  
  427. rrcSelected=[];
  428. this.dom.find('input[name=bgplayRrcSelect]:checked').each(function(){
  429. rrcSelected.push($(this).val());
  430. });
  431.  
  432. this.ignoreReannouncements = this.suppressReannounce.is(':checked');
  433.  
  434. if (this.environment.thisWidget!=null){
  435. internalParams={
  436. starttimestamp:this.starttimestampPicker.datetimepicker("getDate").getTime()/1000,
  437. endtimestamp:this.endtimestampPicker.datetimepicker("getDate").getTime()/1000,
  438. targets:arrayToString(this.prefixes),
  439. ignoreReannouncements:this.ignoreReannouncements,
  440. selectedRrcs:arrayToString(rrcSelected)
  441. };
  442.  
  443.  
  444. externalParams = this.environment.jsonWrap.setParams(internalParams);
  445. try{
  446. setUrlParam('instant',"",false);
  447.  
  448. if (this.environment.paramsInUrl == true && this.environment.instances==1){
  449. setUrlParam("starttime",externalParams.starttime,false);
  450. setUrlParam("endtime",externalParams.endtime,false);
  451. setUrlParam("resource",externalParams.resource,false);
  452. setUrlParam("ignoreReannouncements",externalParams.ignoreReannouncements,false);
  453. setUrlParam("selectedRrcs",externalParams.selectedRrcs,false);
  454. }
  455. window.history.replaceState({"html":this.bgplay.html,"pageTitle":'BGPlayjs'},"", currentUrl);
  456. }catch(e){
  457. log('This browser does not support the replaceState function.');
  458. }
  459.  
  460. if (!areMapsEquals(internalParams, this.environment.params)){
  461. this.environment.oldParams=this.environment.params;
  462. this.environment.thisWidget.update(externalParams);
  463. this.closeFlag(); //If the widget was not updated then the query parameters are the same, close the flag
  464. this.eventAggregator.trigger("destroyAll");
  465. }else{
  466. this.discardConfig();
  467. }
  468. }else{
  469. setUrlParam("starttimestamp",this.starttimestampPicker.datetimepicker("getDate").getTime()/1000,false);
  470. setUrlParam("endtimestamp",this.endtimestampPicker.datetimepicker("getDate").getTime()/1000,false);
  471. setUrlParam("targets",arrayToString(this.prefixes),false); //If the last parameter is true, the new url will be loaded
  472. setUrlParam("ignoreReannouncements",this.ignoreReannouncements,false);
  473. setUrlParam("selectedRrcs",stringToArray(rrcSelected),true);
  474. }
  475. }
  476. }
  477.  
  478. });