<commit_before>var wideScreen = 641;
 'use strict';
  var _ = require('lodash');
  moj.Modules.FindLegalAdviser = {
    el: '#resultsMap',
    markers: [],
    searchLocationMarker: null,
    openInfoWindow: null,
    eventsBound: false,

    init: function() {
      this.cacheEls();

      this._handleMQTest();

      if(!this.$resultsMap.length) {
        return;
      }

      this.renderMap(this.$resultsMap.data('lat'), this.$resultsMap.data('lon'));
      this._prepareMarkers();

      $(window).resize(_.debounce($.proxy(this._handleMQTest, this), 500));
    },

    // Handle events which rely on media queries
    _handleMQTest: function() {
      if(window.Modernizr.mq('(min-width: ' + wideScreen + 'px)')) {
        if(!this.eventsBound) {
          this.bindEvents();
        }
      } else if(this.eventsBound) {
        this._unbindEvents();
      }
    },

    bindEvents: function() {
      var self = this;
      this.$organisationListItems.find('.org-summary').each(function() {
        $(this).replaceWith('' + $(this).html() + '');
      });

      this.$organisationListItems.on('click', '.org-summary', function(evt) {
        evt.preventDefault();
        self.$organisationListItems.find('.org-summary').attr('aria-expanded', false);
        self._handleItemHighlight(evt, $(this).closest('li'));
      });

      this.$resultsPagination.on('click', 'a', function(evt) {
        evt.preventDefault();

        if(window.LABELS && window.LABELS.loading) {
          $(evt.target).replaceWith('' + window.LABELS.loading + '');
        }

        self._fetchPage(evt.target.href);

        if(window.history && history.pushState) {
          history.pushState(null, null, evt.target.href);
        }
      });

      this.$findLegalAdviserForm.submit(function(evt) {
        evt.preventDefault();

        var url = document.location.pathname + '?' + $(this).serialize();
        self._fetchPage(url, true);

        if(window.history && history.pushState) {
          history.pushState(null, null, url);
        }

        if(!self.$resultsMap.length) {
          $('
' + window.LABELS.loading + '
').insertAfter($(this));
        }
      });

      window.onpopstate = function() {
        self._fetchPage(document.location.href);
      };

      this.eventsBound = true;
    },

    _unbindEvents: function() {
      this.$organisationListItems
        .unbind('click')
        .find('.org-summary')
        .each(function() {
          $(this).replaceWith('' + $(this).html() + '');
        });

      this.$resultsPagination.unbind('click');
      this.$findLegalAdviserForm.unbind('submit');
      window.onpopstate = null;

      this.eventsBound = false;
    },

    _fetchPage: function(url, scrollToResults) {
      var self = this;

      $.get(url)
        .success(function(data) {
          self.$findLegalAdviserContainer.replaceWith(data);
          self.markers = [];
          self.eventsBound = false;
          self.init();

          if(scrollToResults) {
            $('html, body').delay(300).animate({
              'scrollTop': self.$findLegalAdviserContainer.offset().top - 10
            }, 160);
          }

          $('.search-results-list').attr('tabindex', -1).focus();

          window.ga('send', 'pageview', stripPII(url));
        })
        .error();
    },

    _closeOpenInfoWindow: function() {
      if(this.openInfoWindow) {
        this.openInfoWindow.close();
      }
    },

    _prepareMarkers: function() {
      var organisations = $.map(this.$organisationListItems, function(item) {
        var $item = $(item);
        return {
          id: $item.data('id'),
          position: {
            lat: parseFloat($item.data('lat')),
            lng: parseFloat($item.data('lon'))
          },
          title: $item.find('.fn').text(),
          content: $item.html()
        };
      });

      this.addMarkers(organisations);
    },

    _fitAllMarkers: function() {
      var self = this;

      this.map.fitBounds(this.markers.reduce(function(bounds, marker) {
        return bounds.extend(marker.getPosition());
      }, new google.maps.LatLngBounds()));

      $.each(this.markers, function() {
        this.setMap(self.map);
      });
    },

    _handleHighlightedItemScroll: function($item, $container) {
      var itemHeight = $item.outerHeight();
      var containerHeight = $container.height();

      if(itemHeight + $item.position().top > containerHeight) {
        $container.scrollTop(containerHeight - itemHeight);
      }
    },

    _handleMarkersZooming: function(selectedMarkerId) {
      var markerOnMap = _.find(this.markers, { id: selectedMarkerId });

      $.each(this.markers, function() {
        this.setMap(null);
      });

      markerOnMap.setMap(this.map);

      var pairBounds = new google.maps.LatLngBounds();
      pairBounds.extend(markerOnMap.position);
      pairBounds.extend(this.searchLocationMarker.position);

      this.map.fitBounds(pairBounds);
    },

    _handleItemHighlight: function(evt, $item) {
      var $container = $item.closest('.search-results-list');

      if($item.hasClass('s-highlighted')) {
        this.$organisationListItems.removeClass('s-highlighted');
        this._fitAllMarkers();
        return;
      }

      this.$organisationListItems.removeClass('s-highlighted');
      $item.addClass('s-highlighted');
      $item.find('.org-summary').attr('aria-expanded', true);

      $item.find('.org-details').attr('tabindex', -1).focus();

      this._handleMarkersZooming($item.data('id'));
      this._handleHighlightedItemScroll($item, $container);

      var markerCount = parseInt($item.find('.marker').text(), 10);
      var currentPage = parseInt($container.data('current-page'), 10);
      var name = $item.find('.fn').text();
      var count;

      if(markerCount && currentPage) {
        count = markerCount + ((currentPage - 1) * 10);
      }

      name = (count ? count + ':' : '') + name;

      window.ga('send', 'event', 'find-legal-adviser', 'selected', name);
    },

    renderMap: function(lat, lon) {
      var self = this;

      var searchLocation = {
        lat: lat,
        lng: lon
      };

      var mapOptions = {
        center: searchLocation,
        zoom: 15,
        scrollwheel: false,
        panControl: false,
        streetViewControl: false
      };

      this.map = new google.maps.Map(this.$resultsMap[0], mapOptions);
      this.searchLocationMarker = this.addMarker(searchLocation, {
        title: 'Search location',
        icon: 'icon-location-2x'
      });

      google.maps.event.addListener(self.map, 'click', function() {
        self._closeOpenInfoWindow();
      });
    },

    addMarker: function(position, options) {
      var self = this;
      var image;
      options = options || {};

      if(options.icon) {
        image = {
          url: '/static/images/icons/' + options.icon + '.png',
          scaledSize: new google.maps.Size(16, 16),
          anchor: new google.maps.Point(8, 8)
        };
      } else if(options.id) {
        image = {
          url: '/static/images/icons/icon-numbered-markers-2x.png',
          size: new google.maps.Size(22, 40),
          scaledSize: new google.maps.Size(220, 40),
          origin: new google.maps.Point(22 * (options.id - 1), 0)
        };
      }

      var marker = new google.maps.Marker({
        position: position,
        id: options.id,
        title: options.title,
        map: this.map,
        icon: image
      });

      if(options.content) {
        google.maps.event.addListener(marker, 'click', function() {
          self._closeOpenInfoWindow();
          self.openInfoWindow = new google.maps.InfoWindow({
            content: options.content
          });
          self.openInfoWindow.open(self.map, marker);
        });
      }

      return marker;
    },

    addMarkers: function(points) {
      var self = this;

      $.each(points, function() {
        if(!(this.position)) {
          return;
        }
        self.markers.push(
          self.addMarker(this.position, {
            id: this.id,
            title: this.title,
            content: this.content
          })
        );
      });

      this._fitAllMarkers();
    },

    cacheEls: function() {
      this.$resultsMap = $(this.el);
      this.$findLegalAdviserContainer = $('.find-legal-adviser');
      this.$findLegalAdviserForm = $('.legal-adviser-search');
      this.$organisationListItems = $('.search-results-list .vcard');
      this.$resultsPagination = $('.search-results-pagination');
    }
  };

  function setMapHeight(setHeight) {
    if ($(window).width() >= wideScreen) {
      var listHeight = $("ul.org-list").height();
      if (listHeight > setHeight) setHeight = listHeight;
      $(".search-results-container, .search-results-list").height(setHeight);
    }
  }

  $("document").ready(function(){
    var originalHeight = $("#resultsMap").height();
    setMapHeight(originalHeight);
    $(".search-results-container").click(function(){
      setMapHeight(originalHeight);
    });
  });

<commit_msg>LGA-1541 LARP title duplication bug<commit_after>var wideScreen = 641;
 'use strict';
  var _ = require('lodash');
  moj.Modules.FindLegalAdviser = {
    el: '#resultsMap',
    markers: [],
    searchLocationMarker: null,
    openInfoWindow: null,
    eventsBound: false,

    init: function() {
      this.cacheEls();

      this._handleMQTest();

      if(!this.$resultsMap.length) {
        return;
      }

      this.renderMap(this.$resultsMap.data('lat'), this.$resultsMap.data('lon'));
      this._prepareMarkers();

      $(window).resize(_.debounce($.proxy(this._handleMQTest, this), 500));
    },

    // Handle events which rely on media queries
    _handleMQTest: function() {
      if(window.Modernizr.mq('(min-width: ' + wideScreen + 'px)')) {
        if(!this.eventsBound) {
          this.bindEvents();
        }
      } else if(this.eventsBound) {
        this._unbindEvents();
      }
    },

    bindEvents: function() {
      var self = this;
      this.$organisationListItems.find('.org-summary').each(function() {
        $(this).replaceWith('' + $(this).html() + '');
      });

      this.$organisationListItems.on('click', '.org-summary', function(evt) {
        evt.preventDefault();
        self.$organisationListItems.find('.org-summary').attr('aria-expanded', false);
        self._handleItemHighlight(evt, $(this).closest('li'));
      });

      this.$resultsPagination.on('click', 'a', function(evt) {
        evt.preventDefault();

        if(window.LABELS && window.LABELS.loading) {
          $(evt.target).replaceWith('' + window.LABELS.loading + '');
        }

        self._fetchPage(evt.target.href);

        if(window.history && history.pushState) {
          history.pushState(null, null, evt.target.href);
        }
      });

      this.$findLegalAdviserForm.submit(function(evt) {
        evt.preventDefault();

        var url = document.location.pathname + '?' + $(this).serialize();
        self._fetchPage(url, true);

        if(window.history && history.pushState) {
          history.pushState(null, null, url);
        }

        if(!self.$resultsMap.length) {
          $('
' + window.LABELS.loading + '
').insertAfter($(this));
        }
      });

      window.onpopstate = function() {
        self._fetchPage(document.location.href);
      };

      this.eventsBound = true;
    },

    _unbindEvents: function() {
      this.$organisationListItems
        .unbind('click')
        .find('.org-summary')
        .each(function() {
          $(this).replaceWith('' + $(this).html() + '');
        });

      this.$resultsPagination.unbind('click');
      this.$findLegalAdviserForm.unbind('submit');
      window.onpopstate = null;

      this.eventsBound = false;
    },

    _fetchPage: function(url, scrollToResults) {
      var self = this;

      $.get(url)
        .success(function(data) {
          self.$findLegalAdviserContainer.replaceWith(data);
          self.markers = [];
          self.eventsBound = false;
          self.init();

          if(scrollToResults) {
            $('html, body').delay(300).animate({
              'scrollTop': self.$findLegalAdviserContainer.offset().top - 10
            }, 160);
          }

    //      $('.search-results-list').attr('tabindex', -1).focus();

          window.ga('send', 'pageview', stripPII(url));
        })
        .error();
    },

    _closeOpenInfoWindow: function() {
      if(this.openInfoWindow) {
        this.openInfoWindow.close();
      }
    },

    _prepareMarkers: function() {
      var organisations = $.map(this.$organisationListItems, function(item) {
        var $item = $(item);
        return {
          id: $item.data('id'),
          position: {
            lat: parseFloat($item.data('lat')),
            lng: parseFloat($item.data('lon'))
          },
          title: $item.find('.fn').text(),
          content: $item.html()
        };
      });

      this.addMarkers(organisations);
    },

    _fitAllMarkers: function() {
      var self = this;

      this.map.fitBounds(this.markers.reduce(function(bounds, marker) {
        return bounds.extend(marker.getPosition());
      }, new google.maps.LatLngBounds()));

      $.each(this.markers, function() {
        this.setMap(self.map);
      });
    },

    _handleHighlightedItemScroll: function($item, $container) {
      var itemHeight = $item.outerHeight();
      var containerHeight = $container.height();

      if(itemHeight + $item.position().top > containerHeight) {
        $container.scrollTop(containerHeight - itemHeight);
      }
    },

    _handleMarkersZooming: function(selectedMarkerId) {
      var markerOnMap = _.find(this.markers, { id: selectedMarkerId });

      $.each(this.markers, function() {
        this.setMap(null);
      });

      markerOnMap.setMap(this.map);

      var pairBounds = new google.maps.LatLngBounds();
      pairBounds.extend(markerOnMap.position);
      pairBounds.extend(this.searchLocationMarker.position);

      this.map.fitBounds(pairBounds);
    },

    _handleItemHighlight: function(evt, $item) {
      var $container = $item.closest('.search-results-list');

      if($item.hasClass('s-highlighted')) {
        this.$organisationListItems.removeClass('s-highlighted');
        this._fitAllMarkers();
        return;
      }

      this.$organisationListItems.removeClass('s-highlighted');
      $item.addClass('s-highlighted');
      $item.find('.org-summary').attr('aria-expanded', true);

      $item.find('.org-details').attr('tabindex', -1).focus();

      this._handleMarkersZooming($item.data('id'));
      this._handleHighlightedItemScroll($item, $container);

      var markerCount = parseInt($item.find('.marker').text(), 10);
      var currentPage = parseInt($container.data('current-page'), 10);
      var name = $item.find('.fn').text();
      var count;

      if(markerCount && currentPage) {
        count = markerCount + ((currentPage - 1) * 10);
      }

      name = (count ? count + ':' : '') + name;

      window.ga('send', 'event', 'find-legal-adviser', 'selected', name);
    },

    renderMap: function(lat, lon) {
      var self = this;

      var searchLocation = {
        lat: lat,
        lng: lon
      };

      var mapOptions = {
        center: searchLocation,
        zoom: 15,
        scrollwheel: false,
        panControl: false,
        streetViewControl: false
      };

      this.map = new google.maps.Map(this.$resultsMap[0], mapOptions);
      this.searchLocationMarker = this.addMarker(searchLocation, {
        title: 'Search location',
        icon: 'icon-location-2x'
      });

      google.maps.event.addListener(self.map, 'click', function() {
        self._closeOpenInfoWindow();
      });
    },

    addMarker: function(position, options) {
      var self = this;
      var image;
      options = options || {};

      if(options.icon) {
        image = {
          url: '/static/images/icons/' + options.icon + '.png',
          scaledSize: new google.maps.Size(16, 16),
          anchor: new google.maps.Point(8, 8)
        };
      } else if(options.id) {
        image = {
          url: '/static/images/icons/icon-numbered-markers-2x.png',
          size: new google.maps.Size(22, 40),
          scaledSize: new google.maps.Size(220, 40),
          origin: new google.maps.Point(22 * (options.id - 1), 0)
        };
      }

      var marker = new google.maps.Marker({
        position: position,
        id: options.id,
        title: options.title,
        map: this.map,
        icon: image
      });

      if(options.content) {
        google.maps.event.addListener(marker, 'click', function() {
          self._closeOpenInfoWindow();
          self.openInfoWindow = new google.maps.InfoWindow({
            content: options.content
          });
          self.openInfoWindow.open(self.map, marker);
        });
      }

      return marker;
    },

    addMarkers: function(points) {
      var self = this;

      $.each(points, function() {
        if(!(this.position)) {
          return;
        }
        self.markers.push(
          self.addMarker(this.position, {
            id: this.id,
            title: this.title,
            content: this.content
          })
        );
      });

      this._fitAllMarkers();
    },

    cacheEls: function() {
      this.$resultsMap = $(this.el);
      this.$findLegalAdviserContainer = $('.find-legal-adviser');
      this.$findLegalAdviserForm = $('.legal-adviser-search');
      this.$organisationListItems = $('.search-results-list .vcard');
      this.$resultsPagination = $('.search-results-pagination');
    }
  };

  function setMapHeight(setHeight) {
    if ($(window).width() >= wideScreen) {
      var listHeight = $("ul.org-list").height();
      if (listHeight > setHeight) setHeight = listHeight;
      $(".search-results-container, .search-results-list").height(setHeight);
    }
  }

  $("document").ready(function(){
    var originalHeight = $("#resultsMap").height();
    setMapHeight(originalHeight);
    $(".search-results-container").click(function(){
      setMapHeight(originalHeight);
    });
  });

<|endoftext|>


<commit_before>/**
* The `Matter.Engine` module contains methods for creating and manipulating engines.
* An engine is a controller that manages updating the simulation of the world.
* See `Matter.Runner` for an optional game loop utility.
*
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
*
* @class Engine
*/

var Engine = {};

module.exports = Engine;

var World = require('../body/World');
var Sleeping = require('./Sleeping');
var Resolver = require('../collision/Resolver');
var Render = require('../render/Render');
var Pairs = require('../collision/Pairs');
var Metrics = require('./Metrics');
var Grid = require('../collision/Grid');
var Events = require('./Events');
var Composite = require('../body/Composite');
var Constraint = require('../constraint/Constraint');
var Common = require('./Common');
var Body = require('../body/Body');

(function() {

    /**
     * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults.
     * All properties have default values, and many are pre-calculated automatically based on other properties.
     * See the properties section below for detailed information on what you can pass via the `options` object.
     * @method create
     * @param {HTMLElement} [element]
     * @param {object} [options]
     * @return {engine} engine
     */
    Engine.create = function(element, options) {

        // options may be passed as the first (and only) argument
        options = Common.isElement(element) ? options : element;
        element = Common.isElement(element) ? element : null;

        var defaults = {
            positionIterations: 6,
            velocityIterations: 4,
            constraintIterations: 2,
            enableSleeping: false,
            events: [],
            timing: {
                timestamp: 0,
                timeScale: 1
            },
            broadphase: {
                controller: Grid
            }
        };

        var engine = Common.extend(defaults, options);

        if (element || engine.render) {
            var renderDefaults = {
                element: element,
                controller: Render
            };

            engine.render = Common.extend(renderDefaults, engine.render);
        }

        if (engine.render && engine.render.controller) {
            engine.render = engine.render.controller.create(engine.render);
        }

        engine.world = options.world || World.create(engine.world);
        engine.pairs = Pairs.create();
        engine.broadphase = engine.broadphase.controller.create(engine.broadphase);
        engine.metrics = engine.metrics || { extended: false };

        // @if DEBUG
        engine.metrics = Metrics.create(engine.metrics);
        // @endif

        return engine;
    };

    /**
     * Moves the simulation forward in time by `delta` ms.
     * The `correction` argument is an optional `Number` that specifies the time correction factor to apply to the update.
     * This can help improve the accuracy of the simulation in cases where `delta` is changing between updates.
     * The value of `correction` is defined as `delta / lastDelta`, i.e. the percentage change of `delta` over the last step.
     * Therefore the value is always `1` (no correction) when `delta` constant (or when no correction is desired, which is the default).
     * See the paper on Time Corrected Verlet for more information.
     *
     * Triggers `beforeUpdate` and `afterUpdate` events.
     * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events.
     * @method update
     * @param {engine} engine
     * @param {number} [delta=16.666]
     * @param {number} [correction=1]
     */
    Engine.update = function(engine, delta, correction) {
        delta = delta || 1000 / 60;
        correction = correction || 1;

        var world = engine.world,
            timing = engine.timing,
            broadphase = engine.broadphase,
            broadphasePairs = [],
            i;

        // increment timestamp
        timing.timestamp += delta * timing.timeScale;

        // create an event object
        var event = {
            timestamp: timing.timestamp
        };

        Events.trigger(engine, 'beforeUpdate', event);

        // get lists of all bodies and constraints, no matter what composites they are in
        var allBodies = Composite.allBodies(world),
            allConstraints = Composite.allConstraints(world);

        // @if DEBUG
        // reset metrics logging
        Metrics.reset(engine.metrics);
        // @endif

        // if sleeping enabled, call the sleeping controller
        if (engine.enableSleeping)
            Sleeping.update(allBodies, timing.timeScale);

        // applies gravity to all bodies
        _bodiesApplyGravity(allBodies, world.gravity);

        // update all body position and rotation by integration
        _bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds);

        // update all constraints
        for (i = 0; i < engine.constraintIterations; i++) {
            Constraint.solveAll(allConstraints, timing.timeScale);
        }
        Constraint.postSolveAll(allBodies);

        // broadphase pass: find potential collision pairs
        if (broadphase.controller) {

            // if world is dirty, we must flush the whole grid
            if (world.isModified)
                broadphase.controller.clear(broadphase);

            // update the grid buckets based on current bodies
            broadphase.controller.update(broadphase, allBodies, engine, world.isModified);
            broadphasePairs = broadphase.pairsList;
        } else {

            // if no broadphase set, we just pass all bodies
            broadphasePairs = allBodies;
        }

        // clear all composite modified flags
        if (world.isModified) {
            Composite.setModified(world, false, false, true);
        }

        // narrowphase pass: find actual collisions, then create or update collision pairs
        var collisions = broadphase.detector(broadphasePairs, engine);

        // update collision pairs
        var pairs = engine.pairs,
            timestamp = timing.timestamp;
        Pairs.update(pairs, collisions, timestamp);
        Pairs.removeOld(pairs, timestamp);

        // wake up bodies involved in collisions
        if (engine.enableSleeping)
            Sleeping.afterCollisions(pairs.list, timing.timeScale);

        // trigger collision events
        if (pairs.collisionStart.length > 0)
            Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart });

        // iteratively resolve position between collisions
        Resolver.preSolvePosition(pairs.list);
        for (i = 0; i < engine.positionIterations; i++) {
            Resolver.solvePosition(pairs.list, timing.timeScale);
        }
        Resolver.postSolvePosition(allBodies);

        // iteratively resolve velocity between collisions
        Resolver.preSolveVelocity(pairs.list);
        for (i = 0; i < engine.velocityIterations; i++) {
            Resolver.solveVelocity(pairs.list, timing.timeScale);
        }

        // trigger collision events
        if (pairs.collisionActive.length > 0)
            Events.trigger(engine, 'collisionActive', { pairs: pairs.collisionActive });

        if (pairs.collisionEnd.length > 0)
            Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });

        // @if DEBUG
        // update metrics log
        Metrics.update(engine.metrics, engine);
        // @endif

        // clear force buffers
        _bodiesClearForces(allBodies);

        Events.trigger(engine, 'afterUpdate', event);

        return engine;
    };

    /**
     * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`.
     * @method merge
     * @param {engine} engineA
     * @param {engine} engineB
     */
    Engine.merge = function(engineA, engineB) {
        Common.extend(engineA, engineB);

        if (engineB.world) {
            engineA.world = engineB.world;

            Engine.clear(engineA);

            var bodies = Composite.allBodies(engineA.world);

            for (var i = 0; i < bodies.length; i++) {
                var body = bodies[i];
                Sleeping.set(body, false);
                body.id = Common.nextId();
            }
        }
    };

    /**
     * Clears the engine including the world, pairs and broadphase.
     * @method clear
     * @param {engine} engine
     */
    Engine.clear = function(engine) {
        var world = engine.world;

        Pairs.clear(engine.pairs);

        var broadphase = engine.broadphase;
        if (broadphase.controller) {
            var bodies = Composite.allBodies(world);
            broadphase.controller.clear(broadphase);
            broadphase.controller.update(broadphase, bodies, engine, true);
        }
    };

    /**
     * Zeroes the `body.force` and `body.torque` force buffers.
     * @method bodiesClearForces
     * @private
     * @param {body[]} bodies
     */
    var _bodiesClearForces = function(bodies) {
        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            // reset force buffers
            body.force.x = 0;
            body.force.y = 0;
            body.torque = 0;
        }
    };

    /**
     * Applys a mass dependant force to all given bodies.
     * @method bodiesApplyGravity
     * @private
     * @param {body[]} bodies
     * @param {vector} gravity
     */
    var _bodiesApplyGravity = function(bodies, gravity) {
        var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001;

        if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) {
            return;
        }

        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            if (body.isStatic || body.isSleeping)
                continue;

            // apply gravity
            body.force.y += body.mass * gravity.y * gravityScale;
            body.force.x += body.mass * gravity.x * gravityScale;
        }
    };

    /**
     * Applys `Body.update` to all given `bodies`.
     * @method updateAll
     * @private
     * @param {body[]} bodies
     * @param {number} deltaTime
     * The amount of time elapsed between updates
     * @param {number} timeScale
     * @param {number} correction
     * The Verlet correction factor (deltaTime / lastDeltaTime)
     * @param {bounds} worldBounds
     */
    var _bodiesUpdate = function(bodies, deltaTime, timeScale, correction, worldBounds) {
        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            if (body.isStatic || body.isSleeping)
                continue;

            Body.update(body, deltaTime, timeScale, correction);
        }
    };

    /**
     * An alias for `Runner.run`, see `Matter.Runner` for more information.
     * @method run
     * @param {engine} engine
     */

    /**
    * Fired just before an update
    *
    * @event beforeUpdate
    * @param {} event An event object
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update and all collision events
    *
    * @event afterUpdate
    * @param {} event An event object
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
    *
    * @event collisionStart
    * @param {} event An event object
    * @param {} event.pairs List of affected pairs
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
    *
    * @event collisionActive
    * @param {} event An event object
    * @param {} event.pairs List of affected pairs
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
    *
    * @event collisionEnd
    * @param {} event An event object
    * @param {} event.pairs List of affected pairs
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /*
    *
    *  Properties Documentation
    *
    */

    /**
     * An integer `Number` that specifies the number of position iterations to perform each update.
     * The higher the value, the higher quality the simulation will be at the expense of performance.
     *
     * @property positionIterations
     * @type number
     * @default 6
     */

    /**
     * An integer `Number` that specifies the number of velocity iterations to perform each update.
     * The higher the value, the higher quality the simulation will be at the expense of performance.
     *
     * @property velocityIterations
     * @type number
     * @default 4
     */

    /**
     * An integer `Number` that specifies the number of constraint iterations to perform each update.
     * The higher the value, the higher quality the simulation will be at the expense of performance.
     * The default value of `2` is usually very adequate.
     *
     * @property constraintIterations
     * @type number
     * @default 2
     */

    /**
     * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module.
     * Sleeping can improve stability and performance, but often at the expense of accuracy.
     *
     * @property enableSleeping
     * @type boolean
     * @default false
     */

    /**
     * An `Object` containing properties regarding the timing systems of the engine.
     *
     * @property timing
     * @type object
     */

    /**
     * A `Number` that specifies the global scaling factor of time for all bodies.
     * A value of `0` freezes the simulation.
     * A value of `0.1` gives a slow-motion effect.
     * A value of `1.2` gives a speed-up effect.
     *
     * @property timing.timeScale
     * @type number
     * @default 1
     */

    /**
     * A `Number` that specifies the current simulation-time in milliseconds starting from `0`.
     * It is incremented on every `Engine.update` by the given `delta` argument.
     *
     * @property timing.timestamp
     * @type number
     * @default 0
     */

    /**
     * An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`.
     * One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`.
     *
     * A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`).
     * It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you.
     *
     * @property render
     * @type render
     * @default a Matter.Render instance
     */

    /**
     * An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`.
     *
     * @property broadphase
     * @type grid
     * @default a Matter.Grid instance
     */

    /**
     * A `World` composite object that will contain all simulated bodies and constraints.
     *
     * @property world
     * @type world
     * @default a Matter.World instance
     */

})();
<commit_msg>handle missing options in Engine.create<commit_after>/**
* The `Matter.Engine` module contains methods for creating and manipulating engines.
* An engine is a controller that manages updating the simulation of the world.
* See `Matter.Runner` for an optional game loop utility.
*
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
*
* @class Engine
*/

