<commit_before>describe('DataStore', function () {
  var store;

  beforeEach(function () {
    visit('/');
  });

  afterEach(function () {
    App.reset();
  });

  it('should push preloaded data into the store', function() {
    var allGroups, testGroup;
    var now = new Date();
    var groups = [{
        id: 999,
        title: 'test group',
        order: 0,
        date: now,
        fields: '[]'
    }];

    // attach GroupModel preload data
    var meta = document.createElement('meta');
    meta.setAttribute('name', 'preload-groups');
    meta.setAttribute('content', JSON.stringify(groups));
    document.head.appendChild(meta);

    // restart the app so it can get the preload
    Ember.run(function () {
      App.reset();
    });

    visit('groups');

    andThen(function () {
      store = App.__container__.lookup('store:main');
      allGroups = store.all('groups');
      testGroup = allGroups.objectAt(0);

      window.b = testGroup;
      expect(allGroups.get('length')).to.equal(1);
      expect(testGroup).to.exist;
      expect(testGroup.title).to.equal(groups[0].title);
      expect(testGroup.id).to.equal(groups[0].id);
      document.head.removeChild(meta);
    });
  });
});
<commit_msg>Streamline DataStore test<commit_after>describe('DataStore', function () {
  beforeEach(function () {
    visit('/');
  });

  afterEach(function () {
    App.reset();
  });

  it('should push preloaded data into the store', function() {
    var now = new Date();
    var groups = [{
        id: 999,
        title: 'test group',
        order: 0,
        date: now,
        fields: '[]'
    }];

    // attach GroupModel preload data
    var meta = document.createElement('meta');
    meta.setAttribute('name', 'preload-groups');
    meta.setAttribute('content', JSON.stringify(groups));
    document.head.appendChild(meta);

    // restart the app so it can get the preload
    Ember.run(function () {
      App.reset();
    });

    document.head.removeChild(meta);

    andThen(function () {
      var store = App.__container__.lookup('store:main'),
          testGroup = store.findById('groups', 999);

      assertDataStoreCount('groups', 1);

      expect(testGroup).to.exist;
      testGroup.title.should.equal(groups[0].title);
    });
  });
});
<|endoftext|>


<commit_before>import { combineReducers } from 'redux';
import { debounce } from 'underscore'; // TODO: implement this in utils

import fetchJSON from './utils/fetch_json';
import mapObject from './utils/map_object';
import identity from './utils/identity';

const RESOURCE_FETCH = 'RESOURCE_FETCH';
const RESOURCE_RECEIVED = 'RESOURCE_RECEIVED';
const RESOURCE_ERROR = 'RESOURCE_ERROR';

const userState = '__userState';
const resourceManagerState = '__resourceManagerState';

export default function applyResourceManager(resources) {
  const resourceConfigs = applyDefaults(resources);
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const reducers = {
      [userState]: reducer,
      [resourceManagerState]: createResourceManagerReducer(resourceConfigs),
    };
    reducer = combineReducers(reducers);
    const store = createStore(reducer, preloadedState, enhancer);
    const getResources = mapObject(
      resourceConfigs, (config) => createResourceGetter(config, store)
    );
    const wrappedStore = {
      ...store,
      getResources,
      getState: function wrappedGetState() {
        const state = store.getState();
        return {
          ...state[userState],
          [resourceManagerState]: state[resourceManagerState],
        };
      },
    };
    return wrappedStore;
  };
}

function createResourceManagerReducer(resourceConfigs) {
  return combineReducers(mapObject(resourceConfigs, (config) => createResourceReducer(config)));
}

function createResourceGetter(resourceConfig, store) {
  const { createCacheKey, resourceName } = resourceConfig;
  const { getState, dispatch } = store;
  return (params) => {
    const state = getState()[resourceManagerState][resourceName];
    const key = createCacheKey(params);
    if (!state[key] || Date.now() > state[key].expiration) {
      fetchResource(resourceConfig, params, dispatch);
    }
    return state[key] || { status: 'pending' };
  };
}

function applyDefaults(definitions) {
  return mapObject(definitions, (config, name) => ({
    ...config,
    resourceName: name,
    createCacheKey: config.createCacheKey || createDefaultCacheKey(config),
    parseResponse: config.parseResponse || identity,
  }));
}

function createDefaultCacheKey(resourceConfig) {
  return function defaultCacheKey(params) {
    const { url } = getUrlAndFetchOptions(resourceConfig, params);
    return url;
  };
}

function getUrlAndFetchOptions(resourceConfig, params) {
  const { buildUrl } = resourceConfig;
  const buildUrlResult = buildUrl(params);
  if (typeof buildUrlResult === 'string') {
    return {
      url: buildUrlResult,
      fetchOptions: {},
    };
  }
  const { url, ...fetchOptions } = buildUrlResult;
  return { url, fetchOptions };
}

const fetchResource = (() => {
  const queue = {};
  const fetchInBatch = debounce((resourceConfig, dispatch) => {
    const { buildBatches, resourceName } = resourceConfig;
    const batches = buildBatches(queue[resourceName].slice());
    batches.forEach((batch) => {
      const { url, fetchOptions } = getUrlAndFetchOptions(resourceConfig, batch);
      const request = batch.map((params) => {
        const retry = () => fetchResource(resourceConfig, params, dispatch);
        return { params, retry };
      });
      sendRequest(resourceConfig, url, fetchOptions, request, dispatch);
    });
    queue[resourceName] = [];
  }, 50); // TODO: make this batching buffer configurable?

  return (resourceConfig, params, dispatch) => {
    const { buildBatches, resourceName } = resourceConfig;
    if (buildBatches) {
      queue[resourceName] = queue[resourceName] || [];
      queue[resourceName].push(params);
      fetchInBatch(resourceConfig, dispatch);
    } else {
      const retry = () => fetchResource(resourceConfig, params, dispatch);
      const { url, fetchOptions } = getUrlAndFetchOptions(resourceConfig, params);
      const request = { params, retry };
      sendRequest(resourceConfig, url, fetchOptions, request, dispatch);
    }
  };
})();

function sendRequest(resourceConfig, url, fetchOptions, request, dispatch) {
  const { resourceName } = resourceConfig;
  function success(response) {
    dispatch(resourceReceived({ resourceName, request, response }));
  }
  function fail(error) {
    console.error(`redux-resource-manager error from ${resourceName}:`, error);
    dispatch(resourceError({ resourceName, request, error }));
  }

  fetchJSON(url, fetchOptions).then(success, fail);
  dispatch(resourceFetch({ resourceName, request }));
}

// //////////////////// actions

function resourceFetch({ resourceName, request }) {
  const type = RESOURCE_FETCH;
  return { type, resourceName, request };
}

function resourceReceived({ resourceName, request, response }) {
  const type = RESOURCE_RECEIVED;
  return { type, resourceName, request, response };
}

function resourceError({ resourceName, request }) {
  const type = RESOURCE_ERROR;
  return { type, resourceName, request };
}

// //////////////// createResourceReducer

function createResourceReducer(resourceConfig) {
  const {
    resourceName, ttl, createCacheKey, parseResponse, buildBatches, unbatchResponse,
  } = resourceConfig;
  return function resourceReducer(state = {}, action) {
    if (action.resourceName !== resourceName) {
      return state;
    }

    const cacheToUpdate = {};
    let paramsList;
    switch (action.type) {
      case RESOURCE_FETCH:
        paramsList = buildBatches ? action.request : [action.request];
        paramsList.forEach(({ params }) => {
          cacheToUpdate[createCacheKey(params)] = { status: 'pending' };
        });
        return { ...state, ...cacheToUpdate };

      // FIXME: figure out why eslint is messed up here
      case RESOURCE_RECEIVED: // eslint-disable-line
        if (!buildBatches) {
          cacheToUpdate[createCacheKey(action.request.params)] = {
            result: parseResponse(action.response),
            status: 'fulfilled',
            expiration: Date.now() + ttl,
          };
          return { ...state, ...cacheToUpdate };
        }

        const batchedParams = action.request.map(({ params }) => params);
        const { fulfilled, rejected } = unbatchResponse(batchedParams, action.response);

        rejected.forEach(({ params, error }) => {
          // FIXME: this seems so dangerous - all to avoid letting the user have access to
          // retry function in the `unbatchResponse` function
          const { retry } = action.request.find(reqInfo => reqInfo.params === params);
          if (!retry) throw new Error('Could not map params back to retry function');
          cacheToUpdate[createCacheKey(params)] = {
            status: 'rejected',
            retry: retry,
            error: error,
            expiration: Date.now() + ttl,
          };
        });

        fulfilled.forEach(({ params, result }) => {
          cacheToUpdate[createCacheKey(params)] = {
            result: result,
            status: 'fulfilled',
            expiration: Date.now() + ttl,
          };
        });

        return { ...state, ...cacheToUpdate };

      case RESOURCE_ERROR:
        paramsList = buildBatches ? action.request : [action.request];
        paramsList.forEach(({ params, retry }) => {
          cacheToUpdate[createCacheKey(params)] = {
            status: 'rejected',
            retry: retry,
            expiration: Date.now() + ttl,
            error: 'Fetch error', // bad default message????
          };
        });
        return { ...state, ...cacheToUpdate };
      default:
        return state;
    }
  };
}
<commit_msg>dispatch duration as part of RESOURCE_RECEIVED and RESOURCE_ERROR<commit_after>import { combineReducers } from 'redux';
import { debounce } from 'underscore'; // TODO: implement this in utils

