<commit_before>(function () {
  'use strict';

  var uiSelectModule = angular.module('fng.uiSelect', ['ui.select']);

  uiSelectModule.factory('uiSelectHelper', ['$rootScope', '$q', 'SubmissionsService', function ($rootScope, $q, SubmissionsService) {
    var lastW, lastH;
    var localLookups = {};
    return {
      windowChanged: function (w, h) {
        var result = false;
        if (w !== lastW || h !== lastH) {
          lastW = w;
          lastH = h;
          result = true;
        }
        return result;
      },
      addClientLookup: function (lkpName, lkpData) {
        localLookups[lkpName] = lkpData;
      },
      lookupFunc: function (value, formSchema, cb) {
        if (formSchema.array) {
          // TODO extend back end to do multiple lookups in one hit

          var promises = [];
          var results = [];
          angular.forEach(value, function (obj) {
            promises.push(SubmissionsService.getListAttributes(formSchema.ref, obj.x));
          });
          $q.all(promises).then(function (responses) {
            angular.forEach(responses, function (response) {
              results.push({x: {id: value.shift().x, text: response.data.list}});
            });
            cb(formSchema, results);
            setTimeout(function () {
              $rootScope.$digest();
            });
          });
        } else if (formSchema.fngUiSelect.deriveOptions) {
          var retVal;
          if (typeof value === 'string') {
            var obj = localLookups[formSchema.fngUiSelect.deriveOptions].find(function (test) {
              return test.id === value
            });
            retVal = {id: value, text: obj ? obj.text : ''}
          } else {
            retVal = value;
          }
          cb(formSchema, retVal);
        } else {
          SubmissionsService.getListAttributes({type:'lookup', collection:formSchema.ref.collection}, value).then(function (response) {
            cb(formSchema, {id: value, text: response.data.list});
          });
        }
      }
    };
  }]);

  uiSelectModule.controller('FngUISelectCtrl', ['$scope', '$window', '$timeout', '$http', 'uiSelectHelper', function ($scope, $window, $timeout, $http, uiSelectHelper) {

    $scope.uiSelect = $scope.uiSelect || [];

    $scope.windowResizeUiSelect = function (checkResize) {
      // This is to stop the resize firing too often.  Really horrible way of doing it caused by some very regrettable design choices which will be factored out later
      // Actually not choices - just not knowing any better
      if (!checkResize || uiSelectHelper.windowChanged($window.innerWidth, $window.innerHeight)) {
        for (var i = 0; i < $scope.uiSelect.length; i++) {
          var selectId = $scope.uiSelect[i].selectId;
          var select = document.getElementById(selectId);
          if (select && select.offsetParent) {
            var helper = document.getElementById(selectId + '_width-helper');
            if (helper) {
              var w = helper.offsetWidth;
              if (select.offsetLeft + w > $window.innerWidth) {
                w = $window.innerWidth - select.offsetLeft - 20;
              }
              angular.element(document.getElementById(selectId)).css('width', w);
            } else {
              console.log('No helper element found for ' + selectId);
            }
          }
        }
      }
    };

    $scope.refreshOptions = function (searchString, id) {
      var elem = _.find($scope.uiSelect, function (elem) {
        return elem.selectId === id
      });
      if (elem) {
        if (searchString.length === 0) {
          $scope[id + '_options'] = [];
        } else {
          var promise;
          if (elem.filter && elem.filter[0] === '/') {
            // Custom URL
            promise = $http({
              method: 'GET',
              url: elem.filter,
              params: {
                q: searchString,
                e: $scope.record
              },
              cache: false
            });
          } else {
            promise = $http.get('/api/search/' + elem.ref.collection + '?q=' + searchString + (elem.filter ? ('&f=' + elem.filter) : ''));
          }
          promise.then(function (response) {
            if (elem.additional) {
              $scope[id + '_options'] = response.data.results.map(function (result) {
                result.text = result.text + (result.additional ? (', ' + result.additional) : '');
                return result;
              });
            } else {
              $scope[id + '_options'] = response.data.results;
            }
          });
        }
      } else {
        throw new Error('Could not find uiSelect element for ' + id);
      }
    };

    angular.element($window).bind('resize', function () {
      $scope.windowResizeUiSelect(true);
      return $scope.$apply();
    });

    $timeout($scope.windowResizeUiSelect);
  }]);

  uiSelectModule.directive('fngUiSelect', ['$compile', '$window', 'pluginHelper', 'cssFrameworkService', 'formMarkupHelper', 'uiSelectHelper',
    function ($compile, $window, pluginHelper, cssFrameworkService, formMarkupHelper, uiSelectHelper) {
      return {
        restrict: 'E',
        controller: 'FngUISelectCtrl',
        link: function (scope, element, attr) {

          function addToConversions(path, options) {
            if (Object.keys(options).length > 0) {
              var keys = path.split('.');
              if (!scope.conversions) {
                  scope.conversions = {};
              }
              var target = scope.conversions;
              for (var i = 0; i < keys.length; i++) {
                var thisKey = keys[i];
                target[thisKey] = target[thisKey] || {};
                target = target[thisKey];
              }
              angular.extend(target, options);
            }
          }

          var processedAttr = pluginHelper.extractFromAttr(attr, 'fngUiSelect');
          var elemScope = angular.extend({selectId: processedAttr.info.id}, processedAttr.directiveOptions);
          var multi = processedAttr.info.array;
          var elementHtml;
          var input = '';

          scope.uiSelect.push(elemScope);
          addToConversions(processedAttr.info.name, processedAttr.directiveOptions);

          // Sort out the theme, defaulting to select2 (so old users won't see the change).  Bootstrap theme only works with Bootstrap 3
          var theme = processedAttr.directiveOptions.theme || 'select2';
          if (processedAttr.info.theme === 'bootstrap' && cssFrameworkService.framework !== 'bs3') {
            theme = 'select2';
          }

          var multiControl = false;
          var multiStr = '';
          if (multi && (processedAttr.directiveOptions.fngajax || processedAttr.directiveOptions.forcemultiple)) {
            // We need the array to be an array of objects with a x property.  This tells forms-angular to convert it by
            // adding an attribute to the schema.
            pluginHelper.findIdInSchemaAndFlagNeedX(scope.baseSchema(), processedAttr.info.id);
            multiControl = true;
          } else {
            multiStr = multi ? 'multiple close-on-select reset-search-input ' : '';
          }

          var requiredStr = '';
          var allowClearStr = '';
          if (processedAttr.info.required) {
            requiredStr = ' ng-required="true"';
          } else {
            allowClearStr = ' allow-clear';
          }

          // First of all add a hidden input field which we will use to set the width of the select
          var hiddenInputInfo = {
            id: processedAttr.info.id + '_width-helper',
            name: processedAttr.info.name + '_width-helper',
            label: ''
          };
          if (processedAttr.info.size) {
            hiddenInputInfo.size = processedAttr.info.size;
          }
          input = pluginHelper.buildInputMarkup(scope, attr.model, hiddenInputInfo, processedAttr.options, false, multiControl, function (buildingBlocks) {
            return '<input id="' + hiddenInputInfo.id + '" type="text" class="form-control" disabled="" style="position: absolute; left: -4200px;">';
          });

          function optionsFromArray(multiControl, multi, array, arrayGetter) {
            var isObjects = scope[array] && (scope[array].isObjects || typeof scope[array][0] === "object");
            if (isObjects) {
              addToConversions(processedAttr.info.name, {fngajax: uiSelectHelper.lookupFunc});
              uiSelectHelper.addClientLookup(arrayGetter, scope[array]);
            }
            var select = '';
            if (multiControl) {
              select += '{{$select.selected' + (isObjects ? '.text' : '') + '}}';
            } else {
              select += multi ? '{{$item}}' : ('{{$select.selected' + (isObjects ? '.text' : '') + '}}');
            }
            select += '</ui-select-match>';
            select += '<ui-select-choices repeat="option in ' + array + ' | filter:$select.search">';
            select += '

';
            return select;
          }

          elementHtml = pluginHelper.buildInputMarkup(scope, attr.model, processedAttr.info, processedAttr.options, multiControl, multiControl, function (buildingBlocks) {
            var defaultPlaceholder = 'Select an option...';
            if (processedAttr.directiveOptions.fngajax) {
              defaultPlaceholder = 'Start typing...'
            }
            // set up the ui-select directives
            var select = '<ui-select ' + multiStr + buildingBlocks.common + requiredStr + ' theme="' + theme + '" ng-disabled="disabled" style="width:300px;">';
            select += '<ui-select-match' + allowClearStr + ' placeholder="' + (processedAttr.info.placeholder || defaultPlaceholder) + '">';

            if (processedAttr.directiveOptions.fngajax) {
              // Stash any filters
              if (processedAttr.directiveOptions.fngajax !== true) {
                elemScope.filter = processedAttr.directiveOptions.fngajax;
              }
              // Set up lookup function
              addToConversions(processedAttr.info.name, {fngajax: uiSelectHelper.lookupFunc});
              // Use the forms-angular API to query the referenced collection
              elemScope.ref = processedAttr.info.ref;
              if (elemScope.ref) {
                if (elemScope.ref[0] === '{') {
                  elemScope.ref = JSON.parse(elemScope.ref);
                } else {
                  elemScope.ref = {type:'lookup', collection: elemScope.ref};
                  console.warn('Support for string type "ref" property is deprecated - use ref:' + JSON.stringify(elemScope.ref));
                }
              }
              scope[processedAttr.info.id + '_options'] = [];
              if (multiControl) {
                select += '{{$select.selected.text}}';
              } else if (processedAttr.options.subschema) {
                select += '{{' + attr.model + '.' + processedAttr.info.name.replace(processedAttr.options.subschemaroot, processedAttr.options.subschemaroot + '[$index]') + '.text}}';
              } else {
                select += '{{' + buildingBlocks.modelString + '.text}}';
              }
              select += '</ui-select-match>';
              select += '<ui-select-choices repeat="option in (' + processedAttr.info.id + '_options) track by $index" ';
              select += 'refresh="refreshOptions($select.search, \'' + processedAttr.info.id + '\')" ';
              select += 'refresh-delay="100"> ';
              select += '

';
            } else if (processedAttr.directiveOptions.deriveoptions) {
              if (typeof scope[processedAttr.directiveOptions.deriveoptions] === "function") {
                select += optionsFromArray(multiControl, multi, scope[processedAttr.directiveOptions.deriveoptions](), processedAttr.directiveOptions.deriveoptions);
              } else {
                throw new Error("In fng-ui-select " + processedAttr.directiveOptions.deriveoptions + " is not a function on the scope");
              }
            } else if (processedAttr.info.options) {
              // Simple case - enumerated options on the form scope
              select += optionsFromArray(multiControl, multi, processedAttr.info.options);
            } else {
              throw new Error('fng-ui-select has no means of populating select');
            }
            select += '</ui-select-choices>';
            select += '</ui-select>';
            return select;
          });
          scope.content = input + elementHtml;
          element.append($compile(input + elementHtml)(scope));
        }
      }
    }]);
})();
<commit_msg>show errors in base form<commit_after>(function () {
  'use strict';

  var uiSelectModule = angular.module('fng.uiSelect', ['ui.select']);

  uiSelectModule.factory('uiSelectHelper', ['$rootScope', '$q', 'SubmissionsService', function ($rootScope, $q, SubmissionsService) {
    var lastW, lastH;
    var localLookups = {};
    return {
      windowChanged: function (w, h) {
        var result = false;
        if (w !== lastW || h !== lastH) {
          lastW = w;
          lastH = h;
          result = true;
        }
        return result;
      },
      addClientLookup: function (lkpName, lkpData) {
        localLookups[lkpName] = lkpData;
      },
      lookupFunc: function (value, formSchema, cb) {
        if (formSchema.array) {
          // TODO extend back end to do multiple lookups in one hit

          var promises = [];
          var results = [];
          angular.forEach(value, function (obj) {
            promises.push(SubmissionsService.getListAttributes(formSchema.ref, obj.x));
          });
          $q.all(promises).then(function (responses) {
            angular.forEach(responses, function (response) {
              results.push({x: {id: value.shift().x, text: response.data.list}});
            });
            cb(formSchema, results);
            setTimeout(function () {
              $rootScope.$digest();
            });
          });
        } else if (formSchema.fngUiSelect.deriveOptions) {
          var retVal;
          if (typeof value === 'string') {
            var obj = localLookups[formSchema.fngUiSelect.deriveOptions].find(function (test) {
              return test.id === value
            });
            retVal = {id: value, text: obj ? obj.text : ''}
          } else {
            retVal = value;
          }
          cb(formSchema, retVal);
        } else {
          SubmissionsService.getListAttributes({type:'lookup', collection:formSchema.ref.collection}, value).then(function (response) {
            cb(formSchema, {id: value, text: response.data.list});
          });
        }
      }
    };
  }]);

  uiSelectModule.controller('FngUISelectCtrl', ['$scope', '$window', '$timeout', '$http', 'uiSelectHelper', function ($scope, $window, $timeout, $http, uiSelectHelper) {

    $scope.uiSelect = $scope.uiSelect || [];

    $scope.windowResizeUiSelect = function (checkResize) {
      // This is to stop the resize firing too often.  Really horrible way of doing it caused by some very regrettable design choices which will be factored out later
      // Actually not choices - just not knowing any better
      if (!checkResize || uiSelectHelper.windowChanged($window.innerWidth, $window.innerHeight)) {
        for (var i = 0; i < $scope.uiSelect.length; i++) {
          var selectId = $scope.uiSelect[i].selectId;
          var select = document.getElementById(selectId);
          if (select && select.offsetParent) {
            var helper = document.getElementById(selectId + '_width-helper');
            if (helper) {
              var w = helper.offsetWidth;
              if (select.offsetLeft + w > $window.innerWidth) {
                w = $window.innerWidth - select.offsetLeft - 20;
              }
              angular.element(document.getElementById(selectId)).css('width', w);
            } else {
              console.log('No helper element found for ' + selectId);
            }
          }
        }
      }
    };

    $scope.refreshOptions = function (searchString, id) {
      var elem = _.find($scope.uiSelect, function (elem) {
        return elem.selectId === id
      });
      if (elem) {
        if (searchString.length === 0) {
          $scope[id + '_options'] = [];
        } else {
          var promise;
          if (elem.filter && elem.filter[0] === '/') {
            // Custom URL
            promise = $http({
              method: 'GET',
              url: elem.filter,
              params: {
                q: searchString,
                e: $scope.record
              },
              cache: false
            });
          } else {
            promise = $http.get('/api/search/' + elem.ref.collection + '?q=' + searchString + (elem.filter ? ('&f=' + elem.filter) : ''));
          }
          promise.then(function (response) {
            if (response.status >= 400) {
              throw new Error(response.statusMessage)
            } else {
              if (elem.additional) {
                $scope[id + '_options'] = response.data.results.map(function (result) {
                  result.text = result.text + (result.additional ? (', ' + result.additional) : '');
                  return result;
                });
              } else {
                $scope[id + '_options'] = response.data.results;
              }
            }
          })
          .catch(err => {
            $scope.showError(err.data);
          });
        }
      } else {
        throw new Error('Could not find uiSelect element for ' + id);
      }
    };

    angular.element($window).bind('resize', function () {
      $scope.windowResizeUiSelect(true);
      return $scope.$apply();
    });

    $timeout($scope.windowResizeUiSelect);
  }]);

  uiSelectModule.directive('fngUiSelect', ['$compile', '$window', 'pluginHelper', 'cssFrameworkService', 'formMarkupHelper', 'uiSelectHelper',
    function ($compile, $window, pluginHelper, cssFrameworkService, formMarkupHelper, uiSelectHelper) {
      return {
        restrict: 'E',
        controller: 'FngUISelectCtrl',
        link: function (scope, element, attr) {

          function addToConversions(path, options) {
            if (Object.keys(options).length > 0) {
              var keys = path.split('.');
              if (!scope.conversions) {
                  scope.conversions = {};
              }
              var target = scope.conversions;
              for (var i = 0; i < keys.length; i++) {
                var thisKey = keys[i];
                target[thisKey] = target[thisKey] || {};
                target = target[thisKey];
              }
              angular.extend(target, options);
            }
          }

          var processedAttr = pluginHelper.extractFromAttr(attr, 'fngUiSelect');
          var elemScope = angular.extend({selectId: processedAttr.info.id}, processedAttr.directiveOptions);
          var multi = processedAttr.info.array;
          var elementHtml;
          var input = '';

          scope.uiSelect.push(elemScope);
          addToConversions(processedAttr.info.name, processedAttr.directiveOptions);

          // Sort out the theme, defaulting to select2 (so old users won't see the change).  Bootstrap theme only works with Bootstrap 3
          var theme = processedAttr.directiveOptions.theme || 'select2';
          if (processedAttr.info.theme === 'bootstrap' && cssFrameworkService.framework !== 'bs3') {
            theme = 'select2';
          }

          var multiControl = false;
          var multiStr = '';
          if (multi && (processedAttr.directiveOptions.fngajax || processedAttr.directiveOptions.forcemultiple)) {
            // We need the array to be an array of objects with a x property.  This tells forms-angular to convert it by
            // adding an attribute to the schema.
            pluginHelper.findIdInSchemaAndFlagNeedX(scope.baseSchema(), processedAttr.info.id);
            multiControl = true;
          } else {
            multiStr = multi ? 'multiple close-on-select reset-search-input ' : '';
          }

          var requiredStr = '';
          var allowClearStr = '';
          if (processedAttr.info.required) {
            requiredStr = ' ng-required="true"';
          } else {
            allowClearStr = ' allow-clear';
          }

          // First of all add a hidden input field which we will use to set the width of the select
          var hiddenInputInfo = {
            id: processedAttr.info.id + '_width-helper',
            name: processedAttr.info.name + '_width-helper',
            label: ''
          };
          if (processedAttr.info.size) {
            hiddenInputInfo.size = processedAttr.info.size;
          }
          input = pluginHelper.buildInputMarkup(scope, attr.model, hiddenInputInfo, processedAttr.options, false, multiControl, function (buildingBlocks) {
            return '<input id="' + hiddenInputInfo.id + '" type="text" class="form-control" disabled="" style="position: absolute; left: -4200px;">';
          });

          function optionsFromArray(multiControl, multi, array, arrayGetter) {
            var isObjects = scope[array] && (scope[array].isObjects || typeof scope[array][0] === "object");
            if (isObjects) {
              addToConversions(processedAttr.info.name, {fngajax: uiSelectHelper.lookupFunc});
              uiSelectHelper.addClientLookup(arrayGetter, scope[array]);
            }
            var select = '';
            if (multiControl) {
              select += '{{$select.selected' + (isObjects ? '.text' : '') + '}}';
            } else {
              select += multi ? '{{$item}}' : ('{{$select.selected' + (isObjects ? '.text' : '') + '}}');
            }
            select += '</ui-select-match>';
            select += '<ui-select-choices repeat="option in ' + array + ' | filter:$select.search">';
            select += '

';
            return select;
          }

          elementHtml = pluginHelper.buildInputMarkup(scope, attr.model, processedAttr.info, processedAttr.options, multiControl, multiControl, function (buildingBlocks) {
            var defaultPlaceholder = 'Select an option...';
            if (processedAttr.directiveOptions.fngajax) {
              defaultPlaceholder = 'Start typing...'
            }
            // set up the ui-select directives
            var select = '<ui-select ' + multiStr + buildingBlocks.common + requiredStr + ' theme="' + theme + '" ng-disabled="disabled" style="width:300px;">';
            select += '<ui-select-match' + allowClearStr + ' placeholder="' + (processedAttr.info.placeholder || defaultPlaceholder) + '">';

            if (processedAttr.directiveOptions.fngajax) {
              // Stash any filters
              if (processedAttr.directiveOptions.fngajax !== true) {
                elemScope.filter = processedAttr.directiveOptions.fngajax;
              }
              // Set up lookup function
              addToConversions(processedAttr.info.name, {fngajax: uiSelectHelper.lookupFunc});
              // Use the forms-angular API to query the referenced collection
              elemScope.ref = processedAttr.info.ref;
              if (elemScope.ref) {
                if (elemScope.ref[0] === '{') {
                  elemScope.ref = JSON.parse(elemScope.ref);
                } else {
                  elemScope.ref = {type:'lookup', collection: elemScope.ref};
                  console.warn('Support for string type "ref" property is deprecated - use ref:' + JSON.stringify(elemScope.ref));
                }
              }
              scope[processedAttr.info.id + '_options'] = [];
              if (multiControl) {
                select += '{{$select.selected.text}}';
              } else if (processedAttr.options.subschema) {
                select += '{{' + attr.model + '.' + processedAttr.info.name.replace(processedAttr.options.subschemaroot, processedAttr.options.subschemaroot + '[$index]') + '.text}}';
              } else {
                select += '{{' + buildingBlocks.modelString + '.text}}';
              }
              select += '</ui-select-match>';
              select += '<ui-select-choices repeat="option in (' + processedAttr.info.id + '_options) track by $index" ';
              select += 'refresh="refreshOptions($select.search, \'' + processedAttr.info.id + '\')" ';
              select += 'refresh-delay="100"> ';
              select += '

';
            } else if (processedAttr.directiveOptions.deriveoptions) {
              if (typeof scope[processedAttr.directiveOptions.deriveoptions] === "function") {
                select += optionsFromArray(multiControl, multi, scope[processedAttr.directiveOptions.deriveoptions](), processedAttr.directiveOptions.deriveoptions);
              } else {
                throw new Error("In fng-ui-select " + processedAttr.directiveOptions.deriveoptions + " is not a function on the scope");
              }
            } else if (processedAttr.info.options) {
              // Simple case - enumerated options on the form scope
              select += optionsFromArray(multiControl, multi, processedAttr.info.options);
            } else {
              throw new Error('fng-ui-select has no means of populating select');
            }
            select += '</ui-select-choices>';
            select += '</ui-select>';
            return select;
          });
          scope.content = input + elementHtml;
          element.append($compile(input + elementHtml)(scope));
        }
      }
    }]);
})();
<|endoftext|>