var Engine = {};

module.exports = Engine;

var World = require('../body/World');
var Sleeping = require('./Sleeping');
var Resolver = require('../collision/Resolver');
var Render = require('../render/Render');
var Pairs = require('../collision/Pairs');
var Metrics = require('./Metrics');
var Grid = require('../collision/Grid');
var Events = require('./Events');
var Composite = require('../body/Composite');
var Constraint = require('../constraint/Constraint');
var Common = require('./Common');
var Body = require('../body/Body');

(function() {

    /**
     * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults.
     * All properties have default values, and many are pre-calculated automatically based on other properties.
     * See the properties section below for detailed information on what you can pass via the `options` object.
     * @method create
     * @param {HTMLElement} [element]
     * @param {object} [options]
     * @return {engine} engine
     */
    Engine.create = function(element, options) {
        // options may be passed as the first (and only) argument
        options = Common.isElement(element) ? options : element;
        element = Common.isElement(element) ? element : null;

        options = options || {};

        var defaults = {
            positionIterations: 6,
            velocityIterations: 4,
            constraintIterations: 2,
            enableSleeping: false,
            events: [],
            timing: {
                timestamp: 0,
                timeScale: 1
            },
            broadphase: {
                controller: Grid
            }
        };

        var engine = Common.extend(defaults, options);

        if (element || engine.render) {
            var renderDefaults = {
                element: element,
                controller: Render
            };

            engine.render = Common.extend(renderDefaults, engine.render);
        }

        if (engine.render && engine.render.controller) {
            engine.render = engine.render.controller.create(engine.render);
        }

        engine.world = options.world || World.create(engine.world);
        engine.pairs = Pairs.create();
        engine.broadphase = engine.broadphase.controller.create(engine.broadphase);
        engine.metrics = engine.metrics || { extended: false };

        // @if DEBUG
        engine.metrics = Metrics.create(engine.metrics);
        // @endif

        return engine;
    };

    /**
     * Moves the simulation forward in time by `delta` ms.
     * The `correction` argument is an optional `Number` that specifies the time correction factor to apply to the update.
     * This can help improve the accuracy of the simulation in cases where `delta` is changing between updates.
     * The value of `correction` is defined as `delta / lastDelta`, i.e. the percentage change of `delta` over the last step.
     * Therefore the value is always `1` (no correction) when `delta` constant (or when no correction is desired, which is the default).
     * See the paper on Time Corrected Verlet for more information.
     *
     * Triggers `beforeUpdate` and `afterUpdate` events.
     * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events.
     * @method update
     * @param {engine} engine
     * @param {number} [delta=16.666]
     * @param {number} [correction=1]
     */
    Engine.update = function(engine, delta, correction) {
        delta = delta || 1000 / 60;
        correction = correction || 1;

        var world = engine.world,
            timing = engine.timing,
            broadphase = engine.broadphase,
            broadphasePairs = [],
            i;

        // increment timestamp
        timing.timestamp += delta * timing.timeScale;

        // create an event object
        var event = {
            timestamp: timing.timestamp
        };

        Events.trigger(engine, 'beforeUpdate', event);

        // get lists of all bodies and constraints, no matter what composites they are in
        var allBodies = Composite.allBodies(world),
            allConstraints = Composite.allConstraints(world);

        // @if DEBUG
        // reset metrics logging
        Metrics.reset(engine.metrics);
        // @endif

        // if sleeping enabled, call the sleeping controller
        if (engine.enableSleeping)
            Sleeping.update(allBodies, timing.timeScale);

        // applies gravity to all bodies
        _bodiesApplyGravity(allBodies, world.gravity);

        // update all body position and rotation by integration
        _bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds);

        // update all constraints
        for (i = 0; i < engine.constraintIterations; i++) {
            Constraint.solveAll(allConstraints, timing.timeScale);
        }
        Constraint.postSolveAll(allBodies);

        // broadphase pass: find potential collision pairs
        if (broadphase.controller) {

            // if world is dirty, we must flush the whole grid
            if (world.isModified)
                broadphase.controller.clear(broadphase);

            // update the grid buckets based on current bodies
            broadphase.controller.update(broadphase, allBodies, engine, world.isModified);
            broadphasePairs = broadphase.pairsList;
        } else {

            // if no broadphase set, we just pass all bodies
            broadphasePairs = allBodies;
        }

        // clear all composite modified flags
        if (world.isModified) {
            Composite.setModified(world, false, false, true);
        }

        // narrowphase pass: find actual collisions, then create or update collision pairs
        var collisions = broadphase.detector(broadphasePairs, engine);

        // update collision pairs
        var pairs = engine.pairs,
            timestamp = timing.timestamp;
        Pairs.update(pairs, collisions, timestamp);
        Pairs.removeOld(pairs, timestamp);

        // wake up bodies involved in collisions
        if (engine.enableSleeping)
            Sleeping.afterCollisions(pairs.list, timing.timeScale);

        // trigger collision events
        if (pairs.collisionStart.length > 0)
            Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart });

        // iteratively resolve position between collisions
        Resolver.preSolvePosition(pairs.list);
        for (i = 0; i < engine.positionIterations; i++) {
            Resolver.solvePosition(pairs.list, timing.timeScale);
        }
        Resolver.postSolvePosition(allBodies);

        // iteratively resolve velocity between collisions
        Resolver.preSolveVelocity(pairs.list);
        for (i = 0; i < engine.velocityIterations; i++) {
            Resolver.solveVelocity(pairs.list, timing.timeScale);
        }

        // trigger collision events
        if (pairs.collisionActive.length > 0)
            Events.trigger(engine, 'collisionActive', { pairs: pairs.collisionActive });

        if (pairs.collisionEnd.length > 0)
            Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });

        // @if DEBUG
        // update metrics log
        Metrics.update(engine.metrics, engine);
        // @endif

        // clear force buffers
        _bodiesClearForces(allBodies);

        Events.trigger(engine, 'afterUpdate', event);

        return engine;
    };

    /**
     * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`.
     * @method merge
     * @param {engine} engineA
     * @param {engine} engineB
     */
    Engine.merge = function(engineA, engineB) {
        Common.extend(engineA, engineB);

        if (engineB.world) {
            engineA.world = engineB.world;

            Engine.clear(engineA);

            var bodies = Composite.allBodies(engineA.world);

            for (var i = 0; i < bodies.length; i++) {
                var body = bodies[i];
                Sleeping.set(body, false);
                body.id = Common.nextId();
            }
        }
    };

    /**
     * Clears the engine including the world, pairs and broadphase.
     * @method clear
     * @param {engine} engine
     */
    Engine.clear = function(engine) {
        var world = engine.world;

        Pairs.clear(engine.pairs);

        var broadphase = engine.broadphase;
        if (broadphase.controller) {
            var bodies = Composite.allBodies(world);
            broadphase.controller.clear(broadphase);
            broadphase.controller.update(broadphase, bodies, engine, true);
        }
    };

    /**
     * Zeroes the `body.force` and `body.torque` force buffers.
     * @method bodiesClearForces
     * @private
     * @param {body[]} bodies
     */
    var _bodiesClearForces = function(bodies) {
        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            // reset force buffers
            body.force.x = 0;
            body.force.y = 0;
            body.torque = 0;
        }
    };

    /**
     * Applys a mass dependant force to all given bodies.
     * @method bodiesApplyGravity
     * @private
     * @param {body[]} bodies
     * @param {vector} gravity
     */
    var _bodiesApplyGravity = function(bodies, gravity) {
        var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001;

        if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) {
            return;
        }

        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            if (body.isStatic || body.isSleeping)
                continue;

            // apply gravity
            body.force.y += body.mass * gravity.y * gravityScale;
            body.force.x += body.mass * gravity.x * gravityScale;
        }
    };

    /**
     * Applys `Body.update` to all given `bodies`.
     * @method updateAll
     * @private
     * @param {body[]} bodies
     * @param {number} deltaTime
     * The amount of time elapsed between updates
     * @param {number} timeScale
     * @param {number} correction
     * The Verlet correction factor (deltaTime / lastDeltaTime)
     * @param {bounds} worldBounds
     */
    var _bodiesUpdate = function(bodies, deltaTime, timeScale, correction, worldBounds) {
        for (var i = 0; i < bodies.length; i++) {
            var body = bodies[i];

            if (body.isStatic || body.isSleeping)
                continue;

            Body.update(body, deltaTime, timeScale, correction);
        }
    };

    /**
     * An alias for `Runner.run`, see `Matter.Runner` for more information.
     * @method run
     * @param {engine} engine
     */

    /**
    * Fired just before an update
    *
    * @event beforeUpdate
    * @param {} event An event object
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update and all collision events
    *
    * @event afterUpdate
    * @param {} event An event object
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
    *
    * @event collisionStart
    * @param {} event An event object
    * @param {} event.pairs List of affected pairs
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
    *
    * @event collisionActive
    * @param {} event An event object
    * @param {} event.pairs List of affected pairs
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /**
    * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
    *
    * @event collisionEnd
    * @param {} event An event object
    * @param {} event.pairs List of affected pairs
    * @param {number} event.timestamp The engine.timing.timestamp of the event
    * @param {} event.source The source object of the event
    * @param {} event.name The name of the event
    */

    /*
    *
    *  Properties Documentation
    *
    */

    /**
     * An integer `Number` that specifies the number of position iterations to perform each update.
     * The higher the value, the higher quality the simulation will be at the expense of performance.
     *
     * @property positionIterations
     * @type number
     * @default 6
     */

    /**
     * An integer `Number` that specifies the number of velocity iterations to perform each update.
     * The higher the value, the higher quality the simulation will be at the expense of performance.
     *
     * @property velocityIterations
     * @type number
     * @default 4
     */

    /**
     * An integer `Number` that specifies the number of constraint iterations to perform each update.
     * The higher the value, the higher quality the simulation will be at the expense of performance.
     * The default value of `2` is usually very adequate.
     *
     * @property constraintIterations
     * @type number
     * @default 2
     */

    /**
     * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module.
     * Sleeping can improve stability and performance, but often at the expense of accuracy.
     *
     * @property enableSleeping
     * @type boolean
     * @default false
     */

    /**
     * An `Object` containing properties regarding the timing systems of the engine.
     *
     * @property timing
     * @type object
     */

    /**
     * A `Number` that specifies the global scaling factor of time for all bodies.
     * A value of `0` freezes the simulation.
     * A value of `0.1` gives a slow-motion effect.
     * A value of `1.2` gives a speed-up effect.
     *
     * @property timing.timeScale
     * @type number
     * @default 1
     */

    /**
     * A `Number` that specifies the current simulation-time in milliseconds starting from `0`.
     * It is incremented on every `Engine.update` by the given `delta` argument.
     *
     * @property timing.timestamp
     * @type number
     * @default 0
     */

    /**
     * An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`.
     * One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`.
     *
     * A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`).
     * It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you.
     *
     * @property render
     * @type render
     * @default a Matter.Render instance
     */

    /**
     * An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`.
     *
     * @property broadphase
     * @type grid
     * @default a Matter.Grid instance
     */

    /**
     * A `World` composite object that will contain all simulated bodies and constraints.
     *
     * @property world
     * @type world
     * @default a Matter.World instance
     */

})();
<|endoftext|>


