<commit_before>var taaspace = require('../index')

module.exports = function (test) {
  test('cannot have parent', function (t) {
    var sp1 = new taaspace.Space()
    var sp2 = new taaspace.Space()

    t.throws(function () {
      sp2.setParent(sp1)
    }, /parent/, 'space cannot be parent of another space')

    t.notOk(sp1.hasChild(sp2))

    t.doesNotThrow(function () {
      sp2.remove()
    }, 'cannot be removed from any parent')

    t.end()
  })

  test('#getHull', function (t) {
    var sp = new taaspace.Space()
    t.equal(sp.getHull(), null, 'null hull')

    var px = new taaspace.SpacePixel(sp)
    console.log(sp.getHull(), px.getHull())
    t.notEqual(sp.getHull(), null, 'space hull not null')
    t.ok(sp.getHull().equals(px.getHull()), 'hulls are equal')

    t.end()
  })
}
<commit_msg>Remove debug message<commit_after>var taaspace = require('../index')

module.exports = function (test) {
  test('cannot have parent', function (t) {
    var sp1 = new taaspace.Space()
    var sp2 = new taaspace.Space()

    t.throws(function () {
      sp2.setParent(sp1)
    }, /parent/, 'space cannot be parent of another space')

    t.notOk(sp1.hasChild(sp2))

    t.doesNotThrow(function () {
      sp2.remove()
    }, 'cannot be removed from any parent')

    t.end()
  })

  test('#getHull', function (t) {
    var sp = new taaspace.Space()
    t.equal(sp.getHull(), null, 'null hull')

    var px = new taaspace.SpacePixel(sp)

    t.notEqual(sp.getHull(), null, 'space hull not null')
    t.ok(sp.getHull().equals(px.getHull()), 'hulls are equal')

    t.end()
  })
}
<|endoftext|>


<commit_before>// use a minimal 100 line test framework. We do not want this
// file to exit prematurely. both `tape` & `mocha` do process.exit()
var test = require('assert-tap').test
var Readable = require('readable-stream').Readable
var getRawBody = require('../')

// this test is about infinite streams. If this file never terminates
// then its a bug because rawBody with limit's set should not
// allow a process to hang.
// if any of the streams we create are left in flowing mode
// then the script never ends & its a failing test.

function createChunk() {
  var base = Math.random().toString(32)
  var KB_4 = 32 * 4
  var KB_8 = KB_4 * 2
  var KB_16 = KB_8 * 2
  var KB_64 = KB_16 * 4

  var rand = Math.random()
  if (rand < 0.25) {
    return repeat(base, KB_4)
  } else if (rand < 0.5) {
    return repeat(base, KB_8)
  } else if (rand < 0.75) {
    return repeat(base, KB_16)
  } else {
    return repeat(base, KB_64)
  }

  function repeat(str, num) {
    return new Array(num + 1).join(str)
  }
}

function createInfiniteStream() {
  var stream = new Readable()
  stream._read = function () {
    var rand = Math.floor(Math.random() * 10)

    process.nextTick(function () {
      for (var i = 0; i < rand; i++) {
        stream.push(createChunk())
      }
    })
  }

  // immediately put the stream in flowing mode
  stream.resume()

  return stream
}

var defaultLimit = 1024 * 1024

// assert is just the normal node assert & assert.end() is like done() in mocha
test('a stream with a limit lower then length', function (assert) {
  var stream = createInfiniteStream()

  getRawBody(stream, {
    limit: defaultLimit,
    length: defaultLimit * 2
  }, function (err, body) {
    assert.ok(err)
    assert.equal(err.type, 'entity.too.large')
    assert.equal(err.message, 'request entity too large')
    assert.equal(err.statusCode, 413)
    assert.equal(err.length, defaultLimit * 2)
    assert.equal(err.limit, defaultLimit)
    assert.equal(body, undefined)

    assert.end()
  })
})

test('a stream with an encoding', function (assert) {
  var stream = createInfiniteStream()
  stream.setEncoding('utf8')

  getRawBody(stream, {
    limit: defaultLimit
  }, function (err, body) {
    assert.ok(err)
    assert.equal(err.type, 'stream.encoding.set')
    assert.equal(err.message, 'stream encoding should not be set')
    assert.equal(err.statusCode, 500)

    assert.end()
  })
})
<commit_msg>acceptance test for stream with limit<commit_after>// use a minimal 100 line test framework. We do not want this
// file to exit prematurely. both `tape` & `mocha` do process.exit()
var test = require('assert-tap').test
var Readable = require('readable-stream').Readable
var getRawBody = require('../')

// this test is about infinite streams. If this file never terminates
// then its a bug because rawBody with limit's set should not
// allow a process to hang.
// if any of the streams we create are left in flowing mode
// then the script never ends & its a failing test.

function createChunk() {
  var base = Math.random().toString(32)
  var KB_4 = 32 * 4
  var KB_8 = KB_4 * 2
  var KB_16 = KB_8 * 2
  var KB_64 = KB_16 * 4

  var rand = Math.random()
  if (rand < 0.25) {
    return repeat(base, KB_4)
  } else if (rand < 0.5) {
    return repeat(base, KB_8)
  } else if (rand < 0.75) {
    return repeat(base, KB_16)
  } else {
    return repeat(base, KB_64)
  }

  function repeat(str, num) {
    return new Array(num + 1).join(str)
  }
}

function createInfiniteStream() {
  var stream = new Readable()
  stream._read = function () {
    var rand = 2 + Math.floor(Math.random() * 10)

    process.nextTick(function () {
      for (var i = 0; i < rand; i++) {
        stream.push(createChunk())
      }
    })
  }

  // immediately put the stream in flowing mode
  stream.resume()

  return stream
}

var defaultLimit = 1024 * 1024

// assert is just the normal node assert & assert.end() is like done() in mocha
test('a stream with a limit lower then length', function (assert) {
  var stream = createInfiniteStream()

  getRawBody(stream, {
    limit: defaultLimit,
    length: defaultLimit * 2
  }, function (err, body) {
    assert.ok(err)
    assert.equal(err.type, 'entity.too.large')
    assert.equal(err.message, 'request entity too large')
    assert.equal(err.statusCode, 413)
    assert.equal(err.length, defaultLimit * 2)
    assert.equal(err.limit, defaultLimit)
    assert.equal(body, undefined)

    assert.end()
  })
})

test('a stream with an encoding', function (assert) {
  var stream = createInfiniteStream()
  stream.setEncoding('utf8')

  getRawBody(stream, {
    limit: defaultLimit
  }, function (err, body) {
    assert.ok(err)
    assert.equal(err.type, 'stream.encoding.set')
    assert.equal(err.message, 'stream encoding should not be set')
    assert.equal(err.statusCode, 500)

    assert.end()
  })
})

test('a stream with a limit', function (assert) {
  var stream = createInfiniteStream()

  getRawBody(stream, {
    limit: defaultLimit
  }, function (err, body) {
    assert.ok(err)
    assert.equal(err.type, 'entity.too.large')
    assert.equal(err.statusCode, 413)
    assert.ok(err.received > defaultLimit)
    assert.equal(err.limit, defaultLimit)

    assert.end()
  })
})
<|endoftext|>


<commit_before>"use strict";

