<commit_before>/** @jsx React.DOM */
var React = require('react');

var ProjectStore = require('../stores/ProjectStore');
var ItemStore = require('../stores/ItemStore');
var ProjectActions = require('../actions/ProjectActions');
var ItemActions = require('../actions/ItemActions');
var Project = require('./Project.react');
var Loading = require('./Loading.react');
var ItemList = require('./ItemList.react');
var Router = require("react-router");
var Link = Router.Link;

function getProjectShowState (id, items, state)  {
  var title, description;
  var item = state.items[ItemStore.getEditingItemId()];
  var object = state;
  if (item !== null && typeof item !== "undefined") {
    object = item;
  }
  title = object.title;
  description = object.description;
  return {
    project: ProjectStore.findById(id),
    items: items,
    title: title,
    description: description,
    renderItemForm: ItemStore.getShowFormState()
  };
}

var ProjectShow = React.createClass({
  mixins: [ Router.State ],
  closeForm: function () {
    ItemActions.closeForm();
  },
  componentDidMount: function () {
    var id = this.getParams().id;
    ProjectActions.getProjectInformation(id);
    ProjectStore.addChangeListener(this._onChange);
    ItemStore.addChangeListener(this._onChange);
  },

  componentDidUpdate: function () {
    var maxheight = 0;
    $('.itemlists div').each(function () {
      maxheight = Math.max(maxheight, $(this).height());
    });

    console.log(maxheight);

    $('.itemlists div').css('height', maxheight + 'px');
  },

  componentWillUnmount: function () {
    ProjectStore.removeChangeListener(this._onChange);
    ItemStore.removeChangeListener(this._onChange);
  },

  eachItem: function (fn) {
    for (var id in this.state.items) {
      if (this.state.items.hasOwnProperty(id)) {
        var item = this.state.items[id];
        fn(item, id);
      }
    }
  },

  getInitialState: function () {
    return {
      title: "",
      description: null,
      project: null,
      items: [],
      editItem: null,
      focusTodo: true
    };
  },

  handleChange: function (key) {
    return function (e) {
      var state = {};
      state[key] = e.target.value;
      this.setState(state);
    }.bind(this);
  },

  newItem: function (e) {
    e.preventDefault();
    ItemActions.newItem();
    this.setState({
      title: "",
      description: ""
    });
  },

  _onChange: function () {
    this.setState(getProjectShowState(ProjectStore.getSetId(), ItemStore.getItems(), this.state));
  },

  render: function () {
    if (this.state.project !== null) {
      var handler, formTitle;
      if (ItemStore.getEditingItemId() === null) {
        handler = this.saveItem;
        formTitle = "New Item";
      }
      else {
        handler = this.updateItem;
        formTitle = "Editing Item";
      }
      var newItemHref = "/projects/" + this.state.project.id + "/items/new";
      var todoItems = [];
      var progressItems = [];
      var completedItems = [];
      var _this = this;
      this.eachItem(function (item, id) {
        if (item.state === "todo") {
          todoItems.push(item);
        }
        else if (item.state === "inprogress") {
          progressItems.push(item);
        }
        else if (item.state === "completed") {
          completedItems.push(item);
        }
      });

      var form = null;
      if (this.state.renderItemForm) {
        var style = { left: $('.todo-items').offset().left + "px" };
        form = (

            <form onSubmit={handler}>

{formTitle}

                <input type="text" id="title" onChange={this.handleChange("title")} placeholder="Title" value={this.state.title} />

                <textarea id="description" rows="4" onChange={this.handleChange("description")} value={this.state.description} />

                <input type="submit" />

            </form>

        );
      }

      return (

{this.state.project.title}

            <Link to="app">Home</Link>
            <Link to="projects">Projects</Link>
            {this.state.project.title}

            New Item

              To Do
              In Progress
              Completed

                <ItemList items={todoItems} state="todo" />

                <ItemList items={progressItems} state="inprogress" />

                <ItemList items={completedItems} state="completed" />

          {form}

      );
    }
    else {
      return (

          <Loading />

      );
    }
  },

  saveItem: function (e) {
    e.preventDefault();
    ItemActions.createItem(this.state);
  },

  toggleCompleted: function () {
    this.setState({
      focusTodo: true,
      focusInprogress: false,
      focusCompleted: true
    });
  },

  toggleProgress: function () {
    this.setState({
      focusTodo: false,
      focusInprogress: true,
      focusCompleted: false
    });
  },

  toggleTodo: function () {
    this.setState({
      focusTodo: true,
      focusInprogress: false,
      focusCompleted: false
    });
  },

  updateItem: function (e) {
    e.preventDefault();
    ItemActions.updateItem({ title: this.state.title, description: this.state.description, id: ItemStore.getEditingItemId() });
  }
});

module.exports = ProjectShow;<commit_msg>fixes complete focus bug<commit_after>/** @jsx React.DOM */
var React = require('react');

var ProjectStore = require('../stores/ProjectStore');
var ItemStore = require('../stores/ItemStore');
var ProjectActions = require('../actions/ProjectActions');
var ItemActions = require('../actions/ItemActions');
var Project = require('./Project.react');
var Loading = require('./Loading.react');
var ItemList = require('./ItemList.react');
var Router = require("react-router");
var Link = Router.Link;

function getProjectShowState (id, items, state)  {
  var title, description;
  var item = state.items[ItemStore.getEditingItemId()];
  var object = state;
  if (item !== null && typeof item !== "undefined") {
    object = item;
  }
  title = object.title;
  description = object.description;
  return {
    project: ProjectStore.findById(id),
    items: items,
    title: title,
    description: description,
    renderItemForm: ItemStore.getShowFormState()
  };
}

var ProjectShow = React.createClass({
  mixins: [ Router.State ],
  closeForm: function () {
    ItemActions.closeForm();
  },
  componentDidMount: function () {
    var id = this.getParams().id;
    ProjectActions.getProjectInformation(id);
    ProjectStore.addChangeListener(this._onChange);
    ItemStore.addChangeListener(this._onChange);
  },

  componentDidUpdate: function () {
    var maxheight = 0;
    $('.itemlists div').each(function () {
      maxheight = Math.max(maxheight, $(this).height());
    });

    console.log(maxheight);

    $('.itemlists div').css('height', maxheight + 'px');
  },

  componentWillUnmount: function () {
    ProjectStore.removeChangeListener(this._onChange);
    ItemStore.removeChangeListener(this._onChange);
  },

  eachItem: function (fn) {
    for (var id in this.state.items) {
      if (this.state.items.hasOwnProperty(id)) {
        var item = this.state.items[id];
        fn(item, id);
      }
    }
  },

  getInitialState: function () {
    return {
      title: "",
      description: null,
      project: null,
      items: [],
      editItem: null,
      focusTodo: true
    };
  },

  handleChange: function (key) {
    return function (e) {
      var state = {};
      state[key] = e.target.value;
      this.setState(state);
    }.bind(this);
  },

  newItem: function (e) {
    e.preventDefault();
    ItemActions.newItem();
    this.setState({
      title: "",
      description: ""
    });
  },

  _onChange: function () {
    this.setState(getProjectShowState(ProjectStore.getSetId(), ItemStore.getItems(), this.state));
  },

  render: function () {
    if (this.state.project !== null) {
      var handler, formTitle;
      if (ItemStore.getEditingItemId() === null) {
        handler = this.saveItem;
        formTitle = "New Item";
      }
      else {
        handler = this.updateItem;
        formTitle = "Editing Item";
      }
      var newItemHref = "/projects/" + this.state.project.id + "/items/new";
      var todoItems = [];
      var progressItems = [];
      var completedItems = [];
      var _this = this;
      this.eachItem(function (item, id) {
        if (item.state === "todo") {
          todoItems.push(item);
        }
        else if (item.state === "inprogress") {
          progressItems.push(item);
        }
        else if (item.state === "completed") {
          completedItems.push(item);
        }
      });

      var form = null;
      if (this.state.renderItemForm) {
        var style = { left: $('.todo-items').offset().left + "px" };
        form = (

            <form onSubmit={handler}>

{formTitle}

                <input type="text" id="title" onChange={this.handleChange("title")} placeholder="Title" value={this.state.title} />

                <textarea id="description" rows="4" onChange={this.handleChange("description")} value={this.state.description} />

                <input type="submit" />

            </form>

        );
      }

      return (

{this.state.project.title}

            <Link to="app">Home</Link>
            <Link to="projects">Projects</Link>
            {this.state.project.title}

            New Item

              To Do
              In Progress
              Completed

                <ItemList items={todoItems} state="todo" />

                <ItemList items={progressItems} state="inprogress" />

                <ItemList items={completedItems} state="completed" />

          {form}

      );
    }
    else {
      return (

          <Loading />

      );
    }
  },

  saveItem: function (e) {
    e.preventDefault();
    ItemActions.createItem(this.state);
  },

  toggleCompleted: function () {
    this.setState({
      focusTodo: false,
      focusInprogress: false,
      focusCompleted: true
    });
  },

  toggleProgress: function () {
    this.setState({
      focusTodo: false,
      focusInprogress: true,
      focusCompleted: false
    });
  },

  toggleTodo: function () {
    this.setState({
      focusTodo: true,
      focusInprogress: false,
      focusCompleted: false
    });
  },

  updateItem: function (e) {
    e.preventDefault();
    ItemActions.updateItem({ title: this.state.title, description: this.state.description, id: ItemStore.getEditingItemId() });
  }
});

