<commit_before>/**
 * angular-adaptive-googlemaps v0.1.0
 * The MIT License
 * Copyright (c) 2013 Jan Antala
 */

(function (google) {
  'use strict';

  var adaptive = angular.module('adaptive.googlemaps', []);

  adaptive.controller('GoogleMapsCtrl', function ($scope, $element, $attrs, $parse) {
      var STATIC_URL = '//maps.googleapis.com/maps/api/staticmap?';
      var STYLE_ATTRIBUTES = ['color', 'label', 'size'];
      var that = this;

      this.makeMarkerStrings = function makeMarkerStrings(markers) {
        return markers.map(function (marker) {
          var str = Object.keys(marker).map(function (key) {
            if (STYLE_ATTRIBUTES.indexOf(key) > -1) {
              return key + ':' + marker[key] + '|';
            }
          }).join('');

          return str + marker.coords.join(',');
        });
      };

      this.buildSourceString = function buildSourceString(attrs, markers) {
        var markerStrings;

        if (markers) {
          if (!angular.isArray(markers)) {
            markers = [markers];
          }
          markerStrings = this.makeMarkerStrings(markers);
        }

        var params = Object.keys(attrs).map(function (attr) {
          if (attr === 'markers' && markerStrings) {
            return Object.keys(markerStrings).map(function (key) {
              return 'markers=' + encodeURIComponent(markerStrings[key]);
            }).join('&');
          }

          if (attr[0] !== '$' && attr !== 'alt') {
            return encodeURIComponent(attr) + '=' + encodeURIComponent(attrs[attr]);
          }
        });

        return STATIC_URL + params.reduce(function (a, b) {
          if (!a) {
            return b;
          }

          if (b !== undefined) {
            return a + '&' + b;
          }

          return a;
        }, '');
      };

      this.loadMap = function($element, center, zoom, markers) {
        var mapOptions = {
          center: new google.maps.LatLng(0, 0),
          zoom: (Number(zoom) || 8),
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var map = new google.maps.Map($element[0], mapOptions);
        var geocoder = new google.maps.Geocoder();
        geocoder.geocode( { 'address': center}, function(results, status) {
          if (status === google.maps.GeocoderStatus.OK) {
            map.setCenter(results[0].geometry.location);

            for (var i = 0; i < markers.length; i++) {
              var marker = new google.maps.Marker({
                position: new google.maps.LatLng(markers[i].coords[0], markers[i].coords[1]),
                title: markers[i].title,
                map: map,
                draggable: false,
                animation: google.maps.Animation.DROP
              });
            }
          }
          else {
            console.error('Geocode was not successful for the following reason: ' + status);
          }
        });
      };

      this.setStyle = function(style){
        console.log(style);
        $scope.style = style;
      };

      $scope.getHref = function() {
        return 'http://maps.apple.com/?center=' + $attrs.center + '&z=' + $attrs.zoom;
      };
    });

    adaptive.directive('googlemaps', function ($parse) {
      return {
        template: '',
        replace: true,
        restrict: 'E',
        controller: 'GoogleMapsCtrl',
        scope: true,

        link: function postLink(scope, element, attrs, ctrl) {

          var REDIRECT_ON_CLICK = true;
          var LOAD_MAP_ON_CLICK = true;
          var ael = element;
          var imgel = element.find('img')[0];

          var markers = $parse(attrs.markers)(scope);

          if (!attrs.sensor) {
            throw new Error('The `sensor` attribute is required.');
          }

          if (!attrs.size) {
            throw new Error('The `size` attribute is required.');
          }

          if (!attrs.center) {
            throw new Error('The `center` attribute is required.');
          }

          var sizeBits = attrs.size.split('x');
          if (sizeBits.length !== 2) {
            throw new Error('Size must be specified as `wxh`.');
          }

          var staticAttributes = {
            'sensor': attrs.sensor,
            'size': attrs.size,
            'center': attrs.center,
            'zoom': attrs.zoom,
            'markers': attrs.markers
          };
          imgel.src = ctrl.buildSourceString(staticAttributes, markers);
          console.log(imgel);

          ctrl.setStyle({
            'display': 'block',
            'cursor': 'pointer',
            'width': parseInt(sizeBits[0], 10) + 'px',
            'height': parseInt(sizeBits[1], 10) + 'px'
          });

          var mapLoaded = false;
          element.bind('click', function(event){
            if (REDIRECT_ON_CLICK && !mapLoaded) {
              // event.preventDefault();
            }
            else if (LOAD_MAP_ON_CLICK && !mapLoaded) {
              event.preventDefault();
              mapLoaded = true;
              ctrl.loadMap(ael, attrs.center, attrs.zoom, markers);
            }
            else if (!LOAD_MAP_ON_CLICK && mapLoaded) {
              event.preventDefault();
            }
          });
        }
      };
    });
}(google));<commit_msg>disable href after map was loaded<commit_after>/**
 * angular-adaptive-googlemaps v0.1.0
 * The MIT License
 * Copyright (c) 2013 Jan Antala
 */

(function (google) {
  'use strict';

  var adaptive = angular.module('adaptive.googlemaps', []);

  adaptive.controller('GoogleMapsCtrl', function ($scope, $element, $attrs, $parse) {
      $scope.MAP_HREF = 'http://maps.apple.com/?center=' + $attrs.center + '&z=' + $attrs.zoom;
      var STATIC_URL = '//maps.googleapis.com/maps/api/staticmap?';
      var STYLE_ATTRIBUTES = ['color', 'label', 'size'];
      var that = this;

      this.makeMarkerStrings = function makeMarkerStrings(markers) {
        return markers.map(function (marker) {
          var str = Object.keys(marker).map(function (key) {
            if (STYLE_ATTRIBUTES.indexOf(key) > -1) {
              return key + ':' + marker[key] + '|';
            }
          }).join('');

          return str + marker.coords.join(',');
        });
      };

      this.buildSourceString = function buildSourceString(attrs, markers) {
        var markerStrings;

        if (markers) {
          if (!angular.isArray(markers)) {
            markers = [markers];
          }
          markerStrings = this.makeMarkerStrings(markers);
        }

        var params = Object.keys(attrs).map(function (attr) {
          if (attr === 'markers' && markerStrings) {
            return Object.keys(markerStrings).map(function (key) {
              return 'markers=' + encodeURIComponent(markerStrings[key]);
            }).join('&');
          }

          if (attr[0] !== '$' && attr !== 'alt') {
            return encodeURIComponent(attr) + '=' + encodeURIComponent(attrs[attr]);
          }
        });

        return STATIC_URL + params.reduce(function (a, b) {
          if (!a) {
            return b;
          }

          if (b !== undefined) {
            return a + '&' + b;
          }

          return a;
        }, '');
      };

      var mapLoaded = false;
      this.loadMap = function($element, center, zoom, markers) {
        var mapOptions = {
          center: new google.maps.LatLng(0, 0),
          zoom: (Number(zoom) || 8),
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var map = new google.maps.Map($element[0], mapOptions);
        $scope.MAP_HREF = '';
        $element[0].href='';

        var geocoder = new google.maps.Geocoder();
        geocoder.geocode( { 'address': center}, function(results, status) {
          if (status === google.maps.GeocoderStatus.OK) {
            map.setCenter(results[0].geometry.location);

            for (var i = 0; i < markers.length; i++) {
              var marker = new google.maps.Marker({
                position: new google.maps.LatLng(markers[i].coords[0], markers[i].coords[1]),
                title: markers[i].title,
                map: map,
                draggable: false,
                animation: google.maps.Animation.DROP
              });
            }
          }
          else {
            console.error('Geocode was not successful for the following reason: ' + status);
          }
        });
      };

      this.setStyle = function(style){
        console.log(style);
        $scope.style = style;
      };
    });

    adaptive.directive('googlemaps', function ($parse) {
      return {
        template: '',
        replace: true,
        restrict: 'E',
        controller: 'GoogleMapsCtrl',
        scope: true,

        link: function postLink(scope, element, attrs, ctrl) {

          var REDIRECT_ON_CLICK = false;
          var LOAD_MAP_ON_CLICK = true;
          var ael = element;
          var imgel = element.find('img')[0];

          var markers = $parse(attrs.markers)(scope);

          if (!attrs.sensor) {
            throw new Error('The `sensor` attribute is required.');
          }

          if (!attrs.size) {
            throw new Error('The `size` attribute is required.');
          }

          if (!attrs.center) {
            throw new Error('The `center` attribute is required.');
          }

          var sizeBits = attrs.size.split('x');
          if (sizeBits.length !== 2) {
            throw new Error('Size must be specified as `wxh`.');
          }

          var staticAttributes = {
            'sensor': attrs.sensor,
            'size': attrs.size,
            'center': attrs.center,
            'zoom': attrs.zoom,
            'markers': attrs.markers
          };
          imgel.src = ctrl.buildSourceString(staticAttributes, markers);
          console.log(imgel);

          ctrl.setStyle({
            'display': 'block',
            'cursor': 'pointer',
            'width': parseInt(sizeBits[0], 10) + 'px',
            'height': parseInt(sizeBits[1], 10) + 'px'
          });

          var mapLoaded = false;
          element.bind('click', function(event){
            if (REDIRECT_ON_CLICK && !mapLoaded) {
              // event.preventDefault();
            }
            else if (LOAD_MAP_ON_CLICK && !mapLoaded) {
              event.preventDefault();
              mapLoaded = true;
              ctrl.loadMap(ael, attrs.center, attrs.zoom, markers);
            }
            else if (!LOAD_MAP_ON_CLICK && mapLoaded) {
              event.preventDefault();
            }
          });
        }
      };
    });
}(google));<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Container, Content, Card, Spinner } from 'native-base';

import JobTypeCardPreview from './jobTypeCardPreview';
import TimeCardPreview from './timeCardPreview';
import PlaceCardPreview from './placeCardPreview';
import CalendarCardPreview from './calendarCardPreview';
import CardItemButton from '../../common/card-item-button/cardItemButton';
import GlobalStyle from '../../common/globalStyle';
import I18n from '../../../i18n';

import { createJsonDataAttributes } from '../../../networking/json';
import { requestPostJob } from '../../../actions/jobs';

// Temporary constants. These will be moved and implemented in another way in the future!
const EXAMPLE_IMAGE_URL = 'https://facebook.github.io/react/img/logo_og.png';

// Screen shown during job creation, with a preview of the job.
class JobPreviewScreen extends Component {

  static navigationOptions = {
    title: I18n.t('screen_titles.job_preview'),
  };

  static propTypes = {
    jobPreview: React.PropTypes.objectOf(React.PropTypes.any).isRequired,
    token: React.PropTypes.string.isRequired,
    createJob: React.PropTypes.func.isRequired,
    loading: React.PropTypes.bool.isRequired,
  };

  postJob() {
    const data = this.props.jobPreview;
    const jobJson = createJsonDataAttributes({
      hours: data.hours,
      name: data.name,
      description: data.description,
      owner_user_id: data.owner_user_id,
      job_date: data.job_date,
      job_end_date: data.job_end_date,
      language_id: data.language_id,
      category_id: data.category_id,
      hourly_pay_id: data.hourly_pay_id,
      skills: data.skill_ids,
      city: data.city,
      street: data.street,
      zip: data.zip,
    });
    this.props.createJob(jobJson, this.props.token);
  }

  // TODO revamp how job duration is handled

  render() {
    if (this.props.loading) {
      return <Spinner color="blue" />;
    }
    const dateData = this.props.jobPreview.helperDate;
    return (
      <Container>
        <Content contentContainerStyle={GlobalStyle.padder}>
          <Card>
            <JobTypeCardPreview
              title={this.props.jobPreview.name}
              subtitle={this.props.jobPreview.description}
              cover={{ uri: EXAMPLE_IMAGE_URL }}
              icon={{ uri: EXAMPLE_IMAGE_URL }}
            />
            <TimeCardPreview
              data={{
                duration: I18n.t('size.small.estimated_duration'),
                cost: I18n.t('size.small.cost') }}
            />
            <CalendarCardPreview
              data={{
                date: dateData.date,
                time: dateData.time,
              }}
            />
            <PlaceCardPreview
              data={{
                address: this.props.jobPreview.street,
                zip: this.props.jobPreview.zip,
                city: this.props.jobPreview.city,
              }}
            />
            <CardItemButton
              text={'create job'}
              onPress={() => this.postJob()}
            />
          </Card>
        </Content>
      </Container>
    );
  }
}

const mapStateToProps = state => ({
  token: state.session.token,
  jobPreview: state.jobCreation,
  loading: state.jobs.jobLoading,
});

function bindAction(dispatch) {
  return {
    createJob: (jobJson, token) => dispatch(requestPostJob(jobJson, token)),
  };
}

export default connect(mapStateToProps, bindAction)(JobPreviewScreen);
<commit_msg>Initial navigation after successfully creating a job<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Container, Content, Card, Spinner } from 'native-base';