import fetchJSON from './utils/fetch_json';
import mapObject from './utils/map_object';
import identity from './utils/identity';

const RESOURCE_FETCH = 'RESOURCE_FETCH';
const RESOURCE_RECEIVED = 'RESOURCE_RECEIVED';
const RESOURCE_ERROR = 'RESOURCE_ERROR';

const userState = '__userState';
const resourceManagerState = '__resourceManagerState';

export default function applyResourceManager(resources) {
  const resourceConfigs = applyDefaults(resources);
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const reducers = {
      [userState]: reducer,
      [resourceManagerState]: createResourceManagerReducer(resourceConfigs),
    };
    reducer = combineReducers(reducers);
    const store = createStore(reducer, preloadedState, enhancer);
    const getResources = mapObject(
      resourceConfigs, (config) => createResourceGetter(config, store)
    );
    const wrappedStore = {
      ...store,
      getResources,
      getState: function wrappedGetState() {
        const state = store.getState();
        return {
          ...state[userState],
          [resourceManagerState]: state[resourceManagerState],
        };
      },
    };
    return wrappedStore;
  };
}

function createResourceManagerReducer(resourceConfigs) {
  return combineReducers(mapObject(resourceConfigs, (config) => createResourceReducer(config)));
}

function createResourceGetter(resourceConfig, store) {
  const { createCacheKey, resourceName } = resourceConfig;
  const { getState, dispatch } = store;
  return (params) => {
    const state = getState()[resourceManagerState][resourceName];
    const key = createCacheKey(params);
    if (!state[key] || Date.now() > state[key].expiration) {
      fetchResource(resourceConfig, params, dispatch);
    }
    return state[key] || { status: 'pending' };
  };
}

function applyDefaults(definitions) {
  return mapObject(definitions, (config, name) => ({
    ...config,
    resourceName: name,
    createCacheKey: config.createCacheKey || createDefaultCacheKey(config),
    parseResponse: config.parseResponse || identity,
  }));
}

function createDefaultCacheKey(resourceConfig) {
  return function defaultCacheKey(params) {
    const { url } = getUrlAndFetchOptions(resourceConfig, params);
    return url;
  };
}

function getUrlAndFetchOptions(resourceConfig, params) {
  const { buildUrl } = resourceConfig;
  const buildUrlResult = buildUrl(params);
  if (typeof buildUrlResult === 'string') {
    return {
      url: buildUrlResult,
      fetchOptions: {},
    };
  }
  const { url, ...fetchOptions } = buildUrlResult;
  return { url, fetchOptions };
}

const fetchResource = (() => {
  const queue = {};
  const fetchInBatch = debounce((resourceConfig, dispatch) => {
    const { buildBatches, resourceName } = resourceConfig;
    const batches = buildBatches(queue[resourceName].slice());
    batches.forEach((batch) => {
      const { url, fetchOptions } = getUrlAndFetchOptions(resourceConfig, batch);
      const request = batch.map((params) => {
        const retry = () => fetchResource(resourceConfig, params, dispatch);
        return { params, retry };
      });
      sendRequest(resourceConfig, url, fetchOptions, request, dispatch);
    });
    queue[resourceName] = [];
  }, 50); // TODO: make this batching buffer configurable?

  return (resourceConfig, params, dispatch) => {
    const { buildBatches, resourceName } = resourceConfig;
    if (buildBatches) {
      queue[resourceName] = queue[resourceName] || [];
      queue[resourceName].push(params);
      fetchInBatch(resourceConfig, dispatch);
    } else {
      const retry = () => fetchResource(resourceConfig, params, dispatch);
      const { url, fetchOptions } = getUrlAndFetchOptions(resourceConfig, params);
      const request = { params, retry };
      sendRequest(resourceConfig, url, fetchOptions, request, dispatch);
    }
  };
})();

function getTimer() {
  return Math.round(performance.now());
}

function getDuration(startTime) {
  return getTimer() - startTime;
}

function sendRequest(resourceConfig, url, fetchOptions, request, dispatch) {
  const { resourceName } = resourceConfig;
  const startTime = getTimer();

  function success(response) {
    const duration = getDuration(startTime);
    dispatch(resourceReceived({ resourceName, request, response, duration }));
  }
  function fail(error) {
    const duration = getDuration(startTime);
    console.error(`redux-resource-manager error from ${resourceName}:`, error);
    dispatch(resourceError({ resourceName, request, error, duration }));
  }

  fetchJSON(url, fetchOptions).then(success, fail);
  dispatch(resourceFetch({ resourceName, request }));
}

// //////////////////// actions

function resourceFetch({ resourceName, request }) {
  const type = RESOURCE_FETCH;
  return { type, resourceName, request };
}

function resourceReceived({ resourceName, request, response, duration }) {
  const type = RESOURCE_RECEIVED;
  return { type, resourceName, request, response, duration };
}

function resourceError({ resourceName, request, duration }) {
  const type = RESOURCE_ERROR;
  return { type, resourceName, request, duration };
}

// //////////////// createResourceReducer

function createResourceReducer(resourceConfig) {
  const {
    resourceName, ttl, createCacheKey, parseResponse, buildBatches, unbatchResponse,
  } = resourceConfig;
  return function resourceReducer(state = {}, action) {
    if (action.resourceName !== resourceName) {
      return state;
    }

    const cacheToUpdate = {};
    let paramsList;
    switch (action.type) {
      case RESOURCE_FETCH:
        paramsList = buildBatches ? action.request : [action.request];
        paramsList.forEach(({ params }) => {
          cacheToUpdate[createCacheKey(params)] = { status: 'pending' };
        });
        return { ...state, ...cacheToUpdate };

      // FIXME: figure out why eslint is messed up here
      case RESOURCE_RECEIVED: // eslint-disable-line
        if (!buildBatches) {
          cacheToUpdate[createCacheKey(action.request.params)] = {
            result: parseResponse(action.response),
            status: 'fulfilled',
            expiration: Date.now() + ttl,
          };
          return { ...state, ...cacheToUpdate };
        }

        const batchedParams = action.request.map(({ params }) => params);
        const { fulfilled, rejected } = unbatchResponse(batchedParams, action.response);

        rejected.forEach(({ params, error }) => {
          // FIXME: this seems so dangerous - all to avoid letting the user have access to
          // retry function in the `unbatchResponse` function
          const { retry } = action.request.find(reqInfo => reqInfo.params === params);
          if (!retry) throw new Error('Could not map params back to retry function');
          cacheToUpdate[createCacheKey(params)] = {
            status: 'rejected',
            retry: retry,
            error: error,
            expiration: Date.now() + ttl,
          };
        });

        fulfilled.forEach(({ params, result }) => {
          cacheToUpdate[createCacheKey(params)] = {
            result: result,
            status: 'fulfilled',
            expiration: Date.now() + ttl,
          };
        });

        return { ...state, ...cacheToUpdate };

      case RESOURCE_ERROR:
        paramsList = buildBatches ? action.request : [action.request];
        paramsList.forEach(({ params, retry }) => {
          cacheToUpdate[createCacheKey(params)] = {
            status: 'rejected',
            retry: retry,
            expiration: Date.now() + ttl,
            error: 'Fetch error', // bad default message????
          };
        });
        return { ...state, ...cacheToUpdate };
      default:
        return state;
    }
  };
}
<|endoftext|>


<commit_before>var chai = require('chai');
var expect = require('chai').expect;
var AssertionError = require('chai').AssertionError;
var chaiAsPromised = require('chai-as-promised');
var chaiMugshot = require('../index.js');
var Mugshot = require('mugshot');
var WdioAdapter = Mugshot.adapters.WebdriverIO;
var wdio = require('webdriverio');
var fs = require('fs');
var path = require('path');

chai.use(chaiAsPromised);

var name = 'great';
var ext = '.png';
var dir = path.join(__dirname, '..', 'visual-tests');

function cleanUp() {
  var paths = [path.join(dir, name + ext), path.join(dir, name + '.new' + ext),
               path.join(dir, name + '.diff' + ext)];

  for (var i = 0; i < paths.length; i++) {
    try {
      fs.unlinkSync(paths[i]);
    } catch(error) {
      if (error.code != 'ENOENT') {
        throw error;
      }
    }
  }

  try {
    fs.rmdirSync(dir);
  } catch(error) {
    if (error.code != 'ENOENT') {
      throw error;
    }
  }
}