module.exports = ProjectShow;<|endoftext|>


<commit_before>'use strict';

// Calendarevents controller
angular.module('calendarevents').controller('CalendareventsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Calendarevents',
    function($scope, $stateParams, $location, Authentication, Calendarevents) {
        $scope.authentication = Authentication;

        // Create new Calendarevent
        $scope.create = function() {
            // Create new Calendarevent object
            var calendarevent = new Calendarevents({
                name: this.name,
                description: this.description,
                startDate: this.startDate,
                endDate: this.endDate
            });

            // Redirect after save
            calendarevent.$save(function(response) {
                $location.path('calendarevents/' + response._id);

                // Clear form fields
                $scope.name = '';
                $scope.description = '';
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
            });
        };

        // Remove existing Calendarevent
        $scope.remove = function(calendarevent) {
            if (calendarevent) {
                calendarevent.$remove();

                for (var i in $scope.calendarevents) {
                    if ($scope.calendarevents[i] === calendarevent) {
                        $scope.calendarevents.splice(i, 1);
                    }
                }
            } else {
                $scope.calendarevent.$remove(function() {
                    $location.path('calendarevents');
                });
            }
        };

        // Update existing Calendarevent
        $scope.update = function() {
            var calendarevent = $scope.calendarevent;

            calendarevent.$update(function() {
                $location.path('calendarevents/' + calendarevent._id);
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
            });
        };

        // Find a list of Calendarevents
        $scope.find = function() {
            $scope.calendarevents = Calendarevents.query();
        };

        // Find existing Calendarevent
        $scope.findOne = function() {
            $scope.calendarevent = Calendarevents.get({
                calendareventId: $stateParams.calendareventId
            });
        };

        $scope.participate = function(calendarevent) {
            console.log(calendarevent.participants);
            var exists=false;
            for(var i = 0; i < calendarevent.participants.length; i++) {
                if (Authentication.user._id === calendarevent.participants[i]){
                    exists=true;
                    calendarevent.participants.splice(i,1);
                }
            }
            if (exists==false){
                calendarevent.participants.push(Authentication.user._id);
            }

            calendarevent.$update(function() {
                //successfull
            }, function(errorResponse) {
                console.log('error...');
                $scope.error = errorResponse.data.message;
            });
        };

        function getDay(d){
            var days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
            return days[d.getDay()];
        };

        function getDate(d){
            return d.getDate().toString()+"."+(1+d.getMonth()).toString()+"."+d.getFullYear().toString();
        };
        function getTime(d){
            return d.toLocaleTimeString();
        };

        $scope.getDateString = function(date){
            if (date===undefined){
                return '';
            }
            var d = new Date(date);
            return getDay(d)+' '+getDate(d)+' '+getTime(d);
        };

    }
]);
<commit_msg>remove warnings<commit_after>'use strict';

// Calendarevents controller
angular.module('calendarevents').controller('CalendareventsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Calendarevents',
    function($scope, $stateParams, $location, Authentication, Calendarevents) {
        $scope.authentication = Authentication;

        // Create new Calendarevent
        $scope.create = function() {
            // Create new Calendarevent object
            var calendarevent = new Calendarevents({
                name: this.name,
                description: this.description,
                startDate: this.startDate,
                endDate: this.endDate
            });

            // Redirect after save
            calendarevent.$save(function(response) {
                $location.path('calendarevents/' + response._id);

                // Clear form fields
                $scope.name = '';
                $scope.description = '';
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
            });
        };

        // Remove existing Calendarevent
        $scope.remove = function(calendarevent) {
            if (calendarevent) {
                calendarevent.$remove();

                for (var i in $scope.calendarevents) {
                    if ($scope.calendarevents[i] === calendarevent) {
                        $scope.calendarevents.splice(i, 1);
                    }
                }
            } else {
                $scope.calendarevent.$remove(function() {
                    $location.path('calendarevents');
                });
            }
        };

        // Update existing Calendarevent
        $scope.update = function() {
            var calendarevent = $scope.calendarevent;

            calendarevent.$update(function() {
                $location.path('calendarevents/' + calendarevent._id);
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
            });
        };

        // Find a list of Calendarevents
        $scope.find = function() {
            $scope.calendarevents = Calendarevents.query();
        };

        // Find existing Calendarevent
        $scope.findOne = function() {
            $scope.calendarevent = Calendarevents.get({
                calendareventId: $stateParams.calendareventId
            });
        };

        $scope.participate = function(calendarevent) {
            console.log(calendarevent.participants);
            var exists=false;
            for(var i = 0; i < calendarevent.participants.length; i++) {
                if (Authentication.user._id === calendarevent.participants[i]){
                    exists=true;
                    calendarevent.participants.splice(i,1);
                }
            }
            if (exists===false){
                calendarevent.participants.push(Authentication.user._id);
            }

            calendarevent.$update(function() {
                //successfull
            }, function(errorResponse) {
                console.log('error...');
                $scope.error = errorResponse.data.message;
            });
        };

        function getDay(d){
            var days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
            return days[d.getDay()];
        }

        function getDate(d){
            return d.getDate().toString()+'.'+(1+d.getMonth()).toString()+'.'+d.getFullYear().toString();
        }
        function getTime(d){
            return d.toLocaleTimeString();
        }

        $scope.getDateString = function(date){
            if (date===undefined){
                return '';
            }
            var d = new Date(date);
            return getDay(d)+' '+getDate(d)+' '+getTime(d);
        };

    }
]);
<|endoftext|>


<commit_before>Router.route('/order/:_id', function () {
  this.render('Order', {
    data: function () {
      return Orders.findOne({_id: this.params._id});
    }
  });
});

Template.Order.helpers({
  settings: function() {
    var order = this;
    return {
      collection: Resources.find(),
      showFilter: false,
      showNavigation: 'never',
      rowsPerPage: 100,
      rowClass: function(resource) {
        return order.cssClass(resource);
      },
      fields: [
        'subject',
        'title',
        'quantity',
        {
          key: 'action',
          label: 'Action',
          tmpl: Template.orderResourceAction
        },
        {
          key: 'sold',
          label: 'Sold',
          tmpl: Template.orderResourceSold
        }
      ]
    };
  },
  resources: function () {
    return Resources.find();
  }
});

Template.Order.events({
  'click .reactive-table tr': function (event) {
    event.preventDefault();
    var resource = this;
    var order = Template.currentData();
    // checks if the actual clicked element has the class `delete`
    switch (event.target.className) {
      case 'fa fa-trash': order.remove(resource); break;
      case 'fa fa-cart-plus': order.add(resource); break;
      case 'checkbox': order.sell(resource); break;
    }
  }
});

Template.Order.onRendered(function(){
  var self = this;
  self.autorun(function () {
    var data = Template.currentData(self.view);
    if (data) {
      Session.set('courseId', data.getCourse()._id);
    }
  });
});

Template.orderResourceSold.onRendered(function() {
  if (!this.rendered){
    // Disable the already sold resources
    $('input:checked').attr('disabled', true);
    this.rendered = true;
  }
});

Template.orderResourceAction.helpers({
  icon: function () {
    var resource = this;
    var order = Template.parentData(5);
    if(order.ordered(resource)) {
      if (order.isSold(resource) || order.definitiveState()) {
        return '';
      } else {
        return 'fa-trash';
      }
    } else {
      return 'fa-cart-plus';
    }
  }
});

Template.orderResourceSold.helpers({
  isSold: function () {
    var resource = this;
    var order = Template.parentData(5);
    return order.isSold(resource);
  },
  disabled: function () {
    var resource = this;
    var order = Template.parentData(5);
    return order.cssClass(resource);
  }
});

Template.orderAction.events({
  'click .btn': function (event) {
    event.stopPropagation();
    event.preventDefault();
    if (event.target.className.contains('Contact')) {
      this.contact();
    }
  }
});

Template.orderActionBar.events({
  'click #cancel': function() {
    Session.set('intent', 'cancel');
    $('#confirmAction').modal();
  }
});

Template.confirmAction.events({
  'click #confirm': function () {
    var intent = Session.get('intent');
    var order = this;
    if (intent === 'cancel') {
      Orders.update(order._id, {
        $set: {
          state: 'canceled'
        }
      });
    } else if (intent === 'sellLastResource') {
      order.sell(Resources.findOne(Session.get('lastResourceId')), true);
    } else {
      order.remove(Resources.findOne(Session.get('lastResourceId')), true);
    }
    $('#confirmAction').modal('hide');
  }
});

Template.confirmAction.helpers({
  content: function() {
    var intent = Session.get('intent');
    if (intent === 'cancel') {
      return 'You are about to cancel this order.';
    } else {
      return 'You are about to finalize this order.';
    }
  }
});
<commit_msg>Shows availability<commit_after>Router.route('/order/:_id', function () {
  this.render('Order', {
    data: function () {
      return Orders.findOne({_id: this.params._id});
    }
  });
});

Template.Order.helpers({
  settings: function() {
    var order = this;
    return {
      collection: Resources.find(),
      showFilter: false,
      showNavigation: 'never',
      rowsPerPage: 100,
      rowClass: function(resource) {
        return order.cssClass(resource);
      },
      fields: [
        'subject',
        'title',
        {
          key: 'quantity',
          label: 'Quantity',
          fn: function(value, resource) {
            return resource.availability() + ' (' + resource.quantity + ' in stock)';
          }
        },
        {
          key: 'action',
          label: 'Action',
          tmpl: Template.orderResourceAction
        },
        {
          key: 'sold',
          label: 'Sold',
          tmpl: Template.orderResourceSold
        }
      ]
    };
  },
  resources: function () {
    return Resources.find();
  }
});