import JobTypeCardPreview from './jobTypeCardPreview';
import TimeCardPreview from './timeCardPreview';
import PlaceCardPreview from './placeCardPreview';
import CalendarCardPreview from './calendarCardPreview';
import CardItemButton from '../../common/card-item-button/cardItemButton';
import GlobalStyle from '../../common/globalStyle';
import I18n from '../../../i18n';

import { createJsonDataAttributes } from '../../../networking/json';
import { requestPostJob } from '../../../actions/jobs';

// Temporary constants. These will be moved and implemented in another way in the future!
const EXAMPLE_IMAGE_URL = 'https://facebook.github.io/react/img/logo_og.png';

// Screen shown during job creation, with a preview of the job.
class JobPreviewScreen extends Component {

  static navigationOptions = {
    title: I18n.t('screen_titles.job_preview'),
  };

  static propTypes = {
    jobPreview: React.PropTypes.objectOf(React.PropTypes.any).isRequired,
    token: React.PropTypes.string.isRequired,
    createJob: React.PropTypes.func.isRequired,
    loading: React.PropTypes.bool.isRequired,
    jobError: React.PropTypes.objectOf(React.PropTypes.any),
  };
  static defaultProps = {
    jobError: null,
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.loading && !nextProps.loading && nextProps.jobError === null) {
      // Successfully created a job. Navigate!
      // TODO reset 'create job' navigation stack
      this.props.navigation.navigate('MyJobsScreen');
    }
  }

  postJob() {
    const data = this.props.jobPreview;
    const jobJson = createJsonDataAttributes({
      hours: data.hours,
      name: data.name,
      description: data.description,
      owner_user_id: data.owner_user_id,
      job_date: data.job_date,
      job_end_date: data.job_end_date,
      language_id: data.language_id,
      category_id: data.category_id,
      hourly_pay_id: data.hourly_pay_id,
      skills: data.skill_ids,
      city: data.city,
      street: data.street,
      zip: data.zip,
    });
    this.props.createJob(jobJson, this.props.token);
  }

  // TODO revamp how job duration is handled

  render() {
    if (this.props.loading) {
      return <Spinner color="blue" />;
    }
    if (this.props.jobError != null) {
      // TODO handle errors
      // console.warn(JSON.stringify(this.props.jobError));
    }
    const dateData = this.props.jobPreview.helperDate;
    return (
      <Container>
        <Content contentContainerStyle={GlobalStyle.padder}>
          <Card>
            <JobTypeCardPreview
              title={this.props.jobPreview.name}
              subtitle={this.props.jobPreview.description}
              cover={{ uri: EXAMPLE_IMAGE_URL }}
              icon={{ uri: EXAMPLE_IMAGE_URL }}
            />
            <TimeCardPreview
              data={{
                duration: I18n.t('size.small.estimated_duration'),
                cost: I18n.t('size.small.cost') }}
            />
            <CalendarCardPreview
              data={{
                date: dateData.date,
                time: dateData.time,
              }}
            />
            <PlaceCardPreview
              data={{
                address: this.props.jobPreview.street,
                zip: this.props.jobPreview.zip,
                city: this.props.jobPreview.city,
              }}
            />
            <CardItemButton
              text={'create job'}
              onPress={() => this.postJob()}
            />
          </Card>
        </Content>
      </Container>
    );
  }
}

const mapStateToProps = state => ({
  token: state.session.token,
  jobPreview: state.jobCreation,
  loading: state.jobs.jobLoading,
  jobError: state.jobs.error,
});

function bindAction(dispatch) {
  return {
    createJob: (jobJson, token) => dispatch(requestPostJob(jobJson, token)),
  };
}

export default connect(mapStateToProps, bindAction)(JobPreviewScreen);
<|endoftext|>


<commit_before>/*
 * UserFollowBtn - Component
 * Handles with follow / unfollow actions to an user
 *
 * Example:
 * m.component(c.UserFollowBtn, {follow_id: 10, following: false})
 */

import m from 'mithril';
import postgrest from 'mithril-postgrest';
import h from '../h';
import models from '../models';

const UserFollowBtn = {
    controller(args) {
        const following = m.prop((args.following||false)),
              followVM = postgrest.filtersVM({follow_id: 'eq'}),
              loading = m.prop(false),
              userFollowInsert = models.userFollow.postOptions({
                  follow_id: args.follow_id}),
              userFollowDelete = (() => {
                  followVM.follow_id(args.follow_id);

                  return models.userFollow.deleteOptions(
                      followVM.parameters());
              })(),
              follow = () => {
                  const l = postgrest.loaderWithToken(userFollowInsert);
                  loading(true);

                  l.load().then(() => {
                      following(true);
                      loading(false);
                  });
              },
              unfollow = () => {
                  const l = postgrest.loaderWithToken(userFollowDelete);
                  loading(true);

                  l.load().then(() => {
                      following(false);
                      loading(false);
                  });
              };

        return {
            following: following,
            follow: follow,
            unfollow: unfollow,
            loading: loading
        };
    },
    view(ctrl, args) {
        if (ctrl.loading()) { return h.loader(); }
        if (ctrl.following()) {
            return m('a.w-button.btn.btn-medium.u-margintop-20',
                     {onclick: ctrl.unfollow},
                     'Deixar de seguir');
        } else {
            return m('a.w-button.btn.btn-medium.btn-terciary.u-margintop-20',
                     {onclick: ctrl.follow},
                     'Seguir');
        }
    }
};

export default UserFollowBtn;
<commit_msg>added hover on unfollow<commit_after>/*
 * UserFollowBtn - Component
 * Handles with follow / unfollow actions to an user
 *
 * Example:
 * m.component(c.UserFollowBtn, {follow_id: 10, following: false})
 */

import m from 'mithril';
import postgrest from 'mithril-postgrest';
import h from '../h';
import models from '../models';

const UserFollowBtn = {
    controller(args) {
        const following = m.prop((args.following||false)),
              followVM = postgrest.filtersVM({follow_id: 'eq'}),
              loading = m.prop(false),
              hover = m.prop(false),
              userFollowInsert = models.userFollow.postOptions({
                  follow_id: args.follow_id}),
              userFollowDelete = (() => {
                  followVM.follow_id(args.follow_id);

                  return models.userFollow.deleteOptions(
                      followVM.parameters());
              })(),
              follow = () => {
                  const l = postgrest.loaderWithToken(userFollowInsert);
                  loading(true);

                  l.load().then(() => {
                      following(true);
                      loading(false);
                  });
              },
              unfollow = () => {
                  const l = postgrest.loaderWithToken(userFollowDelete);
                  loading(true);

                  l.load().then(() => {
                      following(false);
                      loading(false);
                  });
              };

        return {
            following: following,
            follow: follow,
            unfollow: unfollow,
            loading: loading,
            hover: hover
        };
    },
    view(ctrl, args) {
        if (ctrl.loading()) { return h.loader(); }
        if (ctrl.following()) {
            return m('a.w-button.btn.btn-medium.u-margintop-20',
                     {
                         onclick: ctrl.unfollow,
                         onmouseover: () => ctrl.hover(true),
                         onmouseout: () => ctrl.hover(false)
                     },
                     (ctrl.hover() ? 'Deixar de seguir' : 'Seguindo'));
        } else {
            return m('a.w-button.btn.btn-medium.btn-terciary.u-margintop-20',
                     {onclick: ctrl.follow},
                     'Seguir');
        }
    }
};

export default UserFollowBtn;
<|endoftext|>


<commit_before>/* global PIXI */

var Potion = require('potion');

var app;

var Bunny = function() {
  this.x = 0;
  this.y = 0;
  this.speedX = 0;
  this.speedY = 0;

  this.object = new PIXI.Sprite(app.assets.get('bunny.png'));

  this.object.scale.set(0.5 + Math.random() * 0.5);
  this.object.rotation = Math.random() - 0.5;

  app.stage.addChild(this.object);
};

