<commit_before>var App = angular.module('App', ['pascalprecht.translate','ngRoute','ApiModel','ngSanitize','ngLoadScript','ngMeta']);

App.config(function($routeProvider,ngMetaProvider) {
    $routeProvider

      // route for the home page
      .when('/', {
        templateUrl : 'lib/pages/home.html',
        controller  : 'appCtrl'
      })
      // route for the about page
      .when('/terms', {
        templateUrl : 'lib/pages/terms.html',
        controller  : 'appCtrl'
      })
      .when('/privacy', {
        templateUrl : 'lib/pages/privacy.html',
        controller  : 'appCtrl'
      })
      .when('/guides', {
        templateUrl : 'lib/pages/guides.html',
        controller  : 'appCtrl'
      })
      // route for the contact page
      .when('/view/:orderId', {
        templateUrl : 'lib/pages/test.html',
        controller  : 'pageCtrl'
      })
      .when('/view/:orderId/:slug', {
        templateUrl : 'lib/pages/test.html',
        controller  : 'pageCtrl',
      })
      .when('/event/:eventId', {
        templateUrl : 'lib/pages/event.html',
        controller  : 'pageCtrl'
      })
      .when('/event/:eventId/:slug', {
        templateUrl : 'lib/pages/event.html',
        controller  : 'pageCtrl'
      })
      .otherwise({
                redirectTo: '/'
            });
  });
App.run(['ngMeta', function(ngMeta) {
  ngMeta.init();
}]);
App.filter('ucfirst', function() {
    return function(input, all) {
      var reg = (all) ? /([^\W_]+[^\s-]*) */g : /([^\W_]+[^\s-]*)/;
      return (!!input) ? input.replace(reg, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) : '';
    }
  });
App.filter("un_slug", [ function(){
 return function(str){
    try {
      return (str || '').replace(/-/g, ' ');
    } catch(e) {
      console.error("error in un_slug", e);
      return (str || '');
    }
  }
 }
]);
App.filter("remove_under", [ function(){
 return function(str){
    try {
      return (str || '').replace(/_/g, ' ');
    } catch(e) {
      console.error("error in remove_under", e);
      return (str || '');
    }
  }
 }
]);
App.filter('removeAt', function() {
    return function (value) {
        var s = value;
 var n = s.indexOf('@');
  s = s.substring(0, n != -1 ? n : s.length);
  return s;
    };

  });