Template.Order.events({
  'click .reactive-table tr': function (event) {
    event.preventDefault();
    var resource = this;
    var order = Template.currentData();
    // checks if the actual clicked element has the class `delete`
    switch (event.target.className) {
      case 'fa fa-trash': order.remove(resource); break;
      case 'fa fa-cart-plus': order.add(resource); break;
      case 'checkbox': order.sell(resource); break;
    }
  }
});

Template.Order.onRendered(function(){
  var self = this;
  self.autorun(function () {
    var data = Template.currentData(self.view);
    if (data) {
      Session.set('courseId', data.getCourse()._id);
    }
  });
});

Template.orderResourceSold.onRendered(function() {
  if (!this.rendered){
    // Disable the already sold resources
    $('input:checked').attr('disabled', true);
    this.rendered = true;
  }
});

Template.orderResourceAction.helpers({
  icon: function () {
    var resource = this;
    var order = Template.parentData(5);
    if(order.ordered(resource)) {
      if (order.isSold(resource) || order.definitiveState()) {
        return '';
      } else {
        return 'fa-trash';
      }
    } else {
      return 'fa-cart-plus';
    }
  }
});

Template.orderResourceSold.helpers({
  isSold: function () {
    var resource = this;
    var order = Template.parentData(5);
    return order.isSold(resource);
  },
  disabled: function () {
    var resource = this;
    var order = Template.parentData(5);
    return order.cssClass(resource);
  }
});

Template.orderAction.events({
  'click .btn': function (event) {
    event.stopPropagation();
    event.preventDefault();
    if (event.target.className.contains('Contact')) {
      this.contact();
    }
  }
});

Template.orderActionBar.events({
  'click #cancel': function() {
    Session.set('intent', 'cancel');
    $('#confirmAction').modal();
  }
});

Template.confirmAction.events({
  'click #confirm': function () {
    var intent = Session.get('intent');
    var order = this;
    if (intent === 'cancel') {
      Orders.update(order._id, {
        $set: {
          state: 'canceled'
        }
      });
    } else if (intent === 'sellLastResource') {
      order.sell(Resources.findOne(Session.get('lastResourceId')), true);
    } else {
      order.remove(Resources.findOne(Session.get('lastResourceId')), true);
    }
    $('#confirmAction').modal('hide');
  }
});

Template.confirmAction.helpers({
  content: function() {
    var intent = Session.get('intent');
    if (intent === 'cancel') {
      return 'You are about to cancel this order.';
    } else {
      return 'You are about to finalize this order.';
    }
  }
});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ReactDOM = require('react-dom')

const windowActions = require('../actions/windowActions')
const ImmutableComponent = require('./immutableComponent')

const config = require('../constants/config')
const top500 = require('./../data/top500')
const {aboutUrls, isNavigatableAboutPage, isSourceAboutUrl, isUrl} = require('../lib/appUrlUtil')
const Immutable = require('immutable')
const debounce = require('../lib/debounce')
const settings = require('../constants/settings')
const siteTags = require('../constants/siteTags')
const suggestionTypes = require('../constants/suggestionTypes')
const getSetting = require('../settings').getSetting
const eventUtil = require('../lib/eventUtil')
const cx = require('../lib/classSet')
const locale = require('../l10n')
const windowStore = require('../stores/windowStore')
const suggestion = require('../../app/renderer/lib/suggestion')

class UrlBarSuggestions extends ImmutableComponent {
  constructor (props) {
    super(props)
    this.searchXHR = debounce(this.searchXHR.bind(this), 50)
  }

  get activeFrame () {
    return windowStore.getFrame(this.props.activeFrameKey)
  }

  get activeIndex () {
    if (this.props.suggestionList === null) {
      return 0
    }
    return Math.abs(this.props.selectedIndex % (this.props.suggestionList.size + 1))
  }

  nextSuggestion () {
    // If the user presses down and don't have an explicit selected index, skip to the 2nd one
    if (this.props.locationValueSuffix && this.props.selectedIndex === null && this.props.suggestionList.size > 1) {
      this.updateSuggestions(2)
      return
    }

    this.updateSuggestions(this.props.selectedIndex + 1)
  }

  previousSuggestion () {
    const suggestions = this.props.suggestionList
    if (!suggestions) {
      return
    }

    let newIndex = this.props.selectedIndex - 1
    if (newIndex < 0) {
      newIndex = suggestions.size
    }
    this.updateSuggestions(newIndex)
  }

  blur () {
    window.removeEventListener('click', this)
    windowActions.setUrlBarSuggestions(null, null)
    windowActions.setUrlBarPreview(null)
  }

  clickSelected (e) {
    this.ctrlKey = e.ctrlKey
    this.metaKey = e.metaKey
    this.shiftKey = e.shiftKey
    const node = ReactDOM.findDOMNode(this)
    if (node) {
      node.getElementsByClassName('selected')[0].click()
    }
  }

  // Whether the suggestions box should be rendered
  shouldRender () {
    return this.props.suggestionList && this.props.suggestionList.size > 0
  }

  render () {
    window.removeEventListener('click', this)

    if (!this.shouldRender()) {
      return null
    }

    // Add an event listener on the window to hide suggestions when they are shown.
    window.addEventListener('click', this)

    // If there is a URL suffix that means there's an active autocomplete for the first element.
    // We should show that as selected so the user knows what is being matched.

    const suggestions = this.props.suggestionList
    const bookmarkSuggestions = suggestions.filter((s) => s.type === suggestionTypes.BOOKMARK)
    const historySuggestions = suggestions.filter((s) => s.type === suggestionTypes.HISTORY)
    const aboutPagesSuggestions = suggestions.filter((s) => s.type === suggestionTypes.ABOUT_PAGES)
    const tabSuggestions = suggestions.filter((s) => s.type === suggestionTypes.TAB)
    const searchSuggestions = suggestions.filter((s) => s.type === suggestionTypes.SEARCH)
    const topSiteSuggestions = suggestions.filter((s) => s.type === suggestionTypes.TOP_SITE)

    let items = []
    let index = 0
    const addToItems = (suggestions, sectionKey, title, icon) => {
      if (suggestions.size > 0) {
        items.push(

          {
            icon
            ?
            : null
          }
          {title}

)
      }
      items = items.concat(suggestions.map((suggestion, i) => {
        const currentIndex = index + i
        const selected = this.activeIndex === currentIndex + 1 || (!this.activeIndex && currentIndex === 0 && this.props.locationValueSuffix)
        return <li data-index={currentIndex + 1}
          onMouseOver={this.onMouseOver.bind(this)}
          onClick={suggestion.onClick}
          key={`${suggestion.location}|${index + i}`}
          ref={(node) => { selected && (this.selectedElement = node) }}
          className={cx({
            selected,
            suggestionItem: true,
            [suggestion.type]: true
          })}>
          {
            suggestion.type !== suggestionTypes.TOP_SITE && suggestion.title
            ?
{suggestion.title}

            : null
          }
          {
            suggestion.type !== suggestionTypes.SEARCH && suggestion.type !== suggestionTypes.ABOUT_PAGES
            ?
{suggestion.location}

            : null
          }

      }))
      index += suggestions.size
    }
    addToItems(historySuggestions, 'historyTitle', locale.translation('historySuggestionTitle'), 'fa-clock-o')
    addToItems(bookmarkSuggestions, 'bookmarksTitle', locale.translation('bookmarksSuggestionTitle'), 'fa-star-o')
    addToItems(aboutPagesSuggestions, 'aboutPagesTitle', locale.translation('aboutPagesSuggestionTitle'), null)
    addToItems(tabSuggestions, 'tabsTitle', locale.translation('tabsSuggestionTitle'), 'fa-external-link')
    addToItems(searchSuggestions, 'searchTitle', locale.translation('searchSuggestionTitle'), 'fa-search')
    addToItems(topSiteSuggestions, 'topSiteTitle', locale.translation('topSiteSuggestionTitle'), 'fa-link')
    const documentHeight = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--navbar-height'), 10)
    const menuHeight = this.props.menubarVisible ? 30 : 0
    return

      {items}

  }

  onMouseOver (e) {
    this.updateSuggestions(parseInt(e.target.dataset.index, 10))
  }

  componentDidMount () {
    if (this.props.urlLocation.length > 0) {
      this.suggestionList = this.getNewSuggestionList(this.props)
      this.searchXHR(this.props, true)
    }
  }

  componentWillUpdate (nextProps) {
    if (this.selectedElement) {
      this.selectedElement.scrollIntoView()
    }
    // If both the URL is the same and the number of sites to consider is
    // the same then we don't need to regenerate the suggestions list.
    if (this.props.urlLocation === nextProps.urlLocation &&
        this.props.sites.size === nextProps.sites.size &&
        // Make sure to update if there are online suggestions
        this.props.searchResults.size === nextProps.searchResults.size) {
      return
    }
    this.suggestionList = this.getNewSuggestionList(nextProps)
    this.searchXHR(nextProps, !(this.props.urlLocation === nextProps.urlLocation))
  }