describe('Chai-Mugshot Plugin', function() {
  this.timeout(0);

  var url = 'file://' + path.join(__dirname, 'test.html'),
      brokenSelector = {
        name: name,
        selector: 'anything'
      },
      noSelector = {
        name: name
      },
      withSelector = {
        name: name,
        selector: '#rectangle'
      },
      wdioInstance, mugshot;

  before(function() {
    var options = {
      desiredCapabilities: {
        browserName: 'phantomjs'
      }
    };

    return wdioInstance = wdio.remote(options).init().url(url)
      .then(function() {
        var browser = new WdioAdapter(this);
        mugshot = new Mugshot(browser);

        chai.use(chaiMugshot(mugshot));
      });
  });

  beforeEach(function(done) {
    cleanUp();

    mugshot.test(withSelector, function(error) {
      if (error) {
        throw error;
      }

      done();
    });
  });

  it('should be rejected if mugshot fails', function() {
    return expect(expect(brokenSelector).to.be.identical).to.be
      .rejectedWith(Error);
  });

  it('should not throw if there is no previous baseline', function() {
    fs.unlinkSync(path.join(dir, name + ext));

    return expect(expect(withSelector).to.be.identical).to.be.fulfilled;
  });

  it('should not throw if there if there are no differences', function() {
    return expect(expect(withSelector).to.be.identical).to.be.fulfilled;
  });

  it('should throw error if there are differences', function() {
    return expect(expect(withSelector).to.not.be.identical).to.be
      .rejectedWith(AssertionError);
  });

  it('should not throw if there are differences', function() {
    return expect(expect(noSelector).to.not.be.identical).to.be.fulfilled;
  });

  it('should throw if there are no differences', function() {
    return expect(expect(noSelector).to.be.identical).to.be
      .rejectedWith(AssertionError);
  });

  after(function() {
    cleanUp();
    return wdioInstance.end();
  });
});
<commit_msg>remove duplicate text<commit_after>var chai = require('chai');
var expect = require('chai').expect;
var AssertionError = require('chai').AssertionError;
var chaiAsPromised = require('chai-as-promised');
var chaiMugshot = require('../index.js');
var Mugshot = require('mugshot');
var WdioAdapter = Mugshot.adapters.WebdriverIO;
var wdio = require('webdriverio');
var fs = require('fs');
var path = require('path');

chai.use(chaiAsPromised);

var name = 'great';
var ext = '.png';
var dir = path.join(__dirname, '..', 'visual-tests');

function cleanUp() {
  var paths = [path.join(dir, name + ext), path.join(dir, name + '.new' + ext),
               path.join(dir, name + '.diff' + ext)];

  for (var i = 0; i < paths.length; i++) {
    try {
      fs.unlinkSync(paths[i]);
    } catch(error) {
      if (error.code != 'ENOENT') {
        throw error;
      }
    }
  }

  try {
    fs.rmdirSync(dir);
  } catch(error) {
    if (error.code != 'ENOENT') {
      throw error;
    }
  }
}

describe('Chai-Mugshot Plugin', function() {
  this.timeout(0);

  var url = 'file://' + path.join(__dirname, 'test.html'),
      brokenSelector = {
        name: name,
        selector: 'anything'
      },
      noSelector = {
        name: name
      },
      withSelector = {
        name: name,
        selector: '#rectangle'
      },
      wdioInstance, mugshot;

  before(function() {
    var options = {
      desiredCapabilities: {
        browserName: 'phantomjs'
      }
    };

    return wdioInstance = wdio.remote(options).init().url(url)
      .then(function() {
        var browser = new WdioAdapter(this);
        mugshot = new Mugshot(browser);

        chai.use(chaiMugshot(mugshot));
      });
  });

  beforeEach(function(done) {
    cleanUp();

    mugshot.test(withSelector, function(error) {
      if (error) {
        throw error;
      }

      done();
    });
  });

  it('should be rejected if mugshot fails', function() {
    return expect(expect(brokenSelector).to.be.identical).to.be
      .rejectedWith(Error);
  });

  it('should not throw if there is no previous baseline', function() {
    fs.unlinkSync(path.join(dir, name + ext));

    return expect(expect(withSelector).to.be.identical).to.be.fulfilled;
  });

  it('should not throw if there are no differences', function() {
    return expect(expect(withSelector).to.be.identical).to.be.fulfilled;
  });

  it('should throw error if there are differences', function() {
    return expect(expect(withSelector).to.not.be.identical).to.be
      .rejectedWith(AssertionError);
  });

  it('should not throw if there are differences', function() {
    return expect(expect(noSelector).to.not.be.identical).to.be.fulfilled;
  });

  it('should throw if there are no differences', function() {
    return expect(expect(noSelector).to.be.identical).to.be
      .rejectedWith(AssertionError);
  });

  after(function() {
    cleanUp();
    return wdioInstance.end();
  });
});
<|endoftext|>