<commit_before>;(function(){

  function formProgress(settings) {

    const { form, progressEl, proggressAttr, unit } = settings;
    let { inputTypes } = settings;

    const progressStep = 100 / (form.length - 1);
    let currentProgress = 0;

    // make all input types lowercase
    inputTypes = inputTypes.map(function(type){
      return type.toString().toLowerCase();
    });

    // improve with bubbling, one callback to the form
    [].forEach.call(form, (input) => {
      if (inputTypes.indexOf(input.tagName.toLowerCase()) != -1) {

        // increase progress
        input.addEventListener('input', function() {
          if (this.value.length !== 0 && !this.progressChecked) {
            currentProgress += progressStep;

            if (proggressAttr === 'style') {
              progressEl.style.width = currentProgress + unit;
            }

            this.progressChecked = true;
          }

          // decrease progress
          if (this.value.length === 0 && this.progressChecked) {
            currentProgress -= progressStep;

            if (proggressAttr === 'style') {
              progressEl.style.width = currentProgress + unit;
            }

            this.progressChecked = false;
          }
        });

      }
    });
  }

  window.formProgress = formProgress;

}());<commit_msg>Now main func using event bubbling for listening events from inputs<commit_after>;(function(){

  function formProgress(settings) {

    const { form, progressEl, proggressAttr, unit } = settings;
    let { inputTypes } = settings;

    const progressStep = 100 / (form.length - 1);
    let currentProgress = 0;

    // make all input types lowercase
    inputTypes = inputTypes.map((type) => {
      return type.toString().toLowerCase();
    });

    form.addEventListener('input', (evt) => {
      let input = evt.target;

      // increase progress
      if (input.value.length !== 0 && !input.progressChecked) {
        currentProgress += progressStep;

        if (proggressAttr === 'style') {
          progressEl.style.width = currentProgress + unit;
        }

        input.progressChecked = true;
      }

      // decrease progress
      if (input.value.length === 0 && input.progressChecked) {
        currentProgress -= progressStep;

        if (proggressAttr === 'style') {
          progressEl.style.width = currentProgress + unit;
        }

        input.progressChecked = false;
      }
    });

  }

  window.formProgress = formProgress;

}());<|endoftext|>


