<commit_before>/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

module.exports = {
    'ios' : {
        parser : './src/metadata/ios_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-ios.git',
        version: '3.2.0-rc1'
    },
    'android' : {
        parser : './src/metadata/android_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git',
        version: '3.2.0-rc1'
    },
    'wp7' : {
        parser : './src/metadata/wp7_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-wp8.git',
        version: '3.2.0-rc1'
    },
    'wp8' : {
        parser : './src/metadata/wp8_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-wp8.git',
        version: '3.2.0-rc1'
    },
    'blackberry10' : {
        parser : './src/metadata/blackberry10_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-blackberry.git',
        version: '3.2.0-rc1'
    },
    'www':{
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-app-hello-world.git',
        version: '3.2.0-rc1'
    },
    'firefoxos':{
        parser: './src/metadata/firefoxos_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-firefoxos.git',
        version: '3.2.0-rc1'
    },
    'windows8':{
        parser: './src/metadata/windows8_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-windows.git',
        version: '3.2.0-rc1'
    }
};

var addModuleProperty = require('./src/util').addModuleProperty;
Object.keys(module.exports).forEach(function(key) {
    var obj = module.exports[key];
    if (obj.parser) {
        addModuleProperty(module, 'parser', obj.parser, false, obj);
    }
});
<commit_msg>Append subdirectory for concerned platforms<commit_after>/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

module.exports = {
    'ios' : {
        parser : './src/metadata/ios_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-ios.git',
        version: '3.2.0-rc1'
    },
    'android' : {
        parser : './src/metadata/android_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git',
        version: '3.2.0-rc1'
    },
    'wp7' : {
        parser : './src/metadata/wp7_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-wp8.git',
        version: '3.2.0-rc1',
        subdirectory: 'wp7'
    },
    'wp8' : {
        parser : './src/metadata/wp8_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-wp8.git',
        version: '3.2.0-rc1',
        subdirectory: 'wp8'
    },
    'blackberry10' : {
        parser : './src/metadata/blackberry10_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-blackberry.git',
        version: '3.2.0-rc1',
        subdirectory: 'blackberry10'
    },
    'www':{
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-app-hello-world.git',
        version: '3.2.0-rc1'
    },
    'firefoxos':{
        parser: './src/metadata/firefoxos_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-firefoxos.git',
        version: '3.2.0-rc1'
    },
    'windows8':{
        parser: './src/metadata/windows8_parser',
        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-windows.git',
        version: '3.2.0-rc1',
        subdirectory: 'windows8'
    }
};

var addModuleProperty = require('./src/util').addModuleProperty;
Object.keys(module.exports).forEach(function(key) {
    var obj = module.exports[key];
    if (obj.parser) {
        addModuleProperty(module, 'parser', obj.parser, false, obj);
    }
});
<|endoftext|>