App.controller('pageCtrl', function ($scope,$timeout,  $window,$translate,$route,$routeParams,ngMeta,$filter, $location,AppRestangular,anchorSmoothScroll,urlService) {

$scope.$route = $route;

$scope.$location = $location;
     $scope.$routeParams = $routeParams;
     $scope.name = 'pageController';
  if($routeParams.eventId){
    $scope.order_id = $routeParams.eventId
    $scope.pageType = "event";
  }else{
    var the_id = $routeParams.orderId;
    var claveType = the_id.charAt(0).toUpperCase();
    if(claveType == "X"){
      $scope.order_id = the_id.substr(1);
      $scope.pageType = "place";
    }else{
      $scope.order_id = the_id;
      $scope.pageType = "eat";
      console.log("is an eat");
    }

  }
  $scope.message = 'Look! I am an about page.';
  $scope.openInApp = () =>{

    var hash = window.location.hash.split("/");
    console.log(hash);
    if(hash[1] == 'view'){
      var the_id = hash[2].split("?");
      var claveType = the_id[0].charAt(0);
      console.log('clavetype: '+claveType);
      if(claveType == "x"){
        var elID = the_id[0];
      }else{
          var elID = "f"+the_id[0];
      }
      console.log("citywiz://id?cityclave="+elID);

      //deeplink.open("citywiz://id?cityclave="+elID);
      window.open("citywiz://id?cityclave="+elID);
    }
  }
  $scope.openInApptest = () =>{

    var hash = window.location.hash.split("/");
    console.log(hash);
    if(hash[1] == 'view'){
      var the_id = hash[2].split("?");
      var claveType = the_id[0].charAt(0);
      console.log('clavetype: '+claveType);
      if(claveType == "x"){
        var elID = the_id[0];
      }else{
          var elID = "f"+the_id[0];
      }
      console.log("citywiz://id?cityclave="+elID);

      //deeplink.open("citywiz://id?cityclave="+elID);
      window.location.replace("citywiz://id?cityclave="+elID);
    }
  }
//load data
$scope.gotoElement = function (eID){
      // set the location.hash to the id of
      // the element you wish to scroll to.
      urlService.setUrl(eID);
      //$location.hash(eID);
      $location.url("/"+eID);

    };
/************* load dynamic data based on guide ************/
  $scope.loadDetails = function() {
$scope.loaded = false;
    itemdata.get().then(function(data) {

    $scope.card = data;
    if($scope.pageType == 'place'){
      console.log("is place: "+JSON.stringify(data));
    }
    var unslug_cat = $filter('un_slug')(data.cat);
    unslug_cat = $filter('ucfirst')(unslug_cat);
    if(data.cat == 'nightlife'){
    var text = unslug_cat+" en "+data.city;
  }else{
    var text = unslug_cat+" food en "+data.city;
  }
  if($scope.pageType == 'place'){
    var text = unslug_cat;
  };
    ngMeta.setTitle(data.name);
    ngMeta.setTag('description', text);
    ngMeta.setTag('vport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
    ngMeta.setTag('image', data.social_imgs[0].img_path);
       //$scope.viewResult();
       // after data has finished loading
       //$scope.viewResult(data.latitude,data.longitude);

        setTimeout(function() {

       $scope.loaded = true;
       $scope.lang = function(){ return $translate.use();}
       $scope.$apply();

    }, 1000);

});

  };
if($scope.pageType == 'eat'){
  var itemdata = AppRestangular.one("id", $scope.order_id);
}else if($scope.pageType = 'place'){
  var itemdata = AppRestangular.one("placeid", $scope.order_id);
}else if($scope.pageType == 'event'){
  var itemdata = AppRestangular.one("eventid", $scope.order_id);
}

  $scope.loadDetails();
//load data ends
});
App.controller('appCtrl', function ($scope,$timeout,  $window,$translate,$route, $location,ngMeta,$routeParams,anchorSmoothScroll,urlService) {
 $scope.$route = $route;
$scope.$location = $location;
     $scope.$routeParams = $routeParams;
     $scope.name = 'appCtrl';
  $scope.helloworld = "hey! hello world!";
  $scope.data = {
  cb2: 'es'
};
  ngMeta.setTag('image', 'http://citywiz.imgix.net/citywiz_cover.png');
   $scope.changeLanguage = function (key) {
    $translate.use(key);
  };
 $scope.gotoElement = function (eID){
      // set the location.hash to the id of
      // the element you wish to scroll to.
      //$location.hash(eID);

      // call $anchorScroll()
      anchorSmoothScroll.scrollTo(eID);

    };

setTimeout(function() {

       $scope.loaded = true;
       var hash = urlService.getUrl();
       $scope.lang = function(){ return $translate.use();}
       if(hash){
            anchorSmoothScroll.scrollTo(hash);
       }
       $scope.$apply();

    }, 500);
});
App.config(['$translateProvider', function ($translateProvider) {
        $translateProvider.translations('en', {
            LANGBOARD: "Local Discovery Guides",
            APPBOARD: "Your App for Puerto Rico tourism!",
            DOWNAPP: "Get the free app!",
            VIEWBLOG: "View guides & articles",
            APPHERO2: "Citywiz helps you discover #EcoAdventure #Food #Culture #Attractions #Events. Discover and connect to everything local.",
            ABOUTUSTITLE:"We believe life is easier when you know what's around you.",
            APPABOUTUS: "
Citywiz is a free and easy-to-use iPhone\® and Android\® App that will guide you to discover and connect to everything local \(currently in Puerto Rico\).

If you’re looking for a place to eat, go for a night out, get the intel of nearby events or searching for an adventure on our beautiful island, our app will help you stay connected to everything your city has to offer.

New city-wizards \(guides\) will be added regularly for you to discover cool and essential things like food, outdoor adventures, music, art, culture and more.
",
            TEAMTITLE: "How wonderful to meet you!",
            TEAM: "
We are a small but passionate Puerto Rican team focused on delivering new and fun technology products that will help you search and discover.
",
            DOWNLOADTITLE: "Start discovering your city now!",
            DOWNLOAD: "Our FREE app is available now for iPhone and Android. Download now and get started!",
            ARTICLESHERO: "Discover places to visit, places to eat or stay and meet other tourists through our articles.",
            INSTAGRAMCOPY: "Follow our Instagram where we feature Puerto Rico's top places and food tru the lens of awesome local photographers/tourists who love the island and you should follow. Tap on the images for info and credit."

        })
        .translations('es', {
            LANGBOARD: "Guías de descubrimiento local",
            APPBOARD: "Tu App pal' turisteo!",
            DOWNAPP: "¡Descarga el app gratis!",
            VIEWBLOG: "Ver guías y artículos",
            APPHERO2: "CityWiz te ayuda a descubrir #aventureo #foodeo #turisteo #cultura en Puerto Rico. Descubre y conéctate a todo lo local.",
            ABOUTUSTITLE:"La vida es más fácil cuando sabes lo que te rodea.",
            APPABOUTUS: "
Citywiz es una aplicación de iPhone\® y Android\® gratuita y fácil de usar que te ayudará a descubrir y conectarte con todo lo que te rodea \(actualmente en Puerto Rico\).

Si estás buscando un lugar para comer, salir de paseo, obtener información de eventos cercanos o buscando una aventura en nuestra hermosa isla, nuestra aplicación te ayudará a mantenerte conectado con todo lo que tu ciudad tiene para ofrecer.

Nuevos city-wizards \(guías\) serán añadidos regularmente para que continúes descubriendo cosas nuevas y esenciales como comida, aventura, música, arte, cultura y mucho más.
",
            TEAMTITLE: "¡Qué maravilloso conocerte!",
            TEAM: "
Somos un pequeño pero apasionado equipo puertorriqueño enfocado en brindar nuevos y divertidos productos tecnológicos que te ayudarán a buscar y descubrir.
",
            DOWNLOADTITLE: "¡Comienza a descubrir tu ciudad ya!",
            DOWNLOAD: "Nuestra aplicación GRATIS ya está disponible para iPhone\® y Android\®. ¡Descargue ahora y comienza a descubrir!",
            ARTICLESHERO: "Descubre lugares para visitar, sitios para comer o quedarse y conoce a otros turistas a través de nuestros artículos.",
            INSTAGRAMCOPY: "Sigue nuestro Instagram donde presentamos los mejores lugares y comida de Puerto Rico capturados por increíbles fotógrafos / turisteros locales que aman la isla y los cuales debe seguir. Toque las imágenes para obtener información y crédito."
        });
$translateProvider.useSanitizeValueStrategy(null);
$translateProvider.preferredLanguage('es');
}]);
App.service('anchorSmoothScroll', function(){

    this.scrollTo = function(eID) {

        // This scrolling function
        // is from http://www.itnewb.com/tutorial/Creating-the-Smooth-Scroll-Effect-with-JavaScript

        var startY = currentYPosition();
        var stopY = elmYPosition(eID);
        var distance = stopY > startY ? stopY - startY : startY - stopY;
        if (distance < 100) {
            scrollTo(0, stopY); return;
        }
        var speed = Math.round(distance / 100);
        if (speed >= 20) speed = 20;
        var step = Math.round(distance / 25);
        var leapY = stopY > startY ? startY + step : startY - step;
        var timer = 0;
        if (stopY > startY) {
            for ( var i=startY; i<stopY; i+=step ) {
                setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
                leapY += step; if (leapY > stopY) leapY = stopY; timer++;
            } return;
        }
        for ( var i=startY; i>stopY; i-=step ) {
            setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
            leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
        }

        function currentYPosition() {
            // Firefox, Chrome, Opera, Safari
            if (self.pageYOffset) return self.pageYOffset;
            // Internet Explorer 6 - standards mode
            if (document.documentElement && document.documentElement.scrollTop)
                return document.documentElement.scrollTop;
            // Internet Explorer 6, 7 and 8
            if (document.body.scrollTop) return document.body.scrollTop;
            return 0;
        }

        function elmYPosition(eID) {
            var elm = document.getElementById(eID);
            var y = elm.offsetTop;
            var node = elm;
            while (node.offsetParent && node.offsetParent != document.body) {
                node = node.offsetParent;
                y += node.offsetTop;
            } return y;
        }

    };

});
App.service('urlService', function() {
  var urlHash;

  var setUrl = function(hash) {
      urlHash = hash;
  };

  var getUrl = function(){
      return urlHash;
  };

  return {
    setUrl: setUrl,
    getUrl: getUrl
  };

});
<commit_msg>Update app.js<commit_after>var App = angular.module('App', ['pascalprecht.translate','ngRoute','ApiModel','ngSanitize','ngLoadScript','ngMeta']);

App.config(function($routeProvider,ngMetaProvider) {
    $routeProvider

      // route for the home page
      .when('/', {
        templateUrl : 'lib/pages/home.html',
        controller  : 'appCtrl'
      })
      // route for the about page
      .when('/terms', {
        templateUrl : 'lib/pages/terms.html',
        controller  : 'appCtrl'
      })
      .when('/privacy', {
        templateUrl : 'lib/pages/privacy.html',
        controller  : 'appCtrl'
      })
      .when('/guides', {
        templateUrl : 'lib/pages/guides.html',
        controller  : 'appCtrl'
      })
      // route for the contact page
      .when('/view/:orderId', {
        templateUrl : 'lib/pages/test.html',
        controller  : 'pageCtrl'
      })
      .when('/view/:orderId/:slug', {
        templateUrl : 'lib/pages/test.html',
        controller  : 'pageCtrl',
      })
      .when('/event/:eventId', {
        templateUrl : 'lib/pages/event.html',
        controller  : 'pageCtrl'
      })
      .when('/event/:eventId/:slug', {
        templateUrl : 'lib/pages/event.html',
        controller  : 'pageCtrl'
      })
      .otherwise({
                redirectTo: '/'
            });
  });
App.run(['ngMeta', function(ngMeta) {
  ngMeta.init();
}]);
App.filter('ucfirst', function() {
    return function(input, all) {
      var reg = (all) ? /([^\W_]+[^\s-]*) */g : /([^\W_]+[^\s-]*)/;
      return (!!input) ? input.replace(reg, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) : '';
    }
  });
App.filter("un_slug", [ function(){
 return function(str){
    try {
      return (str || '').replace(/-/g, ' ');
    } catch(e) {
      console.error("error in un_slug", e);
      return (str || '');
    }
  }
 }
]);
App.filter("remove_under", [ function(){
 return function(str){
    try {
      return (str || '').replace(/_/g, ' ');
    } catch(e) {
      console.error("error in remove_under", e);
      return (str || '');
    }
  }
 }
]);
App.filter('removeAt', function() {
    return function (value) {
        var s = value;
 var n = s.indexOf('@');
  s = s.substring(0, n != -1 ? n : s.length);
  return s;
    };

  });
App.controller('pageCtrl', function ($scope,$timeout,  $window,$translate,$route,$routeParams,ngMeta,$filter, $location,AppRestangular,anchorSmoothScroll,urlService) {

$scope.$route = $route;

$scope.$location = $location;
     $scope.$routeParams = $routeParams;
     $scope.name = 'pageController';
  if($routeParams.eventId){
    $scope.order_id = $routeParams.eventId
    $scope.pageType = "event";
  }else{
    var the_id = $routeParams.orderId;
    var claveType = the_id.charAt(0).toUpperCase();
    if(claveType == "X"){
      $scope.order_id = the_id.substr(1);
      $scope.pageType = "place";
    }else{
      $scope.order_id = the_id;
      $scope.pageType = "eat";
      console.log("is an eat");
    }

  }
  $scope.message = 'Look! I am an about page.';
  $scope.openInApp = () =>{

    var hash = window.location.hash.split("/");
    console.log(hash);
    if(hash[1] == 'view'){
      var the_id = hash[2].split("?");
      var claveType = the_id[0].charAt(0);
      console.log('clavetype: '+claveType);
      if(claveType == "x"){
        var elID = the_id[0];
      }else{
          var elID = "f"+the_id[0];
      }
      console.log("citywiz://id?cityclave="+elID);

      //deeplink.open("citywiz://id?cityclave="+elID);
      window.open("citywiz://id?cityclave="+elID);
    }
  }
  $scope.openInApptest = () =>{

    var hash = window.location.hash.split("/");
    console.log(hash);
    if(hash[1] == 'view'){
      var the_id = hash[2].split("?");
      var claveType = the_id[0].charAt(0);
      console.log('clavetype: '+claveType);
      if(claveType == "x"){
        var elID = the_id[0];
      }else{
          var elID = "f"+the_id[0];
      }
      console.log("citywiz://id?cityclave="+elID);

      //deeplink.open("citywiz://id?cityclave="+elID);
      window.location.replace("citywiz://id?cityclave="+elID);
    }
  }
//load data
$scope.gotoElement = function (eID){
      // set the location.hash to the id of
      // the element you wish to scroll to.
      urlService.setUrl(eID);
      //$location.hash(eID);
      $location.url("/"+eID);

    };
/************* load dynamic data based on guide ************/
  $scope.loadDetails = function() {
$scope.loaded = false;
    itemdata.get().then(function(data) {

    $scope.card = data;
    if($scope.pageType == 'place'){
      console.log("is place: "+JSON.stringify(data));
    }
    var unslug_cat = $filter('un_slug')(data.cat);
    unslug_cat = $filter('ucfirst')(unslug_cat);
    if(data.cat == 'nightlife'){
    var text = unslug_cat+" en "+data.city;
  }else{
    var text = unslug_cat+" food en "+data.city;
  }
  if($scope.pageType == 'place'){
    var text = unslug_cat;
  };
    ngMeta.setTitle(data.name);
    ngMeta.setTag('description', text);
    ngMeta.setTag('vport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
    ngMeta.setTag('image', data.social_imgs[0].img_path);
       //$scope.viewResult();
       // after data has finished loading
       //$scope.viewResult(data.latitude,data.longitude);

        setTimeout(function() {

       $scope.loaded = true;
       $scope.lang = function(){ return $translate.use();}
       $scope.$apply();

    }, 1000);

});

  };
if($scope.pageType == 'eat'){
  var itemdata = AppRestangular.one("id", $scope.order_id);
}else if($scope.pageType = 'place'){
  var itemdata = AppRestangular.one("placeid", $scope.order_id);
}else if($scope.pageType == 'event'){
  var itemdata = AppRestangular.one("eventid", $scope.order_id);
}

  $scope.loadDetails();
//load data ends
});
App.controller('appCtrl', function ($scope,$timeout,  $window,$translate,$route, $location,ngMeta,$routeParams,anchorSmoothScroll,urlService) {
 $scope.$route = $route;
$scope.$location = $location;
     $scope.$routeParams = $routeParams;
     $scope.name = 'appCtrl';
  $scope.helloworld = "hey! hello world!";
  $scope.data = {
  cb2: 'es'
};
  ngMeta.setTag('image', 'http://citywiz.imgix.net/citywiz_cover.png');
   $scope.changeLanguage = function (key) {
    $translate.use(key);
  };
 $scope.gotoElement = function (eID){
      // set the location.hash to the id of
      // the element you wish to scroll to.
      //$location.hash(eID);

      // call $anchorScroll()
      anchorSmoothScroll.scrollTo(eID);

    };

setTimeout(function() {

       $scope.loaded = true;
       var hash = urlService.getUrl();
       $scope.lang = function(){ return $translate.use();}
       if(hash){
            anchorSmoothScroll.scrollTo(hash);
       }
       $scope.$apply();

    }, 500);
});
App.config(['$translateProvider', function ($translateProvider) {
        $translateProvider.translations('en', {
            LANGBOARD: "Local Discovery Guides",
            APPBOARD: "Your App for Puerto Rico tourism!",
            DOWNAPP: "Get the free app!",
            VIEWBLOG: "View guides & articles",
            APPHERO2: "Citywiz helps you discover #EcoAdventure #Food #Culture #Attractions #Events. Discover and connect to everything local.",
            ABOUTUSTITLE:"We believe life is easier when you know what's around you.",
            APPABOUTUS: "
Citywiz is a free and easy-to-use iPhone\® and Android\® App that will guide you to discover and connect to everything local \(currently in Puerto Rico\).

If you’re looking for a place to eat, go for a night out, get the intel of nearby events or searching for an adventure on our beautiful island, our app will help you stay connected to everything your city has to offer.

New city-wizards \(guides\) will be added regularly for you to discover cool and essential things like food, outdoor adventures, music, art, culture and more.
",
            TEAMTITLE: "How wonderful to meet you!",
            TEAM: "
We are a small but passionate Puerto Rican team focused on delivering new and fun technology products that will help you search and discover.
",
            DOWNLOADTITLE: "Start discovering your city now!",
            DOWNLOAD: "Our FREE app is available now for iPhone and Android. Download now and get started!",
            ARTICLESHERO: "Discover places to visit, places to eat or stay and meet other tourists through our articles.",
            INSTAGRAMCOPY: "Follow our Instagram where we feature Puerto Rico's top places and food tru the lens of awesome local photographers/tourists who love the island and you should follow. Tap on the images for info and credit."

        })
        .translations('es', {
            LANGBOARD: "Guías de descubrimiento local",
            APPBOARD: "Tu App pal' turisteo!",
            DOWNAPP: "¡Descarga el app gratis!",
            VIEWBLOG: "Ver guías y artículos",
            APPHERO2: "CityWiz te ayuda a descubrir #aventureo #foodeo #turisteo #cultura en Puerto Rico. Descubre y conéctate a todo lo local.",
            ABOUTUSTITLE:"La vida es más fácil cuando sabes lo que te rodea.",
            APPABOUTUS: "
Citywiz es una aplicación de iPhone\® y Android\® gratuita y fácil de usar que te ayudará a descubrir y conectarte con todo lo que te rodea \(actualmente en Puerto Rico\).

Si estás buscando un lugar para comer, salir de paseo, obtener información de eventos cercanos o buscando una aventura en nuestra hermosa isla, nuestra aplicación te ayudará a mantenerte conectado con todo lo que tu ciudad tiene para ofrecer.

Nuevos city-wizards \(guías\) serán añadidos regularmente para que continúes descubriendo cosas nuevas y esenciales como comida, aventura, música, arte, cultura y mucho más.
",
            TEAMTITLE: "¡Qué maravilloso conocerte!",
            TEAM: "
Somos un pequeño pero apasionado equipo puertorriqueño enfocado en brindar nuevos y divertidos productos tecnológicos que te ayudarán a buscar y descubrir.
",
            DOWNLOADTITLE: "¡Comienza a descubrir tu ciudad ya!",
            DOWNLOAD: "Nuestra aplicación GRATIS ya está disponible para iPhone\® y Android\®. ¡Descargue ahora y comienza a descubrir!",
            ARTICLESHERO: "Descubre lugares para visitar, sitios para comer o quedarse y conoce a otros turistas a través de nuestros artículos.",
            INSTAGRAMCOPY: "Sigue nuestro Instagram donde presentamos los mejores lugares y comida de Puerto Rico capturados por increíbles fotógrafos / turisteros locales que aman la isla y los cuales debe seguir. Toque las imágenes para obtener información y crédito."
        });
$translateProvider.useSanitizeValueStrategy(null);
$translateProvider.preferredLanguage('en');
}]);
App.service('anchorSmoothScroll', function(){

    this.scrollTo = function(eID) {

        // This scrolling function
        // is from http://www.itnewb.com/tutorial/Creating-the-Smooth-Scroll-Effect-with-JavaScript

        var startY = currentYPosition();
        var stopY = elmYPosition(eID);
        var distance = stopY > startY ? stopY - startY : startY - stopY;
        if (distance < 100) {
            scrollTo(0, stopY); return;
        }
        var speed = Math.round(distance / 100);
        if (speed >= 20) speed = 20;
        var step = Math.round(distance / 25);
        var leapY = stopY > startY ? startY + step : startY - step;
        var timer = 0;
        if (stopY > startY) {
            for ( var i=startY; i<stopY; i+=step ) {
                setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
                leapY += step; if (leapY > stopY) leapY = stopY; timer++;
            } return;
        }
        for ( var i=startY; i>stopY; i-=step ) {
            setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
            leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
        }

        function currentYPosition() {
            // Firefox, Chrome, Opera, Safari
            if (self.pageYOffset) return self.pageYOffset;
            // Internet Explorer 6 - standards mode
            if (document.documentElement && document.documentElement.scrollTop)
                return document.documentElement.scrollTop;
            // Internet Explorer 6, 7 and 8
            if (document.body.scrollTop) return document.body.scrollTop;
            return 0;
        }

        function elmYPosition(eID) {
            var elm = document.getElementById(eID);
            var y = elm.offsetTop;
            var node = elm;
            while (node.offsetParent && node.offsetParent != document.body) {
                node = node.offsetParent;
                y += node.offsetTop;
            } return y;
        }

    };

});
App.service('urlService', function() {
  var urlHash;

  var setUrl = function(hash) {
      urlHash = hash;
  };

  var getUrl = function(){
      return urlHash;
  };

  return {
    setUrl: setUrl,
    getUrl: getUrl
  };

});
<|endoftext|>


<commit_before>var App = new Marionette.Application();

App.addRegions({
    "today": "#today",
    "week": "#week",
    "month": "#month"
});

var TodayView = Marionette.ItemView.extend({
    className: 'view',
    template: "#todayView"
});

var PeriodView = Marionette.ItemView.extend({
    className: 'view',
    template: "#periodView"
});

// Initialize
App.today.show(todayView);
App.week.show(weekView);
App.month.show(monthView);<commit_msg>Finishing marionette<commit_after>var App = new Marionette.Application();

App.addRegions({
    "today": "#today",
    "week": "#week",
    "month": "#month"
});

var TodayView = Marionette.ItemView.extend({
    className: 'view',
    template: "#todayView"
});

var PeriodView = Marionette.ItemView.extend({
    className: 'view',
    template: "#periodView"
});

// Initialize

var todayView = new TodayView({
	model: today;
});

var weekView = new WeekView({
	model: week;
});

var monthView = new MonthView({
	model: month;
});

App.today.show(todayView);
App.week.show(weekView);
App.month.show(monthView);<|endoftext|>


<commit_before>// IFG-Anfragen Vis
// (c) 2013 Stefan Wehrmeyer

(function($){

  var isTouch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;

  var margin = {top: 20, right: 20, bottom: 20, left: 20};
  var innerX = {top: 0, right: 50, bottom: 30, left: 80};
  var innerY = {top: 30, right: 80, bottom: 50, left: 30};

  d3.selection.prototype.moveToFront = function() {
    return this.each(function() {
      this.parentNode.appendChild(this);
    });
  };

  var containerWidth = document.getElementById('vis').offsetWidth;

  var width = Math.max(containerWidth, 768) - margin.left - margin.right,
      height = 468 - margin.top - margin.bottom;

  var parseYear = d3.time.format("%Y").parse;

  var innerXWidth = width - innerX.right - innerX.left;
  var x = d3.time.scale()
      .range([0, innerXWidth]);

  var innerYHeight = height - innerY.top - innerY.bottom;
  var y = d3.scale.linear()
      .domain([0, 100])
      .range([innerYHeight, 0]);

  var yAxis = d3.svg.axis()
      .scale(y)
      .tickSize(-width, 0, 0)
      .ticks(5)
      .tickFormat(function(d){ return d + '%'; })
      .orient("left");

  var xAxis = d3.svg.axis()
      .scale(x)
      .tickSize(-height + innerY.bottom, 0, 0)
      .tickPadding(6)
      .orient("top");

  var circleRadius = d3.scale.sqrt()
      .rangeRound([1, IFGVis.maxDotSize]);

  var connectionLine = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; })
    .interpolate("basis")
    .defined(function(d){
      return d.defined;
    });

  var svg = d3.select("#vis").append("svg:svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

  svg = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg.append("g")
    .attr("class", "y axis")
    .attr('transform', 'translate(' + innerY.left + ',' + innerY.top + ')')
    .call(yAxis);

  svg.select('.y.axis .major line').classed('bottomline', true);

  var activeGroups = 0;

  var activateGroup = function(key, hover) {
    return function(){
      var obj = groups[key];
      obj.group.moveToFront();
      svg.selectAll("." + key).style("fill", IFGVis.colors[key]).classed('active', true);
      obj.group.select('.line').style('display', 'block');
      if (stack[stack.length - 1] === key) {
        svg.select('#label')
          .attr('transform', 'translate(' + (innerXWidth + innerX.left + 40) + ',' + (obj.labelpos + 12) + ')')
          .style('display', 'block');
        svg.select('#label-triangle')
          .attr('transform', 'translate(' + (innerXWidth + innerX.left) + ',' + (obj.labelpos + 22) + ')');
        svg.select('#label-text')
          .text(IFGVis.labels[key])
          .style('fill', IFGVis.colors[key]);
        var bbox = svg.select('#label-text').node().getBBox();
        svg.select('#label-rect')
          .attr('transform', 'translate(' + (-bbox.width - 5) + ',' + (-20) + ')')
          .attr('width', bbox.width + 10)
          .attr('height', bbox.height + 5);
        svg.selectAll('.label').style('display', 'block');
        obj.group.selectAll('.circle-number').style('display', 'block');
      } else {
        obj.group.selectAll('.circle-number').style('display', 'none');
      }
      activeInForeground();
    };
  };

  var permanentlyActivateGroup = function(key){
    return function(){
      var obj = groups[key];
      obj.isActive = !obj.isActive;
      if (obj.isActive) {
        activateGroup(key)();
      } else {
        deactivateGroup(key)();
      }
    };
  };

  var deactivateGroup = function(key) {
    return function() {
      var obj = groups[key];
      if (obj.isActive) { return; }
      obj.group.select('.line').style('display', 'none');
      svg.selectAll("." + key).style("fill", "").classed('active', false);
      obj.group.selectAll('.circle-number').style('display', 'none');
      refreshAllActiveGroups();
    };
  };

  var activeInForeground = function(){
    for (var key in groups){
      if (groups[key].isActive){
        groups[key].group.moveToFront();
      }
    }
    if (stack.length > 0) {
      groups[stack[stack.length - 1]].group.moveToFront();
    }
    svg.selectAll('.label').moveToFront();
  };

  var refreshAllActiveGroups = function(){
    for (var key in groups){
      if (groups[key].isActive){
        activateGroup(key)();
      }
    }
    activeInForeground();
  };

  var groups = {};

  var getLineData = function(groupData){
    var newData = [], d, rad, dist;
    for (var i = 0; i < groupData.length; i += 1){
      if (i < groupData.length - 1) {
        dist = x(groupData[1].year) - x(groupData[0].year);
        dist = Math.round((dist - 50) / 2);
      }
      rad = dist;
      if (i > 0){
        d = $.extend({}, groupData[i]);
        d.rad = rad;
        d.x = x(d.year) - rad;
        d.y = y(d.transparency);
        d.defined = true;
        newData.push(d);
      }
      d = $.extend({}, groupData[i]);
      d.x = x(d.year);
      d.y = y(d.transparency);
      d.defined = true;
      newData.push(d);
      if (i < groupData.length - 1) {
        d = $.extend({}, groupData[i]);
        d.x = x(d.year) + rad;
        d.y = y(d.transparency);
        d.defined = true;
        newData.push(d);
      }
    }

    return newData;
  };

  var makeTriangle = (function() {
    var t = d3.svg.symbol();
    t.size(100);
    return t;
  }());

  var makeGroup = function(key, groupData){
    var group = svg.append('g')
      .attr('transform', 'translate(' + innerX.left + ',' + innerY.top + ')')
      .attr('class', 'group ' + key);

    var connectionData = getLineData(groupData);

    group.append("svg:path")
        .attr('class', 'line')
        .style('stroke', IFGVis.colors[key])
        .style('display', 'none')
        .attr("d", connectionLine(connectionData));

    var groupSelect = group
      .selectAll("." + key)
      .data(groupData);

    var circleGroup = groupSelect
      .enter().append("g");

    circleGroup.append('path')
      .attr('d', makeTriangle.type('triangle-up')())
      .attr('class', 'triangle circle-number label-background')
      .attr('transform', function(d){
        return 'translate(' + (x(d.year)) + ',' + (y(d.transparency) + 8) + ')';
      })
      .style('display', 'none');

    var circleGroupText = circleGroup.append('g')
      .attr('class', 'circle-number');

    circleGroupText.append('rect')
        .attr('width', '70')
        .attr('class', 'label-background')
        .attr('height', '70')
        .attr('transform', function(d){
          return 'translate(' + (x(d.year) - 35) + ',' + (y(d.transparency) + 12) + ')';
        });

    var t = circleGroupText.append('text')
      .attr('class', 'circle-number highlight')
      .style('fill', IFGVis.colors[key])
      .attr('transform', function(d){
        return 'translate(' + (x(d.year)) + ',' + (y(d.transparency) + 31) + ')';
      })
      .style('display', 'none')
      .attr('text-anchor', 'middle');

    t.append('tspan')
      .attr('x', 0)
      .text(function(d){
          return d.transparency + '%';
      });
    t.append('tspan')
      .attr('x', 0)
      .attr('dy', 15)
      .text(function(d){
          return 'von ' + d.count;
      });
    t.append('tspan')
      .attr('x', 0)
      .attr('dy', 15)
      .text(function(d){
        return d.count === 1 ? 'Antrag' : 'Anträgen';
      });
    t.append('tspan')
      .attr('x', 0)
      .attr('dy', 15)
      .text('bewilligt');

    if (isTouch){
      group.data(groupData)
        .on("touchstart", navigateToKey(key));
    } else {
      group.data(groupData)
        .on("mouseover", activateGroup(key, true))
        .on("mouseout", deactivateGroup(key))
        .on("click", navigateToKey(key));
    }

    var lastBubble = groupData[groupData.length - 1];
    var labelpos = y(lastBubble.transparency);

    return {
      labelpos: labelpos,
      group: group,
      isActive: false
    };
  };

  var dataLoaded = function(error, data) {
    data.forEach(function(d) {
      d.year = parseYear(d.year);
      d.count = parseInt(d.count, 10);
      d.transparency = parseInt(d.transparency, 10);
    });
    data = data.filter(function(d){
      return d.count > 0;
    })
    .sort(function(a, b){
      return a.year - b.year;
    });

    x.domain(d3.extent(data, function(d) { return d.year; }));

    svg.append("g")
      .attr("class", "x axis")
      .attr('transform', 'translate(' + innerX.left + ',' + innerX.top + ')')
      .call(xAxis);

    var label = svg.append('g')
      .attr('id', 'label')
      .attr('class', 'label')
      .style('display', 'none');

    label.append('rect')
      .attr('id', 'label-rect')
      .attr('class', 'label-background')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', 1)
      .attr('height', 1);
    svg.append('path')
      .attr('id', 'label-triangle')
      .attr('d', makeTriangle.type('triangle-down')())
      .attr('class', 'triangle label label-background');
    label.append('text')
      .attr('id', 'label-text')
      .attr('text-anchor', 'end');

    circleRadius.domain(d3.extent(data, function(d) { return d.count; }));

    var filterFunc = function(key){
      return function(d){ return d.name === key; };
    };

    // Add Circles independent from group
    var circleData = data.slice();
    circleData.sort(function(a, b){
      return b.count - a.count;
    });
    svg.selectAll('.dot')
      .data(circleData)
      .enter()
      .append('circle')
      .attr("class", function(d){
        return "dot circle " + d.name;
      })
      .attr("r", function(d) {
        return circleRadius(d.count);
      });

    var helpCircleData = circleData.slice().filter(function(d, i){
      return circleRadius(d.count) <= IFGVis.dotSizeNeedsHelp;
    });
    svg.selectAll('.helpdot')
      .data(helpCircleData)
      .enter()
      .append('circle')
      .attr("r", IFGVis.helpDotSize)
      .attr("class", "helpdot circle");

    svg.selectAll('.circle')
      .attr('transform', 'translate(' + innerX.left + ',' + innerY.top + ')')
      .attr("cx", function(d) { return x(d.year); })
      .attr("cy", function(d) { return y(d.transparency); });

    if (isTouch){
      svg.selectAll('.circle')
        .on("touchstart", function(d){
          navigateToKey(d.name)();
        });
    } else {
      svg.selectAll('.circle')
        .on("mouseover", function(d){
          activateGroup(d.name, true)();
        })
        .on("mouseout", function(d){
          deactivateGroup(d.name)();
        })
        .on("click", function(d){
          navigateToKey(d.name)();
        });
    }

    for (var key in IFGVis.colors) {
      groups[key] = makeGroup(key, data.filter(filterFunc(key)));
    }

    init();
  };

  var initial = true, stack = [];

  var WorkspaceRouter = Backbone.Router.extend({
    routes: {
      "*args": "show"
    },

    show: function(args) {
      if (initial && args === "") {
        router.navigate(IFGVis.defaultInstitution, {trigger: true});
        initial = false;
        return;
      }
      initial = false;
      args = args.split('&');
      $('.label').hide();
      $('input').prop('checked', false);
      for (var key in groups){
        groups[key].isActive = false;
        deactivateGroup(key)();
      }
      activeGroups = 0;
      stack = [];
      for (var i = 0; i < args.length; i += 1) {
        if (groups[args[i]] !== undefined) {
          stack.push(args[i]);
          $('input[value="' + args[i] + '"]').prop('checked', true);
          activeGroups += 1;
          permanentlyActivateGroup(args[i])();
        }
      }
      refreshAllActiveGroups();
    }

  });

  var init = function(){
    Backbone.history.start();
  };

  var router = new WorkspaceRouter();

  var navigateToKey = function(key){
    return function(){
      var checked = $('input[value="' + key + '"]').prop('checked');
      $('input[value="' + key + '"]').prop('checked', !checked);
      toggleOnStack(key, !checked);
      updateNav();
    };
  };

  var toggleOnStack = function(key, add){
    if (add) {
      stack.push(key);
    } else {
      stack = stack.filter(function(el){
        return el !== key;
      });
    }
  };

  var updateNav = function(){
    router.navigate(stack.join('&'), {trigger: true});
  };

  $(function(){
    $('#auswahl-button').on('click touchstart', function(e){
      e.preventDefault();
      $('#auswahl').slideToggle();
    });
    $('#choose-all').on('click touchstart', function(e){
      e.preventDefault();
      $('.auswahl-liste input').prop('checked', true);
      stack = [];
      $('.auswahl-liste input').each(function(i, el){
        stack.push($(el).val());
      });
      updateNav();
    });
    $('#choose-none').on('click touchstart', function(e){
      e.preventDefault();
      $('.auswahl-liste input').prop('checked', false);
      stack = [];
      updateNav();
    });
    $('.auswahl-liste input').change(function(e){
      toggleOnStack($(this).val(), $(this).prop('checked'));
      updateNav();
    });
    $('.close').on('click touchstart', function(e){
      e.preventDefault();
      $('#auswahl').slideUp();
    });
  });

  dataLoaded(null, IFGVis.data);
  // d3.csv("data.csv", dataLoaded);

}(jQuery));
<commit_msg>Add bigger margin to bottom<commit_after>// IFG-Anfragen Vis
// (c) 2013 Stefan Wehrmeyer

(function($){

  var isTouch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;

  var margin = {top: 20, right: 20, bottom: 20, left: 20};
  var innerX = {top: 0, right: 50, bottom: 30, left: 80};
  var innerY = {top: 30, right: 80, bottom: 80, left: 30};

  d3.selection.prototype.moveToFront = function() {
    return this.each(function() {
      this.parentNode.appendChild(this);
    });
  };

  var containerWidth = document.getElementById('vis').offsetWidth;

  var width = Math.max(containerWidth, 768) - margin.left - margin.right,
      height = 468 - margin.top - margin.bottom;

  var parseYear = d3.time.format("%Y").parse;

  var innerXWidth = width - innerX.right - innerX.left;
  var x = d3.time.scale()
      .range([0, innerXWidth]);

  var innerYHeight = height - innerY.top - innerY.bottom;
  var y = d3.scale.linear()
      .domain([0, 100])
      .range([innerYHeight, 0]);

  var yAxis = d3.svg.axis()
      .scale(y)
      .tickSize(-width, 0, 0)
      .ticks(5)
      .tickFormat(function(d){ return d + '%'; })
      .orient("left");

  var xAxis = d3.svg.axis()
      .scale(x)
      .tickSize(-height + innerY.bottom, 0, 0)
      .tickPadding(6)
      .orient("top");

  var circleRadius = d3.scale.sqrt()
      .rangeRound([1, IFGVis.maxDotSize]);

  var connectionLine = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; })
    .interpolate("basis")
    .defined(function(d){
      return d.defined;
    });

  var svg = d3.select("#vis").append("svg:svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

  svg = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg.append("g")
    .attr("class", "y axis")
    .attr('transform', 'translate(' + innerY.left + ',' + innerY.top + ')')
    .call(yAxis);

  svg.select('.y.axis .major line').classed('bottomline', true);

  var activeGroups = 0;

  var activateGroup = function(key, hover) {
    return function(){
      var obj = groups[key];
      obj.group.moveToFront();
      svg.selectAll("." + key).style("fill", IFGVis.colors[key]).classed('active', true);
      obj.group.select('.line').style('display', 'block');
      if (stack[stack.length - 1] === key) {
        svg.select('#label')
          .attr('transform', 'translate(' + (innerXWidth + innerX.left + 40) + ',' + (obj.labelpos + 12) + ')')
          .style('display', 'block');
        svg.select('#label-triangle')
          .attr('transform', 'translate(' + (innerXWidth + innerX.left) + ',' + (obj.labelpos + 22) + ')');
        svg.select('#label-text')
          .text(IFGVis.labels[key])
          .style('fill', IFGVis.colors[key]);
        var bbox = svg.select('#label-text').node().getBBox();
        svg.select('#label-rect')
          .attr('transform', 'translate(' + (-bbox.width - 5) + ',' + (-20) + ')')
          .attr('width', bbox.width + 10)
          .attr('height', bbox.height + 5);
        svg.selectAll('.label').style('display', 'block');
        obj.group.selectAll('.circle-number').style('display', 'block');
      } else {
        obj.group.selectAll('.circle-number').style('display', 'none');
      }
      activeInForeground();
    };
  };

  var permanentlyActivateGroup = function(key){
    return function(){
      var obj = groups[key];
      obj.isActive = !obj.isActive;
      if (obj.isActive) {
        activateGroup(key)();
      } else {
        deactivateGroup(key)();
      }
    };
  };

  var deactivateGroup = function(key) {
    return function() {
      var obj = groups[key];
      if (obj.isActive) { return; }
      obj.group.select('.line').style('display', 'none');
      svg.selectAll("." + key).style("fill", "").classed('active', false);
      obj.group.selectAll('.circle-number').style('display', 'none');
      refreshAllActiveGroups();
    };
  };

  var activeInForeground = function(){
    for (var key in groups){
      if (groups[key].isActive){
        groups[key].group.moveToFront();
      }
    }
    if (stack.length > 0) {
      groups[stack[stack.length - 1]].group.moveToFront();
    }
    svg.selectAll('.label').moveToFront();
  };

  var refreshAllActiveGroups = function(){
    for (var key in groups){
      if (groups[key].isActive){
        activateGroup(key)();
      }
    }
    activeInForeground();
  };

  var groups = {};

  var getLineData = function(groupData){
    var newData = [], d, rad, dist;
    for (var i = 0; i < groupData.length; i += 1){
      if (i < groupData.length - 1) {
        dist = x(groupData[1].year) - x(groupData[0].year);
        dist = Math.round((dist - 50) / 2);
      }
      rad = dist;
      if (i > 0){
        d = $.extend({}, groupData[i]);
        d.rad = rad;
        d.x = x(d.year) - rad;
        d.y = y(d.transparency);
        d.defined = true;
        newData.push(d);
      }
      d = $.extend({}, groupData[i]);
      d.x = x(d.year);
      d.y = y(d.transparency);
      d.defined = true;
      newData.push(d);
      if (i < groupData.length - 1) {
        d = $.extend({}, groupData[i]);
        d.x = x(d.year) + rad;
        d.y = y(d.transparency);
        d.defined = true;
        newData.push(d);
      }
    }

    return newData;
  };

  var makeTriangle = (function() {
    var t = d3.svg.symbol();
    t.size(100);
    return t;
  }());

  var makeGroup = function(key, groupData){
    var group = svg.append('g')
      .attr('transform', 'translate(' + innerX.left + ',' + innerY.top + ')')
      .attr('class', 'group ' + key);

    var connectionData = getLineData(groupData);

    group.append("svg:path")
        .attr('class', 'line')
        .style('stroke', IFGVis.colors[key])
        .style('display', 'none')
        .attr("d", connectionLine(connectionData));

    var groupSelect = group
      .selectAll("." + key)
      .data(groupData);

    var circleGroup = groupSelect
      .enter().append("g");

    circleGroup.append('path')
      .attr('d', makeTriangle.type('triangle-up')())
      .attr('class', 'triangle circle-number label-background')
      .attr('transform', function(d){
        return 'translate(' + (x(d.year)) + ',' + (y(d.transparency) + 8) + ')';
      })
      .style('display', 'none');

    var circleGroupText = circleGroup.append('g')
      .attr('class', 'circle-number');

    circleGroupText.append('rect')
        .attr('width', '70')
        .attr('class', 'label-background')
        .attr('height', '70')
        .attr('transform', function(d){
          return 'translate(' + (x(d.year) - 35) + ',' + (y(d.transparency) + 12) + ')';
        });

    var t = circleGroupText.append('text')
      .attr('class', 'circle-number highlight')
      .style('fill', IFGVis.colors[key])
      .attr('transform', function(d){
        return 'translate(' + (x(d.year)) + ',' + (y(d.transparency) + 31) + ')';
      })
      .style('display', 'none')
      .attr('text-anchor', 'middle');

    t.append('tspan')
      .attr('x', 0)
      .text(function(d){
          return d.transparency + '%';
      });
    t.append('tspan')
      .attr('x', 0)
      .attr('dy', 15)
      .text(function(d){
          return 'von ' + d.count;
      });
    t.append('tspan')
      .attr('x', 0)
      .attr('dy', 15)
      .text(function(d){
        return d.count === 1 ? 'Antrag' : 'Anträgen';
      });
    t.append('tspan')
      .attr('x', 0)
      .attr('dy', 15)
      .text('bewilligt');

    if (isTouch){
      group.data(groupData)
        .on("touchstart", navigateToKey(key));
    } else {
      group.data(groupData)
        .on("mouseover", activateGroup(key, true))
        .on("mouseout", deactivateGroup(key))
        .on("click", navigateToKey(key));
    }

    var lastBubble = groupData[groupData.length - 1];
    var labelpos = y(lastBubble.transparency);

    return {
      labelpos: labelpos,
      group: group,
      isActive: false
    };
  };

  var dataLoaded = function(error, data) {
    data.forEach(function(d) {
      d.year = parseYear(d.year);
      d.count = parseInt(d.count, 10);
      d.transparency = parseInt(d.transparency, 10);
    });
    data = data.filter(function(d){
      return d.count > 0;
    })
    .sort(function(a, b){
      return a.year - b.year;
    });

    x.domain(d3.extent(data, function(d) { return d.year; }));

    svg.append("g")
      .attr("class", "x axis")
      .attr('transform', 'translate(' + innerX.left + ',' + innerX.top + ')')
      .call(xAxis);

    var label = svg.append('g')
      .attr('id', 'label')
      .attr('class', 'label')
      .style('display', 'none');

    label.append('rect')
      .attr('id', 'label-rect')
      .attr('class', 'label-background')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', 1)
      .attr('height', 1);
    svg.append('path')
      .attr('id', 'label-triangle')
      .attr('d', makeTriangle.type('triangle-down')())
      .attr('class', 'triangle label label-background');
    label.append('text')
      .attr('id', 'label-text')
      .attr('text-anchor', 'end');

    circleRadius.domain(d3.extent(data, function(d) { return d.count; }));

    var filterFunc = function(key){
      return function(d){ return d.name === key; };
    };

    // Add Circles independent from group
    var circleData = data.slice();
    circleData.sort(function(a, b){
      return b.count - a.count;
    });
    svg.selectAll('.dot')
      .data(circleData)
      .enter()
      .append('circle')
      .attr("class", function(d){
        return "dot circle " + d.name;
      })
      .attr("r", function(d) {
        return circleRadius(d.count);
      });

    var helpCircleData = circleData.slice().filter(function(d, i){
      return circleRadius(d.count) <= IFGVis.dotSizeNeedsHelp;
    });
    svg.selectAll('.helpdot')
      .data(helpCircleData)
      .enter()
      .append('circle')
      .attr("r", IFGVis.helpDotSize)
      .attr("class", "helpdot circle");

    svg.selectAll('.circle')
      .attr('transform', 'translate(' + innerX.left + ',' + innerY.top + ')')
      .attr("cx", function(d) { return x(d.year); })
      .attr("cy", function(d) { return y(d.transparency); });

    if (isTouch){
      svg.selectAll('.circle')
        .on("touchstart", function(d){
          navigateToKey(d.name)();
        });
    } else {
      svg.selectAll('.circle')
        .on("mouseover", function(d){
          activateGroup(d.name, true)();
        })
        .on("mouseout", function(d){
          deactivateGroup(d.name)();
        })
        .on("click", function(d){
          navigateToKey(d.name)();
        });
    }

    for (var key in IFGVis.colors) {
      groups[key] = makeGroup(key, data.filter(filterFunc(key)));
    }

    init();
  };

  var initial = true, stack = [];

  var WorkspaceRouter = Backbone.Router.extend({
    routes: {
      "*args": "show"
    },

    show: function(args) {
      if (initial && args === "") {
        router.navigate(IFGVis.defaultInstitution, {trigger: true});
        initial = false;
        return;
      }
      initial = false;
      args = args.split('&');
      $('.label').hide();
      $('input').prop('checked', false);
      for (var key in groups){
        groups[key].isActive = false;
        deactivateGroup(key)();
      }
      activeGroups = 0;
      stack = [];
      for (var i = 0; i < args.length; i += 1) {
        if (groups[args[i]] !== undefined) {
          stack.push(args[i]);
          $('input[value="' + args[i] + '"]').prop('checked', true);
          activeGroups += 1;
          permanentlyActivateGroup(args[i])();
        }
      }
      refreshAllActiveGroups();
    }

  });

  var init = function(){
    Backbone.history.start();
  };

  var router = new WorkspaceRouter();

  var navigateToKey = function(key){
    return function(){
      var checked = $('input[value="' + key + '"]').prop('checked');
      $('input[value="' + key + '"]').prop('checked', !checked);
      toggleOnStack(key, !checked);
      updateNav();
    };
  };

  var toggleOnStack = function(key, add){
    if (add) {
      stack.push(key);
    } else {
      stack = stack.filter(function(el){
        return el !== key;
      });
    }
  };

  var updateNav = function(){
    router.navigate(stack.join('&'), {trigger: true});
  };

  $(function(){
    $('#auswahl-button').on('click touchstart', function(e){
      e.preventDefault();
      $('#auswahl').slideToggle();
    });
    $('#choose-all').on('click touchstart', function(e){
      e.preventDefault();
      $('.auswahl-liste input').prop('checked', true);
      stack = [];
      $('.auswahl-liste input').each(function(i, el){
        stack.push($(el).val());
      });
      updateNav();
    });
    $('#choose-none').on('click touchstart', function(e){
      e.preventDefault();
      $('.auswahl-liste input').prop('checked', false);
      stack = [];
      updateNav();
    });
    $('.auswahl-liste input').change(function(e){
      toggleOnStack($(this).val(), $(this).prop('checked'));
      updateNav();
    });
    $('.close').on('click touchstart', function(e){
      e.preventDefault();
      $('#auswahl').slideUp();
    });
  });

  dataLoaded(null, IFGVis.data);
  // d3.csv("data.csv", dataLoaded);

}(jQuery));
<|endoftext|>