  getNewSuggestionList (props) {
    props = props || this.props
    if (!props.urlLocation && !props.urlPreview) {
      return null
    }

    const navigateClickHandler = (formatUrl) => (site, e) => {
      // We have a wonky way of fake clicking from keyboard enter,
      // so remove the meta keys from the real event here.
      e.metaKey = e.metaKey || this.metaKey
      e.ctrlKey = e.ctrlKey || this.ctrlKey
      e.shiftKey = e.shiftKey || this.shiftKey
      delete this.metaKey
      delete this.ctrlKey
      delete this.shiftKey

      const location = formatUrl(site)
      // When clicked make sure to hide autocomplete
      windowActions.setRenderUrlBarSuggestions(false)
      if (eventUtil.isForSecondaryAction(e)) {
        windowActions.newFrame({
          location,
          partitionNumber: site && site.get && site.get('partitionNumber') || undefined
        }, !!e.shiftKey)
        e.preventDefault()
        windowActions.setNavBarFocused(true)
      } else {
        windowActions.loadUrl(this.activeFrame, location)
        windowActions.setUrlBarActive(false)
        windowActions.setUrlBarPreview(null)
        this.blur()
      }
    }

    const urlLocationLower = props.urlLocation.toLowerCase()
    let suggestions = new Immutable.List()
    const defaultme = (x) => x
    const mapListToElements = ({data, maxResults, type, clickHandler = navigateClickHandler,
        sortHandler = defaultme, formatTitle = defaultme, formatUrl = defaultme,
        filterValue = (site) => site.toLowerCase().includes(urlLocationLower)
    }) => // Filter out things which are already in our own list at a smaller index
      data
      // Per suggestion provider filter
      .filter(filterValue)
      // Filter out things which are already in the suggestions list
      .filter((site) =>
        suggestions.findIndex((x) => (x.location || '').toLowerCase() === (formatUrl(site) || '').toLowerCase()) === -1 ||
          // Tab autosuggestions should always be included since they will almost always be in history
          type === suggestionTypes.TAB)
      .sort(sortHandler)
      .take(maxResults)
      .map((site) => {
        return {
          onClick: clickHandler.bind(null, site),
          title: formatTitle(site),
          location: formatUrl(site),
          type
        }
      })

    const sortBasedOnLocationPos = (s1, s2) => {
      const location1 = suggestion.normalizeLocation(s1.get('location'))
      const location2 = suggestion.normalizeLocation(s2.get('location'))
      const pos1 = location1.indexOf(urlLocationLower)
      const pos2 = location2.indexOf(urlLocationLower)
      if (pos1 === -1 && pos2 === -1) {
        return 0
      } else if (pos1 === -1) {
        return 1
      } else if (pos2 === -1) {
        return -1
      } else {
        if (pos1 - pos2 !== 0) {
          return pos1 - pos2
        } else {
          // sort site.com higher than site.com/somepath
          const sdnv1 = suggestion.simpleDomainNameValue(s1)
          const sdnv2 = suggestion.simpleDomainNameValue(s2)
          if (sdnv1 !== sdnv2) {
            return sdnv2 - sdnv1
          } else {
            // If there's a tie on the match location, use the age
            // decay modified access count
            return suggestion.sortByAccessCountWithAgeDecay(s1, s2)
          }
        }
      }
    }

    const historyFilter = (site) => {
      const title = site.get('title') || ''
      const location = site.get('location') || ''
      // Note: Bookmark sites are now included in history. This will allow
      // sites to appear in the auto-complete regardless of their bookmark
      // status. If history is turned off, bookmarked sites will appear
      // in the bookmark section.
      return (title.toLowerCase().includes(urlLocationLower) ||
              location.toLowerCase().includes(urlLocationLower)) &&
              site.get('lastAccessedTime')
    }
    var historySites = props.sites.filter(historyFilter)

    // potentially append virtual history items (such as www.google.com when
    // searches have been made but the root site has not been visited)
    historySites = historySites.concat(suggestion.createVirtualHistoryItems(historySites))

    // history
    if (getSetting(settings.HISTORY_SUGGESTIONS)) {
      suggestions = suggestions.concat(mapListToElements({
        data: historySites,
        maxResults: config.urlBarSuggestions.maxHistorySites,
        type: suggestionTypes.HISTORY,
        clickHandler: navigateClickHandler((site) => {
          return site.get('location')
        }),
        sortHandler: sortBasedOnLocationPos,
        formatTitle: (site) => site.get('title'),
        formatUrl: (site) => site.get('location'),
        filterValue: historyFilter
      }))
    }

    // bookmarks
    if (getSetting(settings.BOOKMARK_SUGGESTIONS)) {
      suggestions = suggestions.concat(mapListToElements({
        data: props.sites,
        maxResults: config.urlBarSuggestions.maxBookmarkSites,
        type: suggestionTypes.BOOKMARK,
        clickHandler: navigateClickHandler((site) => {
          return site.get('location')
        }),
        sortHandler: sortBasedOnLocationPos,
        formatTitle: (site) => site.get('title'),
        formatUrl: (site) => site.get('location'),
        filterValue: (site) => {
          const title = site.get('title') || ''
          const location = site.get('location') || ''
          return (title.toLowerCase().includes(urlLocationLower) ||
            location.toLowerCase().includes(urlLocationLower)) &&
            site.get('tags') && site.get('tags').includes(siteTags.BOOKMARK)
        }
      }))
    }

    // about pages
    suggestions = suggestions.concat(mapListToElements({
      data: aboutUrls.keySeq().filter((x) => isNavigatableAboutPage(x)),
      maxResults: config.urlBarSuggestions.maxAboutPages,
      type: suggestionTypes.ABOUT_PAGES,
      clickHandler: navigateClickHandler((x) => x)}))

    // opened frames
    if (getSetting(settings.OPENED_TAB_SUGGESTIONS)) {
      suggestions = suggestions.concat(mapListToElements({
        data: windowStore.getFrames(),
        maxResults: config.urlBarSuggestions.maxOpenedFrames,
        type: suggestionTypes.TAB,
        clickHandler: (frameProps) =>
          windowActions.setActiveFrame(frameProps),
        sortHandler: sortBasedOnLocationPos,
        formatTitle: (frame) => frame.get('title'),
        formatUrl: (frame) => frame.get('location'),
        filterValue: (frame) => !isSourceAboutUrl(frame.get('location')) &&
          frame.get('key') !== props.activeFrameKey &&
          (frame.get('title') && frame.get('title').toLowerCase().includes(urlLocationLower) ||
          frame.get('location') && frame.get('location').toLowerCase().includes(urlLocationLower))}))
    }

    // Search suggestions
    if (getSetting(settings.OFFER_SEARCH_SUGGESTIONS) && props.searchResults) {
      suggestions = suggestions.concat(mapListToElements({
        data: props.searchResults,
        maxResults: config.urlBarSuggestions.maxSearch,
        type: suggestionTypes.SEARCH,
        clickHandler: navigateClickHandler((searchTerms) => {
          let searchURL = props.searchSelectEntry
          ? props.searchSelectEntry.search : props.searchDetail.get('searchURL')
          return searchURL.replace('{searchTerms}', encodeURIComponent(searchTerms))
        })
      }))
    }

    // Alexa top 500
    suggestions = suggestions.concat(mapListToElements({
      data: top500,
      maxResults: config.urlBarSuggestions.maxTopSites,
      type: suggestionTypes.TOP_SITE,
      clickHandler: navigateClickHandler((x) => x)}))

    return suggestions
  }

  updateSuggestions (newIndex) {
    const suggestions = this.suggestionList || this.props.suggestionList
    if (!suggestions) {
      return
    }
    // Update the urlbar preview content
    if (newIndex === 0 || newIndex > suggestions.size) {
      windowActions.setUrlBarPreview(null)
      newIndex = null
    } else {
      const currentActive = suggestions.get(newIndex - 1)
      if (currentActive && currentActive.title) {
        windowActions.setUrlBarPreview(currentActive.title)
      }
    }
    windowActions.setUrlBarSuggestions(suggestions, newIndex)
  }

  searchXHR (props, searchOnline) {
    props = props || this.props
    let autocompleteURL = props.searchSelectEntry
    ? props.searchSelectEntry.autocomplete : props.searchDetail.get('autocompleteURL')
    if (!getSetting(settings.OFFER_SEARCH_SUGGESTIONS) || !autocompleteURL) {
      windowActions.setUrlBarSuggestionSearchResults(Immutable.fromJS([]))
      this.updateSuggestions(props.selectedIndex)
      return
    }

    let urlLocation = props.urlLocation
    if (!isUrl(urlLocation) && urlLocation.length > 0) {
      if (props.searchSelectEntry) {
        const replaceRE = new RegExp('^' + props.searchSelectEntry.shortcut + ' ', 'g')
        urlLocation = urlLocation.replace(replaceRE, '')
      }
      // Render all suggestions asap
      this.updateSuggestions(props.selectedIndex)

      if (searchOnline) {
        const xhr = new window.XMLHttpRequest({mozSystem: true})
        xhr.open('GET', autocompleteURL
          .replace('{searchTerms}', encodeURIComponent(urlLocation)), true)
        xhr.responseType = 'json'
        xhr.send()
        xhr.onload = () => {
          // Once we have the online suggestions, append them to the others
          windowActions.setUrlBarSuggestionSearchResults(Immutable.fromJS(xhr.response[1]))
          this.updateSuggestions(props.selectedIndex)
        }
      }
    } else {
      windowActions.setUrlBarSuggestionSearchResults(Immutable.fromJS([]))
      this.updateSuggestions(props.selectedIndex)
    }
  }
}

