<commit_before>import warning from 'warning'
import React, { PropTypes } from 'react'
import History from './History'
import MatchCountProvider from './MatchCountProvider'
import {
  history as historyType,
  location as locationType,
  router as routerType
} from './PropTypes'

class Router extends React.Component {
  static propTypes = {
    history: historyType,
    location: locationType,
    children: PropTypes.oneOfType([ PropTypes.node, PropTypes.func ]),
    createHref: PropTypes.func,
    onPush: PropTypes.func,
    onReplace: PropTypes.func
  }

  static defaultProps = {
    createHref(to) {
      return this.props.history.createHref(to)
    },
    onPush(location) {
      if (this.props.history) {
        this.props.history.push(location)
      } else {
        warning(
          false,
          'Missing <Router history> prop; <Link>s won\'t work'
        )
      }
    },
    onReplace(location) {
      if (this.props.history) {
        this.props.history.replace(location)
      } else {
        warning(
          false,
          'Missing <Router history> prop; <Redirect>s won\'t work'
        )
      }
    }
  }

  static childContextTypes = {
    router: routerType.isRequired
  }

  getChildContext() {
    return {
      router: {
        createHref: this.createHref,
        transitionTo: this.transitionTo,
        replaceWith: this.replaceWith,
        blockTransitions: this.blockTransitions
      }
    }
  }

  createHref = (to) => {
    return this.props.createHref.call(this, to)
  }

  transitionTo = (location) => {
    this.props.onPush.call(this, location)
  }

  replaceWith = (location) => {
    this.props.onReplace.call(this, location)
  }

  blockTransitions = (getPromptMessage) => {
    return this.props.history.listenBefore(getPromptMessage)
  }

  render() {
    const { children, history, location } = this.props

    return (
      <History history={history} location={location}>
        {({ location }) => (
          <MatchCountProvider>
            {typeof children === 'function' ? (
              children({ location })
            ) : React.Children.count(children) > 1 ? (

{children}

            ) : (
              children
            )}
          </MatchCountProvider>
        )}
      </History>
    )
  }
}

export default Router
<commit_msg>Use expressions instead of function bodies<commit_after>import warning from 'warning'
import React, { PropTypes } from 'react'
import History from './History'
import MatchCountProvider from './MatchCountProvider'
import {
  history as historyType,
  location as locationType,
  router as routerType
} from './PropTypes'

class Router extends React.Component {
  static propTypes = {
    history: historyType,
    location: locationType,
    children: PropTypes.oneOfType([ PropTypes.node, PropTypes.func ]),
    createHref: PropTypes.func,
    onPush: PropTypes.func,
    onReplace: PropTypes.func
  }

  static defaultProps = {
    createHref(to) {
      return this.props.history.createHref(to)
    },
    onPush(location) {
      if (this.props.history) {
        this.props.history.push(location)
      } else {
        warning(
          false,
          'Missing <Router history> prop; <Link>s won\'t work'
        )
      }
    },
    onReplace(location) {
      if (this.props.history) {
        this.props.history.replace(location)
      } else {
        warning(
          false,
          'Missing <Router history> prop; <Redirect>s won\'t work'
        )
      }
    }
  }

  static childContextTypes = {
    router: routerType.isRequired
  }

  getChildContext() {
    return {
      router: {
        createHref: this.createHref,
        transitionTo: this.transitionTo,
        replaceWith: this.replaceWith,
        blockTransitions: this.blockTransitions
      }
    }
  }

  createHref = (to) =>
    this.props.createHref.call(this, to)

  transitionTo = (location) =>
    this.props.onPush.call(this, location)

  replaceWith = (location) =>
    this.props.onReplace.call(this, location)

  blockTransitions = (getPromptMessage) =>
    this.props.history.listenBefore(getPromptMessage)

  render() {
    const { children, history, location } = this.props

    return (
      <History history={history} location={location}>
        {({ location }) => (
          <MatchCountProvider>
            {typeof children === 'function' ? (
              children({ location })
            ) : React.Children.count(children) > 1 ? (

{children}

            ) : (
              children
            )}
          </MatchCountProvider>
        )}
      </History>
    )
  }
}

export default Router
<|endoftext|>