<commit_before>var map = L.map('map').setView([59.66, 10.77], 5);
// L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
var Kartverket = new L.TileLayer.Kartverket("topo2graatone");
Kartverket.addTo(map);

var myStyle = {"color": "#000000", "weigth": 0, "opacity": 1, "fillOpacity": 1};
var Norge = L.geoJson.ajax("data/fylker.geojson", {style:myStyle});

// Norge.addTo(map);

navigator.geolocation.getCurrentPosition(onSuccess,
                                         onError,
                                         {maximumAge: 10000, timeout: 5000, enableHighAccuracy: true,
                                         interval: 6000})

  function onSuccess(pos){
  var lat = pos.coords.latitude;
  var lon = pos.coords.longitude;
  console.log(lat, lon);

  var point = {
    "type": "Feature",
    "properties": {},
    "geometry": {
        "type": "Point",
        "coordinates": [lon, lat]
    }
};
    var bufferStyle = {"color": "#ff0000"};
    var buffer = turf.buffer(point,5000,'meters');
    console.log(buffer);
    console.log(Norge);
    var geojsonbuffer= L.geoJson(buffer, {style:bufferStyle});
    geojsonbuffer.addTo(map);
    console.log(geojsonbuffer);
    JSON.stringify(Norge);
    console.log(Norge);
    var layers = L.layerGroup([Kartverket, Norge, geojsonbuffer]);
    // layers.addTo(map);
    // geojsonbuffer.addTo(map);
    // var bufferLayer = L.GeoJSON(buffer).addTo(map);
    // buffer.setGeoJSON();
    // console.log(turf.featurecollection);
    // var result = turf.featurecollection([buffer.features, point]);

    // var differenced = turf.difference(geojsonbuffer, Norge)
    // differenced.addTo(map);

}
function onError(){
  alert('Noe gikk feil');
}

