<commit_before>/**
 * The StoriesEdit view.
 */
define([
  'jquery',
  'backbone',
  'mps'
], function($,Backbone,mps) {

  'use strict';

  var config = {
    ZOOM: 3,
    MINZOOM: 3,
    MAXZOOM: 20,
    LAT: 15,
    LNG: 27,
    ISO: 'ALL',
    BASEMAP: 'grayscale',
    BASELAYER: 'loss',
    MONTHNAMES: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    MONTHNAMES_SHORT: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
    QUARTERNAMES: ["JAN - MAR", "APR - JUN", "JUL - SEP", "OCT - DEC"],
    mapLoaded: false
  };

  config.MAPOPTIONS = {
    zoom: config.ZOOM,
    minZoom: config.MINZOOM,
    maxZoom: config.MAXZOOM,
    center: new google.maps.LatLng(config.LAT, config.LNG),
    mapTypeId: google.maps.MapTypeId.HYBRID,
    backgroundColor: '#99b3cc',
    disableDefaultUI: true,
  };

  config.OVERLAYSTYLES = {
    strokeWeight: 2,
    fillOpacity: 0.45,
    fillColor: "#FFF",
    strokeColor: "#A2BC28",
    editable: true,
    icon: new google.maps.MarkerImage(
      '/assets/icons/marker_exclamation.png',
      new google.maps.Size(36, 36), // size
      new google.maps.Point(0, 0), // offset
      new google.maps.Point(18, 18) // anchor
    )
  };

  config.MAPSTYLES = {};

  config.MAPSTYLES.grayscale = {
    type: 'style',
    style: [ { "featureType": "water" }, { "featureType": "transit", "stylers": [ { "saturation": -100 } ] }, { "featureType": "road", "stylers": [ { "saturation": -100 } ] }, { "featureType": "poi", "stylers": [ { "saturation": -100 } ] }, { "featureType": "landscape", "stylers": [ { "saturation": -100 } ] }, { "featureType": "administrative", "stylers": [ { "saturation": -100 } ] },{ "featureType": "poi.park", "elementType": "geometry", "stylers": [ { "visibility": 'off' } ] } ]
  }

  config.MAPSTYLES.terrain = {
    type: 'mapType',
    style: google.maps.MapTypeId.TERRAIN,
    title: "Terrain"
  }

  config.MAPSTYLES.satellite = {
    type: 'mapType',
    style: google.maps.MapTypeId.SATELLITE,
    title: "Satellite"
  }

  config.MAPSTYLES.roads = {
    type: 'mapType',
    style: google.maps.MapTypeId.HYBRID,
    title: "Roads"
  }

  config.MAPSTYLES.treeheight = {
    type: 'customMapType',
    style: new google.maps.ImageMapType({
      getTileUrl: function(ll, z) {
        var X = Math.abs(ll.x % (1 << z)); // wrap
        return window.gfw.config.GFW_API_HOST + "/gee/simple_green_coverage/" + z + "/" + X + "/" + ll.y + ".png";
      },
      tileSize: new google.maps.Size(256, 256),
      isPng: true,
      maxZoom: 17,
      name: "Forest Height",
      alt: "Global forest height"
    })
  }

  config.MAPSTYLES.landsat = [];

  for(var i = 1999; i < 2013; i++) {
    (function(year) {
      config.MAPSTYLES.landsat[i] = new google.maps.ImageMapType({
        getTileUrl: function(ll, z) {
          var X = Math.abs(ll.x % (1 << z));  // wrap
          return window.gfw.config.GFW_API_HOST + "/gee/landsat_composites/" + z + "/" + X + "/" + ll.y + ".png?year="+year;
        },
        tileSize: new google.maps.Size(256, 256),
        isPng: true,
        maxZoom: 17,
        name: "Landsat "+i
      });
    })(i);
  }

  var StoriesEditModel = Backbone.Model.extend({
    defaults: {
      the_geom: null
    }
  })

  var StoriesEditView = Backbone.View.extend({

    el: '#storiesEditView',

    events: {
      'click #zoomIn': '_zoomIn',
      'click #zoomOut': '_zoomOut',
      'click #autoLocate': '_autoLocate',
      'input #story_video' : 'videoInput'
    },

    initialize: function() {
      if (!this.$el.length) {
        return
      }

      this.model = new StoriesEditModel();

      this.uploadsIds = [];
      this.filesAdded = 0;

      this._initViews();
      this._initBindings();

      this.render();
    },

    videoInput: function(e) {
      this._addVideoThumbnail($(e.target).val());
    },

    _getVideoID: function(url) {
      // template: http://img.youtube.com/vi/<video-id-here>/default.jpg
      // a Youtube video ID has a 11 characters legngth
      return 'http://img.youtube.com/vi/' + url.split('v=')[1].substring(0, 11) + '/default.jpg';
    },

    _addVideoThumbnail: function(url) {
      var vidID  = this._getVideoID(url),
          $thumb = $('#videothumbnail');
      if ($thumb.length > 0) {
        $thumb.find('.inner_box').css('background-image','url('+ vidID +')')
      } else {
        $('.thumbnails').append('

<svg><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#shape-close"></use></svg>
');
        this.uploadsIds.push('VID-'+vidID);
        $thumb = $('#videothumbnail');
        $thumb.find('.destroy').on('click', function(e) {
            e.preventDefault();

            var confirmation = confirm('Are you sure?')

            if (confirmation == true) {
              this.uploadsIds = _.without(this.uploadsIds, 'VID-'+vidID);
              $("#story_uploads_ids").val(this.uploadsIds.join(","));

              $thumb.fadeOut(250, function() {
                $thumb.remove();
              });
            }
          });
      }
    },

    _initBindings: function() {
      var that = this;

      $('.upload_picture').on('click', function(e) {
        e.preventDefault();

        $('#fileupload').click();
      });

      $('#fileupload').fileupload({
          url: '/media/upload',
          dataType: 'json',
          autoUpload: true,
          acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
          maxFileSize: 4000000, // 4 MB
          // Enable image resizing, except for Android and Opera,
          // which actually support image resizing, but fail to
          // send Blob objects via XHR requests:
          disableImageResize: /Android(?!.*Chrome)|Opera/
            .test(window.navigator.userAgent),
          previewMaxWidth: 132,
          previewMaxHeight: 76,
          previewCrop: true,
          timeout: 3600000
      }).on('fileuploadadd', function (e, data) {
        data.context = $('
').appendTo('#files');

        that.filesAdded += _.size(data.files);
        _.each(data.files, function(file) {
          if (file && file.size > 4000000) {
            mps.publish('Notification/open', ['notif-limit-exceed']);
            return;
          } else {
            var filename = that.prettifyFilename(file.name);
            var $thumbnail = $("

"+ file.name +"

<svg><use xlink:href='#shape-spinner'></use></svg>

");
            $('.thumbnails').append($thumbnail);
            $thumbnail.fadeIn(250);

            var $submitButton = $("form input[type='submit']");
            $submitButton.addClass('disabled');
            $submitButton.attr('disabled', 'disabled');
            $submitButton.val('Please wait...');
          }
        });

        // data.submit();
      }).on('fileuploaddone', function (e, data) {
        var files = [data.result];

        $.each(files, function (index, file) {
          that.filesAdded--;
          that.uploadsIds.push(file.basename);

          var url = file.url.replace('https', 'http');
          var $thumb = $("

<svg><use xlink:href='#shape-close'></use></svg>
");

          var filename = that.prettifyFilename(file.basename).substring(45);

          $(".thumbnail[data-name='"+filename+"']").fadeOut(250, function() {
            $(this).remove();

            $(".thumbnails").append($thumb);
            $thumb.fadeIn(250);
          });

          $thumb.find('.destroy').on('click', function(e) {
            e.preventDefault();

            var confirmation = confirm('Are you sure?')

            if (confirmation == true) {
              that.uploadsIds = _.without(that.uploadsIds, file.basename);
              $("#story_uploads_ids").val(that.uploadsIds.join(","));

              $thumb.fadeOut(250, function() {
                $thumb.remove();
              });
            }
          });
        });

        if (that.filesAdded <= 0) {
          var $submitButton = $("form input[type='submit']");
          $submitButton.val('Submit story');
          $submitButton.removeClass('disabled');
          $submitButton.attr('disabled', false);
        }

        $('#story_uploads_ids').val(that.uploadsIds.join(','));
        ga('send', 'event', 'Stories', 'New story', 'submit');
      }).on('fileuploadfail', function (e, data){
        mps.publish('Notification/open', ['upload-error-server']);
        var $submitButton = $("form input[type='submit']");
        $submitButton.val('Submit story');
        $submitButton.removeClass('disabled');
        $submitButton.attr('disabled', false);
      });
    },

    _initViews: function() {
      var that = this;
      var $searchInput = $('.map-search-input');

      // Load map
      this.map = new google.maps.Map(document.getElementById('stories_map'),config.MAPOPTIONS);

      // Listen to map loaded
      google.maps.event.addListenerOnce(this.map, 'idle', _.bind(function(){
        this._autoLocate();
      }, this ));

      // Set autocomplete search input
      this.autocomplete = new google.maps.places.Autocomplete($searchInput[0], {types: ['geocode']});

      // Listen to selected areas (search)
      google.maps.event.addListener(this.autocomplete, 'place_changed', _.bind(function() {
        var place = this.autocomplete.getPlace();
        if (place && place.geometry && place.geometry.viewport) {
          this.map.fitBounds(place.geometry.viewport)
        }
        if (place && place.geometry && place.geometry.location && !place.geometry.viewport) {
          var index = [];
          for (var x in place.geometry.location) {
             index.push(x);
          }
          this.map.setCenter(new google.maps.LatLng(place.geometry.location[index[0]], place.geometry.location[index[1]]));
        }
      }, this ));

      google.maps.event.addDomListener($searchInput[0], 'keydown', function(e) {
        if (e.keyCode == 13) {
          e.preventDefault();
        }
      });

      // Listen to any change on center position
      google.maps.event.addListener(this.map, 'zoom_changed',
        _.bind(function() {
          this.setCenter();
        }, this)
      );
      google.maps.event.addListener(this.map, 'dragend',
        _.bind(function() {
          this.setCenter();
      }, this));

    },

    _autoLocate: function(e){
      this.$autoLocate.addClass('active');
      if(navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(
          _.bind(function(position) {
            this.$autoLocate.removeClass('active');
            var pos = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
            this.map.panTo(pos);
            this.setCenter();
            this.setZoom(18);
          }, this ),
          _.bind(function() {
            this.$autoLocate.removeClass('active');
            mps.publish('Notification/open', ['notif-enable-location']);
          }, this )
        );
      }else{
        this.$autoLocate.removeClass('active');
      }
    },

    //ZOOM
    _zoomIn: function() {
      this.setZoom(this.getZoom() + 1);
    },
    _zoomOut: function(){
      this.setZoom(this.getZoom() - 1);
    },
    getZoom: function(){
      return this.map.getZoom();
    },
    setZoom: function(zoom){
      this.map.setZoom(zoom);
    },

    setCenter: function() {
      var center = this.map.getCenter();
      var the_geom = JSON.stringify({
        'type': 'Point',
        'coordinates': [ center.lng(), center.lat() ]
      });
      this.model.set('the_geom',the_geom);
      this.$the_geom.val(this.model.get('the_geom'));
    },

    prettifyFilename: function (filename) {
      var file = filename.substring(0,filename.length - 4);
      return file.toLowerCase().replace(/ /g,"_");
    },

    render: function() {
      this.$the_geom = this.$('#story_the_geom');
      this.$autoLocate = this.$('#autoLocate');

      var the_geom = this.$the_geom.val()
      this.model.set('the_geom', the_geom);

      return this;
    }
  });

  return StoriesEditView;

});

<commit_msg>drag and drop logic JS for the story thumbnails<commit_after>/**
 * The StoriesEdit view.
 */
define([
  'jquery',
  'backbone',
  'mps'
], function($,Backbone,mps) {

  'use strict';

  var config = {
    ZOOM: 3,
    MINZOOM: 3,
    MAXZOOM: 20,
    LAT: 15,
    LNG: 27,
    ISO: 'ALL',
    BASEMAP: 'grayscale',
    BASELAYER: 'loss',
    MONTHNAMES: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    MONTHNAMES_SHORT: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
    QUARTERNAMES: ["JAN - MAR", "APR - JUN", "JUL - SEP", "OCT - DEC"],
    mapLoaded: false
  };

  config.MAPOPTIONS = {
    zoom: config.ZOOM,
    minZoom: config.MINZOOM,
    maxZoom: config.MAXZOOM,
    center: new google.maps.LatLng(config.LAT, config.LNG),
    mapTypeId: google.maps.MapTypeId.HYBRID,
    backgroundColor: '#99b3cc',
    disableDefaultUI: true,
  };

  config.OVERLAYSTYLES = {
    strokeWeight: 2,
    fillOpacity: 0.45,
    fillColor: "#FFF",
    strokeColor: "#A2BC28",
    editable: true,
    icon: new google.maps.MarkerImage(
      '/assets/icons/marker_exclamation.png',
      new google.maps.Size(36, 36), // size
      new google.maps.Point(0, 0), // offset
      new google.maps.Point(18, 18) // anchor
    )
  };

  config.MAPSTYLES = {};

  config.MAPSTYLES.grayscale = {
    type: 'style',
    style: [ { "featureType": "water" }, { "featureType": "transit", "stylers": [ { "saturation": -100 } ] }, { "featureType": "road", "stylers": [ { "saturation": -100 } ] }, { "featureType": "poi", "stylers": [ { "saturation": -100 } ] }, { "featureType": "landscape", "stylers": [ { "saturation": -100 } ] }, { "featureType": "administrative", "stylers": [ { "saturation": -100 } ] },{ "featureType": "poi.park", "elementType": "geometry", "stylers": [ { "visibility": 'off' } ] } ]
  }

  config.MAPSTYLES.terrain = {
    type: 'mapType',
    style: google.maps.MapTypeId.TERRAIN,
    title: "Terrain"
  }

  config.MAPSTYLES.satellite = {
    type: 'mapType',
    style: google.maps.MapTypeId.SATELLITE,
    title: "Satellite"
  }

  config.MAPSTYLES.roads = {
    type: 'mapType',
    style: google.maps.MapTypeId.HYBRID,
    title: "Roads"
  }

  config.MAPSTYLES.treeheight = {
    type: 'customMapType',
    style: new google.maps.ImageMapType({
      getTileUrl: function(ll, z) {
        var X = Math.abs(ll.x % (1 << z)); // wrap
        return window.gfw.config.GFW_API_HOST + "/gee/simple_green_coverage/" + z + "/" + X + "/" + ll.y + ".png";
      },
      tileSize: new google.maps.Size(256, 256),
      isPng: true,
      maxZoom: 17,
      name: "Forest Height",
      alt: "Global forest height"
    })
  }

  config.MAPSTYLES.landsat = [];

  for(var i = 1999; i < 2013; i++) {
    (function(year) {
      config.MAPSTYLES.landsat[i] = new google.maps.ImageMapType({
        getTileUrl: function(ll, z) {
          var X = Math.abs(ll.x % (1 << z));  // wrap
          return window.gfw.config.GFW_API_HOST + "/gee/landsat_composites/" + z + "/" + X + "/" + ll.y + ".png?year="+year;
        },
        tileSize: new google.maps.Size(256, 256),
        isPng: true,
        maxZoom: 17,
        name: "Landsat "+i
      });
    })(i);
  }

  var StoriesEditModel = Backbone.Model.extend({
    defaults: {
      the_geom: null
    }
  })

  var StoriesEditView = Backbone.View.extend({

    el: '#storiesEditView',

    events: {
      'click #zoomIn': '_zoomIn',
      'click #zoomOut': '_zoomOut',
      'click #autoLocate': '_autoLocate',
      'input #story_video' : 'videoInput',
      'dragenter .sortable' : 'dragenter',
      'dragstart .sortable' : 'dragstart'
    },

    initialize: function() {
      if (!this.$el.length) {
        return
      }

      this.model = new StoriesEditModel();

      this.uploadsIds = [];
      this.filesAdded = 0;
      this.sourceDrag = undefined;

      this._initViews();
      this._initBindings();

      this.render();
    },

    videoInput: function(e) {
      this._addVideoThumbnail($(e.target).val());
    },

    _getVideoID: function(url) {
      // template: http://img.youtube.com/vi/<video-id-here>/default.jpg
      // a Youtube video ID has a 11 characters legngth
      return 'http://img.youtube.com/vi/' + url.split('v=')[1].substring(0, 11) + '/default.jpg';
    },

    _addVideoThumbnail: function(url) {
      var vidID  = this._getVideoID(url),
          $thumb = $('#videothumbnail');
      if ($thumb.length > 0) {
        $thumb.find('.inner_box').css('background-image','url('+ vidID +')')
      } else {
        $('.thumbnails').append('

<svg><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#shape-close"></use></svg>
');
        this.uploadsIds.push('VID-'+vidID);
        $thumb = $('#videothumbnail');
        $thumb.find('.destroy').on('click', function(e) {
            e.preventDefault();

            var confirmation = confirm('Are you sure?')

            if (confirmation == true) {
              this.uploadsIds = _.without(this.uploadsIds, 'VID-'+vidID);
              $("#story_uploads_ids").val(this.uploadsIds.join(","));

              $thumb.fadeOut(250, function() {
                $thumb.remove();
              });
            }
          });
      }
    },

    _initBindings: function() {
      var that = this;

      $('.upload_picture').on('click', function(e) {
        e.preventDefault();

        $('#fileupload').click();
      });

      $('#fileupload').fileupload({
          url: '/media/upload',
          dataType: 'json',
          autoUpload: true,
          acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
          maxFileSize: 4000000, // 4 MB
          // Enable image resizing, except for Android and Opera,
          // which actually support image resizing, but fail to
          // send Blob objects via XHR requests:
          disableImageResize: /Android(?!.*Chrome)|Opera/
            .test(window.navigator.userAgent),
          previewMaxWidth: 132,
          previewMaxHeight: 76,
          previewCrop: true,
          timeout: 3600000
      }).on('fileuploadadd', function (e, data) {
        data.context = $('
').appendTo('#files');

        that.filesAdded += _.size(data.files);
        _.each(data.files, function(file) {
          if (file && file.size > 4000000) {
            mps.publish('Notification/open', ['notif-limit-exceed']);
            return;
          } else {
            var filename = that.prettifyFilename(file.name);
            var $thumbnail = $("

"+ file.name +"

<svg><use xlink:href='#shape-spinner'></use></svg>

");
            $('.thumbnails').append($thumbnail);
            $thumbnail.fadeIn(250);

            var $submitButton = $("form input[type='submit']");
            $submitButton.addClass('disabled');
            $submitButton.attr('disabled', 'disabled');
            $submitButton.val('Please wait...');
          }
        });

        // data.submit();
      }).on('fileuploaddone', function (e, data) {
        var files = [data.result];

        $.each(files, function (index, file) {
          that.filesAdded--;
          that.uploadsIds.push(file.basename);

          var url = file.url.replace('https', 'http');
          var $thumb = $("

<svg><use xlink:href='#shape-close'></use></svg>
");

          var filename = that.prettifyFilename(file.basename).substring(45);

          $(".thumbnail[data-name='"+filename+"']").fadeOut(250, function() {
            $(this).remove();

            $(".thumbnails").append($thumb);
            $thumb.fadeIn(250);
          });

          $thumb.find('.destroy').on('click', function(e) {
            e.preventDefault();

            var confirmation = confirm('Are you sure?')

            if (confirmation == true) {
              that.uploadsIds = _.without(that.uploadsIds, file.basename);
              $("#story_uploads_ids").val(that.uploadsIds.join(","));

              $thumb.fadeOut(250, function() {
                $thumb.remove();
              });
            }
          });
        });

        if (that.filesAdded <= 0) {
          var $submitButton = $("form input[type='submit']");
          $submitButton.val('Submit story');
          $submitButton.removeClass('disabled');
          $submitButton.attr('disabled', false);
        }

        $('#story_uploads_ids').val(that.uploadsIds.join(','));
        ga('send', 'event', 'Stories', 'New story', 'submit');
      }).on('fileuploadfail', function (e, data){
        mps.publish('Notification/open', ['upload-error-server']);
        var $submitButton = $("form input[type='submit']");
        $submitButton.val('Submit story');
        $submitButton.removeClass('disabled');
        $submitButton.attr('disabled', false);
      });
    },

    _initViews: function() {
      var that = this;
      var $searchInput = $('.map-search-input');

      // Load map
      this.map = new google.maps.Map(document.getElementById('stories_map'),config.MAPOPTIONS);

      // Listen to map loaded
      google.maps.event.addListenerOnce(this.map, 'idle', _.bind(function(){
        this._autoLocate();
      }, this ));

      // Set autocomplete search input
      this.autocomplete = new google.maps.places.Autocomplete($searchInput[0], {types: ['geocode']});

      // Listen to selected areas (search)
      google.maps.event.addListener(this.autocomplete, 'place_changed', _.bind(function() {
        var place = this.autocomplete.getPlace();
        if (place && place.geometry && place.geometry.viewport) {
          this.map.fitBounds(place.geometry.viewport)
        }
        if (place && place.geometry && place.geometry.location && !place.geometry.viewport) {
          var index = [];
          for (var x in place.geometry.location) {
             index.push(x);
          }
          this.map.setCenter(new google.maps.LatLng(place.geometry.location[index[0]], place.geometry.location[index[1]]));
        }
      }, this ));

      google.maps.event.addDomListener($searchInput[0], 'keydown', function(e) {
        if (e.keyCode == 13) {
          e.preventDefault();
        }
      });

      // Listen to any change on center position
      google.maps.event.addListener(this.map, 'zoom_changed',
        _.bind(function() {
          this.setCenter();
        }, this)
      );
      google.maps.event.addListener(this.map, 'dragend',
        _.bind(function() {
          this.setCenter();
      }, this));

    },

    _autoLocate: function(e){
      this.$autoLocate.addClass('active');
      if(navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(
          _.bind(function(position) {
            this.$autoLocate.removeClass('active');
            var pos = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
            this.map.panTo(pos);
            this.setCenter();
            this.setZoom(18);
          }, this ),
          _.bind(function() {
            this.$autoLocate.removeClass('active');
            mps.publish('Notification/open', ['notif-enable-location']);
          }, this )
        );
      }else{
        this.$autoLocate.removeClass('active');
      }
    },

    isbefore: function(a, b) {
      if (a.parentNode == b.parentNode) {
        for (var cur = a; cur; cur = cur.previousSibling) {
          if (cur === b) {
              return true;
          }
        }
      }
      return false;
    },

    dragenter: function(e) {
      var target = e.target;
      if (this.isbefore(this.sourceDrag, target.parentNode)) {
          target.parentNode.parentNode.insertBefore(this.sourceDrag, target.parentNode);
      } else {
          target.parentNode.insertBefore(this.sourceDrag, target.nextSibling);
      }
    },

    dragstart: function(e) {
      this.sourceDrag = e.target;
      (e.originalEvent || e).dataTransfer.effectAllowed = 'move';
    },

    //ZOOM
    _zoomIn: function() {
      this.setZoom(this.getZoom() + 1);
    },
    _zoomOut: function(){
      this.setZoom(this.getZoom() - 1);
    },
    getZoom: function(){
      return this.map.getZoom();
    },
    setZoom: function(zoom){
      this.map.setZoom(zoom);
    },

    setCenter: function() {
      var center = this.map.getCenter();
      var the_geom = JSON.stringify({
        'type': 'Point',
        'coordinates': [ center.lng(), center.lat() ]
      });
      this.model.set('the_geom',the_geom);
      this.$the_geom.val(this.model.get('the_geom'));
    },

    prettifyFilename: function (filename) {
      var file = filename.substring(0,filename.length - 4);
      return file.toLowerCase().replace(/ /g,"_");
    },

    render: function() {
      this.$the_geom = this.$('#story_the_geom');
      this.$autoLocate = this.$('#autoLocate');

      var the_geom = this.$the_geom.val()
      this.model.set('the_geom', the_geom);

      return this;
    }
  });

  return StoriesEditView;

});

<|endoftext|>


<commit_before>'use strict';
const path    = require('path');
const _       = require('lodash');
const moment  = require('moment');
const low     = require('lowdb');
const storage = require('lowdb/file-sync');
const db      = low(path.resolve(__dirname, './calendar.json'), { storage });

/*
  {
    date: 'time', //day date
    meetings: 'int'
 }
*/

const Calendar = {
  table: 'calendar',
  stamp: 'MM-DD-YYYY'
};

Calendar.code = function(date){
  return moment(date).format(Calendar.stamp);
};

Calendar.decode = function(string){
  return moment(string, Calendar.stamp).toDate();
};

Calendar.serialize = function(day){
  day.date = Calendar.code(day.date);
  return day;
};

Calendar.deserialize = function(day){
  day.date = Calendar.decode(day.date);
  return day;
};

Calendar.all = function(){
  let days = db(Calendar.table)
    .chain()
    .value();

  return _.map(days, Calendar.deserialize);
};

Calendar.findByDate = function(date){
  return _.find(db(Calendar.table).value(), { date: Calendar.code(date) });
};

Calendar.has = function(day){
  return _.isUndefined(Calendar.findByDate(day.date)) === false;
};

Calendar.save = function(day){
  if(_.isUndefined(day)) return;

  if(Calendar.has(day) === false){
    console.log('save not found:', day);
    db(Calendar.table).push(Calendar.serialize(day));
  } else {
    Calendar.update(day);
  }
};

Calendar.update = function(day){
  console.log('update', day);

  return db(Calendar.table)
    .chain()
    .find({ date: Calendar.code(day.date) })
    .assign({ meetings: day.meetings })
    .value();
};

Calendar.filter = function(start){
  if(_.isUndefined(start)) start = Date.now();
  start = moment(Calendar.decode(Calendar.code(start)));

  let days = db(Calendar.table)
    .chain()
    .value();

  days = _.filter(days, function(day){
    let date = Calendar.decode(day.date);
    return start.isSameOrBefore(moment(date))
  });

  return _.map(days, Calendar.deserialize);
};

Calendar.saveAll = function(days){
  days.forEach(function(day){
    Calendar.save(day);
  });
};

module.exports = Calendar;
<commit_msg>fix calnedar storage bug<commit_after>'use strict';
const path    = require('path');
const _       = require('lodash');
const moment  = require('moment');
const low     = require('lowdb');
const storage = require('lowdb/file-sync');
const db      = low(path.resolve(__dirname, './calendar.json'), { storage });

/*
  {
    date: 'time', //day date
    meetings: 'int'
 }
*/

const Calendar = {
  table: 'calendar',
  stamp: 'MM-DD-YYYY'
};

Calendar.code = function(date){
  return moment(date).format(Calendar.stamp);
};

Calendar.decode = function(string){
  return moment(string, Calendar.stamp).toDate();
};

Calendar.serialize = function(day){
  return {
    date: Calendar.code(new Date(day.date.valueOf())),
    meetings: day.meetings
  };
};

Calendar.deserialize = function(day){
  return {
    date: Calendar.decode(day.date),
    meetings: day.meetings
  };
};

Calendar.all = function(){
  let days = db(Calendar.table)
    .chain()
    .value();

  return _.map(days, Calendar.deserialize);
};

Calendar.findByDate = function(date){
  return _.find(db(Calendar.table).value(), { date: Calendar.code(date) });
};

Calendar.has = function(day){
  return _.isUndefined(Calendar.findByDate(day.date)) === false;
};

Calendar.save = function(day){
  if(_.isUndefined(day)) return;
  if(Calendar.has(day)){
    Calendar.update(day);
  } else {
    db(Calendar.table).push(Calendar.serialize(day));
  }
};

Calendar.update = function(day){
  return db(Calendar.table)
    .chain()
    .find({ date: Calendar.code(day.date) })
    .assign({ meetings: day.meetings })
    .value();
};

Calendar.filter = function(start){
  if(_.isUndefined(start)) start = Date.now();
  start = moment(Calendar.decode(Calendar.code(start)));

  let days = db(Calendar.table)
    .chain()
    .value();

  let filteredDays = _.filter(days, function(day){
    let date = Calendar.decode(day.date);
    return start.isSameOrBefore(moment(date))
  });

  return _.map(filteredDays, Calendar.deserialize);
};

Calendar.saveAll = function(days){
  days.forEach(function(day){
    Calendar.save(day);
  });
};

module.exports = Calendar;
<|endoftext|>


<commit_before>// (C) Copyright 2014-2015 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';

const CLASS_ROOT = "check-box";

export default class CheckBox extends Component {

  set checked (value) {
    if ('refs' in this) {
      this.refs.input.checked = !!value;
    }
  }

  get checked () {
    return 'refs' in this ? this.refs.input.checked : null;
  }

  render () {
    var classes = [CLASS_ROOT];
    var labelId = 'checkbox-label';
    var hidden;
    if (this.props.toggle) {
      classes.push(CLASS_ROOT + "--toggle");
    }
    if (this.props.disabled) {
      classes.push(CLASS_ROOT + "--disabled");
      if (this.props.checked) {
        hidden = (
          <input name={this.props.name} type="hidden" value="true"/>
        );
      }
    }
    if (this.props.className) {
      classes.push(this.props.className);
    }

    return (

        <input tabIndex="0" className={CLASS_ROOT + "__input"}
          id={this.props.id} name={this.props.name} type="checkbox"
          disabled={this.props.disabled}
          checked={this.props.checked}
          defaultChecked={this.props.defaultChecked}
          onChange={this.props.onChange}
          ref="input" />

          <svg className={CLASS_ROOT + "__control-check"} viewBox="0 0 24 24"
            preserveAspectRatio="xMidYMid meet">
            <path fill="none" d="M6,11.3 L10.3,16 L18,6.2"></path>
          </svg>

        {hidden}

          {this.props.label}

    );
  }

}

CheckBox.propTypes = {
  checked: PropTypes.bool,
  defaultChecked: PropTypes.bool,
  disabled: PropTypes.bool,
  id: PropTypes.string.isRequired,
  label: PropTypes.node.isRequired,
  name: PropTypes.string,
  onChange: PropTypes.func,
  ariaDescribedby: PropTypes.string,
  toggle: PropTypes.bool
};
<commit_msg>Fix typo in `aria-labelledby`attribute<commit_after>// (C) Copyright 2014-2015 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';

const CLASS_ROOT = "check-box";

export default class CheckBox extends Component {

  set checked (value) {
    if ('refs' in this) {
      this.refs.input.checked = !!value;
    }
  }

  get checked () {
    return 'refs' in this ? this.refs.input.checked : null;
  }

  render () {
    var classes = [CLASS_ROOT];
    var labelId = 'checkbox-label';
    var hidden;
    if (this.props.toggle) {
      classes.push(CLASS_ROOT + "--toggle");
    }
    if (this.props.disabled) {
      classes.push(CLASS_ROOT + "--disabled");
      if (this.props.checked) {
        hidden = (
          <input name={this.props.name} type="hidden" value="true"/>
        );
      }
    }
    if (this.props.className) {
      classes.push(this.props.className);
    }

    return (

        <input tabIndex="0" className={CLASS_ROOT + "__input"}
          id={this.props.id} name={this.props.name} type="checkbox"
          disabled={this.props.disabled}
          checked={this.props.checked}
          defaultChecked={this.props.defaultChecked}
          onChange={this.props.onChange}
          ref="input" />

          <svg className={CLASS_ROOT + "__control-check"} viewBox="0 0 24 24"
            preserveAspectRatio="xMidYMid meet">
            <path fill="none" d="M6,11.3 L10.3,16 L18,6.2"></path>
          </svg>

        {hidden}

          {this.props.label}

    );
  }

}

CheckBox.propTypes = {
  checked: PropTypes.bool,
  defaultChecked: PropTypes.bool,
  disabled: PropTypes.bool,
  id: PropTypes.string.isRequired,
  label: PropTypes.node.isRequired,
  name: PropTypes.string,
  onChange: PropTypes.func,
  ariaDescribedby: PropTypes.string,
  toggle: PropTypes.bool
};
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import _ from 'lodash';
import DaySchedule from './DaySchedule';
import TimeColumn from './TimeColumn';
import StageColumn from './StageColumn';

export default class Schedule extends Component {
  static propTypes = {
    schedule: PropTypes.array.isRequired
  };

  render() {
    const { schedule } = this.props;
    const groupedSchedules = _.groupBy(schedule, 'day');

    return

Schedule

        Friday
        Saturday
        Sunday

      <TimeColumn times={[]} />
      <StageColumn />
      <DaySchedule day={'Friday'} schedule={schedule[0]}/>
      <DaySchedule day={'Saturday'} schedule={schedule[1]}/>
      <DaySchedule day={'Sunday'} schedule={schedule[2]}/>

;
  }
}
<commit_msg>Fix schedules passed down to DaySchedule<commit_after>import React, { Component, PropTypes } from 'react';
import _ from 'lodash';
import DaySchedule from './DaySchedule';
import TimeColumn from './TimeColumn';
import StageColumn from './StageColumn';

export default class Schedule extends Component {
  static propTypes = {
    schedule: PropTypes.array.isRequired
  };

  render() {
    const { schedule } = this.props;
    const groupedSchedules = _.groupBy(schedule, 'day');

    return

Schedule

        Friday
        Saturday
        Sunday

      <TimeColumn times={[]} />
      <StageColumn />
      <DaySchedule day={'Friday'} schedule={groupedSchedules['2016-08-05']}/>
      <DaySchedule day={'Saturday'} schedule={groupedSchedules['2016-08-06']}/>
      <DaySchedule day={'Sunday'} schedule={groupedSchedules['2016-08-07']}/>

;
  }
}
<|endoftext|>


<commit_before>// A wrapper to spin up an instance of couchdb-lucene for use in tests.  This is not intended for production use
// with CouchDB.
//
// The configuration options are:
//
// {
//   port:     "9999"                  // The port couchdb-lucene will run on
//   db: {
//     url:    "http://localhost:7986/" // The URL on which Pouch is running
//     nick:   "local",                // The "nickname" to use for the database when generating the configuration file.
// }
//
// NOTE:  This component cannot be used repeatedly in a `testCaseHolder` element without adding special steps to your
// test sequence.  Your first set of tests within a single `testCaseHolder` will generally succeed, but subsequent
// tests may:
//
// 1. Fail with messages about not being able to reach parts of a component that has already been destroyed.
// 2. Succeed, but generate messages about the port number already being in use.
// 3. Succeed, but only because they randomly managed to start up at the right time.
//
// To use multiple tests in a single `testCaseHolder`, your test sequences must:
//
// 1. Trigger an `onReadyForShutdown` event when you are finished with the rest of your sequence.
// 2. Listen for this component's `onShutdownComplete` event at the end of your test sequence.
//
// The end of your test sequence should look something like:
//
//    sequence: [
//        // Test something here
//        ...
//        // Tell pouchdb-lucene to shut down
//        {
//            func: "{gpii.pouch.lucene}.events.onReadyForShutdown.fire"
//        }
//        // Confirm that pouchdb-lucene is shut down
//        {
//            listener: "fluid.identity"
//            event:    "{gpii.pouch.lucene}.events.onShutdownComplete"
//        }
//    ]
//
// For more examples of using this component more than once in the same `testCaseHolder`, check out the tests in this
// package.
//
"use strict";
var fluid = fluid || require("infusion");
var gpii  = fluid.registerNamespace("gpii");

var AdmZip        = require("adm-zip");
var path          = require("path");
var os            = require("os");
var fs            = require("fs");
var child_process = require("child_process");

// There are some constants that we use in `npm` scripts as well as here, they are found in `package.json`.
var npmSettings = require("../../package.json");

// Configure our directory locations based on the module location and the OS temporary directory.
var basePath = fluid.module.resolvePath("%gpii-pouchdb-lucene/");
var zipPath  = path.resolve(basePath, npmSettings.config.zipPath);
var tmpDir   = os.tmpdir();

var fs = require("fs");

fluid.registerNamespace("gpii.pouch.lucene");
gpii.pouch.lucene.init = function (that){
    // Use our ID as a unique identifier so that we can avoid clobbering another instance.
    var outputDir = path.resolve(that.options.tmpDir, that.id);

    // Unpack the "dist" zip created when we were installed to create a new working directory.
    fluid.log("Creating working directory for this instance...");
    fluid.log("output dir = " + outputDir);

    if (!fs.existsSync(that.options.zipPath)) {
        fluid.fail("The specified couchdb-lucene zip file doesn't exist: '" + that.options.zipPath + "'...");
    }

    var distZip = new AdmZip(that.options.zipPath);
    distZip.extractAllTo(outputDir);

    var workingDir = path.resolve(outputDir, "couchdb-lucene-" + npmSettings.config.version);
    var confFile    = path.resolve(workingDir, "conf", "couchdb-lucene.ini");

    fluid.log("Generating configuration file...");
    var iniContent = gpii.pouch.lucene.generateIniContent(that);
    fs.writeFileSync(confFile, iniContent);

    // Start the service using either the batch file on windows, or the shell script on anything else.
    fluid.log("Starting couchdb-lucene...");
    var script = os.platform().indexOf("win") === 0 ? "bin/run.bat" : "sh bin/run"; // The unix script is not always executable when it's unpacked.
    that.process = child_process.exec(script, { cwd: workingDir}, that.respondToProcessTermination);

    that.safetyTimeout = setTimeout(that.destroyOnTimeout, that.options.processTimeout);

    that.process.stdout.on("data", that.waitForStartup);
};

gpii.pouch.lucene.respondToProcessTermination = function (that, error) {
    if (error) {
        // This is not a fail because we want the rest of the shutdown and cleanup to complete
        fluid.log("Lucene processed stopped with an error:", error);
    }

    that.events.onShutdownComplete.fire();
};

gpii.pouch.lucene.destroyOnTimeout = function (that) {
    fluid.log("Timeout reached for pouchdb lucene process, stopping it automatically...");
    that.events.onReadyForShutdown.fire(that);
};

// Ensure that the service is stopped on component destruction
gpii.pouch.lucene.stopProcess = function (that) {
    clearTimeout(that.safetyTimeout);

    if (that.process) {
        that.process.kill();
    }
};

// Monitor the process' logs for "Accepting connections" and fire an `onStarted` event when the service is ready to
// accept connections.
gpii.pouch.lucene.waitForStartup = function (that, chunk) {
    if (typeof chunk === "string" && chunk.indexOf("Accepting connections") !== -1) {
        // pouchdb-lucene is actually ready a few milliseconds after the log message we look for.
        setTimeout(function(){ that.events.onStarted.fire(that); }, that.options.startupDelay);
    }
    fluid.log(chunk);
};

gpii.pouch.lucene.generateIniContent = function(that) {
    var output = "";
    fluid.each(that.options.iniSettings, function(settings, section){
        output += "\n[" + section + "]\n";

        fluid.each(settings, function (value, key){
            output += key + "=" + value + "\n";
        });
    });

    return output;
};

fluid.defaults("gpii.pouch.lucene", {
    gradeNames:     ["fluid.component"],
    port:           9999,
    startupDelay:   250, // How long to wait before reporting that couchdb-lucene is ready.
    dbUrl:          "http://localhost:5986/ul",
    // As a safety measure, we will automatically kill our process after `processTimeout` milliseconds.
    processTimeout: 60000,
    // The settings we will write to couchdb-lucene's configuration file.  Each top level key will become a section
    // entry, as in [lucene].  Each sub key-value pair will become an entry, as in dir=indexes
    iniSettings: {
        lucene: {
            dir:                  "indexes",
            host:                 "localhost",
            port:                 "{that}.options.port",
            limit:                25,
            allowLeadingWildcard: false
        },
        local: {
            url:  "{that}.options.dbUrl"
        }
    },
    // The location of our distribution zip and working directory.  You should not need to change these.
    zipPath:     zipPath,
    tmpDir:      tmpDir,
    members: {
        process: false
    },
    events: {
        onStarted:          null,
        onReadyForShutdown: null,
        onShutdownComplete: null
    },
    listeners: {
        "onCreate.init": {
            funcName: "gpii.pouch.lucene.init",
            args:     ["{that}"]
        },
        "onReadyForShutdown.stopProcess": {
            funcName: "gpii.pouch.lucene.stopProcess",
            args:     ["{that}"]
        },
        "onStarted.log": {
            funcName: "fluid.log",
            args:     ["pouchdb-lucene started successfully..."]
        },
        "onReadyForShutdown.log": {
            funcName: "fluid.log",
            args:     ["pouchdb-lucene ready for shutdown..."]
        },
        "onShutdownComplete.log": {
            funcName: "fluid.log",
            args:     ["pouchdb-lucene shutdown complete..."]
        }
    },
    invokers: {
        waitForStartup: {
            funcName: "gpii.pouch.lucene.waitForStartup",
            args:     ["{that}", "{arguments}.0"]
        },
        destroyOnTimeout: {
            funcName: "gpii.pouch.lucene.destroyOnTimeout",
            args:     ["{that}"]
        },
        respondToProcessTermination: {
            funcName: "gpii.pouch.lucene.respondToProcessTermination",
            args:     ["{that}", "{arguments}.0"]
        }
    }
});<commit_msg>GPII-1241: Refined error logging on process shutdown.<commit_after>// A wrapper to spin up an instance of couchdb-lucene for use in tests.  This is not intended for production use
// with CouchDB.
//
// The configuration options are:
//
// {
//   port:     "9999"                  // The port couchdb-lucene will run on
//   db: {
//     url:    "http://localhost:7986/" // The URL on which Pouch is running
//     nick:   "local",                // The "nickname" to use for the database when generating the configuration file.
// }
//
// NOTE:  This component cannot be used repeatedly in a `testCaseHolder` element without adding special steps to your
// test sequence.  Your first set of tests within a single `testCaseHolder` will generally succeed, but subsequent
// tests may:
//
// 1. Fail with messages about not being able to reach parts of a component that has already been destroyed.
// 2. Succeed, but generate messages about the port number already being in use.
// 3. Succeed, but only because they randomly managed to start up at the right time.
//
// To use multiple tests in a single `testCaseHolder`, your test sequences must:
//
// 1. Trigger an `onReadyForShutdown` event when you are finished with the rest of your sequence.
// 2. Listen for this component's `onShutdownComplete` event at the end of your test sequence.
//
// The end of your test sequence should look something like:
//
//    sequence: [
//        // Test something here
//        ...
//        // Tell pouchdb-lucene to shut down
//        {
//            func: "{gpii.pouch.lucene}.events.onReadyForShutdown.fire"
//        }
//        // Confirm that pouchdb-lucene is shut down
//        {
//            listener: "fluid.identity"
//            event:    "{gpii.pouch.lucene}.events.onShutdownComplete"
//        }
//    ]
//
// For more examples of using this component more than once in the same `testCaseHolder`, check out the tests in this
// package.
//
"use strict";
var fluid = fluid || require("infusion");
var gpii  = fluid.registerNamespace("gpii");

var AdmZip        = require("adm-zip");
var path          = require("path");
var os            = require("os");
var fs            = require("fs");
var child_process = require("child_process");

// There are some constants that we use in `npm` scripts as well as here, they are found in `package.json`.
var npmSettings = require("../../package.json");

// Configure our directory locations based on the module location and the OS temporary directory.
var basePath = fluid.module.resolvePath("%gpii-pouchdb-lucene/");
var zipPath  = path.resolve(basePath, npmSettings.config.zipPath);
var tmpDir   = os.tmpdir();

var fs = require("fs");

fluid.registerNamespace("gpii.pouch.lucene");
gpii.pouch.lucene.init = function (that){
    // Use our ID as a unique identifier so that we can avoid clobbering another instance.
    var outputDir = path.resolve(that.options.tmpDir, that.id);

    // Unpack the "dist" zip created when we were installed to create a new working directory.
    fluid.log("Creating working directory for this instance...");
    fluid.log("output dir = " + outputDir);

    if (!fs.existsSync(that.options.zipPath)) {
        fluid.fail("The specified couchdb-lucene zip file doesn't exist: '" + that.options.zipPath + "'...");
    }

    var distZip = new AdmZip(that.options.zipPath);
    distZip.extractAllTo(outputDir);

    var workingDir = path.resolve(outputDir, "couchdb-lucene-" + npmSettings.config.version);
    var confFile    = path.resolve(workingDir, "conf", "couchdb-lucene.ini");

    fluid.log("Generating configuration file...");
    var iniContent = gpii.pouch.lucene.generateIniContent(that);
    fs.writeFileSync(confFile, iniContent);

    // Start the service using either the batch file on windows, or the shell script on anything else.
    fluid.log("Starting couchdb-lucene...");
    var script = os.platform().indexOf("win") === 0 ? "bin/run.bat" : "sh bin/run"; // The unix script is not always executable when it's unpacked.
    that.process = child_process.exec(script, { cwd: workingDir}, that.respondToProcessTermination);

    that.safetyTimeout = setTimeout(that.destroyOnTimeout, that.options.processTimeout);

    that.process.stdout.on("data", that.waitForStartup);
};

// Report any errors if the process ends abnormally.  We do not care about "normal" process kills, only abnormal exits.
//
// Thus we look only for output to stderr.
gpii.pouch.lucene.respondToProcessTermination = function (that, stderr) {
    if (stderr) {
        // This is not a fail because we want the rest of the shutdown and cleanup to complete
        fluid.log(stderr.toString());
    }

    that.events.onShutdownComplete.fire();
};

gpii.pouch.lucene.destroyOnTimeout = function (that) {
    fluid.log("Timeout reached for pouchdb lucene process, stopping it automatically...");
    that.events.onReadyForShutdown.fire(that);
};

// Ensure that the service is stopped on component destruction
gpii.pouch.lucene.stopProcess = function (that) {
    clearTimeout(that.safetyTimeout);

    if (that.process) {
        that.process.kill();
    }
};

// Monitor the process' logs for "Accepting connections" and fire an `onStarted` event when the service is ready to
// accept connections.
gpii.pouch.lucene.waitForStartup = function (that, chunk) {
    if (typeof chunk === "string" && chunk.indexOf("Accepting connections") !== -1) {
        // pouchdb-lucene is actually ready a few milliseconds after the log message we look for.
        setTimeout(function(){ that.events.onStarted.fire(that); }, that.options.startupDelay);
    }
    fluid.log(chunk);
};

gpii.pouch.lucene.generateIniContent = function(that) {
    var output = "";
    fluid.each(that.options.iniSettings, function(settings, section){
        output += "\n[" + section + "]\n";

        fluid.each(settings, function (value, key){
            output += key + "=" + value + "\n";
        });
    });

    return output;
};

fluid.defaults("gpii.pouch.lucene", {
    gradeNames:     ["fluid.component"],
    port:           9999,
    startupDelay:   250, // How long to wait before reporting that couchdb-lucene is ready.
    dbUrl:          "http://localhost:5986/ul",
    // As a safety measure, we will automatically kill our process after `processTimeout` milliseconds.
    processTimeout: 60000,
    // The settings we will write to couchdb-lucene's configuration file.  Each top level key will become a section
    // entry, as in [lucene].  Each sub key-value pair will become an entry, as in dir=indexes
    iniSettings: {
        lucene: {
            dir:                  "indexes",
            host:                 "localhost",
            port:                 "{that}.options.port",
            limit:                25,
            allowLeadingWildcard: false
        },
        local: {
            url:  "{that}.options.dbUrl"
        }
    },
    // The location of our distribution zip and working directory.  You should not need to change these.
    zipPath:     zipPath,
    tmpDir:      tmpDir,
    members: {
        process: false
    },
    events: {
        onStarted:          null,
        onReadyForShutdown: null,
        onShutdownComplete: null
    },
    listeners: {
        "onCreate.init": {
            funcName: "gpii.pouch.lucene.init",
            args:     ["{that}"]
        },
        "onReadyForShutdown.stopProcess": {
            funcName: "gpii.pouch.lucene.stopProcess",
            args:     ["{that}"]
        },
        "onStarted.log": {
            funcName: "fluid.log",
            args:     ["pouchdb-lucene started successfully..."]
        },
        "onReadyForShutdown.log": {
            funcName: "fluid.log",
            args:     ["pouchdb-lucene ready for shutdown..."]
        },
        "onShutdownComplete.log": {
            funcName: "fluid.log",
            args:     ["pouchdb-lucene shutdown complete..."]
        }
    },
    invokers: {
        waitForStartup: {
            funcName: "gpii.pouch.lucene.waitForStartup",
            args:     ["{that}", "{arguments}.0"]
        },
        destroyOnTimeout: {
            funcName: "gpii.pouch.lucene.destroyOnTimeout",
            args:     ["{that}"]
        },
        respondToProcessTermination: {
            funcName: "gpii.pouch.lucene.respondToProcessTermination",
            args:     ["{that}", "{arguments}.2"] // the process callback is passed: error, stdout, stderr
        }
    }
});<|endoftext|>


<commit_before>import { CursorMaterial } from './CursorMaterial';
import { ClusterMaterial } from './ClusterMaterial';
import { ContourMaterial } from './ContourMaterial';
import { DepthMaterial } from './DepthMaterial';
import { DepthCursorMaterial } from './DepthCursorMaterial';
import { DepthMapMaterial } from './DepthMapMaterial';
import { ExtendedPointsMaterial } from './ExtendedPointsMaterial';
import { GlyphMaterial } from './GlyphMaterial';
import { HeightMaterial } from './HeightMaterial';
import { ZMaterial } from './ZMaterial';
import { HypsometricMaterial } from './HypsometricMaterial';
import { MissingMaterial } from './MissingMaterial';
import { SurveyLineMaterial } from './SurveyLineMaterial';
import { Line2Material } from './Line2Material';
import { ColourCache } from '../core/ColourCache';
import { TextureCache } from '../core/TextureCache';
import { GlyphAtlasCache } from './GlyphAtlas';
import { EntrancePointMaterial } from './EntrancePointMaterial';

import {
	LineBasicMaterial, MeshLambertMaterial, MeshBasicMaterial, MeshPhongMaterial,
	IncrementStencilOp,
} from '../Three';

function Materials ( viewer ) {

	const cache = new Map();
	const ctx = viewer.ctx;
	const self = this;

	const glyphAtlasCache = new GlyphAtlasCache();
	const cursorMaterials = new Set();
	const lineMaterials = new Set();
	const surveyLineMaterials = new Set();

	let perSurveyMaterials = {};

	let cursorHeight = 0;
	let linewidth = 1;
	let scaleLinewidth = false;

	const colourCache = new ColourCache();
	const textureCache = new TextureCache();

	this.colourCache = colourCache;
	this.textureCache = textureCache;

	const cfg = ctx.cfg;

	const gradientType = cfg.value( 'saturatedGradient', false ) || cfg.themeValue( 'saturatedGradient' );
	const gradient = gradientType ? 'gradientHi' : 'gradientLow';
	const surfaceColour = cfg.themeValue( 'shading.single' );

	this.commonUniforms = {
		fogColor: { value: cfg.themeColor( 'background' ) },
		fogDensity: { value: 0.0025 },
		distanceTransparency: { value: 0.0 }
	};

	this.commonDepthUniforms = {
		datumShift: { value: 0.0 }
	};

	this.cursorUniforms = {
		cursor:      { value: 0 },
		cursorWidth: { value: 5.0 },
		baseColor:   { value: cfg.themeColor( 'shading.cursorBase' ) },
		cursorColor: { value: cfg.themeColor( 'shading.cursor' ) },
	};

	this.terrainOpacity = 0.5;

	Object.defineProperty( this, 'cursorHeight', {
		get: function () { return cursorHeight; },
		set: updateCursors
	} );

	Object.defineProperty( this, 'linewidth', {
		get: function () { return linewidth; },
		set: updateLinewidth
	} );

	Object.defineProperty( this, 'scaleLinewidth', {
		get: function () { return scaleLinewidth; },
		set: updateScaleLinewidth
	} );

	const distanceTransparency = this.commonUniforms.distanceTransparency;

	Object.defineProperty( this, 'distanceTransparency', {
		get: function () { return distanceTransparency.value; },
		set: function ( x ) { distanceTransparency.value = x; }
	} );

	function cacheMaterial ( name, material, stencil ) {

		cache.set( name, material );

		if ( stencil ) {

			material.stencilWrite = true;
			material.stencilZPass = IncrementStencilOp;

		}

		return material;

	}

	function getCacheMaterial ( name, materialFunc, stencil ) {

		let material = cache.get( name );

		if ( material === undefined ) {

			material = cacheMaterial( name, materialFunc(), stencil );

		}

		return material;

	}

	function getSurveyCacheMaterial ( name, materialFunc, stencil ) {

		const material = getCacheMaterial( name, materialFunc, stencil );
		perSurveyMaterials[ name ] = material;

		return material;

	}

	function updateCursors( newHeight ) {

		cursorMaterials.forEach( material => cursorHeight = material.setCursor( newHeight ) );

	}

	function updateLinewidth( width ) {

		lineMaterials.forEach( material => material.linewidth = width );
		linewidth = width;

	}

	function updateScaleLinewidth( mode ) {

		surveyLineMaterials.forEach( material => material.scaleLinewidth = mode );
		scaleLinewidth = mode;

	}

	function updateDatumShifts( event ) {

		self.commonDepthUniforms.datumShift.value = event.value;

	}

	this.getLine2Material = function ( params = { color: 'green' } ) {

		const func = function () { return new Line2Material( ctx, params ); };
		const material = getCacheMaterial( 'line2' + JSON.stringify( params ), func, true );

		return material;

	};

	this.getSurveyLineMaterial = function ( mode = '', dashed = false ) {

		const func = function () { return new SurveyLineMaterial( ctx, mode, dashed ); };
		const material = getSurveyCacheMaterial( 'survey-line-' + mode + ( dashed ? '-dashed' : '' ), func, true );

		if ( mode === 'cursor' || mode === 'depth-cursor' ) {

			// set active cursor material for updating
			cursorMaterials.add( material );

		}

		lineMaterials.add( material );
		surveyLineMaterials.add( material );
		material.linewidth = linewidth;

		return material;

	};

	this.getHeightMaterial = function () {

		const func = function () { return new HeightMaterial( ctx ); };
		return getSurveyCacheMaterial( 'height', func, true );

	};

	this.getZMaterial = function () {

		const func = function () { return new ZMaterial( ctx ); };
		return getSurveyCacheMaterial( 'z', func, true );

	};

	this.getHypsometricMaterial = function () {

		const func = function () { return new HypsometricMaterial( ctx ); };
		return getSurveyCacheMaterial( 'hypsometric', func );

	};

	this.getDepthMapMaterial = function ( terrain ) {

		return new DepthMapMaterial( terrain );

	};

	this.getDepthMaterial = function () {

		const func = function () { return new DepthMaterial( ctx ); };
		return getSurveyCacheMaterial( 'depth', func, true );

	};

	this.getCursorMaterial = function () {

		const func = function () { return new CursorMaterial( ctx ); };
		const material = getSurveyCacheMaterial( 'cursor', func, true );

		// set active cursor material for updating
		cursorMaterials.add( material );

		return material;

	};

	this.getDepthCursorMaterial = function () {

		const func = function () { return new DepthCursorMaterial( ctx ); };
		const material = getSurveyCacheMaterial( 'depthCursor', func, true );

		// set active cursor material for updating
		cursorMaterials.add( material );

		return material;

	};

	this.getBezelMaterial = function  () {

		let func;

		if ( ctx.cfg.themeValue( 'hud.bezelType' ) === 'flat' ) {

			func = function () { return new MeshBasicMaterial( { color: ctx.cfg.themeValue( 'hud.bezel' ) } ); };

		} else {

			func = function () { return new MeshPhongMaterial( { color: ctx.cfg.themeValue( 'hud.bezel' ), specular: 0x888888 } ); };

		}

		return getCacheMaterial( 'bezel', func, true );

	};

	this.getPlainMaterial = function  () {

		const func = function () { return new MeshBasicMaterial( { color: 0xffffff, vertexColors: true } ); };
		return getCacheMaterial( 'plain', func, true );

	};

	this.getSurfaceMaterial = function  () {

		const func = function () { return new MeshLambertMaterial( { color: surfaceColour, vertexColors: false } ); };
		return getCacheMaterial( 'surface', func, true );

	};

	this.getEntrancePointMaterial = function  () {

		const func = function () { return new EntrancePointMaterial( ctx ); };
		return getCacheMaterial( 'entrance', func, true );

	};

	this.getExtendedPointsMaterial = function () {

		const func = function () { return new ExtendedPointsMaterial( ctx ); };
		return getCacheMaterial( 'extendedPoints', func, true );

	};

	this.getMissingMaterial = function () {

		const func = function () { return new MissingMaterial( ctx ); };
		return getCacheMaterial( 'missing', func );

	};

	this.getUnselectedMaterial = function () {

		const func = function () { return new LineBasicMaterial( { color: 0x444444, vertexColors: true } ); };
		return getCacheMaterial( 'unselected', func );

	};

	this.getUnselectedWallMaterial = function () {

		const func = function () { return new MeshLambertMaterial( { color: 0x444444, vertexColors: true} ); };
		return getCacheMaterial( 'unselectedWall', func );

	};

	this.getScaleMaterial = function () {

		const func = function () { return new MeshBasicMaterial( { color: 0xffffff, map: textureCache.getTexture( gradient ) } ); };
		return getCacheMaterial( 'scale', func );

	};

	this.getContourMaterial = function () {

		const func = function () { return new ContourMaterial( ctx ); };
		return getSurveyCacheMaterial( 'contour', func );

	};

	this.getGlyphMaterial = function ( glyphAtlasSpec, rotation ) {

		const atlas = glyphAtlasCache.getAtlas( glyphAtlasSpec );
		const name = JSON.stringify( glyphAtlasSpec ) + ':' + rotation.toString();

		const func = function () { return new GlyphMaterial( ctx, atlas, rotation, viewer ); };

		return getCacheMaterial( name, func );

	};

	this.getClusterMaterial = function ( count ) {

		const func = function () { return new ClusterMaterial( count ); };
		return getCacheMaterial( 'cluster' + count, func, true );

	};

	this.setTerrain = function ( terrain ) {

		terrain.addEventListener( 'datumShiftChange', updateDatumShifts );

	};

	this.flushCache = function () {

		cursorMaterials.clear();
		lineMaterials.clear();
		surveyLineMaterials.clear();

		for ( const name in perSurveyMaterials ) {

			const material = perSurveyMaterials[ name ];

			material.dispose();
			cache.delete( name );

		}

		perSurveyMaterials = {};
		ctx.glyphStringCache = new Map();
		cursorHeight = 0;

	};

	this.setFog = function ( enable ) {

		for ( const name in perSurveyMaterials ) {

			const material = perSurveyMaterials[ name ];

			material.fog = enable;
			material.needsUpdate = true;

		}

	};

}

export { Materials };<commit_msg>clean up materials<commit_after>import { CursorMaterial } from './CursorMaterial';
import { ClusterMaterial } from './ClusterMaterial';
import { ContourMaterial } from './ContourMaterial';
import { DepthMaterial } from './DepthMaterial';
import { DepthCursorMaterial } from './DepthCursorMaterial';
import { ExtendedPointsMaterial } from './ExtendedPointsMaterial';
import { GlyphMaterial } from './GlyphMaterial';
import { HeightMaterial } from './HeightMaterial';
import { ZMaterial } from './ZMaterial';
import { HypsometricMaterial } from './HypsometricMaterial';
import { MissingMaterial } from './MissingMaterial';
import { SurveyLineMaterial } from './SurveyLineMaterial';
import { Line2Material } from './Line2Material';
import { ColourCache } from '../core/ColourCache';
import { TextureCache } from '../core/TextureCache';
import { GlyphAtlasCache } from './GlyphAtlas';
import { EntrancePointMaterial } from './EntrancePointMaterial';

import {
	LineBasicMaterial, MeshLambertMaterial, MeshBasicMaterial, MeshPhongMaterial,
	IncrementStencilOp,
} from '../Three';

function Materials ( viewer ) {

	const cache = new Map();
	const ctx = viewer.ctx;
	const cfg = ctx.cfg;
	const self = this;

	const glyphAtlasCache = new GlyphAtlasCache();
	const cursorMaterials = new Set();
	const lineMaterials = new Set();
	const surveyLineMaterials = new Set();

	let perSurveyMaterials = {};

	let cursorHeight = 0;
	let linewidth = 1;
	let scaleLinewidth = false;

	const colourCache = new ColourCache();
	const textureCache = new TextureCache();

	this.colourCache = colourCache;
	this.textureCache = textureCache;

	const gradientType = cfg.value( 'saturatedGradient', false ) || cfg.themeValue( 'saturatedGradient' );
	const gradient = gradientType ? 'gradientHi' : 'gradientLow';
	const surfaceColour = cfg.themeValue( 'shading.single' );

	this.commonUniforms = {
		fogColor: { value: cfg.themeColor( 'background' ) },
		fogDensity: { value: 0.0025 },
		distanceTransparency: { value: 0.0 }
	};

	this.commonDepthUniforms = {
		datumShift: { value: 0.0 }
	};

	this.cursorUniforms = {
		cursor:      { value: 0 },
		cursorWidth: { value: 5.0 },
		baseColor:   { value: cfg.themeColor( 'shading.cursorBase' ) },
		cursorColor: { value: cfg.themeColor( 'shading.cursor' ) },
	};

	this.terrainOpacity = 0.5;

	const distanceTransparency = this.commonUniforms.distanceTransparency;

	Object.defineProperties( this, {

		'cursorHeight': {
			get: function () { return cursorHeight; },
			set: updateCursors
		},

		'linewidth': {
			get: function () { return linewidth; },
			set: updateLinewidth
		},

		'scaleLinewidth': {
			get: function () { return scaleLinewidth; },
			set: updateScaleLinewidth
		},

		'distanceTransparency': {
			get: function () { return distanceTransparency.value; },
			set: function ( x ) { distanceTransparency.value = x; }
		}
	} );

	function cacheMaterial ( name, material, stencil ) {

		cache.set( name, material );

		if ( stencil ) {

			material.stencilWrite = true;
			material.stencilZPass = IncrementStencilOp;

		}

		return material;

	}

	function getCacheMaterial ( name, materialFunc, stencil ) {

		let material = cache.get( name );

		if ( material === undefined ) {

			material = cacheMaterial( name, materialFunc(), stencil );

		}

		return material;

	}

	function getSurveyCacheMaterial ( name, materialFunc, stencil ) {

		const material = getCacheMaterial( name, materialFunc, stencil );
		perSurveyMaterials[ name ] = material;

		return material;

	}

	function updateCursors( newHeight ) {

		cursorMaterials.forEach( material => cursorHeight = material.setCursor( newHeight ) );

	}

	function updateLinewidth( width ) {

		lineMaterials.forEach( material => material.linewidth = width );
		linewidth = width;

	}

	function updateScaleLinewidth( mode ) {

		surveyLineMaterials.forEach( material => material.scaleLinewidth = mode );
		scaleLinewidth = mode;

	}

	function updateDatumShifts( event ) {

		self.commonDepthUniforms.datumShift.value = event.value;

	}

	this.getLine2Material = function ( params = { color: 'green' } ) {

		const func = () => new Line2Material( ctx, params );
		const material = getCacheMaterial( 'line2' + JSON.stringify( params ), func, true );

		return material;

	};

	this.getSurveyLineMaterial = function ( mode = '', dashed = false ) {

		const func = () => new SurveyLineMaterial( ctx, mode, dashed );
		const material = getSurveyCacheMaterial( 'survey-line-' + mode + ( dashed ? '-dashed' : '' ), func, true );

		if ( mode === 'cursor' || mode === 'depth-cursor' ) {

			// set active cursor material for updating
			cursorMaterials.add( material );

		}

		lineMaterials.add( material );
		surveyLineMaterials.add( material );
		material.linewidth = linewidth;

		return material;

	};

	this.getHeightMaterial = function () {

		const func = () => new HeightMaterial( ctx );
		return getSurveyCacheMaterial( 'height', func, true );

	};

	this.getZMaterial = function () {

		const func = () => new ZMaterial( ctx );
		return getSurveyCacheMaterial( 'z', func, true );

	};

	this.getHypsometricMaterial = function () {

		const func = () => new HypsometricMaterial( ctx );
		return getSurveyCacheMaterial( 'hypsometric', func );

	};

	this.getDepthMaterial = function () {

		const func = () => new DepthMaterial( ctx );
		return getSurveyCacheMaterial( 'depth', func, true );

	};

	this.getCursorMaterial = function () {

		const func = () => new CursorMaterial( ctx );
		const material = getSurveyCacheMaterial( 'cursor', func, true );

		// set active cursor material for updating
		cursorMaterials.add( material );

		return material;

	};

	this.getDepthCursorMaterial = function () {

		const func = () => new DepthCursorMaterial( ctx );
		const material = getSurveyCacheMaterial( 'depthCursor', func, true );

		// set active cursor material for updating
		cursorMaterials.add( material );

		return material;

	};

	this.getBezelMaterial = function  () {

		let func;

		if ( cfg.themeValue( 'hud.bezelType' ) === 'flat' ) {

			func = () => new MeshBasicMaterial( { color: cfg.themeValue( 'hud.bezel' ) } );

		} else {

			func = () => new MeshPhongMaterial( { color: cfg.themeValue( 'hud.bezel' ), specular: 0x888888 } );

		}

		return getCacheMaterial( 'bezel', func, true );

	};

	this.getPlainMaterial = function  () {

		const func = () => new MeshBasicMaterial( { color: 0xffffff, vertexColors: true } );
		return getCacheMaterial( 'plain', func, true );

	};

	this.getSurfaceMaterial = function  () {

		const func = () => new MeshLambertMaterial( { color: surfaceColour, vertexColors: false } );
		return getCacheMaterial( 'surface', func, true );

	};

	this.getEntrancePointMaterial = function  () {

		const func = () => new EntrancePointMaterial( ctx );
		return getCacheMaterial( 'entrance', func, true );

	};

	this.getExtendedPointsMaterial = function () {

		const func = () => new ExtendedPointsMaterial( ctx );
		return getCacheMaterial( 'extendedPoints', func, true );

	};

	this.getMissingMaterial = function () {

		const func = () => new MissingMaterial( ctx );
		return getCacheMaterial( 'missing', func );

	};

	this.getUnselectedMaterial = function () {

		const func = () => new LineBasicMaterial( { color: 0x444444, vertexColors: true } );
		return getCacheMaterial( 'unselected', func );

	};

	this.getUnselectedWallMaterial = function () {

		const func = () => new MeshLambertMaterial( { color: 0x444444, vertexColors: true} );
		return getCacheMaterial( 'unselectedWall', func );

	};

	this.getScaleMaterial = function () {

		const func = () => new MeshBasicMaterial( { color: 0xffffff, map: textureCache.getTexture( gradient ) } );
		return getCacheMaterial( 'scale', func );

	};

	this.getContourMaterial = function () {

		const func = () => new ContourMaterial( ctx );
		return getSurveyCacheMaterial( 'contour', func );

	};

	this.getGlyphMaterial = function ( glyphAtlasSpec, rotation ) {

		const atlas = glyphAtlasCache.getAtlas( glyphAtlasSpec );
		const name = JSON.stringify( glyphAtlasSpec ) + ':' + rotation.toString();

		const func = () => new GlyphMaterial( ctx, atlas, rotation, viewer );

		return getCacheMaterial( name, func );

	};

	this.getClusterMaterial = function ( count ) {

		const func = () => new ClusterMaterial( count );
		return getCacheMaterial( 'cluster' + count, func, true );

	};

	this.setTerrain = function ( terrain ) {

		terrain.addEventListener( 'datumShiftChange', updateDatumShifts );

	};

	this.flushCache = function () {

		cursorMaterials.clear();
		lineMaterials.clear();
		surveyLineMaterials.clear();

		for ( const name in perSurveyMaterials ) {

			const material = perSurveyMaterials[ name ];

			material.dispose();
			cache.delete( name );

		}

		perSurveyMaterials = {};
		ctx.glyphStringCache = new Map();
		cursorHeight = 0;

	};

	this.setFog = function ( enable ) {

		for ( const name in perSurveyMaterials ) {

			const material = perSurveyMaterials[ name ];

			material.fog = enable;
			material.needsUpdate = true;

		}

	};

}

export { Materials };<|endoftext|>


<commit_before>angular.module('n52.core.timeseries', [])
    .service('timeseriesService', ['$rootScope', 'interfaceService', 'statusService', 'styleService', 'settingsService', 'utils',
        function($rootScope, interfaceService, statusService, styleService, settingsService, utils) {
            var defaultDuration = settingsService.timeseriesDataBuffer || moment.duration(2, 'h');

            this.timeseries = {};
            var tsData = {};

            $rootScope.$on('timeExtentChanged', evt => {
                _loadAllData(this.timeseries);
            });

            _loadAllData = function(timeseries) {
                // TODO evtl. erst wenn alle Daten da sind soll die Daten auch gesetzt werden???
                angular.forEach(timeseries, ts => {
                    _loadTsData(ts);
                });
            };

            _addTs = function(ts, timeseries) {
                ts.timebuffer = defaultDuration;
                styleService.createStylesInTs(ts);
                timeseries[ts.internalId] = ts;
                statusService.addTimeseries(ts);
                _loadTsData(ts);
            };

            _loadTsData = function(ts) {
                var generalizeData = statusService.status.generalizeData || false;
                ts.loadingData = true;
                interfaceService.getTsData(ts.id, ts.apiUrl, utils.createBufferedCurrentTimespan(statusService.getTime(), ts.timebuffer, generalizeData))
                    .then(data => {
                        _addTsData(data, ts);
                    });
            };

            _createNewTimebuffer = function(data) {
                if (data.length >= 2) {
                    var newDuration = moment.duration(data[1][0] - data[0][0]);
                    if (newDuration > defaultDuration) {
                        return newDuration;
                    } else {
                        return defaultDuration;
                    }
                }
                return defaultDuration;
            };

            _addTsData = function(data, ts) {
                ts.timebuffer = _createNewTimebuffer(data[ts.id].values);
                tsData[ts.internalId] = data[ts.id];
                if (tsData[ts.internalId].values && tsData[ts.internalId].values.length) {
                    ts.hasNoDataInCurrentExtent = false;
                } else {
                    ts.hasNoDataInCurrentExtent = true;
                }
                $rootScope.$emit('timeseriesDataChanged', ts.internalId);
                ts.loadingData = false;
            };

            this.getData = function(internalId) {
                return tsData[internalId];
            };

            this.getTimeseries = function(internalId) {
                return this.timeseries[internalId];
            };

            this.getAllTimeseries = function() {
                return this.timeseries;
            };

            this.hasTimeseries = function(internalId) {
                return angular.isObject(this.timeseries[internalId]);
            };

            this.getTimeseriesCount = function() {
                return Object.keys(this.timeseries).length;
            };

            this.addTimeseriesById = function(id, apiUrl, params) {
                interfaceService.getTimeseries(id, apiUrl, params).then((data) => {
                    if (angular.isArray(data)) {
                        angular.forEach(data, ts => {
                            _addTs(ts, this.timeseries);
                        });
                    } else {
                        _addTs(data, this.timeseries);
                    }
                });
            };

            this.addTimeseries = function(ts) {
                _addTs(angular.copy(ts), this.timeseries);
            };

            this.removeTimeseries = function(internalId) {
                styleService.deleteStyle(this.timeseries[internalId]);
                delete this.timeseries[internalId];
                delete tsData[internalId];
                statusService.removeTimeseries(internalId);
                $rootScope.$emit('timeseriesDataChanged', internalId);
            };

            this.removeAllTimeseries = function() {
                angular.forEach(this.timeseries, elem => {
                    this.removeTimeseries(elem.internalId);
                });
            };

            this.toggleReferenceValue = function(refValue, internalId) {
                refValue.visible = !refValue.visible;
                $rootScope.$emit('timeseriesDataChanged', internalId);
            };

            this.isTimeseriesVisible = function(internalId) {
                return this.hasTimeseries(internalId) && this.timeseries[internalId].styles.visible;
            };
        }
    ]);
<commit_msg>fix generalized data fetching<commit_after>angular.module('n52.core.timeseries', [])
    .service('timeseriesService', ['$rootScope', 'interfaceService', 'statusService', 'styleService', 'settingsService', 'utils',
        function($rootScope, interfaceService, statusService, styleService, settingsService, utils) {
            var defaultDuration = settingsService.timeseriesDataBuffer || moment.duration(2, 'h');

            this.timeseries = {};
            var tsData = {};

            $rootScope.$on('timeExtentChanged', evt => {
                _loadAllData(this.timeseries);
            });

            _loadAllData = function(timeseries) {
                // TODO evtl. erst wenn alle Daten da sind soll die Daten auch gesetzt werden???
                angular.forEach(timeseries, ts => {
                    _loadTsData(ts);
                });
            };

            _addTs = function(ts, timeseries) {
                ts.timebuffer = defaultDuration;
                styleService.createStylesInTs(ts);
                timeseries[ts.internalId] = ts;
                statusService.addTimeseries(ts);
                _loadTsData(ts);
            };

            _loadTsData = function(ts) {
                var generalizeData = statusService.status.generalizeData || false;
                ts.loadingData = true;
                interfaceService.getTsData(ts.id, ts.apiUrl, utils.createBufferedCurrentTimespan(statusService.getTime(), ts.timebuffer), null, generalizeData)
                    .then(data => {
                        _addTsData(data, ts);
                    });
            };

            _createNewTimebuffer = function(data) {
                if (data.length >= 2) {
                    var newDuration = moment.duration(data[1][0] - data[0][0]);
                    if (newDuration > defaultDuration) {
                        return newDuration;
                    } else {
                        return defaultDuration;
                    }
                }
                return defaultDuration;
            };

            _addTsData = function(data, ts) {
                ts.timebuffer = _createNewTimebuffer(data[ts.id].values);
                tsData[ts.internalId] = data[ts.id];
                if (tsData[ts.internalId].values && tsData[ts.internalId].values.length) {
                    ts.hasNoDataInCurrentExtent = false;
                } else {
                    ts.hasNoDataInCurrentExtent = true;
                }
                $rootScope.$emit('timeseriesDataChanged', ts.internalId);
                ts.loadingData = false;
            };

            this.getData = function(internalId) {
                return tsData[internalId];
            };

            this.getTimeseries = function(internalId) {
                return this.timeseries[internalId];
            };

            this.getAllTimeseries = function() {
                return this.timeseries;
            };

            this.hasTimeseries = function(internalId) {
                return angular.isObject(this.timeseries[internalId]);
            };

            this.getTimeseriesCount = function() {
                return Object.keys(this.timeseries).length;
            };

            this.addTimeseriesById = function(id, apiUrl, params) {
                interfaceService.getTimeseries(id, apiUrl, params).then((data) => {
                    if (angular.isArray(data)) {
                        angular.forEach(data, ts => {
                            _addTs(ts, this.timeseries);
                        });
                    } else {
                        _addTs(data, this.timeseries);
                    }
                });
            };

            this.addTimeseries = function(ts) {
                _addTs(angular.copy(ts), this.timeseries);
            };

            this.removeTimeseries = function(internalId) {
                styleService.deleteStyle(this.timeseries[internalId]);
                delete this.timeseries[internalId];
                delete tsData[internalId];
                statusService.removeTimeseries(internalId);
                $rootScope.$emit('timeseriesDataChanged', internalId);
            };

            this.removeAllTimeseries = function() {
                angular.forEach(this.timeseries, elem => {
                    this.removeTimeseries(elem.internalId);
                });
            };

            this.toggleReferenceValue = function(refValue, internalId) {
                refValue.visible = !refValue.visible;
                $rootScope.$emit('timeseriesDataChanged', internalId);
            };

            this.isTimeseriesVisible = function(internalId) {
                return this.hasTimeseries(internalId) && this.timeseries[internalId].styles.visible;
            };
        }
    ]);
<|endoftext|>


<commit_before>export const route = {

  initialise: () => {
    const hash = location.hash
    const query = hashToQuery(hash)
    return {
      type: 'route-initialise',
      payload: { hash, query }
    }
  },

  query: ({ name, value, active }) => {

    const query = hashToQuery(location.hash)
    const isActiveParameter = name in query

    if (!active) {
      if (isActiveParameter) query[name].push(value)
      else query[name] = [ value ]
    }
    else query[name] = (query[name] || []).filter(x => {
      console.log(x)
      return x !== value
    })

    const hash = queryToHash(query)
    updateLocation(hash)

    return {
      type: 'route-query',
      payload: { hash, ...query }
    }

  },

  search: value => {

    const query = hashToQuery(location.hash)
    query.search = [ value ]
    const hash = queryToHash(query)

    updateLocation(hash)

    return {
      type: 'route-search',
      payload: { hash, ...query }
    }

  },

}

// Methods
function updateLocation(hash) {
  location.hash = hash
}

function hashToQuery(hash) {

  if (hasProperties(hash)) return decodeURIComponent(hash).split('&').reduce(parameterToProperty, {})
  else return {}

  function hasProperties(hash) {
    return /\W+/g.test(hash)
  }

  function parameterToProperty(query, parameter) {
    const properties = getProperties(...parameter.split('='))
    return {
      ...query,
      ...properties
    }
  }

  function getProperties(key, value = '') {
    // created an Object with a sanitised key, and ‘|’-separated values
    return { [key.replace(/\W+/g, '')]: value.split('|') }
  }

}

function queryToHash(query) {

  return Object.keys(query).reduce((hash, key) => {

    const values = query[key].reduce((result, value) => {
      if (!!value) result.push(encodeURIComponent(value))
      return result
    }, [])

    if (values.length){
      const value = query[key].join('|')
      const parameter = [ key, value ].join('=')
      return [ ...hash, parameter ]
    }
    else return [ ...hash ]

  }, []).join('&')

}<commit_msg>Squashed some bugs<commit_after>export const route = {

  initialise: () => {
    const hash = location.hash
    const query = hashToQuery(hash)
    return {
      type: 'route-initialise',
      payload: { hash, query }
    }
  },

  query: ({ name, value, active }) => {

    const query = hashToQuery(location.hash)
    const parameter = query[name] || []
    const isActiveParameter = !!parameter.length

    const otherThanValue = item => item !== value

    if (active) query[name] = parameter.filter(otherThanValue)
    else {
      if (isActiveParameter && parameter.every(otherThanValue)) query[name].push(value)
      else query[name] = [ value ]
    }

    const hash = queryToHash(query)
    updateLocation(hash)

    return {
      type: 'route-query',
      payload: { hash, query }
    }

  },

  search: value => {

    const query = hashToQuery(location.hash)
    query.search = [ value ]
    const hash = queryToHash(query)

    updateLocation(hash)

    return {
      type: 'route-search',
      payload: { hash, query }
    }

  },

}

// Methods
function updateLocation(hash) {
  location.hash = hash
}

function hashToQuery(hash) {

  if (hasProperties(hash)) return decodeURIComponent(hash).split('&').reduce(parameterToProperty, {})
  else return {}

  function hasProperties(hash) {
    return /\W+/g.test(hash)
  }

  function parameterToProperty(query, parameter) {
    const properties = getProperties(...parameter.split('='))
    return {
      ...query,
      ...properties
    }
  }

  function getProperties(key, value = '') {
    // created an Object with a sanitised key, and ‘|’-separated values
    return { [key.replace(/\W+/g, '')]: value.split('|') }
  }

}

function queryToHash(query) {

  return Object.keys(query).reduce((hash, key) => {

    const values = query[key].reduce((result, value) => {
      if (!!value) result.push(encodeURIComponent(value))
      return result
    }, [])

    if (values.length){
      const value = query[key].join('|')
      const parameter = [ key, value ].join('=')
      return [ ...hash, parameter ]
    }
    else return [ ...hash ]

  }, []).join('&')

}<|endoftext|>


<commit_before>"use strict";

function CameraEditor(parent, closeable, container, index)
{
	TabElement.call(this, parent, closeable, container, index, "camera", Editor.filePath + "icons/camera/camera.png");

	this.camera = null;

	//Main container
	this.main = new DualDivisionResizable(this.element);
	this.main.tabPosition = 0.6;
	this.main.tabPositionMin = 0.05;
	this.main.tabPositionMax = 0.95;

	//Canvas
	this.canvas = new Canvas(this.main.divA);

	//Renderer
	this.renderer = new THREE.WebGLRenderer({canvas: this.canvas.element, antialias: Settings.render.antialiasing});

	//Change main div aspect
	this.main.divB.style.overflow = "auto";
	this.main.divB.style.cursor = "default";
	this.main.divB.style.backgroundColor = Editor.theme.panelColor;

	//Self pointer
	var self = this;

	//Form
	this.form = new Form(this.main.divB);
	this.form.defaultTextWidth = 80;
	this.form.position.set(10, 5);
	this.form.spacing.set(5, 5);

	//Camera
	this.form.addText("Camera");
	this.form.nextRow();

	//Name
	this.form.addText("Name");
	this.name = new TextBox(this.form.element);
	this.name.size.set(200, 18);
	this.name.setOnChange(function()
	{
		if(self.camera !== null)
		{
			Editor.history.add(new ChangeAction(self.camera, "name", self.name.getText()));
			Editor.updateObjectViews();
		}
	});
	this.form.add(this.name);
	this.form.nextRow();

	this.form.addText("Add Post Processing");
	this.form.nextRow();

	var addRenderPass = function(pass)
	{
		var composer = self.camera.composer;
		pass.renderToScreen = true;
		for(var i = 0; i < composer.passes.length; i++)
		{
			composer.passes[i].renderToScreen = false;
		}

		self.camera.composer.addPass(pass);
		self.updatePostNodes();
	};

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Render");
	button.setCallback(function()
	{
		addRenderPass(new RenderPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("FXAA");
	button.setCallback(function()
	{
		addRenderPass(new FXAAPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Colorify");
	button.setCallback(function()
	{
		addRenderPass(new ColorifyPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Unreal Bloom");
	button.setCallback(function()
	{
		addRenderPass(new UnrealBloomPass(0.8, 0.3, 0.8));
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Hue & Saturation");
	button.setCallback(function()
	{
		addRenderPass(new HueSaturationPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("SSAO");
	button.setCallback(function()
	{
		var pass = new SSAOPass();
		pass.onlyAO = false;
		addRenderPass(pass);
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Bokeh");
	button.setCallback(function()
	{
		addRenderPass(new BokehPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Technicolor");
	button.setCallback(function()
	{
		addRenderPass(new TechnicolorPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Film");
	button.setCallback(function()
	{
		addRenderPass(new FilmPass(0.35, 0.5, 512, false));
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Dot Screen");
	button.setCallback(function()
	{
		addRenderPass(new DotScreenPass(new THREE.Vector2(0, 0), 0.5, 0.8));
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Sobel");
	button.setCallback(function()
	{
		addRenderPass(new SobelPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Copy");
	button.setCallback(function()
	{
		addRenderPass(new CopyPass());
	});
	this.form.add(button);
	this.form.nextRow();

	this.postNodes = new Form(this.form.element);
	this.form.add(this.postNodes);
	this.form.nextRow();
}

CameraEditor.prototype = Object.create(TabElement.prototype);

//Activate
CameraEditor.prototype.activate = function()
{
	TabElement.prototype.activate.call(this);

	this.name.setText(this.camera.name);

	this.updatePostNodes();
};

//Update post processing nodes
CameraEditor.prototype.updatePostNodes = function()
{
	this.postNodes.removeAll();

	var passes = this.camera.composer.passes;
	for(var i = 0; i < passes.length; i++)
	{
		var node = PassNode.createPass(this.postNodes.element, passes[i].type);
		node.setPass(passes[i]);
		node.setComposer(this.camera.composer);
		node.setEditor(this);

		this.postNodes.add(node);
		this.postNodes.nextRow();
	}

	this.postNodes.updateInterface();
};

//Destroy
CameraEditor.prototype.destroy = function()
{
	TabElement.prototype.destroy.call(this);

	if(this.renderer !== null)
	{
		this.renderer.dispose();
		this.renderer.forceContextLoss();
		this.renderer = null;
	}
};

//Update tab state
CameraEditor.prototype.update = function()
{
	if(this.camera !== null)
	{
		this.camera.aspect = this.canvas.size.x / this.canvas.size.y;
		this.camera.updateProjectionMatrix();
		this.camera.resize(this.canvas.size.x, this.canvas.size.y);
		this.camera.render(this.renderer, ObjectUtils.getScene(this.camera));
	}
};

//Update tab metadata
CameraEditor.prototype.updateMetadata = function()
{
	if(this.camera !== null)
	{
		this.setName(this.camera.name);
		this.name.setText(this.camera.name);

		//Check if object has a parent
		if(this.camera.parent === null)
		{
			this.close();
			return;
		}

		//Check if object exists in parent
		var children = this.camera.parent.children;
		for(var i = 0; i < children.length; i++)
		{
			if(this.camera.uuid === children[i].uuid)
			{
				return;
			}
		}

		//If not found close tab
		if(i >= children.length)
		{
			this.close();
		}
	}
};

CameraEditor.prototype.attach = function(camera)
{
	this.camera = camera;

	this.updateMetadata();
};

CameraEditor.prototype.isAttached = function(camera)
{
	return this.camera === camera;
};

CameraEditor.prototype.updateInterface = function()
{
	//Visibility
	if(this.visible)
	{
		//Form
		this.form.updateInterface();

		//Main
		this.main.size.copy(this.size);
		this.main.updateInterface();

		//Canvas
		this.canvas.size.set(this.main.divA.offsetWidth, this.main.divA.offsetHeight);
		this.canvas.updateInterface();

		//Renderer
		this.renderer.setSize(this.canvas.size.x, this.canvas.size.y);

		//Element
		this.element.style.display = "block";
		this.element.style.top = this.position.y + "px";
		this.element.style.left = this.position.x + "px";
		this.element.style.width = this.size.x + "px";
		this.element.style.height = this.size.y + "px";
	}
	else
	{
		this.element.style.display = "none";
	}
};
<commit_msg>Fixed camera tab canvas size<commit_after>"use strict";

function CameraEditor(parent, closeable, container, index)
{
	TabElement.call(this, parent, closeable, container, index, "camera", Editor.filePath + "icons/camera/camera.png");

	this.camera = null;

	//Main container
	this.main = new DualDivisionResizable(this.element);
	this.main.tabPosition = 0.6;
	this.main.tabPositionMin = 0.05;
	this.main.tabPositionMax = 0.95;

	//Canvas
	this.canvas = new Canvas(this.main.divA);

	//Renderer
	this.renderer = new THREE.WebGLRenderer({canvas: this.canvas.element, antialias: Settings.render.antialiasing});

	//Change main div aspect
	this.main.divB.style.overflow = "auto";
	this.main.divB.style.cursor = "default";
	this.main.divB.style.backgroundColor = Editor.theme.panelColor;

	//Self pointer
	var self = this;

	//Form
	this.form = new Form(this.main.divB);
	this.form.defaultTextWidth = 80;
	this.form.position.set(10, 5);
	this.form.spacing.set(5, 5);

	//Camera
	this.form.addText("Camera");
	this.form.nextRow();

	//Name
	this.form.addText("Name");
	this.name = new TextBox(this.form.element);
	this.name.size.set(200, 18);
	this.name.setOnChange(function()
	{
		if(self.camera !== null)
		{
			Editor.history.add(new ChangeAction(self.camera, "name", self.name.getText()));
			Editor.updateObjectViews();
		}
	});
	this.form.add(this.name);
	this.form.nextRow();

	this.form.addText("Add Post Processing");
	this.form.nextRow();

	var addRenderPass = function(pass)
	{
		var composer = self.camera.composer;
		pass.renderToScreen = true;
		for(var i = 0; i < composer.passes.length; i++)
		{
			composer.passes[i].renderToScreen = false;
		}

		self.camera.composer.addPass(pass);
		self.updatePostNodes();
	};

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Render");
	button.setCallback(function()
	{
		addRenderPass(new RenderPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("FXAA");
	button.setCallback(function()
	{
		addRenderPass(new FXAAPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Colorify");
	button.setCallback(function()
	{
		addRenderPass(new ColorifyPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Unreal Bloom");
	button.setCallback(function()
	{
		addRenderPass(new UnrealBloomPass(0.8, 0.3, 0.8));
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Hue & Saturation");
	button.setCallback(function()
	{
		addRenderPass(new HueSaturationPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("SSAO");
	button.setCallback(function()
	{
		var pass = new SSAOPass();
		pass.onlyAO = false;
		addRenderPass(pass);
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Bokeh");
	button.setCallback(function()
	{
		addRenderPass(new BokehPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Technicolor");
	button.setCallback(function()
	{
		addRenderPass(new TechnicolorPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Film");
	button.setCallback(function()
	{
		addRenderPass(new FilmPass(0.35, 0.5, 512, false));
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Dot Screen");
	button.setCallback(function()
	{
		addRenderPass(new DotScreenPass(new THREE.Vector2(0, 0), 0.5, 0.8));
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Sobel");
	button.setCallback(function()
	{
		addRenderPass(new SobelPass());
	});
	this.form.add(button);
	this.form.nextRow();

	var button = new Button(this.form.element);
	button.size.set(120, 18);
	button.setText("Copy");
	button.setCallback(function()
	{
		addRenderPass(new CopyPass());
	});
	this.form.add(button);
	this.form.nextRow();

	this.postNodes = new Form(this.form.element);
	this.form.add(this.postNodes);
	this.form.nextRow();
}

CameraEditor.prototype = Object.create(TabElement.prototype);

//Activate
CameraEditor.prototype.activate = function()
{
	TabElement.prototype.activate.call(this);

	this.name.setText(this.camera.name);
	this.updatePostNodes();
};

//Update post processing nodes
CameraEditor.prototype.updatePostNodes = function()
{
	this.postNodes.removeAll();

	var passes = this.camera.composer.passes;
	for(var i = 0; i < passes.length; i++)
	{
		var node = PassNode.createPass(this.postNodes.element, passes[i].type);
		node.setPass(passes[i]);
		node.setComposer(this.camera.composer);
		node.setEditor(this);

		this.postNodes.add(node);
		this.postNodes.nextRow();
	}

	this.postNodes.updateInterface();
};

//Destroy
CameraEditor.prototype.destroy = function()
{
	TabElement.prototype.destroy.call(this);

	if(this.renderer !== null)
	{
		this.renderer.dispose();
		this.renderer.forceContextLoss();
		this.renderer = null;
	}
};

//Update tab state
CameraEditor.prototype.update = function()
{
	if(this.camera !== null)
	{
		console.log(this.camera.aspect, this.canvas.size.x, this.canvas.size.y);

		this.camera.aspect = this.canvas.size.x / this.canvas.size.y;
		this.camera.updateProjectionMatrix();
		this.camera.resize(this.canvas.size.x, this.canvas.size.y);
		this.camera.render(this.renderer, ObjectUtils.getScene(this.camera));
	}
};

//Update tab metadata
CameraEditor.prototype.updateMetadata = function()
{
	if(this.camera !== null)
	{
		this.setName(this.camera.name);
		this.name.setText(this.camera.name);

		//Check if object has a parent
		if(this.camera.parent === null)
		{
			this.close();
			return;
		}

		//Check if object exists in parent
		var children = this.camera.parent.children;
		for(var i = 0; i < children.length; i++)
		{
			if(this.camera.uuid === children[i].uuid)
			{
				return;
			}
		}

		//If not found close tab
		if(i >= children.length)
		{
			this.close();
		}
	}
};

CameraEditor.prototype.attach = function(camera)
{
	this.camera = camera;

	this.updateMetadata();
};

CameraEditor.prototype.isAttached = function(camera)
{
	return this.camera === camera;
};

CameraEditor.prototype.updateInterface = function()
{
	//Visibility
	if(this.visible)
	{
		//Form
		this.form.updateInterface();

		//Main
		this.main.size.copy(this.size);
		this.main.updateInterface();

		//Canvas
		this.canvas.size.set(this.size.x * this.main.tabPosition, this.size.y);
		this.canvas.updateInterface();

		//Renderer
		this.renderer.setSize(this.canvas.size.x, this.canvas.size.y);

		//Element
		this.element.style.display = "block";
		this.element.style.top = this.position.y + "px";
		this.element.style.left = this.position.x + "px";
		this.element.style.width = this.size.x + "px";
		this.element.style.height = this.size.y + "px";
	}
	else
	{
		this.element.style.display = "none";
	}
};
<|endoftext|>