<commit_before>(function($) {

	$.extend(mejs.MepDefaults, {
		usePluginFullScreen: true,
		newWindowCallback: function() { return '';},
		fullscreenText: 'Fullscreen'
	});

	$.extend(MediaElementPlayer.prototype, {

		isFullScreen: false,

		isNativeFullScreen: false,

		docStyleOverflow: null,

		isInIframe: false,

		buildfullscreen: function(player, controls, layers, media) {

			if (!player.isVideo)
				return;

			player.isInIframe = (window.location != window.parent.location);

			// native events
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				// chrome doesn't alays fire this in an iframe
				player.container.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
				//player.container.bind('webkitfullscreenchange', function(e) {

					if (mejs.MediaFeatures.isFullScreen()) {
						player.isNativeFullScreen = true;
						// reset the controls once we are fully in full screen
						player.setControlsSize();
					} else {
						player.isNativeFullScreen = false;
						// when a user presses ESC
						// make sure to put the player back into place
						player.exitFullScreen();
					}
				});
			}

			var t = this,
				normalHeight = 0,
				normalWidth = 0,
				container = player.container,
				fullscreenBtn =
					$('
' +
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
					'
')
					.appendTo(controls);

				if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {

					fullscreenBtn.click(function() {
						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;

						if (isFullScreen) {
							player.exitFullScreen();
						} else {
							player.enterFullScreen();
						}
					});

				} else {

					var hideTimeout = null,
						supportsPointerEvents = (document.documentElement.style.pointerEvents === '');

					if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(

						// allows clicking through the fullscreen button and controls down directly to Flash

						/*
						 When a user puts his mouse over the fullscreen button, the controls are disabled
						 So we put a div over the video and another one on iether side of the fullscreen button
						 that caputre mouse movement
						 and restore the controls once the mouse moves outside of the fullscreen button
						*/

						var fullscreenIsDisabled = false,
							restoreControls = function() {
								if (fullscreenIsDisabled) {
									// hide the hovers
									videoHoverDiv.hide();
									controlsLeftHoverDiv.hide();
									controlsRightHoverDiv.hide();

									// restore the control bar
									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									// store for later
									fullscreenIsDisabled = false;
								}
							},
							videoHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							controlsLeftHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							controlsRightHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							positionHoverDivs = function() {
								var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
								videoHoverDiv.css(style);
								controlsLeftHoverDiv.css(style);
								controlsRightHoverDiv.css(style);

								// over video, but not controls
								videoHoverDiv
									.width( t.container.width() )
									.height( t.container.height() - t.controls.height() );

								// over controls, but not the fullscreen button
								var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
									fullScreenBtnWidth = fullscreenBtn.outerWidth(true);

								controlsLeftHoverDiv
									.width( fullScreenBtnOffset )
									.height( t.controls.height() )
									.css({top: t.container.height() - t.controls.height()});

								// after the fullscreen button
								controlsRightHoverDiv
									.width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
									.height( t.controls.height() )
									.css({top: t.container.height() - t.controls.height(),
										 left: fullScreenBtnOffset + fullScreenBtnWidth});
							};

						$(document).resize(function() {
							positionHoverDivs();
						});

						// on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
						fullscreenBtn
							.mouseover(function() {

								if (!t.isFullScreen) {

									var buttonPos = fullscreenBtn.offset(),
										containerPos = player.container.offset();

									// move the button in Flash into place
									media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);

									// allows click through
									fullscreenBtn.css('pointer-events', 'none');
									t.controls.css('pointer-events', 'none');

									// show the divs that will restore things
									videoHoverDiv.show();
									controlsRightHoverDiv.show();
									controlsLeftHoverDiv.show();
									positionHoverDivs();

									fullscreenIsDisabled = true;
								}

							});

						// restore controls anytime the user enters or leaves fullscreen
						media.addEventListener('fullscreenchange', function(e) {
							restoreControls();
						});

						// the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
						// so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
						/*
						$(document).mousemove(function(e) {

							// if the mouse is anywhere but the fullsceen button, then restore it all
							if (fullscreenIsDisabled) {

								var fullscreenBtnPos = fullscreenBtn.offset();

								if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
									e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
									) {

									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									fullscreenIsDisabled = false;
								}
							}
						});
						*/

					} else {

						// the hover state will show the fullscreen button in Flash to hover up and click

						fullscreenBtn
							.mouseover(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								var buttonPos = fullscreenBtn.offset(),
									containerPos = player.container.offset();

								media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);

							})
							.mouseout(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								hideTimeout = setTimeout(function() {
									media.hideFullscreenButton();
								}, 1500);

							});
					}
				}

			player.fullscreenBtn = fullscreenBtn;

			$(document).bind('keydown',function (e) {
				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
					player.exitFullScreen();
				}
			});

		},
		enterFullScreen: function() {

			var t = this;

			// firefox+flash can't adjust plugin sizes without resetting :(
			if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
				//t.media.setFullscreen(true);
				//player.isFullScreen = true;
				return;
			}

			// store overflow
			docStyleOverflow = document.documentElement.style.overflow;
			// set it to not show scroll bars so 100% will work
			document.documentElement.style.overflow = 'hidden';

			// store sizing
			normalHeight = t.container.height();
			normalWidth = t.container.width();

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
			if (t.media.pluginType === 'native') {
				if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

					mejs.MediaFeatures.requestFullScreen(t.container[0]);
					//return;

					if (t.isInIframe) {
						// sometimes exiting from fullscreen doesn't work
						// notably in Chrome . Fixed in version 17
						setTimeout(function checkFullscreen() {

							if (t.isNativeFullScreen) {

								// check if the video is suddenly not really fullscreen
								if ($(window).width() !== screen.width) {
									// manually exit
									t.exitFullScreen();
								} else {
									// test again
									setTimeout(checkFullscreen, 500);
								}
							}

						}, 500);
					}

				} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
					t.media.webkitEnterFullscreen();
					return;
				}
			}

			// check for iframe launch
			if (t.isInIframe) {
				var url = t.options.newWindowCallback(this);

				if (url !== '') {

					// launch immediately
					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
						t.pause();
						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
						return;
					} else {
						setTimeout(function() {
							if (!t.isNativeFullScreen) {
								t.pause();
								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
							}
						}, 250);
					}
				}

			}

			// full window code

			// make full size
			t.container
				.addClass('mejs-container-fullscreen')
				.width('100%')
				.height('100%');
				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});

			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
			// Actually, it seems to be needed for IE8, too
			//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
				setTimeout(function() {
					t.container.css({width: '100%', height: '100%'});
					t.setControlsSize();
				}, 500);
			//}

			if (t.pluginType === 'native') {
				t.$media
					.width('100%')
					.height('100%');
			} else {
				t.container.find('object, embed, iframe')
					.width('100%')
					.height('100%');

				//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
					t.media.setVideoSize($(window).width(),$(window).height());
				//}
			}

			t.layers.children('div')
				.width('100%')
				.height('100%');

			if (t.fullscreenBtn) {
				t.fullscreenBtn
					.removeClass('mejs-fullscreen')
					.addClass('mejs-unfullscreen');
			}

			t.setControlsSize();
			t.isFullScreen = true;
		},

		exitFullScreen: function() {

			var t = this;

			// firefox can't adjust plugins
			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
				t.media.setFullscreen(false);
				//player.isFullScreen = false;
				return;
			}

			// come outo of native fullscreen
			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
				mejs.MediaFeatures.cancelFullScreen();
			}

			// restore scroll bars to document
			document.documentElement.style.overflow = docStyleOverflow;

			t.container
				.removeClass('mejs-container-fullscreen')
				.width(normalWidth)
				.height(normalHeight);
				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			if (t.pluginType === 'native') {
				t.$media
					.width(normalWidth)
					.height(normalHeight);
			} else {
				t.container.find('object embed')
					.width(normalWidth)
					.height(normalHeight);

				t.media.setVideoSize(normalWidth, normalHeight);
			}

			t.layers.children('div')
				.width(normalWidth)
				.height(normalHeight);

			t.fullscreenBtn
				.removeClass('mejs-unfullscreen')
				.addClass('mejs-fullscreen');

			t.setControlsSize();
			t.isFullScreen = false;
		}
	});

})(mejs.$);
<commit_msg>better pointer events detection. (IE doesn't support it)<commit_after>(function($) {

	$.extend(mejs.MepDefaults, {
		usePluginFullScreen: true,
		newWindowCallback: function() { return '';},
		fullscreenText: 'Fullscreen'
	});

	$.extend(MediaElementPlayer.prototype, {

		isFullScreen: false,

		isNativeFullScreen: false,

		docStyleOverflow: null,

		isInIframe: false,

		buildfullscreen: function(player, controls, layers, media) {

			if (!player.isVideo)
				return;

			player.isInIframe = (window.location != window.parent.location);

			// native events
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				// chrome doesn't alays fire this in an iframe
				player.container.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
				//player.container.bind('webkitfullscreenchange', function(e) {

					if (mejs.MediaFeatures.isFullScreen()) {
						player.isNativeFullScreen = true;
						// reset the controls once we are fully in full screen
						player.setControlsSize();
					} else {
						player.isNativeFullScreen = false;
						// when a user presses ESC
						// make sure to put the player back into place
						player.exitFullScreen();
					}
				});
			}

			var t = this,
				normalHeight = 0,
				normalWidth = 0,
				container = player.container,
				fullscreenBtn =
					$('
' +
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
					'
')
					.appendTo(controls);

				if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {

					fullscreenBtn.click(function() {
						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;

						if (isFullScreen) {
							player.exitFullScreen();
						} else {
							player.enterFullScreen();
						}
					});

				} else {

					var hideTimeout = null,
						supportsPointerEvents = (function() {
							// TAKEN FROM MODERNIZR
							var element = document.createElement('x'),
								documentElement = document.documentElement,
								getComputedStyle = window.getComputedStyle,
								supports;
							if(!('pointerEvents' in element.style)){
								return false;
							}
							element.style.pointerEvents = 'auto';
							element.style.pointerEvents = 'x';
							documentElement.appendChild(element);
							supports = getComputedStyle &&
								getComputedStyle(element, '').pointerEvents === 'auto';
							documentElement.removeChild(element);
							return !!supports;
						})();

					console.log('supportsPointerEvents', supportsPointerEvents);

					if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(

						// allows clicking through the fullscreen button and controls down directly to Flash

						/*
						 When a user puts his mouse over the fullscreen button, the controls are disabled
						 So we put a div over the video and another one on iether side of the fullscreen button
						 that caputre mouse movement
						 and restore the controls once the mouse moves outside of the fullscreen button
						*/

						var fullscreenIsDisabled = false,
							restoreControls = function() {
								if (fullscreenIsDisabled) {
									// hide the hovers
									videoHoverDiv.hide();
									controlsLeftHoverDiv.hide();
									controlsRightHoverDiv.hide();

									// restore the control bar
									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									// store for later
									fullscreenIsDisabled = false;
								}
							},
							videoHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							controlsLeftHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							controlsRightHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							positionHoverDivs = function() {
								var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
								videoHoverDiv.css(style);
								controlsLeftHoverDiv.css(style);
								controlsRightHoverDiv.css(style);

								// over video, but not controls
								videoHoverDiv
									.width( t.container.width() )
									.height( t.container.height() - t.controls.height() );

								// over controls, but not the fullscreen button
								var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
									fullScreenBtnWidth = fullscreenBtn.outerWidth(true);

								controlsLeftHoverDiv
									.width( fullScreenBtnOffset )
									.height( t.controls.height() )
									.css({top: t.container.height() - t.controls.height()});

								// after the fullscreen button
								controlsRightHoverDiv
									.width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
									.height( t.controls.height() )
									.css({top: t.container.height() - t.controls.height(),
										 left: fullScreenBtnOffset + fullScreenBtnWidth});
							};

						$(document).resize(function() {
							positionHoverDivs();
						});

						// on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
						fullscreenBtn
							.mouseover(function() {

								if (!t.isFullScreen) {

									var buttonPos = fullscreenBtn.offset(),
										containerPos = player.container.offset();

									// move the button in Flash into place
									media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);

									// allows click through
									fullscreenBtn.css('pointer-events', 'none');
									t.controls.css('pointer-events', 'none');

									// show the divs that will restore things
									videoHoverDiv.show();
									controlsRightHoverDiv.show();
									controlsLeftHoverDiv.show();
									positionHoverDivs();

									fullscreenIsDisabled = true;
								}

							});

						// restore controls anytime the user enters or leaves fullscreen
						media.addEventListener('fullscreenchange', function(e) {
							restoreControls();
						});

						// the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
						// so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
						/*
						$(document).mousemove(function(e) {

							// if the mouse is anywhere but the fullsceen button, then restore it all
							if (fullscreenIsDisabled) {

								var fullscreenBtnPos = fullscreenBtn.offset();

								if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
									e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
									) {

									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									fullscreenIsDisabled = false;
								}
							}
						});
						*/

					} else {

						// the hover state will show the fullscreen button in Flash to hover up and click

						fullscreenBtn
							.mouseover(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								var buttonPos = fullscreenBtn.offset(),
									containerPos = player.container.offset();

								media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);

							})
							.mouseout(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								hideTimeout = setTimeout(function() {
									media.hideFullscreenButton();
								}, 1500);

							});
					}
				}

			player.fullscreenBtn = fullscreenBtn;

			$(document).bind('keydown',function (e) {
				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
					player.exitFullScreen();
				}
			});

		},
		enterFullScreen: function() {

			var t = this;

			// firefox+flash can't adjust plugin sizes without resetting :(
			if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
				//t.media.setFullscreen(true);
				//player.isFullScreen = true;
				return;
			}

			// store overflow
			docStyleOverflow = document.documentElement.style.overflow;
			// set it to not show scroll bars so 100% will work
			document.documentElement.style.overflow = 'hidden';

			// store sizing
			normalHeight = t.container.height();
			normalWidth = t.container.width();

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
			if (t.media.pluginType === 'native') {
				if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

					mejs.MediaFeatures.requestFullScreen(t.container[0]);
					//return;

					if (t.isInIframe) {
						// sometimes exiting from fullscreen doesn't work
						// notably in Chrome . Fixed in version 17
						setTimeout(function checkFullscreen() {

							if (t.isNativeFullScreen) {

								// check if the video is suddenly not really fullscreen
								if ($(window).width() !== screen.width) {
									// manually exit
									t.exitFullScreen();
								} else {
									// test again
									setTimeout(checkFullscreen, 500);
								}
							}

						}, 500);
					}

				} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
					t.media.webkitEnterFullscreen();
					return;
				}
			}

			// check for iframe launch
			if (t.isInIframe) {
				var url = t.options.newWindowCallback(this);

				if (url !== '') {

					// launch immediately
					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
						t.pause();
						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
						return;
					} else {
						setTimeout(function() {
							if (!t.isNativeFullScreen) {
								t.pause();
								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
							}
						}, 250);
					}
				}

			}

			// full window code

			// make full size
			t.container
				.addClass('mejs-container-fullscreen')
				.width('100%')
				.height('100%');
				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});

			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
			// Actually, it seems to be needed for IE8, too
			//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
				setTimeout(function() {
					t.container.css({width: '100%', height: '100%'});
					t.setControlsSize();
				}, 500);
			//}

			if (t.pluginType === 'native') {
				t.$media
					.width('100%')
					.height('100%');
			} else {
				t.container.find('object, embed, iframe')
					.width('100%')
					.height('100%');

				//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
					t.media.setVideoSize($(window).width(),$(window).height());
				//}
			}

			t.layers.children('div')
				.width('100%')
				.height('100%');

			if (t.fullscreenBtn) {
				t.fullscreenBtn
					.removeClass('mejs-fullscreen')
					.addClass('mejs-unfullscreen');
			}

			t.setControlsSize();
			t.isFullScreen = true;
		},

		exitFullScreen: function() {

			var t = this;

			// firefox can't adjust plugins
			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
				t.media.setFullscreen(false);
				//player.isFullScreen = false;
				return;
			}

			// come outo of native fullscreen
			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
				mejs.MediaFeatures.cancelFullScreen();
			}

			// restore scroll bars to document
			document.documentElement.style.overflow = docStyleOverflow;

			t.container
				.removeClass('mejs-container-fullscreen')
				.width(normalWidth)
				.height(normalHeight);
				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			if (t.pluginType === 'native') {
				t.$media
					.width(normalWidth)
					.height(normalHeight);
			} else {
				t.container.find('object embed')
					.width(normalWidth)
					.height(normalHeight);

				t.media.setVideoSize(normalWidth, normalHeight);
			}

			t.layers.children('div')
				.width(normalWidth)
				.height(normalHeight);

			t.fullscreenBtn
				.removeClass('mejs-unfullscreen')
				.addClass('mejs-fullscreen');

			t.setControlsSize();
			t.isFullScreen = false;
		}
	});

})(mejs.$);
<|endoftext|>