describe("attributes", function () {

    var baseContent = {
            $extend: "gpf.attributes.Attribute",
            _value: undefined,
            getValue: function () {
                return this._value;
            },
            constructor: function (value) {
                this._value = value;
            }
        },

        MyAttribute1 = gpf.define(Object.assign({
            $class: "MyAttribute1"
        }, baseContent)),

        MyAttribute2 = gpf.define(Object.assign({
            $class: "MyAttribute2"
        }, baseContent)),

        MyClassWithoutAttributes = gpf.define({
            $class: "MyClassWithoutAttributes"
        }),

        MyClass = gpf.define({
            $class: "MyClass",
            $attributes: [new MyAttribute1("A"), new MyAttribute1("B"), new MyAttribute2("C")],
            "[value]": [new MyAttribute1("D")],
            value: 0
        }),

        MySubClass = gpf.define({
            $class: "MyClass",
            $extend: MyClass,
            $attributes: [new MyAttribute1("E"), new MyAttribute2("F")],
            "[value]": [new MyAttribute2("G")],
            "[value2]": [new MyAttribute1("H")],
            value2: 1
        });

    describe("gpf.attributes.get", function () {

        it("returns an empty object if the class was not allocated by gpf.define", function () {
            var attributes = gpf.attributes.get(String);
            assert(Object.keys(attributes).length === 0);
        });

        it("returns an empty object if no attributes", function () {
            var attributes = gpf.attributes.get(MyClassWithoutAttributes);
            assert(Object.keys(attributes).length === 0);
        });

        it("retrieves all attributes (on class)", function () {
            var attributes = gpf.attributes.get(MyClass);
            assert(Object.keys(attributes).length === 2);
            assert(attributes.$attributes.length === 3);
            assert(attributes.value.length === 1);
            assert(attributes.value[0].getValue() === "D");
        });

        it("retrieves all attributes (on instance)", function () {
            var myObject = new MyClass(),
                attributes = gpf.attributes.get(myObject);
            assert(Object.keys(attributes).length === 2);
            assert(attributes.$attributes.length === 3);
            assert(attributes.value.length === 1);
            assert(attributes.value[0].getValue() === "D");
        });

        it("filters on a given attribute class", function () {
            var attributes = gpf.attributes.get(MyClass, MyAttribute2);
            assert(Object.keys(attributes).length === 1);
            assert(attributes.$attributes.length === 1);
            assert(attributes.$attributes[0].getValue() === "C");
        });

        describe("with inheritance", function () {

            it("retrieves all attributes (on class)", function () {
                var attributes = gpf.attributes.get(MySubClass);
                assert(Object.keys(attributes).length === 3);
                assert(attributes.$attributes.length === 5);
                assert(attributes.value.length === 2);
                assert(attributes.value2[0].getValue() === "H");
            });

            it("filters on a given attribute class", function () {
                var attributes = gpf.attributes.get(MySubClass, MyAttribute1);
                assert(Object.keys(attributes).length === 3);
                assert(attributes.$attributes.length === 3);
                assert(attributes.value2[0].getValue() === "H");
            });

        });

    });

});
<commit_msg>Working on native inheritance (#230)<commit_after>"use strict";

describe("attributes", function () {

    var baseAttributeContent = {
            $extend: "gpf.attributes.Attribute",
            _value: undefined,
            getValue: function () {
                return this._value;
            },
            constructor: function (value) {
                this._value = value;
            }
        },

        MyAttribute1 = gpf.define(Object.assign({
            $class: "MyAttribute1"
        }, baseAttributeContent)),

        MyAttribute2 = gpf.define(Object.assign({
            $class: "MyAttribute2"
        }, baseAttributeContent)),

        MyClassWithoutAttributes = gpf.define({
            $class: "MyClassWithoutAttributes"
        }),

        MyClass = gpf.define({
            $class: "MyClass",
            $attributes: [new MyAttribute1("A"), new MyAttribute1("B"), new MyAttribute2("C")],
            "[value]": [new MyAttribute1("D")],
            value: 0
        }),

        MySubClass = gpf.define({
            $class: "MyClass",
            $extend: MyClass,
            $attributes: [new MyAttribute1("E"), new MyAttribute2("F")],
            "[value]": [new MyAttribute2("G")],
            "[value2]": [new MyAttribute1("H")],
            value2: 1
        });

        // MySubNativeClass = gpf.define({
        //     $class: "MyClass",
        //     $extend: MyNativeSubClass,
        //     $attributes: [new MyAttribute1("E"), new MyAttribute2("F")],
        //     "[value]": [new MyAttribute2("G")],
        //     "[value2]": [new MyAttribute1("H")],
        //     value2: 1
        // })

    function MyNativeSubClass () {
        MyClass.apply(this, arguments);
    }

    MyNativeSubClass.prototype = Object.create(MyClass.prototype);

    describe("gpf.attributes.get", function () {

        it("returns an empty object if the class was not allocated by gpf.define", function () {
            var attributes = gpf.attributes.get(String);
            assert(Object.keys(attributes).length === 0);
        });

        it("returns an empty object if no attributes", function () {
            var attributes = gpf.attributes.get(MyClassWithoutAttributes);
            assert(Object.keys(attributes).length === 0);
        });

        it("retrieves all attributes (on class)", function () {
            var attributes = gpf.attributes.get(MyClass);
            assert(Object.keys(attributes).length === 2);
            assert(attributes.$attributes.length === 3);
            assert(attributes.value.length === 1);
            assert(attributes.value[0].getValue() === "D");
        });

        it("retrieves all attributes (on instance)", function () {
            var myObject = new MyClass(),
                attributes = gpf.attributes.get(myObject);
            assert(Object.keys(attributes).length === 2);
            assert(attributes.$attributes.length === 3);
            assert(attributes.value.length === 1);
            assert(attributes.value[0].getValue() === "D");
        });

        it("filters on a given attribute class", function () {
            var attributes = gpf.attributes.get(MyClass, MyAttribute2);
            assert(Object.keys(attributes).length === 1);
            assert(attributes.$attributes.length === 1);
            assert(attributes.$attributes[0].getValue() === "C");
        });

        function _testGPFInheritance (resultClass) {

            it("retrieves all attributes (on class)", function () {
                var attributes = gpf.attributes.get(resultClass);
                assert(Object.keys(attributes).length === 3);
                assert(attributes.$attributes.length === 5);
                assert(attributes.value.length === 2);
                assert(attributes.value2[0].getValue() === "H");
            });

            it("filters on a given attribute class", function () {
                var attributes = gpf.attributes.get(resultClass, MyAttribute1);
                assert(Object.keys(attributes).length === 3);
                assert(attributes.$attributes.length === 3);
                assert(attributes.value2[0].getValue() === "H");
            });
        }

        describe("with native inheritance", function () {

            it("retrieves all attributes (on class)", function () {
                var attributes = gpf.attributes.get(MyNativeSubClass);
                assert(Object.keys(attributes).length === 2);
                assert(attributes.$attributes.length === 3);
                assert(attributes.value.length === 1);
                assert(attributes.value[0].getValue() === "D");
            });

            // describe("and then with GPF inheritance", function () {
            //     _testGPFInheritance(MySubNativeClass);
            // });

        });

        describe("with GPF inheritance", function () {
            _testGPFInheritance(MySubClass);
        });

    });

});
<|endoftext|>


<commit_before>(function (Q, $) {
/**
 * @module Q-tools
 */

/**
 * Implements lazy-loading for various types of elements.
 * By default, has implementations for "img" and "Q_tool" selectors.
 * The "Q_tool" handler only works with tools whose elements have a "data-q-lazyload" attribute .
 * Note that the elements must have a stable, nonzero width height set in the CSS even
 * if they are empty, otherwise they might not be lazy-loaded, and they might
 * thrash back and forth if removed.
 * @class Q lazyload
 * @constructor
 * @param {Object} [options] Override various options for this tool
 * @param {Array} [options.handle] Set this to
 * @param {Object} [options.handlers] You can modify the defaults by passing an object
 *    that looks like {handlerName: { selector: String, entering: Function, exiting: Function, preparing: Function}}
 *    Function "entering" receives (element, intersectionObserverEntry)
 *    Function "exiting" receives (element, intersectionObserverEntry)
 *    Function "preparing" receives (element) and is used the first time to prepare the element
 *    Both functions must return true if the element was modified.
 * @param {Object} [observerOptions] Override any options to pass to IntersectionObserver
 * @return {Q.Tool}
 */
Q.Tool.define('Q/lazyload', function (options) {

	var tool = this;
	var state = this.state;

	var Elp = Element.prototype;

	if (!window.IntersectionObserver) {
		console.warn("Q/lazyload tool: need to use IntersectionObserver polyfill");
		return; // do nothing, this is an older browser
	}

	// Observe whatever is on the page already
	tool.observer = _createObserver(tool, tool.element);
	tool.observe(tool.prepare(tool.element, false));

	// Override innerHTML

	var originalSet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').set;
	var originalGet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').get;

	Object.defineProperty(Elp, 'innerHTML', {
		set: function (html) {
			var element = document.createElement('div');
			originalSet.call(element, html);
			var found = false;
			Q.each(state.handlers, function (name, info) {
				var elements = element.querySelectorAll
					? Array.from(element.querySelectorAll(info.selector))
					: [];
				if (elements.length) {
					found = true;
					return false;
				}
			});
			if (found) {
				html = originalGet.call(element);
			}
			originalSet.call(this, html);
			if (found) {
				tool.observe(tool.prepare(this, true));
			}
			return html;
		},
		get: originalGet
	});

	Q.each(['insertBefore', 'appendChild'], function (i, fn) {
		var orig = Elp[fn];
		Elp[fn] = function (element) {
			if (!element) {
				return;
			}
			tool.observe(tool.prepare(element, true));
			return orig.apply(this, arguments);
		};
	});

},

{
	root: null,
	handlers: {
		img: {
			selector: 'img',
			entering: function (img, entry) {
				function _loaded() {
					img.addClass('Q_lazy_loaded');
				}
				var src = img.getAttribute('data-lazyload-src');
				if (src) {
					img.setAttribute('src', Q.url(src));
					img.removeAttribute('data-lazyload-src');
					img.addClass('Q_lazy_load');
					if (img.complete) {
						_loaded();
					}
					img.addEventListener('load', _loaded);
				}
				return true;
			},
			exiting: function (img) {
				// no need to do anything
				return true;
			},
			preparing: function (img, beingInsertedIntoDOM) {
				if (!beingInsertedIntoDOM) {
					return true; // too late anyway, browser will load image
				}
				var src = img.getAttribute('src');
				if (src && src.substr(0, 5) !== 'data:'
				&& !img.hasAttribute('data-lazyload-src')) {
					img.setAttribute('data-lazyload-src', Q.url(src));
					img.setAttribute('src', Q.url(
						Q.getObject('Q.images.lazyload.loadingSrc')
						|| "{{Q}}/img/throbbers/transparent.gif"
					));
				}
				return true;
			}
		},
		tool: {
			selector: '.Q_tool',
			entering: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& (!element.Q || !element.Q.tool)) {
					element.addClass('Q_lazy_load');
					element.setAttribute('data-q-lazyload', 'activating');
					Q.activate(element, function () {
						element.setAttribute('data-q-lazyload', 'activated');
						element.addClass('Q_lazy_loaded');
					}, {}, true);
					return true;
				}
			},
			exiting: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& element.Q.tool) {
					Q.Tool.remove(element);
					element.removeClass('Q_lazy_loading');
					element.removeClass('Q_lazy_loaded');
					element.setAttribute('data-q-lazyload', 'removed');
					if (this.state.handlers.tool.exitingRemoveHTML) {
						element.innerHTML = '';
					}
				}
				return true;
			},
			preparing: function (element) {
				return true;
			},
			exitingRemoveHTML: true
		}
	},
	observerOptions: {
		root: null,
		rootMargin: '0px',
		threshold: 0
	}
},

{
	prepare: function (container, beingInsertedIntoDOM) {
		var tool = this;
		var found = [];
		Q.each(tool.state.handlers, function (name, info) {
			var elements = container.querySelectorAll
				? Array.from(container.querySelectorAll(info.selector))
				: [];
			if (container.matches && container.matches(info.selector)) {
				elements.push(container);
			}
			Q.each(elements, function (i, element) {
				if (info.preparing.call(tool, element, beingInsertedIntoDOM) === true) {
					found.push(element);
				}
			});
		});
		return found;
	},
	observe: function (elements) {
		var tool = this;
		Q.each(elements, function (i, element) {
			tool.observer.observe(element);
		});
	}
});

function _createObserver(tool, container) {
	return new IntersectionObserver(function (entries, observer) {
		Q.each(entries, function (i, entry) {
			Q.each(tool.state.handlers, function (name, info) {
				if (entry.target.matches && entry.target.matches(info.selector)) {
					if (entry.isIntersecting) {
						info.entering.call(tool, entry.target, entry);
					} else  {
						var rect = entry.target.getBoundingClientRect();
						if (rect.width > 0 && rect.height > 0) {
							// also covers !document.body.contains(entry.target)
							info.exiting.call(tool, entry.target, entry);
						} // otherwise it might get a false positive
					}
				}
			});
		});
	}, tool.state.observerOptions);
}

function _polyfill() {
	// Exit early if all IntersectionObserver and IntersectionObserverEntry
	// features are natively supported.
	if ('IntersectionObserver' in window &&
	    'IntersectionObserverEntry' in window &&
	    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {

	  // Minimal polyfill for Edge 15's lack of `isIntersecting`
	  // See: https://github.com/w3c/IntersectionObserver/issues/211
	  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
	    Object.defineProperty(window.IntersectionObserverEntry.prototype,
	      'isIntersecting', {
	      get: function () {
	        return this.intersectionRatio > 0;
	      }
	    });
	  }
	  return;
	}
	Q.addScript('{{Q}}/js/polyfills/IntersectionObserver.js');
}