<commit_before>import React from "react";
import {hyperscript as h} from "neutrine-utils";

import "siimple/scss/form/_checkbox.scss";

//Generate a random ID
let randomID = function () {
    return Math.random().toString(36).slice(2, 9) + Date.now().toString(36);
};

//Checkbox component
export default class Checkbox extends React.Component {
     constructor(props) {
        super(props);
        this.state = {
            id: randomID()
        };
        //Initialize the referenced elements object
        this.ref = {};
        //Bind handlers
        this.handleChange = this.handleChange.bind(this);
    }

    //Handle the checkbox change
    handleChange(e) {
        if (typeof this.props.onChange === "function") {
            this.props.onChange.call(null, e.nativeEvent, this.ref.input.checked);
        }
    }

    //Get or set the checkbox state
    checked(isChecked) {
        //Check the is checked value
        if (typeof isChecked === "boolean") {
            //Set the checked value
            this.ref.input.checked = isChecked;
        } else {
            //Return if checkbox is checked
            return this.ref.input.checked;
        }
    }

    //Render the checkbox element
    render() {
        let self = this;
        //Input default props
        let inputProps = {
            id: this.state.id,
            type: "checkbox",
            defaultChecked: this.props.checked,
            name: this.props.name,
            ref: function (i) {
                self.ref.input = i;
            },
            onChange: self.handleChange
        };
        //Switch children content
        let children = [
            h("input", inputProps, null),
            h("label", {htmlFor: this.state.id}, null),
            h("div", {}, null)
        ];
        //Return the checkbox element
        return h("div", {className: "siimple-checkbox", style: this.props.style}, children);
    }
}

//Checkbox default props
Checkbox.defaultProps = {
    name: null,
    checked: true,
    onChange: null,
    style: null
};

<commit_msg>Removed unused div element in checkbox component<commit_after>import React from "react";
import {hyperscript as h} from "neutrine-utils";

import "siimple/scss/form/_checkbox.scss";

//Generate a random ID
let randomID = function () {
    return Math.random().toString(36).slice(2, 9) + Date.now().toString(36);
};

//Checkbox component
export default class Checkbox extends React.Component {
     constructor(props) {
        super(props);
        this.state = {
            id: randomID()
        };
        //Initialize the referenced elements object
        this.ref = {};
        //Bind handlers
        this.handleChange = this.handleChange.bind(this);
    }

    //Handle the checkbox change
    handleChange(e) {
        if (typeof this.props.onChange === "function") {
            this.props.onChange.call(null, e.nativeEvent, this.ref.input.checked);
        }
    }

    //Get or set the checkbox state
    checked(isChecked) {
        //Check the is checked value
        if (typeof isChecked === "boolean") {
            //Set the checked value
            this.ref.input.checked = isChecked;
        } else {
            //Return if checkbox is checked
            return this.ref.input.checked;
        }
    }

    //Render the checkbox element
    render() {
        let self = this;
        //Input default props
        let inputProps = {
            id: this.state.id,
            type: "checkbox",
            defaultChecked: this.props.checked,
            name: this.props.name,
            ref: function (i) {
                self.ref.input = i;
            },
            onChange: self.handleChange
        };
        //Switch children content
        let children = [
            h("input", inputProps, null),
            h("label", {htmlFor: this.state.id}, null)
        ];
        //Return the checkbox element
        return h("div", {className: "siimple-checkbox", style: this.props.style}, children);
    }
}

//Checkbox default props
Checkbox.defaultProps = {
    name: null,
    checked: true,
    onChange: null,
    style: null
};

<|endoftext|>


<commit_before>'use strict';
var CONST = require('./const.js');

var resources = {
	images : [],
	sizes : [],
	patterns : []
};

var services = {
	fbActivRef : null,
	activUsers : {}
};

var ui = {
	canvas : null,
	context : null,
	ratio : 1,
	ratioScreen : 1,
	stepAnimation : 0,
	stepAnimationCloud : 0,
	usersChange: false,
	users : [],
	mapCollision : [],
	mapInteraction : [],
	changeScreen : '',
	screen : CONST.screens.HOME,
	middlePoint : {
		x : 0,
		y : 0
	},
	screenSize : {
			width : 0
			, height : 0
	}
};

var gameModel = {
	version : '10',
	userHash : null,
	user : null,
	typeSocial : null,
	indexUser : -1,
	showStory : false,
	inputArray : [],
	standId : '',
	time : 0,
	lastTime : 0,
	anwserQuestions : [],
	positionScreen: {
		x:0,
		y:0
	},
	position: {
		x:10,
		y:10,
		direction : CONST.directions.UP,
		stepCount : 0
	},
	parameters : {
		useParams : false
		, mic : false
		, motion : false
		, wrongOrientation : false
	}
};

// On initialise la map des collisions qui va déterminer le déplacement possible de notre personnage dans la map
for (var row = 0; row < CONST.ui.SIZE_UNIT.h; row++){
	var arrayRow = [];
	for (var col =0; col < CONST.ui.SIZE_UNIT.w; col++){
		arrayRow.push(false);
	}
	ui.mapCollision.push(arrayRow);
}

module.exports = {
	resources : resources,
	ui : ui,
	gameModel : gameModel,
	services : services
};
<commit_msg>montée de version du modèle pour bien forcer une mise à jour<commit_after>'use strict';
var CONST = require('./const.js');

var resources = {
	images : [],
	sizes : [],
	patterns : []
};

var services = {
	fbActivRef : null,
	activUsers : {}
};

var ui = {
	canvas : null,
	context : null,
	ratio : 1,
	ratioScreen : 1,
	stepAnimation : 0,
	stepAnimationCloud : 0,
	usersChange: false,
	users : [],
	mapCollision : [],
	mapInteraction : [],
	changeScreen : '',
	screen : CONST.screens.HOME,
	middlePoint : {
		x : 0,
		y : 0
	},
	screenSize : {
			width : 0
			, height : 0
	}
};

var gameModel = {
	version : '11',
	userHash : null,
	user : null,
	typeSocial : null,
	indexUser : -1,
	showStory : false,
	inputArray : [],
	standId : '',
	time : 0,
	lastTime : 0,
	anwserQuestions : [],
	positionScreen: {
		x:0,
		y:0
	},
	position: {
		x:10,
		y:10,
		direction : CONST.directions.UP,
		stepCount : 0
	},
	parameters : {
		useParams : false
		, mic : false
		, motion : false
		, wrongOrientation : false
	}
};

// On initialise la map des collisions qui va déterminer le déplacement possible de notre personnage dans la map
for (var row = 0; row < CONST.ui.SIZE_UNIT.h; row++){
	var arrayRow = [];
	for (var col =0; col < CONST.ui.SIZE_UNIT.w; col++){
		arrayRow.push(false);
	}
	ui.mapCollision.push(arrayRow);
}

module.exports = {
	resources : resources,
	ui : ui,
	gameModel : gameModel,
	services : services
};
<|endoftext|>


<commit_before>import diff from '~/utils/StringDiff.js'
import List from './List.js'
import Sign from './Sign.js'

/**
 * A line is a building block in a division
 *
 * A line is comprised of signs
 *
 * @class
 */
class Line extends List {
  static getModel() {
    return Sign
  }

  /**
   * Diff the line-model against the provided string (usually from the DOM representation
   * of this line). Therefore, inserts/deletes to the data will be to bring it into
   * alignment with the given string
   *
   * @public
   * @instance
   *
   * @param {string} str a string to synchronize this line to
   */
  synchronizeTo(str) {
    // TODO: handle whitespace chars more consistently.

    // Note: for the purpose of synchronization algorithm, it is important that the
    //       the whitespace char be a single char (rather than   or something)
    let diffs = diff(this.toString().replace(/\s/g, ' '), str.replace(/\s/g, ' '))

    let diffIndex = 0
    for (let i = 0, n = diffs.length; i < n; i++) {
      // each diff in the array takes this shape:
      // [code = 0, 1, -1, change = 'string difference']
      let d = diffs[i]
      switch (d[0]) {
        // no change, simply increment up our string index
        case diff.EQUAL:
          diffIndex = diffIndex + d[1].length
          break

        // there's been (a) sign(s) inserted
        case diff.INSERT:
          d[1].split('').forEach(char => {
            this.insert(
              new Sign({
                chars: [
                  {
                    sign_char: char,
                  },
                ],
              }),
              diffIndex
            )
            diffIndex++
          })
          break

        // there's been a sign deleted
        case diff.DELETE:
          d[1].split('').forEach(() => this.delete(diffIndex))
          break
      }
    }
  }