<commit_before>(function($) {

	$.extend(mejs.MepDefaults, {
		usePluginFullScreen: true,
		newWindowCallback: function() { return '';},
		fullscreenText: mejs.i18n.t('Fullscreen')
	});

	$.extend(MediaElementPlayer.prototype, {

		isFullScreen: false,

		isNativeFullScreen: false,

		docStyleOverflow: null,

		isInIframe: false,

		buildfullscreen: function(player, controls, layers, media) {

			if (!player.isVideo)
				return;

			player.isInIframe = (window.location != window.parent.location);

			// native events
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				// chrome doesn't alays fire this in an iframe
				var func = function(e) {

					if (mejs.MediaFeatures.isFullScreen()) {
						player.isNativeFullScreen = true;
						// reset the controls once we are fully in full screen
						player.setControlsSize();
					} else {
						player.isNativeFullScreen = false;
						// when a user presses ESC
						// make sure to put the player back into place
						player.exitFullScreen();
					}
				};

				if (mejs.MediaFeatures.hasMozNativeFullScreen) {
					player.globalBind(mejs.MediaFeatures.fullScreenEventName, func);
				} else {
					player.container.bind(mejs.MediaFeatures.fullScreenEventName, func);
				}
			}

			var t = this,
				normalHeight = 0,
				normalWidth = 0,
				container = player.container,
				fullscreenBtn =
					$('
' +
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
					'
')
					.appendTo(controls);

				if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {

					fullscreenBtn.click(function() {
						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;

						if (isFullScreen) {
							player.exitFullScreen();
						} else {
							player.enterFullScreen();
						}
					});

				} else {

					var hideTimeout = null,
						supportsPointerEvents = (function() {
							// TAKEN FROM MODERNIZR
							var element = document.createElement('x'),
								documentElement = document.documentElement,
								getComputedStyle = window.getComputedStyle,
								supports;
							if(!('pointerEvents' in element.style)){
								return false;
							}
							element.style.pointerEvents = 'auto';
							element.style.pointerEvents = 'x';
							documentElement.appendChild(element);
							supports = getComputedStyle &&
								getComputedStyle(element, '').pointerEvents === 'auto';
							documentElement.removeChild(element);
							return !!supports;
						})();

					//console.log('supportsPointerEvents', supportsPointerEvents);

					if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(

						// allows clicking through the fullscreen button and controls down directly to Flash

						/*
						 When a user puts his mouse over the fullscreen button, the controls are disabled
						 So we put a div over the video and another one on iether side of the fullscreen button
						 that caputre mouse movement
						 and restore the controls once the mouse moves outside of the fullscreen button
						*/

						var fullscreenIsDisabled = false,
							restoreControls = function() {
								if (fullscreenIsDisabled) {
									// hide the hovers
									videoHoverDiv.hide();
									controlsLeftHoverDiv.hide();
									controlsRightHoverDiv.hide();

									// restore the control bar
									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									// store for later
									fullscreenIsDisabled = false;
								}
							},
							videoHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							controlsLeftHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							controlsRightHoverDiv = $('
').appendTo(t.container).mouseover(restoreControls),
							positionHoverDivs = function() {
								var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
								videoHoverDiv.css(style);
								controlsLeftHoverDiv.css(style);
								controlsRightHoverDiv.css(style);

								// over video, but not controls
								videoHoverDiv
									.width( t.container.width() )
									.height( t.container.height() - t.controls.height() );

								// over controls, but not the fullscreen button
								var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
									fullScreenBtnWidth = fullscreenBtn.outerWidth(true);

								controlsLeftHoverDiv
									.width( fullScreenBtnOffset )
									.height( t.controls.height() )
									.css({top: t.container.height() - t.controls.height()});

								// after the fullscreen button
								controlsRightHoverDiv
									.width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
									.height( t.controls.height() )
									.css({top: t.container.height() - t.controls.height(),
										 left: fullScreenBtnOffset + fullScreenBtnWidth});
							};

						t.globalBind('resize', function() {
							positionHoverDivs();
						});

						// on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
						fullscreenBtn
							.mouseover(function() {

								if (!t.isFullScreen) {

									var buttonPos = fullscreenBtn.offset(),
										containerPos = player.container.offset();

									// move the button in Flash into place
									media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);

									// allows click through
									fullscreenBtn.css('pointer-events', 'none');
									t.controls.css('pointer-events', 'none');

									// show the divs that will restore things
									videoHoverDiv.show();
									controlsRightHoverDiv.show();
									controlsLeftHoverDiv.show();
									positionHoverDivs();

									fullscreenIsDisabled = true;
								}

							});

						// restore controls anytime the user enters or leaves fullscreen
						media.addEventListener('fullscreenchange', function(e) {
							restoreControls();
						});

						// the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
						// so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
						/*
						t.globalBind('mousemove', function(e) {

							// if the mouse is anywhere but the fullsceen button, then restore it all
							if (fullscreenIsDisabled) {

								var fullscreenBtnPos = fullscreenBtn.offset();

								if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
									e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
									) {

									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									fullscreenIsDisabled = false;
								}
							}
						});
						*/

					} else {

						// the hover state will show the fullscreen button in Flash to hover up and click

						fullscreenBtn
							.mouseover(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								var buttonPos = fullscreenBtn.offset(),
									containerPos = player.container.offset();

								media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);

							})
							.mouseout(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								hideTimeout = setTimeout(function() {
									media.hideFullscreenButton();
								}, 1500);

							});
					}
				}

			player.fullscreenBtn = fullscreenBtn;

			t.globalBind('keydown',function (e) {
				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
					player.exitFullScreen();
				}
			});

		},

		cleanfullscreen: function(player) {
			player.exitFullScreen();
		},

		enterFullScreen: function() {

			var t = this;

			// firefox+flash can't adjust plugin sizes without resetting :(
			if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
				//t.media.setFullscreen(true);
				//player.isFullScreen = true;
				return;
			}

			// store overflow
			docStyleOverflow = document.documentElement.style.overflow;
			// set it to not show scroll bars so 100% will work
			document.documentElement.style.overflow = 'hidden';

			// store sizing
			normalHeight = t.container.height();
			normalWidth = t.container.width();

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
			if (t.media.pluginType === 'native') {
				if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

					mejs.MediaFeatures.requestFullScreen(t.container[0]);
					//return;

					if (t.isInIframe) {
						// sometimes exiting from fullscreen doesn't work
						// notably in Chrome . Fixed in version 17
						setTimeout(function checkFullscreen() {

							if (t.isNativeFullScreen) {

								// check if the video is suddenly not really fullscreen
								if ($(window).width() !== screen.width) {
									// manually exit
									t.exitFullScreen();
								} else {
									// test again
									setTimeout(checkFullscreen, 500);
								}
							}

						}, 500);
					}

				} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
					t.media.webkitEnterFullscreen();
					return;
				}
			}

			// check for iframe launch
			if (t.isInIframe) {
				var url = t.options.newWindowCallback(this);

				if (url !== '') {

					// launch immediately
					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
						t.pause();
						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
						return;
					} else {
						setTimeout(function() {
							if (!t.isNativeFullScreen) {
								t.pause();
								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
							}
						}, 250);
					}
				}

			}

			// full window code

			// make full size
			t.container
				.addClass('mejs-container-fullscreen')
				.width('100%')
				.height('100%');
				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});

			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
			// Actually, it seems to be needed for IE8, too
			//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
				setTimeout(function() {
					t.container.css({width: '100%', height: '100%'});
					t.setControlsSize();
				}, 500);
			//}

			if (t.pluginType === 'native') {
				t.$media
					.width('100%')
					.height('100%');
			} else {
				t.container.find('.mejs-shim')
					.width('100%')
					.height('100%');

				//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
					t.media.setVideoSize($(window).width(),$(window).height());
				//}
			}

			t.layers.children('div')
				.width('100%')
				.height('100%');

			if (t.fullscreenBtn) {
				t.fullscreenBtn
					.removeClass('mejs-fullscreen')
					.addClass('mejs-unfullscreen');
			}

			t.setControlsSize();
			t.isFullScreen = true;
		},

		exitFullScreen: function() {

			var t = this;

			// firefox can't adjust plugins
			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
				t.media.setFullscreen(false);
				//player.isFullScreen = false;
				return;
			}

			// come outo of native fullscreen
			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
				mejs.MediaFeatures.cancelFullScreen();
			}

			// restore scroll bars to document
			document.documentElement.style.overflow = docStyleOverflow;

			t.container
				.removeClass('mejs-container-fullscreen')
				.width(normalWidth)
				.height(normalHeight);
				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			if (t.pluginType === 'native') {
				t.$media
					.width(normalWidth)
					.height(normalHeight);
			} else {
				t.container.find('object embed')
					.width(normalWidth)
					.height(normalHeight);

				t.media.setVideoSize(normalWidth, normalHeight);
			}

			t.layers.children('div')
				.width(normalWidth)
				.height(normalHeight);

			t.fullscreenBtn
				.removeClass('mejs-unfullscreen')
				.addClass('mejs-fullscreen');

			t.setControlsSize();
			t.isFullScreen = false;
		}
	});

})(mejs.$);
<commit_msg>Overhauling hover div creation and placement<commit_after>(function($) {

	$.extend(mejs.MepDefaults, {
		usePluginFullScreen: true,
		newWindowCallback: function() { return '';},
		fullscreenText: mejs.i18n.t('Fullscreen')
	});

	$.extend(MediaElementPlayer.prototype, {

		isFullScreen: false,

		isNativeFullScreen: false,

		docStyleOverflow: null,

		isInIframe: false,

		buildfullscreen: function(player, controls, layers, media) {

			if (!player.isVideo)
				return;

			player.isInIframe = (window.location != window.parent.location);

			// native events
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				// chrome doesn't alays fire this in an iframe
				var func = function(e) {

					if (mejs.MediaFeatures.isFullScreen()) {
						player.isNativeFullScreen = true;
						// reset the controls once we are fully in full screen
						player.setControlsSize();
					} else {
						player.isNativeFullScreen = false;
						// when a user presses ESC
						// make sure to put the player back into place
						player.exitFullScreen();
					}
				};

				if (mejs.MediaFeatures.hasMozNativeFullScreen) {
					player.globalBind(mejs.MediaFeatures.fullScreenEventName, func);
				} else {
					player.container.bind(mejs.MediaFeatures.fullScreenEventName, func);
				}
			}

			var t = this,
				normalHeight = 0,
				normalWidth = 0,
				container = player.container,
				fullscreenBtn =
					$('
' +
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
					'
')
					.appendTo(controls);

				if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {

					fullscreenBtn.click(function() {
						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;

						if (isFullScreen) {
							player.exitFullScreen();
						} else {
							player.enterFullScreen();
						}
					});

				} else {

					var hideTimeout = null,
						supportsPointerEvents = (function() {
							// TAKEN FROM MODERNIZR
							var element = document.createElement('x'),
								documentElement = document.documentElement,
								getComputedStyle = window.getComputedStyle,
								supports;
							if(!('pointerEvents' in element.style)){
								return false;
							}
							element.style.pointerEvents = 'auto';
							element.style.pointerEvents = 'x';
							documentElement.appendChild(element);
							supports = getComputedStyle &&
								getComputedStyle(element, '').pointerEvents === 'auto';
							documentElement.removeChild(element);
							return !!supports;
						})();

					//console.log('supportsPointerEvents', supportsPointerEvents);

					if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(

						// allows clicking through the fullscreen button and controls down directly to Flash

						/*
						 When a user puts his mouse over the fullscreen button, the controls are disabled
						 So we put a div over the video and another one on iether side of the fullscreen button
						 that caputre mouse movement
						 and restore the controls once the mouse moves outside of the fullscreen button
						*/

						var fullscreenIsDisabled = false,
							restoreControls = function() {
								if (fullscreenIsDisabled) {
									// hide the hovers
									for (var i in hoverDivs) {
										hoverDivs[i].hide();
									}

									// restore the control bar
									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									// store for later
									fullscreenIsDisabled = false;
								}
							},
							hoverDivs = {},
							hoverDivNames = ['top', 'left', 'right', 'bottom'],
							i, len,
							positionHoverDivs = function() {
								var fullScreenBtnOffsetLeft = fullscreenBtn.offset().left - t.container.offset().left,
									fullScreenBtnOffsetTop = fullscreenBtn.offset().top - t.container.offset().top,
									fullScreenBtnWidth = fullscreenBtn.outerWidth(true),
									fullScreenBtnHeight = fullscreenBtn.outerHeight(true),
									containerWidth = t.container.width(),
									containerHeight = t.container.height();

							  for (i in hoverDivs) {
									hoverDivs[i].css({position: 'absolute', top: 0, left: 0}); //, backgroundColor: '#f00'});
								}

								// over video, but not controls
								hoverDivs['top']
									.width( containerWidth )
									.height( fullScreenBtnOffsetTop );

								// over controls, but not the fullscreen button
								hoverDivs['left']
									.width( fullScreenBtnOffsetLeft )
									.height( fullScreenBtnHeight )
									.css({top: fullScreenBtnOffsetTop});

								// after the fullscreen button
								hoverDivs['right']
									.width( containerWidth - fullScreenBtnOffsetLeft - fullScreenBtnWidth )
									.height( fullScreenBtnHeight )
									.css({top: fullScreenBtnOffsetTop,
										 left: fullScreenBtnOffsetLeft + fullScreenBtnWidth});

								// under the fullscreen button
								hoverDivs['bottom']
									.width( containerWidth )
									.height( containerHeight - fullScreenBtnHeight - fullScreenBtnOffsetTop )
									.css({top: fullScreenBtnOffsetTop + fullScreenBtnHeight});
							};

						t.globalBind('resize', function() {
							positionHoverDivs();
						});

						for (i = 0, len = hoverDivNames.length; i < len; i += 1) {
							hoverDivs[hoverDivNames[i]] = $('
').appendTo(t.container).mouseover(restoreControls).hide();
						}

						// on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
						fullscreenBtn
							.mouseover(function() {

								if (!t.isFullScreen) {

									var buttonPos = fullscreenBtn.offset(),
										containerPos = player.container.offset();

									// move the button in Flash into place
									media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);

									// allows click through
									fullscreenBtn.css('pointer-events', 'none');
									t.controls.css('pointer-events', 'none');

									// show the divs that will restore things
								  for (i in hoverDivs) {
										hoverDivs[i].show();
									}
									positionHoverDivs();

									fullscreenIsDisabled = true;
								}

							});

						// restore controls anytime the user enters or leaves fullscreen
						media.addEventListener('fullscreenchange', function(e) {
							restoreControls();
						});

						// the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
						// so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
						/*
						t.globalBind('mousemove', function(e) {

							// if the mouse is anywhere but the fullsceen button, then restore it all
							if (fullscreenIsDisabled) {

								var fullscreenBtnPos = fullscreenBtn.offset();

								if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
									e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
									) {

									fullscreenBtn.css('pointer-events', '');
									t.controls.css('pointer-events', '');

									fullscreenIsDisabled = false;
								}
							}
						});
						*/

					} else {

						// the hover state will show the fullscreen button in Flash to hover up and click

						fullscreenBtn
							.mouseover(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								var buttonPos = fullscreenBtn.offset(),
									containerPos = player.container.offset();

								media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);

							})
							.mouseout(function() {

								if (hideTimeout !== null) {
									clearTimeout(hideTimeout);
									delete hideTimeout;
								}

								hideTimeout = setTimeout(function() {
									media.hideFullscreenButton();
								}, 1500);

							});
					}
				}

			player.fullscreenBtn = fullscreenBtn;

			t.globalBind('keydown',function (e) {
				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
					player.exitFullScreen();
				}
			});

		},

		cleanfullscreen: function(player) {
			player.exitFullScreen();
		},

		enterFullScreen: function() {

			var t = this;

			// firefox+flash can't adjust plugin sizes without resetting :(
			if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
				//t.media.setFullscreen(true);
				//player.isFullScreen = true;
				return;
			}

			// store overflow
			docStyleOverflow = document.documentElement.style.overflow;
			// set it to not show scroll bars so 100% will work
			document.documentElement.style.overflow = 'hidden';

			// store sizing
			normalHeight = t.container.height();
			normalWidth = t.container.width();

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
			if (t.media.pluginType === 'native') {
				if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

					mejs.MediaFeatures.requestFullScreen(t.container[0]);
					//return;

					if (t.isInIframe) {
						// sometimes exiting from fullscreen doesn't work
						// notably in Chrome . Fixed in version 17
						setTimeout(function checkFullscreen() {

							if (t.isNativeFullScreen) {

								// check if the video is suddenly not really fullscreen
								if ($(window).width() !== screen.width) {
									// manually exit
									t.exitFullScreen();
								} else {
									// test again
									setTimeout(checkFullscreen, 500);
								}
							}

						}, 500);
					}

				} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
					t.media.webkitEnterFullscreen();
					return;
				}
			}

			// check for iframe launch
			if (t.isInIframe) {
				var url = t.options.newWindowCallback(this);

				if (url !== '') {

					// launch immediately
					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
						t.pause();
						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
						return;
					} else {
						setTimeout(function() {
							if (!t.isNativeFullScreen) {
								t.pause();
								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
							}
						}, 250);
					}
				}

			}

			// full window code

			// make full size
			t.container
				.addClass('mejs-container-fullscreen')
				.width('100%')
				.height('100%');
				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});

			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
			// Actually, it seems to be needed for IE8, too
			//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
				setTimeout(function() {
					t.container.css({width: '100%', height: '100%'});
					t.setControlsSize();
				}, 500);
			//}

			if (t.pluginType === 'native') {
				t.$media
					.width('100%')
					.height('100%');
			} else {
				t.container.find('.mejs-shim')
					.width('100%')
					.height('100%');

				//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
					t.media.setVideoSize($(window).width(),$(window).height());
				//}
			}

			t.layers.children('div')
				.width('100%')
				.height('100%');

			if (t.fullscreenBtn) {
				t.fullscreenBtn
					.removeClass('mejs-fullscreen')
					.addClass('mejs-unfullscreen');
			}

			t.setControlsSize();
			t.isFullScreen = true;
		},

		exitFullScreen: function() {

			var t = this;

			// firefox can't adjust plugins
			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
				t.media.setFullscreen(false);
				//player.isFullScreen = false;
				return;
			}

			// come outo of native fullscreen
			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
				mejs.MediaFeatures.cancelFullScreen();
			}

			// restore scroll bars to document
			document.documentElement.style.overflow = docStyleOverflow;

			t.container
				.removeClass('mejs-container-fullscreen')
				.width(normalWidth)
				.height(normalHeight);
				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			if (t.pluginType === 'native') {
				t.$media
					.width(normalWidth)
					.height(normalHeight);
			} else {
				t.container.find('object embed')
					.width(normalWidth)
					.height(normalHeight);

				t.media.setVideoSize(normalWidth, normalHeight);
			}

			t.layers.children('div')
				.width(normalWidth)
				.height(normalHeight);

			t.fullscreenBtn
				.removeClass('mejs-unfullscreen')
				.addClass('mejs-fullscreen');

			t.setControlsSize();
			t.isFullScreen = false;
		}
	});

})(mejs.$);
<|endoftext|>