_polyfill();

})(Q, jQuery);<commit_msg>Updated lazyload to load polyfill if necessary<commit_after>(function (Q, $) {
/**
 * @module Q-tools
 */

/**
 * Implements lazy-loading for various types of elements.
 * By default, has implementations for "img" and "Q_tool" selectors.
 * The "Q_tool" handler only works with tools whose elements have a "data-q-lazyload" attribute .
 * Note that the elements must have a stable, nonzero width height set in the CSS even
 * if they are empty, otherwise they might not be lazy-loaded, and they might
 * thrash back and forth if removed.
 * @class Q lazyload
 * @constructor
 * @param {Object} [options] Override various options for this tool
 * @param {Array} [options.handle] Set this to
 * @param {Object} [options.handlers] You can modify the defaults by passing an object
 *    that looks like {handlerName: { selector: String, entering: Function, exiting: Function, preparing: Function}}
 *    Function "entering" receives (element, intersectionObserverEntry)
 *    Function "exiting" receives (element, intersectionObserverEntry)
 *    Function "preparing" receives (element) and is used the first time to prepare the element
 *    Both functions must return true if the element was modified.
 * @param {Object} [observerOptions] Override any options to pass to IntersectionObserver
 * @return {Q.Tool}
 */
Q.Tool.define('Q/lazyload', function (options) {

	var tool = this;
	var state = this.state;

	var Elp = Element.prototype;

	Q.ensure(window.IntersectionObserver, _polyfill, function () {
		// Observe whatever is on the page already
		tool.observer = _createObserver(tool, tool.element);
		tool.observe(tool.prepare(tool.element, false));

		// Override innerHTML

		var originalSet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').set;
		var originalGet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').get;

		Object.defineProperty(Elp, 'innerHTML', {
			set: function (html) {
				var element = document.createElement('div');
				originalSet.call(element, html);
				var found = false;
				Q.each(state.handlers, function (name, info) {
					var elements = element.querySelectorAll
						? Array.from(element.querySelectorAll(info.selector))
						: [];
					if (elements.length) {
						found = true;
						return false;
					}
				});
				if (found) {
					html = originalGet.call(element);
				}
				originalSet.call(this, html);
				if (found) {
					tool.observe(tool.prepare(this, true));
				}
				return html;
			},
			get: originalGet
		});

		Q.each(['insertBefore', 'appendChild'], function (i, fn) {
			var orig = Elp[fn];
			Elp[fn] = function (element) {
				if (!element) {
					return;
				}
				tool.observe(tool.prepare(element, true));
				return orig.apply(this, arguments);
			};
		});
	});

},

{
	root: null,
	handlers: {
		img: {
			selector: 'img',
			entering: function (img, entry) {
				function _loaded() {
					img.addClass('Q_lazy_loaded');
				}
				var src = img.getAttribute('data-lazyload-src');
				if (src) {
					img.setAttribute('src', Q.url(src));
					img.removeAttribute('data-lazyload-src');
					img.addClass('Q_lazy_load');
					if (img.complete) {
						_loaded();
					}
					img.addEventListener('load', _loaded);
				}
				return true;
			},
			exiting: function (img) {
				// no need to do anything
				return true;
			},
			preparing: function (img, beingInsertedIntoDOM) {
				if (!beingInsertedIntoDOM) {
					return true; // too late anyway, browser will load image
				}
				var src = img.getAttribute('src');
				if (src && src.substr(0, 5) !== 'data:'
				&& !img.hasAttribute('data-lazyload-src')) {
					img.setAttribute('data-lazyload-src', Q.url(src));
					img.setAttribute('src', Q.url(
						Q.getObject('Q.images.lazyload.loadingSrc')
						|| "{{Q}}/img/throbbers/transparent.gif"
					));
				}
				return true;
			}
		},
		tool: {
			selector: '.Q_tool',
			entering: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& (!element.Q || !element.Q.tool)) {
					element.addClass('Q_lazy_load');
					element.setAttribute('data-q-lazyload', 'activating');
					Q.activate(element, function () {
						element.setAttribute('data-q-lazyload', 'activated');
						element.addClass('Q_lazy_loaded');
					}, {}, true);
					return true;
				}
			},
			exiting: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& element.Q.tool) {
					Q.Tool.remove(element);
					element.removeClass('Q_lazy_loading');
					element.removeClass('Q_lazy_loaded');
					element.setAttribute('data-q-lazyload', 'removed');
					if (this.state.handlers.tool.exitingRemoveHTML) {
						element.innerHTML = '';
					}
				}
				return true;
			},
			preparing: function (element) {
				return true;
			},
			exitingRemoveHTML: true
		}
	},
	observerOptions: {
		root: null,
		rootMargin: '0px',
		threshold: 0
	}
},

{
	prepare: function (container, beingInsertedIntoDOM) {
		var tool = this;
		var found = [];
		Q.each(tool.state.handlers, function (name, info) {
			var elements = container.querySelectorAll
				? Array.from(container.querySelectorAll(info.selector))
				: [];
			if (container.matches && container.matches(info.selector)) {
				elements.push(container);
			}
			Q.each(elements, function (i, element) {
				if (info.preparing.call(tool, element, beingInsertedIntoDOM) === true) {
					found.push(element);
				}
			});
		});
		return found;
	},
	observe: function (elements) {
		var tool = this;
		Q.each(elements, function (i, element) {
			tool.observer.observe(element);
		});
	}
});

function _createObserver(tool, container) {
	return new IntersectionObserver(function (entries, observer) {
		Q.each(entries, function (i, entry) {
			Q.each(tool.state.handlers, function (name, info) {
				if (entry.target.matches && entry.target.matches(info.selector)) {
					if (entry.isIntersecting) {
						info.entering.call(tool, entry.target, entry);
					} else  {
						var rect = entry.target.getBoundingClientRect();
						if (rect.width > 0 && rect.height > 0) {
							// also covers !document.body.contains(entry.target)
							info.exiting.call(tool, entry.target, entry);
						} // otherwise it might get a false positive
					}
				}
			});
		});
	}, tool.state.observerOptions);
}

function _polyfill(callback) {
	// Exit early if all IntersectionObserver and IntersectionObserverEntry
	// features are natively supported.
	if ('IntersectionObserver' in window &&
	    'IntersectionObserverEntry' in window &&
	    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {

	  // Minimal polyfill for Edge 15's lack of `isIntersecting`
	  // See: https://github.com/w3c/IntersectionObserver/issues/211
	  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
	    Object.defineProperty(window.IntersectionObserverEntry.prototype,
	      'isIntersecting', {
	      get: function () {
	        return this.intersectionRatio > 0;
	      }
	    });
	  }
	  return Q.handle(callback);
	}
	Q.addScript('{{Q}}/js/polyfills/IntersectionObserver.js', callback);
}

_polyfill();

})(Q, jQuery);<|endoftext|>


<commit_before>import test from 'ava'
import { resolve } from 'path'
import rp from 'request-promise-native'
import stdMocks from 'std-mocks'
import { Nuxt, Builder } from '../index.js'

const port = 4003
const url = (route) => 'http://localhost:' + port + route

let nuxt = null

// Init nuxt.js and create server listening on localhost:4000
test.before('Init Nuxt.js', async t => {
  const options = {
    rootDir: resolve(__dirname, 'fixtures/basic'),
    dev: false
  }
  nuxt = new Nuxt(options)
  await new Builder(nuxt).build()

  await nuxt.listen(port, 'localhost')
})