  toDOMString() {
    let str = ''
    this.forEach(sign => {
      str += sign.toDOMString()
    }, this)

    return `<p data-line-id="${this.getID()}">${str}</p>`
  }

  /**
   * @returns {string} a plain string with all signs
   */
  toString() {
    let str = ''
    this.forEach(sign => {
      str += sign.toString()
    }, this)
    return str
  }
}

export default Line
<commit_msg>Classes added to signs.<commit_after>import diff from '~/utils/StringDiff.js'
import List from './List.js'
import Sign from './Sign.js'

/**
 * A line is a building block in a division
 *
 * A line is comprised of signs
 *
 * @class
 */
class Line extends List {
  static getModel() {
    return Sign
  }

  /**
   * Diff the line-model against the provided string (usually from the DOM representation
   * of this line). Therefore, inserts/deletes to the data will be to bring it into
   * alignment with the given string
   *
   * @public
   * @instance
   *
   * @param {string} str a string to synchronize this line to
   */
  synchronizeTo(str) {
    // TODO: handle whitespace chars more consistently.

    // Note: for the purpose of synchronization algorithm, it is important that the
    //       the whitespace char be a single char (rather than   or something)
    let diffs = diff(this.toString().replace(/\s/g, ' '), str.replace(/\s/g, ' '))

    let diffIndex = 0
    for (let i = 0, n = diffs.length; i < n; i++) {
      // each diff in the array takes this shape:
      // [code = 0, 1, -1, change = 'string difference']
      let d = diffs[i]
      switch (d[0]) {
        // no change, simply increment up our string index
        case diff.EQUAL:
          diffIndex = diffIndex + d[1].length
          break

        // there's been (a) sign(s) inserted
        case diff.INSERT:
          d[1].split('').forEach(char => {
            this.insert(
              new Sign({
                chars: [
                  {
                    sign_char: char,
                  },
                ],
              }),
              diffIndex
            )
            diffIndex++
          })
          break

        // there's been a sign deleted
        case diff.DELETE:
          d[1].split('').forEach(() => this.delete(diffIndex))
          break
      }
    }
  }

  toDOMString() {
    let str = ''
    this.forEach(sign => {
      let classes = ''
      const attrs = sign.attributes()
      attrs.forEach(attribute => {
        const name = attribute.attribute_name === '' ? '' : attribute.attribute_name + '_'
        attribute.values.forEach(value => {
          classes += value.attribute_value === '' ? '' : name + value.attribute_value + ' '
        })
      })
      classes += classes.indexOf('is_reconstructed_TRUE') === -1 ? 'is_reconstructed_FALSE' : ''
      str += `<span class="${classes}">${sign.toDOMString()}</span>`
    }, this)

    return `<p data-line-id="${this.getID()}">${str}</p>`
  }

  /**
   * @returns {string} a plain string with all signs
   */
  toString() {
    let str = ''
    this.forEach(sign => {
      str += sign.toString()
    }, this)
    return str
  }
}

export default Line
<|endoftext|>


<commit_before>'use strict';

import $ from 'jquery';

export default class BasisPageEffect {
  constructor(args = {}) {
    this.args = $.extend({
      pageEffect: '.c-page-effect',
      duration: 200
    }, args);
    this.container     = $(this.args.pageEffect);
    this.pageOutObject = $('[data-page-effect-link="true"], a[href]:not([target="_blank"], [href^="#"], [href*="javascript"], [href*=".jpg"], [href*=".jpeg"], [href*=".gif"], [href*=".png"], [href*=".mov"], [href*=".swf"], [href*=".mp4"], [href*=".flv"], [href*=".avi"], [href*=".mp3"], [href*=".pdf"], [href*=".zip"], [href^="mailto:"], [data-page-effect-link="false"])');
    this.setListener();
  }

  setListener() {
    $(window).on('load', (event) => {
      this.hide();
    });

    this.pageOutObject.each((i, e) => {
      const link = $(e);
      link.on('click', (event) => {
        if (event.shiftKey || event.ctrlKey || event.metaKey) {
          return;
        }

        event.preventDefault();
        this.show();
        const url = link.attr('href');
        this.moveLocation(url);
      });
    });
  }

  moveLocation(url) {
    setTimeout(() => {
      location.href = url
    }, this.args['duration']);
  }

  hide() {
    this.container
      .attr('aria-hidden', 'true')
      .attr('data-page-effect', 'fadein');
  }

  show() {
    this.container
      .attr('aria-hidden', 'false')
      .attr('data-page-effect', 'fadeout');
  }
}
<commit_msg>Fix page-effetct js bug<commit_after>'use strict';

import $ from 'jquery';

export default class BasisPageEffect {
  constructor(args = {}) {
    this.args = $.extend({
      pageEffect: '.c-page-effect',
      duration: 200
    }, args);
    this.container     = $(this.args.pageEffect);
    this.pageOutObject = $('[data-page-effect-link="true"], a[href]:not([target="_blank"], [href^="#"], [href*="javascript"], [href*=".jpg"], [href*=".jpeg"], [href*=".gif"], [href*=".png"], [href*=".mov"], [href*=".swf"], [href*=".mp4"], [href*=".flv"], [href*=".avi"], [href*=".mp3"], [href*=".pdf"], [href*=".zip"], [href^="mailto:"], [data-page-effect-link="false"])');
    this.setListener();
  }

  setListener() {
    $(window).on('load', (event) => {
      this.hide();
    });

    this.pageOutObject.each((i, e) => {
      const link = $(e);
      link.on('click', (event) => {
        if (event.shiftKey || event.ctrlKey || event.metaKey) {
          return;
        }

        if ('true' !== link.attr('data-page-effect-link')) {
          return;
        }

        event.preventDefault();
        this.show();
        const url = link.attr('href');
        this.moveLocation(url);
      });
    });
  }

  moveLocation(url) {
    setTimeout(() => {
      location.href = url
    }, this.args['duration']);
  }

  hide() {
    this.container
      .attr('aria-hidden', 'true')
      .attr('data-page-effect', 'fadein');
  }

  show() {
    this.container
      .attr('aria-hidden', 'false')
      .attr('data-page-effect', 'fadeout');
  }
}
<|endoftext|>


<commit_before>// Copyright 2002-2012, University of Colorado

/**
 * Shape handling
 *
 * TODO: add nonzero / evenodd support when browsers support it
 *
 * @author Jonathan Olson
 */

var phet = phet || {};
phet.scene = phet.scene || {};

(function(){

    var Vector2 = phet.math.Vector2;

    // for brevity
    function p( x,y ) {
        return new Vector2( x, y );
    }

    phet.scene.Shape = function( pieces, optionalClose ) {
        this.pieces = pieces !== undefined ? pieces : [];
        if( optionalClose ) {
            this.addPiece( new Piece.Close() );
        }
    }
    var Shape = phet.scene.Shape;

    Shape.LineStyles = function( args ) {
        if( args === undefined ) {
            args = {};
        }
        return {
            lineWidth: args.lineWidth !== undefined ? args.lineWidth : 1,
            lineCap: args.lineCap !== undefined ? args.lineCap : 'butt', // butt, round, square
            lineJoin: args.lineJoin !== undefined ? args.lineJoin : 'miter', // miter, round, bevel
            miterLimit: args.miterLimit !== undefined ? args.miterLimit : 10 // see https://svgwg.org/svg2-draft/painting.html for miterLimit computations
        };
    }
    var LineStyles = Shape.LineStyles;

    // Pieces should be considered immutable
    Shape.Piece = function( points ) {
        this.points = points;
    };
    var Piece = Shape.Piece;

    Piece.prototype = {
        constructor: Piece,

        // override for more specific transforms.
        transformed: function( matrix ) {
            // TODO: implement transformations! -- and verify with unit tests
            return this;
        },

        applyPiece: function( shapeState ) {
            _.each( this.points, function( point ) {
                shapeState.bounds = shapeState.bounds.withPoint( point );
            } );
        }
    };

    // TODO: make a canonical CLOSE?
    Piece.Close = function() {
        Piece.call( this, [] );
    };
    Piece.Close.prototype = Object.create( Piece.prototype );
    Piece.Close.prototype.constructor = Piece.Close;
    Piece.Close.prototype.writeToContext = function( context ) { context.closePath(); };

    Piece.MoveTo = function( point ) {
        Piece.call( this, [ point ] );
        this.point = point;
    };
    Piece.MoveTo.prototype = Object.create( Piece.prototype );
    Piece.MoveTo.prototype.constructor = Piece.MoveTo;
    Piece.MoveTo.prototype.writeToContext = function( context ) { context.moveTo( this.point.x, this.point.y ); };

    Piece.LineTo = function( point ) {
        Piece.call( this, [ point ] );
        this.point = point;
    };
    Piece.LineTo.prototype = Object.create( Piece.prototype );
    Piece.LineTo.prototype.constructor = Piece.LineTo;
    Piece.LineTo.prototype.writeToContext = function( context ) { context.lineTo( this.point.x, this.point.y ); };

    // TODO: transforms for rect are different!!!
    Piece.Rect = function( upperLeft, lowerRight ) {
        Piece.call( this, [ upperLeft, lowerRight ] );
        this.upperLeft = upperLeft;
        this.lowerRight = lowerRight;
        this.x = this.upperLeft.x;
        this.y = this.upperLeft.y;
        this.width = this.lowerRight.x - this.x;
        this.height = this.lowerRight.y - this.y;
    };
    Piece.Rect.prototype = Object.create( Piece.prototype );
    Piece.Rect.prototype.constructor = Piece.Rect;
    Piece.Rect.prototype.writeToContext = function( context ) { context.rect( this.x, this.y, this.width, this.height ); };

    Shape.ShapeState = function() {
        this.subpaths = [];
        this.bounds = phet.math.Bounds2.NOTHING;
    };
    var ShapeState = Shape.ShapeState;

    ShapeState.prototype = {
        constructor: ShapeState,

        ensure: function( point ) {

        }
    };

    Shape.rectangle = function( x, y, width, height ) {
        return new Shape().rect( x, y, width, height );
    };
    Shape.rect = Shape.rectangle;

    Shape.bounds = function( bounds ) {
        return new Shape().rect( p( bounds.xMin, bounds.yMin ), p( bounds.xMax, bounds.yMax ) );
    };

    Shape.lineSegment = function( a, b ) {
        // TODO: add type assertions?
        return new Shape().moveTo( a ).lineTo( b );
    };

    Shape.regularPolygon = function( sides, radius ) {
        return new Shape( _.map( _.range( sides ), function( k ) {
            var theta = 2 * Math.PI * k / sides;
            return new Piece.LineTo( p( radius * Math.cos( theta ), radius * Math.sin( theta ) ) );
        } ), true );
    };

    Shape.prototype = {
        constructor: Shape,

        moveTo: function( x, y ) {
            // moveTo( point )
            if( y === undefined && x instanceof Vector2 ) {
                var point = x;
                this.addPiece( new Piece.MoveTo( point ) );
            } else { // moveTo( x, y )
                this.addPiece( new Piece.MoveTo( p( x, y ) ) );
            }
            return this;
        },

        lineTo: function( x, y ) {
            // lineTo( point )
            if( y === undefined && x instanceof Vector2 ) {
                var point = x;
                this.addPiece( new Piece.LineTo( point ) );
            } else { // lineTo( x, y )
                this.addPiece( new Piece.LineTo( p( x, y ) ) );
            }
            return this;
        },

        rect: function( a, b, c, d ) {
            // rect( upperLeft, lowerRight )
            if( c === undefined && a instanceof Vector2 && b instanceof Vector2 ) {
                this.addPiece( new Piece.Rect( a, b ) );
            } else {
                // rect( x, y, width, height )
                this.addPiece( new Piece.Rect( p( a, b ), p( a + c, b + d ) ) );
            }
            return this;
        },

        addPiece: function( piece ) {
            phet.assert( piece.writeToContext );
            this.pieces.push( piece );
        },

        // write out this shape's path to a canvas 2d context. does NOT include the beginPath()!
        writeToContext: function( context ) {
            _.each( this.pieces, function( piece ) {
                if( !piece.writeToContext ) {
                    console.log( piece );
                }
                piece.writeToContext( context );
            } );
        },

        // return a new Shape that is transformed by the associated matrix
        transformed: function( matrix ) {
            // TODO: reimplement transformations
            return this;
        },

        // returns the bounds. if lineDrawingStyles exists, include the stroke in the bounds
        computeBounds: function( lineDrawingStyles ) {

            var shapeState = new ShapeState();

            // TODO: include stroke information somehow
            _.each( this.pieces, function( piece ) {
                piece.applyPiece( shapeState );
            } );

            return shapeState.bounds;
        },

        traced: function( lineDrawingStyles ) {
            if( lineDrawingStyles === undefined ) {
                lineDrawingStyles = Shape.DEFAULT_STYLES;
            }

            var path = [];
            var subpath = [];

            // TODO: return a shape that is this current shape's traced form with a stroke. see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#trace-a-path
            throw new Error( 'Shape traced unimplemented' );
        }
    };

})();<commit_msg>Piece super class removed<commit_after>// Copyright 2002-2012, University of Colorado