<commit_before>var test = require('tape')
var pixie = require('../dist/pixie.js')
var parse = pixie.parse
var compile = pixie.compile
var render = pixie.render

test('parse', function (t) {
  t.plan(4)
  t.same(parse('foo{{bar}}baz{{qux}}qix', '{{', '}}'), [['foo', 'baz', 'qix'], ['bar', 'qux']], 'inner expressions')
  t.same(parse('{{foo}}bar{{baz}}qux{{qix}}', '{{', '}}'), [['', 'bar', 'qux', ''], ['foo', 'baz', 'qix']], 'outer expressions')
  t.same(parse('foo bar baz qux qix', '{{', '}}'), [['foo bar baz qux qix'], []], 'no expressions')
  t.same(parse('foo __bar__ baz __qux__', '__', '__'), [['foo ', ' baz ', ''], ['bar', 'qux']], 'same open and close tags')
})

test('compile', function (t) {
  t.plan(4)

  var sample1 = parse('foo{{bar}}baz{{qux}}qix', '{{', '}}')
  var sample2 = parse('{{foo}}bar{{baz}}qux{{qix}}', '{{', '}}')
  var sample3 = parse('foo bar baz qux qix', '{{', '}}')

  t.is(compile(sample1, { bar: 'baaar', qux: 'quuux' }), 'foobaaarbazquuuxqix', 'inner expressions')
  t.is(compile(sample2, { foo: 'foooo', baz: 'baaaz', qix: 'qiiix' }), 'foooobarbaaazquxqiiix', 'outer expressions')
  t.is(compile(sample3, { dummy: 'data' }), 'foo bar baz qux qix', 'no expressions')
  t.is(compile(sample1, { bar: 'baaar' }), 'foobaaarbazundefinedqix', 'missing data')
})