test('/stateless', async t => {
  const { html } = await nuxt.renderRoute('/stateless')
  t.true(html.includes('
My component!
'))
})

/*
** Example of testing via dom checking
*/
test('/css', async t => {
  const window = await nuxt.renderAndGetWindow(url('/css'))
  const element = window.document.querySelector('.red')
  t.not(element, null)
  t.is(element.textContent, 'This is red')
  t.is(element.className, 'red')
  t.is(window.getComputedStyle(element).color, 'red')
})

test('/stateful', async t => {
  const { html } = await nuxt.renderRoute('/stateful')
  t.true(html.includes('

The answer is 42

'))
})

test('/store', async t => {
  const { html } = await nuxt.renderRoute('/store')
  t.true(html.includes('
Vuex Nested Modules
'))
  t.true(html.includes('
1
'))
})

test('/head', async t => {
  const window = await nuxt.renderAndGetWindow(url('/head'), { virtualConsole: false })
  const html = window.document.body.innerHTML
  const metas = window.document.getElementsByTagName('meta')
  t.is(window.document.title, 'My title')
  t.is(metas[0].getAttribute('content'), 'my meta')
  t.true(html.includes('

I can haz meta tags

'))
})

test('/async-data', async t => {
  const { html } = await nuxt.renderRoute('/async-data')
  t.true(html.includes('
Nuxt.js
'))
})

test('/await-async-data', async t => {
  const { html } = await nuxt.renderRoute('/await-async-data')
  t.true(html.includes('
Await Nuxt.js
'))
})

test('/callback-async-data', async t => {
  const { html } = await nuxt.renderRoute('/callback-async-data')
  t.true(html.includes('
Callback Nuxt.js
'))
})

test('/users/1', async t => {
  const { html } = await nuxt.renderRoute('/users/1')
  t.true(html.includes('
User: 1
'))
})

test('/validate should display a 404', async t => {
  const { html } = await nuxt.renderRoute('/validate')
  t.true(html.includes('This page could not be found'))
})

test('/validate?valid=true', async t => {
  const { html } = await nuxt.renderRoute('/validate?valid=true')
  t.true(html.includes('
I am valid
'))
})

test('/redirect', async t => {
  const { html, redirected } = await nuxt.renderRoute('/redirect')
  t.true(html.includes('

'))
  t.true(redirected.path === '/')
  t.true(redirected.status === 302)
})

test('/redirect -> check redirected source', async t => {
  const window = await nuxt.renderAndGetWindow(url('/redirect'))
  const html = window.document.body.innerHTML
  t.true(html.includes('
Index page
'))
})

test.only('/special-state -> check window.__NUXT__.test = true', async t => {
  const window = await nuxt.renderAndGetWindow(url('/special-state'))
  t.is(window.__NUXT__.test, true)
})

test('/error', async t => {
  try {
    await nuxt.renderRoute('/error', { req: {}, res: {} })
  } catch (err) {
    t.true(err.message.includes('Error mouahahah'))
  }
})

test('/error status code', async t => {
  try {
    await rp(url('/error'))
  } catch (err) {
    t.true(err.statusCode === 500)
    t.true(err.response.body.includes('Error mouahahah'))
  }
})

test('/error2', async t => {
  const { html, error } = await nuxt.renderRoute('/error2')
  t.true(html.includes('Custom error'))
  t.true(error.message.includes('Custom error'))
  t.true(error.statusCode === undefined)
})

test('/error2 status code', async t => {
  try {
    await rp(url('/error2'))
  } catch (err) {
    t.is(err.statusCode, 500)
    t.true(err.response.body.includes('Custom error'))
  }
})

test('/redirect2', async t => {
  stdMocks.use()
  await rp(url('/redirect2')) // Should console.error
  stdMocks.restore()
  const output = stdMocks.flush()
  // Don't display error since redirect returns a noopApp
  t.true(output.stderr.length === 0)
})

test('ETag Header', async t => {
  const { headers: { etag } } = await rp(url('/stateless'), { resolveWithFullResponse: true })
  // Validate etag
  t.regex(etag, /W\/".*"$/)
  // Verify functionality
  const error = await t.throws(rp(url('/stateless'), { headers: { 'If-None-Match': etag } }))
  t.is(error.statusCode, 304)
})

test('/_nuxt/server-bundle.json should return 404', async t => {
  const err = await t.throws(rp(url('/_nuxt/server-bundle.json'), { resolveWithFullResponse: true }))
  t.is(err.statusCode, 404)
})

test('/_nuxt/ should return 404', async t => {
  const err = await t.throws(rp(url('/_nuxt/'), { resolveWithFullResponse: true }))
  t.is(err.statusCode, 404)
})

// Close server and ask nuxt to stop listening to file changes
test.after('Closing server and nuxt.js', t => {
  nuxt.close()
})
<commit_msg>Remove only test<commit_after>import test from 'ava'
import { resolve } from 'path'
import rp from 'request-promise-native'
import stdMocks from 'std-mocks'
import { Nuxt, Builder } from '../index.js'

const port = 4003
const url = (route) => 'http://localhost:' + port + route

let nuxt = null

// Init nuxt.js and create server listening on localhost:4000
test.before('Init Nuxt.js', async t => {
  const options = {
    rootDir: resolve(__dirname, 'fixtures/basic'),
    dev: false
  }
  nuxt = new Nuxt(options)
  await new Builder(nuxt).build()

  await nuxt.listen(port, 'localhost')
})

test('/stateless', async t => {
  const { html } = await nuxt.renderRoute('/stateless')
  t.true(html.includes('
My component!
'))
})

/*
** Example of testing via dom checking
*/
test('/css', async t => {
  const window = await nuxt.renderAndGetWindow(url('/css'))
  const element = window.document.querySelector('.red')
  t.not(element, null)
  t.is(element.textContent, 'This is red')
  t.is(element.className, 'red')
  t.is(window.getComputedStyle(element).color, 'red')
})

test('/stateful', async t => {
  const { html } = await nuxt.renderRoute('/stateful')
  t.true(html.includes('

The answer is 42

'))
})

test('/store', async t => {
  const { html } = await nuxt.renderRoute('/store')
  t.true(html.includes('
Vuex Nested Modules
'))
  t.true(html.includes('
1
'))
})

test('/head', async t => {
  const window = await nuxt.renderAndGetWindow(url('/head'), { virtualConsole: false })
  const html = window.document.body.innerHTML
  const metas = window.document.getElementsByTagName('meta')
  t.is(window.document.title, 'My title')
  t.is(metas[0].getAttribute('content'), 'my meta')
  t.true(html.includes('

I can haz meta tags

'))
})

test('/async-data', async t => {
  const { html } = await nuxt.renderRoute('/async-data')
  t.true(html.includes('
Nuxt.js
'))
})

test('/await-async-data', async t => {
  const { html } = await nuxt.renderRoute('/await-async-data')
  t.true(html.includes('
Await Nuxt.js
'))
})

test('/callback-async-data', async t => {
  const { html } = await nuxt.renderRoute('/callback-async-data')
  t.true(html.includes('
Callback Nuxt.js
'))
})

test('/users/1', async t => {
  const { html } = await nuxt.renderRoute('/users/1')
  t.true(html.includes('
User: 1
'))
})

test('/validate should display a 404', async t => {
  const { html } = await nuxt.renderRoute('/validate')
  t.true(html.includes('This page could not be found'))
})

test('/validate?valid=true', async t => {
  const { html } = await nuxt.renderRoute('/validate?valid=true')
  t.true(html.includes('
I am valid
'))
})

test('/redirect', async t => {
  const { html, redirected } = await nuxt.renderRoute('/redirect')
  t.true(html.includes('

'))
  t.true(redirected.path === '/')
  t.true(redirected.status === 302)
})

test('/redirect -> check redirected source', async t => {
  const window = await nuxt.renderAndGetWindow(url('/redirect'))
  const html = window.document.body.innerHTML
  t.true(html.includes('
Index page
'))
})

test('/special-state -> check window.__NUXT__.test = true', async t => {
  const window = await nuxt.renderAndGetWindow(url('/special-state'))
  t.is(window.__NUXT__.test, true)
})

test('/error', async t => {
  try {
    await nuxt.renderRoute('/error', { req: {}, res: {} })
  } catch (err) {
    t.true(err.message.includes('Error mouahahah'))
  }
})

test('/error status code', async t => {
  try {
    await rp(url('/error'))
  } catch (err) {
    t.true(err.statusCode === 500)
    t.true(err.response.body.includes('Error mouahahah'))
  }
})

test('/error2', async t => {
  const { html, error } = await nuxt.renderRoute('/error2')
  t.true(html.includes('Custom error'))
  t.true(error.message.includes('Custom error'))
  t.true(error.statusCode === undefined)
})

test('/error2 status code', async t => {
  try {
    await rp(url('/error2'))
  } catch (err) {
    t.is(err.statusCode, 500)
    t.true(err.response.body.includes('Custom error'))
  }
})

test('/redirect2', async t => {
  stdMocks.use()
  await rp(url('/redirect2')) // Should console.error
  stdMocks.restore()
  const output = stdMocks.flush()
  // Don't display error since redirect returns a noopApp
  t.true(output.stderr.length === 0)
})

test('ETag Header', async t => {
  const { headers: { etag } } = await rp(url('/stateless'), { resolveWithFullResponse: true })
  // Validate etag
  t.regex(etag, /W\/".*"$/)
  // Verify functionality
  const error = await t.throws(rp(url('/stateless'), { headers: { 'If-None-Match': etag } }))
  t.is(error.statusCode, 304)
})

test('/_nuxt/server-bundle.json should return 404', async t => {
  const err = await t.throws(rp(url('/_nuxt/server-bundle.json'), { resolveWithFullResponse: true }))
  t.is(err.statusCode, 404)
})

test('/_nuxt/ should return 404', async t => {
  const err = await t.throws(rp(url('/_nuxt/'), { resolveWithFullResponse: true }))
  t.is(err.statusCode, 404)
})

// Close server and ask nuxt to stop listening to file changes
test.after('Closing server and nuxt.js', t => {
  nuxt.close()
})
<|endoftext|>


<commit_before>(function (Q, $) {
	/**
	 * @module Q-tools
	 */

	/**
	 * This tool creates parallax effect on tool element.
	 * @class Q parallax
	 * @constructor
	 * @param {Object}             [options] Override various options for this tool
	 *  @param {bool|Number}       [options.speed=false] A negative value will make it move slower than regular scrolling, and faster for positive. Recommended keeping the speed between -10 and 10.
	 *  @param {Float}             [options.center=0.5] Can move start position of parallax element. Top if > 0.5 and bottom if less.
	 *  @param {Number}            [options.zIndex] Can set particular z-index
	 *  @param {String}            [style] Any styles you want to to apply to element.
	 *  @param {String}            [className] Any css classes you want to to apply to element.
	 *  @param {boolean|number}    [leftToRight=false] Horizontal left to right. Use number to define movement limit. If true, 1 value using (means move from border to border).
	 *  @param {boolean|number}    [rightToLeft=false] Horizontal right to left. Use number to define movement limit. If true, 1 value using (means move from border to border).
	 *  @param {boolean|Number}    [spin=false] will spin element to angle defined by number. If just true, angle=360.
	 *  @param {boolean|Number}    [spinRev=false] same as above but spin counterclock-wise.
	 *  @param {boolean|Number}    [spinIn=false] will spin element to angle defined by number. If just true, angle=360.
	 *  @param {boolean|Number}    [spinOut=false] will spin element to angle defined by number. If just true, angle=360.
	 *  @param {boolean|Number}    [fadeInOut=false] fade in than out.
	 *  @param {boolean|Number}    [fadeIn=false] just fade in
	 *  @param {boolean|Number}    [fadeOut=false] just fade out
	 *  @param {boolean|number}    [zoomInOut=false] zoom in than out. Use number as measure of zoom. If true, 0.2 value using.
	 *  @param {boolean|Number}    [zoomIn=false] just zoom in. Use number as measure of zoom. If true, 0.2 value using.
	 *  @param {boolean|Number}    [zoomOut=false] just zoom out. Use number as measure of zoom. If true, 0.2 value using.
	 *  @param {boolean|Number}    [blurInOut=false] blur in than out. Use number as measure of blur. If true, 40 value using.
	 *  @param {boolean|Number}    [blurIn=false] just blur in. Use number as measure of blur. If true, 40 value using.
	 *  @param {boolean|Number}    [blurOut=false] just blur out. Use number as measure of blur. If true, 40 value using.
	 *  @param {boolean|number}    [spin=false] Set angle to rotate element (for example 360). If positive - clockwise, negative - back clockwise.
	 *  @param {boolean|number}    [swing=false] Skew element to and fro. Use number as measure of Skew. If true, 30 value using.
	 *  @param {boolean|number}    [slalom=false] Moving element to and fro. Use number as measure of swing. If true, 50 value using.
	 *  @param {number}            [offset=0] scrollY position so the animation will begin at this point
	 *  @param {String|HTMLElement}	[wrapper] By default, the position of parallax elements is determined via the scroll position of the body.
	 *    Passing in the wrapper property will force to watch that element instead.
	 *  @param {Q.Event}           [onMove] Event that happens when parallax position changed.
	 * @return {Q.Tool}
	 */
	Q.Tool.define("Q/parallax", function () {
		var tool = this;
		var state = this.state;

		var s = Q.Pointer.preventRubberBand.suspend;
		if (!s['Q/parallax']) {
			s['Q/parallax'] = 0;
		}
		++s['Q/parallax'];

		if (state.style) {
			tool.element.setAttribute('style', state.style);
		}
		if (state.className) {
			tool.element.className += ' ' + state.className;
		}

		if (state.speed) {
			tool.rellax();
		} else {
			tool.lax();
		}
	},

	{
		speed: false,
		center: 0.5,
		zIndex: null,
		optimize: false,
		wrapper: null,
		leftToRight: false,
		rightToLeft: false,
		spin: false,
		fadeInOut: false,
		fadeIn: false,
		fadeOut: false,
		zoomInOut: false,
		zoomIn: false,
		zoomOut: false,
		blurInOut: false,
		blurIn: false,
		blurOut: false,
		swing: false,
		slalom: false,
		offset: 0,
		onMove: new Q.Event()
	},

	{
		lax: function () {
			var $te = $(this.element);
			var state = this.state;

			Q.addScript("{{Q}}/js/parallax/lax.js", function () {
				var htmlTag = document.getElementsByTagName("html")[0];

				// this code applied only once, so set data-q-parallax flag to HTML tag
				if (!_parallaxApplied) {
					setTimeout(function () {
						lax.setup();

						var update = function () {
							lax.update(window.scrollY);
							window.requestAnimationFrame(update);
						};

						window.requestAnimationFrame(update);

						var w = window.innerWidth;
						window.addEventListener("resize", function() {
							if(w !== window.innerWidth) {
								lax.updateElements();
							}
						});
					}, 2000);

					_parallaxApplied = true;
				}

				var preset = [];
				var options = [];

				if (state.leftToRight) {
					preset.push(state.leftToRight === true ? 'leftToRight' : 'leftToRight-' + state.leftToRight);
				} else if (state.rightToLeft) {
					preset.push(state.rightToLeft === true ? 'rightToLeft' : 'rightToLeft-' + state.rightToLeft);
				}

				if (state.spin) {
					if (state.spin > 0) {
						preset.push('spin-' + state.spin);
					} else {
						preset.push('spinRev-' + (-1 * state.spin));
					}
				}

				Q.each(['fadeInOut', 'fadeIn', 'fadeOut', 'spinIn', 'spinOut'], function (i, k) {
					if (state[k]) {
						preset.push(state[k] === true ? k : (k + '-' + state[k]));
					}
				});

				Q.each([
					'zoomInOut', 'zoomIn', 'zoomOut', 'blurInOut', 'blurIn', 'blurOut',
					'swing', 'slalom'
				], function (i, k) {
					if (state[k]) {
						preset.push(state[k] === true ? k : (k + '-' + state[k]));
					}
				});

				if (state.optimize) {
					$te.attr('data-lax-optimize', true);
				}

				if (state.offset) {
					options.push('offset=' + state.offset);
				}

				$te.addClass('lax');
				$te.attr('data-lax-preset', preset.join(' '));
				$te.attr('data-lax-options', options.join(' '));
				lax.addElement($te[0]);
			});
		},
		rellax: function () {
			var tool = this;
			var state = this.state;

			Q.addScript("{{Q}}/js/parallax/rellax.js", function () {
				var options = {
					speed: state.speed,
					center: true,
					round: true,
					optimize: state.optimize,
					vertical: true,
					horizontal: false,
					callback: function(positions) {
						Q.handle(state.onMove, tool, [positions]);
					}
				};

				if (state.wrapper) {
					options.wrapper = state.wrapper;
				}
				if (state.center) {
					tool.element.setAttribute('data-rellax-percentage', state.center);
				}
				if (state.zIndex) {
					tool.element.setAttribute('data-rellax-zindex', state.zIndex);
				}

				tool.parallax = new Rellax(tool.element, options);
			});
		},
		refresh: function () {
			this.parallax && this.parallax.refresh();
		},
		Q: {
			beforeRemove: function () {
				this.parallax && this.parallax.destroy();
				var s = Q.Pointer.preventRubberBand.suspend;
				if (--s['Q/parallax'] === 0) {
					delete Q.Pointer.preventRubberBand.suspend['Q/parallax'];
				}
			}
		}
	});

	var _parallaxApplied = false;

})(Q, jQuery);
<commit_msg>Removed "magic" delay 2000ms and allow adding elements dynamically. lax.addElement() need to run after lax.setup(), because lax.setup calling lax.addElement for each element.<commit_after>(function (Q, $) {
	/**
	 * @module Q-tools
	 */

	/**
	 * This tool creates parallax effect on tool element.
	 * @class Q parallax
	 * @constructor
	 * @param {Object}             [options] Override various options for this tool
	 *  @param {bool|Number}       [options.speed=false] A negative value will make it move slower than regular scrolling, and faster for positive. Recommended keeping the speed between -10 and 10.
	 *  @param {Float}             [options.center=0.5] Can move start position of parallax element. Top if > 0.5 and bottom if less.
	 *  @param {Number}            [options.zIndex] Can set particular z-index
	 *  @param {String}            [style] Any styles you want to to apply to element.
	 *  @param {String}            [className] Any css classes you want to to apply to element.
	 *  @param {boolean|number}    [leftToRight=false] Horizontal left to right. Use number to define movement limit. If true, 1 value using (means move from border to border).
	 *  @param {boolean|number}    [rightToLeft=false] Horizontal right to left. Use number to define movement limit. If true, 1 value using (means move from border to border).
	 *  @param {boolean|Number}    [spin=false] will spin element to angle defined by number. If just true, angle=360.
	 *  @param {boolean|Number}    [spinRev=false] same as above but spin counterclock-wise.
	 *  @param {boolean|Number}    [spinIn=false] will spin element to angle defined by number. If just true, angle=360.
	 *  @param {boolean|Number}    [spinOut=false] will spin element to angle defined by number. If just true, angle=360.
	 *  @param {boolean|Number}    [fadeInOut=false] fade in than out.
	 *  @param {boolean|Number}    [fadeIn=false] just fade in
	 *  @param {boolean|Number}    [fadeOut=false] just fade out
	 *  @param {boolean|number}    [zoomInOut=false] zoom in than out. Use number as measure of zoom. If true, 0.2 value using.
	 *  @param {boolean|Number}    [zoomIn=false] just zoom in. Use number as measure of zoom. If true, 0.2 value using.
	 *  @param {boolean|Number}    [zoomOut=false] just zoom out. Use number as measure of zoom. If true, 0.2 value using.
	 *  @param {boolean|Number}    [blurInOut=false] blur in than out. Use number as measure of blur. If true, 40 value using.
	 *  @param {boolean|Number}    [blurIn=false] just blur in. Use number as measure of blur. If true, 40 value using.
	 *  @param {boolean|Number}    [blurOut=false] just blur out. Use number as measure of blur. If true, 40 value using.
	 *  @param {boolean|number}    [spin=false] Set angle to rotate element (for example 360). If positive - clockwise, negative - back clockwise.
	 *  @param {boolean|number}    [swing=false] Skew element to and fro. Use number as measure of Skew. If true, 30 value using.
	 *  @param {boolean|number}    [slalom=false] Moving element to and fro. Use number as measure of swing. If true, 50 value using.
	 *  @param {number}            [offset=0] scrollY position so the animation will begin at this point
	 *  @param {String|HTMLElement}	[wrapper] By default, the position of parallax elements is determined via the scroll position of the body.
	 *    Passing in the wrapper property will force to watch that element instead.
	 *  @param {Q.Event}           [onMove] Event that happens when parallax position changed.
	 * @return {Q.Tool}
	 */
	Q.Tool.define("Q/parallax", function () {
		var tool = this;
		var state = this.state;

		var s = Q.Pointer.preventRubberBand.suspend;
		if (!s['Q/parallax']) {
			s['Q/parallax'] = 0;
		}
		++s['Q/parallax'];

		if (state.style) {
			tool.element.setAttribute('style', state.style);
		}
		if (state.className) {
			tool.element.className += ' ' + state.className;
		}

		if (state.speed) {
			tool.rellax();
		} else {
			tool.lax();
		}
	},

	{
		speed: false,
		center: 0.5,
		zIndex: null,
		optimize: false,
		wrapper: null,
		leftToRight: false,
		rightToLeft: false,
		spin: false,
		fadeInOut: false,
		fadeIn: false,
		fadeOut: false,
		zoomInOut: false,
		zoomIn: false,
		zoomOut: false,
		blurInOut: false,
		blurIn: false,
		blurOut: false,
		swing: false,
		slalom: false,
		offset: 0,
		onMove: new Q.Event()
	},

	{
		lax: function () {
			var $te = $(this.element);
			var state = this.state;

			Q.addScript("{{Q}}/js/parallax/lax.js", function () {
				var preset = [];
				var options = [];

				if (state.leftToRight) {
					preset.push(state.leftToRight === true ? 'leftToRight' : 'leftToRight-' + state.leftToRight);
				} else if (state.rightToLeft) {
					preset.push(state.rightToLeft === true ? 'rightToLeft' : 'rightToLeft-' + state.rightToLeft);
				}

				if (state.spin) {
					if (state.spin > 0) {
						preset.push('spin-' + state.spin);
					} else {
						preset.push('spinRev-' + (-1 * state.spin));
					}
				}

				Q.each(['fadeInOut', 'fadeIn', 'fadeOut', 'spinIn', 'spinOut'], function (i, k) {
					if (state[k]) {
						preset.push(state[k] === true ? k : (k + '-' + state[k]));
					}
				});

				Q.each([
					'zoomInOut', 'zoomIn', 'zoomOut', 'blurInOut', 'blurIn', 'blurOut',
					'swing', 'slalom'
				], function (i, k) {
					if (state[k]) {
						preset.push(state[k] === true ? k : (k + '-' + state[k]));
					}
				});

				if (state.optimize) {
					$te.attr('data-lax-optimize', true);
				}

				if (state.offset) {
					options.push('offset=' + state.offset);
				}

				$te.addClass('lax');
				$te.attr('data-lax-preset', preset.join(' '));
				$te.attr('data-lax-options', options.join(' '));

				// this code applied only once
				if (_parallaxApplied) {
					lax.addElement($te[0]);
				} else {
					//setTimeout(function () {
					lax.setup();

					var update = function () {
						lax.update(window.scrollY);
						window.requestAnimationFrame(update);
					};

					window.requestAnimationFrame(update);

					var w = window.innerWidth;
					window.addEventListener("resize", function() {
						if(w !== window.innerWidth) {
							lax.updateElements();
						}
					});
					//}, 2000);

					_parallaxApplied = true;
				}
			});
		},
		rellax: function () {
			var tool = this;
			var state = this.state;

			Q.addScript("{{Q}}/js/parallax/rellax.js", function () {
				var options = {
					speed: state.speed,
					center: true,
					round: true,
					optimize: state.optimize,
					vertical: true,
					horizontal: false,
					callback: function(positions) {
						Q.handle(state.onMove, tool, [positions]);
					}
				};

				if (state.wrapper) {
					options.wrapper = state.wrapper;
				}
				if (state.center) {
					tool.element.setAttribute('data-rellax-percentage', state.center);
				}
				if (state.zIndex) {
					tool.element.setAttribute('data-rellax-zindex', state.zIndex);
				}

				tool.parallax = new Rellax(tool.element, options);
			});
		},
		refresh: function () {
			this.parallax && this.parallax.refresh();
		},
		Q: {
			beforeRemove: function () {
				this.parallax && this.parallax.destroy();
				var s = Q.Pointer.preventRubberBand.suspend;
				if (--s['Q/parallax'] === 0) {
					delete Q.Pointer.preventRubberBand.suspend['Q/parallax'];
				}
			}
		}
	});

	var _parallaxApplied = false;

})(Q, jQuery);
<|endoftext|>


<commit_before>/*
  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
  Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*jslint browser: true node: true */
/*global load:true, print:true */
var setupBenchmarks,
    fullFixture,
    quickFixture;

fullFixture = [
    'Underscore 1.4.1',
    'Backbone 0.9.2',
    'CodeMirror 2.34',
    'MooTools 1.4.1',
    'jQuery 1.8.2',
    'jQuery.Mobile 1.2.0',
    'Angular 1.0.2'
];

quickFixture = [
    'Backbone 0.9.2',
    'jQuery 1.8.2',
    'Angular 1.0.2'
];

function slug(name) {
    'use strict';
    return name.toLowerCase().replace(/\.js/g, 'js').replace(/\s/g, '-');
}

function kb(bytes) {
    'use strict';
    return (bytes / 1024).toFixed(1);
}

if (typeof window !== 'undefined') {
    // Run all tests in a browser environment.
    setupBenchmarks = function () {
        'use strict';

        function id(i) {
            return document.getElementById(i);
        }

        function setText(id, str) {
            var el = document.getElementById(id);
            if (typeof el.innerText === 'string') {
                el.innerText = str;
            } else {
                el.textContent = str;
            }
        }

        function enableRunButtons() {
            id('runquick').disabled = false;
            id('runfull').disabled = false;
        }

        function disableRunButtons() {
            id('runquick').disabled = true;
            id('runfull').disabled = true;
        }

        function createTable() {
            var str = '',
                index,
                test,
                name;

            str += '
';
            str += '

Source	Size (KiB)	';
            str += 'Time (ms)	Variance

';
            str += '
';
            for (index = 0; index < fullFixture.length; index += 1) {
                test = fullFixture[index];
                name = slug(test);
                str += '
';
                str += '' + test + '	';
                str += '	';
                str += '	';
                str += '	';
                str += '
';
            }
            str += '
Total	';
            str += '	';
            str += '	';
            str += '
';
            str += '
';
            str += '
';

            id('result').innerHTML = str;
        }

        function loadTests() {

            var index = 0,
                totalSize = 0;

            function load(test, callback) {
                var xhr = new XMLHttpRequest(),
                    src = '3rdparty/' + test + '.js';

                window.data = window.data || {};
                window.data[test] = '';

                try {
                    xhr.timeout = 30000;
                    xhr.open('GET', src, true);

                    xhr.ontimeout = function () {
                        setText('status', 'Error: time out while loading ' + test);
                        callback.apply();
                    };

                    xhr.onreadystatechange = function () {
                        var success = false,
                            size = 0;

                        if (this.readyState === XMLHttpRequest.DONE) {
                            if (this.status === 200) {
                                window.data[test] = this.responseText;
                                size = this.responseText.length;
                                totalSize += size;
                                success = true;
                            }
                        }

                        if (success) {
                            setText(test + '-size', kb(size));
                        } else {
                            setText('status', 'Please wait. Error loading ' + src);
                            setText(test + '-size', 'Error');
                        }

                        callback.apply();
                    };

                    xhr.send(null);
                } catch (e) {
                    setText('status', 'Please wait. Error loading ' + src);
                    callback.apply();
                }
            }

            function loadNextTest() {
                var test;

                if (index < fullFixture.length) {
                    test = fullFixture[index];
                    index += 1;
                    setText('status', 'Please wait. Loading ' + test +
                            ' (' + index + ' of ' + fullFixture.length + ')');
                    window.setTimeout(function () {
                        load(slug(test), loadNextTest);
                    }, 100);
                } else {
                    setText('total-size', kb(totalSize));
                    setText('status', 'Ready.');
                    enableRunButtons();
                }
            }

            loadNextTest();
        }

        function runBenchmarks(suite) {

            var index = 0,
                totalTime = 0;

            function reset() {
                var i, name;
                for (i = 0; i < fullFixture.length; i += 1) {
                    name = slug(fullFixture[i]);
                    setText(name + '-time', '');
                    setText(name + '-variance', '');
                }
                setText('total-time', '');
            }

            function run() {
                var el, test, source, benchmark;

                if (index >= suite.length) {
                    setText('total-time', (1000 * totalTime).toFixed(1));
                    setText('status', 'Ready.');
                    enableRunButtons();
                    return;
                }

                test = slug(suite[index]);
                el = id(test);
                source = window.data[test];
                setText(test + '-time', 'Running...');

                // Force the result to be held in this array, thus defeating any
                // possible "dead core elimination" optimization.
                window.tree = [];

                benchmark = new window.Benchmark(test, function (o) {
                    var syntax = window.esprima.parse(source);
                    window.tree.push(syntax.body.length);
                }, {
                    'onComplete': function () {
                        setText(this.name + '-time', (1000 * this.stats.mean).toFixed(1));
                        setText(this.name + '-variance', (1000 * this.stats.variance).toFixed(1));
                        totalTime += this.stats.mean;
                    }
                });

                window.setTimeout(function () {
                    benchmark.run();
                    index += 1;
                    window.setTimeout(run, 211);
                }, 211);
            }

            disableRunButtons();
            setText('status', 'Please wait. Running benchmarks...');

            reset();
            run();
        }

        id('runquick').onclick = function () {
            runBenchmarks(quickFixture);
        };

        id('runfull').onclick = function () {
            runBenchmarks(fullFixture);
        };

        setText('benchmarkjs-version', ' version ' + window.Benchmark.version);
        setText('version', window.esprima.version);

        createTable();
        disableRunButtons();
        loadTests();
    };
} else {

    (function (global) {
        'use strict';
        var Benchmark,
            esprima,
            dirname,
            option,
            fs,
            readFileSync,
            log;

        if (typeof require === 'undefined') {
            dirname = 'test';
            load(dirname + '/3rdparty/benchmark.js');

            load(dirname + '/../esprima.js');

            Benchmark = global.Benchmark;
            esprima = global.esprima;
            readFileSync = global.read;
            log = print;
        } else {
            Benchmark = require('./3rdparty/benchmark');
            esprima = require('../esprima');
            fs = require('fs');
            option = process.argv[2];
            readFileSync = function readFileSync(filename) {
                return fs.readFileSync(filename, 'utf-8');
            };
            dirname = __dirname;
            log = console.log.bind(console);
        }

        function runTests(tests) {
            var index,
                tree = [],
                totalTime = 0,
                totalSize = 0;

            tests.reduce(function (suite, filename) {
                var source = readFileSync(dirname + '/3rdparty/' + slug(filename) + '.js'),
                    size = source.length;
                totalSize += size;
                return suite.add(filename, function () {
                    var syntax = esprima.parse(source);
                    tree.push(syntax.body.length);
                }, {
                    'onComplete': function (event, bench) {
                        log(this.name +
                            ' size ' + kb(size) +
                            ' time ' + (1000 * this.stats.mean).toFixed(1) +
                            ' variance ' + (1000 * 1000 * this.stats.variance).toFixed(1));
                        totalTime += this.stats.mean;
                    }
                });
            }, new Benchmark.Suite()).on('complete', function () {
                log('Total size ' + kb(totalSize) +
                    ' time ' + (1000 * totalTime).toFixed(1));
            }).run();
        }

        if (option === 'quick') {
            runTests(quickFixture);
        } else {
            runTests(fullFixture);
        }
    }(this));
}
/* vim: set sw=4 ts=4 et tw=80 : */
<commit_msg>Benchmark runner: optional location tracking.<commit_after>/*
  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
  Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*jslint browser: true node: true */
/*global load:true, print:true */
var setupBenchmarks,
    fullFixture,
    quickFixture;

fullFixture = [
    'Underscore 1.4.1',
    'Backbone 0.9.2',
    'CodeMirror 2.34',
    'MooTools 1.4.1',
    'jQuery 1.8.2',
    'jQuery.Mobile 1.2.0',
    'Angular 1.0.2'
];

quickFixture = [
    'Backbone 0.9.2',
    'jQuery 1.8.2',
    'Angular 1.0.2'
];

function slug(name) {
    'use strict';
    return name.toLowerCase().replace(/\.js/g, 'js').replace(/\s/g, '-');
}

function kb(bytes) {
    'use strict';
    return (bytes / 1024).toFixed(1);
}

if (typeof window !== 'undefined') {
    // Run all tests in a browser environment.
    setupBenchmarks = function () {
        'use strict';

        function id(i) {
            return document.getElementById(i);
        }

        function setText(id, str) {
            var el = document.getElementById(id);
            if (typeof el.innerText === 'string') {
                el.innerText = str;
            } else {
                el.textContent = str;
            }
        }

        function enableRunButtons() {
            id('runquick').disabled = false;
            id('runfull').disabled = false;
        }

        function disableRunButtons() {
            id('runquick').disabled = true;
            id('runfull').disabled = true;
        }

        function createTable() {
            var str = '',
                index,
                test,
                name;

            str += '
';
            str += '

Source	Size (KiB)	';
            str += 'Time (ms)	Variance

';
            str += '
';
            for (index = 0; index < fullFixture.length; index += 1) {
                test = fullFixture[index];
                name = slug(test);
                str += '
';
                str += '' + test + '	';
                str += '	';
                str += '	';
                str += '	';
                str += '
';
            }
            str += '
Total	';
            str += '	';
            str += '	';
            str += '
';
            str += '
';
            str += '
';

            id('result').innerHTML = str;
        }

        function loadTests() {

            var index = 0,
                totalSize = 0;

            function load(test, callback) {
                var xhr = new XMLHttpRequest(),
                    src = '3rdparty/' + test + '.js';

                window.data = window.data || {};
                window.data[test] = '';

                try {
                    xhr.timeout = 30000;
                    xhr.open('GET', src, true);

                    xhr.ontimeout = function () {
                        setText('status', 'Error: time out while loading ' + test);
                        callback.apply();
                    };

                    xhr.onreadystatechange = function () {
                        var success = false,
                            size = 0;

                        if (this.readyState === XMLHttpRequest.DONE) {
                            if (this.status === 200) {
                                window.data[test] = this.responseText;
                                size = this.responseText.length;
                                totalSize += size;
                                success = true;
                            }
                        }

                        if (success) {
                            setText(test + '-size', kb(size));
                        } else {
                            setText('status', 'Please wait. Error loading ' + src);
                            setText(test + '-size', 'Error');
                        }

                        callback.apply();
                    };

                    xhr.send(null);
                } catch (e) {
                    setText('status', 'Please wait. Error loading ' + src);
                    callback.apply();
                }
            }

            function loadNextTest() {
                var test;

                if (index < fullFixture.length) {
                    test = fullFixture[index];
                    index += 1;
                    setText('status', 'Please wait. Loading ' + test +
                            ' (' + index + ' of ' + fullFixture.length + ')');
                    window.setTimeout(function () {
                        load(slug(test), loadNextTest);
                    }, 100);
                } else {
                    setText('total-size', kb(totalSize));
                    setText('status', 'Ready.');
                    enableRunButtons();
                }
            }

            loadNextTest();
        }

        function runBenchmarks(suite) {

            var index = 0,
                totalTime = 0;

            function reset() {
                var i, name;
                for (i = 0; i < fullFixture.length; i += 1) {
                    name = slug(fullFixture[i]);
                    setText(name + '-time', '');
                    setText(name + '-variance', '');
                }
                setText('total-time', '');
            }

            function run() {
                var el, test, source, benchmark;

                if (index >= suite.length) {
                    setText('total-time', (1000 * totalTime).toFixed(1));
                    setText('status', 'Ready.');
                    enableRunButtons();
                    return;
                }

                test = slug(suite[index]);
                el = id(test);
                source = window.data[test];
                setText(test + '-time', 'Running...');

                // Force the result to be held in this array, thus defeating any
                // possible "dead core elimination" optimization.
                window.tree = [];

                benchmark = new window.Benchmark(test, function (o) {
                    var syntax = window.esprima.parse(source);
                    window.tree.push(syntax.body.length);
                }, {
                    'onComplete': function () {
                        setText(this.name + '-time', (1000 * this.stats.mean).toFixed(1));
                        setText(this.name + '-variance', (1000 * this.stats.variance).toFixed(1));
                        totalTime += this.stats.mean;
                    }
                });

                window.setTimeout(function () {
                    benchmark.run();
                    index += 1;
                    window.setTimeout(run, 211);
                }, 211);
            }

            disableRunButtons();
            setText('status', 'Please wait. Running benchmarks...');

            reset();
            run();
        }

        id('runquick').onclick = function () {
            runBenchmarks(quickFixture);
        };

        id('runfull').onclick = function () {
            runBenchmarks(fullFixture);
        };

        setText('benchmarkjs-version', ' version ' + window.Benchmark.version);
        setText('version', window.esprima.version);

        createTable();
        disableRunButtons();
        loadTests();
    };
} else {

    (function (global) {
        'use strict';
        var Benchmark,
            esprima,
            dirname,
            quick,
            loc = false,
            fs,
            readFileSync,
            log;

        if (typeof require === 'undefined') {
            dirname = 'test';
            load(dirname + '/3rdparty/benchmark.js');

            load(dirname + '/../esprima.js');

            Benchmark = global.Benchmark;
            esprima = global.esprima;
            readFileSync = global.read;
            log = print;
        } else {
            Benchmark = require('./3rdparty/benchmark');
            esprima = require('../esprima');
            fs = require('fs');
            quick = process.argv[2] === 'quick' || process.argv[3] === 'quick';
            loc = process.argv[2] === 'loc' || process.argv[3] === 'loc';
            readFileSync = function readFileSync(filename) {
                return fs.readFileSync(filename, 'utf-8');
            };
            dirname = __dirname;
            log = console.log.bind(console);
        }

        function runTests(tests) {
            var index,
                tree = [],
                totalTime = 0,
                totalSize = 0;

            tests.reduce(function (suite, filename) {
                var source = readFileSync(dirname + '/3rdparty/' + slug(filename) + '.js'),
                    size = source.length;
                totalSize += size;
                return suite.add(filename, function () {
                    var syntax = esprima.parse(source, {loc: loc});
                    tree.push(syntax.body.length);
                }, {
                    'onComplete': function (event, bench) {
                        log(this.name +
                            ' size ' + kb(size) +
                            ' time ' + (1000 * this.stats.mean).toFixed(1) +
                            ' variance ' + (1000 * 1000 * this.stats.variance).toFixed(1));
                        totalTime += this.stats.mean;
                    }
                });
            }, new Benchmark.Suite()).on('complete', function () {
                log('Total size ' + kb(totalSize) +
                    ' time ' + (1000 * totalTime).toFixed(1));
            }).run();
        }

        if (quick) {
            runTests(quickFixture);
        } else {
            runTests(fullFixture);
        }
    }(this));
}
/* vim: set sw=4 ts=4 et tw=80 : */
<|endoftext|>


<commit_before>(function (Q, $, window, undefined) {

var Users = Q.Users;

/**
 * Users Tools
 * @module Users-tools
 */

/**
 * Renders a list of user avatars
 * @class Users list
 * @constructor
 * @param {Object} options options for the tool
 * @param {Array} options.userIds the user ids to render
 * @param {Number} [options.limit=100] positive integer for how many avatars to show at a time
 * @param {Number} [options.preload=0] how many pages (multiples of limit) to preload
 * @param {Object} [options.avatar={icon:80}] options for the child Users/avatar tools
 * @param {Object} [options.clickable=false] options for Q/clickable, if not false
 * @param {Number} [options.preload=0] how many pages (multiples of limit) to preload
 * @param {Q.Event} [options.onRefresh] happens after the refresh method is called
 * @param {Q.Event} [options.onLoadMore] happens when more users are loaded (including first time)
 */
Q.Tool.define('Users/list', function () {
	var tool = this;
	var state = tool.state;
	if (Q.isEmpty(state.userIds)) {
		return;
	}
	var lastScrollTop = 0;
	var $te = $(tool.element);
	$te.addClass('Q_overflow').on('scroll', function () {
		var scrollTop = $te.scrollTop();
		if (scrollTop === lastScrollTop) {
			return;
		}
		if (scrollTop >= $te[0].scrollHeight - $te[0].clientHeight) {
			tool.loadMore();
		}
		lastScrollTop = scrollTop;
	});
	this.refresh();
}, {
	userIds: null,
	limit: 100,
	preload: 1,
	avatar: {
		"short": true,
		icon: (window.devicePixelRatio > 1 ? '200' : '80'),
		reflectChanges: false
	},
	onRefresh: new Q.Event(),
	onLoadMore: new Q.Event(),
	clickable: false
}, {
	/**
	 * Refresh the contents
	 */
	refresh: function (callback) {
		Q.removeElement(this.element.children || this.element.childNodes, true);
		this.loaded = 0;
		this.loadMore(callback);
		Q.handle(this.state.onRefresh, this);
	},
	/**
	 * Load more user avatars.
	 * @return {Number} the number new of avatars loaded
	 */
	loadMore: function (callback) {
		var tool = this;
		var state = tool.state;
		tool.loading = true;
		var length = Q.typeOf(state.userIds) === "object" ? Object.keys(state.userIds).length : state.userIds.length;
		length = Math.min(tool.loaded + state.limit, length);
		var avatars = [], elements = [];
		Q.each(state.userIds, function (i, userId) {
			if (i < tool.loaded || i >= length) {
				return;
			}

			var element = Q.Tool.setUpElement('div', 'Users/avatar',
				Q.extend({}, state.avatar, {
					userId: userId
				}), null, tool.prefix);
			tool.element.appendChild(element);
			elements.push(element);
		});
		var count = length - tool.loaded;
		tool.loaded = length;
		Q.activate(tool.element.children || tool.element.childNodes, function () {
			tool.loading = false;
			if (state.clickable) {
				if (state.clickable === true) {
					state.clickable = {};
				}
				Q.each(elements, function () {
					var $te = $(this);
					var avatar = this.Q.tool;
					avatars.push(avatar)
					avatar.state.onRefresh.add(function () {
						if ($te.closest('html').length) {
							return;
						}
						$te.find('img').on('load', function () {
							$te.plugin('Q/clickable', state.clickable);
						});
					}, tool);
				});
				Q.handle(callback, tool);
				Q.handle(state.onLoadMore, tool, [avatars, elements]);
			}
		});
		return count;
	}
});

})(Q, Q.$, window);<commit_msg>Modified Users/list tool. Added option numeric:true to Q.each<commit_after>(function (Q, $, window, undefined) {

var Users = Q.Users;

/**
 * Users Tools
 * @module Users-tools
 */

/**
 * Renders a list of user avatars
 * @class Users list
 * @constructor
 * @param {Object} options options for the tool
 * @param {Array} options.userIds the user ids to render
 * @param {Number} [options.limit=100] positive integer for how many avatars to show at a time
 * @param {Number} [options.preload=0] how many pages (multiples of limit) to preload
 * @param {Object} [options.avatar={icon:80}] options for the child Users/avatar tools
 * @param {Object} [options.clickable=false] options for Q/clickable, if not false
 * @param {Number} [options.preload=0] how many pages (multiples of limit) to preload
 * @param {Q.Event} [options.onRefresh] happens after the refresh method is called
 * @param {Q.Event} [options.onLoadMore] happens when more users are loaded (including first time)
 */
Q.Tool.define('Users/list', function () {
	var tool = this;
	var state = tool.state;
	if (Q.isEmpty(state.userIds)) {
		return;
	}
	var lastScrollTop = 0;
	var $te = $(tool.element);
	$te.addClass('Q_overflow').on('scroll', function () {
		var scrollTop = $te.scrollTop();
		if (scrollTop === lastScrollTop) {
			return;
		}
		if (scrollTop >= $te[0].scrollHeight - $te[0].clientHeight) {
			tool.loadMore();
		}
		lastScrollTop = scrollTop;
	});
	this.refresh();
}, {
	userIds: null,
	limit: 100,
	preload: 1,
	avatar: {
		"short": true,
		icon: (window.devicePixelRatio > 1 ? '200' : '80'),
		reflectChanges: false
	},
	onRefresh: new Q.Event(),
	onLoadMore: new Q.Event(),
	clickable: false
}, {
	/**
	 * Refresh the contents
	 */
	refresh: function (callback) {
		Q.removeElement(this.element.children || this.element.childNodes, true);
		this.loaded = 0;
		this.loadMore(callback);
		Q.handle(this.state.onRefresh, this);
	},
	/**
	 * Load more user avatars.
	 * @return {Number} the number new of avatars loaded
	 */
	loadMore: function (callback) {
		var tool = this;
		var state = tool.state;
		tool.loading = true;
		var length = Q.typeOf(state.userIds) === "object" ? Object.keys(state.userIds).length : state.userIds.length;
		length = Math.min(tool.loaded + state.limit, length);
		var avatars = [], elements = [];
		Q.each(state.userIds, function (i, userId) {
			if (i < tool.loaded || i >= length) {
				return;
			}

			var element = Q.Tool.setUpElement('div', 'Users/avatar',
				Q.extend({}, state.avatar, {
					userId: userId
				}), null, tool.prefix);
			tool.element.appendChild(element);
			elements.push(element);
		}, {
			numeric: true
		});
		var count = length - tool.loaded;
		tool.loaded = length;
		Q.activate(tool.element.children || tool.element.childNodes, function () {
			tool.loading = false;
			if (state.clickable) {
				if (state.clickable === true) {
					state.clickable = {};
				}
				Q.each(elements, function () {
					var $te = $(this);
					var avatar = this.Q.tool;
					avatars.push(avatar)
					avatar.state.onRefresh.add(function () {
						if ($te.closest('html').length) {
							return;
						}
						$te.find('img').on('load', function () {
							$te.plugin('Q/clickable', state.clickable);
						});
					}, tool);
				});
				Q.handle(callback, tool);
				Q.handle(state.onLoadMore, tool, [avatars, elements]);
			}
		});
		return count;
	}
});

})(Q, Q.$, window);<|endoftext|>


<commit_before>var match = require('../lib/match');
var ranking = require('../lib/ranking');
var player = require('../lib/player');
var gameres = require('../lib/gameres');
var auth = require('basic-auth');
var debug = require('debug')('wol:leaderboard');

exports.submit = function (req, res, next) {
    res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
    res.header('Expires', '-1');
    res.header('Pragma', 'no-cache');

    /* discontinue if missing request data */
    if (!req.body || !req.params.game) return res.send(400);

    var credentials = auth(req) || {};
    var dump = gameres.parse(req.body) || {};

    /* discontinue if missing gameres data */
    if (!dump.client || !dump.client.nick) return res.send(400);

    var _success = function() {
        res.send(202);
        match.process(req.params.game, dump);
    };

    var _error = function() {
        res.writeHead(401, {
            'WWW-Authenticate': 'Basic realm="CnCNet 5 Leaderboard"'
        });

        res.end();
    };

    if (!credentials.name || !credentials.pass) return _error();
    player.auth(dump.client.nick, credentials.name, credentials.pass).then(_success, _error);
};

exports.ladder = function (req, res, next) {
    ranking.ladder(req.params.game, req.params.limit ? req.params.limit : 150).then(function(data) {
        res.send(data);
    });
};

exports.search = function (req, res, next) {
    var _success = function (data) {
        res.send(data);
    };
    var _error = function () {
        res.send(404);
    };

    if (!req.body.player) return _error();
    player.search(req.params.game, req.body.player).then(_success, _error);
};

exports.player = function(req, res, next) {
    var _success = function (data) {
        res.send(data);
    };
    var _error = function () {
        res.send(404);
    };

    player.stats(req.params.game, req.params.player).then(_success, _error);
};

exports.match = function(req, res, next) {
    var _success = function (data) {
        res.send(data);
    };
    var _error = function () {
        res.send(404);
    };

    match.information(req.params.game, parseInt(req.params.gameId)).then(_success, _error);
};
<commit_msg>add minor cache to ladder and player endpoints<commit_after>var match = require('../lib/match');
var ranking = require('../lib/ranking');
var player = require('../lib/player');
var gameres = require('../lib/gameres');
var auth = require('basic-auth');
var debug = require('debug')('wol:leaderboard');

exports.submit = function (req, res, next) {
    res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
    res.header('Expires', '-1');
    res.header('Pragma', 'no-cache');

    /* discontinue if missing request data */
    if (!req.body || !req.params.game) return res.send(400);

    var credentials = auth(req) || {};
    var dump = gameres.parse(req.body) || {};

    /* discontinue if missing gameres data */
    if (!dump.client || !dump.client.nick) return res.send(400);

    var _success = function() {
        res.send(202);
        match.process(req.params.game, dump);
    };

    var _error = function() {
        res.writeHead(401, {
            'WWW-Authenticate': 'Basic realm="CnCNet 5 Leaderboard"'
        });

        res.end();
    };

    if (!credentials.name || !credentials.pass) return _error();
    player.auth(dump.client.nick, credentials.name, credentials.pass).then(_success, _error);
};

exports.ladder = function (req, res, next) {
    res.header('Cache-Control', 'public, max-age=60');

    ranking.ladder(req.params.game, req.params.limit ? req.params.limit : 150).then(function(data) {
        res.send(data);
    });
};

exports.search = function (req, res, next) {
    var _success = function (data) {
        res.send(data);
    };
    var _error = function () {
        res.send(404);
    };

    if (!req.body.player) return _error();
    player.search(req.params.game, req.body.player).then(_success, _error);
};

exports.player = function(req, res, next) {
    res.header('Cache-Control', 'public, max-age=30');

    var _success = function (data) {
        res.send(data);
    };
    var _error = function () {
        res.send(404);
    };

    player.stats(req.params.game, req.params.player).then(_success, _error);
};

exports.match = function(req, res, next) {
    var _success = function (data) {
        res.send(data);
    };
    var _error = function () {
        res.send(404);
    };

    match.information(req.params.game, parseInt(req.params.gameId)).then(_success, _error);
};
<|endoftext|>


<commit_before>var subMenuItem = document.querySelectorAll('.sub-menu .menu-item'),
    subMenu     = document.querySelectorAll('.sub-menu');

document.addEventListener('focus', focusToggle, true);

function focusToggle( e ) {
  if ( e.target.classList.contains('is-sub-menu-item' ) || e.target.classList.contains('menu-level-') ) {
    subMenu[0].classList.add('hover');
  } else {
    subMenu[0].classList.remove('hover');
  }
}

function offCanvas( toggler, primary, wrap, direction ) {
  var body       = document.body,
      menuToggle = document.querySelector( toggler ),
      menu       = document.querySelector( primary ),
      wrap       = document.querySelector( wrap ),
      dir        = direction;

  menuToggle.onclick = function() {
    menu.classList.toggle('is-active');
    body.classList.toggle('is-active-off-canvas');
    if( body.classList.contains( 'is-active-off-canvas' ) ) {
      var menuWidth = menu.offsetWidth,
          bodyDir   = dir,
          wrapDir   = dir,
          bodyDir   = (bodyDir === 'left') ? body.style.left = menuWidth + 'px' : body.style.right = menuWidth + 'px',
          wrapDir   = (wrapDir === 'left') ? wrap.style.left = -menuWidth + 'px' : wrap.style.right = -menuWidth + 'px';

      wrap.classList.add( dir );
    } else {
      var bodyDir   = dir,
          wrapDir   = dir,
          bodyDir = (bodyDir === 'left') ? body.style.left = '0' : body.style.right = '0',
          wrapDir = (wrapDir === 'left') ? wrap.style.left = '0' : wrap.style.right = '0';
      wrap.classList.remove( dir );
    }
  }
}

offCanvas( '.site-menu-toggle', '.primary-menu', '.site-header', 'left' );<commit_msg>Add function comments and documentation. Alter function parameter names.<commit_after>var subMenuItem = document.querySelectorAll('.sub-menu .menu-item'),
    subMenu     = document.querySelectorAll('.sub-menu');

document.addEventListener('focus', focusToggle, true);

function focusToggle( e ) {
  if ( e.target.classList.contains('is-sub-menu-item' ) || e.target.classList.contains('menu-level-') ) {
    subMenu[0].classList.add('hover');
  } else {
    subMenu[0].classList.remove('hover');
  }
}

/**
 * Adds helper function for devs to plug in basic values to assist in off canvas functionality.
 * @param {Element} toggler         //The class name of the element that toggles the off canvas menu.
 * @param {Element} primaryMenu     //The class name of the element that is the primary menu.
 * @param {Element} primaryMenuWrap //The wrapper that contains the primary menu.
 * @param {String} direction        //The direction that the off canvas menu should fly in from.
 */
function offCanvas( toggler, primaryMenu, primaryMenuWrap, direction ) {
  var body       = document.body,
      menuToggle = document.querySelector( toggler ),
      menu       = document.querySelector( primaryMenu ),
      wrap       = document.querySelector( primaryMenuWrap ),
      dir        = direction;

  menuToggle.onclick = function() {
    menu.classList.toggle('is-active');
    body.classList.toggle('is-active-off-canvas');

    if( body.classList.contains( 'is-active-off-canvas' ) ) {
      var menuWidth = menu.offsetWidth,
          bodyDir   = dir,
          wrapDir   = dir,
          bodyDir   = (bodyDir === 'left') ? body.style.left = menuWidth + 'px' : body.style.right = menuWidth + 'px',
          wrapDir   = (wrapDir === 'left') ? wrap.style.left = -menuWidth + 'px' : wrap.style.right = -menuWidth + 'px';

      wrap.classList.add( dir );
    } else {
      var bodyDir   = dir,
          wrapDir   = dir,
          bodyDir = (bodyDir === 'left') ? body.style.left = '0' : body.style.right = '0',
          wrapDir = (wrapDir === 'left') ? wrap.style.left = '0' : wrap.style.right = '0';
      wrap.classList.remove( dir );
    }
  }
}

offCanvas( '.site-menu-toggle', '.primary-menu', '.site-header', 'left' );<|endoftext|>


<commit_before>var assert = require('assert')
var browserify = tryRequire('browserify')
var http = require('http')
var methods = null
var path = require('path')
var run = browserify ? describe : describe.skip

run('when browserified', function () {
  before(function (done) {
    var b = browserify()

    // require methods
    b.require(path.join(__dirname, '..'), {
      expose: 'methods'
    })

    // bundle and eval
    b.bundle(function (err, buf) {
      var require = eval(buf.toString())
      methods = require('methods')
      done()
    })
  })

  describe('methods', function () {
    ['get', 'post', 'put', 'patch', 'delete'].forEach(function (method) {
      it('should contain "' + method + '"', function () {
        assert.notEqual(methods.indexOf(method), -1)
      })
    })

    it('should only have lower-case entries', function() {
      for (var i = 0; i < methods.length; i ++) {
        assert(methods[i], methods[i].toLowerCase(), methods[i] + ' is lower-case')
      }
    })
  })
})

function tryRequire(name) {
  try {
    return require(name)
  } catch (e) {
    return undefined
  }
}
<commit_msg>tests: load browserified code in new context<commit_after>var assert = require('assert')
var browserify = tryRequire('browserify')
var http = require('http')
var methods = null
var path = require('path')
var run = browserify ? describe : describe.skip
var vm = require('vm')

run('when browserified', function () {
  before(function (done) {
    var b = browserify()

    // require methods
    b.require(path.join(__dirname, '..'), {
      expose: 'methods'
    })

    // bundle and eval
    b.bundle(function (err, buf) {
      var require = vm.runInNewContext(buf.toString())
      methods = require('methods')
      done()
    })
  })

  describe('methods', function () {
    ['get', 'post', 'put', 'patch', 'delete'].forEach(function (method) {
      it('should contain "' + method + '"', function () {
        assert.notEqual(methods.indexOf(method), -1)
      })
    })

    it('should only have lower-case entries', function() {
      for (var i = 0; i < methods.length; i ++) {
        assert(methods[i], methods[i].toLowerCase(), methods[i] + ' is lower-case')
      }
    })
  })
})

function tryRequire(name) {
  try {
    return require(name)
  } catch (e) {
    return undefined
  }
}
<|endoftext|>