<commit_before>/*
 * This file is part of the AlphaLemon CMS Application and it is distributed
 * under the GPL LICENSE Version 2.0. To use this application you must leave
 * intact this copyright notice.
 *
 * Copyright (c) AlphaLemon <webmaster@alphalemon.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * For extra documentation and help please visit http://www.alphalemon.com
 *
 * @license    GPL LICENSE Version 2.0
 *
 */

;(function($){
    var methods = {
        addItem: function() {
            $(this).click(function(){
                $('#al_save_item').data('element', null);
                var columns = $(".al_items_list table tr:last").find('.al-column');

                var newKey = $('.al_items_list table tr').length;
                $('.al_items_list table').append('

');

                var attributes = {};
                var newValue = translate("New value");
                var row = $(".al_items_list table tr:last");
                row = $(row);
                $(columns).each(function() {
                    var attributeValue = "";
                    var $this = $(this);
                    var id = newKey + '_' + $this.name;
                    if ( ! $this.hasClass('al_hidden')) {
                        row.append('' + newValue + '	');
                        attributeValue = newValue;
                    } else {
                        row.append('' + newValue + '	');
                    }
                    attributes[$this.attr('rel')] = attributeValue;
                });

                row.append('' + translate('Edit') + '	');
                row.append('' + translate('Delete') + '	');

                $('#al_edit_item_' + newKey).data('attributes', attributes);
                editItem($('#al_edit_item_' + newKey));
                deleteItem($('#al_delete_item_' + newKey));

                return false;
            });
        },
        editItem: function() {
            editItem($(this));
        },
        deleteItem : function() {
            deleteItem($(this));
        },
        save: function(element, values) {
            $(this).click(function(){
                if (element == null) {
                    element = '.al_edit_item';
                }

                if (values == null) {
                    values = attributesToJson(element);
                }
                $('body').EditBlock("Content", JSON.stringify(values));
            });
        },
        saveAttributes: function() {
            $(this).blur(function(){
                var columns = $('.al_active_row').find('.al-column');
                $(columns).each(function() {
                    var $this = $(this);
                    if ( ! $this.hasClass('al_hidden')) {
                        $this.html($('#' + $this.attr('rel')).val());
                    }
                });

                var element = $('#al_save_item').data('element');
                $(element).data('attributes', serializeFormToObject('#al_item_attributes_form'));
            });
        }
    };

    function editItem(element) {
        element.click(function(){
            var $this = $(this);
            var attributes = $this.data('attributes');
            if (attributes == null) {
                attributes = $this.metadata();
                $this.data('attributes', attributes);
            }

            $.each(attributes, function(key, value){
                $('#' + key).val(decodeURIComponent(value));
            });

            $('#al_save_item').data('element', $this);

            selectActiveItem($this);

            return false;
        });
    }

    function deleteItem(element) {
        element.click(function(){
            var $this = $(this);
            selectActiveItem($this);

            if(confirm("Are you sure to remove the active item"))
            {
                var el = $this.attr('rel');
                $('#' + el).remove();
                $(".al_form_item").val('');
            }

            return false;
        });
    }

    function selectActiveItem(element) {
        $('.al_active_row').removeClass('al_active_row');
        $('#' + element.attr('rel')).addClass('al_active_row');
    }

    function attributesToJson(element) {
        var i = 0;
        var values = new Array();
        $(element).each(function(){
            var attributes = $(this).data('attributes');
            if (attributes == null) {
                attributes = $(this).metadata();
            }

            values[i] = attributes;
            i += 1;
        });

        return values;
    }

    function serializeFormToObject(form)
    {
       var o = {};
       $(form).find(':input').each(function() {
           var id = $(this).attr('id');
           if (o[id]) {
               if (!o[id].push) {
                   o[id] = [o[id]];
               }
               o[id].push(this.value || '');
           } else {
               o[id] = this.value || '';
           }
       });

       return o;
    }

    $.fn.list = function( method ) {
        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.list' );
        }
    };
})(jQuery);
<commit_msg>jquery list() plugin has been temporary suspended until jquery.metadata dependency is not removed from this plugin, as did for imagesList<commit_after>/*
 * This file is part of the AlphaLemon CMS Application and it is distributed
 * under the GPL LICENSE Version 2.0. To use this application you must leave
 * intact this copyright notice.
 *
 * Copyright (c) AlphaLemon <webmaster@alphalemon.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * For extra documentation and help please visit http://www.alphalemon.com
 *
 * @license    GPL LICENSE Version 2.0
 *
 */