Bunny.prototype.update = function() {
  this.x += this.speedX;
  this.y += this.speedY;
  this.speedY += app.gravity;

  if (this.x > app.maxX) {
    this.speedX *= -1;
    this.x = app.maxX;
  } else if (this.x < app.minX) {
    this.speedX *= -1;
    this.x = app.minX;
  } if (this.y > app.maxY) {
    this.speedY *= -0.85;
    this.y = app.maxY;
    if (Math.random() > 0.5) {
      this.speedY -= Math.random() * 6;
    }
  } else if (this.y < app.minY) {
    this.speedY = 0;
    this.y = app.minY;
  }

  this.object.position.x = this.x;
  this.object.position.y = this.y;
};

app = Potion.init(document.querySelector('.game'), {
  configure: function() {
    this.setSize(800, 600);
    this.config.useRetina = false;
    this.config.initializeCanvas = false;

    this.renderer = new PIXI.WebGLRenderer(this.width, this.height, { resolution: this.config.useRetina ? 2 : 1, view: this.canvas });

    this.assets.addLoader('pixi', function(url, callback) {
      callback(PIXI.Texture.fromImage(url));
    });

    this.assets.load('pixi', 'bunny.png');
  },

  init: function() {
    this.gravity = 0.75;
    this.amount = 50;
    this.maxX = 800;
    this.minX = 0;
    this.maxY = 600;
    this.minY = 0;

    this.bunnys = [];
    this.stage = new PIXI.Stage();

    this.counter = document.createElement('div');
    this.counter.className = 'counter';
    document.querySelector('.container').appendChild(this.counter);

    this.count = 0;
    this.counter.innerHTML = this.count + ' BUNNIES';
  },

  update: function() {
    if (app.input.mouse.isDown) {
      for (var i=0; i<this.amount; i++) {
        var bunny = new Bunny();
        bunny.speedX = Math.random() * 10;
        bunny.speedY = (Math.random() * 10) - 5;
        this.bunnys.push(bunny);

        this.count += 1;
      }

      this.counter.innerHTML = this.count + ' BUNNIES';
    }

    for (var i=0, len=this.bunnys.length; i<len; i++) {
      var bunny = this.bunnys[i];
      bunny.update();
    }
  },

  render: function() {
    this.renderer.render(this.stage);
  }
});

module.exports = app;
<commit_msg>use async assets preloader in pixi demo<commit_after>/* global PIXI */

var Potion = require('potion');

var app;

var Bunny = function() {
  this.x = 0;
  this.y = 0;
  this.speedX = 0;
  this.speedY = 0;

  this.object = new PIXI.Sprite(app.assets.get('bunny.png'));

  this.object.scale.set(0.5 + Math.random() * 0.5);
  this.object.rotation = Math.random() - 0.5;

  app.stage.addChild(this.object);
};

Bunny.prototype.update = function() {
  this.x += this.speedX;
  this.y += this.speedY;
  this.speedY += app.gravity;

  if (this.x > app.maxX) {
    this.speedX *= -1;
    this.x = app.maxX;
  } else if (this.x < app.minX) {
    this.speedX *= -1;
    this.x = app.minX;
  } if (this.y > app.maxY) {
    this.speedY *= -0.85;
    this.y = app.maxY;
    if (Math.random() > 0.5) {
      this.speedY -= Math.random() * 6;
    }
  } else if (this.y < app.minY) {
    this.speedY = 0;
    this.y = app.minY;
  }

  this.object.position.x = this.x;
  this.object.position.y = this.y;
};

app = Potion.init(document.querySelector('.game'), {
  configure: function() {
    this.setSize(800, 600);
    this.config.useRetina = false;
    this.config.initializeCanvas = false;

    this.renderer = new PIXI.WebGLRenderer(this.width, this.height, { resolution: this.config.useRetina ? 2 : 1, view: this.canvas });

    this.assets.addLoader('pixi', function(url, callback) {
      this.assets._loaders.image(url, function(image) {
        callback(new PIXI.Texture(new PIXI.BaseTexture(image)));
      });
    }.bind(this));

    this.assets.load('pixi', 'bunny.png');
  },

  init: function() {
    this.gravity = 0.75;
    this.amount = 50;
    this.maxX = 800;
    this.minX = 0;
    this.maxY = 600;
    this.minY = 0;

    this.bunnys = [];
    this.stage = new PIXI.Stage();

    this.counter = document.createElement('div');
    this.counter.className = 'counter';
    document.querySelector('.container').appendChild(this.counter);

    this.count = 0;
    this.counter.innerHTML = this.count + ' BUNNIES';
  },

  update: function() {
    if (app.input.mouse.isDown) {
      for (var i=0; i<this.amount; i++) {
        var bunny = new Bunny();
        bunny.speedX = Math.random() * 10;
        bunny.speedY = (Math.random() * 10) - 5;
        this.bunnys.push(bunny);

        this.count += 1;
      }

      this.counter.innerHTML = this.count + ' BUNNIES';
    }

    for (var i=0, len=this.bunnys.length; i<len; i++) {
      var bunny = this.bunnys[i];
      bunny.update();
    }
  },

  render: function() {
    this.renderer.render(this.stage);
  }
});

module.exports = app;
<|endoftext|>