/**
 * Shape handling
 *
 * TODO: add nonzero / evenodd support when browsers support it
 *
 * @author Jonathan Olson
 */

var phet = phet || {};
phet.scene = phet.scene || {};

(function(){

    var Vector2 = phet.math.Vector2;

    // for brevity
    function p( x,y ) {
        return new Vector2( x, y );
    }

    phet.scene.Shape = function( pieces, optionalClose ) {
        this.pieces = pieces !== undefined ? pieces : [];
        if( optionalClose ) {
            this.addPiece( new Piece.Close() );
        }

        // flag to see whether we have
        this.computed = false;

        this.subpaths = [];
    }
    var Shape = phet.scene.Shape;

    Shape.LineStyles = function( args ) {
        if( args === undefined ) {
            args = {};
        }
        return {
            lineWidth: args.lineWidth !== undefined ? args.lineWidth : 1,
            lineCap: args.lineCap !== undefined ? args.lineCap : 'butt', // butt, round, square
            lineJoin: args.lineJoin !== undefined ? args.lineJoin : 'miter', // miter, round, bevel
            miterLimit: args.miterLimit !== undefined ? args.miterLimit : 10 // see https://svgwg.org/svg2-draft/painting.html for miterLimit computations
        };
    }
    var LineStyles = Shape.LineStyles;

    Shape.Piece = {};
    var Piece = Shape.Piece;

    Piece.Close = function() {};
    Piece.Close.prototype = {
        constructor: Piece.Close,

        writeToContext: function( context ) {
            context.closePath();
        },

        transformed: function( matrix ) {
            return [this];
        },

        applyPiece: function( shapeState ) {

        }
    };

    Piece.MoveTo = function( point ) {
        this.point = point;
    };
    Piece.MoveTo.prototype = {
        constructor: Piece.MoveTo,

        writeToContext: function( context ) {
            context.moveTo( this.point.x, this.point.y );
        },

        transformed: function( matrix ) {
            return [new Piece.MoveTo( matrix.timesVector2( this.point ) )];
        },

        applyPiece: function( shapeState ) {
            // TODO: technically, nothing here! - moveTos in a row could cause problems
            shapeState.bounds = shapeState.bounds.withPoint( this.point );
        }
    };

    Piece.LineTo = function( point ) {
        this.point = point;
    };
    Piece.LineTo.prototype = {
        constructor: Piece.LineTo,

        writeToContext: function( context ) {
            context.lineTo( this.point.x, this.point.y );
        },

        transformed: function( matrix ) {
            return [new Piece.LineTo( matrix.timesVector2( this.point ) )];
        },

        applyPiece: function( shapeState ) {
            // TODO: start and end points!
            shapeState.bounds = shapeState.bounds.withPoint( this.point );
        }
    };

    Piece.Rect = function( upperLeft, lowerRight ) {
        this.upperLeft = upperLeft;
        this.lowerRight = lowerRight;
        this.x = this.upperLeft.x;
        this.y = this.upperLeft.y;
        this.width = this.lowerRight.x - this.x;
        this.height = this.lowerRight.y - this.y;
    };
    Piece.Rect.prototype = {
        constructor: Piece.Rect,

        writeToContext: function( context ) {
            context.rect( this.x, this.y, this.width, this.height );
        },

        transformed: function( matrix ) {
            var a = matrix.timesVector2( p( this.x, this.y ) );
            var b = matrix.timesVector2( p( this.x + this.width, this.y ) );
            var c = matrix.timesVector2( p( this.x + this.width, this.y + this.height ) );
            var d = matrix.timesVector2( p( this.x, this.y + this.height ) );
            return [new Piece.MoveTo( a ), new Piece.LineTo( b ), new Piece.LineTo( c ), new Piece.LineTo( d ), new Piece.Close(), new Piece.MoveTo( a )];
        },

        applyPiece: function( shapeState ) {
            shapeState.bounds = shapeState.bounds.withPoint( this.upperLeft ).withPoint( this.lowerRight );
        }
    };

    Shape.ShapeState = function() {
        this.subpaths = [];
        this.bounds = phet.math.Bounds2.NOTHING;
    };
    var ShapeState = Shape.ShapeState;

    ShapeState.prototype = {
        constructor: ShapeState,

        ensure: function( point ) {

        }
    };

    Shape.rectangle = function( x, y, width, height ) {
        return new Shape().rect( x, y, width, height );
    };
    Shape.rect = Shape.rectangle;

    Shape.bounds = function( bounds ) {
        return new Shape().rect( p( bounds.xMin, bounds.yMin ), p( bounds.xMax, bounds.yMax ) );
    };

    Shape.lineSegment = function( a, b ) {
        // TODO: add type assertions?
        return new Shape().moveTo( a ).lineTo( b );
    };

    Shape.regularPolygon = function( sides, radius ) {
        return new Shape( _.map( _.range( sides ), function( k ) {
            var theta = 2 * Math.PI * k / sides;
            return new Piece.LineTo( p( radius * Math.cos( theta ), radius * Math.sin( theta ) ) );
        } ), true );
    };

    Shape.prototype = {
        constructor: Shape,

        moveTo: function( x, y ) {
            // moveTo( point )
            if( y === undefined && x instanceof Vector2 ) {
                var point = x;
                this.addPiece( new Piece.MoveTo( point ) );
            } else { // moveTo( x, y )
                this.addPiece( new Piece.MoveTo( p( x, y ) ) );
            }
            return this;
        },

        lineTo: function( x, y ) {
            // lineTo( point )
            if( y === undefined && x instanceof Vector2 ) {
                var point = x;
                this.addPiece( new Piece.LineTo( point ) );
            } else { // lineTo( x, y )
                this.addPiece( new Piece.LineTo( p( x, y ) ) );
            }
            return this;
        },

        rect: function( a, b, c, d ) {
            // rect( upperLeft, lowerRight )
            if( c === undefined && a instanceof Vector2 && b instanceof Vector2 ) {
                this.addPiece( new Piece.Rect( a, b ) );
            } else {
                // rect( x, y, width, height )
                this.addPiece( new Piece.Rect( p( a, b ), p( a + c, b + d ) ) );
            }
            return this;
        },

        addPiece: function( piece ) {
            phet.assert( piece.writeToContext );
            this.pieces.push( piece );
        },

        // write out this shape's path to a canvas 2d context. does NOT include the beginPath()!
        writeToContext: function( context ) {
            _.each( this.pieces, function( piece ) {
                if( !piece.writeToContext ) {
                    console.log( piece );
                }
                piece.writeToContext( context );
            } );
        },

        // return a new Shape that is transformed by the associated matrix
        transformed: function( matrix ) {
            // TODO: reimplement transformations
            return this;
        },

        // returns the bounds. if lineDrawingStyles exists, include the stroke in the bounds
        computeBounds: function( lineDrawingStyles ) {

            var shapeState = new ShapeState();

            // TODO: include stroke information somehow
            _.each( this.pieces, function( piece ) {
                piece.applyPiece( shapeState );
            } );

            return shapeState.bounds;
        },

        traced: function( lineDrawingStyles ) {
            if( lineDrawingStyles === undefined ) {
                lineDrawingStyles = Shape.DEFAULT_STYLES;
            }

            var path = [];
            var subpath = [];

            // TODO: return a shape that is this current shape's traced form with a stroke. see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#trace-a-path
            throw new Error( 'Shape traced unimplemented' );
        }
    };

})();<|endoftext|>


<commit_before>'use strict';

Darwinator.GameState = function() {

    // Input
    this.cursors               = null;
    this.cheatKey              = null;
    this.pauseKey              = null;

    // Groups
    this.bullets               = null;
    this.gui                   = null;

    // Displayables
    this.fps                   = null;
    this.stats                 = null;
    this.health                = null;
    this.secondsRemaining      = null;
    this.enemiesRemaining      = null;
    this.pauseText             = null;
    this.roundSecondsRemaining = null;
    this.endRoundTimer         = null;
    this.displayTimeLeftTimer  = null;
    this.crosshair             = null;

};