module.exports = UrlBarSuggestions
<commit_msg>Work-around for error where history filtering using Immutable.Map() was occasionally passing "undefined" to the filter function. With the error in place, it didn't seem to break functionality, it just logged the error.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ReactDOM = require('react-dom')

const windowActions = require('../actions/windowActions')
const ImmutableComponent = require('./immutableComponent')

const config = require('../constants/config')
const top500 = require('./../data/top500')
const {aboutUrls, isNavigatableAboutPage, isSourceAboutUrl, isUrl} = require('../lib/appUrlUtil')
const Immutable = require('immutable')
const debounce = require('../lib/debounce')
const settings = require('../constants/settings')
const siteTags = require('../constants/siteTags')
const suggestionTypes = require('../constants/suggestionTypes')
const getSetting = require('../settings').getSetting
const eventUtil = require('../lib/eventUtil')
const cx = require('../lib/classSet')
const locale = require('../l10n')
const windowStore = require('../stores/windowStore')
const suggestion = require('../../app/renderer/lib/suggestion')

class UrlBarSuggestions extends ImmutableComponent {
  constructor (props) {
    super(props)
    this.searchXHR = debounce(this.searchXHR.bind(this), 50)
  }

  get activeFrame () {
    return windowStore.getFrame(this.props.activeFrameKey)
  }

  get activeIndex () {
    if (this.props.suggestionList === null) {
      return 0
    }
    return Math.abs(this.props.selectedIndex % (this.props.suggestionList.size + 1))
  }

  nextSuggestion () {
    // If the user presses down and don't have an explicit selected index, skip to the 2nd one
    if (this.props.locationValueSuffix && this.props.selectedIndex === null && this.props.suggestionList.size > 1) {
      this.updateSuggestions(2)
      return
    }

    this.updateSuggestions(this.props.selectedIndex + 1)
  }

  previousSuggestion () {
    const suggestions = this.props.suggestionList
    if (!suggestions) {
      return
    }

    let newIndex = this.props.selectedIndex - 1
    if (newIndex < 0) {
      newIndex = suggestions.size
    }
    this.updateSuggestions(newIndex)
  }

  blur () {
    window.removeEventListener('click', this)
    windowActions.setUrlBarSuggestions(null, null)
    windowActions.setUrlBarPreview(null)
  }

  clickSelected (e) {
    this.ctrlKey = e.ctrlKey
    this.metaKey = e.metaKey
    this.shiftKey = e.shiftKey
    const node = ReactDOM.findDOMNode(this)
    if (node) {
      node.getElementsByClassName('selected')[0].click()
    }
  }

  // Whether the suggestions box should be rendered
  shouldRender () {
    return this.props.suggestionList && this.props.suggestionList.size > 0
  }

  render () {
    window.removeEventListener('click', this)

    if (!this.shouldRender()) {
      return null
    }

    // Add an event listener on the window to hide suggestions when they are shown.
    window.addEventListener('click', this)

    // If there is a URL suffix that means there's an active autocomplete for the first element.
    // We should show that as selected so the user knows what is being matched.

    const suggestions = this.props.suggestionList
    const bookmarkSuggestions = suggestions.filter((s) => s.type === suggestionTypes.BOOKMARK)
    const historySuggestions = suggestions.filter((s) => s.type === suggestionTypes.HISTORY)
    const aboutPagesSuggestions = suggestions.filter((s) => s.type === suggestionTypes.ABOUT_PAGES)
    const tabSuggestions = suggestions.filter((s) => s.type === suggestionTypes.TAB)
    const searchSuggestions = suggestions.filter((s) => s.type === suggestionTypes.SEARCH)
    const topSiteSuggestions = suggestions.filter((s) => s.type === suggestionTypes.TOP_SITE)

    let items = []
    let index = 0
    const addToItems = (suggestions, sectionKey, title, icon) => {
      if (suggestions.size > 0) {
        items.push(

          {
            icon
            ?
            : null
          }
          {title}

)
      }
      items = items.concat(suggestions.map((suggestion, i) => {
        const currentIndex = index + i
        const selected = this.activeIndex === currentIndex + 1 || (!this.activeIndex && currentIndex === 0 && this.props.locationValueSuffix)
        return <li data-index={currentIndex + 1}
          onMouseOver={this.onMouseOver.bind(this)}
          onClick={suggestion.onClick}
          key={`${suggestion.location}|${index + i}`}
          ref={(node) => { selected && (this.selectedElement = node) }}
          className={cx({
            selected,
            suggestionItem: true,
            [suggestion.type]: true
          })}>
          {
            suggestion.type !== suggestionTypes.TOP_SITE && suggestion.title
            ?
{suggestion.title}

            : null
          }
          {
            suggestion.type !== suggestionTypes.SEARCH && suggestion.type !== suggestionTypes.ABOUT_PAGES
            ?
{suggestion.location}

            : null
          }

      }))
      index += suggestions.size
    }
    addToItems(historySuggestions, 'historyTitle', locale.translation('historySuggestionTitle'), 'fa-clock-o')
    addToItems(bookmarkSuggestions, 'bookmarksTitle', locale.translation('bookmarksSuggestionTitle'), 'fa-star-o')
    addToItems(aboutPagesSuggestions, 'aboutPagesTitle', locale.translation('aboutPagesSuggestionTitle'), null)
    addToItems(tabSuggestions, 'tabsTitle', locale.translation('tabsSuggestionTitle'), 'fa-external-link')
    addToItems(searchSuggestions, 'searchTitle', locale.translation('searchSuggestionTitle'), 'fa-search')
    addToItems(topSiteSuggestions, 'topSiteTitle', locale.translation('topSiteSuggestionTitle'), 'fa-link')
    const documentHeight = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--navbar-height'), 10)
    const menuHeight = this.props.menubarVisible ? 30 : 0
    return

      {items}

  }

  onMouseOver (e) {
    this.updateSuggestions(parseInt(e.target.dataset.index, 10))
  }

  componentDidMount () {
    if (this.props.urlLocation.length > 0) {
      this.suggestionList = this.getNewSuggestionList(this.props)
      this.searchXHR(this.props, true)
    }
  }

  componentWillUpdate (nextProps) {
    if (this.selectedElement) {
      this.selectedElement.scrollIntoView()
    }
    // If both the URL is the same and the number of sites to consider is
    // the same then we don't need to regenerate the suggestions list.
    if (this.props.urlLocation === nextProps.urlLocation &&
        this.props.sites.size === nextProps.sites.size &&
        // Make sure to update if there are online suggestions
        this.props.searchResults.size === nextProps.searchResults.size) {
      return
    }
    this.suggestionList = this.getNewSuggestionList(nextProps)
    this.searchXHR(nextProps, !(this.props.urlLocation === nextProps.urlLocation))
  }