<commit_before>this.GobiertoBudgetConsultations.ConsultationResponsesController = (function() {
  function ConsultationResponsesController() {}

  ConsultationResponsesController.prototype.new = function() {
    _runConsultationApplication();
  };

  function _runConsultationApplication() {
    $(document).on('mouseenter', '.not-allowed', function(e){
      $(this).tipsy({offset: -40, className: 'tip-warning', fade: true, html: true, gravity: $.fn.tipsy.autoBounds(-18, 's'), opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('mouseenter', '.budget-status-figure', function(e){
      $(this).tipsy({ offset: isMobile() ? -20 : 20, className: 'tip-info', fade: true, html: true, gravity: isMobile() ? 's' : 'n', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('mouseenter', '.consultation-status-error', function(e){
      $(this).tipsy({ className: 'tip-warning', fade: true, html: true, gravity: 's', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '[data-tipsy-close]', function(e){
      $('.tipsy').remove();
    });

    var bus = new Vue();

    Vue.component('card-description', {
      props: ['card', 'figures'],
      template: (isMobile() ? '#card-description-mobile'  : '#card-description-desktop'),
      methods: {
        beforeEnter: function (el) {
          el.style.opacity = 0
        },
        enter: function (el, done) {
          $(el).velocity("transition.slideDownIn", {duration: 200, delay: 100, complete: done});
        },
        leave: function (el, done) {
          $(el).velocity("transition.slideUpOut", {duration: 200, complete: done});
        }
      }
    });

    Vue.component('consultation-card', {
      props: ['card', 'active', 'figures'],
      template: (isMobile() ? '#card-mobile'  : '#card-desktop'),
      computed: {
        iconForChoice: function(){
          if(this.card.choice === null) return;

          if(this.card.choice > 0) {
            return "fa-arrow-up";
          } else if (this.card.choice == 0){
            return "fa-circle";
          } else if (this.card.choice < 0){
            return "fa-arrow-down";
          }
        }
      },
      methods: {
        setActive: function(card, e) {
          $('.tipsy').remove();

          // Send the active event to the bus
          bus.$emit('active', card);

          // Save selected card
          var self = this;

          card.toggleDesc = !card.toggleDesc;

          // Reset value
          card.hidden = null;

          // Stick it
          $(".desktop .consultation-info").stick_in_parent();
        }
      }
    });

    Vue.component('budget-box', {
      props: ['card', 'figures'],
      template: '#budget-box',
      methods: {
        showModal: function(d) {
          bus.$emit('open', d);
        },
        makeChoice: function(e) {
          e.preventDefault();
          $('.tipsy').remove();
          bus.$emit('cardOptionChosen', $(e.target), this.card);
        }
      }
    });

    Vue.component('budget-calculator', {
      props: ['active', 'next', 'statusText', 'status'],
      template: '#budget-calculator',
      methods: {
        nextScreen: function(e){
          e.preventDefault();
          bus.$emit('cardOptionChosen', null, null);
        },
        submitConsultation: function(e){
          e.preventDefault();
          bus.$emit('submitConsultation');
        },
        showConsultationStatusError: function(e){
          e.preventDefault();
        }
      }
    });

    Vue.component('description-modal', {
      props: ['current'],
      template: '#description-modal',
      methods: {
        hideModal: function() {
          bus.$emit('close');
        }
      }
    });

    var app = new Vue({
      el: (isMobile() ? "#consultation-mobile-app" : "#consultation-desktop-app"),
      data: {
        figures: false,
        active: false,
        modal: false,
        next: false,
        current: null,
        cards: [],
      },
      computed: {
        statusText: function(){
          return I18n.t('gobierto_budget_consultations.consultation_statuses.' + this.status);
        },
        status: function(){
          var possitiveCards = 0, negativeCards = 0;

          this.$data.cards.forEach(function(card){
            if(card.choice > 0) {
              possitiveCards++;
            } else if (card.choice < 0) {
              negativeCards++;
            }
          });
          if(possitiveCards === negativeCards){
            return 'balance';
          } else if (possitiveCards > negativeCards){
            return 'deficit';
          } else {
            return 'surplus';
          }
        }
      },
      methods: {
        fetchData: function(){
          var self = this;
          var url = $(self.$options.el).data('data-url');
          $.ajax({
            url: url,
            dataType: 'json',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            },
            success: function(response, textStatus, jqXHR){
              if(jqXHR.status == 200){
                Vue.set(self, 'cards', response);
              } else {
                // TODO: handle errors
              }
            },
          });
        },
        cardOptionChosenHandler: function($el, currentCard){
          this.choiceCardAndOpenNext($el, currentCard);
          var allSelected = true;
          app.$data.cards.forEach(function(card){
            if(card.choice === null)
              allSelected = false;
          });

          if(allSelected === true){
            Vue.set(app, 'next', true);
            $('body').animate({
              scrollTop: $(app.$el).offset().top - 25
            }, 500);
          }
        },
        choiceCardAndOpenNext: function($el, currentCard){
          if(currentCard !== null){
            app.$data.cards.forEach(function(card){
              if(currentCard === card) {
                card.choice = $el.data('value');
                card.toggleDesc = false;
              }
            });
          }
          var found = false;
          app.$data.cards.forEach(function(card){
            if(!found && card.choice === null){
              card.toggleDesc = true;
              found = true;
              bus.$emit('active', card);
            }
          });
        },
        submitConsultation: function(){
          var self = this;
          var url = $(self.$options.el).data('submit-url');
          var data = app.$data.cards.map(function(card){
            return {
              item_id: card.id,
              selected_option: card.choice
            }
          });
          $.ajax({
            type: "POST",
            data: {
              consultation_response: {
                selected_options: data
              }
            },
            url: url,
            dataType: 'script',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            }
          });
        }
      },
      created: function() {
        $(this.$options.el).show();
        this.fetchData();

        bus.$on('active', function(currentCard) {
          Vue.set(app, 'active', true);

          app.$data.cards.forEach(function(card){
            if(currentCard != card)
              card.toggleDesc = false;
          });

          var $target = $('[data-card-id="'+currentCard.id+'"]');
          var $targetDescription = $('[data-card-description-id="'+currentCard.id+'"]');
          if($targetDescription.length){
            var offset = $target.offset().top - 200;
            $targetDescription.css({ top: offset + 'px' });
          }

          window.setTimeout(function(){
            // Scroll to selected card
            // Set the description status
            $('body').animate({
              scrollTop: $target.offset().top - (isMobile() ? 25 : 85)
            }, 300, function() {
              // Set individual card state
              if(isMobile()){
                // Once animation ends, check if the span is visible
                var isVisible = $target.find('.visibilityCheck').visible();

                if (isVisible !== 'undefined') {
                  // If is not visible, set hidden to true
                  currentCard.hidden = isVisible ? false : true;
                }
              }
            });
          }, (isMobile() ? 250 : 0));
        });

        bus.$on('open', function(d) {
          Vue.set(app, 'current', d);
          Vue.set(app, 'modal', true);
        });

        bus.$on('close', function() {
          Vue.set(app, 'modal', false);
        });

        bus.$on('cardOptionChosen', this.cardOptionChosenHandler);

        bus.$on('submitConsultation', this.submitConsultation);
      },
    });
  }

  return ConsultationResponsesController;
})();

this.GobiertoBudgetConsultations.consultation_responses_controller = new GobiertoBudgetConsultations.ConsultationResponsesController;
<commit_msg>Trigger tooltips on click<commit_after>this.GobiertoBudgetConsultations.ConsultationResponsesController = (function() {
  function ConsultationResponsesController() {}

  ConsultationResponsesController.prototype.new = function() {
    _runConsultationApplication();
  };

  function _runConsultationApplication() {
    $(document).on('click', '.not-allowed', function(e){
      $(this).tipsy({offset: -40, className: 'tip-warning', fade: true, html: true, gravity: $.fn.tipsy.autoBounds(-18, 's'), opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '.budget-status-figure', function(e){
      $(this).tipsy({ offset: isMobile() ? -20 : 20, className: 'tip-info', fade: true, html: true, gravity: isMobile() ? 's' : 'n', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '.consultation-status-error', function(e){
      $(this).tipsy({ className: 'tip-warning', fade: true, html: true, gravity: 's', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '[data-tipsy-close]', function(e){
      $('.tipsy').remove();
    });

    var bus = new Vue();

    Vue.component('card-description', {
      props: ['card', 'figures'],
      template: (isMobile() ? '#card-description-mobile'  : '#card-description-desktop'),
      methods: {
        beforeEnter: function (el) {
          el.style.opacity = 0
        },
        enter: function (el, done) {
          $(el).velocity("transition.slideDownIn", {duration: 200, delay: 100, complete: done});
        },
        leave: function (el, done) {
          $(el).velocity("transition.slideUpOut", {duration: 200, complete: done});
        }
      }
    });

    Vue.component('consultation-card', {
      props: ['card', 'active', 'figures'],
      template: (isMobile() ? '#card-mobile'  : '#card-desktop'),
      computed: {
        iconForChoice: function(){
          if(this.card.choice === null) return;

          if(this.card.choice > 0) {
            return "fa-arrow-up";
          } else if (this.card.choice == 0){
            return "fa-circle";
          } else if (this.card.choice < 0){
            return "fa-arrow-down";
          }
        }
      },
      methods: {
        setActive: function(card, e) {
          $('.tipsy').remove();

          // Send the active event to the bus
          bus.$emit('active', card);

          // Save selected card
          var self = this;

          card.toggleDesc = !card.toggleDesc;

          // Reset value
          card.hidden = null;

          // Stick it
          $(".desktop .consultation-info").stick_in_parent();
        }
      }
    });

    Vue.component('budget-box', {
      props: ['card', 'figures'],
      template: '#budget-box',
      methods: {
        showModal: function(d) {
          bus.$emit('open', d);
        },
        makeChoice: function(e) {
          e.preventDefault();
          $('.tipsy').remove();
          bus.$emit('cardOptionChosen', $(e.target), this.card);
        }
      }
    });

    Vue.component('budget-calculator', {
      props: ['active', 'next', 'statusText', 'status'],
      template: '#budget-calculator',
      methods: {
        nextScreen: function(e){
          e.preventDefault();
          bus.$emit('cardOptionChosen', null, null);
        },
        submitConsultation: function(e){
          e.preventDefault();
          bus.$emit('submitConsultation');
        },
        showConsultationStatusError: function(e){
          e.preventDefault();
        }
      }
    });

    Vue.component('description-modal', {
      props: ['current'],
      template: '#description-modal',
      methods: {
        hideModal: function() {
          bus.$emit('close');
        }
      }
    });

    var app = new Vue({
      el: (isMobile() ? "#consultation-mobile-app" : "#consultation-desktop-app"),
      data: {
        figures: false,
        active: false,
        modal: false,
        next: false,
        current: null,
        cards: [],
      },
      computed: {
        statusText: function(){
          return I18n.t('gobierto_budget_consultations.consultation_statuses.' + this.status);
        },
        status: function(){
          var possitiveCards = 0, negativeCards = 0;

          this.$data.cards.forEach(function(card){
            if(card.choice > 0) {
              possitiveCards++;
            } else if (card.choice < 0) {
              negativeCards++;
            }
          });
          if(possitiveCards === negativeCards){
            return 'balance';
          } else if (possitiveCards > negativeCards){
            return 'deficit';
          } else {
            return 'surplus';
          }
        }
      },
      methods: {
        fetchData: function(){
          var self = this;
          var url = $(self.$options.el).data('data-url');
          $.ajax({
            url: url,
            dataType: 'json',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            },
            success: function(response, textStatus, jqXHR){
              if(jqXHR.status == 200){
                Vue.set(self, 'cards', response);
              } else {
                // TODO: handle errors
              }
            },
          });
        },
        cardOptionChosenHandler: function($el, currentCard){
          this.choiceCardAndOpenNext($el, currentCard);
          var allSelected = true;
          app.$data.cards.forEach(function(card){
            if(card.choice === null)
              allSelected = false;
          });

          if(allSelected === true){
            Vue.set(app, 'next', true);
            $('body').animate({
              scrollTop: $(app.$el).offset().top - 25
            }, 500);
          }
        },
        choiceCardAndOpenNext: function($el, currentCard){
          if(currentCard !== null){
            app.$data.cards.forEach(function(card){
              if(currentCard === card) {
                card.choice = $el.data('value');
                card.toggleDesc = false;
              }
            });
          }
          var found = false;
          app.$data.cards.forEach(function(card){
            if(!found && card.choice === null){
              card.toggleDesc = true;
              found = true;
              bus.$emit('active', card);
            }
          });
        },
        submitConsultation: function(){
          var self = this;
          var url = $(self.$options.el).data('submit-url');
          var data = app.$data.cards.map(function(card){
            return {
              item_id: card.id,
              selected_option: card.choice
            }
          });
          $.ajax({
            type: "POST",
            data: {
              consultation_response: {
                selected_options: data
              }
            },
            url: url,
            dataType: 'script',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            }
          });
        }
      },
      created: function() {
        $(this.$options.el).show();
        this.fetchData();

        bus.$on('active', function(currentCard) {
          Vue.set(app, 'active', true);

          app.$data.cards.forEach(function(card){
            if(currentCard != card)
              card.toggleDesc = false;
          });

          var $target = $('[data-card-id="'+currentCard.id+'"]');
          var $targetDescription = $('[data-card-description-id="'+currentCard.id+'"]');
          if($targetDescription.length){
            var offset = $target.offset().top - 200;
            $targetDescription.css({ top: offset + 'px' });
          }

          window.setTimeout(function(){
            // Scroll to selected card
            // Set the description status
            $('body').animate({
              scrollTop: $target.offset().top - (isMobile() ? 25 : 85)
            }, 300, function() {
              // Set individual card state
              if(isMobile()){
                // Once animation ends, check if the span is visible
                var isVisible = $target.find('.visibilityCheck').visible();

                if (isVisible !== 'undefined') {
                  // If is not visible, set hidden to true
                  currentCard.hidden = isVisible ? false : true;
                }
              }
            });
          }, (isMobile() ? 250 : 0));
        });

        bus.$on('open', function(d) {
          Vue.set(app, 'current', d);
          Vue.set(app, 'modal', true);
        });

        bus.$on('close', function() {
          Vue.set(app, 'modal', false);
        });

        bus.$on('cardOptionChosen', this.cardOptionChosenHandler);

        bus.$on('submitConsultation', this.submitConsultation);
      },
    });
  }

  return ConsultationResponsesController;
})();

this.GobiertoBudgetConsultations.consultation_responses_controller = new GobiertoBudgetConsultations.ConsultationResponsesController;
<|endoftext|>


<commit_before>// var _ = require('lodash/core');
'use strict'

var map = angular.module('myApp.map', ['ngRoute']);

map.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
  $routeProvider.when('/', {
    templateUrl: '/map.html',
    controller: 'mapCtrl'
  })

  $locationProvider.html5Mode({
    enabled: true,
    requireBase: false
  });
}])

map.controller('schangeCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
  //console.log("FROM STAGE: "+$routeParams.from);
  //console.log("TO STAGE: "+$routeParams.to);
  console.log("HELLO STAGE: " + $routeParams.hello);
}]);

map.controller('mapCtrl', ['$scope', '$http', 'socket', function ($scope, $http, socket) {
  $scope.pstage = '';
  $scope.cstage = '';

  // $scope.sendStage = function () {
  //   socket.emit('visualMsg', 'FROM visual-FRONT');
  //   console.log("msg sent");
  // }

  socket.on('visualMsg', function (data) {
    console.log("visual-front receive: " + data);
    var stages = data.split('->')
    $scope.pstage = stages[0];
    $scope.cstage = stages[1];
  });

  // $scope.$watch('message', (after, before) => {
  //   console.log(after);
  //   // socket.emit('muzicode-message', 'This is a message from VISUAL BACKEND');
  // })

  $http.get('/maps/').success(function (data) {
    $scope.iniData = data;
  });

  // room: room name (default "default")
  // pin: room pin/ password(default "")
  // name: control input name (required)
  // client: optional client identification

  $http({
    url: 'http://127.0.0.1:3000/input',
    method: 'POST',
    data: {
      contentType: 'application/x-www-form-urlencoded',
      room: "",
      pin: "",
      name: "visual",
      client: "visual",
      stage: $scope.stage
    }
  }).success(function (data) {
    console.log("Success" + data);
  }).error(function (data) {
    console.log("Erro: " + data);
  })
}])

map.directive('d3Map', ['d3Service', '$http', '$window', function (d3Service, $http, $window) {
  return {
    restrict: 'EA',
    scope: false,
    link: function (scope, element, attrs) {

      $http.get('/maps/').success(function (data) {
        var iniData = data;
        console.log("GOT MAP: " + JSON.stringify(iniData));

        // EXTRACT INFO FROM DATA
        // get normal stages (except bc and summit)
        var stages = _.remove(iniData, function (n) {
          if (n.stage === 'summit' || n.stage === 'basecamp')
            return false;
          return true;
        })

        // collect path names to help sort stages i.e. a, b, c...
        var pathCode = _.orderBy(_.uniq(_.map(stages, function (o) { return _.head(o.stage); })));
        var NUM_COLUMN = pathCode.length; // column of the map
        var NUM_ROW = 0;
        console.log(pathCode);

        // sort normal stages by path and stage number in desc order
        // sample: [[a2,a1],[b2,b1],[c2,c1]]
        var pathStageContainer = [];
        _.forEach(pathCode, function (obj) {
          var spePath = _.filter(stages, function (o) { return _.head(o.stage) == obj; });
          var orderedSpePath = _.orderBy(spePath, ['stage'], ['desc']);
          var pathHeight = orderedSpePath.length + 2;
          // get the maximum stages in one path as the NUM_ROW
          pathHeight > NUM_ROW ? NUM_ROW = pathHeight : 0;
          pathStageContainer.push(orderedSpePath);
        });

        // DISPLAY SETTINGS
        //var NUM_COLUMN = 3; // column of the map
        //var NUM_ROW = 10; // row of the map
        var RECT_WIDTH = 120;
        var RECT_HEIGHT = 40;

        var MAP_WIDTH = $window.innerWidth;
        var MAP_HEIGHT = $window.innerHeight;
        console.log("WINDOW: width: " + MAP_WIDTH + "  height: " + MAP_HEIGHT);

        var INI_X, RECT_X, INI_Y, RECT_Y, TEXT_X, TEXT_Y, X_OFFSET, Y_OFFSET, LEFT_X;

        INI_Y = RECT_Y = MAP_HEIGHT * 0.1;

        X_OFFSET = MAP_WIDTH / NUM_COLUMN;
        Y_OFFSET = MAP_HEIGHT * 0.8 / NUM_ROW;

        LEFT_X = MAP_WIDTH / (NUM_COLUMN * 2) - RECT_WIDTH / 2;

        // DRAW
        d3Service.d3().then(function (d3) {
          var canvas = d3.select(element[0]).append('svg').attr('width', MAP_WIDTH).attr('height', MAP_HEIGHT).attr('id', 'map-container');

          var data = []; // data contains data with x, y and are ordered
          var length = 0;
          var pathData;
          var i = 0;
          var j = 0;

          // DATA PROCESS
          // data are processed seperately: summit + normal stages + basecamp
          var summitData = _.find(iniData, { 'stage': 'summit' });
          // if the summit exists, draw summit
          if (summitData.visual) {
            summitData.x = (NUM_COLUMN - 1) / 2;
            summitData.y = 0;
            summitData = _.castArray(summitData);
            data = summitData;
          }

          _.forEach(pathStageContainer, function (pathData) {
            _.forEach(pathData, function (o) {
              if (_.isObject(o)) {
                o.x = i;
                o.y = j + 1;
                j++;
              }
            });
            j = 0;
            i++;
            data = _.concat(data, pathData);
          });

          var bcData = _.find(iniData, { 'stage': 'basecamp' });
          if (bcData.visual) {
            // change state for the basecamp and its subsequent stage
            bcData.state = "active";
            var cueList = _.split(bcData.cue, '/');
            _.forEach(cueList, function (cue) {
              var stage = _.find(data, { stage: cue });
              stage.state = "revealed";
            });

            bcData.x = (NUM_COLUMN - 1) / 2;
            bcData.y = NUM_ROW - 1;
            bcData = _.castArray(bcData);
            data = _.concat(data, bcData);
          }

          // Data updated
          var customPath = [];
          scope.$watch('cstage', function () {
            console.log("??/");
            if (scope.cstage) {

              // turn the previous active stage into past -  succ / fail
              var ps = _.find(data, { 'stage': scope.pstage })
              console.log(ps);
              ps.state = "rev_succ";
              customPath.push(scope.pstage)
              console.log("ADD STAGE " + scope.pstage + " TO CUSTOM PATH");
              updateMapStage(ps, 0);

              // active new path
              var cs = _.find(data, { 'stage': scope.cstage });
              console.log(cs);
              cs.state = 'active';
              updateMapStage(cs, 1);

              // ps cue stage
              var psCues = ps.cue.split('/');
              console.log(psCues);
              console.log(cs.stage);
              var psCuesWithoutCs = _.filter(psCues, function (s) { return s !== cs.stage });
              console.log(psCuesWithoutCs);

              // get missed stages
              var revealeds = _.filter(data, { 'state': 'revealed' })
              console.log(revealeds);
              _.forEach(revealeds, function (rs) {
                console.log(rs);
                if (_.isObject(rs))
                  rs.state = 'missed';
                updateMapStage(rs, 1);
              });

              // reveal new stages
              var fss = _.split(cs.cue, '/');
              var flist = []
              console.log(fss);
              _.forEach(fss, function (c) {
                var fs = _.find(data, { 'stage': c })
                fs.state = 'revealed';
                flist.push(fs);
                updateMapStage(fs, 2);
              });

              updateMapLine(ps, cs, flist, psCuesWithoutCs);

              // CALL IMAGE DISPLAY / CONTENT / WHATSOEVER
              // END DATA PROCESS
            }
          });

          // COLLECT CUSTOM PATH
          // DRAW
          drawArrow(canvas, data);
          drawStage(canvas, data);

          function drawArrow(canvas, data) {
            _.forEach(data, function (cStageDatum) {
              if (cStageDatum && cStageDatum.cue) {
                // get all the cues of this stage
                var cueList = _.split(cStageDatum.cue, '/');

                var cueStageDatum;
                _.forEach(cueList, function (cueStage) {
                  cueStageDatum = _.find(data, { 'stage': _.trim(cueStage) });
                  canvas
                    .append('line')
                    .attr("x1", function () { return LEFT_X + cStageDatum.x * X_OFFSET + RECT_WIDTH / 2 })
                    .attr("y1", function () { return INI_Y + cStageDatum.y * Y_OFFSET + RECT_HEIGHT / 2 })
                    .attr("x2", function () { return LEFT_X + cueStageDatum.x * X_OFFSET + RECT_WIDTH / 2 })
                    .attr("y2", function () { return INI_Y + cueStageDatum.y * Y_OFFSET + RECT_HEIGHT / 2 })
                    .style("stroke-dasharray", ("6, 6"))
                    .attr('stroke', function () { return getLineColor(cStageDatum); })
                    .attr('stroke-width', '2px')
                    .attr("id", function () {
                      return cueStageDatum.stage ? (cStageDatum.stage + '_' + cueStageDatum.stage
                      ) : ('line_' + cStageDatum.stage)
                    })
                    .attr('opacity', function () { return getLineOpacity(cStageDatum.state, cueStageDatum.state) })
                });
              }
            });
          }

          function drawStage(canvas, data) {
            // console.log(data);
            canvas
              .selectAll('rect')
              .data(data)
              .enter()
              .append('rect')
              .attr('x', function (d) { return LEFT_X + d.x * X_OFFSET })
              .attr('y', function (d) { return INI_Y + d.y * Y_OFFSET })
              .attr('width', RECT_WIDTH)
              .attr('height', RECT_HEIGHT)
              .attr('fill', function (d) { return getRectFillColor(d.state); })
              .attr('stroke', function (d) { return getLineColor(d.state) })
              .attr('stroke-width', '2px')
              .attr('opacity', function (d) { return getStageOpacity(d.state); })
              .attr('id', function (d) { return 'rect_' + d.stage })
            canvas
              .selectAll('text')
              .data(data)
              .enter()
              .append('text')
              .text(function (d) { return d.stage; })
              .attr('x', function (d) { return LEFT_X + d.x * X_OFFSET + RECT_WIDTH / 2 })
              .attr('y', function (d) { return INI_Y + d.y * Y_OFFSET + 25 })
              .attr('text-anchor', 'middle')
              .attr('font-size', '20px')
              .attr('fill', function (d) { return getTextColor(d.state) })
              .attr('id', function (d) { return d.stage })
              .attr('opacity', function (d) { return getStageOpacity(d.state); })
          }
        });
      })

      var INTERVAL = 1000;
      function updateMapStage(stage, delay) {
        var sname = stage.stage;
        var state;
        if (_.indexOf(sname) === 'path') {
          state = 'path';  // speical
        } else {
          state = stage.state;
        }

        console.log(sname);
        d3Service.d3().then(function (d3) {
          // update rect
          d3.select('#rect_' + sname)
            .transition()
            .delay(delay * INTERVAL)
            .duration(INTERVAL)
            .attr('fill', function () { return getRectFillColor(state) })
            .attr('stroke', function () { return getLineColor(state) })
            .attr('opacity', function () { return getStageOpacity(state) })

          // update text
          d3.select('#' + sname)
            .transition()
            .delay(delay * INTERVAL)
            .duration(INTERVAL)
            .attr('fill', function () { return getTextColor(state) })
            .attr('opacity', function () { return getStageOpacity(state) })
        })
      }

      function updateMapLine(p, c, fss, pcstages) {
        var pstage = p.stage;
        var cstage = c.stage;
        var ps = p.state;
        var cs = c.state;
        var fs, fstage;

        d3Service.d3().then(function (d3) {
          if (fss) {
            _.forEach(fss, function (f) {
              fstage = f.stage;
              fs = f.state;

              // the line linking pstage and cstage -> turn solid and change color
              d3.select('#' + pstage + '_' + cstage)
                .transition()
                .delay(INTERVAL)
                .duration(INTERVAL)
                .style("stroke-dasharray", ("0, 0"))
                .attr('opacity', function () { return getLineOpacity(ps, cs) })
                .attr('stroke', function () { return getLineColor(ps) })
              // the line linking cstage and fstage -> black dotted-line
              d3.select('#' + cstage + '_' + fstage)
                .transition()
                .delay(INTERVAL * 2)
                .duration(INTERVAL)
                .style("stroke-dasharray", ("6, 6"))
                .attr('opacity', function () { return getLineOpacity(cs, fs) })
                .attr('stroke', function () { return getLineColor(cs) })
            })
          }
          else {
            d3.select('#line_' + ps)
              .transition()
              .delay(INTERVAL)
              .duration(INTERVAL)
              .attr('opacity', function () { return getLineOpacity(ps, cs) })
              .attr('stroke', function () { return getLineColor(ps) })
          }

          console.log(pcstages)
          // past cues stage
          _.forEach(pcstages, function (pcstage) {
            // the line linking pstage and missed stage -> disappear
            d3.select('#' + pstage + '_' + pcstage)
              .transition()
              .delay(INTERVAL * 1)
              .duration(INTERVAL)
              .attr('opacity', function () { return getLineOpacity(ps, pcstage) })
          })

        });
      }

      function getLineOpacity(pstate, cstate) {
        if ((pstate === 'rev_succ' && cstate === 'active') || (pstate === 'rev_fail' && cstate === 'active') || (pstate === 'active' && cstate === 'revealed')) {
          return 1;
        } else {
          return 0; // should be 0
        }
      }

      function getRectFillColor(state) { // check if its a path or a stage Î
        if (state === 'path') {
          return '#C5C9FF';  // blue
        } else if (state === 'active') {
          return 'black';
        } else {
          return 'white';
        }
      }

      function getTextColor(state) {
        if (state === 'rev_succ') {
          return 'green';
        } else if (state === 'rev_fail') {
          return 'red';
        }
        else if (state === 'active') {
          return 'white';
        } else {
          return 'black';
        }
      }

      function getLineColor(state) {
        if (state === 'rev_succ') {
          return 'green';
        } else if (state === 'rev_fail') {
          return 'red';
        }
        else {
          return 'black';
        }
      }

      function getStageOpacity(state) {
        if (state === 'missed') {
          return 0.2;
        } else if (state === 'hidden') {
          return 0;
        } else {
          return 1;
        }
      }
    }
  }
}])

<commit_msg>clean code + comments<commit_after>// var _ = require('lodash/core');
'use strict'

var map = angular.module('myApp.map', ['ngRoute']);

map.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
  $routeProvider.when('/', {
    templateUrl: '/map.html',
    controller: 'mapCtrl'
  })

  $locationProvider.html5Mode({
    enabled: true,
    requireBase: false
  });
}])

map.controller('mapCtrl', ['$scope', '$http', 'socket', function ($scope, $http, socket) {
  $scope.pstage = '';
  $scope.cstage = '';

  // $scope.sendStage = function () {
  //   socket.emit('visualMsg', 'FROM visual-FRONT');
  //   console.log("msg sent");
  // }

  socket.on('visualMsg', function (data) {
    console.log("visual-front receive: " + data);
    var stages = data.split('->')
    $scope.pstage = stages[0];
    $scope.cstage = stages[1];
  });

  $http.get('/maps/').success(function (data) {
    $scope.iniData = data;
  });

  // room: room name (default "default")
  // pin: room pin/ password(default "")
  // name: control input name (required)
  // client: optional client identification

  //   $http({
  //     url: 'http://127.0.0.1:3000/input',
  //     method: 'POST',
  //     data: {
  //       contentType: 'application/x-www-form-urlencoded',
  //       room: "",
  //       pin: "",
  //       name: "visual",
  //       client: "visual",
  //       stage: $scope.stage
  //     }
  //   }).success(function (data) {
  //     console.log("Success" + data);
  //   }).error(function (data) {
  //     console.log("Erro: " + data);
  //   })
  // }])

  map.directive('d3Map', ['d3Service', '$http', '$window', function (d3Service, $http, $window) {
    return {
      restrict: 'EA',
      scope: false,
      link: function (scope, element, attrs) {

        $http.get('/maps/').success(function (data) {
          var iniData = data;
          console.log("GOT MAP: " + JSON.stringify(iniData));

          // EXTRACT INFO FROM DATA
          // get normal stages (except bc and summit)
          var stages = _.remove(iniData, function (n) {
            if (n.stage === 'summit' || n.stage === 'basecamp')
              return false;
            return true;
          })

          // collect path names to help sort stages i.e. a, b, c...
          var pathCode = _.orderBy(_.uniq(_.map(stages, function (o) { return _.head(o.stage); })));
          var NUM_COLUMN = pathCode.length; // column of the map
          var NUM_ROW = 0;

          // sort normal stages by path and stage number in desc order
          // sample: [[a2,a1],[b2,b1],[c2,c1]]
          var pathStageContainer = [];
          _.forEach(pathCode, function (obj) {
            var spePath = _.filter(stages, function (o) { return _.head(o.stage) == obj; });
            var orderedSpePath = _.orderBy(spePath, ['stage'], ['desc']);
            var pathHeight = orderedSpePath.length + 2;
            // get the maximum stages in one path as the NUM_ROW
            pathHeight > NUM_ROW ? NUM_ROW = pathHeight : 0;
            pathStageContainer.push(orderedSpePath);
          });

          // DISPLAY SETTINGS
          //var NUM_COLUMN = 3; // column of the map
          //var NUM_ROW = 10; // row of the map
          var RECT_WIDTH = 120;
          var RECT_HEIGHT = 40;

          var MAP_WIDTH = $window.innerWidth;
          var MAP_HEIGHT = $window.innerHeight;
          console.log("WINDOW: width: " + MAP_WIDTH + "  height: " + MAP_HEIGHT);

          var INI_X, RECT_X, INI_Y, RECT_Y, TEXT_X, TEXT_Y, X_OFFSET, Y_OFFSET, LEFT_X;

          INI_Y = RECT_Y = MAP_HEIGHT * 0.1;

          X_OFFSET = MAP_WIDTH / NUM_COLUMN;
          Y_OFFSET = MAP_HEIGHT * 0.8 / NUM_ROW;

          LEFT_X = MAP_WIDTH / (NUM_COLUMN * 2) - RECT_WIDTH / 2;

          // DRAW
          d3Service.d3().then(function (d3) {
            var canvas = d3.select(element[0]).append('svg').attr('width', MAP_WIDTH).attr('height', MAP_HEIGHT).attr('id', 'map-container');

            var data = []; // data contains data with x, y and are ordered
            var length = 0;
            var pathData;
            var i = 0;
            var j = 0;

            // DATA PROCESS
            // data are processed seperately: summit + normal stages + basecamp
            var summitData = _.find(iniData, { 'stage': 'summit' });
            // if the summit exists, draw summit
            if (summitData.visual) {
              summitData.x = (NUM_COLUMN - 1) / 2;
              summitData.y = 0;
              summitData = _.castArray(summitData);
              data = summitData;
            }

            _.forEach(pathStageContainer, function (pathData) {
              _.forEach(pathData, function (o) {
                if (_.isObject(o)) {
                  o.x = i;
                  o.y = j + 1;
                  j++;
                }
              });
              j = 0;
              i++;
              data = _.concat(data, pathData);
            });

            var bcData = _.find(iniData, { 'stage': 'basecamp' });
            if (bcData.visual) {
              // change state for the basecamp and its subsequent stage
              bcData.state = "active";
              var cueList = _.split(bcData.cue, '/');
              _.forEach(cueList, function (cue) {
                var stage = _.find(data, { stage: cue });
                stage.state = "revealed";
              });

              bcData.x = (NUM_COLUMN - 1) / 2;
              bcData.y = NUM_ROW - 1;
              bcData = _.castArray(bcData);
              data = _.concat(data, bcData);
            }

            // Data updated
            // ps - previous stage, the passed one
            // cs - current stage, the triggered one
            // fs - future stage, the stages cued next
            var customPath = [];
            scope.$watch('cstage', function () {
              if (scope.cstage) {

                // turn the previous active stage into past -  succ / fail
                var ps = _.find(data, { 'stage': scope.pstage })
                ps.state = "rev_succ";
                customPath.push(scope.pstage)
                updateMapStage(ps, 0);

                // active new path
                var cs = _.find(data, { 'stage': scope.cstage });
                cs.state = 'active';
                updateMapStage(cs, 1);

                // ps cue stage
                var psCues = ps.cue.split('/');
                var psCuesWithoutCs = _.filter(psCues, function (s) { return s !== cs.stage });

                // get missed stages
                var revealeds = _.filter(data, { 'state': 'revealed' })
                console.log(revealeds);
                _.forEach(revealeds, function (rs) {
                  console.log(rs);
                  if (_.isObject(rs))
                    rs.state = 'missed';
                  updateMapStage(rs, 1);
                });

                // reveal new stages
                var fss = _.split(cs.cue, '/');
                var flist = [];
                _.forEach(fss, function (c) {
                  var fs = _.find(data, { 'stage': c })
                  fs.state = 'revealed';
                  flist.push(fs);
                  updateMapStage(fs, 2);
                });

                updateMapLine(ps, cs, flist, psCuesWithoutCs);

                // CALL IMAGE DISPLAY / CONTENT / WHATSOEVER
                // END DATA PROCESS
              }
            });

            // COLLECT CUSTOM PATH
            // DRAW
            drawArrow(canvas, data);
            drawStage(canvas, data);

            function drawArrow(canvas, data) {
              _.forEach(data, function (cStageDatum) {
                if (cStageDatum && cStageDatum.cue) {
                  // get all the cues of this stage
                  var cueList = _.split(cStageDatum.cue, '/');

                  var cueStageDatum;
                  _.forEach(cueList, function (cueStage) {
                    cueStageDatum = _.find(data, { 'stage': _.trim(cueStage) });
                    canvas
                      .append('line')
                      .attr("x1", function () { return LEFT_X + cStageDatum.x * X_OFFSET + RECT_WIDTH / 2 })
                      .attr("y1", function () { return INI_Y + cStageDatum.y * Y_OFFSET + RECT_HEIGHT / 2 })
                      .attr("x2", function () { return LEFT_X + cueStageDatum.x * X_OFFSET + RECT_WIDTH / 2 })
                      .attr("y2", function () { return INI_Y + cueStageDatum.y * Y_OFFSET + RECT_HEIGHT / 2 })
                      .style("stroke-dasharray", ("6, 6"))
                      .attr('stroke', function () { return getLineColor(cStageDatum); })
                      .attr('stroke-width', '2px')
                      .attr("id", function () {
                        return cueStageDatum.stage ? (cStageDatum.stage + '_' + cueStageDatum.stage
                        ) : ('line_' + cStageDatum.stage)
                      })
                      .attr('opacity', function () { return getLineOpacity(cStageDatum.state, cueStageDatum.state) })
                  });
                }
              });
            }

            function drawStage(canvas, data) {
              canvas
                .selectAll('rect')
                .data(data)
                .enter()
                .append('rect')
                .attr('x', function (d) { return LEFT_X + d.x * X_OFFSET })
                .attr('y', function (d) { return INI_Y + d.y * Y_OFFSET })
                .attr('width', RECT_WIDTH)
                .attr('height', RECT_HEIGHT)
                .attr('fill', function (d) { return getRectFillColor(d.state); })
                .attr('stroke', function (d) { return getLineColor(d.state) })
                .attr('stroke-width', '2px')
                .attr('opacity', function (d) { return getStageOpacity(d.state); })
                .attr('id', function (d) { return 'rect_' + d.stage })
              canvas
                .selectAll('text')
                .data(data)
                .enter()
                .append('text')
                .text(function (d) { return d.stage; })
                .attr('x', function (d) { return LEFT_X + d.x * X_OFFSET + RECT_WIDTH / 2 })
                .attr('y', function (d) { return INI_Y + d.y * Y_OFFSET + 25 })
                .attr('text-anchor', 'middle')
                .attr('font-size', '20px')
                .attr('fill', function (d) { return getTextColor(d.state) })
                .attr('id', function (d) { return d.stage })
                .attr('opacity', function (d) { return getStageOpacity(d.state); })
            }
          });
        })

        // used as unit for time delay
        var INTERVAL = 1000;
        function updateMapStage(stage, delay) {
          var sname = stage.stage;
          var state;
          if (_.indexOf(sname) === 'path') {
            state = 'path';  // speical
          } else {
            state = stage.state;
          }

          console.log(sname);
          d3Service.d3().then(function (d3) {
            // update rect
            d3.select('#rect_' + sname)
              .transition()
              .delay(delay * INTERVAL)
              .duration(INTERVAL)
              .attr('fill', function () { return getRectFillColor(state) })
              .attr('stroke', function () { return getLineColor(state) })
              .attr('opacity', function () { return getStageOpacity(state) })

            // update text
            d3.select('#' + sname)
              .transition()
              .delay(delay * INTERVAL)
              .duration(INTERVAL)
              .attr('fill', function () { return getTextColor(state) })
              .attr('opacity', function () { return getStageOpacity(state) })
          })
        }

        // Update lines
        function updateMapLine(p, c, fss, pcstages) {
          var pstage = p.stage;
          var cstage = c.stage;
          var ps = p.state;
          var cs = c.state;
          var fs, fstage;

          d3Service.d3().then(function (d3) {
            if (fss) {
              _.forEach(fss, function (f) {
                fstage = f.stage;
                fs = f.state;

                // update lines linking pstage and cstage -> turn solid and change color
                d3.select('#' + pstage + '_' + cstage)
                  .transition()
                  .delay(INTERVAL)
                  .duration(INTERVAL)
                  .style("stroke-dasharray", ("0, 0"))
                  .attr('opacity', function () { return getLineOpacity(ps, cs) })
                  .attr('stroke', function () { return getLineColor(ps) })

                // update lines linking cstage and fstage -> black dotted-line
                d3.select('#' + cstage + '_' + fstage)
                  .transition()
                  .delay(INTERVAL * 2)
                  .duration(INTERVAL)
                  .style("stroke-dasharray", ("6, 6"))
                  .attr('opacity', function () { return getLineOpacity(cs, fs) })
                  .attr('stroke', function () { return getLineColor(cs) })
              })
            }
            else {  // if there is no fs i.e. reach the summit - need test?
              d3.select('#line_' + ps)
                .transition()
                .delay(INTERVAL)
                .duration(INTERVAL)
                .attr('opacity', function () { return getLineOpacity(ps, cs) })
                .attr('stroke', function () { return getLineColor(ps) })
            }

            // past cues stage
            _.forEach(pcstages, function (pcstage) {
              // the line linking pstage and missed stage -> disappear
              d3.select('#' + pstage + '_' + pcstage)
                .transition()
                .delay(INTERVAL * 1)
                .duration(INTERVAL)
                .attr('opacity', function () { return getLineOpacity(ps, pcstage) })
            })
          });
        }

        function getLineOpacity(pstate, cstate) {
          if ((pstate === 'rev_succ' && cstate === 'active') || (pstate === 'rev_fail' && cstate === 'active') || (pstate === 'active' && cstate === 'revealed')) {
            return 1;
          } else {
            return 0; // should be 0
          }
        }

        function getRectFillColor(state) { // check if its a path or a stage
          if (state === 'path') {
            return '#C5C9FF';  // blue
          } else if (state === 'active') {
            return 'black';
          } else {
            return 'white';
          }
        }

        function getTextColor(state) {
          if (state === 'rev_succ') {
            return 'green';
          } else if (state === 'rev_fail') {
            return 'red';
          }
          else if (state === 'active') {
            return 'white';
          } else {
            return 'black';
          }
        }

        function getLineColor(state) {
          if (state === 'rev_succ') {
            return 'green';
          } else if (state === 'rev_fail') {
            return 'red';
          }
          else {
            return 'black';
          }
        }

        function getStageOpacity(state) {
          if (state === 'missed') {
            return 0.2;
          } else if (state === 'hidden') {
            return 0;
          } else {
            return 1;
          }
        }
      }
    }
  }])

<|endoftext|>


<commit_before>/* jshint multistr: true */

var Capture = {

  mixins: [apiMixin],

  props: {

    capture: {
      type: Object,
      required: true,
    }

  },

  template: '\

\

\
        \
        \
        \
        \
        {{capture.UUID}}\

\

\

Name
\

{{capture.Name}}
\

Query
\

\
          {{capture.GremlinQuery}}\

\

Desc
\

{{capture.Description}}
\

BPF
\

{{capture.BPFFilter}}
\

Header
\

{{capture.HeaderSize}}
\

R. Pkts
\

{{capture.RawPacketLimit}}
\

Flows
\

\
          <flow-table :value="capture.GremlinQuery + \'.Flows().Dedup()\'"></flow-table>\

\

\

\
  ',

  data: function() {
    return {
      showFlows: false,
      deleting: false,
    };
  },

  computed: {

    // https://github.com/skydive-project/skydive/issues/202
    canShowFlows: function() {
      return this.capture.GremlinQuery.search('ShortestPathTo') === -1;
    },

  },

  methods: {

    warningMessage: function() {
      return '\
        This capture doesn\'t currently match any node

\
        Please check there is a Layer 2 link in case of 2 nodes capture.\
      ';
    },

    remove: function(capture) {
      var self = this,
          uuid = capture.UUID;
      this.deleting = true;
      this.$captureDelete(uuid)
        .always(function() {
          self.deleting = false;
        });
    },

    highlightCaptureNodes: function(capture, bool) {
      var self = this;
      // Avoid highlighting the nodes while the capture
      // is being deleted
      if (this.deleting) {
        return;
      }
      this.$topologyQuery(capture.GremlinQuery)
        .then(function(nodes) {
          nodes.forEach(function(n) {
            if (bool)
              self.$store.commit("highlight", n.ID);
            else
              self.$store.commit("unhighlight", n.ID);
          });
        });
    }

  }

};

Vue.component('capture-list', {

  mixins: [apiMixin],

  components: {
    'capture': Capture,
  },

  template: '\

 0">\

\

\
          <capture :capture="capture"></capture>\

\

\

\
  ',

  data: function() {
    return {
      captures: {},
      deleting: [],
      timer: null,
    };
  },

  created: function() {
    websocket.addMsgHandler('OnDemandNotification', this.onMsg.bind(this));
    websocket.addConnectHandler(this.init.bind(this));
  },

  beforeDestroy: function() {
    websocket.delConnectHandler(this.init.bind(this));
  },

  computed: {
    count: function() {
      return Object.keys(this.captures).length;
    }
  },

  methods: {

    init: function() {
      var self = this;
      this.$captureList()
        .then(function(data) {
          self.captures = data;
        });
    },

    onMsg: function(msg) {
      var self = this;
      switch(msg.Type) {
        case "CaptureDeleted":
          Vue.delete(this.captures, msg.Obj.UUID);
          break;
        case "CaptureAdded":
          Vue.set(this.captures, msg.Obj.UUID, msg.Obj);
          break;
        case "CaptureNodeUpdated":
          this.$captureGet(msg.Obj)
            .then(function(data) {
              Vue.set(self.captures, data.UUID, data);
            });
      }
    }

  }

});
<commit_msg>ui: add capture Type in capture list<commit_after>/* jshint multistr: true */

var Capture = {

  mixins: [apiMixin],

  props: {

    capture: {
      type: Object,
      required: true,
    }

  },

  template: '\

\

\
        \
        \
        \
        \
        {{capture.UUID}}\

\

\

Name
\

{{capture.Name}}
\

Query
\

\
          {{capture.GremlinQuery}}\

\

Desc
\

{{capture.Description}}
\

Type
\

{{capture.Type}}
\

BPF
\

{{capture.BPFFilter}}
\

Header
\

{{capture.HeaderSize}}
\

R. Pkts
\

{{capture.RawPacketLimit}}
\

Flows
\

\
          <flow-table :value="capture.GremlinQuery + \'.Flows().Dedup()\'"></flow-table>\

\

\

\
  ',

  data: function() {
    return {
      showFlows: false,
      deleting: false,
    };
  },

  computed: {

    // https://github.com/skydive-project/skydive/issues/202
    canShowFlows: function() {
      return this.capture.GremlinQuery.search('ShortestPathTo') === -1;
    },

  },

  methods: {

    warningMessage: function() {
      return '\
        This capture doesn\'t currently match any node

\
        Please check there is a Layer 2 link in case of 2 nodes capture.\
      ';
    },

    remove: function(capture) {
      var self = this,
          uuid = capture.UUID;
      this.deleting = true;
      this.$captureDelete(uuid)
        .always(function() {
          self.deleting = false;
        });
    },

    highlightCaptureNodes: function(capture, bool) {
      var self = this;
      // Avoid highlighting the nodes while the capture
      // is being deleted
      if (this.deleting) {
        return;
      }
      this.$topologyQuery(capture.GremlinQuery)
        .then(function(nodes) {
          nodes.forEach(function(n) {
            if (bool)
              self.$store.commit("highlight", n.ID);
            else
              self.$store.commit("unhighlight", n.ID);
          });
        });
    }

  }

};

Vue.component('capture-list', {

  mixins: [apiMixin],

  components: {
    'capture': Capture,
  },

  template: '\

 0">\

\

\
          <capture :capture="capture"></capture>\

\

\

\
  ',

  data: function() {
    return {
      captures: {},
      deleting: [],
      timer: null,
    };
  },

  created: function() {
    websocket.addMsgHandler('OnDemandNotification', this.onMsg.bind(this));
    websocket.addConnectHandler(this.init.bind(this));
  },

  beforeDestroy: function() {
    websocket.delConnectHandler(this.init.bind(this));
  },

  computed: {
    count: function() {
      return Object.keys(this.captures).length;
    }
  },

  methods: {

    init: function() {
      var self = this;
      this.$captureList()
        .then(function(data) {
          self.captures = data;
        });
    },

    onMsg: function(msg) {
      var self = this;
      switch(msg.Type) {
        case "CaptureDeleted":
          Vue.delete(this.captures, msg.Obj.UUID);
          break;
        case "CaptureAdded":
          Vue.set(this.captures, msg.Obj.UUID, msg.Obj);
          break;
        case "CaptureNodeUpdated":
          this.$captureGet(msg.Obj)
            .then(function(data) {
              Vue.set(self.captures, data.UUID, data);
            });
      }
    }

  }

});
<|endoftext|>


<commit_before>// Substance.Document 0.4.0
// (c) 2010-2013 Michael Aufreiter
// Substance.Document may be freely distributed under the MIT license.
// For all details and documentation:
// http://interior.substance.io/modules/document.html

(function(root) {

// Import
// ========

var _,
    util,
    errors,
    Chronicle,
    ot,
    Data;

if (typeof exports !== 'undefined') {
  _    = require('underscore');
  ot   = require('./lib/operation');
  util   = require('./lib/util/util');
  errors   = require('./lib/util/errors');
  Chronicle = require('./lib/chronicle/chronicle');
  ot = require('./lib/chronicle/lib/ot/index');
  Data = require('./lib/data/data');
} else {
  _ = root._;
  ot = root.ot;
  util = root.Substance.util;
  errors   = root.Substance.errors;
  Chronicle = root.Substance.Chronicle;
  ot = Chronicle.ot;
  Data = root.Substance.Data;
}

// Implementation
// ========

// Default Document Schema
// --------

var SCHEMA = {
  // Static indexes
  "indexes": {
    // all comments are now indexed by node association
    "comments": {
      "type": "comment",
      "properties": ["node"]
    },
    // All comments are now indexed by node
    "annotations": {
      "type": "annotation",
      "properties": ["node"]
    }
  },

  "types": {
    // Specific type for substance documents, holding all content elements
    "content": {
      "properties": {
      }
    },

    "text": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "document": {
      "properties": {
        "views": ["array", "views"]
      }
    },

    "view": {
      "properties": {
        "nodes": ["array", "content"]
      }
    },

    "codeblock": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "image": {
      "parent": "content",
      "properties": {
        "large": "string",
        "medium": "string",
        "caption": "string"
      }
    },

    "heading": {
      "parent": "content",
      "properties": {
        "content": "string",
        "level": "number"
      }
    },

    // Annotations
    "annotation": {
      "properties": {
        "node": "content",
        "property": "string",
        "range": "object"
      }
    },

    "strong": {
      "parent": "annotation",
      "properties": {
      }
    },

    "emphasis": {
      "properties": {
      },
      "parent": "annotation"
    },

    "code": {
      "parent": "annotation",
      "properties": {
      }
    },

    "link": {
      "parent": "annotation",
      "properties": {
        "url": "string"
      }
    },

    "idea": {
      "parent": "annotation",
      "properties": {
      }
    },

    "error": {
      "parent": "annotation",
      "properties": {
      }
    },

    "question": {
      "parent": "annotation",
      "properties": {
      }
    },

    // Comments
    "comment": {
      "properties": {
        "content": "string",
        "node": "node"
      }
    }
  }
};

// Seed Data
// ========
//
// Some pre-defined nodes that are required for each document
// `document` stores all meta-information about the document
// `content` is the main view

var SEED = [
  ["create", {
      "id": "document",
      "type": "document",
      "views": ["content", "figures", "publications"]
    }
  ],
  ["create", {
      "id": "content",
      "type": "view",
      "nodes": []
    }
  ],
  ["create", {
      "id": "figures",
      "type": "view",
      "nodes": []
    }
  ],
  ["create", {
      "id": "publications",
      "type": "view",
      "nodes": []
    }
  ]
];

// Command Converter
// ========
//
// Turns document command into Data.Graph commands

var Converter = function() {

  // Delete nodes from document
  // --------
  //
  // ["delete", {nodes: ["h1", "t1"]}]

  this.delete = function(graph, command) {
    return _.map(command.args.nodes, function(n) {
      return Data.Graph.Delete({id: n});
    });
  };

  // Position nodes in document
  // --------
  //
  // ["position", {"nodes": ["t1", "t2"], "target": -1}]
  //

  this.position = function(graph, command) {
    var path = command.path.concat(["nodes"]);
    var view = graph.resolve(path).slice(0);
    var nodes = command.args.nodes;
    var ops = [];
    var idx;

    // Create a sequence of atomic array operations that
    // are bundled into a Compound operation
    // 1. Remove elements (from right to left)
    // 2. Insert at the very position

    // the sequence contains selected nodes in the order they
    // occurr in the view
    var seq = _.intersection(view, nodes);
    var l = view.length;

    while(seq.length > 0) {
      var id = seq.pop();
      idx = view.indexOf(id);
      if (idx >= 0) {
        ops.push(ot.ArrayOperation.Delete(idx, id));
        l--;
      }
    }

    // target index can be given as negative number (as known from python/ruby)
    var target = (l === 0) ? 0 : (l + command.args.target) % l;
    for (idx = 0; idx < nodes.length; idx++) {
      ops.push(ot.ArrayOperation.Insert(target + idx, nodes[idx]));
    }

    var compound = ot.ArrayOperation.Compound(ops);

    return Data.Graph.Update(path, compound);
  };

  // Update incrementally
  // --------
  //

  this.update = function(graph, command) {
    var propertyBaseType = graph.propertyBaseType(graph.get(command.path[0]), command.path[1]);
    var val = graph.resolve(command.path);

    var update;

    // String
    if (propertyBaseType === 'string') {
      update = ot.TextOperation.fromOT(val, command.args);
    }

    // Array
    else if (propertyBaseType === 'array') {
      throw new Error("Not yet implemented for arrays");
    }

    // Object
    else if (propertyBaseType === 'object') {
      update = ot.ObjectOperation.Extend(val, command.args);
    }

    // Other
    else {
      throw new Error("Unsupported type for update: " + propertyBaseType);
    }

    return Data.Graph.Update(command.path, update);
  };

  // Set property values
  // --------
  //
  // Unlike update you can set values directly
  // ["set", "h1", "content", "Hello Welt"] // string update
  // ["set", "a1", "pos", ["a", "b", "c"]] // array update (not yet implemented)

  this.set = function(graph, command) {

    if (!command.args) { // for string updates
      command.args = command.path.pop();
    }

    var propertyBaseType = graph.propertyBaseType(graph.get(command.path[0]), command.path[1]);
    var result;

    var val, newVal, update;

    val = graph.resolve(command.path);
    newVal = command.args;

    // String
    if (propertyBaseType === 'string') {
      update = ot.TextOperation.fromOT(val, [-val.length, newVal]);
    }
    // Array
    else if (propertyBaseType === 'array') {
      update = ot.ArrayOperation.Update(val, newVal);
    }
    // Object
    else if (propertyBaseType === 'object') {
      // TODO: for that we need to delete all keys and create the new ones
      //  or a more intelligent solution (i.e. diff)
      throw new Error("Not yet implemented for objects");
    }
    // Other
    else {
      // treating any other type via string operation
      val = val.toString();
      newVal = newVal.toString();
      update = ot.TextOperation.fromOT(val, [-val.length, newVal]);
    }

    result = Data.Graph.Update(command.path, update);
    return result;
  };

  // Annotate document
  // --------
  //
  // `command.path` defines the referenced content node and property
  // ["annotate", "t1", "content", {"id": "a1",  type": "idea"}]

  this.annotate = function(graph, command) {
    // TODO: check if source exists, otherwise reject annotation
    if (command.path.length !== 2) throw new Error("Invalid target: " + command.path);

    var annotation = _.extend({}, command.args, {
      node: command.path[0],
      property: command.path[1]
    });

    return Data.Graph.Create(annotation);
  };

  // Comment
  // --------
  //
  // `command.path` holds the node id, where the comment should stick on

  this.comment = function(graph, command) {
    // Delegates to graph.create method
    // TODO: check if source exists, otherwise reject annotation

    // keep track of annotation
    if (command.path.length !== 1) throw new Error("Invalid target: " + command.path);

    var comment = _.extend({}, command.args);
    comment.node = command.path[0];
    comment.type = comment.type || 'comment';

    return Data.Graph.Create(comment);
  };
};

// Document
// --------
//
// A generic model for representing and transforming digital documents

var Document = function(doc, schema) {
  Data.Graph.call(this, schema || SCHEMA);
  // Set public properties
  this.id = doc.id;

  // TODO: shift into a dedicated facility
  this.meta = {};

  this.reset();
};

Document.__prototype__ = function() {

  var __super__ = util.prototype(this);
  var converter = new Converter();

  // Resets the versioned object to a clean state.
  // --------
  //

  this.reset = function() {
    // Seed graph
    _.each(SEED, function(cmd) {
      this.exec(cmd);
    }, this);
  };

  var updateAnnotations = function(node, property, change) {
    // We need to update the range of affected annotations.

    var annotations = this.find("annotations", node.id);
    annotations = _.filter(annotations, function(a) {
      return a.property === property;
    });
    for (var idx = 0; idx < annotations.length; idx++) {
      ot.TextOperation.Range.transform(annotations[idx].range, change);
    }
  };

  // Executes a document manipulation command.
  // --------
  // The command is converted into a sequence of graph commands

  this.exec = function(command) {
    console.log("Executing command: ", command);
    var graphCommand;
    // convert the command into a Data.Graph compatible command
    command = new Data.Command(command);
    if (converter[command.op]) {
      graphCommand = converter[command.op](this, command);
    } else {
      graphCommand = command;
    }

    // console.log('converted cmd', command);
    var commands = _.isArray(graphCommand) ? graphCommand : [graphCommand];

    _.each(commands, function(c) {

      __super__.exec.call(this, c);

      if (c.op === "update") {
        var node = this.get(c.path[0]);
        var property = c.path[1];
        var change = c.args;
        updateAnnotations.call(this, node, property, change);
      }
    }, this);
    this.trigger('command:executed', command);
  };
};

// Document.__prototype__.prototype = Chronicle.Versioned.prototype;
Document.__prototype__.prototype = Data.Graph.prototype;
Document.prototype = new Document.__prototype__();

// add event support
_.extend(Document.prototype, util.Events);

// Export
// ========

if (typeof exports !== 'undefined') {
  module.exports = Document;
} else {
  root.Substance.Document = Document;
}

})(this);
<commit_msg>Add some comments about future refactorings.<commit_after>// Substance.Document 0.4.0
// (c) 2010-2013 Michael Aufreiter
// Substance.Document may be freely distributed under the MIT license.
// For all details and documentation:
// http://interior.substance.io/modules/document.html

(function(root) {

// Import
// ========

var _,
    util,
    errors,
    Chronicle,
    ot,
    Data;

if (typeof exports !== 'undefined') {
  _    = require('underscore');
  ot   = require('./lib/operation');
  util   = require('./lib/util/util');
  errors   = require('./lib/util/errors');
  Chronicle = require('./lib/chronicle/chronicle');
  ot = require('./lib/chronicle/lib/ot/index');
  Data = require('./lib/data/data');
} else {
  _ = root._;
  ot = root.ot;
  util = root.Substance.util;
  errors   = root.Substance.errors;
  Chronicle = root.Substance.Chronicle;
  ot = Chronicle.ot;
  Data = root.Substance.Data;
}

// Implementation
// ========

// Default Document Schema
// --------

var SCHEMA = {
  // Static indexes
  "indexes": {
    // all comments are now indexed by node association
    "comments": {
      "type": "comment",
      "properties": ["node"]
    },
    // All comments are now indexed by node
    "annotations": {
      "type": "annotation",
      "properties": ["node"]
    }
  },

  "types": {
    // Specific type for substance documents, holding all content elements
    "content": {
      "properties": {
      }
    },

    "text": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "document": {
      "properties": {
        "views": ["array", "views"]
      }
    },

    "view": {
      "properties": {
        "nodes": ["array", "content"]
      }
    },

    "codeblock": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "image": {
      "parent": "content",
      "properties": {
        "large": "string",
        "medium": "string",
        "caption": "string"
      }
    },

    "heading": {
      "parent": "content",
      "properties": {
        "content": "string",
        "level": "number"
      }
    },

    // Annotations
    "annotation": {
      "properties": {
        "node": "content",
        "property": "string",
        "range": "object"
      }
    },

    "strong": {
      "parent": "annotation",
      "properties": {
      }
    },

    "emphasis": {
      "properties": {
      },
      "parent": "annotation"
    },

    "code": {
      "parent": "annotation",
      "properties": {
      }
    },

    "link": {
      "parent": "annotation",
      "properties": {
        "url": "string"
      }
    },

    "idea": {
      "parent": "annotation",
      "properties": {
      }
    },

    "error": {
      "parent": "annotation",
      "properties": {
      }
    },

    "question": {
      "parent": "annotation",
      "properties": {
      }
    },

    // Comments
    "comment": {
      "properties": {
        "content": "string",
        "node": "node"
      }
    }
  }
};

// Seed Data
// ========
//
// Some pre-defined nodes that are required for each document
// `document` stores all meta-information about the document
// `content` is the main view

var SEED = [
  ["create", {
      "id": "document",
      "type": "document",
      "views": ["content", "figures", "publications"]
    }
  ],
  ["create", {
      "id": "content",
      "type": "view",
      "nodes": []
    }
  ],
  ["create", {
      "id": "figures",
      "type": "view",
      "nodes": []
    }
  ],
  ["create", {
      "id": "publications",
      "type": "view",
      "nodes": []
    }
  ]
];

// Command Converter
// ========
//
// Turns document command into Data.Graph commands

var Converter = function() {

  // Delete nodes from document
  // --------
  //
  // ["delete", {nodes: ["h1", "t1"]}]

  this.delete = function(graph, command) {
    return _.map(command.args.nodes, function(n) {
      return Data.Graph.Delete({id: n});
    });
  };

  // Position nodes in document
  // --------
  //
  // ["position", {"nodes": ["t1", "t2"], "target": -1}]
  //

  // TODO: we could use Graph.set which computes a rather minimal set of ArrayOps
  //       to get rid of the ArrayOperation dependency here
  this.position = function(graph, command) {
    var path = command.path.concat(["nodes"]);
    var view = graph.resolve(path).slice(0);
    var nodes = command.args.nodes;
    var ops = [];
    var idx;

    // Create a sequence of atomic array operations that
    // are bundled into a Compound operation
    // 1. Remove elements (from right to left)
    // 2. Insert at the very position

    // the sequence contains selected nodes in the order they
    // occurr in the view
    var seq = _.intersection(view, nodes);
    var l = view.length;

    while(seq.length > 0) {
      var id = seq.pop();
      idx = view.indexOf(id);
      if (idx >= 0) {
        ops.push(ot.ArrayOperation.Delete(idx, id));
        l--;
      }
    }

    // target index can be given as negative number (as known from python/ruby)
    var target = (l === 0) ? 0 : (l + command.args.target) % l;
    for (idx = 0; idx < nodes.length; idx++) {
      ops.push(ot.ArrayOperation.Insert(target + idx, nodes[idx]));
    }

    var compound = ot.ArrayOperation.Compound(ops);

    return Data.Graph.Update(path, compound);
  };

  // Update incrementally
  // --------
  //

  // TODO: if we would integrate the convenience mechanisms for update and set into
  //  Data.Graph, we could get rid of the OT dependencies here.

  this.update = function(graph, command) {
    var propertyBaseType = graph.propertyBaseType(graph.get(command.path[0]), command.path[1]);
    var val = graph.resolve(command.path);

    var update;

    // String
    if (propertyBaseType === 'string') {
      update = ot.TextOperation.fromOT(val, command.args);
    }

    // Array
    else if (propertyBaseType === 'array') {
      throw new Error("Not yet implemented for arrays");
    }

    // Object
    else if (propertyBaseType === 'object') {
      update = ot.ObjectOperation.Extend(val, command.args);
    }

    // Other
    else {
      throw new Error("Unsupported type for update: " + propertyBaseType);
    }

    return Data.Graph.Update(command.path, update);
  };

  // Set property values
  // --------
  //
  // Unlike update you can set values directly
  // ["set", "h1", "content", "Hello Welt"] // string update
  // ["set", "a1", "pos", ["a", "b", "c"]] // array update (not yet implemented)

  this.set = function(graph, command) {

    if (!command.args) { // for string updates
      command.args = command.path.pop();
    }

    var propertyBaseType = graph.propertyBaseType(graph.get(command.path[0]), command.path[1]);
    var result;

    var val, newVal, update;

    val = graph.resolve(command.path);
    newVal = command.args;

    // String
    if (propertyBaseType === 'string') {
      update = ot.TextOperation.fromOT(val, [-val.length, newVal]);
    }
    // Array
    else if (propertyBaseType === 'array') {
      update = ot.ArrayOperation.Update(val, newVal);
    }
    // Object
    else if (propertyBaseType === 'object') {
      // TODO: for that we need to delete all keys and create the new ones
      //  or a more intelligent solution (i.e. diff)
      throw new Error("Not yet implemented for objects");
    }
    // Other
    else {
      // treating any other type via string operation
      val = val.toString();
      newVal = newVal.toString();
      update = ot.TextOperation.fromOT(val, [-val.length, newVal]);
    }

    result = Data.Graph.Update(command.path, update);
    return result;
  };

  // Annotate document
  // --------
  //
  // `command.path` defines the referenced content node and property
  // ["annotate", "t1", "content", {"id": "a1",  type": "idea"}]

  this.annotate = function(graph, command) {
    // TODO: check if source exists, otherwise reject annotation
    if (command.path.length !== 2) throw new Error("Invalid target: " + command.path);

    var annotation = _.extend({}, command.args, {
      node: command.path[0],
      property: command.path[1]
    });

    return Data.Graph.Create(annotation);
  };

  // Comment
  // --------
  //
  // `command.path` holds the node id, where the comment should stick on

  this.comment = function(graph, command) {
    // Delegates to graph.create method
    // TODO: check if source exists, otherwise reject annotation

    // keep track of annotation
    if (command.path.length !== 1) throw new Error("Invalid target: " + command.path);

    var comment = _.extend({}, command.args);
    comment.node = command.path[0];
    comment.type = comment.type || 'comment';

    return Data.Graph.Create(comment);
  };
};

// Document
// --------
//
// A generic model for representing and transforming digital documents

var Document = function(doc, schema) {
  Data.Graph.call(this, schema || SCHEMA);
  // Set public properties
  this.id = doc.id;

  // TODO: shift into a dedicated facility
  this.meta = {};

  this.reset();
};

Document.__prototype__ = function() {

  var __super__ = util.prototype(this);
  var converter = new Converter();

  // Resets the versioned object to a clean state.
  // --------
  //

  this.reset = function() {
    // Seed graph
    _.each(SEED, function(cmd) {
      this.exec(cmd);
    }, this);
  };

  var updateAnnotations = function(node, property, change) {
    // We need to update the range of affected annotations.

    var annotations = this.find("annotations", node.id);
    annotations = _.filter(annotations, function(a) {
      return a.property === property;
    });
    for (var idx = 0; idx < annotations.length; idx++) {
      ot.TextOperation.Range.transform(annotations[idx].range, change);
    }
  };

  // Executes a document manipulation command.
  // --------
  // The command is converted into a sequence of graph commands

  this.exec = function(command) {
    console.log("Executing command: ", command);
    var graphCommand;
    // convert the command into a Data.Graph compatible command
    command = new Data.Command(command);
    if (converter[command.op]) {
      graphCommand = converter[command.op](this, command);
    } else {
      graphCommand = command;
    }

    // console.log('converted cmd', command);
    var commands = _.isArray(graphCommand) ? graphCommand : [graphCommand];

    _.each(commands, function(c) {

      __super__.exec.call(this, c);

      if (c.op === "update") {
        var node = this.get(c.path[0]);
        var property = c.path[1];
        var change = c.args;
        updateAnnotations.call(this, node, property, change);
      }
    }, this);
    this.trigger('command:executed', command);
  };
};

// Document.__prototype__.prototype = Chronicle.Versioned.prototype;
Document.__prototype__.prototype = Data.Graph.prototype;
Document.prototype = new Document.__prototype__();

// add event support
_.extend(Document.prototype, util.Events);

// Export
// ========

if (typeof exports !== 'undefined') {
  module.exports = Document;
} else {
  root.Substance.Document = Document;
}

})(this);
<|endoftext|>


<commit_before>define(['jquery'], function ($) {

    function changeLanguage(lang) {
        if (location.search.indexOf("language") > -1) {
            location.search = location.search.replace(/language=[a-z][a-z]/, "language=" + lang);
        } else if (location.search == "") {
            var url = location.href;
            if (url.substr(url.length - 1) == '?') {
                location.href += "language=" + lang;
            } else {
                location.href += "?language=" + lang;
            }
        } else {
            location.href += "&language=" + lang;
        }
    }

    $('#header-signin').click(function () {
        'login?callbackUrl={0}'.format(encodeURIComponent(location.href)).goto();
    });

    $('.language-selection').each(function (index, action) {
        var language = $(action).attr('data-language');
        $(action).click(function () {
            changeLanguage(language);
        });
    });

});<commit_msg>#218 Correction of language change<commit_after>define(['jquery'], function ($) {

    function changeLanguage(lang) {
        if (location.search.indexOf("language") > -1) {
            location.search = location.search.replace(/language=[a-z][a-z]/, "language=" + lang);
        } else if (location.search == "") {
            location.search = "language=" + lang;
        } else {
            location.search += "&language=" + lang;
        }
    }

    $('#header-signin').click(function () {
        'login?callbackUrl={0}'.format(encodeURIComponent(location.href)).goto();
    });

    $('.language-selection').each(function (index, action) {
        var language = $(action).attr('data-language');
        $(action).click(function () {
            changeLanguage(language);
        });
    });

});<|endoftext|>


<commit_before>(function (dynamicHandler) {

})(module.exports);<commit_msg>Remove unused scripts<commit_after><|endoftext|>


<commit_before>var
  fs = require('fs'),
  _ = require('lodash'),
  path = require('path'),
  InternalError = require('kuzzle-common-objects').Errors.internalError,
  q = require('q'),
  stringify = require('json-stable-stringify'),
  jsonToYaml = require('json2yaml'),
  generateSwagger,
  writeFiles;

generateSwagger = (routes, apiVersion) => {
  var swagger;

  swagger = {
    basePath: '/api',
    consumes: [
      'application/json'
    ],
    host: 'sandbox.kuzzle.io:7511',
    info: {
      contact: {
        email: 'hello@kuzzle.io',
        name: 'Kuzzle team',
        url: 'http://kuzzle.io'
      },
      description: 'The Kuzzle REST API',
      license: {
        name: 'Apache 2',
        url: 'http://opensource.org/licenses/apache2.0'
      },
      title: 'Kuzzle API',
      version: apiVersion
    },
    produces: [
      'application/json'
    ],
    schemes: [
      'http'
    ],
    swagger: '2.0',
    paths: {}
  };

  routes.forEach(route => {
    var
      reg = /:([^\/]*)/g,
      m;

    if (swagger.paths[route.url] === undefined) {
      swagger.paths[route.url] = {};
    }

    if (swagger.paths[route.url][route.verb] === undefined) {
      if (route.infos !== undefined) {
        route.infos.description += '\nController: ' + route.controller + '. Action: ' + route.action + '.';
        swagger.paths[route.url][route.verb] = route.infos;
      }
      else {
        // the route definision is minimal, lets create a default one
        swagger.paths[route.url][route.verb] = {
          description: 'Controller: ' + route.controller + '. Action: ' + route.action + '.',
          produces: 'application/json',
          responses: {
            '200': {
              description: 'OK',
              schema: {
                action: 'string',
                controller: 'string',
                error: 'object or null',
                metadata: 'object',
                requestId: 'string',
                result: 'object',
                scope: 'string or null',
                state: 'string',
                status: 'integer'
              }
            }
          },
          parameters: []
        };
      }

      while ((m = reg.exec(route.url)) !== null) {
        if (m.index === reg.lastIndex) {
          reg.lastIndex++;
        }
        swagger.paths[route.url][route.verb].parameters.push({
          description: 'TODO',
          in: 'path',
          name: m[1],
          required: true,
          type: 'string'
        });
      }
    }

  });

  return q(swagger);
};

writeFiles = swagger => {
  var baseDir = path.join(__dirname, '..', '..', '..', '..');

  try {
    fs.writeFileSync(path.join(baseDir, 'kuzzle-swagger.json'), stringify(swagger));
  }
  catch (e) {
    q.reject(new InternalError('Unable to write the kuzzle-swagger.json file'));
  }
  try {
    fs.writeFileSync(path.join(baseDir, 'kuzzle-swagger.yml'), jsonToYaml.stringify(swagger));
  }
  catch (e) {
    q.reject(new InternalError('Unable to write the kuzzle-swagger.yml file'));
  }
  return q(swagger);
};

module.exports = function GenerateSwaggerFiles (kuzzle) {
  var routes = [];
  this.kuzzle = kuzzle;

  kuzzle.config.httpRoutes.forEach(_route => {
    var route = _.assign({}, _route);
    route.url = '/' + kuzzle.config.apiVersion + route.url;
    routes.push(route);
  });

  routes.push({verb: 'get', url: '/_serverInfo', controller: 'read', action: 'serverInfo'});

  kuzzle.pluginsManager.routes.forEach(_route => {
    var route = _.assign({}, _route);
    route.url = '/' + kuzzle.config.apiVersion + '/_plugin' + route.url;
    routes.push(route);
  });

  if (this.kuzzle.isServer) {
    return generateSwagger(routes, kuzzle.config.apiVersion)
      .then(swagger => writeFiles(swagger));
  }

  return q({isWorker: true});
};<commit_msg>changes following comments<commit_after>var
  fs = require('fs'),
  _ = require('lodash'),
  path = require('path'),
  InternalError = require('kuzzle-common-objects').Errors.internalError,
  q = require('q'),
  stringify = require('json-stable-stringify'),
  jsonToYaml = require('json2yaml'),
  generateSwagger,
  writeFiles;

generateSwagger = (routes, apiVersion) => {
  var swagger;

  swagger = {
    basePath: '/api',
    consumes: [
      'application/json'
    ],
    host: 'sandbox.kuzzle.io:7511',
    info: {
      contact: {
        email: 'hello@kuzzle.io',
        name: 'Kuzzle team',
        url: 'http://kuzzle.io'
      },
      description: 'The Kuzzle REST API',
      license: {
        name: 'Apache 2',
        url: 'http://opensource.org/licenses/apache2.0'
      },
      title: 'Kuzzle API',
      version: apiVersion
    },
    produces: [
      'application/json'
    ],
    schemes: [
      'http'
    ],
    swagger: '2.0',
    paths: {}
  };

  routes.forEach(route => {
    var
      reg = /:([^\/]*)/g,
      m;

    if (swagger.paths[route.url] === undefined) {
      swagger.paths[route.url] = {};
    }

    if (swagger.paths[route.url][route.verb] === undefined) {
      if (route.infos !== undefined) {
        route.infos.description += '\nController: ' + route.controller + '. Action: ' + route.action + '.';
        swagger.paths[route.url][route.verb] = route.infos;
      }
      else {
        // the route definision is minimal, lets create a default one
        swagger.paths[route.url][route.verb] = {
          description: 'Controller: ' + route.controller + '. Action: ' + route.action + '.',
          produces: 'application/json',
          responses: {
            '200': {
              description: 'OK',
              schema: {
                action: 'string',
                controller: 'string',
                error: 'object or null',
                metadata: 'object',
                requestId: 'string',
                result: 'object',
                scope: 'string or null',
                state: 'string',
                status: 'integer'
              }
            }
          },
          parameters: []
        };
      }

      while ((m = reg.exec(route.url)) !== null) {
        reg.lastIndex++;
        swagger.paths[route.url][route.verb].parameters.push({
          description: 'TODO',
          in: 'path',
          name: m[1],
          required: true,
          type: 'string'
        });
      }
    }
  });

  return q(swagger);
};

writeFiles = swagger => {
  var baseDir = path.join(__dirname, '..', '..', '..', '..');

  try {
    fs.writeFileSync(path.join(baseDir, 'kuzzle-swagger.json'), stringify(swagger));
  }
  catch (e) {
    q.reject(new InternalError('Unable to write the kuzzle-swagger.json file'));
  }
  try {
    fs.writeFileSync(path.join(baseDir, 'kuzzle-swagger.yml'), jsonToYaml.stringify(swagger));
  }
  catch (e) {
    q.reject(new InternalError('Unable to write the kuzzle-swagger.yml file'));
  }
  return q(swagger);
};

module.exports = function GenerateSwaggerFiles (kuzzle) {
  var routes = [];

  if (! this.kuzzle.isServer) {
    return q({isWorker: true});
  }

  this.kuzzle = kuzzle;

  kuzzle.config.httpRoutes.forEach(_route => {
    var route = _.assign({}, _route);
    route.url = '/' + kuzzle.config.apiVersion + route.url;
    routes.push(route);
  });

  routes.push({verb: 'get', url: '/_serverInfo', controller: 'read', action: 'serverInfo'});

  kuzzle.pluginsManager.routes.forEach(_route => {
    var route = _.assign({}, _route);
    route.url = '/' + kuzzle.config.apiVersion + '/_plugin' + route.url;
    routes.push(route);
  });

  return generateSwagger(routes, kuzzle.config.apiVersion)
    .then(swagger => writeFiles(swagger));
};<|endoftext|>