<commit_before>angular.module('queup', [
  'queup.factory',
  'socket.io',
  'queup.auth',
  'queup.before',
  'queup.class_info',
  'queup.class_list',
  'queup.new_class',
  'queup.in_session',
  'queup.queue_list',
  'queup.student_list',
  'queup.class_settings',
  'ui.router'
])
.config(function($stateProvider, $urlRouterProvider){
  $stateProvider
    .state('signin', {
      url: '/signin',
      views: {
        'main': {
          templateUrl: 'auth/signin.html',
          controller: 'AuthController'
        }
      }
    })
    .state('q', {
      url:"/q",
      views: {
        'main': {
          templateUrl: "nav.html",
          controller: 'AuthController'
        }
      }
    })
    .state('q.before_session', {
      url: '/before_session',
      views: {
        'nav': {
          templateUrl: 'before_session/before_session.html',
          controller: 'Before_sessionController',
        }
      },
    })
    .state('q.before_session.class_info', {
      url: '/class_info',
      views: {
        'sub': {
          templateUrl: 'before_session/class_info.html',
          controller: 'Class_infoController',
        }
      },
    })
    .state('q.before_session.class_list', {
      url: '/class_list',
      views: {
        'sub': {
          templateUrl: 'before_session/class_list.html',
          controller: 'Class_listController'
        }
      },
    })
    .state('q.before_session.new_class', {
      url: '/new_class',
      views: {
        'sub': {
          templateUrl: 'before_session/new_class.html',
          controller: 'New_classController'
        }
      },
    })
    .state('q.in_session', {
      url: '/in_session',
      views: {
        'nav': {
          templateUrl: 'in_session/in_session.html',
          controller: 'In_sessionController'
        }
      },
    })
    .state('q.in_session.queue_list', {
      url: '/queue_list',
      views: {
        'sub': {
          templateUrl: 'in_session/queue_list.html',
          controller: 'Queue_listController'
        }
      },
    })
    .state('q.in_session.student_list', {
      url: '/student_list',
      views: {
        'sub': {
          templateUrl: 'in_session/student_list.html',
          controller: 'Student_listController'
        }
      },
    })
    .state('q.in_session.class_settings', {
      url: '/class_settings',
      views: {
        'sub': {
          templateUrl: 'in_session/class_settings.html',
          controller: 'Class_settingsController'
        }
      },
    })

  $urlRouterProvider.otherwise('/signin');
})
<commit_msg>add authenitcation checks to routes<commit_after>angular.module('queup', [
  'queup.factory',
  'socket.io',
  'queup.auth',
  'queup.before',
  'queup.class_info',
  'queup.class_list',
  'queup.new_class',
  'queup.in_session',
  'queup.queue_list',
  'queup.student_list',
  'queup.class_settings',
  'ui.router'
])
.config(function($stateProvider, $urlRouterProvider){

  var authenticate = function($q, auth, teacherData) {
    var deferred = $q.defer();
    if(auth.loggedIn) {
      deferred.resolve('Logged In');
      console.log('logged in')
    } else {
      deferred.reject('Not Logged In');
      console.log('not logged in')
    }
    return deferred.promise;
  };

  $stateProvider
    .state('signin', {
      url: '/signin',
      views: {
        'main': {
          templateUrl: 'auth/signin.html',
          controller: 'AuthController'
        }
      }
    })
    .state('q', {
      url:"/q",
      views: {
        'main': {
          templateUrl: "nav.html",
          controller: 'AuthController'
        }
      }
    })
    .state('q.before_session', {
      url: '/before_session',
      views: {
        'nav': {
          templateUrl: 'before_session/before_session.html',
          controller: 'Before_sessionController',
        }
      },
      resolve: {
        authenticate: authenticate
      }
    })
    .state('q.before_session.class_info', {
      url: '/class_info',
      views: {
        'sub': {
          templateUrl: 'before_session/class_info.html',
          controller: 'Class_infoController',
        }
      },
    })
    .state('q.before_session.class_list', {
      url: '/class_list',
      views: {
        'sub': {
          templateUrl: 'before_session/class_list.html',
          controller: 'Class_listController'
        }
      },
    })
    .state('q.before_session.new_class', {
      url: '/new_class',
      views: {
        'sub': {
          templateUrl: 'before_session/new_class.html',
          controller: 'New_classController'
        }
      },
    })
    .state('q.in_session', {
      url: '/in_session',
      views: {
        'nav': {
          templateUrl: 'in_session/in_session.html',
          controller: 'In_sessionController'
        }
      },
      resolve: {
        authenticate: authenticate
      }
    })
    .state('q.in_session.queue_list', {
      url: '/queue_list',
      views: {
        'sub': {
          templateUrl: 'in_session/queue_list.html',
          controller: 'Queue_listController'
        }
      },
    })
    .state('q.in_session.student_list', {
      url: '/student_list',
      views: {
        'sub': {
          templateUrl: 'in_session/student_list.html',
          controller: 'Student_listController'
        }
      },
    })
    .state('q.in_session.class_settings', {
      url: '/class_settings',
      views: {
        'sub': {
          templateUrl: 'in_session/class_settings.html',
          controller: 'Class_settingsController'
        }
      },
    })

  $urlRouterProvider.otherwise('/signin');
})
.run(function ($rootScope, $state) {
  $rootScope.$on('$stateChangeError', function () {
    // Redirect to login page
    $state.go('signin');
  });
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
 * ALL RIGHTS RESERVED.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
 * nor the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 *
 * This work has been performed in the framework of the SONATA project,
 * funded by the European Commission under Grant number 671517 through
 * the Horizon 2020 and 5G-PPP programmes. The authors would like to
 * acknowledge the contributions of their colleagues of the SONATA
 * partner consortium (www.sonata-nfv.eu).* dirPagination - AngularJS module for paginating (almost) anything.
 */

describe('SonataBSS Instantiates a Service', function() {

    var requestId;

    beforeEach(function() {
        browser.driver.manage().window().maximize();
        browser.get('https://'+browser.params.host+':'+browser.params.host+'/#/login');
        browser.driver.findElement(by.id('username')).sendKeys('sonata');
        browser.driver.findElement(by.id('password')).sendKeys('sonata');
        browser.driver.findElement(by.xpath('//button[. = "Login"]')).click();
        browser.driver.findElement(by.xpath("//a[@href='#/nSDs']")).click();
    });

    it('services list must not be empty', function() {
        var count = element.all(by.repeater('nSD in nSDs')).count();
        expect(count).toBeGreaterThan(0);
    });

    it('when clicked: "request service instantiation" instantiates a new service', function() {

        var EC = protractor.ExpectedConditions;

        var modal = element.all(by.css('[ng-click="openInstantiateNSD(nSD)"]')).get(0).click();
        browser.wait(EC.visibilityOf(modal), 5000);

        modal = element(by.id('instantiateNSD'));
        var yes = modal.element(by.css('.btn-success'));

        yes.click();
        browser.sleep(1500);

        modal = element(by.id('instantiateRequest'));
        expect(modal.isDisplayed()).toBe(true);

        modal.element(by.id('requestId')).getText().then(function(text) {
            requestId = text;
        });

    });

    it('instantiation request must be in the list', function() {

        browser.driver.findElement(by.xpath("//a[@href='#/requests']")).click();

        var query = element(by.model('RequestsSearch'));
        query.sendKeys(requestId);

        var data = element.all(by.repeater("Request in Requests"));

        expect(data.count()).toBe(1);

    });

	it('request must be ready after service instantiation process', function() {

		browser.driver.findElement(by.xpath("//a[@href='#/requests']")).click();

		var query = element(by.model('RequestsSearch'));
		query.sendKeys(requestId);

		var EC = protractor.ExpectedConditions;
		browser.wait(EC.textToBePresentInElement(element(by.repeater("Request in Requests").column('status')) ,'ready', 900000));

    });

});<commit_msg>int-service-instantiation<commit_after>/**
 * Copyright (c) 2015 SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
 * ALL RIGHTS RESERVED.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
 * nor the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 *
 * This work has been performed in the framework of the SONATA project,
 * funded by the European Commission under Grant number 671517 through
 * the Horizon 2020 and 5G-PPP programmes. The authors would like to
 * acknowledge the contributions of their colleagues of the SONATA
 * partner consortium (www.sonata-nfv.eu).* dirPagination - AngularJS module for paginating (almost) anything.
 */

describe('SonataBSS Instantiates a Service', function() {

    var requestId;

    beforeEach(function() {
        browser.driver.manage().window().maximize();
        browser.get('https://'+browser.params.host+':'+browser.params.port+'/#/login');
        browser.driver.findElement(by.id('username')).sendKeys('sonata');
        browser.driver.findElement(by.id('password')).sendKeys('sonata');
        browser.driver.findElement(by.xpath('//button[. = "Login"]')).click();
        browser.driver.findElement(by.xpath("//a[@href='#/nSDs']")).click();
    });

    it('services list must not be empty', function() {
        var count = element.all(by.repeater('nSD in nSDs')).count();
        expect(count).toBeGreaterThan(0);
    });

    it('when clicked: "request service instantiation" instantiates a new service', function() {

        var EC = protractor.ExpectedConditions;

        var modal = element.all(by.css('[ng-click="openInstantiateNSD(nSD)"]')).get(0).click();
        browser.wait(EC.visibilityOf(modal), 5000);

        modal = element(by.id('instantiateNSD'));
        var yes = modal.element(by.css('.btn-success'));

        yes.click();
        browser.sleep(1500);

        modal = element(by.id('instantiateRequest'));
        expect(modal.isDisplayed()).toBe(true);

        modal.element(by.id('requestId')).getText().then(function(text) {
            requestId = text;
        });

    });

    it('instantiation request must be in the list', function() {

        browser.driver.findElement(by.xpath("//a[@href='#/requests']")).click();

        var query = element(by.model('RequestsSearch'));
        query.sendKeys(requestId);

        var data = element.all(by.repeater("Request in Requests"));

        expect(data.count()).toBe(1);

    });

	it('request must be ready after service instantiation process', function() {

		browser.driver.findElement(by.xpath("//a[@href='#/requests']")).click();

		var query = element(by.model('RequestsSearch'));
		query.sendKeys(requestId);

		var EC = protractor.ExpectedConditions;
		browser.wait(EC.textToBePresentInElement(element(by.repeater("Request in Requests").column('status')) ,'ready', 900000));

    });

});<|endoftext|>


<commit_before>'use strict';

let React = require('react-native');
let ScrollableMixin = require('react-native-scrollable-mixin');
let {
  PropTypes,
  ScrollView,
  View,
} = React;

let cloneReferencedElement = require('react-native-clone-referenced-element');

let DefaultLoadingIndicator = require('./DefaultLoadingIndicator');

class InfiniteScrollView extends React.Component {
  static propTypes = {
    ...ScrollView.propTypes,
    distanceToLoadMore: PropTypes.number.isRequired,
    canLoadMore: PropTypes.bool.isRequired,
    isLoadingMore: PropTypes.bool.isRequired,
    onLoadError: PropTypes.func,
    onLoadMoreAsync: PropTypes.func.isRequired,
    renderLoadingIndicator: PropTypes.func.isRequired,
    renderLoadingErrorIndicator: PropTypes.func.isRequired,
  };

  static defaultProps = {
    distanceToLoadMore: 1500,
    canLoadMore: false,
    isLoadingMore: false,
    scrollEventThrottle: 16,
    renderLoadingIndicator: () => <DefaultLoadingIndicator />,
    renderLoadingErrorIndicator: () => <View />,
    renderScrollComponent: props => <ScrollView {...props} />,
  };

  constructor(props, context) {
    super(props, context);

    this.state = {
      isDisplayingError: false,
    };
  }

  getScrollResponder(): ReactComponent {
    return this._scrollComponent.getScrollResponder();
  }

  setNativeProps(nativeProps) {
    this._scrollComponent.setNativeProps(nativeProps);
  }

  render() {
    let statusIndicator;

    if (this.state.isDisplayingError) {
      statusIndicator = React.cloneElement(
        this.props.renderLoadingErrorIndicator(this._retryOnLoadMore.bind(this)),
        { key: 'loading-error-indicator' },
      );
    } else if (this.props.canLoadMore) {
      statusIndicator = React.cloneElement(
        this.props.renderLoadingIndicator(),
        { key: 'loading-indicator' },
      );
    }

    let {
      renderScrollComponent,
      ...props,
    } = this.props;
    Object.assign(props, {
      onScroll: this._handleScroll.bind(this),
      children: [this.props.children, statusIndicator],
    });

    return cloneReferencedElement(renderScrollComponent(props), {
      ref: component => { this._scrollComponent = component; },
    });
  }

  _handleScroll(event) {
    if (this.props.onScroll) {
      this.props.onScroll(event);
    }

    if (this.props.isLoadingMore || !this.props.canLoadMore) {
      return;
    }

    if (this._distanceFromEnd(event) < this.props.distanceToLoadMore) {
      this._onLoadMore();
    }
  }

  _onLoadMore() {
    this.props.onLoadMoreAsync().catch((error) => {
      this.props.onLoadError && this.props.onLoadError(error);
      this.setState({isDisplayingError: true});
    });
  }

  _retryOnLoadMore() {
    this.setState({isDisplayingError: false});
    this._onLoadMore();
  }

  _distanceFromEnd(event): number {
    let {
      contentSize,
      contentInset,
      contentOffset,
      layoutMeasurement,
    } = event.nativeEvent;

    if (this.props.horizontal) {
      var contentLength = contentSize.width;
      var trailingInset = contentInset.right;
      var scrollOffset = contentOffset.x;
      var viewportLength = layoutMeasurement.width;
    } else {
      contentLength = contentSize.height;
      trailingInset = contentInset.bottom;
      scrollOffset = contentOffset.y;
      viewportLength = layoutMeasurement.height;
    }

    return contentLength + trailingInset - scrollOffset - viewportLength;
  }
}

Object.assign(InfiniteScrollView.prototype, ScrollableMixin);

module.exports = InfiniteScrollView;
<commit_msg>Remove unnecessary parens, reset event throttle to 100<commit_after>'use strict';

let React = require('react-native');
let ScrollableMixin = require('react-native-scrollable-mixin');
let {
  PropTypes,
  ScrollView,
  View,
} = React;

let cloneReferencedElement = require('react-native-clone-referenced-element');

let DefaultLoadingIndicator = require('./DefaultLoadingIndicator');

class InfiniteScrollView extends React.Component {
  static propTypes = {
    ...ScrollView.propTypes,
    distanceToLoadMore: PropTypes.number.isRequired,
    canLoadMore: PropTypes.bool.isRequired,
    isLoadingMore: PropTypes.bool.isRequired,
    onLoadError: PropTypes.func,
    onLoadMoreAsync: PropTypes.func.isRequired,
    renderLoadingIndicator: PropTypes.func.isRequired,
    renderLoadingErrorIndicator: PropTypes.func.isRequired,
  };

  static defaultProps = {
    distanceToLoadMore: 1500,
    canLoadMore: false,
    isLoadingMore: false,
    scrollEventThrottle: 100,
    renderLoadingIndicator: () => <DefaultLoadingIndicator />,
    renderLoadingErrorIndicator: () => <View />,
    renderScrollComponent: props => <ScrollView {...props} />,
  };

  constructor(props, context) {
    super(props, context);

    this.state = {
      isDisplayingError: false,
    };
  }

  getScrollResponder(): ReactComponent {
    return this._scrollComponent.getScrollResponder();
  }

  setNativeProps(nativeProps) {
    this._scrollComponent.setNativeProps(nativeProps);
  }

  render() {
    let statusIndicator;

    if (this.state.isDisplayingError) {
      statusIndicator = React.cloneElement(
        this.props.renderLoadingErrorIndicator(this._retryOnLoadMore.bind(this)),
        { key: 'loading-error-indicator' },
      );
    } else if (this.props.canLoadMore) {
      statusIndicator = React.cloneElement(
        this.props.renderLoadingIndicator(),
        { key: 'loading-indicator' },
      );
    }

    let {
      renderScrollComponent,
      ...props,
    } = this.props;
    Object.assign(props, {
      onScroll: this._handleScroll.bind(this),
      children: [this.props.children, statusIndicator],
    });

    return cloneReferencedElement(renderScrollComponent(props), {
      ref: component => { this._scrollComponent = component; },
    });
  }

  _handleScroll(event) {
    if (this.props.onScroll) {
      this.props.onScroll(event);
    }

    if (this.props.isLoadingMore || !this.props.canLoadMore) {
      return;
    }

    if (this._distanceFromEnd(event) < this.props.distanceToLoadMore) {
      this._onLoadMore();
    }
  }

  _onLoadMore() {
    this.props.onLoadMoreAsync().catch(error => {
      this.props.onLoadError && this.props.onLoadError(error);
      this.setState({isDisplayingError: true});
    });
  }

  _retryOnLoadMore() {
    this.setState({isDisplayingError: false});
    this._onLoadMore();
  }

  _distanceFromEnd(event): number {
    let {
      contentSize,
      contentInset,
      contentOffset,
      layoutMeasurement,
    } = event.nativeEvent;

    if (this.props.horizontal) {
      var contentLength = contentSize.width;
      var trailingInset = contentInset.right;
      var scrollOffset = contentOffset.x;
      var viewportLength = layoutMeasurement.width;
    } else {
      contentLength = contentSize.height;
      trailingInset = contentInset.bottom;
      scrollOffset = contentOffset.y;
      viewportLength = layoutMeasurement.height;
    }

    return contentLength + trailingInset - scrollOffset - viewportLength;
  }
}

Object.assign(InfiniteScrollView.prototype, ScrollableMixin);

module.exports = InfiniteScrollView;
<|endoftext|>


<commit_before>OpenSpending = "OpenSpending" in window ? OpenSpending : {};

(function ($) {

OpenSpending.Treemap = function (elem, context, state) {
  var self = this;

  var resources = [OpenSpending.scriptRoot + "/lib/vendor/underscore.js",
                 OpenSpending.scriptRoot + "/lib/aggregator.js",
                 OpenSpending.scriptRoot + "/lib/utils/utils.js",
                 OpenSpending.scriptRoot + "/widgets/treemap/js/thejit-2.js",
                 OpenSpending.scriptRoot + "/widgets/treemap/css/treemap.css"
                 ];

  this.context = context;
  this.state = state;

  this.configure = function(endConfigure) {
    self.$qb.empty();
    var qb = new OpenSpending.Widgets.QueryBuilder(
      self.$qb, self.update, endConfigure, self.context, [
            {
              variable: 'drilldown',
              label: 'Tiles:',
              type: 'select',
              single: true,
              'default': self.state.drilldown,
              help: 'The sum for each member of this dimension will be presented as a tile on the treemap.'
            },
            {
              variable: 'cuts',
              label: 'Filters:',
              type: 'cuts',
              'default': self.state.cuts,
              help: 'Limit the set of data to display.'
            }
          ]
    );
  };

  this.update = function(state) {
    self.$e.empty();
    self.state = state;
    self.state.cuts = self.state.cuts || {};

    if (self.context.time) {
      self.state.cuts.year = self.context.time;
    }

    var cuts = [];
    for (var field in self.state.cuts) {
      cuts.push(field + ':' + self.state.cuts[field]);
    }

    if (typeof self.context.member !== 'undefined' && typeof self.context.dimension !== 'undefined') {
      cuts.push(self.context.dimension + ':' + self.context.member);
    }

    if (self.state.drilldown) {
      new OpenSpending.Aggregator({
        siteUrl: self.context.siteUrl,
        dataset: self.context.dataset,
        drilldowns: [self.state.drilldown],
        cuts: cuts,
        rootNodeLabel: 'Total',
        callback: function(data) {
          self.setDataFromAggregator(this.dataset, this.drilldowns[0], data);
          self.draw();
        }
      });
    }
  };

  this.serialize = function() {
    return self.state;
  };

  this.init = function () {
    self.$e = elem;
    self.$e.before('

');
    self.$qb = elem.prev();
    self.$e.addClass("treemap-widget");
    self.update(self.state);
  };

  this.setDataFromAggregator = function (dataset, dimension, data) {
    var needsColorization = true;
    self.total = data.amount;
    self.data = {children: _.map(data.children, function(item) {
      if (item.color)
        needsColorization = false;

      return {
        children: [],
        id: item.id,
        name: item.label || item.name,
        data: {
            value: item.amount,
            $area: item.amount,
            title: item.label || item.name,
            link: self.context.siteUrl + '/' + dataset + '/' + dimension + '/' + item.name,
            $color: item.color || '#333333'
          }
        };
    })};

    if (needsColorization) {
      this.autoColorize();
    }
  };

  this.autoColorize = function() {
    var nodes = self.data.children.length;
    var colors = OpenSpending.Utils.getColorPalette(nodes);
    for (var i = 0; i < nodes; i++) {
      self.data.children[i].data.$color = colors[i];
    }
  };

  this.draw = function () {
    if (!self.data.children.length) {
      $(self.$e).hide();
      return;
    }
    $(self.$e).show();
    self.tm = new $jit.TM.Squarified({
        injectInto: self.$e.prop('id'),
        levelsToShow: 1,
        titleHeight: 0,
        animate: true,

        offset: 2,
        Label: {
          type: 'HTML',
          size: 12,
          family: 'Tahoma, Verdana, Arial',
          color: '#DDE7F0'
          },
        Node: {
          color: '#243448',
          CanvasStyles: {
            shadowBlur: 0,
            shadowColor: '#000'
          }
        },
        Events: {
          enable: true,
          onClick: function(node) {
            if(node) {
                document.location.href = node.data.link;
            }
          },
          onRightClick: function() {
            self.tm.out();
          },
          onMouseEnter: function(node, eventInfo) {
            if(node) {
              node.setCanvasStyle('shadowBlur', 8);
              node.orig_color = node.getData('color');
              node.setData('color', '#A3B3C7');
              self.tm.fx.plotNode(node, self.tm.canvas);
              // tm.labels.plotLabel(tm.canvas, node);
            }
          },
          onMouseLeave: function(node) {
            if(node) {
              node.removeData('color');
              node.removeCanvasStyle('shadowBlur');
              node.setData('color', node.orig_color);
              self.tm.plot();
            }
          }
        },
        duration: 1000,
        Tips: {
          enable: true,
          type: 'Native',
          offsetX: 20,
          offsetY: 20,
          onShow: function(tip, node, isLeaf, domElement) {
            var html = '
' + node.name +
                ': ' + OpenSpending.Utils.formatAmount(node.data.value) +
                '

';
            var data = node.data;
            tip.innerHTML = html;
          }
        },
        //Implement this method for retrieving a requested
        //subtree that has as root a node with id = nodeId,
        //and level as depth. This method could also make a server-side
        //call for the requested subtree. When completed, the onComplete
        //callback method should be called.
        request: function(nodeId, level, onComplete){
          // var tree = eval('(' + json + ')');
          var tree = json;
          var subtree = $jit.json.getSubtree(tree, nodeId);
          $jit.json.prune(subtree, 1);
          onComplete.onComplete(nodeId, subtree);
        },
        //Add the name of the node in the corresponding label
        //This method is called once, on label creation and only for DOM labels.
        onCreateLabel: function(domElement, node){
          if ((node.data.value/self.total)>0.03) {
            domElement.innerHTML = "

" + OpenSpending.Utils.formatAmount(node.data.value) + "
" + node.name + "
";
          }
        }
    });
    self.tm.loadJSON(this.data);
    self.tm.refresh();
  };

  // The rest of this function is suitable for copypasta into other
  // plugins: load all scripts we need, and return a promise object
  // that will fire when the class is ready
  var dfd = $.Deferred();
  dfd.done(function(that) {that.init();});

  if (!window.treemapWidgetLoaded) {
    yepnope({
      load: resources,
      complete: function() {
        window.treemapWidgetLoaded = true;
        dfd.resolve(self);
      }
    });
  } else {
    dfd.resolve(self);
  }

  return dfd.promise();
};

})(jQuery);

<commit_msg>Load excanvas in MSIE. <commit_after>OpenSpending = "OpenSpending" in window ? OpenSpending : {};

(function ($) {

OpenSpending.Treemap = function (elem, context, state) {
  var self = this;

  var resources = [OpenSpending.scriptRoot + "/lib/vendor/underscore.js",
                 OpenSpending.scriptRoot + "/lib/aggregator.js",
                 OpenSpending.scriptRoot + "/lib/utils/utils.js",
                 OpenSpending.scriptRoot + "/widgets/treemap/js/thejit-2.js",
                 OpenSpending.scriptRoot + "/widgets/treemap/css/treemap.css"
                 ];

  if ($.browser.msie) {
    resources.push(OpenSpending.scriptRoot + "/widgets/treemap/js/excanvas.js");
  }

  this.context = context;
  this.state = state;

  this.configure = function(endConfigure) {
    self.$qb.empty();
    var qb = new OpenSpending.Widgets.QueryBuilder(
      self.$qb, self.update, endConfigure, self.context, [
            {
              variable: 'drilldown',
              label: 'Tiles:',
              type: 'select',
              single: true,
              'default': self.state.drilldown,
              help: 'The sum for each member of this dimension will be presented as a tile on the treemap.'
            },
            {
              variable: 'cuts',
              label: 'Filters:',
              type: 'cuts',
              'default': self.state.cuts,
              help: 'Limit the set of data to display.'
            }
          ]
    );
  };

  this.update = function(state) {
    self.$e.empty();
    self.state = state;
    self.state.cuts = self.state.cuts || {};

    if (self.context.time) {
      self.state.cuts.year = self.context.time;
    }

    var cuts = [];
    for (var field in self.state.cuts) {
      cuts.push(field + ':' + self.state.cuts[field]);
    }

    if (typeof self.context.member !== 'undefined' && typeof self.context.dimension !== 'undefined') {
      cuts.push(self.context.dimension + ':' + self.context.member);
    }

    if (self.state.drilldown) {
      new OpenSpending.Aggregator({
        siteUrl: self.context.siteUrl,
        dataset: self.context.dataset,
        drilldowns: [self.state.drilldown],
        cuts: cuts,
        rootNodeLabel: 'Total',
        callback: function(data) {
          self.setDataFromAggregator(this.dataset, this.drilldowns[0], data);
          self.draw();
        }
      });
    }
  };

  this.serialize = function() {
    return self.state;
  };

  this.init = function () {
    self.$e = elem;
    self.$e.before('

');
    self.$qb = elem.prev();
    self.$e.addClass("treemap-widget");
    self.update(self.state);
  };

  this.setDataFromAggregator = function (dataset, dimension, data) {
    var needsColorization = true;
    self.total = data.amount;
    self.data = {children: _.map(data.children, function(item) {
      if (item.color)
        needsColorization = false;

      return {
        children: [],
        id: item.id,
        name: item.label || item.name,
        data: {
            value: item.amount,
            $area: item.amount,
            title: item.label || item.name,
            link: self.context.siteUrl + '/' + dataset + '/' + dimension + '/' + item.name,
            $color: item.color || '#333333'
          }
        };
    })};

    if (needsColorization) {
      this.autoColorize();
    }
  };

  this.autoColorize = function() {
    var nodes = self.data.children.length;
    var colors = OpenSpending.Utils.getColorPalette(nodes);
    for (var i = 0; i < nodes; i++) {
      self.data.children[i].data.$color = colors[i];
    }
  };

  this.draw = function () {
    if (!self.data.children.length) {
      $(self.$e).hide();
      return;
    }
    $(self.$e).show();
    self.tm = new $jit.TM.Squarified({
        injectInto: self.$e.prop('id'),
        levelsToShow: 1,
        titleHeight: 0,
        animate: true,

        offset: 2,
        Label: {
          type: 'HTML',
          size: 12,
          family: 'Tahoma, Verdana, Arial',
          color: '#DDE7F0'
          },
        Node: {
          color: '#243448',
          CanvasStyles: {
            shadowBlur: 0,
            shadowColor: '#000'
          }
        },
        Events: {
          enable: true,
          onClick: function(node) {
            if(node) {
                document.location.href = node.data.link;
            }
          },
          onRightClick: function() {
            self.tm.out();
          },
          onMouseEnter: function(node, eventInfo) {
            if(node) {
              node.setCanvasStyle('shadowBlur', 8);
              node.orig_color = node.getData('color');
              node.setData('color', '#A3B3C7');
              self.tm.fx.plotNode(node, self.tm.canvas);
              // tm.labels.plotLabel(tm.canvas, node);
            }
          },
          onMouseLeave: function(node) {
            if(node) {
              node.removeData('color');
              node.removeCanvasStyle('shadowBlur');
              node.setData('color', node.orig_color);
              self.tm.plot();
            }
          }
        },
        duration: 1000,
        Tips: {
          enable: true,
          type: 'Native',
          offsetX: 20,
          offsetY: 20,
          onShow: function(tip, node, isLeaf, domElement) {
            var html = '
' + node.name +
                ': ' + OpenSpending.Utils.formatAmount(node.data.value) +
                '

';
            var data = node.data;
            tip.innerHTML = html;
          }
        },
        //Implement this method for retrieving a requested
        //subtree that has as root a node with id = nodeId,
        //and level as depth. This method could also make a server-side
        //call for the requested subtree. When completed, the onComplete
        //callback method should be called.
        request: function(nodeId, level, onComplete){
          // var tree = eval('(' + json + ')');
          var tree = json;
          var subtree = $jit.json.getSubtree(tree, nodeId);
          $jit.json.prune(subtree, 1);
          onComplete.onComplete(nodeId, subtree);
        },
        //Add the name of the node in the corresponding label
        //This method is called once, on label creation and only for DOM labels.
        onCreateLabel: function(domElement, node){
          if ((node.data.value/self.total)>0.03) {
            domElement.innerHTML = "

" + OpenSpending.Utils.formatAmount(node.data.value) + "
" + node.name + "
";
          }
        }
    });
    self.tm.loadJSON(this.data);
    self.tm.refresh();
  };

  // The rest of this function is suitable for copypasta into other
  // plugins: load all scripts we need, and return a promise object
  // that will fire when the class is ready
  var dfd = $.Deferred();
  dfd.done(function(that) {that.init();});

  if (!window.treemapWidgetLoaded) {
    yepnope({
      load: resources,
      complete: function() {
        window.treemapWidgetLoaded = true;
        dfd.resolve(self);
      }
    });
  } else {
    dfd.resolve(self);
  }

  return dfd.promise();
};

})(jQuery);

<|endoftext|>


<commit_before>function submitNewSlipwayDetails(data){
  var idKey = Date.now();
  var keyRoute = new Firebase('https://crackling-inferno-1794.firebaseio.com/'+ idKey);
  var nameInput              = document.getElementById('Name').value,
      longInput              = document.getElementById('Longitude').value,
      latInput               = document.getElementById('Latitude').value,
      websiteInput           = document.getElementById('Website').value,
      personInput            = document.getElementById('PersonName').value,
      phoneNumberInput       = document.getElementById('PhoneNumber').value,
      mobilePhoneInput       = document.getElementById('MobilePhoneNumber').value,
      emailInput             = document.getElementById('Email').value,
      rampDescInput          = document.getElementById('RampDescription').value,
      rampTypeInput          = document.getElementById('RampType').value,
      suitabilityInput       = document.getElementById('Suitability').value, // select
      rampLengthInput        = document.getElementById('RampLength').value, // select
      facilitiesInput        = document.getElementById('Facilities').value,
      navHazInput            = document.getElementById('NavigationalHazards').value,
      upperAreaMaterialInput = document.getElementById('UpperAreaMaterial').value, // select
      lowerAreaMaterialInput = document.getElementById('LowerAreaMaterial').value, //select
      chargesInput           = document.getElementById('Charges').value;

  keyRoute.set([
    idKey,
    nameInput,
    longInput,
    latInput,
            , // NearestPlace
            , // Country
            , // Region
    websiteInput,
    personInput,
    phoneNumberInput,
    mobilePhoneInput,
            , // Fax
    emailInput,
    rampDescInput,
            , // Directions
    rampTypeInput,
    upperAreaMaterialInput,
    lowerAreaMaterialInput,
    suitabilityInput,
    rampLengthInput,
    facilitiesInput,
    chargesInput,
                , // CruisingArea
    navHazInput,
                  // Images
  ]);
}
<commit_msg>console logging succeson adding to db #89<commit_after>function submitNewSlipwayDetails(data) {
    var idKey = Date.now();
    var keyRoute = new Firebase('https://crackling-inferno-1794.firebaseio.com/' + idKey);
    var nameInput = document.getElementById('Name').value,
        longInput = document.getElementById('Longitude').value,
        latInput = document.getElementById('Latitude').value,
        websiteInput = document.getElementById('Website').value,
        personInput = document.getElementById('PersonName').value,
        phoneNumberInput = document.getElementById('PhoneNumber').value,
        mobilePhoneInput = document.getElementById('MobilePhoneNumber').value,
        emailInput = document.getElementById('Email').value,
        rampDescInput = document.getElementById('RampDescription').value,
        rampTypeInput = document.getElementById('RampType').value,
        suitabilityInput = document.getElementById('Suitability').value, // select
        rampLengthInput = document.getElementById('RampLength').value, // select
        facilitiesInput = document.getElementById('Facilities').value,
        navHazInput = document.getElementById('NavigationalHazards').value,
        upperAreaMaterialInput = document.getElementById('UpperAreaMaterial').value, // select
        lowerAreaMaterialInput = document.getElementById('LowerAreaMaterial').value, //select
        chargesInput = document.getElementById('Charges').value;

    var onComplete = function(error) {
        if (error) {
            console.log('Synchronization failed');
        } else {
            console.log('Synchronization succeeded');
        }
    };

    keyRoute.set([
        idKey,
        nameInput,
        longInput,
        latInput,
        websiteInput,
        personInput,
        phoneNumberInput,
        mobilePhoneInput,
        // Fax
        emailInput,
        rampDescInput,
        // Directions
        rampTypeInput,
        upperAreaMaterialInput,
        lowerAreaMaterialInput,
        suitabilityInput,
        rampLengthInput,
        facilitiesInput,
        chargesInput,
        // CruisingArea
        navHazInput
        // Images
    ], onComplete);
}
<|endoftext|>


<commit_before>CT.admin.monitor = {
	"init": function() {
		CT.admin.core.init("monitor", function(loc) {
			CT.admin.monitor._graph = new CT.admin.monitor.Graph();
			document.body.appendChild(CT.admin.monitor._graph.content);
			CT.pubsub.set_cb("message", CT.admin.monitor._graph.update);
			CT.pubsub.subscribe("monitor");
			CT.pubsub.connect(loc.host, loc.port,
				"__admin__" + Math.floor(Math.random() * 1000) + btoa(CT.admin.core._pw));
		});
	}
};

CT.admin.monitor.Graph = CT.Class({
	CLASSNAME: "CT.admin.monitor.Graph",
	_graph: function() {
		var lines = this.lines;
		new Chartist.Line(".ct-chart", {
			series: Object.values(this.data)
		}, { low: 0, high: 100 });
		setTimeout(function() {
			CT.dom.className("ct-line").forEach(function(n, i) {
				lines[i].style.background
					= window.getComputedStyle(n).getPropertyValue("stroke");
			});
		});
	},
	update: function(data) {
		var key, d, fresh = !Object.keys(this.data).length;
		for (key in data.message) {
			if (!(key in this.data))
				this.data[key] = [];
			d = data.message[key];
			if (["read", "write"].indexOf(key) != -1)
				d /= 10000;
			else if (["sent", "recv"].indexOf(key) != -1)
				d /= 100000000;
			this.data[key].push(d);
		}
		CT.dom.clear(this.content);
		if (fresh) {
			this.lines = Object.keys(this.data).map(function(k) {
				if (["read", "write"].indexOf(k) != -1)
					k += " (times 10,000)";
				else if (["sent", "recv"].indexOf(k) != -1)
					k += " (times 100,000,000)";
				return CT.dom.div(k, "big m5 padded inline-block")
			});
			CT.dom.addContent("legend", this.lines);
		}
		this._graph();
	},
	init: function() {
		this.data = {};
		this.content = CT.dom.div(null, "ct-chart ct-perfect-fourth");
	}
});<commit_msg>admin monitor: enabled autohistory<commit_after>CT.admin.monitor = {
	"init": function() {
		CT.admin.core.init("monitor", function(loc) {
			CT.admin.monitor._graph = new CT.admin.monitor.Graph();
			document.body.appendChild(CT.admin.monitor._graph.content);
			CT.pubsub.set_autohistory(true);
			CT.pubsub.set_cb("message", CT.admin.monitor._graph.update);
			CT.pubsub.subscribe("monitor");
			CT.pubsub.connect(loc.host, loc.port,
				"__admin__" + Math.floor(Math.random() * 1000) + btoa(CT.admin.core._pw));
		});
	}
};

CT.admin.monitor.Graph = CT.Class({
	CLASSNAME: "CT.admin.monitor.Graph",
	_graph: function() {
		var lines = this.lines;
		new Chartist.Line(".ct-chart", {
			series: Object.values(this.data)
		}, { low: 0, high: 100 });
		setTimeout(function() {
			CT.dom.className("ct-line").forEach(function(n, i) {
				lines[i].style.background
					= window.getComputedStyle(n).getPropertyValue("stroke");
			});
		});
	},
	update: function(data) {
		var key, d, fresh = !Object.keys(this.data).length;
		for (key in data.message) {
			if (!(key in this.data))
				this.data[key] = [];
			d = data.message[key];
			if (["read", "write"].indexOf(key) != -1)
				d /= 10000;
			else if (["sent", "recv"].indexOf(key) != -1)
				d /= 100000000;
			this.data[key].push(d);
		}
		CT.dom.clear(this.content);
		if (fresh) {
			this.lines = Object.keys(this.data).map(function(k) {
				if (["read", "write"].indexOf(k) != -1)
					k += " (times 10,000)";
				else if (["sent", "recv"].indexOf(k) != -1)
					k += " (times 100,000,000)";
				return CT.dom.div(k, "big m5 padded inline-block")
			});
			CT.dom.addContent("legend", this.lines);
		}
		this._graph();
	},
	init: function() {
		this.data = {};
		this.content = CT.dom.div(null, "ct-chart ct-perfect-fourth");
	}
});<|endoftext|>


<commit_before>var path = require("path");
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var Clean = require("clean-webpack-plugin");

// BASE APP DIR
var root_dir = path.resolve(__dirname, "..");

// FUNCTION TO EXTRACT CSS FOR PRODUCTION
function extractForProduction(loaders) {
  return ExtractTextPlugin.extract("style", loaders.substr(loaders.indexOf("!")));
}

module.exports = function(options) {
    console.log(options.prod ? "Using PRODUCTION options\n" : "Using DEV options\n");
    // STYLE LOADERS
    var cssLoaders = "style-loader!css-loader",
      scssLoaders = "style!css!autoprefixer!sass?outputStyle=expanded";

    // DIRECTORY CLEANER
    var cleanDirectories = ["dist"];

    // OUTPUT PATH
    var outputPath = path.join(root_dir, "assets");

    // COMMON PLUGINS
    var plugins = [
        new webpack.optimize.DedupePlugin(),
        new Clean(cleanDirectories)
    ];

    if (options.prod) {
        // WRAP INTO CSS FILE
        cssLoaders = extractForProduction(cssLoaders);
        scssLoaders = extractForProduction(scssLoaders);

        // PROD PLUGINS
        plugins.push(new webpack.PrefetchPlugin("react"));
        plugins.push(new ExtractTextPlugin("app.css"));
        plugins.push(new webpack.optimize.UglifyJsPlugin({warnings: false, minimize: true, sourceMap: false}));
        plugins.push(new webpack.optimize.CommonsChunkPlugin("vendors", "vendors.js"));
        // PROD OUTPUT PATH
        outputPath = path.join(root_dir, "dist");
    } else {
        plugins.push(new webpack.HotModuleReplacementPlugin());
    }

    var config = {
        entry: {
            app: options.prod ?
                path.resolve(root_dir, "app/Main.js") :
                [
                    "webpack-dev-server/client?http://localhost:8080",
                    "webpack/hot/only-dev-server",
                    path.resolve(root_dir, "app/Main-dev.js")
                ]
        },
        output: {
            path: outputPath,
            filename: "app.js"
        },
        devtool: "#inline-source-map",
        debug: options.prod ? false : true,
        module: {
            loaders: [
                {
                    test: /\.jsx$/,
                    include: [path.join(root_dir, "app"), path.join(root_dir, "node_modules/react-foundation-apps")],
                    loaders: options.prod ? ["babel-loader"] : ["react-hot", "babel-loader"]
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: "babel-loader",
                    query: {compact: false}
                },
                { test: /\.json/, loader: "json" },
                { test: /\.coffee$/, loader: "coffee-loader" },
                { test: /\.(coffee\.md|litcoffee)$/, loader: "coffee-loader?literate" },
                { test: /\.css$/, loader: cssLoaders },
                {
                    test: /\.scss$/,
                    //loader: "style!css!sass?outputStyle=expanded&includePaths[]=" + (path.resolve(root_dir, "./node_modules"))
                    loader: scssLoaders
                },
                { test: /\.woff$/, loader: "url-loader?limit=100000&mimetype=application/font-woff" },
                { test: /.*\.svg$/, loaders: ["svg-inline-loader", "svgo-loader"] },
                { test: /\.md/, loader: 'html!remarkable' }
            ]
        },
        resolve: {
            //alias: {lzma: path.resolve(root_dir, "./node_modules/lzma/src/lzma.js")},
            root: [path.resolve(root_dir, "./app"), path.resolve(root_dir, "../dl/src")],
            extensions: ["", ".js", ".jsx", ".coffee", ".json"],
            modulesDirectories: ["node_modules", "bower_components", path.resolve(root_dir, "../dl/lib")],
            fallback: [path.resolve(root_dir, "./node_modules")]
        },
        resolveLoader: {
            root: path.join(root_dir, "node_modules"),
            fallback: [path.resolve(root_dir, "./node_modules")]
        },
        plugins: plugins,
        root: outputPath,
        remarkable: {
            preset: "full",
            typographer: true
        }
    };

    if(options.prod) config.entry.vendors = [
        "react", "react-highcharts/stocks.js", "classnames", "react-router", "counterpart", "react-translate-component",
        "perfect-scrollbar", "jdenticon", "react-notification-system", "react-tooltip",
        "whatwg-fetch", "alt", "react-json-inspector",
        "immutable", "lzma", "bytebuffer_3.5.4.js", "lodash"
    ];

    return config;

}
<commit_msg>don't remove html attrs when minimizing help files #327<commit_after>var path = require("path");
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var Clean = require("clean-webpack-plugin");

// BASE APP DIR
var root_dir = path.resolve(__dirname, "..");

// FUNCTION TO EXTRACT CSS FOR PRODUCTION
function extractForProduction(loaders) {
  return ExtractTextPlugin.extract("style", loaders.substr(loaders.indexOf("!")));
}

module.exports = function(options) {
    console.log(options.prod ? "Using PRODUCTION options\n" : "Using DEV options\n");
    // STYLE LOADERS
    var cssLoaders = "style-loader!css-loader",
      scssLoaders = "style!css!autoprefixer!sass?outputStyle=expanded";

    // DIRECTORY CLEANER
    var cleanDirectories = ["dist"];

    // OUTPUT PATH
    var outputPath = path.join(root_dir, "assets");

    // COMMON PLUGINS
    var plugins = [
        new webpack.optimize.DedupePlugin(),
        new Clean(cleanDirectories)
    ];

    if (options.prod) {
        // WRAP INTO CSS FILE
        cssLoaders = extractForProduction(cssLoaders);
        scssLoaders = extractForProduction(scssLoaders);

        // PROD PLUGINS
        plugins.push(new webpack.PrefetchPlugin("react"));
        plugins.push(new ExtractTextPlugin("app.css"));
        plugins.push(new webpack.optimize.UglifyJsPlugin({warnings: false, minimize: true, sourceMap: false, compress: true, output: {screw_ie8: true}}));
        plugins.push(new webpack.optimize.CommonsChunkPlugin("vendors", "vendors.js"));
        // PROD OUTPUT PATH
        outputPath = path.join(root_dir, "dist");
    } else {
        plugins.push(new webpack.HotModuleReplacementPlugin());
    }

    var config = {
        entry: {
            app: options.prod ?
                path.resolve(root_dir, "app/Main.js") :
                [
                    "webpack-dev-server/client?http://localhost:8080",
                    "webpack/hot/only-dev-server",
                    path.resolve(root_dir, "app/Main-dev.js")
                ]
        },
        output: {
            path: outputPath,
            filename: "app.js"
        },
        devtool: "#inline-source-map",
        debug: options.prod ? false : true,
        module: {
            loaders: [
                {
                    test: /\.jsx$/,
                    include: [path.join(root_dir, "app"), path.join(root_dir, "node_modules/react-foundation-apps")],
                    loaders: options.prod ? ["babel-loader"] : ["react-hot", "babel-loader"]
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: "babel-loader",
                    query: {compact: false}
                },
                { test: /\.json/, loader: "json" },
                { test: /\.coffee$/, loader: "coffee-loader" },
                { test: /\.(coffee\.md|litcoffee)$/, loader: "coffee-loader?literate" },
                { test: /\.css$/, loader: cssLoaders },
                {
                    test: /\.scss$/,
                    //loader: "style!css!sass?outputStyle=expanded&includePaths[]=" + (path.resolve(root_dir, "./node_modules"))
                    loader: scssLoaders
                },
                { test: /\.woff$/, loader: "url-loader?limit=100000&mimetype=application/font-woff" },
                { test: /.*\.svg$/, loaders: ["svg-inline-loader", "svgo-loader"] },
                { test: /\.md/, loader: 'html?removeAttributeQuotes=false!remarkable' }
            ]
        },
        resolve: {
            //alias: {lzma: path.resolve(root_dir, "./node_modules/lzma/src/lzma.js")},
            root: [path.resolve(root_dir, "./app"), path.resolve(root_dir, "../dl/src")],
            extensions: ["", ".js", ".jsx", ".coffee", ".json"],
            modulesDirectories: ["node_modules", "bower_components", path.resolve(root_dir, "../dl/lib")],
            fallback: [path.resolve(root_dir, "./node_modules")]
        },
        resolveLoader: {
            root: path.join(root_dir, "node_modules"),
            fallback: [path.resolve(root_dir, "./node_modules")]
        },
        plugins: plugins,
        root: outputPath,
        remarkable: {
            preset: "full",
            typographer: true
        }
    };

    if(options.prod) config.entry.vendors = [
        "react", "react-highcharts/stocks.js", "classnames", "react-router", "counterpart", "react-translate-component",
        "perfect-scrollbar", "jdenticon", "react-notification-system", "react-tooltip",
        "whatwg-fetch", "alt", "react-json-inspector",
        "immutable", "lzma", "bytebuffer_3.5.4.js", "lodash"
    ];

    return config;

}
<|endoftext|>


<commit_before>/**
 * The Timeline view module.
 *
 * Timeline for all layers configured by setting layer-specific options.
 *
 * @return Timeline view (extends Backbone.View).
 */
define([
  'underscore',
  'backbone',
  'moment',
  'd3',
  'handlebars',
  'text!templates/timelineYear.handlebars'
], function(_, Backbone, moment, d3, Handlebars, tpl) {

  'use strict';

  var TimelineYearClass = Backbone.View.extend({

    className: 'timeline-year',
    template: Handlebars.compile(tpl),

    defaults: {
      dateRange: [moment([2001]), moment()],
      playSpeed: 400,
      width: 750,
      height: 50
    },

    events: {
      'click .play': 'togglePlay'
    },

    initialize: function(layer, currentDate) {
      _.bindAll(this, 'onAnimationBrush', 'onBrush', 'onBrushEnd', 'updateCurrentDate');
      this.layer = layer;
      this.name = layer.slug;
      this.options = _.extend({}, this.defaults, this.options || {});
      if (currentDate && currentDate[0]) {
        this.currentDate = currentDate;
      } else {
        this.updateCurrentDate(this.options.dateRange);
      }

      // Status
      this.playing = false;

      // d3 slider objets
      this.svg = {};
      this.xscale = {};
      this.brush = {};
      this.slider = {};
      this.handlers = {
        left:{},
        right:{}
      };

      /**
       * Current extent position.
       * We use this because we need where the extent is going to be,
       * we can't get the values from the handlers because they
       * have animation.
       */
      this.ext = {
        left: 0,
        right: 0
      };

      this.render();
    },

    /**
     * Render d3 timeline slider.
     */
    render: function() {
      var self = this;
      this.$timeline = $('.timeline-container');
      this.$el.html(this.template());
      this.$timeline.append(this.el);

      // Cache
      this.$play = this.$el.find('.play');
      this.$playIcon = this.$el.find('.play-icon');
      this.$stopIcon = this.$el.find('.stop-icon');
      this.$time = this.$el.find('.time');

      // SVG options
      var margin = {top: 0, right: 20, bottom: 0, left: 20};
      var width = this.options.width - margin.left - margin.right;
      var height = this.options.height - margin.bottom - margin.top;

      // Set xscale
      this.xscale = d3.scale.linear()
          .domain([this.options.dateRange[0].year(), this.options.dateRange[1].year()])
          .range([0, width])
          .clamp(true);

      this.ext.left = this.xscale(this.currentDate[0].year());
      this.ext.right = this.xscale(this.currentDate[1].year());

      // Set brush and listeners
      this.brush = d3.svg.brush()
          .x(this.xscale)
          .extent([0, 0])
          .on('brush', function() {
            self.onBrush(this);
          })
          .on('brushend', function() {
            self.onBrushEnd(this);
          });

      // Set SVG
      var timelineWidth = width + margin.left + margin.right;
      this.svg = d3.select(this.$time[0]).append('svg')
          .attr('width', timelineWidth)
          .attr('height', height + margin.top + margin.bottom)
          .style('width', timelineWidth + 'px')
        .append('g')
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      // Dots xaxis
      this.svg.append('g')
          .attr('class', 'xaxis')
          .attr('transform', 'translate(0,{0})'.format(height/2 - 2))
          .call(d3.svg.axis()
            .scale(this.xscale)
            .orient('top')
            .ticks(this.options.dateRange[1].year() - this.options.dateRange[0].year())
            .tickFormat(function() {
              return '▪';
            })
            .tickSize(0)
            .tickPadding(0))
          .select('.domain').remove();

      // // xAxis
      // this.svg.append('g')
      //     .attr('class', 'xaxis')
      //     .attr('transform', 'translate(0, ' + (height / 2) + ')')
      //     .call(d3.svg.axis()
      //       .scale(this.xscale)
      //       .orient('top')
      //       .ticks(this.options.dateRange[1].year() - this.options.dateRange[0].year())
      //       .tickFormat(function(d) {return String(d); })
      //       .tickSize(0)
      //       .tickPadding(-4))
      //   .select('.domain').remove();

      this.svg.select('.xaxis').selectAll('g.line').remove();

      // Years xaxis
      var xAxis = d3.svg.axis()
          .scale(this.xscale)
          .orient('bottom')
          .ticks(this.options.dateRange[1].year() - this.options.dateRange[0].year())
          .tickSize(0)
          .tickPadding(0)
          .tickFormat(function(d) {return String(d); })

      this.svg.append('g')
          .attr('class', 'xaxis-years')
          .attr('transform', 'translate({0},{1})'.format(0, height/2 + 6))
          .call(xAxis)
        .select('.domain').remove();

      // this.svg.select('.xaxis').selectAll('g.tick')
      //   .insert('rect', ':first-child')
      //   .attr('width', 30)
      //   .attr('height', 12)
      //   .attr('x', -15)
      //   .attr('y', -5)
      //   .attr('fill', 'white');

      // Handlers
      this.slider = this.svg.append('g')
          .attr('class', 'slider')
          .call(this.brush);

      this.handlers.left = this.slider.append('svg:image')
          .attr('class', 'handle')
          .attr('width', 16)
          .attr('height', 16)
          .attr('xlink:href', '/assets/svg/dragger2.svg')
          .attr('x', this.xscale(this.currentDate[0].year()))
          .attr('y', -3);

      this.handlers.right = this.handlers.left
         .select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
         .attr('x', this.xscale(this.currentDate[1].year()));

      this.slider.select('.background')
          .style('cursor', 'pointer')
          .attr('height', height);

      // Tipsy
      this.tipsy = this.svg.append('g')
        .attr('class', 'tipsy')
        .style('visibility', 'hidden');

      this.trail = this.tipsy.append('svg:line')
        .attr('class', 'trail')
        .attr('x1', this.handlers.right.attr('x'))
        .attr('x2', this.handlers.right.attr('x'))
        .attr('y1', 0)
        .attr('y2', height);

      this.tooltip = d3.select(this.$time[0]).append('div')
        .attr('class', 'tooltip')
        .style('visibility', 'hidden')
        .style('left', this.handlers.right.attr('x') + 'px')
        .text(this.options.dateRange[0].year()-1);

      // Hidden brush for the animation
      this.hiddenBrush = d3.svg.brush()
          .x(this.xscale)
          .extent([0, 0])
          .on('brush', function() {
            self.onAnimationBrush(this);
          })
          .on('brushend', function() {
            self.onAnimationBrushEnd(this);
          });

      this.svg.selectAll('.extent,.resize')
          .remove();

      this.domain = this.svg.select('.xaxis')
        .insert('svg:line', ':first-child')
        .attr('class', 'domain')
        .attr('x1', this.handlers.left.attr('x'))
        .attr('x2', this.handlers.right.attr('x'));

      this.formatXaxis();
    },

    /**
     * Event fired when user clicks play/stop button.
     */
    togglePlay: function() {
      (this.playing) ? this.stopAnimation() : this.animate();
    },

    stopAnimation: function() {
      if (!this.playing) {return;}
      // End animation extent hiddenBrush
      // this will call onAnimationBrushEnd
      this.trail
        .call(this.hiddenBrush.event)
        .interrupt();
    },

    /**
     * Play the timeline by extending hiddenBrush with d3 animation.
     */
    animate: function() {
      this.presenter.startPlaying();
      var hlx = this.handlers.left.attr('x');
      var hrx = this.handlers.right.attr('x');
      var trailFrom = Math.round(this.xscale.invert(hlx)) + 1; // +1 year left handler
      var trailTo = Math.round(this.xscale.invert(hrx));

      if (trailTo === trailFrom) {
        return;
      }

      var speed = (trailTo - trailFrom) * this.options.playSpeed;

      this.togglePlayIcon();
      this.playing = true;
      this.yearsArr = []; // clean years

      this.showTipsy();
      this.hiddenBrush.extent([trailFrom, trailFrom]);

      // Animate extent hiddenBrush to trailTo
      this.trail
          .call(this.hiddenBrush.event)
        .transition()
          .duration(speed)
          .ease('line')
          .call(this.hiddenBrush.extent([trailFrom, trailTo]))
          .call(this.hiddenBrush.event);
    },

    /**
     * Event fired when timeline is being played.
     * Updates handlers positions and timeline date when reach a year.
     */
    onAnimationBrush: function() {
      var value = this.hiddenBrush.extent()[1];
      var roundValue = Math.round(value); // current year

      // yearsArr keep track of the years already loaded.
      // reason to do this is that value is never an
      // absolute value so we don't know when the trail
      // is in the right position.
      if (this.yearsArr.indexOf(roundValue) < 0 &&
        roundValue > 0) {

        // Move domain right
        this.domain
          .attr('x2', this.xscale(roundValue));

        // Move trail
        this.trail
          .attr('x1', this.xscale(roundValue))
          .attr('x2', this.xscale(roundValue));

        // Move && update tooltip
        this.tooltip
          .text(roundValue)
          .style('left', this.xscale(roundValue) + 'px');

        this.formatXaxis();

        // Update timeline
        var startYear = Math.round(this.xscale.invert(this.handlers.left.attr('x')));
        this.updateCurrentDate([moment([startYear]), moment([roundValue])]);

        this.yearsArr.push(roundValue);
      }
    },

    onAnimationBrushEnd: function (){
      var value = this.hiddenBrush.extent()[1];
      var hrl = this.ext.left;
      var trailFrom = Math.round(this.xscale.invert(hrl)) + 1; // +1 year left handler

      if (value > 0 && value !==  trailFrom) {
        this.presenter.stopPlaying();
        this.togglePlayIcon();
        this.playing = false;
      }
    },

    /**
     * Event fired when user click anywhere on the timeline
     * and keep pressing.
     * Updates just handlers positions.
     */
    onBrush: function(event) {
      var value = this.xscale.invert(d3.mouse(event)[0]);
      var roundValue = Math.round(value);

      var xl = this.handlers.left.attr('x');
      var xr = this.handlers.right.attr('x');

      this.hideTipsy();

      if (this.playing) {
        this.stopAnimation();
      }

      if (Math.abs(this.xscale(value) - xr) <
        Math.abs(this.xscale(value) - xl)) {
        if (this.ext.left > this.xscale(roundValue)) {
          return;
        }
        this.ext.right = this.xscale(roundValue);

        this.domain
          .attr('x1', this.ext.left);

        // Move right handler
        this.handlers.right
          .transition()
          .duration(100)
          .ease('line')
          .attr('x', this.xscale(roundValue));

        // Move domain right
        this.domain
          .transition()
          .duration(100)
          .ease('line')
          .attr('x2', this.xscale(roundValue));

      } else {
        if (this.ext.right < this.xscale(roundValue)) {
          return;
        }
        this.ext.left = this.xscale(roundValue);

        this.domain
          .attr('x2', this.ext.right);

        // Move left handler
        this.handlers.left
          .transition()
          .duration(100)
          .ease('line')
          .attr('x', this.xscale(roundValue));

        // Move domain left
        this.domain
          .transition()
          .duration(100)
          .ease('line')
          .attr('x1', this.xscale(roundValue));
      }

      this.formatXaxis();
    },

    formatXaxis: function() {
      var self = this;
      d3.select('.xaxis').selectAll('text').filter(function(d) {
        var left = self.ext.left;
        var right = self.ext.right;
        if (d >= Math.round(self.xscale.invert(left)) && d <= Math.round(self.xscale.invert(right))) {
          d3.select(this).classed('selected', true);
        } else {
          d3.select(this).classed('selected', false);
        }
      });
      d3.select('.xaxis-years').selectAll('text').filter(function(d) {
        var left = self.ext.left;
        var right = self.ext.right;
        if (d >= Math.round(self.xscale.invert(left)) && d <= Math.round(self.xscale.invert(right))) {
          d3.select(this).classed('selected', true);
        } else {
          d3.select(this).classed('selected', false);
        }
      });
    },

    /**
     * Event fired when user ends the click.
     * Update the timeline date. (calls updateCurrentDate)
     */
    onBrushEnd: function() {

      // give time to finish animations.
      setTimeout(function() {
        var startYear = Math.floor(this.xscale.invert(this.handlers.left.attr('x')));
        var endYear = Math.ceil(this.xscale.invert(this.handlers.right.attr('x')));

        this.updateCurrentDate([moment([startYear]), moment([endYear])]);
      }.bind(this), 100);
    },

    /**
     * Handles a timeline date change UI event by dispaching
     * to TimelinePresenter.
     *
     * @param {Array} timelineDate 2D array of moment dates [begin, end]
     */
    updateCurrentDate: function(date) {
      this.currentDate = date;
      this.presenter.updateTimelineDate(date);
    },

    togglePlayIcon: function() {
      this.$playIcon.toggle();
      this.$stopIcon.toggle();
    },

    showTipsy: function() {
      this.tipsy.style('visibility', 'visible');
      this.tooltip.style('visibility', 'visible');
    },

    hideTipsy: function() {
      this.tipsy.style('visibility', 'hidden');
      this.tooltip.style('visibility', 'hidden');
    },

    getName: function() {
      return this.name;
    },

    getCurrentDate: function() {
      return this.currentDate;
    }
  });

  return TimelineYearClass;

});
<commit_msg>HOTFIX: timeline 2006.99999999998 issue (ay dame veneno que quiero morir)<commit_after>/**
 * The Timeline view module.
 *
 * Timeline for all layers configured by setting layer-specific options.
 *
 * @return Timeline view (extends Backbone.View).
 */
define([
  'underscore',
  'backbone',
  'moment',
  'd3',
  'handlebars',
  'text!templates/timelineYear.handlebars'
], function(_, Backbone, moment, d3, Handlebars, tpl) {

  'use strict';

  var TimelineYearClass = Backbone.View.extend({

    className: 'timeline-year',
    template: Handlebars.compile(tpl),

    defaults: {
      dateRange: [moment([2001]), moment()],
      playSpeed: 400,
      width: 750,
      height: 50
    },

    events: {
      'click .play': 'togglePlay'
    },

    initialize: function(layer, currentDate) {
      _.bindAll(this, 'onAnimationBrush', 'onBrush', 'onBrushEnd', 'updateCurrentDate');
      this.layer = layer;
      this.name = layer.slug;
      this.options = _.extend({}, this.defaults, this.options || {});
      if (currentDate && currentDate[0]) {
        this.currentDate = currentDate;
      } else {
        this.updateCurrentDate(this.options.dateRange);
      }

      // Status
      this.playing = false;

      // d3 slider objets
      this.svg = {};
      this.xscale = {};
      this.brush = {};
      this.slider = {};
      this.handlers = {
        left:{},
        right:{}
      };

      /**
       * Current extent position.
       * We use this because we need where the extent is going to be,
       * we can't get the values from the handlers because they
       * have animation.
       */
      this.ext = {
        left: 0,
        right: 0
      };

      this.render();
    },

    /**
     * Render d3 timeline slider.
     */
    render: function() {
      var self = this;
      this.$timeline = $('.timeline-container');
      this.$el.html(this.template());
      this.$timeline.append(this.el);

      // Cache
      this.$play = this.$el.find('.play');
      this.$playIcon = this.$el.find('.play-icon');
      this.$stopIcon = this.$el.find('.stop-icon');
      this.$time = this.$el.find('.time');

      // SVG options
      var margin = {top: 0, right: 20, bottom: 0, left: 20};
      var width = this.options.width - margin.left - margin.right;
      var height = this.options.height - margin.bottom - margin.top;

      // Set xscale
      this.xscale = d3.scale.linear()
          .domain([this.options.dateRange[0].year(), this.options.dateRange[1].year()])
          .range([0, width])
          .clamp(true);

      this.ext.left = this.xscale(this.currentDate[0].year());
      this.ext.right = this.xscale(this.currentDate[1].year());

      // Set brush and listeners
      this.brush = d3.svg.brush()
          .x(this.xscale)
          .extent([0, 0])
          .on('brush', function() {
            self.onBrush(this);
          })
          .on('brushend', function() {
            self.onBrushEnd(this);
          });

      // Set SVG
      var timelineWidth = width + margin.left + margin.right;
      this.svg = d3.select(this.$time[0]).append('svg')
          .attr('width', timelineWidth)
          .attr('height', height + margin.top + margin.bottom)
          .style('width', timelineWidth + 'px')
        .append('g')
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      // Dots xaxis
      this.svg.append('g')
          .attr('class', 'xaxis')
          .attr('transform', 'translate(0,{0})'.format(height/2 - 2))
          .call(d3.svg.axis()
            .scale(this.xscale)
            .orient('top')
            .ticks(this.options.dateRange[1].year() - this.options.dateRange[0].year())
            .tickFormat(function() {
              return '▪';
            })
            .tickSize(0)
            .tickPadding(0))
          .select('.domain').remove();

      // // xAxis
      // this.svg.append('g')
      //     .attr('class', 'xaxis')
      //     .attr('transform', 'translate(0, ' + (height / 2) + ')')
      //     .call(d3.svg.axis()
      //       .scale(this.xscale)
      //       .orient('top')
      //       .ticks(this.options.dateRange[1].year() - this.options.dateRange[0].year())
      //       .tickFormat(function(d) {return String(d); })
      //       .tickSize(0)
      //       .tickPadding(-4))
      //   .select('.domain').remove();

      this.svg.select('.xaxis').selectAll('g.line').remove();

      // Years xaxis
      var xAxis = d3.svg.axis()
          .scale(this.xscale)
          .orient('bottom')
          .ticks(this.options.dateRange[1].year() - this.options.dateRange[0].year())
          .tickSize(0)
          .tickPadding(0)
          .tickFormat(function(d) {return String(d); })

      this.svg.append('g')
          .attr('class', 'xaxis-years')
          .attr('transform', 'translate({0},{1})'.format(0, height/2 + 6))
          .call(xAxis)
        .select('.domain').remove();

      // this.svg.select('.xaxis').selectAll('g.tick')
      //   .insert('rect', ':first-child')
      //   .attr('width', 30)
      //   .attr('height', 12)
      //   .attr('x', -15)
      //   .attr('y', -5)
      //   .attr('fill', 'white');

      // Handlers
      this.slider = this.svg.append('g')
          .attr('class', 'slider')
          .call(this.brush);

      this.handlers.left = this.slider.append('svg:image')
          .attr('class', 'handle')
          .attr('width', 16)
          .attr('height', 16)
          .attr('xlink:href', '/assets/svg/dragger2.svg')
          .attr('x', this.xscale(this.currentDate[0].year()))
          .attr('y', -3);

      this.handlers.right = this.handlers.left
         .select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
         .attr('x', this.xscale(this.currentDate[1].year()));

      this.slider.select('.background')
          .style('cursor', 'pointer')
          .attr('height', height);

      // Tipsy
      this.tipsy = this.svg.append('g')
        .attr('class', 'tipsy')
        .style('visibility', 'hidden');

      this.trail = this.tipsy.append('svg:line')
        .attr('class', 'trail')
        .attr('x1', this.handlers.right.attr('x'))
        .attr('x2', this.handlers.right.attr('x'))
        .attr('y1', 0)
        .attr('y2', height);

      this.tooltip = d3.select(this.$time[0]).append('div')
        .attr('class', 'tooltip')
        .style('visibility', 'hidden')
        .style('left', this.handlers.right.attr('x') + 'px')
        .text(this.options.dateRange[0].year()-1);

      // Hidden brush for the animation
      this.hiddenBrush = d3.svg.brush()
          .x(this.xscale)
          .extent([0, 0])
          .on('brush', function() {
            self.onAnimationBrush(this);
          })
          .on('brushend', function() {
            self.onAnimationBrushEnd(this);
          });

      this.svg.selectAll('.extent,.resize')
          .remove();

      this.domain = this.svg.select('.xaxis')
        .insert('svg:line', ':first-child')
        .attr('class', 'domain')
        .attr('x1', this.handlers.left.attr('x'))
        .attr('x2', this.handlers.right.attr('x'));

      this.formatXaxis();
    },

    /**
     * Event fired when user clicks play/stop button.
     */
    togglePlay: function() {
      (this.playing) ? this.stopAnimation() : this.animate();
    },

    stopAnimation: function() {
      if (!this.playing) {return;}
      // End animation extent hiddenBrush
      // this will call onAnimationBrushEnd
      this.trail
        .call(this.hiddenBrush.event)
        .interrupt();
    },

    /**
     * Play the timeline by extending hiddenBrush with d3 animation.
     */
    animate: function() {
      this.presenter.startPlaying();
      var hlx = this.handlers.left.attr('x');
      var hrx = this.handlers.right.attr('x');
      var trailFrom = Math.round(this.xscale.invert(hlx)) + 1; // +1 year left handler
      var trailTo = Math.round(this.xscale.invert(hrx));

      if (trailTo === trailFrom) {
        return;
      }

      var speed = (trailTo - trailFrom) * this.options.playSpeed;

      this.togglePlayIcon();
      this.playing = true;
      this.yearsArr = []; // clean years

      this.showTipsy();
      this.hiddenBrush.extent([trailFrom, trailFrom]);

      // Animate extent hiddenBrush to trailTo
      this.trail
          .call(this.hiddenBrush.event)
        .transition()
          .duration(speed)
          .ease('line')
          .call(this.hiddenBrush.extent([trailFrom, trailTo]))
          .call(this.hiddenBrush.event);
    },

    /**
     * Event fired when timeline is being played.
     * Updates handlers positions and timeline date when reach a year.
     */
    onAnimationBrush: function() {
      var value = this.hiddenBrush.extent()[1];
      var roundValue = Math.round(value); // current year

      // yearsArr keep track of the years already loaded.
      // reason to do this is that value is never an
      // absolute value so we don't know when the trail
      // is in the right position.
      if (this.yearsArr.indexOf(roundValue) < 0 &&
        roundValue > 0) {

        // Move domain right
        this.domain
          .attr('x2', this.xscale(roundValue));

        // Move trail
        this.trail
          .attr('x1', this.xscale(roundValue))
          .attr('x2', this.xscale(roundValue));

        // Move && update tooltip
        this.tooltip
          .text(roundValue)
          .style('left', this.xscale(roundValue) + 'px');

        this.formatXaxis();

        // Update timeline
        var startYear = Math.round(this.xscale.invert(this.handlers.left.attr('x')));
        this.updateCurrentDate([moment([startYear]), moment([roundValue])]);

        this.yearsArr.push(roundValue);
      }
    },

    onAnimationBrushEnd: function (){
      var value = this.hiddenBrush.extent()[1];
      var hrl = this.ext.left;
      var trailFrom = Math.round(this.xscale.invert(hrl)) + 1; // +1 year left handler

      if (value > 0 && value !==  trailFrom) {
        this.presenter.stopPlaying();
        this.togglePlayIcon();
        this.playing = false;
      }
    },

    /**
     * Event fired when user click anywhere on the timeline
     * and keep pressing.
     * Updates just handlers positions.
     */
    onBrush: function(event) {
      var value = this.xscale.invert(d3.mouse(event)[0]);
      var roundValue = Math.round(value);

      var xl = this.handlers.left.attr('x');
      var xr = this.handlers.right.attr('x');

      this.hideTipsy();

      if (this.playing) {
        this.stopAnimation();
      }

      if (Math.abs(this.xscale(value) - xr) <
        Math.abs(this.xscale(value) - xl)) {
        if (this.ext.left > this.xscale(roundValue)) {
          return;
        }
        this.ext.right = this.xscale(roundValue);

        this.domain
          .attr('x1', this.ext.left);

        // Move right handler
        this.handlers.right
          .transition()
          .duration(100)
          .ease('line')
          .attr('x', this.xscale(roundValue));

        // Move domain right
        this.domain
          .transition()
          .duration(100)
          .ease('line')
          .attr('x2', this.xscale(roundValue));

      } else {
        if (this.ext.right < this.xscale(roundValue)) {
          return;
        }
        this.ext.left = this.xscale(roundValue);

        this.domain
          .attr('x2', this.ext.right);

        // Move left handler
        this.handlers.left
          .transition()
          .duration(100)
          .ease('line')
          .attr('x', this.xscale(roundValue));

        // Move domain left
        this.domain
          .transition()
          .duration(100)
          .ease('line')
          .attr('x1', this.xscale(roundValue));
      }

      this.formatXaxis();
    },

    formatXaxis: function() {
      var self = this;
      d3.select('.xaxis').selectAll('text').filter(function(d) {
        var left = self.ext.left;
        var right = self.ext.right;
        if (d >= Math.round(self.xscale.invert(left)) && d <= Math.round(self.xscale.invert(right))) {
          d3.select(this).classed('selected', true);
        } else {
          d3.select(this).classed('selected', false);
        }
      });
      d3.select('.xaxis-years').selectAll('text').filter(function(d) {
        var left = self.ext.left;
        var right = self.ext.right;
        if (d >= Math.round(self.xscale.invert(left)) && d <= Math.round(self.xscale.invert(right))) {
          d3.select(this).classed('selected', true);
        } else {
          d3.select(this).classed('selected', false);
        }
      });
    },

    /**
     * Event fired when user ends the click.
     * Update the timeline date. (calls updateCurrentDate)
     */
    onBrushEnd: function() {

      // give time to finish animations.
      setTimeout(function() {
        var startYear = Math.round(this.xscale.invert(this.handlers.left.attr('x')));
        var endYear = Math.ceil(this.xscale.invert(this.handlers.right.attr('x')));

        this.updateCurrentDate([moment([startYear]), moment([endYear])]);
      }.bind(this), 100);
    },

    /**
     * Handles a timeline date change UI event by dispaching
     * to TimelinePresenter.
     *
     * @param {Array} timelineDate 2D array of moment dates [begin, end]
     */
    updateCurrentDate: function(date) {
      this.currentDate = date;
      this.presenter.updateTimelineDate(date);
    },

    togglePlayIcon: function() {
      this.$playIcon.toggle();
      this.$stopIcon.toggle();
    },

    showTipsy: function() {
      this.tipsy.style('visibility', 'visible');
      this.tooltip.style('visibility', 'visible');
    },

    hideTipsy: function() {
      this.tipsy.style('visibility', 'hidden');
      this.tooltip.style('visibility', 'hidden');
    },

    getName: function() {
      return this.name;
    },

    getCurrentDate: function() {
      return this.currentDate;
    }
  });

  return TimelineYearClass;

});
<|endoftext|>


<commit_before>/*
    Framework for building object relational database apps
    Copyright (C) 2021  John Rogelstad

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/*jslint node*/
(function (exports) {
    "use strict";

    const {Database} = require("../database");
    const db = new Database();

    function getSortedModules(client) {
        return new Promise(function (resolve, reject) {
            let sql = (
                "SELECT name, version, script, " +
                "to_json(dependencies) AS dependencies " +
                "FROM _module;"
            );

            function callback(resp) {
                let modules = resp.rows;

                function resolveDependencies(module, tree) {
                    tree = tree || module.tree;

                    module.tree.forEach(function (dependency) {
                        let parent = modules.find(
                            (module) => module.name === dependency
                        );

                        parent.tree.forEach(
                            (pDepencency) => tree.push(pDepencency)
                        );

                        resolveDependencies(parent, tree);
                    });
                }

                // Simplify dependencies
                modules.forEach(function (module) {
                    module.dependencies = module.dependencies.map(
                        (dep) => dep.module.name
                    );
                    module.tree = module.dependencies.slice();
                });

                // Process modules, start by resolving,
                // then sorting on dependencies
                modules.forEach((module) => resolveDependencies(module));

                // Sort
                modules = (function () {
                    let module;
                    let idx;
                    let ret = [];

                    function top(mod) {
                        return mod.tree.every(
                            (dep) => ret.some((added) => added.name === dep)
                        );
                    }

                    while (modules.length) {
                        module = modules.find(top);

                        ret.push(module);
                        idx = modules.indexOf(module);
                        modules.splice(idx, 1);
                    }

                    return ret;
                }());

                resolve(modules);
            }

            client.query(sql).then(callback).catch(reject);
        });
    }

    /**
        Custom data service scripts loaded from the database at run time.
        @class Services
        @constructor
        @namespace Services
    */
    exports.Services = function () {
        // ..........................................................
        // PUBLIC
        //

        let that = {};

        /**
            Fetch all service scripts from the database and resolve in promise.
            @method getServices
            @param {Object} payload Request payload
            @param {Client} payload.client Database client
            @return {Promise}
        */
        that.getServices = function (obj) {
            return new Promise(function (resolve, reject) {
                let client = db.getClient(obj.client);
                let sql = (
                    "SELECT name, module, script " +
                    "FROM data_service WHERE NOT is_deleted;"
                );

                function callback(res) {
                    let srvc = res[0].rows;
                    let mods = res[1].map((mod) => mod.name);
                    let ret = [];

                    mods.forEach(function (mod) {
                        srvc.forEach(function (srv) {
                            if (mod === srv.module) {
                                ret.push(srv);
                            }
                        });
                    });

                    resolve(ret);
                }

                Promise.all([
                    client.query(sql),
                    getSortedModules(client)
                ]).then(callback).catch(reject);
            });
        };

        return that;
    };

}(exports));

<commit_msg>Update services.js<commit_after>/*
    Framework for building object relational database apps
    Copyright (C) 2021  John Rogelstad

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/*jslint node*/
(function (exports) {
    "use strict";

    const {Database} = require("../database");
    const db = new Database();

    function getSortedModules(client) {
        return new Promise(function (resolve, reject) {
            let sql = (
                "SELECT name, version, script, " +
                "to_json(dependencies) AS dependencies " +
                "FROM _module WHERE NOT is_deleted;"
            );

            function callback(resp) {
                let modules = resp.rows;

                function resolveDependencies(module, tree) {
                    tree = tree || module.tree;

                    module.tree.forEach(function (dependency) {
                        let parent = modules.find(
                            (module) => module.name === dependency
                        );

                        parent.tree.forEach(
                            (pDepencency) => tree.push(pDepencency)
                        );

                        resolveDependencies(parent, tree);
                    });
                }

                // Simplify dependencies
                modules.forEach(function (module) {
                    module.dependencies = module.dependencies.map(
                        (dep) => dep.module.name
                    );
                    module.tree = module.dependencies.slice();
                });

                // Process modules, start by resolving,
                // then sorting on dependencies
                modules.forEach((module) => resolveDependencies(module));

                // Sort
                modules = (function () {
                    let module;
                    let idx;
                    let ret = [];

                    function top(mod) {
                        return mod.tree.every(
                            (dep) => ret.some((added) => added.name === dep)
                        );
                    }

                    while (modules.length) {
                        module = modules.find(top);

                        ret.push(module);
                        idx = modules.indexOf(module);
                        modules.splice(idx, 1);
                    }

                    return ret;
                }());

                resolve(modules);
            }

            client.query(sql).then(callback).catch(reject);
        });
    }

    /**
        Custom data service scripts loaded from the database at run time.
        @class Services
        @constructor
        @namespace Services
    */
    exports.Services = function () {
        // ..........................................................
        // PUBLIC
        //

        let that = {};

        /**
            Fetch all service scripts from the database and resolve in promise.
            @method getServices
            @param {Object} payload Request payload
            @param {Client} payload.client Database client
            @return {Promise}
        */
        that.getServices = function (obj) {
            return new Promise(function (resolve, reject) {
                let client = db.getClient(obj.client);
                let sql = (
                    "SELECT name, module, script " +
                    "FROM data_service WHERE NOT is_deleted;"
                );

                function callback(res) {
                    let srvc = res[0].rows;
                    let mods = res[1].map((mod) => mod.name);
                    let ret = [];

                    mods.forEach(function (mod) {
                        srvc.forEach(function (srv) {
                            if (mod === srv.module) {
                                ret.push(srv);
                            }
                        });
                    });

                    resolve(ret);
                }

                Promise.all([
                    client.query(sql),
                    getSortedModules(client)
                ]).then(callback).catch(reject);
            });
        };

        return that;
    };

}(exports));

<|endoftext|>


<commit_before>'use strict';

angular.module('impactApp', [
    'ngCookies',
    'ngResource',
    'ngSanitize',
    'ui.router',
    'ui.bootstrap',
    'ngStorage',
    'ngAnimate',
    'ngFileUpload',
    'ngMessages',
    'chart.js',
    'ui.tree',
    'toastr',
    'ui.mask'
  ])
  .config(function($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider, $urlMatcherFactoryProvider, $modalProvider, toastrConfig, treeConfig) {
    moment.locale('fr');
    $urlRouterProvider.otherwise('/');
    $locationProvider.html5Mode(true);
    $httpProvider.interceptors.push('authInterceptor');
    $urlMatcherFactoryProvider.strictMode(false);
    $modalProvider.options.animation = false;
    angular.extend(toastrConfig, {
      progressBar: true,
      positionClass: 'toast-top-right'
    });
    treeConfig.dragClass = 'angular-ui-tree-drag';
  })
  .factory('authInterceptor', function($rootScope, $q, $cookies) {
    return {
      // Add authorization token to headers
      request: function(config) {
        config.headers = config.headers || {};
        if ($cookies.get('token') && !config.ignoreInterceptor) {
          config.headers.Authorization = 'Bearer ' + $cookies.get('token');
        }

        return config;
      },

      // Intercept 401s
      responseError: function(response) {
        switch (response.status) {
          case 401:
            $rootScope.$broadcast('event:auth-loginRequired', response);
            break;
          case 403:
            $rootScope.$broadcast('event:auth-forbidden', response);
            break;
        }

        return $q.reject(response);
      }
    };
  })
  .run(function($rootScope, $state, $window, $location, Auth, $cookies) {
    $rootScope.$on('$stateChangeSuccess', function() {
      if ($window._paq) {
        $window._paq.push(['setCustomUrl', $location.path()]);
        $window._paq.push(['trackPageView']);
      }
    });

    $rootScope.$on('event:auth-loginRequired', function() {
      $cookies.remove('token');
      $state.go('login');
    });

    $rootScope.$on('event:auth-forbidden', function() {
      // TODO: specific state for auth-forbidden
      $state.go('login');
    });

    $rootScope.$on('$stateChangeStart', function(event, toState, toStateParams) {
      if (toState.data && toState.data.title) {
        $rootScope.title = toState.data.title + ' - Votre MDPH en ligne';
      } else {
        $rootScope.title = 'Votre MDPH en ligne';
      }

      $rootScope.returnToState = toState;
      $rootScope.returnToStateParams = toStateParams;
    });
  });
<commit_msg>Rework<commit_after>'use strict';

angular.module('impactApp', [
    'ngCookies',
    'ngResource',
    'ngSanitize',
    'ui.router',
    'ui.bootstrap',
    'ngStorage',
    'ngAnimate',
    'ngFileUpload',
    'ngMessages',
    'chart.js',
    'ui.tree',
    'toastr',
    'ui.mask'
  ])
  .config(function($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider, $urlMatcherFactoryProvider, $modalProvider, toastrConfig, treeConfig) {
    moment.locale('fr');
    $urlRouterProvider.otherwise('/');
    $locationProvider.html5Mode(true);
    $httpProvider.interceptors.push('authInterceptor');
    $urlMatcherFactoryProvider.strictMode(false);
    $modalProvider.options.animation = false;
    angular.extend(toastrConfig, {
      progressBar: true,
      positionClass: 'toast-top-right'
    });
    treeConfig.dragClass = 'angular-ui-tree-drag';
  })
  .factory('authInterceptor', function($rootScope, $q, $cookies) {
    return {
      // Add authorization token to headers
      request: function(config) {
        config.headers = config.headers || {};
        if ($cookies.get('token') && !config.ignoreInterceptor) {
          config.headers.Authorization = 'Bearer ' + $cookies.get('token');
        }

        return config;
      },

      // Intercept 401s
      responseError: function(response) {
        switch (response.status) {
          case 401:
            $rootScope.$broadcast('event:auth-loginRequired', response);
            break;
          case 403:
            $rootScope.$broadcast('event:auth-forbidden', response);
            break;
        }

        return $q.reject(response);
      }
    };
  })
  .run(function($rootScope, $state, $window, $location, Auth, $cookies) {
    $rootScope.$on('$stateChangeSuccess', function() {
      if ($window._paq) {
        $window._paq.push(['setCustomUrl', $location.path()]);
        $window._paq.push(['trackPageView']);
      }
    });

    $rootScope.$on('event:auth-loginRequired', function() {
      $cookies.remove('token');
      $state.go('login');
    });

    $rootScope.$on('event:auth-forbidden', function() {
      // TODO: specific state for auth-forbidden
      $state.go('login');
    });

    $rootScope.$on('$stateChangeStart', function(event, toState) {
      if (toState.data && toState.data.title) {
        $rootScope.title = toState.data.title + ' - Votre MDPH en ligne';
      } else {
        $rootScope.title = 'Votre MDPH en ligne';
      }
    });
  });
<|endoftext|>