  getNewSuggestionList (props) {
    props = props || this.props
    if (!props.urlLocation && !props.urlPreview) {
      return null
    }

    const navigateClickHandler = (formatUrl) => (site, e) => {
      // We have a wonky way of fake clicking from keyboard enter,
      // so remove the meta keys from the real event here.
      e.metaKey = e.metaKey || this.metaKey
      e.ctrlKey = e.ctrlKey || this.ctrlKey
      e.shiftKey = e.shiftKey || this.shiftKey
      delete this.metaKey
      delete this.ctrlKey
      delete this.shiftKey

      const location = formatUrl(site)
      // When clicked make sure to hide autocomplete
      windowActions.setRenderUrlBarSuggestions(false)
      if (eventUtil.isForSecondaryAction(e)) {
        windowActions.newFrame({
          location,
          partitionNumber: site && site.get && site.get('partitionNumber') || undefined
        }, !!e.shiftKey)
        e.preventDefault()
        windowActions.setNavBarFocused(true)
      } else {
        windowActions.loadUrl(this.activeFrame, location)
        windowActions.setUrlBarActive(false)
        windowActions.setUrlBarPreview(null)
        this.blur()
      }
    }

    const urlLocationLower = props.urlLocation.toLowerCase()
    let suggestions = new Immutable.List()
    const defaultme = (x) => x
    const mapListToElements = ({data, maxResults, type, clickHandler = navigateClickHandler,
        sortHandler = defaultme, formatTitle = defaultme, formatUrl = defaultme,
        filterValue = (site) => site.toLowerCase().includes(urlLocationLower)
    }) => // Filter out things which are already in our own list at a smaller index
      data
      // Per suggestion provider filter
      .filter(filterValue)
      // Filter out things which are already in the suggestions list
      .filter((site) =>
        suggestions.findIndex((x) => (x.location || '').toLowerCase() === (formatUrl(site) || '').toLowerCase()) === -1 ||
          // Tab autosuggestions should always be included since they will almost always be in history
          type === suggestionTypes.TAB)
      .sort(sortHandler)
      .take(maxResults)
      .map((site) => {
        return {
          onClick: clickHandler.bind(null, site),
          title: formatTitle(site),
          location: formatUrl(site),
          type
        }
      })

    const sortBasedOnLocationPos = (s1, s2) => {
      const location1 = suggestion.normalizeLocation(s1.get('location'))
      const location2 = suggestion.normalizeLocation(s2.get('location'))
      const pos1 = location1.indexOf(urlLocationLower)
      const pos2 = location2.indexOf(urlLocationLower)
      if (pos1 === -1 && pos2 === -1) {
        return 0
      } else if (pos1 === -1) {
        return 1
      } else if (pos2 === -1) {
        return -1
      } else {
        if (pos1 - pos2 !== 0) {
          return pos1 - pos2
        } else {
          // sort site.com higher than site.com/somepath
          const sdnv1 = suggestion.simpleDomainNameValue(s1)
          const sdnv2 = suggestion.simpleDomainNameValue(s2)
          if (sdnv1 !== sdnv2) {
            return sdnv2 - sdnv1
          } else {
            // If there's a tie on the match location, use the age
            // decay modified access count
            return suggestion.sortByAccessCountWithAgeDecay(s1, s2)
          }
        }
      }
    }

    const historyFilter = (site) => {
      if (!site) {
        return false
      }
      const title = site.get('title') || ''
      const location = site.get('location') || ''
      // Note: Bookmark sites are now included in history. This will allow
      // sites to appear in the auto-complete regardless of their bookmark
      // status. If history is turned off, bookmarked sites will appear
      // in the bookmark section.
      return (title.toLowerCase().includes(urlLocationLower) ||
              location.toLowerCase().includes(urlLocationLower)) &&
              site.get('lastAccessedTime')
    }
    var historySites = props.sites.filter(historyFilter)

    // potentially append virtual history items (such as www.google.com when
    // searches have been made but the root site has not been visited)
    historySites = historySites.concat(suggestion.createVirtualHistoryItems(historySites))

    // history
    if (getSetting(settings.HISTORY_SUGGESTIONS)) {
      suggestions = suggestions.concat(mapListToElements({
        data: historySites,
        maxResults: config.urlBarSuggestions.maxHistorySites,
        type: suggestionTypes.HISTORY,
        clickHandler: navigateClickHandler((site) => {
          return site.get('location')
        }),
        sortHandler: sortBasedOnLocationPos,
        formatTitle: (site) => site.get('title'),
        formatUrl: (site) => site.get('location'),
        filterValue: historyFilter
      }))
    }

    // bookmarks
    if (getSetting(settings.BOOKMARK_SUGGESTIONS)) {
      suggestions = suggestions.concat(mapListToElements({
        data: props.sites,
        maxResults: config.urlBarSuggestions.maxBookmarkSites,
        type: suggestionTypes.BOOKMARK,
        clickHandler: navigateClickHandler((site) => {
          return site.get('location')
        }),
        sortHandler: sortBasedOnLocationPos,
        formatTitle: (site) => site.get('title'),
        formatUrl: (site) => site.get('location'),
        filterValue: (site) => {
          const title = site.get('title') || ''
          const location = site.get('location') || ''
          return (title.toLowerCase().includes(urlLocationLower) ||
            location.toLowerCase().includes(urlLocationLower)) &&
            site.get('tags') && site.get('tags').includes(siteTags.BOOKMARK)
        }
      }))
    }

    // about pages
    suggestions = suggestions.concat(mapListToElements({
      data: aboutUrls.keySeq().filter((x) => isNavigatableAboutPage(x)),
      maxResults: config.urlBarSuggestions.maxAboutPages,
      type: suggestionTypes.ABOUT_PAGES,
      clickHandler: navigateClickHandler((x) => x)}))

    // opened frames
    if (getSetting(settings.OPENED_TAB_SUGGESTIONS)) {
      suggestions = suggestions.concat(mapListToElements({
        data: windowStore.getFrames(),
        maxResults: config.urlBarSuggestions.maxOpenedFrames,
        type: suggestionTypes.TAB,
        clickHandler: (frameProps) =>
          windowActions.setActiveFrame(frameProps),
        sortHandler: sortBasedOnLocationPos,
        formatTitle: (frame) => frame.get('title'),
        formatUrl: (frame) => frame.get('location'),
        filterValue: (frame) => !isSourceAboutUrl(frame.get('location')) &&
          frame.get('key') !== props.activeFrameKey &&
          (frame.get('title') && frame.get('title').toLowerCase().includes(urlLocationLower) ||
          frame.get('location') && frame.get('location').toLowerCase().includes(urlLocationLower))}))
    }

    // Search suggestions
    if (getSetting(settings.OFFER_SEARCH_SUGGESTIONS) && props.searchResults) {
      suggestions = suggestions.concat(mapListToElements({
        data: props.searchResults,
        maxResults: config.urlBarSuggestions.maxSearch,
        type: suggestionTypes.SEARCH,
        clickHandler: navigateClickHandler((searchTerms) => {
          let searchURL = props.searchSelectEntry
          ? props.searchSelectEntry.search : props.searchDetail.get('searchURL')
          return searchURL.replace('{searchTerms}', encodeURIComponent(searchTerms))
        })
      }))
    }

    // Alexa top 500
    suggestions = suggestions.concat(mapListToElements({
      data: top500,
      maxResults: config.urlBarSuggestions.maxTopSites,
      type: suggestionTypes.TOP_SITE,
      clickHandler: navigateClickHandler((x) => x)}))

    return suggestions
  }

  updateSuggestions (newIndex) {
    const suggestions = this.suggestionList || this.props.suggestionList
    if (!suggestions) {
      return
    }
    // Update the urlbar preview content
    if (newIndex === 0 || newIndex > suggestions.size) {
      windowActions.setUrlBarPreview(null)
      newIndex = null
    } else {
      const currentActive = suggestions.get(newIndex - 1)
      if (currentActive && currentActive.title) {
        windowActions.setUrlBarPreview(currentActive.title)
      }
    }
    windowActions.setUrlBarSuggestions(suggestions, newIndex)
  }

  searchXHR (props, searchOnline) {
    props = props || this.props
    let autocompleteURL = props.searchSelectEntry
    ? props.searchSelectEntry.autocomplete : props.searchDetail.get('autocompleteURL')
    if (!getSetting(settings.OFFER_SEARCH_SUGGESTIONS) || !autocompleteURL) {
      windowActions.setUrlBarSuggestionSearchResults(Immutable.fromJS([]))
      this.updateSuggestions(props.selectedIndex)
      return
    }

    let urlLocation = props.urlLocation
    if (!isUrl(urlLocation) && urlLocation.length > 0) {
      if (props.searchSelectEntry) {
        const replaceRE = new RegExp('^' + props.searchSelectEntry.shortcut + ' ', 'g')
        urlLocation = urlLocation.replace(replaceRE, '')
      }
      // Render all suggestions asap
      this.updateSuggestions(props.selectedIndex)

      if (searchOnline) {
        const xhr = new window.XMLHttpRequest({mozSystem: true})
        xhr.open('GET', autocompleteURL
          .replace('{searchTerms}', encodeURIComponent(urlLocation)), true)
        xhr.responseType = 'json'
        xhr.send()
        xhr.onload = () => {
          // Once we have the online suggestions, append them to the others
          windowActions.setUrlBarSuggestionSearchResults(Immutable.fromJS(xhr.response[1]))
          this.updateSuggestions(props.selectedIndex)
        }
      }
    } else {
      windowActions.setUrlBarSuggestionSearchResults(Immutable.fromJS([]))
      this.updateSuggestions(props.selectedIndex)
    }
  }
}

module.exports = UrlBarSuggestions
<|endoftext|>


<commit_before>'use strict';

mdrSearchApp.controller('SearchController',
    function SearchController($scope, $route, dataProvider) {
        dataProvider.getMembers().then(function(members) {
            $scope.members = members;
        });

        $scope.myData = [{
                "name": "Cox",
                "gender": "Carney",
                "company": "Enormo",
                "employed": "sdsdfgsdfg"
            },{
                "name": "Lorraine",
                "gender": "Wise",
                "company": "Comveyer",
                "employed": "sdgsdf"
            },{
                "name": "Nancy",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "pesho",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "gosho",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "secret",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "kiro",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "stefan",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": " ",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "aaa",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "1",
                "gender": "Carney",
                "company": "Enormo",
                "employed": "sdsdfgsdfg"
            },{
                "name": "2",
                "gender": "Wise",
                "company": "Comveyer",
                "employed": "sdgsdf"
            },{
                "name": "3",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "4",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "5",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "6",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "7",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "8",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "9",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "10",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            }];

        //
        $scope.gridOptions = {
            enableGridMenu: true,
            enablePagination: true,
            enablePaginationControls: true,
            paginationPageSizes: [5, 7, 9],
            paginationPageSize: 3,
            columnDefs: [
                { name: 'name' },
                { name: 'gender' },
                { name: 'company' },
                { name: 'employed'}
            ]
        };

        $scope.gridOptions2 = {
            enablePaginationControls: false,
            paginationPageSize: 25,
            columnDefs: [
                { name: 'name' },
                { name: 'gender' },
                { name: 'company' }
            ]
        };
        $scope.gridOptions.data = $scope.myData;
    }
);<commit_msg>comment local query<commit_after>'use strict';