<commit_before>var Container = function Container() {
	var self = this;
	this.bootstrap = function(moduleName) {
		if (!angular) throw new Error("AngularJS not available. STOP.");
		if (!require) throw new Error("RequireJS not available. STOP.");
		if (!_) throw new Error("Underscore not available. STOP.");

		self.injector = angular.bootstrap("#dummyElement", [moduleName]);
		self.controllerProvider = self.injector.get("$controller");
      	self.rootScope = self.injector.get("$rootScope");
      	self.compileService = self.injector.get("$compile");
	};

	this.newScope = function() {
		return self.rootScope.$new();
	};

	this.controller = function(controllerName, scope) {
		return self.controllerProvider(controllerName, {$scope: scope});
	};

	this.view = function(viewUrl, controller, scope) {
		var deferred = Q.defer();
		var childScope = self.rootScope;
		require(["text!" + viewUrl], function(viewHTML) {
			var wrappingElement = angular.element("

");
			wrappingElement.append(viewHTML);
			wrappingElement.data("$ngControllerController", controller);

			var compiledTemplate = self.compileService(wrappingElement)(scope);
			scope.$apply();
			deferred.resolve(compiledTemplate);
		});
		return deferred.promise;
	};

	this.mvc = function(controllerName, viewUrl) {
		var scope = self.newScope();
		var controller = self.controller(controllerName, scope);
		return this.view(viewUrl, controller, scope).then(function(compiledTemplate) {
			return { controller: controller, view: compiledTemplate, scope: scope };
		});
	};
};

var DuckDOM = function DuckDOM(view, scope) {
	this.interactWith = function(selector, value) {
		var elements = angular.element(selector, view);

		_.each(elements, function(element) {
			if (element.nodeName === "INPUT" && element.type === "text") {
				elements.val(value).trigger("input");
			}
			else if (element.nodeName === "INPUT" && element.type === "button") {
				elements.submit();
			}
			else if (element.nodeName === "INPUT" && element.type === "checkbox") {
				elements.trigger("click");
			}
		});
		scope.$apply();
	};

	this.element = function(selector) {
		return angular.element(selector, view);
	};
};<commit_msg>Adding interaction for SELECT element - <Mojo><commit_after>var Container = function Container() {
	var self = this;
	this.bootstrap = function(moduleName) {
		if (!angular) throw new Error("AngularJS not available. STOP.");
		if (!require) throw new Error("RequireJS not available. STOP.");
		if (!_) throw new Error("Underscore not available. STOP.");

		self.injector = angular.bootstrap("#dummyElement", [moduleName]);
		self.controllerProvider = self.injector.get("$controller");
      	self.rootScope = self.injector.get("$rootScope");
      	self.compileService = self.injector.get("$compile");
	};

	this.newScope = function() {
		return self.rootScope.$new();
	};

	this.controller = function(controllerName, scope) {
		return self.controllerProvider(controllerName, {$scope: scope});
	};

	this.view = function(viewUrl, controller, scope) {
		var deferred = Q.defer();
		var childScope = self.rootScope;
		require(["text!" + viewUrl], function(viewHTML) {
			var wrappingElement = angular.element("

");
			wrappingElement.append(viewHTML);
			wrappingElement.data("$ngControllerController", controller);
			var compiledTemplate = self.compileService(wrappingElement)(scope);
			scope.$apply();
			deferred.resolve(compiledTemplate);
		});
		return deferred.promise;
	};

	this.mvc = function(controllerName, viewUrl) {
		var scope = self.newScope();
		var controller = self.controller(controllerName, scope);
		return this.view(viewUrl, controller, scope).then(function(compiledTemplate) {
			console.log("Controller is " + controller);
			console.log("View is " + compiledTemplate);
			console.log("Scope is " + scope);
			return { controller: controller, view: compiledTemplate, scope: scope };
		});
	};
};

var DuckDOM = function DuckDOM(view, scope) {
	this.interactWith = function(selector, value) {
		var elements = angular.element(selector, view);

		_.each(elements, function(element) {
			if (element.nodeName === "INPUT" && element.type === "text") {
				elements.val(value).trigger("input");
			}
			else if (element.nodeName === "INPUT" && element.type === "button") {
				elements.submit();
			}
			else if (element.nodeName === "INPUT" && element.type === "checkbox") {
				elements.click().trigger("click");
			}
			else if (element.nodeName === "SELECT") {
			angular.element(elements[0].options[value]).attr("selected", true);
			elements.trigger("change");
			}
		});
		scope.$apply();
 	};

	this.element = function(selector) {
		return angular.element(selector, view);
	};
};<|endoftext|>


<commit_before>/*************************************************
 * Copyright (c) 2016 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

 export default
 	['$scope', '$state', '$stateParams', 'DashboardHostsForm', 'GenerateForm', 'ParseTypeChange', 'DashboardHostService', 'host',
 	function($scope, $state, $stateParams, DashboardHostsForm, GenerateForm, ParseTypeChange, DashboardHostService, host){
 		var generator = GenerateForm,
 			form = DashboardHostsForm;
        $scope.parseType = 'yaml';
 		$scope.formCancel = function(){
 			$state.go('^', null, {reload: true});
 		};
 		$scope.toggleHostEnabled = function(){
 			$scope.host.enabled = !$scope.host.enabled;
 		};
 		$scope.toggleEnabled = function(){
 			$scope.host.enabled = !$scope.host.enabled;
 		};
 		$scope.formSave = function(){
 			var host = {
 				id: $scope.host.id,
 				variables: $scope.extraVars === '---' || $scope.extraVars === '{}' ? null : $scope.extraVars,
 				name: $scope.name,
 				description: $scope.description
 			};
 			DashboardHostService.putHost(host).then(function(res){
 				$state.go('^', null, {reload: true});
 			});

 		};
 		var init = function(){
 			$scope.host = host;
 			$scope.extraVars = host.variables === '' ? '---' : host.variables;
 			generator.inject(form, {mode: 'edit', related: false, scope: $scope});
     		$scope.extraVars = $scope.host.variables === '' ? '---' : $scope.host.variables;
    		$scope.name = host.name;
 			$scope.description = host.description;
        	ParseTypeChange({
        		scope: $scope,
        		field_id: 'host_variables',
        		variable: 'extraVars',
        	});
 		};

 		init();
 	}];<commit_msg>pass enabled/disabled to DsahboardHostService #1679<commit_after>/*************************************************
 * Copyright (c) 2016 Ansible, Inc.
 *
 * All Rights Reserved
 *************************************************/

 export default
 	['$scope', '$state', '$stateParams', 'DashboardHostsForm', 'GenerateForm', 'ParseTypeChange', 'DashboardHostService', 'host',
 	function($scope, $state, $stateParams, DashboardHostsForm, GenerateForm, ParseTypeChange, DashboardHostService, host){
 		var generator = GenerateForm,
 			form = DashboardHostsForm;
        $scope.parseType = 'yaml';
 		$scope.formCancel = function(){
 			$state.go('^', null, {reload: true});
 		};
 		$scope.toggleHostEnabled = function(){
 			$scope.host.enabled = !$scope.host.enabled;
 		};
 		$scope.toggleEnabled = function(){
 			$scope.host.enabled = !$scope.host.enabled;
 		};
 		$scope.formSave = function(){
 			var host = {
 				id: $scope.host.id,
 				variables: $scope.extraVars === '---' || $scope.extraVars === '{}' ? null : $scope.extraVars,
 				name: $scope.name,
 				description: $scope.description,
 				enabled: $scope.host.enabled
 			};
 			DashboardHostService.putHost(host).then(function(res){
 				$state.go('^', null, {reload: true});
 			});

 		};
 		var init = function(){
 			$scope.host = host;
 			$scope.extraVars = host.variables === '' ? '---' : host.variables;
 			generator.inject(form, {mode: 'edit', related: false, scope: $scope});
     		$scope.extraVars = $scope.host.variables === '' ? '---' : $scope.host.variables;
    		$scope.name = host.name;
 			$scope.description = host.description;
        	ParseTypeChange({
        		scope: $scope,
        		field_id: 'host_variables',
        		variable: 'extraVars',
        	});
 		};

 		init();
 	}];<|endoftext|>


<commit_before>import {
  INPUT_WIDTH_SLIDER, LABEL_WIDTH_SLIDER, HELP_ICON_PREVIEW, FIELD_HELP_PREVIEW, TOOLTIP_PREVIEW,
  FORM, STORY_ROOT, CLOSE_ICON_BUTTON, BACKGROUND_UI_LOCATOR, LINK, ICON, INPUT_WIDTH_PREVIEW,
  COMMMON_DATA_ELEMENT_INPUT, LABEL, RERUN_TESTS_BUTTON,
} from './locators';

// actions locators
export const clearButton = () => cy.get(FORM).find('button').contains('Clear');

// accessibility locators
export const reRunTestsButton = () => cy.get(RERUN_TESTS_BUTTON);

// knobs locators
export const getKnobsInput = propertyName => cy.get(`[name="${propertyName}"]`);
export const knobsTab = () => cy.get(FORM).find('button').contains('Knobs');
export const actionsTab = () => cy.get(FORM).find('button').contains('Actions');
export const accessibilityTab = () => cy.get(FORM).find('button').contains('Accessibility');
export const eventInAction = event => cy.get(FORM).find('span').contains(event);
export const inputWidthSlider = () => cy.get(INPUT_WIDTH_SLIDER);
export const labelWidthSlider = () => cy.get(LABEL_WIDTH_SLIDER);

// component preview locators
export const storyRoot = () => cy.iFrame(STORY_ROOT);
export const commonButtonPreview = () => storyRoot().find('button');
export const labelPreview = () => storyRoot().find('label').first();
export const label = () => cy.iFrame(LABEL);
export const helpIcon = () => cy.iFrame(HELP_ICON_PREVIEW).first();
export const tooltipPreview = () => cy.iFrame(TOOLTIP_PREVIEW);
export const fieldHelpPreview = () => cy.iFrame(FIELD_HELP_PREVIEW).first();
export const closeIconButton = () => cy.iFrame(CLOSE_ICON_BUTTON);
export const backgroundUILocator = () => cy.iFrame(BACKGROUND_UI_LOCATOR);
export const link = () => cy.iFrame(LINK);
export const icon = () => cy.iFrame(ICON);
export const inputWidthPreview = () => cy.iFrame(INPUT_WIDTH_PREVIEW);
export const commonDataElementInputPreview = () => cy.iFrame(COMMMON_DATA_ELEMENT_INPUT);
export const getDataElementByValue = element => cy.iFrame(`[data-element="${element}"]`);
export const getDataElementByNameAndValue = (name, value) => cy.iFrame(`[data-${name}="${value}"]`);
<commit_msg>add timeout for rerun tests button<commit_after>import {
  INPUT_WIDTH_SLIDER, LABEL_WIDTH_SLIDER, HELP_ICON_PREVIEW, FIELD_HELP_PREVIEW, TOOLTIP_PREVIEW,
  FORM, STORY_ROOT, CLOSE_ICON_BUTTON, BACKGROUND_UI_LOCATOR, LINK, ICON, INPUT_WIDTH_PREVIEW,
  COMMMON_DATA_ELEMENT_INPUT, LABEL, RERUN_TESTS_BUTTON,
} from './locators';

// actions locators
export const clearButton = () => cy.get(FORM).find('button').contains('Clear');

// accessibility locators
export const reRunTestsButton = () => cy.get(RERUN_TESTS_BUTTON, {timeout: 10000} );

// knobs locators
export const getKnobsInput = propertyName => cy.get(`[name="${propertyName}"]`);
export const knobsTab = () => cy.get(FORM).find('button').contains('Knobs');
export const actionsTab = () => cy.get(FORM).find('button').contains('Actions');
export const accessibilityTab = () => cy.get(FORM).find('button').contains('Accessibility');
export const eventInAction = event => cy.get(FORM).find('span').contains(event);
export const inputWidthSlider = () => cy.get(INPUT_WIDTH_SLIDER);
export const labelWidthSlider = () => cy.get(LABEL_WIDTH_SLIDER);

// component preview locators
export const storyRoot = () => cy.iFrame(STORY_ROOT);
export const commonButtonPreview = () => storyRoot().find('button');
export const labelPreview = () => storyRoot().find('label').first();
export const label = () => cy.iFrame(LABEL);
export const helpIcon = () => cy.iFrame(HELP_ICON_PREVIEW).first();
export const tooltipPreview = () => cy.iFrame(TOOLTIP_PREVIEW);
export const fieldHelpPreview = () => cy.iFrame(FIELD_HELP_PREVIEW).first();
export const closeIconButton = () => cy.iFrame(CLOSE_ICON_BUTTON);
export const backgroundUILocator = () => cy.iFrame(BACKGROUND_UI_LOCATOR);
export const link = () => cy.iFrame(LINK);
export const icon = () => cy.iFrame(ICON);
export const inputWidthPreview = () => cy.iFrame(INPUT_WIDTH_PREVIEW);
export const commonDataElementInputPreview = () => cy.iFrame(COMMMON_DATA_ELEMENT_INPUT);
export const getDataElementByValue = element => cy.iFrame(`[data-element="${element}"]`);
export const getDataElementByNameAndValue = (name, value) => cy.iFrame(`[data-${name}="${value}"]`);
<|endoftext|>


<commit_before>import { Dimensions } from 'react-native';
import handleSize from './utils';

const myWidth = Dimensions.get('window').width;
const myHeight = Dimensions.get('window').height;

const width = num => myWidth * handleSize(num);
const height = num => myHeight * handleSize(num);
const totalSize = num => Math.sqrt((myHeight * myHeight) + (myWidth * myWidth)) * handleSize(num);

export { width, height, totalSize };
<commit_msg>Delete index.js<commit_after><|endoftext|>


<commit_before>/*!
 *    MyMoney - 10-expense.js v.1.1
 *    Copyright (C) 2017 MING-CHIEN LEE
 *
 *    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
 *    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/>.
 *
 *    Copyright Contact Information
 *    MING-CHIEN LEE <edisonlee@edisonlee55.com> (https://www.edisonlee55.com/#contact)
 */
var fdb = new ForerunnerDB();
var db = fdb.db("MyMoneyDB");
var collection = db.collection("MyMoneyCollection");
collection.load(function () {
  var expenses = collection.find(
    {},
    {
      $orderBy: { timestamp: -1 },
      $limit: 10
    }
  );
  for (var i = 0; i < expenses.length; i++) {
    $("tbody").append("
" + expenses[i].date + "	" + expenses[i].name + "	" + expenses[i].price + "
");
  }
});<commit_msg>Update 10-expense.js<commit_after>/**
 * MyMoney - 10-expense.js v.1.1
 * Copyright (c) 2018 MING-CHIEN LEE
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
var fdb = new ForerunnerDB();
var db = fdb.db("MyMoneyDB");
var collection = db.collection("MyMoneyCollection");
collection.load(function () {
  var expenses = collection.find(
    {},
    {
      $orderBy: { timestamp: -1 },
      $limit: 10
    }
  );
  for (var i = 0; i < expenses.length; i++) {
    $("tbody").append("
" + expenses[i].date + "	" + expenses[i].name + "	" + expenses[i].price + "
");
  }
});
<|endoftext|>


<commit_before>"use strict";

treeherder.controller('MainCtrl', [
    '$scope', '$rootScope', '$routeParams', '$location', 'ThLog',
    'localStorageService', 'ThRepositoryModel', 'thPinboard',
    'thClassificationTypes', 'thEvents', '$interval',
    'ThExclusionProfileModel', 'thJobFilters',
    function MainController(
        $scope, $rootScope, $routeParams, $location, ThLog,
        localStorageService, ThRepositoryModel, thPinboard,
        thClassificationTypes, thEvents, $interval,
        ThExclusionProfileModel, thJobFilters) {

        var $log = new ThLog("MainCtrl");

        thClassificationTypes.load();
        ThRepositoryModel.load();

        $scope.clearJob = function() {
            // setting the selectedJob to null hides the bottom panel
            $rootScope.selectedJob = null;
        };
        $scope.processKeyboardInput = function(ev){

            //Only listen to key commands when the body has focus. Otherwise
            //html input elements won't work correctly.
            if( (document.activeElement.nodeName !== 'BODY') ||
                (ev.keyCode === 16) ){
                return;
            }

            if( (ev.keyCode === 73) ){
                // toggle display in-progress jobs(pending/running), key:i
                $scope.toggleInProgress();

            }else if( (ev.keyCode === 74) || (ev.keyCode === 78) ){
                //Highlight next unclassified failure keys:j/n
                $rootScope.$broadcast(
                    thEvents.selectNextUnclassifiedFailure
                    );

            }else if( (ev.keyCode === 75) || (ev.keyCode === 80) ){
                //Highlight previous unclassified failure keys:k/p
                $rootScope.$broadcast(
                    thEvents.selectPreviousUnclassifiedFailure
                    );

            }else if(ev.keyCode === 83){
                //Select/deselect active build or changeset, keys:s
                $rootScope.$broadcast(thEvents.jobPin, $rootScope.selectedJob);

            }else if(ev.keyCode === 85){
                //display only unclassified failures, keys:u
                $scope.toggleUnclassifiedFailures();
            }
        };

        // detect window width and put it in scope so items can react to
        // a narrow/wide window
        $scope.getWidth = function() {
            return $(window).width();
        };
        $scope.$watch($scope.getWidth, function(newValue, oldValue) {
            $scope.windowWidth = newValue;
        });
        window.onresize = function(){
            $scope.$apply();
        };

        // the repos the user has chosen to watch
        $scope.watchedRepos = ThRepositoryModel.watchedRepos;

        $scope.unwatchRepo = function(name) {
            ThRepositoryModel.unwatch(name);
        };

        // update the repo status (treestatus) in an interval of every 2 minutes
        $interval(ThRepositoryModel.updateAllWatchedRepoTreeStatus, 2 * 60 * 1000);

        $scope.getTopNavBarHeight = function() {
            return $("#th-global-top-nav-panel").find("#top-nav-main-panel").height();
        };

        // adjust the body padding so we can see all the job/resultset data
        // if the top navbar height has changed due to window width changes
        // or adding enough watched repos to wrap.
        $rootScope.$watch($scope.getTopNavBarHeight, function(newValue) {
            $("body").css("padding-top", newValue);
        });

        /**
         * The watched repos in the nav bar can be either on the left or the
         * right side of the screen and the drop-down menu may get cut off
         * if it pulls right while on the left side of the screen.
         * And it can change any time the user re-sizes the window, so we must
         * check this each time a drop-down is invoked.
         */
        $scope.setDropDownPull = function(event) {
            $log.debug("dropDown", event.target);
            var element = event.target.offsetParent;
            if (element.offsetLeft > $scope.getWidth() / 2) {
                $(element).find(".dropdown-menu").addClass("pull-right");
            } else {
                $(element).find(".dropdown-menu").removeClass("pull-right");
            }

        };

        $scope.isSkippingExclusionProfiles = function() {
            return thJobFilters.isSkippingExclusionProfiles();
        };

        $scope.getUnclassifiedFailureCount = function(repoName) {
            return thJobFilters.getCountExcludedForRepo(repoName);
        };

        $scope.toggleExcludedJobs = function() {
            thJobFilters.toggleSkipExclusionProfiles();
        };

        $scope.toggleUnclassifiedFailures = function() {
            $log.debug("toggleUnclassifiedFailures");
            if (thJobFilters.isUnclassifiedFailures()) {
                thJobFilters.resetNonFieldFilters();
            } else {
                thJobFilters.showUnclassifiedFailures();
            }
        };

        $scope.toggleInProgress = function() {
            thJobFilters.toggleInProgress();
        };

        $scope.allExpanded = function(cls) {
            var fullList = $("." + cls);
            var visibleList = $("." + cls + ":visible");
            return fullList.length === visibleList.length;
        };

        $scope.allCollapsed = function(cls) {
            var visibleList = $("." + cls + ":visible");
            return visibleList.length === 0;
        };

        $scope.toggleAllJobsAndRevisions = function() {
            var collapse = ($scope.allCollapsed("job-list") &&
                            $scope.allCollapsed("revision-list"));
            $rootScope.$broadcast(
                thEvents.toggleAllJobs, collapse
            );
            $rootScope.$broadcast(
                thEvents.toggleAllRevisions, collapse
            );
        };

        $scope.toggleAllJobs = function(collapse) {
            collapse = collapse || $scope.allCollapsed("job-list");
            $rootScope.$broadcast(
                thEvents.toggleAllJobs, collapse
            );

        };

        $scope.toggleAllRevisions = function(collapse) {
            collapse = collapse || $scope.allCollapsed("revision-list");
            $rootScope.$broadcast(
                thEvents.toggleAllRevisions, collapse
            );

        };

        // give the page a way to determine which nav toolbar to show
        $rootScope.$on('$locationChangeSuccess', function(ev,newUrl) {
            $rootScope.locationPath = $location.path().replace('/', '');
        });

        $rootScope.urlBasePath = $location.absUrl().split('?')[0];

        $scope.isRepoPanelShowing = false;

        $scope.toggleRepoPanel = function() {
            $scope.isRepoPanelShowing=!$scope.isRepoPanelShowing;
        };

        $scope.changeRepo = function(repo_name) {
            // hide the repo panel if they chose to load one.
            $scope.isRepoPanelShowing = false;
            $rootScope.selectedJob = null;
            thPinboard.unPinAll();

            ThRepositoryModel.setCurrent(repo_name);
            $location.search({repo: repo_name});

        };

        $scope.pinboardCount = thPinboard.count;
        $scope.pinnedJobs = thPinboard.pinnedJobs;

        $scope.user = angular.fromJson(localStorageService.get("user")) || {};
        $scope.user.loggedin = angular.isDefined($scope.user.email) && $scope.user.email !== null;

        // get a cached version of the exclusion profiles
        ThExclusionProfileModel.get_list({}, true).then(function(profiles){
            $scope.exclusion_profiles = profiles;
            $rootScope.active_exclusion_profile = _.find(
                $scope.exclusion_profiles,
                function(elem){
                    return elem.is_default;
                }
            );
            if($rootScope.active_exclusion_profile){
                $scope.$broadcast(thEvents.globalFilterChanged, null);
            }
        }, null);
    }
]);
<commit_msg>update urlBasePath on  change<commit_after>"use strict";