Darwinator.GameState.prototype = {

    init: function (reset) {
        if (!reset) {
            // Input
            this.cursors        = this.game.input.keyboard.createCursorKeys();
            this.cheatKey       = this.game.input.keyboard.addKey(Phaser.Keyboard.E);
            this.pauseKey       = this.game.input.keyboard.addKey(Phaser.Keyboard.P);
            this.fullScreenKey  = this.game.input.keyboard.addKey(Phaser.Keyboard.F);

            // Map
            this.level = new Darwinator.Level(this.game);
            this.level.addTopLayer();

            // Containers
            this.bullets = this.game.add.group();
            this.gui     = this.initGUI();

            // Misc
            this.game.time.advancedTiming = true;
            this.gui.fixedToCamera        = true;
        }

        this.game.add.existing(this.gui);
        this.game.add.existing(this.bullets);

        this.cheatKey.onDown.add(this.endRound, this);
        this.pauseKey.onDown.add(this.togglePause, this);
        this.game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL;
        this.fullScreenKey.onDown.add(this.goFullScreen, this);

        // Since states lack a callback for the resume event
        this.game.onResume.add(this.resumed, this);
    },

    beforeSwitch: function () {
        this.game.world.remove(this.game.player);
        this.game.world.remove(this.game.enemies);
        this.game.world.remove(this.gui);
        this.game.world.remove(this.bullets);

        this.cheatKey.onDown.remove(this.endRound, this);
        this.pauseKey.onDown.remove(this.togglePause, this);
        this.game.onResume.remove(this.resumed, this);

        this.stopTimers();
        this.game.time.events.remove(this.game.player.dodgeTimer);
        this.game.player.alpha = 1;
        this.game.player.dodging = false;
    },

    create: function () {

        this.spawnPlayer(160, 620);
        this.game.enemies = this.level.spawnEnemies();

        // TODO Find the right way to do this
        this.game.enemies.setAll('alive', true);

        this.game.world.bringToTop(this.level.toplayer);

        for (var i = 0; i < this.game.enemies.length; i++) {
            var enemy = this.game.enemies.getAt(i);
            var weapon = new Darwinator.Cannon(this.game, enemy, this.bullets);
            enemy.arm(weapon);
        }

        this.game.player.weapon = new Darwinator.Bow(this.game, this.game.player, this.bullets);

        this.game.world.bringToTop(this.gui);

        this.startTimers();

        this.game.level = this.level;

        // Hide the cursor
        this.game.canvas.style.cursor = "none";
    },

    initGUI: function () {
        var gui   = this.game.add.group(),
            style = { font: '16px monospace', fill: '#fff' },
            x     = this.game.width  / 2,
            y     = this.game.height / 2;

        this.fps              = gui.add(new Phaser.Text(this.game, 16, 16, 'FPS: 0', style));
        this.stats            = gui.add(new Phaser.Text(this.game, 16, 36, '', style));
        this.health           = gui.add(new Phaser.Text(this.game, 16, 56, '', style));
        this.secondsRemaining = gui.add(new Phaser.Text(this.game, 16, 76, 'Seconds remaining: ' + Darwinator.ROUND_LENGTH_SECONDS, style));
        this.enemiesRemaining = gui.add(new Phaser.Text(this.game, 16, 96, 'Enemies remaining: ', style));
        this.pauseText        = gui.add(new Phaser.Text(this.game, x, y, 'Game paused', style));
        this.gameOver         = gui.add(new Phaser.Text(this.game, x, y, 'Game Over', {fontSize: '24px monospace', fill:'#FFF'}));

        this.pauseText.anchor.setTo(0.5, 0.5);
        this.gameOver.anchor.setTo(0.5, 0.5);

        // Should be hidden by default
        this.pauseText.visible = false;
        this.gameOver.visible  = false;

        this.crosshair = gui.add(this.game.add.sprite(this.game.input.activePointer.x, this.game.input.activePointer.y, 'crosshair'));
        this.crosshair.scale.setTo(1.5, 1.5);
        this.crosshair.anchor.setTo(0.5, 0.5);
        return gui;
    },

    startTimers: function () {
        // End round when the time limit is reached
        this.endRoundTimer = this.game.time.events.add(Phaser.Timer.SECOND * Darwinator.ROUND_LENGTH_SECONDS, this.endRound, this);
        // Display seconds remaining until round ends
        this.roundSecondsRemaining = Darwinator.ROUND_LENGTH_SECONDS;
        this.displayTimeLeftTimer = this.game.time.events.repeat(Phaser.Timer.SECOND, Darwinator.ROUND_LENGTH_SECONDS, this.updateTimer, this);
    },

    stopTimers: function () {
        this.game.time.events.remove(this.endRoundTimer);
        this.game.time.events.remove(this.displayTimeLeftTimer);
        this.secondsRemaining.text = 'Seconds remaining: ' + Darwinator.ROUND_LENGTH_SECONDS;
    },

    spawnPlayer: function (x, y) {
        // Instanciate new player or reset existing
        if (!this.game.player) {
            this.game.player = new Darwinator.Player(this.game, x, y, this.cursors);
        } else {
            this.game.player.reset(x, y, Darwinator.PLAYER_BASE_HEALTH);
            this.game.player.resetAttributes();
        }

        // Add player sprite to stage and focus camera
        this.game.add.existing(this.game.player);
        this.game.camera.follow(this.game.player);
    },

    update: function () {
        //console.log(this.crosshair);
        for (var i = 0; i < this.bullets.length; i++) {
            var bulletGroup = this.bullets.getAt(i);
            this.game.physics.arcade.collide(bulletGroup, this.game.enemies, this.bulletCollisionHandler, null, this);
            this.game.physics.arcade.collide(bulletGroup, this.level.collisionLayer, this.bulletCollisionHandler, null, this);
            this.game.physics.arcade.collide(bulletGroup, this.game.player, this.bulletCollisionHandler, null, this);
        }

        this.game.physics.arcade.collide(this.game.player, this.level.collisionLayer);
        this.game.physics.arcade.collide(this.game.enemies, this.level.collisionLayer);

        this.updateGUI();

        // End round when all enemies are dead
        if (this.game.enemies.countLiving() === 0) {
            this.endRound();
        }

        if (this.game.player.health <= 0) {
            if (this.game.player.immortal) {
              this.game.player.health = 100;
            } else {
              this.game.player.kill();
              // this.game.player.reset();
              this.gameover();
            }
        }
    },

    updateGUI: function () {
        this.fps.text = 'FPS: ' + this.game.time.fps;
        this.stats.text = 'Player stamina: ' + Math.round(this.game.player.currBreath) + '/' + Math.round(this.game.player.stamina);
        this.health.text = 'Health: ' + Math.round(this.game.player.health);
        this.enemiesRemaining.text = 'Enemies remaining: ' + this.game.enemies.countLiving();

        var pointer = this.game.input.activePointer;
        this.crosshair.x = pointer.x;
        this.crosshair.y = pointer.y;
    },

    updateTimer: function () { // Callback to update time remaining display every second
        this.roundSecondsRemaining--;
        this.secondsRemaining.text = 'Seconds remaining: ' + this.roundSecondsRemaining;
    },

    bulletCollisionHandler: function (bullet, target) {
        /* It seems Phaser is a bit inconsistent with which parameter is sent first */
        if (bullet instanceof Darwinator.Entity) {
            var tmp = bullet;
            bullet = target;
            target = tmp;
        }
        /* Only do deal damage and remove bullet if the target was a entity of another type than the owner
        of the bullet */
        if (target instanceof Darwinator.Player && bullet.owner instanceof Darwinator.Player ||
            target instanceof Darwinator.Enemy && bullet.owner instanceof Darwinator.Enemy) {
            if (!(bullet instanceof Darwinator.Entity)) {
                bullet.kill();
            }
            return;
        }
        if (target instanceof Darwinator.Entity && !target.dodging) {
            var dmg = bullet.owner.damage;
            target.takeDamage(dmg);
            if(target instanceof Darwinator.Player){
              var enemy = bullet.owner;
              enemy.damageDone += dmg;
            }
        }
        if (!(bullet instanceof Darwinator.Entity)) {
            bullet.kill();
        }
    },

    endRound: function() {
        this.beforeSwitch();
        this.game.state.start('result', false);
    },

    gameover: function() {
        this.beforeSwitch()
        this.game.state.start('gameover', false);
    },

    togglePause: function() {
        this.game.paused = !this.game.paused;
    },

    paused: function () {
        this.pauseText.visible = true;
        console.log('Paused game.');
    },

    resumed: function() {
        this.pauseText.visible = false;
        console.log('Resumed game.');
    },

    goFullScreen: function(){
      this.game.scale.startFullScreen();
    },

};
<commit_msg>kill bullets when round ends<commit_after>'use strict';

Darwinator.GameState = function() {

    // Input
    this.cursors               = null;
    this.cheatKey              = null;
    this.pauseKey              = null;

    // Groups
    this.bullets               = null;
    this.gui                   = null;

    // Displayables
    this.fps                   = null;
    this.stats                 = null;
    this.health                = null;
    this.secondsRemaining      = null;
    this.enemiesRemaining      = null;
    this.pauseText             = null;
    this.roundSecondsRemaining = null;
    this.endRoundTimer         = null;
    this.displayTimeLeftTimer  = null;
    this.crosshair             = null;

};