mdrSearchApp.controller('SearchController',
    function SearchController($scope, $route, dataProvider) {
        //dataProvider.getMembers().then(function(members) {
        //    $scope.members = members;
        //});

        $scope.myData = [{
                "name": "Cox",
                "gender": "Carney",
                "company": "Enormo",
                "employed": "sdsdfgsdfg"
            },{
                "name": "Lorraine",
                "gender": "Wise",
                "company": "Comveyer",
                "employed": "sdgsdf"
            },{
                "name": "Nancy",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "pesho",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "gosho",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "secret",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "kiro",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "stefan",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": " ",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "aaa",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "1",
                "gender": "Carney",
                "company": "Enormo",
                "employed": "sdsdfgsdfg"
            },{
                "name": "2",
                "gender": "Wise",
                "company": "Comveyer",
                "employed": "sdgsdf"
            },{
                "name": "3",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "4",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "5",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "6",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "7",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "8",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "9",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            },{
                "name": "10",
                "gender": "Waters",
                "company": "Fuelton",
                "employed": "sdfg"
            }];

        //
        $scope.gridOptions = {
            enableGridMenu: true,
            enablePagination: true,
            enablePaginationControls: true,
            paginationPageSizes: [5, 7, 9],
            paginationPageSize: 3,
            columnDefs: [
                { name: 'name' },
                { name: 'gender' },
                { name: 'company' },
                { name: 'employed'}
            ]
        };

        $scope.gridOptions2 = {
            enablePaginationControls: false,
            paginationPageSize: 25,
            columnDefs: [
                { name: 'name' },
                { name: 'gender' },
                { name: 'company' }
            ]
        };
        $scope.gridOptions.data = $scope.myData;
    }
);<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router({mergeParams: true});
var config = require("../config.js");
var _ = require('lodash');
var utils = require('../utils');
var middlewares = require('./middlewares');

var ProjectPackage = require('../models/projectPackage');
var resHelper = require('../response_codes');
var Bid = require('../models/bid');

var dbInterface     = require("../db_interface.js");
var C               = require("../constants");

var getDbColOptions = function(req){
	return {account: req.params.account, project: req.params.project};
}

//Every API list below has to log in to access
router.use(middlewares.loggedIn);

// Create a package
router.post('/packages.json', middlewares.isMainContractor, createPackage);
// Get a package by name
router.get('/packages/:packageName.json', hasReadPackageAccess, findPackage);

function createPackage(req, res, next) {
	'use strict';

	let place = '/:account/:project/packages.json POST';

	// Instantiate a model
	let projectPackage = ProjectPackage.createInstance(getDbColOptions(req));

	let whitelist = ['name', 'site', 'budget', 'completedBy'];

	projectPackage = utils.writeCleanedBodyToModel(whitelist, req.body, projectPackage);

	projectPackage.save().then(projectPackage => {
		resHelper.respond(place, req, res, next, resHelper.OK, projectPackage);

	}).catch(err => {
		let errCode = utils.mongoErrorToResCode(err);
		resHelper.respond(place, req, res, next, errCode, err);

	});

}

function findPackage(req, res, next){
	'use strict';

	let place = '/:account/:project/package/:packageName.json GET';

	ProjectPackage.findByName(getDbColOptions(req), req.params.packageName).then(projectPackage => {
		if(projectPackage){
			resHelper.respond(place, req, res, next, resHelper.OK, projectPackage);
		} else {
			resHelper.respond(place, req, res, next, resHelper.PACKAGE_NOT_FOUND);
		}
	}).catch(err => {
		let errCode = utils.mongoErrorToResCode(err);
		resHelper.respond(place, req, res, next, errCode, err);

	});

}

// packages/* specific middlewares
function hasReadPackageAccess(req, res, next){
	middlewares.checkRole([C.REPO_ROLE_SUBCONTRACTOR, C.REPO_ROLE_MAINCONTRACTOR], req).then((roles) => {
		// if role is maincontractor then no more check is needed

		if(roles.indexOf(C.REPO_ROLE_MAINCONTRACTOR) !== -1){
			return Promise.resolve();
		} else {
			return middlewares.isSubContractorInvitedHelper(req);
		}

	}).then(() => {
		next();
	}).catch(resCode => {
		resHelper.respond("Middleware: check has read access", req, res, next, resCode, null, req.params);
	});
}

module.exports = router;<commit_msg>listproject api<commit_after>var express = require('express');
var router = express.Router({mergeParams: true});
var config = require("../config.js");
var _ = require('lodash');
var utils = require('../utils');
var middlewares = require('./middlewares');

var ProjectPackage = require('../models/projectPackage');
var resHelper = require('../response_codes');
var Bid = require('../models/bid');

var dbInterface     = require("../db_interface.js");
var C               = require("../constants");

var getDbColOptions = function(req){
	return {account: req.params.account, project: req.params.project};
}

//Every API list below has to log in to access
router.use(middlewares.loggedIn);

// Create a package
router.post('/packages.json', middlewares.isMainContractor, createPackage);
// Get all packages
router.get('/packages.json', middlewares.isMainContractor, listPackages);
// Get a package by name
router.get('/packages/:packageName.json', hasReadPackageAccess, findPackage);

function createPackage(req, res, next) {
	'use strict';

	let place = '/:account/:project/packages.json POST';

	// Instantiate a model
	let projectPackage = ProjectPackage.createInstance(getDbColOptions(req));

	let whitelist = ['name', 'site', 'budget', 'completedBy'];

	projectPackage = utils.writeCleanedBodyToModel(whitelist, req.body, projectPackage);

	projectPackage.save().then(projectPackage => {
		resHelper.respond(place, req, res, next, resHelper.OK, projectPackage);

	}).catch(err => {
		let errCode = utils.mongoErrorToResCode(err);
		resHelper.respond(place, req, res, next, errCode, err);

	});

}

function findPackage(req, res, next){
	'use strict';

	let place = '/:account/:project/packages/:packageName.json GET';

	ProjectPackage.findByName(getDbColOptions(req), req.params.packageName).then(projectPackage => {
		if(projectPackage){
			resHelper.respond(place, req, res, next, resHelper.OK, projectPackage);
		} else {
			resHelper.respond(place, req, res, next, resHelper.PACKAGE_NOT_FOUND);
		}
	}).catch(err => {
		let errCode = utils.mongoErrorToResCode(err);
		resHelper.respond(place, req, res, next, errCode, err);

	});

}

function listPackages(req, res, next){
	'use strict';

	let place = '/:account/:project/packages.json GET';

	ProjectPackage.find(getDbColOptions(req)).then(projectPackages => {
		resHelper.respond(place, req, res, next, resHelper.OK, projectPackages);
	}).catch(err => {
		let errCode = utils.mongoErrorToResCode(err);
		resHelper.respond(place, req, res, next, errCode, err);

	});

}

// packages/* specific middlewares
function hasReadPackageAccess(req, res, next){
	middlewares.checkRole([C.REPO_ROLE_SUBCONTRACTOR, C.REPO_ROLE_MAINCONTRACTOR], req).then((roles) => {
		// if role is maincontractor then no more check is needed

		if(roles.indexOf(C.REPO_ROLE_MAINCONTRACTOR) !== -1){
			return Promise.resolve();
		} else {
			return middlewares.isSubContractorInvitedHelper(req);
		}

	}).then(() => {
		next();
	}).catch(resCode => {
		resHelper.respond("Middleware: check has read access", req, res, next, resCode, null, req.params);
	});
}

module.exports = router;<|endoftext|>


<commit_before>/* jshint globalstrict: true */
/* global require */

"use strict";

var testing = require('grunt-dom-test');