treeherder.controller('MainCtrl', [
    '$scope', '$rootScope', '$routeParams', '$location', 'ThLog',
    'localStorageService', 'ThRepositoryModel', 'thPinboard',
    'thClassificationTypes', 'thEvents', '$interval',
    'ThExclusionProfileModel', 'thJobFilters',
    function MainController(
        $scope, $rootScope, $routeParams, $location, ThLog,
        localStorageService, ThRepositoryModel, thPinboard,
        thClassificationTypes, thEvents, $interval,
        ThExclusionProfileModel, thJobFilters) {

        var $log = new ThLog("MainCtrl");

        thClassificationTypes.load();
        ThRepositoryModel.load();

        $scope.clearJob = function() {
            // setting the selectedJob to null hides the bottom panel
            $rootScope.selectedJob = null;
        };
        $scope.processKeyboardInput = function(ev){

            //Only listen to key commands when the body has focus. Otherwise
            //html input elements won't work correctly.
            if( (document.activeElement.nodeName !== 'BODY') ||
                (ev.keyCode === 16) ){
                return;
            }

            if( (ev.keyCode === 73) ){
                // toggle display in-progress jobs(pending/running), key:i
                $scope.toggleInProgress();

            }else if( (ev.keyCode === 74) || (ev.keyCode === 78) ){
                //Highlight next unclassified failure keys:j/n
                $rootScope.$broadcast(
                    thEvents.selectNextUnclassifiedFailure
                    );

            }else if( (ev.keyCode === 75) || (ev.keyCode === 80) ){
                //Highlight previous unclassified failure keys:k/p
                $rootScope.$broadcast(
                    thEvents.selectPreviousUnclassifiedFailure
                    );

            }else if(ev.keyCode === 83){
                //Select/deselect active build or changeset, keys:s
                $rootScope.$broadcast(thEvents.jobPin, $rootScope.selectedJob);

            }else if(ev.keyCode === 85){
                //display only unclassified failures, keys:u
                $scope.toggleUnclassifiedFailures();
            }
        };

        // detect window width and put it in scope so items can react to
        // a narrow/wide window
        $scope.getWidth = function() {
            return $(window).width();
        };
        $scope.$watch($scope.getWidth, function(newValue, oldValue) {
            $scope.windowWidth = newValue;
        });
        window.onresize = function(){
            $scope.$apply();
        };

        // the repos the user has chosen to watch
        $scope.watchedRepos = ThRepositoryModel.watchedRepos;

        $scope.unwatchRepo = function(name) {
            ThRepositoryModel.unwatch(name);
        };

        // update the repo status (treestatus) in an interval of every 2 minutes
        $interval(ThRepositoryModel.updateAllWatchedRepoTreeStatus, 2 * 60 * 1000);

        $scope.getTopNavBarHeight = function() {
            return $("#th-global-top-nav-panel").find("#top-nav-main-panel").height();
        };

        // adjust the body padding so we can see all the job/resultset data
        // if the top navbar height has changed due to window width changes
        // or adding enough watched repos to wrap.
        $rootScope.$watch($scope.getTopNavBarHeight, function(newValue) {
            $("body").css("padding-top", newValue);
        });

        /**
         * The watched repos in the nav bar can be either on the left or the
         * right side of the screen and the drop-down menu may get cut off
         * if it pulls right while on the left side of the screen.
         * And it can change any time the user re-sizes the window, so we must
         * check this each time a drop-down is invoked.
         */
        $scope.setDropDownPull = function(event) {
            $log.debug("dropDown", event.target);
            var element = event.target.offsetParent;
            if (element.offsetLeft > $scope.getWidth() / 2) {
                $(element).find(".dropdown-menu").addClass("pull-right");
            } else {
                $(element).find(".dropdown-menu").removeClass("pull-right");
            }

        };

        $scope.isSkippingExclusionProfiles = function() {
            return thJobFilters.isSkippingExclusionProfiles();
        };

        $scope.getUnclassifiedFailureCount = function(repoName) {
            return thJobFilters.getCountExcludedForRepo(repoName);
        };

        $scope.toggleExcludedJobs = function() {
            thJobFilters.toggleSkipExclusionProfiles();
        };

        $scope.toggleUnclassifiedFailures = function() {
            $log.debug("toggleUnclassifiedFailures");
            if (thJobFilters.isUnclassifiedFailures()) {
                thJobFilters.resetNonFieldFilters();
            } else {
                thJobFilters.showUnclassifiedFailures();
            }
        };

        $scope.toggleInProgress = function() {
            thJobFilters.toggleInProgress();
        };

        $scope.allExpanded = function(cls) {
            var fullList = $("." + cls);
            var visibleList = $("." + cls + ":visible");
            return fullList.length === visibleList.length;
        };

        $scope.allCollapsed = function(cls) {
            var visibleList = $("." + cls + ":visible");
            return visibleList.length === 0;
        };

        $scope.toggleAllJobsAndRevisions = function() {
            var collapse = ($scope.allCollapsed("job-list") &&
                            $scope.allCollapsed("revision-list"));
            $rootScope.$broadcast(
                thEvents.toggleAllJobs, collapse
            );
            $rootScope.$broadcast(
                thEvents.toggleAllRevisions, collapse
            );
        };

        $scope.toggleAllJobs = function(collapse) {
            collapse = collapse || $scope.allCollapsed("job-list");
            $rootScope.$broadcast(
                thEvents.toggleAllJobs, collapse
            );

        };

        $scope.toggleAllRevisions = function(collapse) {
            collapse = collapse || $scope.allCollapsed("revision-list");
            $rootScope.$broadcast(
                thEvents.toggleAllRevisions, collapse
            );

        };

        $rootScope.urlBasePath = $location.absUrl().split('?')[0];

        // give the page a way to determine which nav toolbar to show
        $rootScope.$on('$locationChangeSuccess', function(ev,newUrl) {
            $rootScope.locationPath = $location.path().replace('/', '');

            // this is to avoid bad urls showing up
            // when the app redirects internally
            $rootScope.urlBasePath = $location.absUrl().split('?')[0];
        });

        $scope.isRepoPanelShowing = false;

        $scope.toggleRepoPanel = function() {
            $scope.isRepoPanelShowing=!$scope.isRepoPanelShowing;
        };

        $scope.changeRepo = function(repo_name) {
            // hide the repo panel if they chose to load one.
            $scope.isRepoPanelShowing = false;
            $rootScope.selectedJob = null;
            thPinboard.unPinAll();

            ThRepositoryModel.setCurrent(repo_name);
            $location.search({repo: repo_name});

        };

        $scope.pinboardCount = thPinboard.count;
        $scope.pinnedJobs = thPinboard.pinnedJobs;

        $scope.user = angular.fromJson(localStorageService.get("user")) || {};
        $scope.user.loggedin = angular.isDefined($scope.user.email) && $scope.user.email !== null;

        // get a cached version of the exclusion profiles
        ThExclusionProfileModel.get_list({}, true).then(function(profiles){
            $scope.exclusion_profiles = profiles;
            $rootScope.active_exclusion_profile = _.find(
                $scope.exclusion_profiles,
                function(elem){
                    return elem.is_default;
                }
            );
            if($rootScope.active_exclusion_profile){
                $scope.$broadcast(thEvents.globalFilterChanged, null);
            }
        }, null);
    }
]);
<|endoftext|>