Darwinator.GameState.prototype = {

    init: function (reset) {
        if (!reset) {
            // Input
            this.cursors        = this.game.input.keyboard.createCursorKeys();
            this.cheatKey       = this.game.input.keyboard.addKey(Phaser.Keyboard.E);
            this.pauseKey       = this.game.input.keyboard.addKey(Phaser.Keyboard.P);
            this.fullScreenKey  = this.game.input.keyboard.addKey(Phaser.Keyboard.F);

            // Map
            this.level = new Darwinator.Level(this.game);
            this.level.addTopLayer();

            // Containers
            this.bullets = this.game.add.group();
            this.gui     = this.initGUI();

            // Misc
            this.game.time.advancedTiming = true;
            this.gui.fixedToCamera        = true;
        }

        this.game.add.existing(this.gui);
        this.game.add.existing(this.bullets);

        this.cheatKey.onDown.add(this.endRound, this);
        this.pauseKey.onDown.add(this.togglePause, this);
        this.game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL;
        this.fullScreenKey.onDown.add(this.goFullScreen, this);

        // Since states lack a callback for the resume event
        this.game.onResume.add(this.resumed, this);
    },

    beforeSwitch: function () {
        this.game.world.remove(this.game.player);
        this.game.world.remove(this.game.enemies);
        this.game.world.remove(this.gui);
        this.game.world.remove(this.bullets);

        this.cheatKey.onDown.remove(this.endRound, this);
        this.pauseKey.onDown.remove(this.togglePause, this);
        this.game.onResume.remove(this.resumed, this);

        this.stopTimers();

        this.game.time.events.remove(this.game.player.dodgeTimer);
        this.game.player.alpha = 1;
        this.game.player.dodging = false;

        for(var i = 0; i < this.bullets.length; i++){
            var bulletGroup = this.bullets.getAt(i);
            bulletGroup.forEachAlive(function(bullet){bullet.kill();}, this);
        }
    },

    create: function () {

        this.spawnPlayer(160, 620);
        this.game.enemies = this.level.spawnEnemies();

        // TODO Find the right way to do this
        this.game.enemies.setAll('alive', true);

        this.game.world.bringToTop(this.level.toplayer);

        for (var i = 0; i < this.game.enemies.length; i++) {
            var enemy = this.game.enemies.getAt(i);
            var weapon = new Darwinator.Cannon(this.game, enemy, this.bullets);
            enemy.arm(weapon);
        }

        this.game.player.weapon = new Darwinator.Bow(this.game, this.game.player, this.bullets);

        this.game.world.bringToTop(this.gui);

        this.startTimers();

        this.game.level = this.level;

        // Hide the cursor
        this.game.canvas.style.cursor = "none";
    },

    initGUI: function () {
        var gui   = this.game.add.group(),
            style = { font: '16px monospace', fill: '#fff' },
            x     = this.game.width  / 2,
            y     = this.game.height / 2;

        this.fps              = gui.add(new Phaser.Text(this.game, 16, 16, 'FPS: 0', style));
        this.stats            = gui.add(new Phaser.Text(this.game, 16, 36, '', style));
        this.health           = gui.add(new Phaser.Text(this.game, 16, 56, '', style));
        this.secondsRemaining = gui.add(new Phaser.Text(this.game, 16, 76, 'Seconds remaining: ' + Darwinator.ROUND_LENGTH_SECONDS, style));
        this.enemiesRemaining = gui.add(new Phaser.Text(this.game, 16, 96, 'Enemies remaining: ', style));
        this.pauseText        = gui.add(new Phaser.Text(this.game, x, y, 'Game paused', style));
        this.gameOver         = gui.add(new Phaser.Text(this.game, x, y, 'Game Over', {fontSize: '24px monospace', fill:'#FFF'}));

        this.pauseText.anchor.setTo(0.5, 0.5);
        this.gameOver.anchor.setTo(0.5, 0.5);

        // Should be hidden by default
        this.pauseText.visible = false;
        this.gameOver.visible  = false;

        this.crosshair = gui.add(this.game.add.sprite(this.game.input.activePointer.x, this.game.input.activePointer.y, 'crosshair'));
        this.crosshair.scale.setTo(1.5, 1.5);
        this.crosshair.anchor.setTo(0.5, 0.5);
        return gui;
    },

    startTimers: function () {
        // End round when the time limit is reached
        this.endRoundTimer = this.game.time.events.add(Phaser.Timer.SECOND * Darwinator.ROUND_LENGTH_SECONDS, this.endRound, this);
        // Display seconds remaining until round ends
        this.roundSecondsRemaining = Darwinator.ROUND_LENGTH_SECONDS;
        this.displayTimeLeftTimer = this.game.time.events.repeat(Phaser.Timer.SECOND, Darwinator.ROUND_LENGTH_SECONDS, this.updateTimer, this);
    },

    stopTimers: function () {
        this.game.time.events.remove(this.endRoundTimer);
        this.game.time.events.remove(this.displayTimeLeftTimer);
        this.secondsRemaining.text = 'Seconds remaining: ' + Darwinator.ROUND_LENGTH_SECONDS;
    },

    spawnPlayer: function (x, y) {
        // Instanciate new player or reset existing
        if (!this.game.player) {
            this.game.player = new Darwinator.Player(this.game, x, y, this.cursors);
        } else {
            this.game.player.reset(x, y, Darwinator.PLAYER_BASE_HEALTH);
            this.game.player.resetAttributes();
        }

        // Add player sprite to stage and focus camera
        this.game.add.existing(this.game.player);
        this.game.camera.follow(this.game.player);
    },

    update: function () {
        //console.log(this.crosshair);
        for (var i = 0; i < this.bullets.length; i++) {
            var bulletGroup = this.bullets.getAt(i);
            this.game.physics.arcade.collide(bulletGroup, this.game.enemies, this.bulletCollisionHandler, null, this);
            this.game.physics.arcade.collide(bulletGroup, this.level.collisionLayer, this.bulletCollisionHandler, null, this);
            this.game.physics.arcade.collide(bulletGroup, this.game.player, this.bulletCollisionHandler, null, this);
        }

        this.game.physics.arcade.collide(this.game.player, this.level.collisionLayer);
        this.game.physics.arcade.collide(this.game.enemies, this.level.collisionLayer);

        this.updateGUI();

        // End round when all enemies are dead
        if (this.game.enemies.countLiving() === 0) {
            this.endRound();
        }

        if (this.game.player.health <= 0) {
            if (this.game.player.immortal) {
              this.game.player.health = 100;
            } else {
              this.game.player.kill();
              // this.game.player.reset();
              this.gameover();
            }
        }
    },

    updateGUI: function () {
        this.fps.text = 'FPS: ' + this.game.time.fps;
        this.stats.text = 'Player stamina: ' + Math.round(this.game.player.currBreath) + '/' + Math.round(this.game.player.stamina);
        this.health.text = 'Health: ' + Math.round(this.game.player.health);
        this.enemiesRemaining.text = 'Enemies remaining: ' + this.game.enemies.countLiving();

        var pointer = this.game.input.activePointer;
        this.crosshair.x = pointer.x;
        this.crosshair.y = pointer.y;
    },

    updateTimer: function () { // Callback to update time remaining display every second
        this.roundSecondsRemaining--;
        this.secondsRemaining.text = 'Seconds remaining: ' + this.roundSecondsRemaining;
    },

    bulletCollisionHandler: function (bullet, target) {
        /* It seems Phaser is a bit inconsistent with which parameter is sent first */
        if (bullet instanceof Darwinator.Entity) {
            var tmp = bullet;
            bullet = target;
            target = tmp;
        }
        /* Only do deal damage and remove bullet if the target was a entity of another type than the owner
        of the bullet */
        if (target instanceof Darwinator.Player && bullet.owner instanceof Darwinator.Player ||
            target instanceof Darwinator.Enemy && bullet.owner instanceof Darwinator.Enemy) {
            if (!(bullet instanceof Darwinator.Entity)) {
                bullet.kill();
            }
            return;
        }
        if (target instanceof Darwinator.Entity && !target.dodging) {
            var dmg = bullet.owner.damage;
            target.takeDamage(dmg);
            if(target instanceof Darwinator.Player){
              var enemy = bullet.owner;
              enemy.damageDone += dmg;
            }
        }
        if (!(bullet instanceof Darwinator.Entity)) {
            bullet.kill();
        }
    },

    endRound: function() {
        this.beforeSwitch();
        this.game.state.start('result', false);
    },

    gameover: function() {
        this.beforeSwitch()
        this.game.state.start('gameover', false);
    },

    togglePause: function() {
        this.game.paused = !this.game.paused;
    },

    paused: function () {
        this.pauseText.visible = true;
        console.log('Paused game.');
    },

    resumed: function() {
        this.pauseText.visible = false;
        console.log('Resumed game.');
    },

    goFullScreen: function(){
      this.game.scale.startFullScreen();
    },

};
<|endoftext|>


<commit_before>import {attr} from './attr';
import {once} from './event';
import {Promise} from './promise';
import {assign, includes, isString, toNode} from './lang';

let id = 0;

export class Player {

    constructor(el) {
        this.id = ++id;
        this.el = toNode(el);
    }

    isVideo() {
        return this.isYoutube() || this.isVimeo() || this.isHTML5();
    }

    isHTML5() {
        return this.el.tagName === 'VIDEO';
    }

    isIFrame() {
        return this.el.tagName === 'IFRAME';
    }

    isYoutube() {
        return this.isIFrame() && !!this.el.src.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/(watch\?v=[^&\s]+|embed)|youtu\.be\/.*/);
    }

    isVimeo() {
        return this.isIFrame() && !!this.el.src.match(/vimeo\.com\/video\/.*/);
    }

    enableApi() {

        if (this.ready) {
            return this.ready;
        }

        const youtube = this.isYoutube();
        const vimeo = this.isVimeo();

        let poller;

        if (youtube || vimeo) {

            return this.ready = new Promise(resolve => {

                once(this.el, 'load', () => {
                    if (youtube) {
                        const listener = () => post(this.el, {event: 'listening', id: this.id});
                        poller = setInterval(listener, 100);
                        listener();
                    }
                });

                listen(data => youtube && data.id === this.id && data.event === 'onReady' || vimeo && Number(data.player_id) === this.id)
                    .then(() => {
                        resolve();
                        poller && clearInterval(poller);
                    });

                attr(this.el, 'src', `${this.el.src}${includes(this.el.src, '?') ? '&' : '?'}${youtube ? 'enablejsapi=1' : `api=1&player_id=${this.id}`}`);

            });

        }

        return Promise.resolve();

    }

    play() {

        if (!this.isVideo()) {
            return;
        }

        if (this.isIFrame()) {
            this.enableApi().then(() => post(this.el, {func: 'playVideo', method: 'play'}));
        } else if (this.isHTML5()) {
            try {
                const promise = this.el.play();

                if (promise) {
                    promise.catch(() => {
                        if (!this.el.muted) {
                            this.el.muted = true;
                            this.play();
                        }
                    });
                }
            } catch (e) {}
        }
    }

    pause() {

        if (!this.isVideo()) {
            return;
        }

        if (this.isIFrame()) {
            this.enableApi().then(() => post(this.el, {func: 'pauseVideo', method: 'pause'}));
        } else if (this.isHTML5()) {
            this.el.pause();
        }
    }

    mute() {

        if (!this.isVideo()) {
            return;
        }

        if (this.isIFrame()) {
            this.enableApi().then(() => post(this.el, {func: 'mute', method: 'setVolume', value: 0}));
        } else if (this.isHTML5()) {
            this.el.muted = true;
            attr(this.el, 'muted', '');
        }

    }

}

function post(el, cmd) {
    try {
        el.contentWindow.postMessage(JSON.stringify(assign({event: 'command'}, cmd)), '*');
    } catch (e) {}
}

function listen(cb) {

    return new Promise(resolve => {

        once(window, 'message', (_, data) => resolve(data), false, ({data}) => {

            if (!data || !isString(data)) {
                return;
            }

            try {
                data = JSON.parse(data);
            } catch (e) {
                return;
            }

            return data && cb(data);

        });

    });

}
<commit_msg>update<commit_after>import {attr} from './attr';
import {once} from './event';
import {Promise} from './promise';
import {assign, includes, isString, noop, toNode} from './lang';

let id = 0;

export class Player {

    constructor(el) {
        this.id = ++id;
        this.el = toNode(el);
    }

    isVideo() {
        return this.isYoutube() || this.isVimeo() || this.isHTML5();
    }

    isHTML5() {
        return this.el.tagName === 'VIDEO';
    }

    isIFrame() {
        return this.el.tagName === 'IFRAME';
    }