testing.a("modal")
    .withFile("src/picoModal.js")
    .withUtility("node_modules/chai/chai.js")

    .setup(function ($) {
        $.assert = $.window.chai.assert;
        $.picoModal = $.window.picoModal;
    })

    .should("Be created when 'show' is called").in(function (done, $) {
        $.picoModal(
            "
Curse your sudden but inevitable betrayal!
"
        ).show();
        $.assert.equal(
            $.query(".pico-content div").one().text(),
            "Curse your sudden but inevitable betrayal!");
        done();
    })

    .should("Be creatable with existing DOM content").using(
        "
Curse your sudden but inevitable betrayal!
"
    ).in(function (done, $) {

        $.picoModal( $.query("#myContent").one().elem ).show();

        $.assert.equal(
            $.query(".pico-content #myContent").one().text(),
            "Curse your sudden but inevitable betrayal!" );

        $.query("#myContent").one();

        done();
    })

    .should("Be re-usable via .show and .close").in(function (done, $) {
        var modal = $.picoModal("Curse your sudden but inevitable betrayal!");
        $.assert.isFalse( modal.isVisible() );

        modal.show();
        $.assert.isTrue( modal.isVisible() );

        modal.close();
        $.assert.isFalse( modal.isVisible() );

        modal.show();
        $.assert.isTrue( modal.isVisible() );

        done();
    })

    .should("Allow a specific width to be set").in(function (done, $) {
        $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            width: 50
        }).show();

        $.assert.equal( '50px', $.query(".pico-content").one().styles().width );

        done();
    })

    .should("Allow custom classes to be added").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            modalClass: "my-modal",
            overlayClass: "my-overlay",
            closeClass: "my-close"
        }).show();

        $.assert.equal( $.query(".my-modal").one().elem, modal.modalElem());
        $.assert.equal( $.query(".my-overlay").one().elem, modal.overlayElem());
        $.assert.equal( $.query(".my-close").one().elem, modal.closeElem());

        done();
    })

    .should("Allow functions as options").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            width: function (def) {
                $.assert.equal(def, 'auto');
                return 200;
            }
        }).show();

        $.assert.equal('200px', modal.modalElem().style.width);

        done();
    })

    .should("Allow custom styles to be set").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            modalStyles: { border: "1px solid red", background: "orange" },
            overlayStyles: { border: "1px solid yellow", background: "green" },
            closeStyles: { border: "1px solid blue", background: "purple" }
        }).show();

        $.assert.equal(modal.modalElem().style.borderColor, "red");
        $.assert.equal(modal.modalElem().style.background, "orange");

        $.assert.equal(modal.overlayElem().style.borderColor, "yellow");
        $.assert.equal(modal.overlayElem().style.background, "green");

        $.assert.equal(modal.closeElem().style.borderColor, "blue");
        $.assert.equal(modal.closeElem().style.background, "purple");

        done();
    })

    .should("Allow styles to be modified").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            modalStyles: function (styles) {
                styles.border = "1px solid red";
                styles.background = "orange";
            }
        }).show();

        $.assert.equal(modal.modalElem().style.borderColor, "red");
        $.assert.equal(modal.modalElem().style.background, "orange");
        $.assert.equal(modal.modalElem().style.padding, "20px");

        done();
    })

    .should("Allow the close button to be disabled").in(function (done, $) {
        $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            closeButton: false
        }).show();

        $.assert.equal($.query("pico-close").count, 0);

        done();
    })

    .should("Close when the shadow is clicked").skip(function () {
        throw new Error();
    })

    .should("Allow shadow clicks to be disabled").skip(function () {
        throw new Error();
    })

    .should("Trigger events").skip(function () {
        throw new Error();
    })

    .should("Allow `beforeShow` to prevent show").skip(function () {
        throw new Error();
    })

    .should("Allow `beforeClose` to prevent close").skip(function () {
        throw new Error();
    })

    .should("Bypass `beforeClose` with `forceClose`").skip(function () {
        throw new Error();
    })

    .should("Be destroyable").skip(function () {
        throw new Error();
    })

    .should("Allow its DOM to be prebuilt").skip(function () {
        throw new Error();
    })

    .should("Allow an alternate document parent").skip(function () {
        throw new Error();
    })

    .should("Set focus on the first element").skip(function () {
        throw new Error();
    })

    .should("Loop the tab key back to the start").skip(function () {
        throw new Error();
    })

    .should("Loop shift-tab to the end").skip(function () {
        throw new Error();
    })

    .should("Allow focus capture to be disabled").skip(function () {
        throw new Error();
    })

    .should("Close the modal when escape is pressed").skip(function () {
        throw new Error();
    })

    .should("Allow 'escape to close' to be disabled").skip(function () {
        throw new Error();
    })

    .should("Allow customizing the close button html").skip(function () {
        throw new Error();
    })

    .should("Add an ID to every modal").skip(function () {
        throw new Error();
    })

    .should("Allow a custom ID to be added").skip(function () {
        throw new Error();
    })

    .should("Allow custom aria attributes").skip(function () {
        throw new Error();
    })

    ;

<commit_msg>Organize tests into a few suites<commit_after>/* jshint globalstrict: true */
/* global require */

"use strict";

var testing = require('grunt-dom-test');

testing.a("modal")
    .withFile("src/picoModal.js")
    .withUtility("node_modules/chai/chai.js")

    .setup(function ($) {
        $.assert = $.window.chai.assert;
        $.picoModal = $.window.picoModal;
    })

    .should("Be created when 'show' is called").in(function (done, $) {
        $.picoModal(
            "
Curse your sudden but inevitable betrayal!
"
        ).show();
        $.assert.equal(
            $.query(".pico-content div").one().text(),
            "Curse your sudden but inevitable betrayal!");
        done();
    })

    .should("Be creatable with existing DOM content").using(
        "
Curse your sudden but inevitable betrayal!
"
    ).in(function (done, $) {

        $.picoModal( $.query("#myContent").one().elem ).show();

        $.assert.equal(
            $.query(".pico-content #myContent").one().text(),
            "Curse your sudden but inevitable betrayal!" );

        $.query("#myContent").one();

        done();
    })

    .should("Be re-usable via .show and .close").in(function (done, $) {
        var modal = $.picoModal("Curse your sudden but inevitable betrayal!");
        $.assert.isFalse( modal.isVisible() );

        modal.show();
        $.assert.isTrue( modal.isVisible() );

        modal.close();
        $.assert.isFalse( modal.isVisible() );

        modal.show();
        $.assert.isTrue( modal.isVisible() );

        done();
    })

    .should("Allow a specific width to be set").in(function (done, $) {
        $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            width: 50
        }).show();

        $.assert.equal( '50px', $.query(".pico-content").one().styles().width );

        done();
    })

    .should("Allow custom classes to be added").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            modalClass: "my-modal",
            overlayClass: "my-overlay",
            closeClass: "my-close"
        }).show();

        $.assert.equal( $.query(".my-modal").one().elem, modal.modalElem());
        $.assert.equal( $.query(".my-overlay").one().elem, modal.overlayElem());
        $.assert.equal( $.query(".my-close").one().elem, modal.closeElem());

        done();
    })

    .should("Allow functions as options").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            width: function (def) {
                $.assert.equal(def, 'auto');
                return 200;
            }
        }).show();

        $.assert.equal('200px', modal.modalElem().style.width);

        done();
    })

    .should("Allow custom styles to be set").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            modalStyles: { border: "1px solid red", background: "orange" },
            overlayStyles: { border: "1px solid yellow", background: "green" },
            closeStyles: { border: "1px solid blue", background: "purple" }
        }).show();

        $.assert.equal(modal.modalElem().style.borderColor, "red");
        $.assert.equal(modal.modalElem().style.background, "orange");

        $.assert.equal(modal.overlayElem().style.borderColor, "yellow");
        $.assert.equal(modal.overlayElem().style.background, "green");

        $.assert.equal(modal.closeElem().style.borderColor, "blue");
        $.assert.equal(modal.closeElem().style.background, "purple");

        done();
    })

    .should("Allow styles to be modified").in(function (done, $) {
        var modal = $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            modalStyles: function (styles) {
                styles.border = "1px solid red";
                styles.background = "orange";
            }
        }).show();

        $.assert.equal(modal.modalElem().style.borderColor, "red");
        $.assert.equal(modal.modalElem().style.background, "orange");
        $.assert.equal(modal.modalElem().style.padding, "20px");

        done();
    })

    .should("Allow the close button to be disabled").in(function (done, $) {
        $.picoModal({
            content: "Curse your sudden but inevitable betrayal!",
            closeButton: false
        }).show();

        $.assert.equal($.query("pico-close").count, 0);

        done();
    })

    .should("Be destroyable").skip(function () {
        throw new Error();
    })

    .should("Allow its DOM to be prebuilt").skip(function () {
        throw new Error();
    })

    .should("Allow an alternate document parent").skip(function () {
        throw new Error();
    })

    .should("Allow customizing the close button html").skip(function () {
        throw new Error();
    })

    .and("And the modal overlay")

    .should("Close the modal when the shadow is clicked").skip(function () {
        throw new Error();
    })

    .should("Allow shadow clicks to be disabled").skip(function () {
        throw new Error();
    })

    .and("Modal events")

    .should("be triggered").skip(function () {
        throw new Error();
    })

    .should("Allow `beforeShow` to prevent show").skip(function () {
        throw new Error();
    })

    .should("Allow `beforeClose` to prevent close").skip(function () {
        throw new Error();
    })

    .should("Bypass `beforeClose` with `forceClose`").skip(function () {
        throw new Error();
    })

    .and("Modal accessibility")

    .should("Add an ID to every modal").skip(function () {
        throw new Error();
    })

    .should("Allow a custom ID to be added").skip(function () {
        throw new Error();
    })

    .should("Allow custom aria attributes").skip(function () {
        throw new Error();
    })

    .should("Set focus on the first element").skip(function () {
        throw new Error();
    })

    .should("Loop the tab key back to the start").skip(function () {
        throw new Error();
    })

    .should("Loop shift-tab to the end").skip(function () {
        throw new Error();
    })

    .should("Allow focus capture to be disabled").skip(function () {
        throw new Error();
    })

    .should("Close the modal when escape is pressed").skip(function () {
        throw new Error();
    })

    .should("Allow 'escape to close' to be disabled").skip(function () {
        throw new Error();
    })

    ;

<|endoftext|>


<commit_before>var Pipe = require('../lib/pipe');
var assert = require('chai').assert;

describe('Pipe', function(){
  context('new pipe', function(){
    it('has correct default attributes', function(){
      var pipe = new Pipe();

      assert.equal(pipe.width, 75);
    });

    it('has a random y location', function() {
      var pipe1 = new Pipe();
      var pipe2 = new Pipe();

      assert(pipe1.y !== pipe2.y);
    });

    it('moves across the canvas', function(){
      var pipe = new Pipe();

      assert.equal(pipe.x, 500)
      for (var i = 0; i < 20; i++) {
        pipe.moveAcrossCanvas;
      }
      assert.equal(pipe.x, 480)
    });
  });
});
<commit_msg>fix failing tests<commit_after>var Pipe = require('../lib/pipe');
var assert = require('chai').assert;

describe('Pipe', function(){
  context('new pipe', function(){
    it('has correct default attributes', function(){
      var pipe = new Pipe();

      assert.equal(pipe.width, 49);
    });

    it('has a random y location', function() {
      var pipe1 = new Pipe();
      var pipe2 = new Pipe();

      assert(pipe1.y !== pipe2.y);
    });

    it('moves across the canvas', function(){
      var pipe = new Pipe(context, 500);

      assert.equal(pipe.x, 500)
      for (var i = 0; i < 20; i++) {
        pipe.moveAcrossCanvas;
      }
      assert.equal(pipe.x, 480)
    });
  });
});
<|endoftext|>