;(function($){
    var methods = {
        addItem: function() {
            $(this).click(function(){
                $('#al_save_item').data('element', null);
                var columns = $(".al_items_list table tr:last").find('.al-column');

                var newKey = $('.al_items_list table tr').length;
                $('.al_items_list table').append('

');

                var attributes = {};
                var newValue = translate("New value");
                var row = $(".al_items_list table tr:last");
                row = $(row);
                $(columns).each(function() {
                    var attributeValue = "";
                    var $this = $(this);
                    var id = newKey + '_' + $this.name;
                    if ( ! $this.hasClass('al_hidden')) {
                        row.append('' + newValue + '	');
                        attributeValue = newValue;
                    } else {
                        row.append('' + newValue + '	');
                    }
                    attributes[$this.attr('rel')] = attributeValue;
                });

                row.append('' + translate('Edit') + '	');
                row.append('' + translate('Delete') + '	');

                $('#al_edit_item_' + newKey).data('attributes', attributes);
                editItem($('#al_edit_item_' + newKey));
                deleteItem($('#al_delete_item_' + newKey));

                return false;
            });
        },
        editItem: function() {
            editItem($(this));
        },
        deleteItem : function() {
            deleteItem($(this));
        },
        save: function(element, values) {
            $(this).click(function(){
                if (element == null) {
                    element = '.al_edit_item';
                }

                if (values == null) {
                    values = attributesToJson(element);
                }
                $('body').EditBlock("Content", JSON.stringify(values));
            });
        },
        saveAttributes: function() {
            $(this).blur(function(){
                var columns = $('.al_active_row').find('.al-column');
                $(columns).each(function() {
                    var $this = $(this);
                    if ( ! $this.hasClass('al_hidden')) {
                        $this.html($('#' + $this.attr('rel')).val());
                    }
                });

                var element = $('#al_save_item').data('element');
                $(element).data('attributes', serializeFormToObject('#al_item_attributes_form'));
            });
        }
    };

    function editItem(element) {
        element.click(function(){
            var $this = $(this);
            var attributes = $this.data('attributes');
            if (attributes == null) {
                attributes = $this.metadata();
                $this.data('attributes', attributes);
            }

            $.each(attributes, function(key, value){
                $('#' + key).val(decodeURIComponent(value));
            });

            $('#al_save_item').data('element', $this);

            selectActiveItem($this);

            return false;
        });
    }

    function deleteItem(element) {
        element.click(function(){
            var $this = $(this);
            selectActiveItem($this);

            if(confirm("Are you sure to remove the active item"))
            {
                var el = $this.attr('rel');
                $('#' + el).remove();
                $(".al_form_item").val('');
            }

            return false;
        });
    }

    function selectActiveItem(element) {
        $('.al_active_row').removeClass('al_active_row');
        $('#' + element.attr('rel')).addClass('al_active_row');
    }

    function attributesToJson(element) {
        var i = 0;
        var values = new Array();
        $(element).each(function(){
            var attributes = $(this).data('attributes');
            if (attributes == null) {
                attributes = $(this).metadata();
            }

            values[i] = attributes;
            i += 1;
        });

        return values;
    }

    function serializeFormToObject(form)
    {
       var o = {};
       $(form).find(':input').each(function() {
           var id = $(this).attr('id');
           if (o[id]) {
               if (!o[id].push) {
                   o[id] = [o[id]];
               }
               o[id].push(this.value || '');
           } else {
               o[id] = this.value || '';
           }
       });

       return o;
    }

    $.fn.list = function( method ) {

        alert('This plugin at the moment is not used by AlphaLemon CMS and by any other official block. It will be fixed ASAP but if you use it, please consider to fix it up: you must remove the jquery.metadata dependency as already did for imagesList plugin');

        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.list' );
        }
    };
})(jQuery);
<|endoftext|>