test('render', function (t) {
  t.plan(2)
  t.is(render('foo{{bar}}baz{{qux}}qix', {bar: 'hello', qux: 'world'}, '{{', '}}'), 'foohellobazworldqix', 'plain render')
  t.is(render('<%foo%>bar<%baz%>qux<%qix%>', {foo: 'bar', baz: 'qux', qix: 'qaz'}, '<%', '%>'), 'barbarquxquxqaz', 'custom tags')
})
<commit_msg>test against old render<commit_after>var test = require('tape')
var pixie = require('../dist/pixie.js')
var parse = pixie.parse
var compile = pixie.compile
var render = pixie.render

function renderOG (source, data, open, close) {
  return compile(parse(source, open, close), data)
}

test('parse', function (t) {
  t.plan(4)

  var sample1 = parse('foo{{bar}}baz{{qux}}qix', '{{', '}}')
  var sample2 = parse('{{foo}}bar{{baz}}qux{{qix}}', '{{', '}}')
  var sample3 = parse('foo bar baz qux qix', '{{', '}}')
  var sample4 = parse('foo __bar__ baz __qux__', '__', '__')

  t.same(sample1, [['foo', 'baz', 'qix'], ['bar', 'qux']], 'inner expressions')
  t.same(sample2, [['', 'bar', 'qux', ''], ['foo', 'baz', 'qix']], 'outer expressions')
  t.same(sample3, [['foo bar baz qux qix'], []], 'no expressions')
  t.same(sample4, [['foo ', ' baz ', ''], ['bar', 'qux']], 'same open and close tags')
})

test('compile', function (t) {
  t.plan(4)

  var sample1 = parse('foo{{bar}}baz{{qux}}qix', '{{', '}}')
  var sample2 = parse('{{foo}}bar{{baz}}qux{{qix}}', '{{', '}}')
  var sample3 = parse('foo bar baz qux qix', '{{', '}}')

  t.is(compile(sample1, { bar: 'baaar', qux: 'quuux' }), 'foobaaarbazquuuxqix', 'inner expressions')
  t.is(compile(sample2, { foo: 'foooo', baz: 'baaaz', qix: 'qiiix' }), 'foooobarbaaazquxqiiix', 'outer expressions')
  t.is(compile(sample3, { dummy: 'data' }), 'foo bar baz qux qix', 'no expressions')
  t.is(compile(sample1, { bar: 'baaar' }), 'foobaaarbazundefinedqix', 'missing data')
})

function renderTest (render) {
  test('render', function (t) {
    t.plan(2)

    var sample1 = render('foo{{bar}}baz{{qux}}qix', { bar: 'hello', qux: 'world' }, '{{', '}}')
    var sample2 = render('<%foo%>bar<%baz%>qux<%qix%>', { foo: 'bar', baz: 'qux', qix: 'qaz' }, '<%', '%>')

    t.is(sample1, 'foohellobazworldqix', 'plain render')
    t.is(sample2, 'barbarquxquxqaz', 'custom tags')
  })
}