<commit_before>/*
	This file is part of FacilMap.

	FacilMap 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.

	FacilMap 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 FacilMap.  If not, see <http://www.gnu.org/licenses/>.

	Obtain the source code from http://gitorious.org/facilmap.
*/

/**
 * An abstract class whose implementations connect to a NameFinder.
*/
FacilMap.NameFinder = OpenLayers.Class({
	/**
	 * Perform a search through a NameFinder. This function itself does not connect to an actual NameFinder, it only finds one result if
	 * the query String consists of coordinates encoded in a Lat,Lon string or an OpenStreetMap Permalink.
	 * @param String query The query string.
	 * @param Function callbackFunction A function that is executed when the search has been performed. The function takes one argument that
	 *                                  contains an array with the results. It is undefined if an error has occurred. Each result is an object
	 *                                  with the following properties:
	 *                                  * OpenLayers.LonLat lonlat The coordinates of the result
	 *                                  * String name: The title of the result.
	 *                                  * String info: Some additional information about the result, such as the type.
	 *                                  * function getZoom(OpenLayers.Map): Returns the zoom level that the search result should be displayed at on the given map.
	 *                                  * Node osm: The associated OSM object or null.
	 * @return void
	*/
	find : function(query, callbackFunction) {
		query.replace(/^\s+/, "").replace(/\s+$/, "");
		var query_match;
		var query_urlPart;
		if(query_match = query.match(/^http:\/\/(www\.)?osm\.org\/go\/([-A-Za-z0-9_@]+)/))
		{ // Coordinates, shortlink
			var shortlink = FacilMap.Util.decodeShortLink(query_match[2]);
			results = [ {
				lonlat : shortlink.lonlat,
				info : OpenLayers.i18n("Coordinates"),
				name : shortlink.lonlat.lat + ", " + shortlink.lonlat.lon,
				getZoom : function(map) {
					return shortlink.zoom;
				}
			} ];
			callbackFunction(results);
		}
		else if(query_match = query.match(/^(-?\s*\d+([.,]\d+)?)\s*[,;]?\s*(-?\s*\d+([.,]\d+)?)$/))
		{ // Coordinates
			results = [ {
				lonlat : new OpenLayers.LonLat(query_match[3].replace(",", ".").replace(/\s+/, ""), query_match[1].replace(",", ".").replace(/\s+/, "")),
				info : OpenLayers.i18n("Coordinates"),
				getZoom : function(map) {
					return 15;
				}
			} ];
			results[0].name = results[0].lonlat.lat+","+results[0].lonlat.lon;
			callbackFunction(results);
		}
		else if((query_match = query.match(/^http:\/\/.*\?(.*)$/)) && typeof (query_urlPart = FacilMap.Util.decodeQueryString(query_match[1])).lon != "undefined" && typeof query_urlPart.lat != "undefined")
		{ // OpenStreetMap Permalink
			results = [ {
				lonlat : new OpenLayers.LonLat(query_urlPart.lon, query_urlPart.lat),
				info : OpenLayers.i18n("Coordinates"),
				name : query_urlPart.lat + ", " + query_urlPart.lon,
				zoomCallback : function(map) {
					if(query_urlPart.zoom == undefined)
						return 15;
					else
						return 1*query_urlPart.zoom;
				}
			} ];
			callbackFunction(results);
		}
		else
			callbackFunction([ ]);
	},

	/**
	 * Returns an array of the position and length of an actual place that is searched for with the given query.
	 * If a name finder for example allows to search for supermarkets in London using the query string
	 * "supermarket, London, UK" then this function would return (13, 9) which is "London, UK" in that string.
	 * This is important for the auto-suggest feature as you only want to get suggestions for actual places, not
	 * for POIs that you search for.
	 * @param String query
	 * @return Array An array of offset and length of the location part or null if there is no such
	*/
	getLocationPart : function(query) {
		return [ 0, query.length ];
	},

	/**
	 * Initilise an auto-suggest feature on a text input field that will use this NameFinder.
	 *
	 * Creates the following properties on the input node:
	 * - fmAutocompleteTimeout
	 * - fmAutocompleteLoadingValue
	 * - fmAutocompleteLoadedValue
	 * - fmAutocompleteList
	 * - fmAutocompleteResults: The list of results returned by the namefinder
	 * - fmAutocompleteSelected
	 * @param Element input The DOM node of a text input field.
	 * @return void
	*/
	initAutoSuggest : function(input) {
		input.setAttribute("autocomplete", "off");

		// Opera fix
		input.style.position = "relative";

		var namefinder = this;

		OpenLayers.Event.observe(input, "keypress", OpenLayers.Function.bindAsEventListener(this._autoSuggestKeyPress, this));

		var clickOpener = OpenLayers.Function.bindAsEventListener(function() { this._openAutoSuggest(input); }, this);

		OpenLayers.Event.observe(input, "focus", OpenLayers.Function.bindAsEventListener(function(e){
			setTimeout(function(){ OpenLayers.Event.observe(input, "click", clickOpener); }, 150);
		}, this));
		OpenLayers.Event.observe(input, "blur", OpenLayers.Function.bindAsEventListener(function(e){
			OpenLayers.Event.stopObserving(input, "click", clickOpener);
		}, this));

		// Wait some time before closing the suggestion list on blur so that clicking the results still works
		OpenLayers.Event.observe(input, "blur", OpenLayers.Function.bindAsEventListener(function(){ setTimeout(function(){ namefinder._closeAutoSuggest(input); }, 150) }, this));
	},

	_autoSuggestKeyPress : function(e) {
		var input = e.target || e.srcElement;
		var namefinder = this;

		var kc_down = 40;
		var kc_up = 38;
		var kc_return = 13;
		var kc_enter = 14;
		var kc_escape = 27;

		if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey)
		{
			if(e.keyCode == kc_down || e.keyCode == kc_up)
			{
				this._openAutoSuggest(input);
				if(input.fmAutocompleteResults == null)
					return true;

				var currentIndex = -1;
				if(input.fmAutocompleteSelected != null)
				{
					this._unselectAutoSuggestItem(input, input.fmAutocompleteSelected);
					currentIndex = input.fmAutocompleteSelected.i;
					input.fmAutocompleteSelected = null;
				}

				if(currentIndex == -1)
					currentIndex = (e.keyCode == kc_up ? input.fmAutocompleteResults.length-1 : 0);
				else
				{
					currentIndex += (e.keyCode == kc_up ? -1 : 1);
					if(currentIndex < 0)
						currentIndex += input.fmAutocompleteResults.length;
					else if(currentIndex >= input.fmAutocompleteResults.length)
						currentIndex -= input.fmAutocompleteResults.length;
				}

				input.fmAutocompleteSelected = input.fmAutocompleteResults[currentIndex];
				this._selectAutoSuggestItem(input, input.fmAutocompleteSelected);

				OpenLayers.Event.stop(e);
				return false;
			}
			else if(e.keyCode == kc_return || e.keyCode == kc_enter)
			{
				if(input.fmAutocompleteSelected)
				{
					input.value = input.fmAutocompleteSelected.name;
					this._closeAutoSuggest(input);
					OpenLayers.Event.stop(e);
					return false;
				}
				else
				{
					if(input.fmAutocompleteTimeout != null)
						clearTimeout(input.fmAutocompleteTimeout);
					if(input.fmAutocompleteList && input.fmAutocompleteList.style.display != "none")
						this._closeAutoSuggest(input);
				}
				return true;
			}
			else if(e.keyCode == kc_escape)
			{
				if(input.fmAutocompleteList && input.fmAutocompleteList.style.display != "none")
				{
					this._closeAutoSuggest(input);
					OpenLayers.Event.stop(e);
					return false;
				}
			}
		}

		if(input.fmAutocompleteTimeout != null)
			clearTimeout(input.fmAutocompleteTimeout);
		input.fmAutocompleteTimeout = setTimeout(function(){ namefinder._openAutoSuggest(input); }, 500);
		return true;
	},

	_openAutoSuggest : function(input) {
		var offset = this.getLocationPart(input.value);
		var val = (offset == null ? input.value : input.value.substr(offset[0], offset[1]));
		var valOrig = input.value;

		if(input.fmAutocompleteLoadingValue != null && input.fmAutocompleteLoadingValue == val)
		{ // List is already present, only make it visible again
			if(input.fmAutocompleteList != null)
				input.fmAutocompleteList.style.display = "block";
			return;
		}

		if(val == "" || (offset == null || offset[1] < 3))
		{
			this._closeAutoSuggest(input);
			return;
		}

		var namefinder = this;
		input.fmAutocompleteLoadingValue = val;
		if(offset != null) // If null, there is no location part so no search is useful
			this.find(val, function(results){ input.fmAutocompleteLoadedValue = val; namefinder._openAutoSuggestResult(input, results, valOrig); });
	},

	_openAutoSuggestResult : function(input, results, value) {
		// Do not show list if loading has been aborted by _closeAutoSuggest() in the meantime
		if(input.fmAutocompleteLoadingValue == null || results == null)
			return;

		var namefinder = this;

		input.fmAutocompleteResults = results;

		if(input.fmAutocompleteList == null)
		{
			input.fmAutocompleteList = document.createElement("ol");
			input.fmAutocompleteList.className = "fmAutocomplete";
			input.fmAutocompleteList.style.position = "absolute";
			input.fmAutocompleteList.style.top = (input.offsetTop + input.offsetHeight) + "px";
			input.fmAutocompleteList.style.left = input.offsetLeft + "px";
			input.fmAutocompleteList.style.minWidth = input.offsetWidth + "px";
			input.parentNode.appendChild(input.fmAutocompleteList);
		}

		while(input.fmAutocompleteList.firstChild)
			input.fmAutocompleteList.removeChild(input.fmAutocompleteList.firstChild);

		var offset = this.getLocationPart(value);

		var foundSelection = false;
		for(var i=0; i<results.length; i++) (function(i)
		{
			var li = document.createElement("li");
			var name = document.createElement("strong");
			name.appendChild(document.createTextNode(results[i].name));
			results[i].name = value.substr(0, offset[0]) + results[i].name + value.substr(offset[0]+offset[1]);
			li.appendChild(name);
			li.appendChild(document.createTextNode(" (" + results[i].info + ")"));
			input.fmAutocompleteList.appendChild(li);
			results[i].li = li;
			results[i].i = i;
			if(!foundSelection && input.fmAutocompleteSelected != null && input.fmAutocompleteSelected.lonlat == results[i].lonlat && input.fmAutocompleteSelected.name == results[i].name && input.fmAutocompleteSelected.info == results[i].info)
			{
				namefinder._selectAutoSuggestItem(input, results[i]);
				input.fmAutocompleteSelected = results[i];
				foundSelection = true;
			}
			li.onmousemove = function() {
				if(input.fmAutocompleteSelected != null)
					namefinder._unselectAutoSuggestItem(input, input.fmAutocompleteSelected);
				input.fmAutocompleteSelected = results[i];
				namefinder._selectAutoSuggestItem(input, results[i]);
			};
			li.onclick = function() {
				input.value = results[i].name;
				namefinder._closeAutoSuggest(input);
			};
		})(i);

		if(!foundSelection)
			input.fmAutocompleteSelected = null;

		input.fmAutocompleteList.style.display = "block";
	},

	_closeAutoSuggest : function(input) {
		if(input.fmAutocompleteTimeout != null)
			clearTimeout(input.fmAutocompleteTimeout);

		// Prevent showing the list if find() is currently waiting for a response
		input.fmAutocompleteLoadingValue = null;

		if(input.fmAutocompleteList != null)
			input.fmAutocompleteList.style.display = "none";
		if(input.fmAutocompleteSelected != null)
		{
			this._unselectAutoSuggestItem(input, input.fmAutocompleteSelected);
			input.fmAutocompleteSelected = null;
		}
	},

	_selectAutoSuggestItem : function(input, item)
	{
		item.li.className = "selected";

		// Scroll to item
		var list = input.fmAutocompleteList;
		if(list == null || list.scrollTop == undefined)
			return;

		var itemTop = item.li.offsetTop;
		var itemBottom = itemTop + item.li.offsetHeight;

		if(itemTop < list.scrollTop) // Need to scroll up
			list.scrollTop = itemTop;
		else if(itemBottom > list.scrollTop + list.offsetHeight) // Need to scroll down
			list.scrollTop = itemBottom - list.offsetHeight;
	},

	_unselectAutoSuggestItem : function(input, item)
	{
		item.li.className = "";
	}
});<commit_msg>FS#51<commit_after>/*
	This file is part of FacilMap.

	FacilMap 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.

	FacilMap 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 FacilMap.  If not, see <http://www.gnu.org/licenses/>.

	Obtain the source code from http://gitorious.org/facilmap.