<commit_before>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core',
  name: 'Window',

  // documentation: 'Encapsulates top-level window/document features.',

  exports: [
    'getElementsByClassName',
    'getElementById',
    'assert',
    'async',
    'cancelAnimationFrame',
    'clearInterval',
    'clearTimeout',
    'console',
    'delayed',
    'document',
    'dynamic',
    'error',
    'framed',
    'info',
    'log',
    'merged',
    'requestAnimationFrame',
    'setInterval',
    'setTimeout',
    'warn',
    'window'
  ],

  properties: [
    [ 'name', 'window' ],
    'window',
    {
      name: 'document',
      factory: function() { return this.window.document; }
    },
    {
      name: 'console',
      factory: function() { return this.window.console; }
    }
  ],

  methods: [
    function getElementById(id) {
      return this.document.getElementById(id);
    },

    function getElementsByClassName(cls) {
      return this.document.getElementsByClassName(cls);
    },

    function assert(b /*, args */) {
      /* Like console.assert() except that it takes more than one argument. */
      if ( ! b ) {
        this.console.assert(false, [].splice.call(arguments, 1).join(''));
      }
    },

    function error() { this.console.error.apply(this.console, arguments); },
    function info()  { this.console.info.apply(this.console, arguments); },
    function log()   { this.console.log.apply(this.console, arguments); },
    function warn()  { this.console.warn.apply(this.console, arguments); },

    function async(l) {
      /* Decorate a listener so that the event is delivered asynchronously. */
      return this.delayed(l, 0);
    },

    function delayed(l, delay) {
      /* Decorate a listener so that events are delivered 'delay' ms later. */
      return foam.Function.bind(function() {
        this.setTimeout(
          function() { l.apply(this, arguments); },
          delay);
      }, this);
    },

    function merged(l, opt_delay) {
      var delay = opt_delay || 16;
      var X     = this;

      // TODO: setName

      return function() {
        var triggered = false;
        var lastArgs  = null;
        function mergedListener() {
          triggered = false;
          var args = foam.Array.argsToArray(lastArgs);
          lastArgs = null;
          l.apply(this, args);
        }

        var f = function() {
          lastArgs = arguments;

          if ( ! triggered ) {
            triggered = true;
            X.setTimeout(mergedListener, delay);
          }
        };

        return f;
      }();
    },

    function framed(l) {
      var X = this;

      // TODO: setName
      return function() {
        var triggered = false;
        var lastArgs  = null;
        function frameFired() {
          triggered = false;
          var args = lastArgs;
          lastArgs = null;
          l.apply(this, args);
        }

        var f = function framed() {
          lastArgs = arguments;

          if ( ! triggered ) {
            triggered = true;
            X.requestAnimationFrame(frameFired);
          }
        };

        return f;
      }();
    },

    function dynamic() {
    },

    function setTimeout(f, t) {
      return this.window.setTimeout.apply(this.window, arguments);
    },
    function clearTimeout(id) {
      this.window.clearTimeout(id);
    },

    function setInterval(f, t) {
      return this.window.setInterval.apply(this.window, arguments);
    },
    function clearInterval(id) {
      this.window.clearInterval(id);
    },

    function requestAnimationFrame(f) {
      return this.window.requestAnimationFrame(f);
    },
    function cancelAnimationFrame(id) {
      this.window.cancelAnimationFrame(id);
    }
  ]
});