// TODO: Add leaflet mini map
<commit_msg>difference works<commit_after>var map = L.map('map').setView([59.66, 10.77], 5);
// L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
var Kartverket = new L.TileLayer.Kartverket("topo2graatone");
Kartverket.addTo(map);

var myStyle = {"color": "#000000", "weigth": 0, "opacity": 1, "fillOpacity": 1};
var Norge = L.geoJson.ajax("data/norge2.geojson", {style:myStyle});
Norge.toGeoJSON();
// Norge.addTo(map);

var polygon2 = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [-2.021484375, 57.61010702068388],
      [-2.021484375, 72.18180355624855],
      [33.83789062499999, 72.18180355624855],
      [33.83789062499999, 57.61010702068388],
      [-2.021484375, 57.61010702068388]
    ]]
  }
};
// L.geoJSON(polygon2).addTo(map);

navigator.geolocation.getCurrentPosition(onSuccess,
                                         onError,
                                         {maximumAge: 10000, timeout: 5000, enableHighAccuracy: true,
                                         interval: 6000})

  function onSuccess(pos){
  var lat = pos.coords.latitude;
  var lon = pos.coords.longitude;
  console.log(lat, lon);

  var point = {
    "type": "Feature",
    "properties": {},
    "geometry": {
        "type": "Point",
        "coordinates": [lon, lat]
    }
};
    var bufferStyle = {"color": "#ff0000"};
    var buffer = turf.buffer(point,5000,'meters');
    console.log(buffer);
    console.log(Norge);
    var geojsonbuffer= L.geoJson(buffer, {style:bufferStyle});
    // geojsonbuffer.addTo(map);
    console.log(geojsonbuffer);
    var layers = L.layerGroup([Kartverket, Norge, geojsonbuffer]);
    // layers.addTo(map);
    // geojsonbuffer.addTo(map);
    // var bufferLayer = L.GeoJSON(buffer).addTo(map);
    // buffer.setGeoJSON();
    // console.log(turf.featurecollection);
    // var result = turf.featurecollection([buffer.features, point]);

    var differenced = turf.difference(polygon2, buffer);
    console.log(differenced);
    L.geoJSON(differenced).addTo(map);
    // differenced.addTo(map);

}
function onError(){
  alert('Noe gikk feil');
}