    isYoutube() {
        return this.isIFrame() && !!this.el.src.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/(watch\?v=[^&\s]+|embed)|youtu\.be\/.*/);
    }

    isVimeo() {
        return this.isIFrame() && !!this.el.src.match(/vimeo\.com\/video\/.*/);
    }

    enableApi() {

        if (this.ready) {
            return this.ready;
        }

        const youtube = this.isYoutube();
        const vimeo = this.isVimeo();

        let poller;

        if (youtube || vimeo) {

            return this.ready = new Promise(resolve => {

                once(this.el, 'load', () => {
                    if (youtube) {
                        const listener = () => post(this.el, {event: 'listening', id: this.id});
                        poller = setInterval(listener, 100);
                        listener();
                    }
                });

                listen(data => youtube && data.id === this.id && data.event === 'onReady' || vimeo && Number(data.player_id) === this.id)
                    .then(() => {
                        resolve();
                        poller && clearInterval(poller);
                    });

                attr(this.el, 'src', `${this.el.src}${includes(this.el.src, '?') ? '&' : '?'}${youtube ? 'enablejsapi=1' : `api=1&player_id=${this.id}`}`);

            });

        }

        return Promise.resolve();

    }

    play() {

        if (!this.isVideo()) {
            return;
        }

        if (this.isIFrame()) {
            this.enableApi().then(() => post(this.el, {func: 'playVideo', method: 'play'}));
        } else if (this.isHTML5()) {
            try {
                const promise = this.el.play();

                if (promise) {
                    promise.catch(noop);
                }
            } catch (e) {}
        }
    }

    pause() {

        if (!this.isVideo()) {
            return;
        }

        if (this.isIFrame()) {
            this.enableApi().then(() => post(this.el, {func: 'pauseVideo', method: 'pause'}));
        } else if (this.isHTML5()) {
            this.el.pause();
        }
    }

    mute() {

        if (!this.isVideo()) {
            return;
        }

        if (this.isIFrame()) {
            this.enableApi().then(() => post(this.el, {func: 'mute', method: 'setVolume', value: 0}));
        } else if (this.isHTML5()) {
            this.el.muted = true;
            attr(this.el, 'muted', '');
        }

    }

}

function post(el, cmd) {
    try {
        el.contentWindow.postMessage(JSON.stringify(assign({event: 'command'}, cmd)), '*');
    } catch (e) {}
}

function listen(cb) {

    return new Promise(resolve => {

        once(window, 'message', (_, data) => resolve(data), false, ({data}) => {

            if (!data || !isString(data)) {
                return;
            }

            try {
                data = JSON.parse(data);
            } catch (e) {
                return;
            }

            return data && cb(data);

        });

    });

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";
    var log = require("js/util/log");

    var isMac = navigator.platform.indexOf("Mac") === 0;

    var getKeyCode = function (event) {
        if (!isMac && event.key === "Unidentified") {
            switch (event.keyCode) {
                case 55:
                    return "ArrowUp";
                case 53:
                    return "ArrowLeft";
                case 222:
                    return "ArrowRight";
                case 57:
                    return "ArrowDown";
                default:
                    return "Unidentified";
            }
        } else {
            return event.key;
        }
    };

    exports.isMac = isMac;

    exports.getKeyCode = getKeyCode;
});
<commit_msg>Review fixes<commit_after>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";
    var isMac = navigator.platform.indexOf("Mac") === 0;

    /**
     * On Win, arrow keys do not send us the right key value
     * So we have this function to return us the correct key value
     * @param  {SyntheticEvent} event
     * @return {string} key name
     */
    var getKeyCode = function (event) {
        if (!isMac && event.key === "Unidentified") {
            switch (event.keyCode) {
                case 55:
                    return "ArrowUp";
                case 53:
                    return "ArrowLeft";
                case 222:
                    return "ArrowRight";
                case 57:
                    return "ArrowDown";
                default:
                    return "Unidentified";
            }
        } else {
            return event.key;
        }
    };

    exports.isMac = isMac;

    exports.getKeyCode = getKeyCode;
});
<|endoftext|>


<commit_before>define(function(require) {
    'use strict';

    var _ = require('lodash');
    var moment = require('moment');
    var React = require('react');

    var Utils = {
        guid: (function() {
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                    .toString(16)
                    .substring(1);
            }
            return function() {
                return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
                    s4() + '-' + s4() + s4() + s4();
            };
        })(),

        /**
         * Get formatted time string given the start and end times.
         * @param  {Int} start - Start timestamp.
         * @param  {Int} end - End timestamp.
         * @param  {Bool} includeDate - Whether time should include date.
         * @return {String} - Formatted time optionally prepended by date.
         */
        calculateTimeString: function(start, end, includeDate) {
            var format = 'h:mm A',
                startTime = moment(start).format(format),
                endTime = moment(end).format(format);

            var date = includeDate ? moment(start).format('MMM Do,') : '';

            // If same minute, just show a single minute, not a range.
            if(startTime === endTime){
                return date + " " + startTime;
            }

            return date + " " + startTime + ' - ' + endTime;
        },

        /**
         * Retrieves the loader classes for a component.
         * @param {Bool} loading - The loading state of a component.
         * @param {Array|String} iconClasses - The classes to add to the loader when loading.
         * @returns {Object} - classSet
         */
        getLoaderClasses: function(loading, iconClasses) {
            if (typeof iconClasses === 'string') {
                iconClasses = iconClasses.split(' ');
            }
            if (!iconClasses || !_.isArray(iconClasses)) {
                iconClasses = ['icon', 'ion-loading-c'];
            }
            var classes = {
                'loader': true,
                'hide': !loading
            };

            _.forEach(iconClasses, function(iconClass) {
                classes[iconClass] = loading;
            });

            return this.classSet(classes);
        },

        /**
         * Utility for creating a string of class names. Each parameter should be the
         * string class name to add, or an object where the key is the classname to add and the
         * value is a boolean value denoting whether it should be added or not.
         *
         * Copied from `classnames` open source project
         *
         * @author JedWatson
         * @license MIT
         * @link https://github.com/JedWatson/classnames
         *
         * @param  {...String|Object} var_args An argument for each class to add
         * @return {String}         String of class names separated by space
         */
        classSet: function() {
            var args = arguments;
            var classes = [];

            for (var i = 0; i < args.length; i++) {
                var arg = args[i];
                if (!arg) {
                    continue;
                }

                if ('string' === typeof arg || 'number' === typeof arg) {
                    classes.push(arg);
                }
                else if ('object' === typeof arg) {
                    for (var key in arg) {
                        if (arg.hasOwnProperty(key) && arg[key]) {
                            classes.push(key);
                        }
                    }
                }
            }
            return classes.join(' ');
        },

        /**
         * Starts with a base object that contains all of the functions to create the base react class from. The
         * clobber object contains functions that will overwrite 1 or more functions that exist on the base. The clobbered
         * base object is then assigned as the mixins property of the add object. The add object contains new functions
         * that did not originally exist on the base as well as lifecycle functions that will be called both from the
         * mixins object and the add object. The new React Class is simply the add object with a mixins property containing
         * the base React Class functions that have been potentially altered to yield new functionality.
         * @param {Object} base - A React Class definition object.
         * @param {Object} clobber - The functions to overwrite on the base object.
         * @param {Object} add - The new methods and duplicate lifecycle methods to add to the React Class.
         * @returns {Object} - A React Class
         */
        extendReactClass: function(base, clobber, add) {
            add.mixins = [_.extend(_.cloneDeep(base), clobber)];

            return React.createClass(add);
        }
    };

    return Utils;
});
<commit_msg>Simplified guid function in utils.<commit_after>define(function(require) {
    'use strict';

    var _ = require('lodash');
    var moment = require('moment');
    var React = require('react');

    var Utils = {
        guid: function() {
            var s4 = function() {
                return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
            };
            return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
        },

        /**
         * Get formatted time string given the start and end times.
         * @param  {Int} start - Start timestamp.
         * @param  {Int} end - End timestamp.
         * @param  {Bool} includeDate - Whether time should include date.
         * @return {String} - Formatted time optionally prepended by date.
         */
        calculateTimeString: function(start, end, includeDate) {
            var format = 'h:mm A',
                startTime = moment(start).format(format),
                endTime = moment(end).format(format);

            var date = includeDate ? moment(start).format('MMM Do,') : '';

            // If same minute, just show a single minute, not a range.
            if(startTime === endTime){
                return date + " " + startTime;
            }

            return date + " " + startTime + ' - ' + endTime;
        },

        /**
         * Retrieves the loader classes for a component.
         * @param {Bool} loading - The loading state of a component.
         * @param {Array|String} iconClasses - The classes to add to the loader when loading.
         * @returns {Object} - classSet
         */
        getLoaderClasses: function(loading, iconClasses) {
            if (typeof iconClasses === 'string') {
                iconClasses = iconClasses.split(' ');
            }
            if (!iconClasses || !_.isArray(iconClasses)) {
                iconClasses = ['icon', 'ion-loading-c'];
            }
            var classes = {
                'loader': true,
                'hide': !loading
            };

            _.forEach(iconClasses, function(iconClass) {
                classes[iconClass] = loading;
            });

            return this.classSet(classes);
        },

        /**
         * Utility for creating a string of class names. Each parameter should be the
         * string class name to add, or an object where the key is the classname to add and the
         * value is a boolean value denoting whether it should be added or not.
         *
         * Copied from `classnames` open source project
         *
         * @author JedWatson
         * @license MIT
         * @link https://github.com/JedWatson/classnames
         *
         * @param  {...String|Object} var_args An argument for each class to add
         * @return {String}         String of class names separated by space
         */
        classSet: function() {
            var args = arguments;
            var classes = [];

            for (var i = 0; i < args.length; i++) {
                var arg = args[i];
                if (!arg) {
                    continue;
                }

                if ('string' === typeof arg || 'number' === typeof arg) {
                    classes.push(arg);
                }
                else if ('object' === typeof arg) {
                    for (var key in arg) {
                        if (arg.hasOwnProperty(key) && arg[key]) {
                            classes.push(key);
                        }
                    }
                }
            }
            return classes.join(' ');
        },

        /**
         * Starts with a base object that contains all of the functions to create the base react class from. The
         * clobber object contains functions that will overwrite 1 or more functions that exist on the base. The clobbered
         * base object is then assigned as the mixins property of the add object. The add object contains new functions
         * that did not originally exist on the base as well as lifecycle functions that will be called both from the
         * mixins object and the add object. The new React Class is simply the add object with a mixins property containing
         * the base React Class functions that have been potentially altered to yield new functionality.
         * @param {Object} base - A React Class definition object.
         * @param {Object} clobber - The functions to overwrite on the base object.
         * @param {Object} add - The new methods and duplicate lifecycle methods to add to the React Class.
         * @returns {Object} - A React Class
         */
        extendReactClass: function(base, clobber, add) {
            add.mixins = [_.extend(_.cloneDeep(base), clobber)];

            return React.createClass(add);
        }
    };

    return Utils;
});
<|endoftext|>