/*
 * requestAnimationFrame is not available on nodejs,
 * so swap out with calls to setTimeout.
 */
if ( foam.isServer ) {
  foam.CLASS({
    refines: 'foam.core.Window',
    methods: [
      function requestAnimationFrame(f) {
        return this.setTimeout(f, 16);
      },
      function cancelAnimationFrame(id) {
        this.clearTimeout(id);
      }
    ]
  });
}

foam.X = foam.core.Window.create({window: global}, foam).Y;
<commit_msg>Framed and Merged now setName.<commit_after>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core',
  name: 'Window',

  // documentation: 'Encapsulates top-level window/document features.',

  exports: [
    'getElementsByClassName',
    'getElementById',
    'assert',
    'async',
    'cancelAnimationFrame',
    'clearInterval',
    'clearTimeout',
    'console',
    'delayed',
    'document',
    'dynamic',
    'error',
    'framed',
    'info',
    'log',
    'merged',
    'requestAnimationFrame',
    'setInterval',
    'setTimeout',
    'warn',
    'window'
  ],

  properties: [
    [ 'name', 'window' ],
    'window',
    {
      name: 'document',
      factory: function() { return this.window.document; }
    },
    {
      name: 'console',
      factory: function() { return this.window.console; }
    }
  ],

  methods: [
    function getElementById(id) {
      return this.document.getElementById(id);
    },

    function getElementsByClassName(cls) {
      return this.document.getElementsByClassName(cls);
    },

    function assert(b /*, args */) {
      /* Like console.assert() except that it takes more than one argument. */
      if ( ! b ) {
        this.console.assert(false, [].splice.call(arguments, 1).join(''));
      }
    },

    function error() { this.console.error.apply(this.console, arguments); },
    function info()  { this.console.info.apply(this.console, arguments); },
    function log()   { this.console.log.apply(this.console, arguments); },
    function warn()  { this.console.warn.apply(this.console, arguments); },

    function async(l) {
      /* Decorate a listener so that the event is delivered asynchronously. */
      return this.delayed(l, 0);
    },

    function delayed(l, delay) {
      /* Decorate a listener so that events are delivered 'delay' ms later. */
      return foam.Function.bind(function() {
        this.setTimeout(
          function() { l.apply(this, arguments); },
          delay);
      }, this);
    },

    function merged(l, opt_delay) {
      var delay = opt_delay || 16;
      var X     = this;

      return foam.Function.setName(function() {
        var triggered = false;
        var lastArgs  = null;
        function mergedListener() {
          triggered = false;
          var args = foam.Array.argsToArray(lastArgs);
          lastArgs = null;
          l.apply(this, args);
        }

        var f = function() {
          lastArgs = arguments;

          if ( ! triggered ) {
            triggered = true;
            X.setTimeout(mergedListener, delay);
          }
        };

        return f;
      }(), 'merged(' + l.name + ')');
    },

    function framed(l) {
      var X = this;

      return foam.Function.setName(function() {
        var triggered = false;
        var lastArgs  = null;
        function frameFired() {
          triggered = false;
          var args = lastArgs;
          lastArgs = null;
          l.apply(this, args);
        }

        var f = function framed() {
          lastArgs = arguments;

          if ( ! triggered ) {
            triggered = true;
            X.requestAnimationFrame(frameFired);
          }
        };

        return f;
      }(), 'framed(' + l.name + ')');
    },

    function dynamic() {
    },

    function setTimeout(f, t) {
      return this.window.setTimeout.apply(this.window, arguments);
    },
    function clearTimeout(id) {
      this.window.clearTimeout(id);
    },

    function setInterval(f, t) {
      return this.window.setInterval.apply(this.window, arguments);
    },
    function clearInterval(id) {
      this.window.clearInterval(id);
    },

    function requestAnimationFrame(f) {
      return this.window.requestAnimationFrame(f);
    },
    function cancelAnimationFrame(id) {
      this.window.cancelAnimationFrame(id);
    }
  ]
});