// TODO: Add leaflet mini map
<|endoftext|>


<commit_before>(function(window, document, undefined) {

    // When the embedder is compiled, dependencies will be loaded directly before this
    // function. Set dependencies to use no-conflict mode to avoid destroying any
    // original objects.
    var __ = _.noConflict();
    var _$ = Zepto;
    var _Backbone = Backbone.noConflict();
    var _Popcorn = Popcorn.noConflict();

    // _amara may exist with a queue of actions that need to be processed after the
    // embedder has finally loaded. Store the queue in toPush for processing in init().
    var toPush = window._amara || [];

    var Amara = function(Amara) {

        // For reference in inner functions.
        var that = this;

        // This will store all future instances of Amara-powered videos.
        // I'm trying really hard here to not use the word "widget".
        this.amaraInstances = [];

        // Private methods that are called via the push() method.
        var actions = {

            // The core function for constructing an entire video with Amara subtitles from
            // just a video URL. This includes DOM creation for the video, etc.
            embedVideo: function(options) {

                // Make sure we have a URL to work with.
                // If we do, init a new Amara view.
                if (__.has(options, 'url') && __.has(options, 'div')) {

                    that.amaraInstances.push(
                        new that.AmaraView({

                            // TODO: This needs to support a node OR ID string.
                            el: _$(options.div)[0],
                            model: new VideoModel(options)
                        })
                    );
                }
            }
        };

        // Utilities.
        var utils = {
            parseFloatAndRound: function(val) {
                return (Math.round(parseFloat(val) * 100) / 100).toFixed(2);
            }
        };

        // Video model.
        var VideoModel = _Backbone.Model.extend({

            // The initialization of these vars is unnecessary, but it's nice to know
            // what vars will *eventually* be on the video model.

            // This var will be true once we've retrieved the rest of the model attrs
            // from the Amara API.
            isComplete: false,

            // Set from within the embedder.
            div: '',
            height: '',
            initialLanguage: null,
            isOnAmara: null,
            subtitles: [], // Backbone collection
            url: '',
            width: '',

            // Set from the Amara API
            all_urls: [],
            created: null,
            description: null,
            duration: null,
            id: null,
            languages: [],
            original_language: null,
            project: null,
            resource_uri: null,
            team: null,
            thumbnail: null,
            title: null,

            // Every time a video model is created, do this.
            initialize: function() {

                var video = this;
                var apiURL = 'https://staging.universalsubtitles.org/api2/partners/videos/?&video_url=';

                this.subtitles = new that.Subtitles();

                // Make a call to the Amara API to get attributes like available languages,
                // internal ID, description, etc.
                _$.ajax({
                    url: apiURL + this.get('url'),
                    dataType: 'jsonp',
                    success: function(resp) {

                        if (resp.objects.length) {

                            // The video exists on Amara.
                            video.set('isOnAmara', true);

                            // There should only be one object.
                            if (resp.objects.length === 1) {

                                // Set all of the API attrs as attrs on the video model.
                                video.set(resp.objects[0]);

                                // Set the initial language to either the one provided by the initial
                                // options, or the original language from the API.
                                video.set('initialLanguage',
                                    video.get('initialLanguage') ||
                                    video.get('original_language')
                                );
                            }

                        } else {

                            // The video does not exist on Amara.
                            video.set('isOnAmara', false);

                        }

                        // Mark that the video model has been completely populated.
                        video.set('isComplete', true);
                    }
                });
            }
        });

        // SubtitleSet model.
        var SubtitleSet = _Backbone.Model.extend({

            // Set from the Amara API
            description: null,
            language: null,
            note: null,
            resource_uri: null,
            site_url: null,
            sub_format: null,
            subtitles: [],
            title: null,
            version_no: null,
            video: null,
            video_description: null,
            video_title: null

        });

        // Subtitles collection.
        this.Subtitles = _Backbone.Collection.extend({
            model: SubtitleSet
        });

        // Amara view. This contains all of the events and logic for a single instance of
        // an Amara-powered video.
        this.AmaraView = _Backbone.View.extend({

            initialize: function() {
                this.model.view = this;
                this.template = __.template(this.templateHTML);
                this.render();
            },

            events: {
                'click a.amara-share-button':      'shareButtonClicked',
                'click a.amara-transcript-button': 'toggleTranscriptDisplay',
                'click a.amara-subtitles-button':  'toggleSubtitlesDisplay'
            },

            render: function() {

                var that = this;

                // Create a container that we will use to inject the Popcorn video.
                this.$el.prepend('

');

                this.$popContainer = $('div.amara-popcorn', this.$el);

                // Copy the width and height to the new Popcorn container.
                this.$popContainer.width(this.$el.width());
                this.$popContainer.height(this.$el.height());

                // This is a hack until Popcorn.js supports passing a DOM elem to
                // its smart() method. See: http://bit.ly/L0Lb7t
                var id = 'amara-popcorn-' + Math.floor(Math.random() * 100000000);
                this.$popContainer.attr('id', id);

                // Reset the height on the parent amara-embed div. If we don't do this,
                // our amara-tools div won't be visible.
                this.$el.height('auto');

                // Init the Popcorn video.
                this.pop = _Popcorn.smart(this.$popContainer.attr('id'), this.model.get('url'));

                this.pop.on('loadedmetadata', function() {

                    // Set the video model's height and width, now that we know it.
                    that.model.set('height', that.pop.position().height);
                    that.model.set('width', that.pop.position().width);

                    // Create the actual core DOM for the Amara container.
                    that.$el.append(that.template({
                        video_url: 'http://www.universalsubtitles.org/en/videos/' + that.model.get('id'),
                        width: that.model.get('width')
                    }));

                    // Just set some cached Zepto selections for later use.
                    that.cacheNodes();

                    // Wait until we have a complete video model (the API was hit as soon as
                    // the video instance was created), and then retrieve the initial set
                    // of subtitles, so we can begin building out the transcript viewer
                    // and the subtitle display.
                    //
                    // We could just make this a callback on the model's initialize() for
                    // after we get a response, but there may be cases where we want to init
                    // a VideoModel separately from an AmaraView.
                    that.waitUntilVideoIsComplete(
                        function() {

                            // Grab the subtitles for the initial language and do yo' thang.
                            if (that.model.get('isOnAmara')) {

                                // Make the request to fetch the initial subtitles.
                                that.fetchSubtitles(that.model.get('initialLanguage'), function() {

                                    // When we've got a response with the subtitles, start building
                                    // out the transcript viewer and subtitles.
                                    that.buildTranscript(that.model.get('initialLanguage'));
                                    that.buildSubtitles(that.model.get('initialLanguage'));
                                });
                            } else {
                                // Do some other stuff for videos that aren't yet on Amara.
                            }
                        }
                    );
                });

                return this;

            },

            buildSubtitles: function(language) {

                // Get the subtitle sets for this language.
                var subtitleSets = this.model.subtitles.where({'language': language});

                if (subtitleSets.length) {
                    var subtitleSet = subtitleSets[0];

                    // Get the actual subtitles for this language.
                    var subtitles = subtitleSet.get('subtitles');

                    // For each subtitle, init the Popcorn subtitle plugin.
                    for (var i = 0; i < subtitles.length; i++) {
                        this.pop.amarasubtitle({
                            start: subtitles[i].start,
                            end: subtitles[i].end,
                            text: subtitles[i].text
                        });
                    }

                    this.$popSubtitlesContainer = $('div.amara-popcorn-subtitles', this.$el);
                }
            },
            buildTranscript: function(language) {

                var subtitleSet;

                // Get the subtitle sets for this language.
                var subtitleSets = this.model.subtitles.where({'language': language});

                if (subtitleSets.length) {
                    subtitleSet = subtitleSets[0];
                } else {
                    $('.amara-transcript-line-right', this.$transcriptBody).text('No subtitles available.');
                }

                // Get the actual subtitles for this language.
                var subtitles = subtitleSet.get('subtitles');

                if (subtitles.length) {

                    // Remove the loading indicator.
                    this.$transcriptBody.html('');

                    // For each subtitle, init the Popcorn transcript plugin.
                    for (var i = 0; i < subtitles.length; i++) {
                        this.pop.amaratranscript({
                            start: subtitles[i].start,
                            start_clean: utils.parseFloatAndRound(subtitles[i].start),
                            start_of_paragraph: subtitles[i].start_of_paragraph,
                            end: subtitles[i].end,
                            text: subtitles[i].text,
                            container: this.$transcriptBody.get(0)
                        });
                    }
                } else {
                    $('.amara-transcript-line-right', this.$transcriptBody).text('No subtitles available.');
                }
            },

            // Make a call to the Amara API and retrieve a set of subtitles for a specific
            // video in a specific language. When we get a response, add the subtitle set
            // to the video model's 'subtitles' collection for later retrieval by language code.
            fetchSubtitles: function(language, callback) {
                var that = this;

                var apiURL = ''+
                    'https://staging.universalsubtitles.org/api2/partners/videos/' +
                    this.model.get('id') + '/languages/' + language + '/subtitles/';

                // Make a call to the Amara API to retrieve subtitles for this language.
                //
                // TODO: If we already have subtitles in this language, don't do anything.
                _$.ajax({
                    url: apiURL,
                    dataType: 'jsonp',
                    success: function(resp) {

                        // Save these subtitles to the video's 'subtitles' collection.
                        resp.language = language;
                        that.model.subtitles.add(
                            new SubtitleSet(resp)
                        );

                        // Call the callback.
                        callback(resp);
                    }
                });
            },
            shareButtonClicked: function() {
                return false;
            },
            toggleSubtitlesDisplay: function(e) {
                this.$popSubtitlesContainer.toggle();
                this.$subtitlesButton.toggleClass('amara-button-enabled');
                return false;
            },
            toggleTranscriptDisplay: function() {
                this.$transcript.toggle();
                this.$transcriptButton.toggleClass('amara-button-enabled');
                return false;
            },
            waitUntilVideoIsComplete: function(callback) {

                var that = this;

                // isComplete gets set as soon as the initial API call to build out the video
                // instance has finished.
                if (!this.model.get('isComplete')) {
                    setTimeout(function() { that.waitUntilVideoIsComplete(callback); }, 100);
                } else {
                    callback();
                }
            },

            templateHTML: '' +
                '
' +
                '
' +
                //'        ' +
                '        Amara' +
                '
' +
                '

' +
                '

' +
                '
' +
                '
' +
                '
' +
                '
' +
                //'
' +
                //'                Auto-stream OFF' +
                //'
' +
                //'
' +
                //'                <form action="" class="amara-transcript-search">' +
                //'                    <input class="amara-transcript-search-input" placeholder="Search transcript" />' +
                //'                </form>' +
                //'
' +
                '
' +
                '
' +
                '            ' +
                '                ' +
                '                    Loading transcript…' +
                '                ' +
                '            ' +
                '
' +
                '
' +
                '
',

            cacheNodes: function() {
                this.$amaraTools = $('div.amara-tools', this.$el);
                this.$transcript = $('div.amara-transcript', this.$amaraTools);
                this.$transcriptBody = $('div.amara-transcript-body', this.$transcript);
                this.$transcriptButton = $('a.amara-transcript-button', this.$amaraTools);
                this.$subtitlesButton = $('a.amara-subtitles-button', this.$amaraTools);
            }

        });

        // push() handles all action calls before and after the embedder is loaded.
        // Aside from init(), this is the only function that may be called from the
        // parent document.
        //
        // Must send push() an object with only two items:
        //     * Action  (string)
        //     * Options (object)
        //
        // Note: we don't use traditional function arguments because before the
        // embedder is loaded, _amara is just an array with a normal push() method.
        this.push = function(args) {

            // No arguments? Don't do anything.
            if (!arguments.length) { return; }

            // Must send push() an object with only two items.
            if (__.size(arguments[0]) === 2) {

                var action = args[0];
                var options = args[1];

                // If a method exists for this action, call it with the options.
                if (actions[action]) {
                    actions[action](options);
                }
            }

        };

        // init() gets called as soon as the embedder has finished loading.
        // Simply processes the existing _amara queue if we have one.
        this.init = function() {

            // Load the Amara CSS.
            var tag = document.getElementsByTagName('script')[0];
            var style = document.createElement('link');
            style.rel = 'stylesheet';
            style.type = 'text/css';

            // TODO: This needs to be a production URL based on DEBUG or not.
            style.href = '/site_media/css/embedder/amara.css';
            tag.parentNode.insertBefore(style, tag);

            // Change the template delimiter for Underscore templates.
            __.templateSettings = { interpolate : /\{\{(.+?)\}\}/g };

            // If we have a queue from before the embedder loaded, process the actions.
            if (toPush) {
                for (var i = 0; i < toPush.length; i++) {
                    that.push(toPush[i]);
                }
                toPush = [];
            }

            // Check to see if we have any amara-embed's to initilize.
            var amaraEmbeds = _$('div.amara-embed');

            if (amaraEmbeds.length) {
                amaraEmbeds.each(function() {

                    var $div = $(this);

                    // Call embedVideo with this div and URL.
                    that.push(['embedVideo', {
                        'div': this,
                        'initialLanguage': $div.data('initial-language'),
                        'url': $div.data('url')
                    }]);
                });
            }

        };

    };

    window._amara = new Amara();
    window._amara.init();

}(window, document));
<commit_msg>The camelCasing is getting annoying.<commit_after>(function(window, document, undefined) {

    // When the embedder is compiled, dependencies will be loaded directly before this
    // function. Set dependencies to use no-conflict mode to avoid destroying any
    // original objects.
    var __ = _.noConflict();
    var _$ = Zepto;
    var _Backbone = Backbone.noConflict();
    var _Popcorn = Popcorn.noConflict();

    // _amara may exist with a queue of actions that need to be processed after the
    // embedder has finally loaded. Store the queue in toPush for processing in init().
    var toPush = window._amara || [];

    var Amara = function(Amara) {

        // For reference in inner functions.
        var that = this;

        // This will store all future instances of Amara-powered videos.
        // I'm trying really hard here to not use the word "widget".
        this.amaraInstances = [];

        // Private methods that are called via the push() method.
        var actions = {

            // The core function for constructing an entire video with Amara subtitles from
            // just a video URL. This includes DOM creation for the video, etc.
            embedVideo: function(options) {

                // Make sure we have a URL to work with.
                // If we do, init a new Amara view.
                if (__.has(options, 'url') && __.has(options, 'div')) {

                    that.amaraInstances.push(
                        new that.AmaraView({

                            // TODO: This needs to support a node OR ID string.
                            el: _$(options.div)[0],
                            model: new VideoModel(options)
                        })
                    );
                }
            }
        };

        // Utilities.
        var utils = {
            parseFloatAndRound: function(val) {
                return (Math.round(parseFloat(val) * 100) / 100).toFixed(2);
            }
        };

        // Video model.
        var VideoModel = _Backbone.Model.extend({

            // The initialization of these vars is unnecessary, but it's nice to know
            // what vars will *eventually* be on the video model.

            // This var will be true once we've retrieved the rest of the model attrs
            // from the Amara API.
            is_complete: false,

            // Set from within the embedder.
            div: '',
            height: '',
            initial_language: null,
            is_on_amara: null,
            subtitles: [], // Backbone collection
            url: '',
            width: '',

            // Set from the Amara API
            all_urls: [],
            created: null,
            description: null,
            duration: null,
            id: null,
            languages: [],
            original_language: null,
            project: null,
            resource_uri: null,
            team: null,
            thumbnail: null,
            title: null,

            // Every time a video model is created, do this.
            initialize: function() {

                var video = this;
                var apiURL = 'https://staging.universalsubtitles.org/api2/partners/videos/?&video_url=';

                this.subtitles = new that.Subtitles();

                // Make a call to the Amara API to get attributes like available languages,
                // internal ID, description, etc.
                _$.ajax({
                    url: apiURL + this.get('url'),
                    dataType: 'jsonp',
                    success: function(resp) {

                        if (resp.objects.length) {

                            // The video exists on Amara.
                            video.set('is_on_amara', true);

                            // There should only be one object.
                            if (resp.objects.length === 1) {

                                // Set all of the API attrs as attrs on the video model.
                                video.set(resp.objects[0]);

                                // Set the initial language to either the one provided by the initial
                                // options, or the original language from the API.
                                video.set('initial_language',
                                    video.get('initial_language') ||
                                    video.get('original_language')
                                );
                            }

                        } else {

                            // The video does not exist on Amara.
                            video.set('is_on_amara', false);

                        }

                        // Mark that the video model has been completely populated.
                        video.set('is_complete', true);
                    }
                });
            }
        });

        // SubtitleSet model.
        var SubtitleSet = _Backbone.Model.extend({

            // Set from the Amara API
            description: null,
            language: null,
            note: null,
            resource_uri: null,
            site_url: null,
            sub_format: null,
            subtitles: [],
            title: null,
            version_no: null,
            video: null,
            video_description: null,
            video_title: null

        });

        // Subtitles collection.
        this.Subtitles = _Backbone.Collection.extend({
            model: SubtitleSet
        });

        // Amara view. This contains all of the events and logic for a single instance of
        // an Amara-powered video.
        this.AmaraView = _Backbone.View.extend({

            initialize: function() {
                this.model.view = this;
                this.template = __.template(this.templateHTML);
                this.render();
            },

            events: {
                'click a.amara-share-button':      'shareButtonClicked',
                'click a.amara-transcript-button': 'toggleTranscriptDisplay',
                'click a.amara-subtitles-button':  'toggleSubtitlesDisplay'
            },

            render: function() {

                var that = this;

                // Create a container that we will use to inject the Popcorn video.
                this.$el.prepend('

');

                this.$popContainer = $('div.amara-popcorn', this.$el);

                // Copy the width and height to the new Popcorn container.
                this.$popContainer.width(this.$el.width());
                this.$popContainer.height(this.$el.height());

                // This is a hack until Popcorn.js supports passing a DOM elem to
                // its smart() method. See: http://bit.ly/L0Lb7t
                var id = 'amara-popcorn-' + Math.floor(Math.random() * 100000000);
                this.$popContainer.attr('id', id);

                // Reset the height on the parent amara-embed div. If we don't do this,
                // our amara-tools div won't be visible.
                this.$el.height('auto');

                // Init the Popcorn video.
                this.pop = _Popcorn.smart(this.$popContainer.attr('id'), this.model.get('url'));

                this.pop.on('loadedmetadata', function() {

                    // Set the video model's height and width, now that we know it.
                    that.model.set('height', that.pop.position().height);
                    that.model.set('width', that.pop.position().width);

                    // Create the actual core DOM for the Amara container.
                    that.$el.append(that.template({
                        video_url: 'http://www.universalsubtitles.org/en/videos/' + that.model.get('id'),
                        width: that.model.get('width')
                    }));

                    // Just set some cached Zepto selections for later use.
                    that.cacheNodes();

                    // Wait until we have a complete video model (the API was hit as soon as
                    // the video instance was created), and then retrieve the initial set
                    // of subtitles, so we can begin building out the transcript viewer
                    // and the subtitle display.
                    //
                    // We could just make this a callback on the model's initialize() for
                    // after we get a response, but there may be cases where we want to init
                    // a VideoModel separately from an AmaraView.
                    that.waitUntilVideoIsComplete(
                        function() {

                            // Grab the subtitles for the initial language and do yo' thang.
                            if (that.model.get('is_on_amara')) {

                                // Make the request to fetch the initial subtitles.
                                that.fetchSubtitles(that.model.get('initial_language'), function() {

                                    // When we've got a response with the subtitles, start building
                                    // out the transcript viewer and subtitles.
                                    that.buildTranscript(that.model.get('initial_language'));
                                    that.buildSubtitles(that.model.get('initial_language'));
                                });
                            } else {
                                // Do some other stuff for videos that aren't yet on Amara.
                            }
                        }
                    );
                });

                return this;

            },

            buildSubtitles: function(language) {

                // Get the subtitle sets for this language.
                var subtitleSets = this.model.subtitles.where({'language': language});

                if (subtitleSets.length) {
                    var subtitleSet = subtitleSets[0];

                    // Get the actual subtitles for this language.
                    var subtitles = subtitleSet.get('subtitles');

                    // For each subtitle, init the Popcorn subtitle plugin.
                    for (var i = 0; i < subtitles.length; i++) {
                        this.pop.amarasubtitle({
                            start: subtitles[i].start,
                            end: subtitles[i].end,
                            text: subtitles[i].text
                        });
                    }

                    this.$popSubtitlesContainer = $('div.amara-popcorn-subtitles', this.$el);
                }
            },
            buildTranscript: function(language) {

                var subtitleSet;

                // Get the subtitle sets for this language.
                var subtitleSets = this.model.subtitles.where({'language': language});

                if (subtitleSets.length) {
                    subtitleSet = subtitleSets[0];
                } else {
                    $('.amara-transcript-line-right', this.$transcriptBody).text('No subtitles available.');
                }

                // Get the actual subtitles for this language.
                var subtitles = subtitleSet.get('subtitles');

                if (subtitles.length) {

                    // Remove the loading indicator.
                    this.$transcriptBody.html('');

                    // For each subtitle, init the Popcorn transcript plugin.
                    for (var i = 0; i < subtitles.length; i++) {
                        this.pop.amaratranscript({
                            start: subtitles[i].start,
                            start_clean: utils.parseFloatAndRound(subtitles[i].start),
                            start_of_paragraph: subtitles[i].start_of_paragraph,
                            end: subtitles[i].end,
                            text: subtitles[i].text,
                            container: this.$transcriptBody.get(0)
                        });
                    }
                } else {
                    $('.amara-transcript-line-right', this.$transcriptBody).text('No subtitles available.');
                }
            },

            // Make a call to the Amara API and retrieve a set of subtitles for a specific
            // video in a specific language. When we get a response, add the subtitle set
            // to the video model's 'subtitles' collection for later retrieval by language code.
            fetchSubtitles: function(language, callback) {
                var that = this;

                var apiURL = ''+
                    'https://staging.universalsubtitles.org/api2/partners/videos/' +
                    this.model.get('id') + '/languages/' + language + '/subtitles/';

                // Make a call to the Amara API to retrieve subtitles for this language.
                //
                // TODO: If we already have subtitles in this language, don't do anything.
                _$.ajax({
                    url: apiURL,
                    dataType: 'jsonp',
                    success: function(resp) {

                        // Save these subtitles to the video's 'subtitles' collection.
                        resp.language = language;
                        that.model.subtitles.add(
                            new SubtitleSet(resp)
                        );

                        // Call the callback.
                        callback(resp);
                    }
                });
            },
            shareButtonClicked: function() {
                return false;
            },
            toggleSubtitlesDisplay: function(e) {
                this.$popSubtitlesContainer.toggle();
                this.$subtitlesButton.toggleClass('amara-button-enabled');
                return false;
            },
            toggleTranscriptDisplay: function() {
                this.$transcript.toggle();
                this.$transcriptButton.toggleClass('amara-button-enabled');
                return false;
            },
            waitUntilVideoIsComplete: function(callback) {

                var that = this;

                // is_complete gets set as soon as the initial API call to build out the video
                // instance has finished.
                if (!this.model.get('is_complete')) {
                    setTimeout(function() { that.waitUntilVideoIsComplete(callback); }, 100);
                } else {
                    callback();
                }
            },

            templateHTML: '' +
                '
' +
                '
' +
                //'        ' +
                '        Amara' +
                '
' +
                '

' +
                '

' +
                '
' +
                '
' +
                '
' +
                '
' +
                //'
' +
                //'                Auto-stream OFF' +
                //'
' +
                //'
' +
                //'                <form action="" class="amara-transcript-search">' +
                //'                    <input class="amara-transcript-search-input" placeholder="Search transcript" />' +
                //'                </form>' +
                //'
' +
                '
' +
                '
' +
                '            ' +
                '                ' +
                '                    Loading transcript…' +
                '                ' +
                '            ' +
                '
' +
                '
' +
                '
',

            cacheNodes: function() {
                this.$amaraTools = $('div.amara-tools', this.$el);
                this.$transcript = $('div.amara-transcript', this.$amaraTools);
                this.$transcriptBody = $('div.amara-transcript-body', this.$transcript);
                this.$transcriptButton = $('a.amara-transcript-button', this.$amaraTools);
                this.$subtitlesButton = $('a.amara-subtitles-button', this.$amaraTools);
            }

        });

        // push() handles all action calls before and after the embedder is loaded.
        // Aside from init(), this is the only function that may be called from the
        // parent document.
        //
        // Must send push() an object with only two items:
        //     * Action  (string)
        //     * Options (object)
        //
        // Note: we don't use traditional function arguments because before the
        // embedder is loaded, _amara is just an array with a normal push() method.
        this.push = function(args) {

            // No arguments? Don't do anything.
            if (!arguments.length) { return; }

            // Must send push() an object with only two items.
            if (__.size(arguments[0]) === 2) {

                var action = args[0];
                var options = args[1];

                // If a method exists for this action, call it with the options.
                if (actions[action]) {
                    actions[action](options);
                }
            }

        };

        // init() gets called as soon as the embedder has finished loading.
        // Simply processes the existing _amara queue if we have one.
        this.init = function() {

            // Load the Amara CSS.
            var tag = document.getElementsByTagName('script')[0];
            var style = document.createElement('link');
            style.rel = 'stylesheet';
            style.type = 'text/css';

            // TODO: This needs to be a production URL based on DEBUG or not.
            style.href = '/site_media/css/embedder/amara.css';
            tag.parentNode.insertBefore(style, tag);

            // Change the template delimiter for Underscore templates.
            __.templateSettings = { interpolate : /\{\{(.+?)\}\}/g };

            // If we have a queue from before the embedder loaded, process the actions.
            if (toPush) {
                for (var i = 0; i < toPush.length; i++) {
                    that.push(toPush[i]);
                }
                toPush = [];
            }

            // Check to see if we have any amara-embed's to initilize.
            var amaraEmbeds = _$('div.amara-embed');

            if (amaraEmbeds.length) {
                amaraEmbeds.each(function() {

                    var $div = $(this);

                    // Call embedVideo with this div and URL.
                    that.push(['embedVideo', {
                        'div': this,
                        'initial_language': $div.data('initial-language'),
                        'url': $div.data('url')
                    }]);
                });
            }

        };

    };

    window._amara = new Amara();
    window._amara.init();

}(window, document));
<|endoftext|>