renderTest(render)
renderTest(renderOG)
<|endoftext|>


<commit_before>function getBoundsByElement(el) {
  const thumbAreaRect = el.getBoundingClientRect();
  return {
    x: thumbAreaRect.left,
    y: thumbAreaRect.top,
    w: thumbAreaRect.width
  };
}

function getCroppedBoundsByElement(el, imageWidth, imageHeight) {
  const thumbAreaRect = el.getBoundingClientRect();

  // fill image into the area
  // (do they same as object-fit:cover does to retrieve coordinates)
  const hRatio = thumbAreaRect.width / imageWidth;
  const vRatio = thumbAreaRect.height / imageHeight;
  const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;

  const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;
  const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;

  // Coordinates of the image,
  // as if it was not cropped,
  // height is calculated automatically
  const bounds = {
    x: thumbAreaRect.left + offsetX,
    y: thumbAreaRect.top + offsetY,
    w: imageWidth * fillZoomLevel
  };

  // Coordinates of inner crop area
  // relative to the image
  bounds.innerRect = {
    w: thumbAreaRect.width,
    h: thumbAreaRect.height,
    x: offsetX,
    y: offsetY
  };

  return bounds;
}

/**
 * Get dimensions of thumbnail image
 * (click on which opens photoswipe or closes photoswipe to)
 *
 * @param {Integer} index
 * @param {Object} itemData
 * @param {PhotoSwipe} instance PhotoSwipe instance
 * @returns Object|undefined
 */
export function getThumbBounds(index, itemData, instance) {
  // legacy event, before filters were introduced
  const event = instance.dispatch('thumbBounds', {
    index,
    itemData,
    instance
  });
  if (event.thumbBounds) {
    return event.thumbBounds;
  }

  const { element } = itemData;
  let thumbBounds;

  if (element && instance.options.thumbSelector !== false) {
    const thumbSelector = instance.options.thumbSelector || 'img';
    const thumbnail = element.matches(thumbSelector)
      ? element : element.querySelector(thumbSelector);

    if (thumbnail) {
      if (!itemData.thumbCropped) {
        thumbBounds = getBoundsByElement(thumbnail);
      } else {
        thumbBounds = getCroppedBoundsByElement(
          thumbnail,
          itemData.w,
          itemData.h
        );
      }
    }
  }

  return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);
}
<commit_msg>Add thumbEl filter<commit_after>function getBoundsByElement(el) {
  const thumbAreaRect = el.getBoundingClientRect();
  return {
    x: thumbAreaRect.left,
    y: thumbAreaRect.top,
    w: thumbAreaRect.width
  };
}

function getCroppedBoundsByElement(el, imageWidth, imageHeight) {
  const thumbAreaRect = el.getBoundingClientRect();

  // fill image into the area
  // (do they same as object-fit:cover does to retrieve coordinates)
  const hRatio = thumbAreaRect.width / imageWidth;
  const vRatio = thumbAreaRect.height / imageHeight;
  const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;

  const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;
  const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;

  // Coordinates of the image,
  // as if it was not cropped,
  // height is calculated automatically
  const bounds = {
    x: thumbAreaRect.left + offsetX,
    y: thumbAreaRect.top + offsetY,
    w: imageWidth * fillZoomLevel
  };

  // Coordinates of inner crop area
  // relative to the image
  bounds.innerRect = {
    w: thumbAreaRect.width,
    h: thumbAreaRect.height,
    x: offsetX,
    y: offsetY
  };

  return bounds;
}

/**
 * Get dimensions of thumbnail image
 * (click on which opens photoswipe or closes photoswipe to)
 *
 * @param {Integer} index
 * @param {Object} itemData
 * @param {PhotoSwipe} instance PhotoSwipe instance
 * @returns Object|undefined
 */
export function getThumbBounds(index, itemData, instance) {
  // legacy event, before filters were introduced
  const event = instance.dispatch('thumbBounds', {
    index,
    itemData,
    instance
  });
  if (event.thumbBounds) {
    return event.thumbBounds;
  }

  const { element } = itemData;
  let thumbBounds;
  let thumbnail;

  if (element && instance.options.thumbSelector !== false) {
    const thumbSelector = instance.options.thumbSelector || 'img';
    thumbnail = element.matches(thumbSelector)
      ? element : element.querySelector(thumbSelector);
  }

  thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);

  if (thumbnail) {
    if (!itemData.thumbCropped) {
      thumbBounds = getBoundsByElement(thumbnail);
    } else {
      thumbBounds = getCroppedBoundsByElement(
        thumbnail,
        itemData.w,
        itemData.h
      );
    }
  }

  return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);
}
<|endoftext|>


<commit_before>import {EventEmitter} from "events";
import lazy from "lazy.js";

import AppDispatcher from "../AppDispatcher";
import DeploymentEvents from "../events/DeploymentEvents";
import deploymentScheme from "./schemes/deploymentScheme";

function processDeployments(deployments) {
  return lazy(deployments).map(function (deployment) {
    deployment = lazy(deploymentScheme).extend(deployment).value();

    deployment.affectedAppsString = deployment.affectedApps.join(", ");
    deployment.currentActionsString = deployment.currentActions.join(", ");

    return deployment;
  }).value();
}

function removeDeployment(deployments, deploymentId) {
  return lazy(deployments).reject({
    id: deploymentId
  }).value();
}

var DeploymentStore = lazy(EventEmitter.prototype).extend({
  deployments: []
}).value();

AppDispatcher.register(function (action) {
  switch (action.actionType) {
    case DeploymentEvents.REQUEST:
      DeploymentStore.deployments = processDeployments(action.data.body);
      DeploymentStore.emit(DeploymentEvents.CHANGE);
      break;
    case DeploymentEvents.REQUEST_ERROR:
      DeploymentStore.emit(
        DeploymentEvents.REQUEST_ERROR,
        action.data.body,
        action.data.status
      );
      break;
    case DeploymentEvents.REVERT:
      DeploymentStore.deployments =
        removeDeployment(DeploymentStore.deployments, action.deploymentId);
      DeploymentStore.emit(DeploymentEvents.CHANGE);
      break;
    case DeploymentEvents.REVERT_ERROR:
      DeploymentStore.emit(
        DeploymentEvents.REVERT_ERROR,
        action.data.body,
        action.data.status
      );
      break;
    case DeploymentEvents.STOP:
      DeploymentStore.deployments =
        removeDeployment(DeploymentStore.deployments, action.deploymentId);
      DeploymentStore.emit(DeploymentEvents.CHANGE);
      break;
    case DeploymentEvents.STOP_ERROR:
      DeploymentStore.emit(
        DeploymentEvents.STOP_ERROR,
        action.data.body,
        action.data.status
      );
      break;
  }
});

export default DeploymentStore;
<commit_msg>Get rid of lazy.js in DeploymentStore<commit_after>import {EventEmitter} from "events";

import AppDispatcher from "../AppDispatcher";
import DeploymentEvents from "../events/DeploymentEvents";
import deploymentScheme from "./schemes/deploymentScheme";

import Util from "../helpers/Util";

function processDeployments(deployments) {
  return deployments.map(function (deployment) {
    deployment = Util.extendObject(deploymentScheme, deployment);

    deployment.affectedAppsString = deployment.affectedApps.join(", ");
    deployment.currentActionsString = deployment.currentActions.join(", ");

    return deployment;
  });
}

function removeDeployment(deployments, deploymentId) {
  return deployments.filter(deployment => deployment.id !== deploymentId);
}

var DeploymentStore = Util.extendObject(EventEmitter.prototype, {
  deployments: []
});

AppDispatcher.register(function (action) {
  switch (action.actionType) {
    case DeploymentEvents.REQUEST:
      DeploymentStore.deployments = processDeployments(action.data.body);
      DeploymentStore.emit(DeploymentEvents.CHANGE);
      break;
    case DeploymentEvents.REQUEST_ERROR:
      DeploymentStore.emit(
        DeploymentEvents.REQUEST_ERROR,
        action.data.body,
        action.data.status
      );
      break;
    case DeploymentEvents.REVERT:
      DeploymentStore.deployments =
        removeDeployment(DeploymentStore.deployments, action.deploymentId);
      DeploymentStore.emit(DeploymentEvents.CHANGE);
      break;
    case DeploymentEvents.REVERT_ERROR:
      DeploymentStore.emit(
        DeploymentEvents.REVERT_ERROR,
        action.data.body,
        action.data.status
      );
      break;
    case DeploymentEvents.STOP:
      DeploymentStore.deployments =
        removeDeployment(DeploymentStore.deployments, action.deploymentId);
      DeploymentStore.emit(DeploymentEvents.CHANGE);
      break;
    case DeploymentEvents.STOP_ERROR:
      DeploymentStore.emit(
        DeploymentEvents.STOP_ERROR,
        action.data.body,
        action.data.status
      );
      break;
  }
});

export default DeploymentStore;
<|endoftext|>