/*
 * requestAnimationFrame is not available on nodejs,
 * so swap out with calls to setTimeout.
 */
if ( foam.isServer ) {
  foam.CLASS({
    refines: 'foam.core.Window',
    methods: [
      function requestAnimationFrame(f) {
        return this.setTimeout(f, 16);
      },
      function cancelAnimationFrame(id) {
        this.clearTimeout(id);
      }
    ]
  });
}

foam.X = foam.core.Window.create({window: global}, foam).Y;
<|endoftext|>


<commit_before>/**
 * Copyright Dailymotion S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @provides dm.player
 * @requires dm.prelude
 *           dm.qs
 */

/**
 * Dailymotion Player.
 *
 * @class dm
 * @static
 * @access private
 */
DM.provide('',
{
    player: function(element, options)
    {
        return DM.Player.create(element, options);
    }
});

/**
 * The Player object.
 *
 * @class DM.Player
 * @access private
 */
DM.provide('Player',
{
    _INSTANCES: {},
    _HANDLER: null,
    _INTERVAL_ID: null,
    API_MODE: null,

    // video properties
    autoplay: false,
    currentTime: 0,
    bufferedTime: 0,
    duration: NaN,
    seeking: false,
    error: null,
    ended: false,
    muted: false,
    volume: 1,
    paused: true,
    fullscreen: false,

    play: function() {this.api('play');},
    togglePlay: function() {this.api('toggle-play');},
    pause: function() {this.api('pause');},
    seek: function(time) {this.api('seek', time);},
    load: function(id) {this.api('load', id);},
    setMuted: function(muted) {this.api('muted', muted);},
    toggleMuted: function() {this.api('toggle-muted');},
    setVolume: function(volume) {this.api('volume', volume);},
    setFullscreen: function(fullscreen) {this.api('fullscreen', fullscreen);},
    watchOnSite: function(muted) {this.api('watch-on-site');},

    api: function(command, arg)
    {
        if (arg) command += '=' + arg;
        this._send(command);
    },

    create: function(element, options)
    {
        element = DM.$(element);
        if (!element || element.nodeType != 1)
            throw new Error("Invalid first argument sent to DM.player(), requires a HTML element or element id: " + element);
        if (!options || typeof options != 'object')
            throw new Error("Missing `options' parameter for DM.player()");
        if (!options.video)
            throw new Error("Missing `video' option parameter for DM.player()");

        options = DM.copy(options,
        {
            width: 480,
            height: 270,
            title: "video player",
            params: {},
            events: {}
        });

        var player = document.createElement("iframe");
        DM.Array.forEach(['id', 'style', 'class'], function(attr) {player.setAttribute(attr, element.getAttribute(attr));});
        element.parentNode.replaceChild(player, element);
        player.frameborder = "0";
        player.title = "Dailymotion " + options.title;
        player.type = "text/html";
        player.width = options.width;
        player.height = options.height;

        DM.copy(player, DM.Player);

        player.init(options.video, options.params);

        if (typeof options.events == "object")
        {
            for (var name in options.events)
            {
                player.addEventListener(name, options.events[name], false);
            }
        }

        return player;
    },

    init: function(video, params)
    {
        DM.Player._installHandlers();
        params = typeof params == "object" ? params : {};
        params.api = DM.Player.API_MODE;
        this.id = params.id = this.id ? this.id : DM.guid();
        this.src = DM._domain.www + "/embed/video/" + video + '?' + DM.QS.encode(params);
        if (DM.Player._INSTANCES[this.id] != this)
        {
            DM.Player._INSTANCES[this.id] = this;
            this.addEventListener('unload', function() {delete DM.Player._INSTANCES[this.id];});
        }
        this.autoplay = !(params.autoplay === false || (params.autoplay && params.autoplay.match(/^(?:false|no|off|)/i)));
    },

    _installHandlers: function()
    {
        if (window.postMessage && DM.Player.API_MODE != "fragment")
        {
            DM.Player.API_MODE = "postMessage";

            if (!DM.Player._HANDLER)
            {
                DM.Player._HANDLER = function(e)
                {
                    if (!e.origin || e.origin.indexOf(DM._domain.www) !== 0) return;
                    var event = DM.QS.decode(e.data);
                    if (!event.id || !event.event) return;
                    var player = DM.$(event.id);
                    player._recvEvent(event);
                };
                if (window.addEventListener) window.addEventListener("message", DM.Player._HANDLER, false);
                else if (window.attachEvent) window.attachEvent("onmessage", DM.Player._HANDLER);
            }
        }
        else
        {
            DM.Player.API_MODE = "fragment";
            return; // no yet ready

            if (!DM.Player._INTERVAL_ID)
            {
                DM.Player._INTERVAL_ID = setInterval(function()
                {
                    for (var id in DM.Player._INSTANCES)
                    {
                        var player = DM.Player._INSTANCES[id], pos;
                        if ((pos = player.src.indexOf('#')) != -1)
                        {
                            var event = DM.QS.decode(src.substring(pos + 1));
                            player.src = src.substring(0, pos); // reset fragment
                            if (event.id && event.event) player._recvEvent(event);
                        }
                    }
                    if (DM.Player._INSTANCES.length === 0) clearInterval(DM.Player._INTERVAL_ID);
                }, 0);
            }
        }
    },

    _send: window.postMessage ? function(command)
    {
        this.contentWindow.postMessage(command, DM._domain.www);
    }
    : function(command) // fragment API mode fallback
    {
        var src = this.src, pos;
        if ((pos = src.indexOf('#')) != -1) src = src.substring(0, pos);
        this.src = src + '#' + command;
    },

    _dispatch: document.createEvent ? function(type)
    {
        var e = document.createEvent("HTMLEvents");
        e.initEvent(type, true, true);
        this.dispatchEvent(e);
    }
    : function(type) // IE compat
    {
        e = document.createEventObject();
        this.fireEvent('on'+event.event, e);
    },

    _recvEvent: function(event)
    {
        switch (event.event)
        {
            case 'loadedmetadata': this.error = null; this.ended = false; break;
            case 'timeupdate': this.currentTime = event.time; break;
            case 'progress': this.bufferedTime = event.time; break;
            case 'durationchange': this.duration = event.duration; break;
            case 'seeking': this.seeking = true; this.currentTime = event.time; break;
            case 'seeked': this.seeking = false; this.currentTime = event.time; break;
            case 'fullscreenchange': this.fullscreen = event.fullscreen; break;
            case 'volumechange': this.volume = event.volume; break;
            case 'playing':
            case 'play': this.paused = false; break;
            case 'ended': this.ended = true; break; // no break, also set paused
            case 'ended':
            case 'pause': this.paused = true; break;
            case 'error': this.error = {code: event.code, title: event.title, message: event.message}; break;
        }

        this._dispatch(event.event);
    },

    // IE compat (DM.copy won't set this if already defined)
    addEventListener: function(name, callback, capture)
    {
        if (this.attachEvent) this.attachEvent("on" + name, callback, capture);
    }
});
<commit_msg>Fix autoplay bug (simplier code)<commit_after>/**
 * Copyright Dailymotion S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @provides dm.player
 * @requires dm.prelude
 *           dm.qs
 */