*/

/**
 * An abstract class whose implementations connect to a NameFinder.
*/
FacilMap.NameFinder = OpenLayers.Class({
	/**
	 * Perform a search through a NameFinder. This function itself does not connect to an actual NameFinder, it only finds one result if
	 * the query String consists of coordinates encoded in a Lat,Lon string or an OpenStreetMap Permalink.
	 * @param String query The query string.
	 * @param Function callbackFunction A function that is executed when the search has been performed. The function takes one argument that
	 *                                  contains an array with the results. It is undefined if an error has occurred. Each result is an object
	 *                                  with the following properties:
	 *                                  * OpenLayers.LonLat lonlat The coordinates of the result
	 *                                  * String name: The title of the result.
	 *                                  * String info: Some additional information about the result, such as the type.
	 *                                  * function getZoom(OpenLayers.Map): Returns the zoom level that the search result should be displayed at on the given map.
	 *                                  * Node osm: The associated OSM object or null.
	 * @return void
	*/
	find : function(query, callbackFunction) {
		query.replace(/^\s+/, "").replace(/\s+$/, "");
		var query_match;
		var query_urlPart;
		if(query_match = query.match(/^http:\/\/(www\.)?osm\.org\/go\/([-A-Za-z0-9_@]+)/))
		{ // Coordinates, shortlink
			var shortlink = FacilMap.Util.decodeShortLink(query_match[2]);
			results = [ {
				lonlat : shortlink.lonlat,
				info : OpenLayers.i18n("Coordinates"),
				name : shortlink.lonlat.lat + ", " + shortlink.lonlat.lon,
				getZoom : function(map) {
					return shortlink.zoom;
				}
			} ];
			callbackFunction(results);
		}
		else if(query_match = query.match(/^(-?\s*\d+([.,]\d+)?)\s*[,;]?\s*(-?\s*\d+([.,]\d+)?)$/))
		{ // Coordinates
			results = [ {
				lonlat : new OpenLayers.LonLat(query_match[3].replace(",", ".").replace(/\s+/, ""), query_match[1].replace(",", ".").replace(/\s+/, "")),
				info : OpenLayers.i18n("Coordinates"),
				getZoom : function(map) {
					return 15;
				}
			} ];
			results[0].name = results[0].lonlat.lat+","+results[0].lonlat.lon;
			callbackFunction(results);
		}
		else if((query_match = query.match(/^http:\/\/.*\?(.*)$/)) && typeof (query_urlPart = FacilMap.Util.decodeQueryString(query_match[1])).lon != "undefined" && typeof query_urlPart.lat != "undefined")
		{ // OpenStreetMap Permalink
			results = [ {
				lonlat : new OpenLayers.LonLat(query_urlPart.lon, query_urlPart.lat),
				info : OpenLayers.i18n("Coordinates"),
				name : query_urlPart.lat + ", " + query_urlPart.lon,
				zoomCallback : function(map) {
					if(query_urlPart.zoom == undefined)
						return 15;
					else
						return 1*query_urlPart.zoom;
				}
			} ];
			callbackFunction(results);
		}
		else
			callbackFunction([ ]);
	},

	/**
	 * Returns an array of the position and length of an actual place that is searched for with the given query.
	 * If a name finder for example allows to search for supermarkets in London using the query string
	 * "supermarket, London, UK" then this function would return (13, 9) which is "London, UK" in that string.
	 * This is important for the auto-suggest feature as you only want to get suggestions for actual places, not
	 * for POIs that you search for.
	 * @param String query
	 * @return Array An array of offset and length of the location part or null if there is no such
	*/
	getLocationPart : function(query) {
		return [ 0, query.length ];
	},

	/**
	 * Initilise an auto-suggest feature on a text input field that will use this NameFinder.
	 *
	 * Creates the following properties on the input node:
	 * - fmAutocompleteTimeout
	 * - fmAutocompleteLoadingValue
	 * - fmAutocompleteLoadedValue
	 * - fmAutocompleteList
	 * - fmAutocompleteResults: The list of results returned by the namefinder
	 * - fmAutocompleteSelected
	 * - fmAutocompletePrevious
	 * @param Element input The DOM node of a text input field.
	 * @return void
	*/
	initAutoSuggest : function(input) {
		input.setAttribute("autocomplete", "off");

		// Opera fix
		input.style.position = "relative";

		var namefinder = this;

		OpenLayers.Event.observe(input, "keypress", OpenLayers.Function.bindAsEventListener(this._autoSuggestKeyPress, this));

		var clickOpener = OpenLayers.Function.bindAsEventListener(function() { this._openAutoSuggest(input); }, this);

		OpenLayers.Event.observe(input, "focus", OpenLayers.Function.bindAsEventListener(function(e){
			setTimeout(function(){ OpenLayers.Event.observe(input, "click", clickOpener); }, 150);
		}, this));
		OpenLayers.Event.observe(input, "blur", OpenLayers.Function.bindAsEventListener(function(e){
			OpenLayers.Event.stopObserving(input, "click", clickOpener);
		}, this));

		// Wait some time before closing the suggestion list on blur so that clicking the results still works
		OpenLayers.Event.observe(input, "blur", OpenLayers.Function.bindAsEventListener(function(){ setTimeout(function(){ namefinder._closeAutoSuggest(input); }, 150) }, this));
	},

	_autoSuggestKeyPress : function(e) {
		var input = e.target || e.srcElement;
		var namefinder = this;

		var kc_down = 40;
		var kc_up = 38;
		var kc_return = 13;
		var kc_enter = 14;
		var kc_escape = 27;

		if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey)
		{
			if(e.keyCode == kc_down || e.keyCode == kc_up)
			{
				this._openAutoSuggest(input);
				if(input.fmAutocompleteResults == null)
					return true;

				var currentIndex = -1;
				if(input.fmAutocompleteSelected != null)
				{
					this._unselectAutoSuggestItem(input, input.fmAutocompleteSelected);
					currentIndex = input.fmAutocompleteSelected.i;
					input.fmAutocompleteSelected = null;
				}

				if(currentIndex == -1)
					currentIndex = (e.keyCode == kc_up ? input.fmAutocompleteResults.length-1 : 0);
				else
				{
					currentIndex += (e.keyCode == kc_up ? -1 : 1);
					if(currentIndex < 0)
						currentIndex += input.fmAutocompleteResults.length;
					else if(currentIndex >= input.fmAutocompleteResults.length)
						currentIndex -= input.fmAutocompleteResults.length;
				}

				input.fmAutocompleteSelected = input.fmAutocompleteResults[currentIndex];
				this._selectAutoSuggestItem(input, input.fmAutocompleteSelected);

				OpenLayers.Event.stop(e);
				return false;
			}
			else if(e.keyCode == kc_return || e.keyCode == kc_enter)
			{
				if(input.fmAutocompleteSelected)
				{
					input.value = input.fmAutocompleteSelected.name;
					this._closeAutoSuggest(input);
					OpenLayers.Event.stop(e);
					return false;
				}
				else
				{
					if(input.fmAutocompleteTimeout != null)
						clearTimeout(input.fmAutocompleteTimeout);
					if(input.fmAutocompleteList && input.fmAutocompleteList.style.display != "none")
						this._closeAutoSuggest(input);
				}
				return true;
			}
			else if(e.keyCode == kc_escape)
			{
				if(input.fmAutocompleteList && input.fmAutocompleteList.style.display != "none")
				{
					this._closeAutoSuggest(input);
					OpenLayers.Event.stop(e);
					return false;
				}
			}
		}

		if(input.fmAutocompletePrevious == input.value)
			return true;
		input.fmAutocompletePrevious = input.value;

		if(input.fmAutocompleteTimeout != null)
			clearTimeout(input.fmAutocompleteTimeout);
		input.fmAutocompleteTimeout = setTimeout(function(){ namefinder._openAutoSuggest(input); }, 500);
		return true;
	},

	_openAutoSuggest : function(input) {
		input.fmAutocompletePrevious = input.value;

		var offset = this.getLocationPart(input.value);
		var val = (offset == null ? input.value : input.value.substr(offset[0], offset[1]));
		var valOrig = input.value;

		if(input.fmAutocompleteLoadingValue != null && input.fmAutocompleteLoadingValue == val)
		{ // List is already present, only make it visible again
			if(input.fmAutocompleteList != null)
				input.fmAutocompleteList.style.display = "block";
			return;
		}

		if(val == "" || (offset == null || offset[1] < 3))
		{
			this._closeAutoSuggest(input);
			return;
		}

		var namefinder = this;
		input.fmAutocompleteLoadingValue = val;
		if(offset != null) // If null, there is no location part so no search is useful
			this.find(val, function(results){ input.fmAutocompleteLoadedValue = val; namefinder._openAutoSuggestResult(input, results, valOrig); });
	},

	_openAutoSuggestResult : function(input, results, value) {
		// Do not show list if loading has been aborted by _closeAutoSuggest() in the meantime
		if(input.fmAutocompleteLoadingValue == null || results == null)
			return;

		var namefinder = this;

		input.fmAutocompleteResults = results;

		if(input.fmAutocompleteList == null)
		{
			input.fmAutocompleteList = document.createElement("ol");
			input.fmAutocompleteList.className = "fmAutocomplete";
			input.fmAutocompleteList.style.position = "absolute";
			input.fmAutocompleteList.style.top = (input.offsetTop + input.offsetHeight) + "px";
			input.fmAutocompleteList.style.left = input.offsetLeft + "px";
			input.fmAutocompleteList.style.minWidth = input.offsetWidth + "px";
			input.parentNode.appendChild(input.fmAutocompleteList);
		}

		while(input.fmAutocompleteList.firstChild)
			input.fmAutocompleteList.removeChild(input.fmAutocompleteList.firstChild);

		var offset = this.getLocationPart(value);

		var foundSelection = false;
		for(var i=0; i<results.length; i++) (function(i)
		{
			var li = document.createElement("li");
			var name = document.createElement("strong");
			name.appendChild(document.createTextNode(results[i].name));
			results[i].name = value.substr(0, offset[0]) + results[i].name + value.substr(offset[0]+offset[1]);
			li.appendChild(name);
			li.appendChild(document.createTextNode(" (" + results[i].info + ")"));
			input.fmAutocompleteList.appendChild(li);
			results[i].li = li;
			results[i].i = i;
			if(!foundSelection && input.fmAutocompleteSelected != null && input.fmAutocompleteSelected.lonlat == results[i].lonlat && input.fmAutocompleteSelected.name == results[i].name && input.fmAutocompleteSelected.info == results[i].info)
			{
				namefinder._selectAutoSuggestItem(input, results[i]);
				input.fmAutocompleteSelected = results[i];
				foundSelection = true;
			}
			li.onmousemove = function() {
				if(input.fmAutocompleteSelected != null)
					namefinder._unselectAutoSuggestItem(input, input.fmAutocompleteSelected);
				input.fmAutocompleteSelected = results[i];
				namefinder._selectAutoSuggestItem(input, results[i]);
			};
			li.onclick = function() {
				input.value = results[i].name;
				namefinder._closeAutoSuggest(input);
			};
		})(i);

		if(!foundSelection)
			input.fmAutocompleteSelected = null;

		input.fmAutocompleteList.style.display = "block";
	},

	_closeAutoSuggest : function(input) {
		if(input.fmAutocompleteTimeout != null)
			clearTimeout(input.fmAutocompleteTimeout);

		// Prevent showing the list if find() is currently waiting for a response
		input.fmAutocompleteLoadingValue = null;

		if(input.fmAutocompleteList != null)
			input.fmAutocompleteList.style.display = "none";
		if(input.fmAutocompleteSelected != null)
		{
			this._unselectAutoSuggestItem(input, input.fmAutocompleteSelected);
			input.fmAutocompleteSelected = null;
		}
	},

	_selectAutoSuggestItem : function(input, item)
	{
		item.li.className = "selected";

		// Scroll to item
		var list = input.fmAutocompleteList;
		if(list == null || list.scrollTop == undefined)
			return;

		var itemTop = item.li.offsetTop;
		var itemBottom = itemTop + item.li.offsetHeight;

		if(itemTop < list.scrollTop) // Need to scroll up
			list.scrollTop = itemTop;
		else if(itemBottom > list.scrollTop + list.offsetHeight) // Need to scroll down
			list.scrollTop = itemBottom - list.offsetHeight;
	},

	_unselectAutoSuggestItem : function(input, item)
	{
		item.li.className = "";
	}
});<|endoftext|>