/**
 * Dailymotion Player.
 *
 * @class dm
 * @static
 * @access private
 */
DM.provide('',
{
    player: function(element, options)
    {
        return DM.Player.create(element, options);
    }
});

/**
 * The Player object.
 *
 * @class DM.Player
 * @access private
 */
DM.provide('Player',
{
    _INSTANCES: {},
    _HANDLER: null,
    _INTERVAL_ID: null,
    API_MODE: null,

    // video properties
    autoplay: false,
    currentTime: 0,
    bufferedTime: 0,
    duration: NaN,
    seeking: false,
    error: null,
    ended: false,
    muted: false,
    volume: 1,
    paused: true,
    fullscreen: false,

    play: function() {this.api('play');},
    togglePlay: function() {this.api('toggle-play');},
    pause: function() {this.api('pause');},
    seek: function(time) {this.api('seek', time);},
    load: function(id) {this.api('load', id);},
    setMuted: function(muted) {this.api('muted', muted);},
    toggleMuted: function() {this.api('toggle-muted');},
    setVolume: function(volume) {this.api('volume', volume);},
    setFullscreen: function(fullscreen) {this.api('fullscreen', fullscreen);},
    watchOnSite: function(muted) {this.api('watch-on-site');},

    api: function(command, arg)
    {
        if (arg) command += '=' + arg;
        this._send(command);
    },

    create: function(element, options)
    {
        element = DM.$(element);
        if (!element || element.nodeType != 1)
            throw new Error("Invalid first argument sent to DM.player(), requires a HTML element or element id: " + element);
        if (!options || typeof options != 'object')
            throw new Error("Missing `options' parameter for DM.player()");
        if (!options.video)
            throw new Error("Missing `video' option parameter for DM.player()");

        options = DM.copy(options,
        {
            width: 480,
            height: 270,
            title: "video player",
            params: {},
            events: {}
        });

        var player = document.createElement("iframe");
        DM.Array.forEach(['id', 'style', 'class'], function(attr) {player.setAttribute(attr, element.getAttribute(attr));});
        element.parentNode.replaceChild(player, element);
        player.frameborder = "0";
        player.title = "Dailymotion " + options.title;
        player.type = "text/html";
        player.width = options.width;
        player.height = options.height;

        DM.copy(player, DM.Player);

        player.init(options.video, options.params);

        if (typeof options.events == "object")
        {
            for (var name in options.events)
            {
                player.addEventListener(name, options.events[name], false);
            }
        }

        return player;
    },

    init: function(video, params)
    {
        DM.Player._installHandlers();
        params = typeof params == "object" ? params : {};
        params.api = DM.Player.API_MODE;
        this.id = params.id = this.id ? this.id : DM.guid();
        this.src = DM._domain.www + "/embed/video/" + video + '?' + DM.QS.encode(params);
        if (DM.Player._INSTANCES[this.id] != this)
        {
            DM.Player._INSTANCES[this.id] = this;
            this.addEventListener('unload', function() {delete DM.Player._INSTANCES[this.id];});
        }

        this.autoplay = params.autoplay && (/^(1|true|yes|on)/i).test(params.autoplay + '');
    },

    _installHandlers: function()
    {
        if (window.postMessage && DM.Player.API_MODE != "fragment")
        {
            DM.Player.API_MODE = "postMessage";

            if (!DM.Player._HANDLER)
            {
                DM.Player._HANDLER = function(e)
                {
                    if (!e.origin || e.origin.indexOf(DM._domain.www) !== 0) return;
                    var event = DM.QS.decode(e.data);
                    if (!event.id || !event.event) return;
                    var player = DM.$(event.id);
                    player._recvEvent(event);
                };
                if (window.addEventListener) window.addEventListener("message", DM.Player._HANDLER, false);
                else if (window.attachEvent) window.attachEvent("onmessage", DM.Player._HANDLER);
            }
        }
        else
        {
            DM.Player.API_MODE = "fragment";
            return; // no yet ready

            if (!DM.Player._INTERVAL_ID)
            {
                DM.Player._INTERVAL_ID = setInterval(function()
                {
                    for (var id in DM.Player._INSTANCES)
                    {
                        var player = DM.Player._INSTANCES[id], pos;
                        if ((pos = player.src.indexOf('#')) != -1)
                        {
                            var event = DM.QS.decode(src.substring(pos + 1));
                            player.src = src.substring(0, pos); // reset fragment
                            if (event.id && event.event) player._recvEvent(event);
                        }
                    }
                    if (DM.Player._INSTANCES.length === 0) clearInterval(DM.Player._INTERVAL_ID);
                }, 0);
            }
        }
    },

    _send: window.postMessage ? function(command)
    {
        this.contentWindow.postMessage(command, DM._domain.www);
    }
    : function(command) // fragment API mode fallback
    {
        var src = this.src, pos;
        if ((pos = src.indexOf('#')) != -1) src = src.substring(0, pos);
        this.src = src + '#' + command;
    },

    _dispatch: document.createEvent ? function(type)
    {
        var e = document.createEvent("HTMLEvents");
        e.initEvent(type, true, true);
        this.dispatchEvent(e);
    }
    : function(type) // IE compat
    {
        e = document.createEventObject();
        this.fireEvent('on'+event.event, e);
    },

    _recvEvent: function(event)
    {
        switch (event.event)
        {
            case 'loadedmetadata': this.error = null; this.ended = false; break;
            case 'timeupdate': this.currentTime = event.time; break;
            case 'progress': this.bufferedTime = event.time; break;
            case 'durationchange': this.duration = event.duration; break;
            case 'seeking': this.seeking = true; this.currentTime = event.time; break;
            case 'seeked': this.seeking = false; this.currentTime = event.time; break;
            case 'fullscreenchange': this.fullscreen = event.fullscreen; break;
            case 'volumechange': this.volume = event.volume; break;
            case 'playing':
            case 'play': this.paused = false; break;
            case 'ended': this.ended = true; break; // no break, also set paused
            case 'ended':
            case 'pause': this.paused = true; break;
            case 'error': this.error = {code: event.code, title: event.title, message: event.message}; break;
        }

        this._dispatch(event.event);
    },

    // IE compat (DM.copy won't set this if already defined)
    addEventListener: function(name, callback, capture)
    {
        if (this.attachEvent) this.attachEvent("on" + name, callback, capture);
    }
});
<|endoftext|>