<commit_before>var B = require('../index.js').Buffer
var test = require('tape')

test('new buffer from array', function (t) {
  t.equal(
    new B([1, 2, 3]).toString(),
    '\u0001\u0002\u0003'
  )
  t.end()
})

test('new buffer from string', function (t) {
  t.plan(1)
  t.equal(
    new B('hey', 'utf8').toString(),
    'hey'
  )
  t.end()
})

test('buffer toArrayBuffer()', function (t) {
  var data = [1, 2, 3, 4, 5, 6, 7, 8]
  if (typeof (new B(data)).toArrayBuffer === 'function') {
    var result = new B(data).toArrayBuffer()
    var expected = new Uint8Array(data).buffer
    for (var i = 0; i < expected.length; i++) {
      t.equal(result[i], expected[i])
    }
  } else {
    t.pass('No toArrayBuffer() method provided in old browsers')
  }
  t.end()
})

test('buffer toJSON()', function (t) {
  t.plan(1)
  var data = [1, 2, 3, 4]
  t.deepEqual(
    new B(data).toJSON(),
    { type: 'Buffer', data: [1,2,3,4] }
  )
  t.end()
})

test('buffer copy example', function (t) {
  t.plan(1)

  buf1 = new B(26)
  buf2 = new B(26)

  for (var i = 0 ; i < 26 ; i++) {
    buf1[i] = i + 97; // 97 is ASCII a
    buf2[i] = 33; // ASCII !
  }

  buf1.copy(buf2, 8, 16, 20)

  t.equal(
    buf2.toString('ascii', 0, 25),
    '!!!!!!!!qrst!!!!!!!!!!!!!'
  )
  t.end()
})
<commit_msg>fix toArrayBuffer() test so it will run on Firefox<commit_after>var B = require('../index.js').Buffer
var test = require('tape')

test('new buffer from array', function (t) {
  t.equal(
    new B([1, 2, 3]).toString(),
    '\u0001\u0002\u0003'
  )
  t.end()
})

test('new buffer from string', function (t) {
  t.plan(1)
  t.equal(
    new B('hey', 'utf8').toString(),
    'hey'
  )
  t.end()
})

test('buffer toArrayBuffer()', function (t) {
  var data = [1, 2, 3, 4, 5, 6, 7, 8]
  if (typeof Uint8Array === 'function') {
    var result = new B(data).toArrayBuffer()
    var expected = new Uint8Array(data).buffer
    for (var i = 0; i < expected.byteLength; i++) {
      t.equal(result[i], expected[i])
    }
  } else {
    t.pass('No toArrayBuffer() method provided in old browsers')
  }
  t.end()
})

test('buffer toJSON()', function (t) {
  t.plan(1)
  var data = [1, 2, 3, 4]
  t.deepEqual(
    new B(data).toJSON(),
    { type: 'Buffer', data: [1,2,3,4] }
  )
  t.end()
})

test('buffer copy example', function (t) {
  t.plan(1)

  buf1 = new B(26)
  buf2 = new B(26)

  for (var i = 0 ; i < 26 ; i++) {
    buf1[i] = i + 97; // 97 is ASCII a
    buf2[i] = 33; // ASCII !
  }

  buf1.copy(buf2, 8, 16, 20)

  t.equal(
    buf2.toString('ascii', 0, 25),
    '!!!!!!!!qrst!!!!!!!!!!!!!'
  )
  t.end()
})
<|endoftext|>