<commit_before>'use strict';
let VirtualDOM = require('virtual-dom');
let svg = require('virtual-dom/virtual-hyperscript/svg');
let Rx = require('rx');
let {makeDOMDriver} = require('../web/render-dom');
let {makeHTMLDriver} = require('../web/render-html');
let run = require('./run');

var Cycle = {
  /**
   * Takes a `computer` function which outputs an Observable of virtual DOM
   * elements, and renders that into the DOM element indicated by `container`,
   * which can be either a CSS selector or an actual element. At the same time,
   * provides the `interactions` input to the `computer` function, which is a
   * collection of all possible events happening on all elements which were
   * rendered. You must query this collection with
   * `interactions.get(selector, eventName)` in order to get an Observable of
   * interactions of type `eventName` happening on the element identified by
   * `selector`.
   * Example: `interactions.get('.mybutton', 'click').map(ev => ...)`
   *
   * @param {(String|HTMLElement)} container the DOM selector for the element
   * (or the element itself) to contain the rendering of the VTrees.
   * @param {Function} computer a function that takes `interactions` as input
   * and outputs an Observable of virtual DOM elements.
   * @return {Object} an object containing properties `rootElem$`,
   * `interactions`, `dispose()` that can be used for debugging or testing.
   * @function applyToDOM
   */
  run, // TODO write docs

  makeDOMDriver, // TODO write docs

  /**
   * Converts a given Observable of virtual DOM elements (`vtree$`) into an
   * Observable of corresponding HTML strings (`html$`). The provided `vtree$`
   * must complete (must call onCompleted on its observers) in finite time,
   * otherwise the output `html$` will never emit an HTML string.
   *
   * @param {Rx.Observable} vtree$ Observable of virtual DOM elements.
   * @return {Rx.Observable} an Observable emitting a string as the HTML
   * renderization of the virtual DOM element.
   * @function renderAsHTML
   */
  makeHTMLDriver, // TODO write docs

  /**
   * Informs Cycle to recognize the given `tagName` as a custom element
   * implemented as the given function whenever `tagName` is used in VTrees
   * rendered in the context of some parent (in `applyToDOM` or in other custom
   * elements).
   * The given `definitionFn` function takes two parameters as input, in this
   * order: `interactions` and `properties`. The former works just like it does
   * in the `computer` function given to `applyToDOM`, and the later contains
   * Observables representing properties of the custom element, given from the
   * parent context. `properties.get('foo')` will return the Observable `foo$`.
   *
   * The `definitionFn` must output an object containing the property `vtree$`
   * as an Observable. If the output object contains other Observables, then
   * they are treated as custom events of the custom element.
   *
   * @param {String} tagName a name for identifying the custom element.
   * @param {Function} definitionFn the implementation for the custom element.
   * This function takes two arguments: `interactions`, and `properties`, and
   * should output an object of Observables.
   * @function registerCustomElement
   */
  //registerCustomElement: CustomElements.registerCustomElement,
  // TODO deprecated. Do something about it

  /**
   * A shortcut to the root object of
   * [RxJS](https://github.com/Reactive-Extensions/RxJS).
   * @name Rx
   */
  Rx: Rx,

  /**
   * A shortcut to [virtual-hyperscript](
   * https://github.com/Matt-Esch/virtual-dom/tree/master/virtual-hyperscript).
   * This is a helper for creating VTrees in Views.
   * @name h
   */
  h: VirtualDOM.h,

  /**
   * A shortcut to the svg hyperscript function.
   * @name svg
   */
  svg: svg
};

module.exports = Cycle;
<commit_msg>Rewrite top-most JSDocs in src/core/cycle.js<commit_after>'use strict';
let VirtualDOM = require('virtual-dom');
let svg = require('virtual-dom/virtual-hyperscript/svg');
let Rx = require('rx');
let {makeDOMDriver} = require('../web/render-dom');
let {makeHTMLDriver} = require('../web/render-html');
let run = require('./run');

var Cycle = {
  /**
   * Takes an `app` function and circularly connects it to the given collection
   * of driver functions.
   *
   * The `app` function expects a collection of "driver response" Observables as
   * input, and should return a collection of "driver request" Observables.
   * The driver response collection can be queried using a getter function:
   * `responses.get(driverName, ...params)`, returns an Observable. The
   * structure of `params` is defined by the API of the corresponding
   * `driverName`. The driver request collection should be a simple object where
   * keys match the driver names used by `responses.get()` and defined on the
   * second parameter given to `run()`.
   *
   * @param {Function} app a function that takes `responses` as input
   * and outputs a collection of `requests` Observables.
   * @param {Object} drivers an object where keys are driver names and values
   * are driver functions.
   * @return {Array} an array where the first object is the collection of driver
   * requests, and the second objet is the collection of driver responses, that
   * can be used for debugging or testing.
   * @function run
   */
  run,

  /**
   * A factory for the DOM driver function. Takes a `container` to define the
   * target on the existing DOM which this driver will operate on. All custom
   * elements which this driver can detect should be given as the second
   * parameter.
   *
   * @param {(String|HTMLElement)} container the DOM selector for the element
   * (or the element itself) to contain the rendering of the VTrees.
   * @param {Object} a collection of custom element definitions. The key of each
   * property should be the tag name of the custom element, and the value should
   * be a function defining the implementation of the custom element. This
   * function follows the same contract as the top-most `app` function: input
   * are driver responses, output are requests to drivers.
   * @return {Function} the DOM driver function. The function expects an
   * Observable of VTree as input, and outputs the response object for this
   * driver, containing functions `get()` and `dispose()` that can be used for
   * debugging and testing.
   * @function makeDOMDriver
   */
  makeDOMDriver,

  /**
   * A factory for the HTML driver function. Takes the registry object of all
   * custom elements as the only parameter. The HTML driver function will use
   * the custom element registry to detect custom element on the VTree and apply
   * their implementations.
   *
   * @param {Object} a collection of custom element definitions. The key of each
   * property should be the tag name of the custom element, and the value should
   * be a function defining the implementation of the custom element. This
   * function follows the same contract as the top-most `app` function: input
   * are driver responses, output are requests to drivers.
   * @return {Function} the HTML driver function. The function expects an
   * Observable of Virtual DOM elements as input, and outputs the response
   * object for this driver, containing functions `get()` and `dispose()` that
   * can be used for debugging and testing. To get the Observable of strings as
   * the HTML renderization of the virtual DOM elements, call simply
   * `get(htmlDriverName)` on the responses object returned by Cycle.run();
   * @function renderAsHTML
   */
  makeHTMLDriver,

  /**
   * A shortcut to the root object of
   * [RxJS](https://github.com/Reactive-Extensions/RxJS).
   * @name Rx
   */
  Rx: Rx,

  /**
   * A shortcut to [virtual-hyperscript](
   * https://github.com/Matt-Esch/virtual-dom/tree/master/virtual-hyperscript).
   * This is a helper for creating VTrees in Views.
   * @name h
   */
  h: VirtualDOM.h,

  /**
   * A shortcut to the svg hyperscript function.
   * @name svg
   */
  svg: svg
};

module.exports = Cycle;
<|endoftext|>


<commit_before>var assert = require('better-assert');
var herro = require('../.');
var Herror = herro.Herror;

var error = new Herror('Let\'s go!');

// # props
var enumprops = Object.keys(error).join(',');
var allprops = Object.getOwnPropertyNames(error).join(',');

process.stdout.write(
  'enumprops=['+enumprops + '] ; allprops=[' + allprops + '] '
);

assert( enumprops.match(/stack/g) === null);
assert(  allprops.match(/stack|message|arch/g) !== null);

// # inheritance

assert( error instanceof Error );
assert( error instanceof Herror );
<commit_msg>0.1.28 -> It is Node 11 that has error.stack enumerable, I will have to ask. Remove 0.8 from travis.yml, better-assert@1.0.1 is Node@^0.10<commit_after>var assert = require('better-assert');
var herro = require('../.');
var Herror = herro.Herror;

var error = new Herror('Let\'s go!');

// # props
var enumprops = Object.keys(error).join(',');
var allprops = Object.getOwnPropertyNames(error).join(',');

process.stdout.write(
  'enumprops=['+enumprops + '] ; allprops=[' + allprops + '] '
);

assert( enumprops.match(/stack/g) !== null);
assert(  allprops.match(/stack|message|arch/g) !== null);

// # inheritance

assert( error instanceof Error );
assert( error instanceof Herror );
<|endoftext|>


<commit_before>/*
 * jqModal - Minimalist Modaling with jQuery
 *
 * Copyright (c) 2007-2014 Brice Burgess @IceburgBrice
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * $Version: 1.1.0 (2014.07.03 +r21)
 * Requires: jQuery 1.2.3+
 */

(function($) {

	/**
	 * Initialize a set of elements as "modals". Modals typically are popup dialogs,
	 * notices, modal windows, &c.
	 *
	 * @name jqm
	 * @param options user defined options, augments defaults.
	 * @type jQuery
	 * @cat Plugins/jqModal
	 */

	$.fn.jqm=function(options){
		return this.each(function(){
			var e = $(this),
				jqm = e.data('jqm') || $.extend({ID: I++}, $.jqm.params),
				o = $.extend(jqm,options);

			// add/extend options to modal and mark as initialized
			e.data('jqm',o).addClass('jqm-init');

			// ... Attach events to trigger showing of this modal
			o.trigger && e.jqmAddTrigger(o.trigger);
		});
	};

	/**
	 * Matching modals will have their jqmShow() method fired by attaching a
	 *   onClick event to elements matching `trigger`.
	 *
	 * @name jqmAddTrigger
	 * @param trigger a selector String, jQuery collection of elements, or a DOM element.
	 */
	$.fn.jqmAddTrigger=function(trigger){
		return this.each(function(){
			if(!addTrigger($(this), 'jqmShow', trigger))
				err("jqmAddTrigger must be called on initialized modals")
		});
	};

	/**
	 * Matching modals will have their jqmHide() method fired by attaching an
	 *   onClick event to elements matching `trigger`.
	 *
	 * @name jqmAddClose
	 * @param trigger a selector String, jQuery collection of elements, or a DOM element.
	 */
	$.fn.jqmAddClose=function(trigger){
		return this.each(function(){
			if(!addTrigger($(this), 'jqmHide', trigger))
				err("jqmAddClose must be called on initialized modals")
		});
	};

	/**
	 * Open matching modals (if not shown)
	 */
	$.fn.jqmShow=function(trigger){
		return this.each(function(){ !this._jqmShown&&show($(this), trigger); });
	};

	/**
	 * Close matching modals
	 */
	$.fn.jqmHide=function(trigger){
		return this.each(function(){ this._jqmShown&&hide($(this), trigger); });
	};

	// utility functions

	var
		err = function(msg){
			if(window.console && window.console.error) window.console.error(msg);

	}, show = function(e, t){

		/**
		 * e = modal element (as jQuery object)
		 * t = triggering element
		 *
		 * o = options
		 * z = z-index of modal
		 * v = overlay element (as jQuery object)
		 * h = hash (for jqModal <= r15 compatibility)
		 */

		var o = e.data('jqm'),
			t = t || window.event,
			z = (parseInt(e.css('z-index'))),
			z = (z > 0) ? z : 3000,
			v = $('

').addClass(o.overlayClass).css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:o.overlay/100}),

			// maintain legacy "hash" construct
			h = {w: e, c: o, o: v, t: t};

		e.css('z-index',z);

		if(o.ajax){
			var target = o.target || e,
				url = o.ajax;

			target = (typeof target == 'string') ? $(target,e) : $(target);
			if(url.substr(0,1) == '@') url = $(t).attr(url.substring(1));

			 // Load the Ajax Content (and once loaded);
			   // Fire the onLoad callback (if exists),
			   // Attach closing events to elements inside the modal that match the closingClass,
			   // and Execute the jqModal default Open Callback
			target.html(o.ajaxText).load(url,function(){
				o.onLoad && o.onLoad.call(this,h);
				open(h);
			});
		}
		else { open(h); }

	}, hide = function(e, t){
		/**
		 * e = modal element (as jQuery object)
		 * t = triggering element
		 *
		 * o = options
		 * h = hash (for jqModal <= r15 compatibility)
		 */

		var o = e.data('jqm'),
			t = t || window.event,

		// maintain legacy "hash" construct
		h = {w: e, c: o, o: e.data('jqmv'), t: t};

		close(h);

	}, onShow = function(hash){
		// onShow callback. Responsible for showing a modal and overlay.
		//  return false to stop opening modal.

		// hash object;
		//  w: (jQuery object) The modal element
		//  c: (object) The modal's options object
		//  o: (jQuery object) The overlay element
		//  t: (DOM object) The triggering element

		// display the overlay (prepend to body) if not disabled
		if(hash.c.overlay > 0)
			hash.o.prependTo('body');

		// make modal visible
		hash.w.show();

		// call focusFunc (attempts to focus on first input in modal)
		$.jqm.focusFunc(hash.w);

		return true;

	}, onHide = function(hash){
		// onHide callback. Responsible for hiding a modal and overlay.
		//  return false to stop closing modal.

		// hash object;
		//  w: (jQuery object) The modal element
		//  c: (object) The modal's options object
		//  o: (jQuery object) The overlay element
		//  t: (DOM object) The triggering element

		// hide modal and if overlay, remove overlay.
		hash.w.hide() && hash.o && hash.o.remove();

		return true;

	},  addTrigger = function(e, key, trigger){
		// addTrigger: Adds a jqmShow/jqmHide (key) event click on modal (e)
		//  to all elements that match trigger string (trigger)

		var jqm = e.data('jqm');

		// return false if e is not an initialized modal element
		if(!e.data('jqm')) return false;

		return $(trigger).each(function(){
			this[key] = this[key] || [];

			// register this modal with this trigger only once
			if($.inArray(jqm.ID,this[key]) < 0) {
				this[key].push(jqm.ID);

				// register trigger click event for this modal
				$(this).click(function(){
					var trigger = this;

					e[key](this);

					// stop trigger click event from bubbling
					return false;
				});
			}

		});

	},  open = function(h){
		// open: executes the onOpen callback + performs common tasks if successful

		// transform legacy hash into new var shortcuts
		var e = h.w,
			v = h.o,
			o = h.c;

		// execute onShow callback
		if(o.onShow(h) !== false){
			// mark modal as shown
			e[0]._jqmShown = true;

			// if modal dialog
			//
			// Bind the Keep Focus Function [F] if no other Modals are open (!A[0]) +
			// Add this modal to the opened modals stack (A) for nested modal support
			//
			// else, close dialog when overlay is clicked
			if(o.modal){ !A[0]&&F('bind'); A.push(e); }
			else e.jqmAddClose(v);

			//  Attach closing events to elements inside the modal that match the closingClass
			o.closeClass&&e.jqmAddClose($('.' + o.closeClass,e));

			// IF toTop is true and overlay exists;
			//  Add placeholder element  before modal to
			//  remember it's position in the DOM and move it to a child of the body tag (after overlay)
			o.toTop&&v&&e.before('').insertAfter(v);

			// remember overlay (for closing function)
			e.data('jqmv',v);

			// close modal if the esc key is pressed and closeOnEsc is set to true
			var modal = $(h.w);
			return $.jqm.closeOnEscFunc(modal, o);
		}

	},  close = function(h){
		// close: executes the onHide callback + performs common tasks if successful

		// transform legacy hash into new var shortcuts
		 var e = h.w,
			v = h.o,
			o = h.c;

		// execute onShow callback
		if(o.onHide(h) !== false){
			// mark modal as !shown
			e[0]._jqmShown = false;

			 // If modal, remove from modal stack.
			 // If no modals in modal stack, unbind the Keep Focus Function
			 if(o.modal){A.pop();!A[0]&&F('unbind');}

			 // IF toTop was passed and an overlay exists;
			 //  Move modal back to its "remembered" position.
			 o.toTop&&v&&$('#jqmP'+o.ID).after(e).remove();
		}

	},  F = function(t){
		// F: The Keep Focus Function (for modal: true dialos)
		// Binds or Unbinds (t) the Focus Examination Function (X) to keypresses and clicks

		$(document)[t]("keypress keydown mousedown",X);

	}, X = function(e){
		// X: The Focus Examination Function (for modal: true dialogs)

		var modal = $(e.target).data('jqm') || $(e.target).parents('.jqm-init:first').data('jqm'),
			activeModal = A[A.length-1].data('jqm');

		// allow bubbling if event target is within active modal dialog
		if(modal && modal.ID == activeModal.ID) return true;

		// else, trigger focusFunc (focus on first input element and halt bubbling)
		return $.jqm.focusFunc(activeModal);
	},

	I = 0,   // modal ID increment (for nested modals)
	A = [];  // array of active modals (used to lock interactivity to appropriate modal)

	// $.jqm, overridable defaults
	$.jqm = {
		/**
		 *  default options
		 *
		 * (Integer)   overlay      - [0-100] Translucency percentage (opacity) of the body covering overlay. Set to 0 for NO overlay, and up to 100 for a 100% opaque overlay.
		 * (String)    overlayClass - Applied to the body covering overlay. Useful for controlling overlay look (tint, background-image, &c) with CSS.
		 * (String)    closeClass   - Children of the modal element matching `closeClass` will fire the onHide event (to close the modal).
		 * (Mixed)     trigger      - Matching elements will fire the onShow event (to display the modal). Trigger can be a selector String, a jQuery collection of elements, a DOM element, or a False boolean.
		 * (String)    ajax         - URL to load content from via an AJAX request. False to disable ajax. If ajax begins with a "@", the URL is extracted from the attribute of the triggering element (e.g. use '@data-url' for; ...)
		 * (Mixed)     target       - Children of the modal element to load the ajax response into. If false, modal content will be overwritten by ajax response. Useful for retaining modal design.
		 *                            Target may be a selector string, jQuery collection of elements, or a DOM element -- and MUST exist as a child of the modal element.
		 * (String)    ajaxText     - Text shown while waiting for ajax return. Replaces HTML content of `target` element.
		 * (Boolean)   modal        - If true, user interactivity will be locked to the modal window until closed.
		 * (Boolean)   toTop        - If true, modal will be posistioned as a first child of the BODY element when opened, and its DOM posistion restored when closed. Useful for overcoming z-Index container issues.
		 * (Function)  onShow       - User defined callback function fired when modal opened.
		 * (Function)  onHide       - User defined callback function fired when modal closed.
		 * (Function)  onLoad       - User defined callback function fired when ajax content loads.
		 */
		params: {
			overlay: 50,
			overlayClass: 'jqmOverlay',
			closeClass: 'jqmClose',
			closeOnEsc: false,
			trigger: '.jqModal',
			ajax: false,
			target: false,
			ajaxText: '',
			modal: false,
			toTop: false,
			onShow: onShow,
			onHide: onHide,
			onLoad: false
		},

		// focusFunc is fired when a modal is shown, or when interaction occurs outside
		// a modal enabled dialog. Passed the modal element.
		focusFunc: function(e) { $(':input:visible:first',e).focus(); return false; },
		// closeOnEscFunc is used when closeOnEsc param is set to true.
		closeOnEscFunc: function(modal, o) {
			modal.unbind("keydown", $.jqm.closeOnEscFunc)
			if (o.closeOnEsc) {
				modal.attr("tabindex", 0);
				modal.bind("keydown", $.jqm.closeOnEscFunc, function (event) {
					if (event.keyCode == 27) {
						event.preventDefault();
						modal.jqmHide();
					}
				});
				modal.focus();
			}
		}
	};

})( jQuery );<commit_msg>simplify the scope of $.jqm.closeOnEscFunc<commit_after>/*
 * jqModal - Minimalist Modaling with jQuery
 *
 * Copyright (c) 2007-2014 Brice Burgess @IceburgBrice
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * $Version: 1.1.0 (2014.07.03 +r21)
 * Requires: jQuery 1.2.3+
 */

(function($) {

	/**
	 * Initialize a set of elements as "modals". Modals typically are popup dialogs,
	 * notices, modal windows, &c.
	 *
	 * @name jqm
	 * @param options user defined options, augments defaults.
	 * @type jQuery
	 * @cat Plugins/jqModal
	 */

	$.fn.jqm=function(options){
		return this.each(function(){
			var e = $(this),
				jqm = e.data('jqm') || $.extend({ID: I++}, $.jqm.params),
				o = $.extend(jqm,options);

			// add/extend options to modal and mark as initialized
			e.data('jqm',o).addClass('jqm-init');

			// ... Attach events to trigger showing of this modal
			o.trigger && e.jqmAddTrigger(o.trigger);
		});
	};

	/**
	 * Matching modals will have their jqmShow() method fired by attaching a
	 *   onClick event to elements matching `trigger`.
	 *
	 * @name jqmAddTrigger
	 * @param trigger a selector String, jQuery collection of elements, or a DOM element.
	 */
	$.fn.jqmAddTrigger=function(trigger){
		return this.each(function(){
			if(!addTrigger($(this), 'jqmShow', trigger))
				err("jqmAddTrigger must be called on initialized modals")
		});
	};

	/**
	 * Matching modals will have their jqmHide() method fired by attaching an
	 *   onClick event to elements matching `trigger`.
	 *
	 * @name jqmAddClose
	 * @param trigger a selector String, jQuery collection of elements, or a DOM element.
	 */
	$.fn.jqmAddClose=function(trigger){
		return this.each(function(){
			if(!addTrigger($(this), 'jqmHide', trigger))
				err("jqmAddClose must be called on initialized modals")
		});
	};

	/**
	 * Open matching modals (if not shown)
	 */
	$.fn.jqmShow=function(trigger){
		return this.each(function(){ !this._jqmShown&&show($(this), trigger); });
	};

	/**
	 * Close matching modals
	 */
	$.fn.jqmHide=function(trigger){
		return this.each(function(){ this._jqmShown&&hide($(this), trigger); });
	};

	// utility functions

	var
		err = function(msg){
			if(window.console && window.console.error) window.console.error(msg);

	}, show = function(e, t){

		/**
		 * e = modal element (as jQuery object)
		 * t = triggering element
		 *
		 * o = options
		 * z = z-index of modal
		 * v = overlay element (as jQuery object)
		 * h = hash (for jqModal <= r15 compatibility)
		 */

		var o = e.data('jqm'),
			t = t || window.event,
			z = (parseInt(e.css('z-index'))),
			z = (z > 0) ? z : 3000,
			v = $('

').addClass(o.overlayClass).css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:o.overlay/100}),

			// maintain legacy "hash" construct
			h = {w: e, c: o, o: v, t: t};

		e.css('z-index',z);

		if(o.ajax){
			var target = o.target || e,
				url = o.ajax;

			target = (typeof target == 'string') ? $(target,e) : $(target);
			if(url.substr(0,1) == '@') url = $(t).attr(url.substring(1));

			 // Load the Ajax Content (and once loaded);
			   // Fire the onLoad callback (if exists),
			   // Attach closing events to elements inside the modal that match the closingClass,
			   // and Execute the jqModal default Open Callback
			target.html(o.ajaxText).load(url,function(){
				o.onLoad && o.onLoad.call(this,h);
				open(h);
			});
		}
		else { open(h); }

	}, hide = function(e, t){
		/**
		 * e = modal element (as jQuery object)
		 * t = triggering element
		 *
		 * o = options
		 * h = hash (for jqModal <= r15 compatibility)
		 */

		var o = e.data('jqm'),
			t = t || window.event,

		// maintain legacy "hash" construct
		h = {w: e, c: o, o: e.data('jqmv'), t: t};

		close(h);

	}, onShow = function(hash){
		// onShow callback. Responsible for showing a modal and overlay.
		//  return false to stop opening modal.

		// hash object;
		//  w: (jQuery object) The modal element
		//  c: (object) The modal's options object
		//  o: (jQuery object) The overlay element
		//  t: (DOM object) The triggering element

		// display the overlay (prepend to body) if not disabled
		if(hash.c.overlay > 0)
			hash.o.prependTo('body');

		// make modal visible
		hash.w.show();

		// call focusFunc (attempts to focus on first input in modal)
		$.jqm.focusFunc(hash.w);

		return true;

	}, onHide = function(hash){
		// onHide callback. Responsible for hiding a modal and overlay.
		//  return false to stop closing modal.

		// hash object;
		//  w: (jQuery object) The modal element
		//  c: (object) The modal's options object
		//  o: (jQuery object) The overlay element
		//  t: (DOM object) The triggering element

		// hide modal and if overlay, remove overlay.
		hash.w.hide() && hash.o && hash.o.remove();

		return true;

	},  addTrigger = function(e, key, trigger){
		// addTrigger: Adds a jqmShow/jqmHide (key) event click on modal (e)
		//  to all elements that match trigger string (trigger)

		var jqm = e.data('jqm');

		// return false if e is not an initialized modal element
		if(!e.data('jqm')) return false;

		return $(trigger).each(function(){
			this[key] = this[key] || [];

			// register this modal with this trigger only once
			if($.inArray(jqm.ID,this[key]) < 0) {
				this[key].push(jqm.ID);

				// register trigger click event for this modal
				$(this).click(function(){
					var trigger = this;

					e[key](this);

					// stop trigger click event from bubbling
					return false;
				});
			}

		});

	},  open = function(h){
		// open: executes the onOpen callback + performs common tasks if successful

		// transform legacy hash into new var shortcuts
		var e = h.w,
			v = h.o,
			o = h.c;

		// execute onShow callback
		if(o.onShow(h) !== false){
			// mark modal as shown
			e[0]._jqmShown = true;

			// if modal dialog
			//
			// Bind the Keep Focus Function [F] if no other Modals are open (!A[0]) +
			// Add this modal to the opened modals stack (A) for nested modal support
			//
			// else, close dialog when overlay is clicked
			if(o.modal){ !A[0]&&F('bind'); A.push(e); }
			else e.jqmAddClose(v);

			//  Attach closing events to elements inside the modal matching closingClass
			o.closeClass&&e.jqmAddClose($('.' + o.closeClass,e));

			// IF toTop is true and overlay exists;
			//  Add placeholder element  before modal to
			//  remember it's position in the DOM and move it to a child of the body tag (after overlay)
			o.toTop&&v&&e.before('').insertAfter(v);

			// remember overlay (for closing function)
			e.data('jqmv',v);

			// close modal if the esc key is pressed and closeOnEsc is set to true
			e.unbind("keydown",$.jqm.closeOnEscFunc);
			if(o.closeOnEsc) {
				e.attr("tabindex", 0).bind("keydown",$.jqm.closeOnEscFunc).focus();
			}
		}

	},  close = function(h){
		// close: executes the onHide callback + performs common tasks if successful

		// transform legacy hash into new var shortcuts
		 var e = h.w,
			v = h.o,
			o = h.c;

		// execute onShow callback
		if(o.onHide(h) !== false){
			// mark modal as !shown
			e[0]._jqmShown = false;

			 // If modal, remove from modal stack.
			 // If no modals in modal stack, unbind the Keep Focus Function
			 if(o.modal){A.pop();!A[0]&&F('unbind');}

			 // IF toTop was passed and an overlay exists;
			 //  Move modal back to its "remembered" position.
			 o.toTop&&v&&$('#jqmP'+o.ID).after(e).remove();
		}

	},  F = function(t){
		// F: The Keep Focus Function (for modal: true dialos)
		// Binds or Unbinds (t) the Focus Examination Function (X) to keypresses and clicks

		$(document)[t]("keypress keydown mousedown",X);

	}, X = function(e){
		// X: The Focus Examination Function (for modal: true dialogs)

		var modal = $(e.target).data('jqm') || $(e.target).parents('.jqm-init:first').data('jqm'),
			activeModal = A[A.length-1].data('jqm');

		// allow bubbling if event target is within active modal dialog
		if(modal && modal.ID == activeModal.ID) return true;

		// else, trigger focusFunc (focus on first input element and halt bubbling)
		return $.jqm.focusFunc(activeModal);
	},

	I = 0,   // modal ID increment (for nested modals)
	A = [];  // array of active modals (used to lock interactivity to appropriate modal)

	// $.jqm, overridable defaults
	$.jqm = {
		/**
		 *  default options
		 *
		 * (Integer)   overlay      - [0-100] Translucency percentage (opacity) of the body covering overlay. Set to 0 for NO overlay, and up to 100 for a 100% opaque overlay.
		 * (String)    overlayClass - Applied to the body covering overlay. Useful for controlling overlay look (tint, background-image, &c) with CSS.
		 * (String)    closeClass   - Children of the modal element matching `closeClass` will fire the onHide event (to close the modal).
		 * (Mixed)     trigger      - Matching elements will fire the onShow event (to display the modal). Trigger can be a selector String, a jQuery collection of elements, a DOM element, or a False boolean.
		 * (String)    ajax         - URL to load content from via an AJAX request. False to disable ajax. If ajax begins with a "@", the URL is extracted from the attribute of the triggering element (e.g. use '@data-url' for; ...)
		 * (Mixed)     target       - Children of the modal element to load the ajax response into. If false, modal content will be overwritten by ajax response. Useful for retaining modal design.
		 *                            Target may be a selector string, jQuery collection of elements, or a DOM element -- and MUST exist as a child of the modal element.
		 * (String)    ajaxText     - Text shown while waiting for ajax return. Replaces HTML content of `target` element.
		 * (Boolean)   modal        - If true, user interactivity will be locked to the modal window until closed.
		 * (Boolean)   toTop        - If true, modal will be posistioned as a first child of the BODY element when opened, and its DOM posistion restored when closed. Useful for overcoming z-Index container issues.
		 * (Function)  onShow       - User defined callback function fired when modal opened.
		 * (Function)  onHide       - User defined callback function fired when modal closed.
		 * (Function)  onLoad       - User defined callback function fired when ajax content loads.
		 */
		params: {
			overlay: 50,
			overlayClass: 'jqmOverlay',
			closeClass: 'jqmClose',
			closeOnEsc: false,
			trigger: '.jqModal',
			ajax: false,
			target: false,
			ajaxText: '',
			modal: false,
			toTop: false,
			onShow: onShow,
			onHide: onHide,
			onLoad: false
		},

		// focusFunc is fired when a modal is shown, or when interaction occurs outside
		// a modal enabled dialog. Passed the modal element.
		focusFunc: function(e) { $(':input:visible:first',e).focus(); return false; },
		// closeOnEscFunc is attached to modals where closeOnEsc param true.
		closeOnEscFunc: function(event){
			if (event.keyCode == 27) {
				$(this).jqmHide();
				return false;
			}
		}
	};

})( jQuery );<|endoftext|>


<commit_before>/**
 * Game.js description here
 *
 * @author fridek
 * @date 16.04.11
 * @version $
 */

var Game = Class.extend({
    world: null,

    currentMap: null,
    fixDef: null,
    bodyDef: null,
    canvas: null,

    width: null,
    height: null,

    init: function (canvas) {
        this.canvas = document.getElementById("canvas");
        this.height = this.canvas.offsetHeight;
        this.width = this.canvas.offsetWidth;

         var    b2Vec2 = Box2D.Common.Math.b2Vec2,
                b2AABB = Box2D.Collision.b2AABB,
                b2BodyDef = Box2D.Dynamics.b2BodyDef,
                b2Body = Box2D.Dynamics.b2Body,
                b2FixtureDef = Box2D.Dy namics.b2FixtureDef,
                b2Fixture = Box2D.Dynamics.b2Fixture,
                b2World = Box2D.Dynamics.b2World,
                b2MassData = Box2D.Collision.Shapes.b2MassData,
                b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,
                b2CircleShape = Box2D.Collision.Shapes.b2CircleShape,
                b2DebugDraw = Box2D.Dynamics.b2DebugDraw,
                b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef;

         this.world = new b2World(
            new b2Vec2(0, 10),    //gravity
            true                 //allow sleep
         );

         this.fixDef = new b2FixtureDef;
         this.fixDef.density = 1.0;
         this.fixDef.friction = 0.5;
         this.fixDef.restitution = 0.2;

         this.bodyDef = new b2BodyDef;

         //create ground
         this.bodyDef.type = b2Body.b2_staticBody;
         this.fixDef.shape = new b2PolygonShape;
         this.fixDef.shape.SetAsBox(this.width / 30, 2);
         // bottom
         this.bodyDef.position.Set(10, this.height / 30 + 1.8);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);
         // top
         this.bodyDef.position.Set(10, -1.8);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);

         this.fixDef.shape.SetAsBox(2, this.height / 30);
         // left
         this.bodyDef.position.Set(-1.8, 13);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);
         // right
         this.bodyDef.position.Set(this.width / 30 + 1.8, 13);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);

         this.maps = new Maps(this);
         this.maps.makeMap('testmap');

         //setup debug draw
         var debugDraw = new b2DebugDraw();
			debugDraw.SetSprite(this.canvas.getContext("2d"));
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.5);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			this.world.SetDebugDraw(debugDraw);

         var that = this;
         window.setInterval(function() {that.step.apply(that);}, 1000 / 30);
    },

    step: function () {
        this.world.Step(1 / 30, 10, 10);
        this.world.DrawDebugData();
        this.world.ClearForces();
    }
});<commit_msg>quickfix<commit_after>/**
 * Game.js description here
 *
 * @author fridek
 * @date 16.04.11
 * @version $
 */

var Game = Class.extend({
    world: null,

    currentMap: null,
    fixDef: null,
    bodyDef: null,
    canvas: null,

    width: null,
    height: null,

    init: function (canvas) {
        this.canvas = document.getElementById("canvas");
        this.height = this.canvas.offsetHeight;
        this.width = this.canvas.offsetWidth;

         var    b2Vec2 = Box2D.Common.Math.b2Vec2,
                b2AABB = Box2D.Collision.b2AABB,
                b2BodyDef = Box2D.Dynamics.b2BodyDef,
                b2Body = Box2D.Dynamics.b2Body,
                b2FixtureDef = Box2D.Dynamics.b2FixtureDef,
                b2Fixture = Box2D.Dynamics.b2Fixture,
                b2World = Box2D.Dynamics.b2World,
                b2MassData = Box2D.Collision.Shapes.b2MassData,
                b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,
                b2CircleShape = Box2D.Collision.Shapes.b2CircleShape,
                b2DebugDraw = Box2D.Dynamics.b2DebugDraw,
                b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef;

         this.world = new b2World(
            new b2Vec2(0, 10),    //gravity
            true                 //allow sleep
         );

         this.fixDef = new b2FixtureDef;
         this.fixDef.density = 1.0;
         this.fixDef.friction = 0.5;
         this.fixDef.restitution = 0.2;

         this.bodyDef = new b2BodyDef;

         //create ground
         this.bodyDef.type = b2Body.b2_staticBody;
         this.fixDef.shape = new b2PolygonShape;
         this.fixDef.shape.SetAsBox(this.width / 30, 2);
         // bottom
         this.bodyDef.position.Set(10, this.height / 30 + 1.8);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);
         // top
         this.bodyDef.position.Set(10, -1.8);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);

         this.fixDef.shape.SetAsBox(2, this.height / 30);
         // left
         this.bodyDef.position.Set(-1.8, 13);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);
         // right
         this.bodyDef.position.Set(this.width / 30 + 1.8, 13);
         this.world.CreateBody(this.bodyDef).CreateFixture(this.fixDef);

         this.maps = new Maps(this);
         this.maps.makeMap('testmap');

         //setup debug draw
         var debugDraw = new b2DebugDraw();
			debugDraw.SetSprite(this.canvas.getContext("2d"));
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.5);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			this.world.SetDebugDraw(debugDraw);

         var that = this;
         window.setInterval(function() {that.step.apply(that);}, 1000 / 30);
    },

    step: function () {
        this.world.Step(1 / 30, 10, 10);
        this.world.DrawDebugData();
        this.world.ClearForces();
    }
});<|endoftext|>


<commit_before>
require("../scss/app.scss");

var $ = require("jquery");
var Backbone = require("backbone");
Backbone.$ = $;
var Viewmaster = require("viewmaster");
var Promise = require("bluebird");
Promise.longStackTraces();
var key = require("keymaster");

var Panes = require("./Panes");
var Editor = require("./Editor");
var Preview = require("./Preview");
var Toolbar = require("./Toolbar");
var Dropdown = require("./Dropdown");
var SelectMenu = require("./SelectMenu");
var TitleForm = require("./TitleForm");
var errorReporter = require("./errorReporter");

var Layout = Viewmaster.extend({

    template: function() {
        return "

";
    },

    constructor: function(opts) {
        var self = this;
        Viewmaster.prototype.constructor.apply(this, arguments);

        this.toolbar = new Toolbar({
            model: this.model
        });

        this.editor = new Editor({
            model: this.model
        });

        this.appendView(".container", this.toolbar);

        this.panes = new Panes();
        this.appendView(".container", this.panes);

        this.panes.setView(".left-pane", this.editor);

        this.preview = new Preview({
            model: this.model
        });
        this.panes.setView(".right-pane", this.preview);

        self.listenTo(self.toolbar, "all", function(eventName, arg) {
            self.editor.trigger(eventName, arg);
        });

        this.model.initialized.then(function() {
            self.panes.setPos(500);
        });

        self.listenTo(self.toolbar, "saveDraft", self.saveDraft.bind(self));
        key("ctrl+s", function(e) {
            self.saveDraft();
            return false;
        });

        self.listenTo(self.toolbar, "publish", function() {
            self.model.publish(self.editor.getContent())
            .then(function() {
                window.location = self.model.get("publicUrl");
            }, errorReporter("Failed to publish"));
        });

        self.toolbar.on("new", function(e) {
            var form = new TitleForm();
            Dropdown.display(e.target, form);

            form.getTitle().then(function(t) {
                if (typeof self.model.createNew === "function") {
                    return self.model.reset(self.model.createNew(t));
                }
                throw new Error("createNew is not implemented");
            }).then(function() {
                form.parent.remove();
            }, errorReporter("Failed to create new page"));

        });

        self.listenTo(self.toolbar, "open", function(e) {

            var menu = new SelectMenu({
                title: "Open",
            });

            Dropdown.display(e.target, menu);

            menu.selectFrom(self.model.fetchPageList())
            .then(function(page) {
                if (typeof self.model.fetchPage === "function") {
                    return self.model.reset(self.model.fetchPage(page));
                }
                throw new Error("fetchPage is not implemented");
            }).then(function() {
                menu.parent.remove();
            });

        });

        self.listenTo(self.toolbar, "delete", function(e) {
            self.model.delete().catch(errorReporter("Failed to delete page"));
        });

        self.listenTo(self.toolbar, "externalPreview", function() {
            window.open(self.model.get("draftUrl") , "_blank");
        });

    },

    saveDraft: function() {
        var self = this;
        self.model.saveDraft(self.editor.getContent())
        .then(function() {
            self.preview.refresh();
        }, errorReporter("Failed to save draft"));
    }

});

module.exports = Layout;
<commit_msg>confirm delete<commit_after>
require("../scss/app.scss");

var $ = require("jquery");
var Backbone = require("backbone");
Backbone.$ = $;
var Viewmaster = require("viewmaster");
var Promise = require("bluebird");
Promise.longStackTraces();
var key = require("keymaster");

var Panes = require("./Panes");
var Editor = require("./Editor");
var Preview = require("./Preview");
var Toolbar = require("./Toolbar");
var Dropdown = require("./Dropdown");
var SelectMenu = require("./SelectMenu");
var TitleForm = require("./TitleForm");
var errorReporter = require("./errorReporter");

var Layout = Viewmaster.extend({

    template: function() {
        return "

";
    },

    constructor: function(opts) {
        var self = this;
        Viewmaster.prototype.constructor.apply(this, arguments);

        this.toolbar = new Toolbar({
            model: this.model
        });

        this.editor = new Editor({
            model: this.model
        });

        this.appendView(".container", this.toolbar);

        this.panes = new Panes();
        this.appendView(".container", this.panes);

        this.panes.setView(".left-pane", this.editor);

        this.preview = new Preview({
            model: this.model
        });
        this.panes.setView(".right-pane", this.preview);

        self.listenTo(self.toolbar, "all", function(eventName, arg) {
            self.editor.trigger(eventName, arg);
        });

        this.model.initialized.then(function() {
            self.panes.setPos(500);
        });

        self.listenTo(self.toolbar, "saveDraft", self.saveDraft.bind(self));
        key("ctrl+s", function(e) {
            self.saveDraft();
            return false;
        });

        self.listenTo(self.toolbar, "publish", function() {
            self.model.publish(self.editor.getContent())
            .then(function() {
                window.location = self.model.get("publicUrl");
            }, errorReporter("Failed to publish"));
        });

        self.toolbar.on("new", function(e) {
            var form = new TitleForm();
            Dropdown.display(e.target, form);

            form.getTitle().then(function(t) {
                if (typeof self.model.createNew === "function") {
                    return self.model.reset(self.model.createNew(t));
                }
                throw new Error("createNew is not implemented");
            }).then(function() {
                form.parent.remove();
            }, errorReporter("Failed to create new page"));

        });

        self.listenTo(self.toolbar, "open", function(e) {

            var menu = new SelectMenu({
                title: "Open",
            });

            Dropdown.display(e.target, menu);

            menu.selectFrom(self.model.fetchPageList())
            .then(function(page) {
                if (typeof self.model.fetchPage === "function") {
                    return self.model.reset(self.model.fetchPage(page));
                }
                throw new Error("fetchPage is not implemented");
            }).then(function() {
                menu.parent.remove();
            });

        });

        self.listenTo(self.toolbar, "delete", function(e) {
            if (!window.confirm("Delete this page?")) return;
            self.model.delete().catch(errorReporter("Failed to delete page"));
        });

        self.listenTo(self.toolbar, "externalPreview", function() {
            window.open(self.model.get("draftUrl") , "_blank");
        });

    },

    saveDraft: function() {
        var self = this;
        self.model.saveDraft(self.editor.getContent())
        .then(function() {
            self.preview.refresh();
        }, errorReporter("Failed to save draft"));
    }

});

module.exports = Layout;
<|endoftext|>


<commit_before>/*
  Youtube Player with Playlist (v2.22)
  https://github.com/carloscabo/responsive-youtube-player-with-playlist
  by Carlos Cabo (@putuko)
*/

var RYPP = (function($, undefined) {
  'use strict';

  function Rypp(el, api_key, options) {

    if (typeof api_key === 'undefined') {
      console.log("Youtube API V3 requires a valid API KEY.\nFollow the instructions at: https://developers.google.com/youtube/v3/getting-started");
      return false;
    }

    // DOM Elements container
    this.DOM = {};

    // Default settings container
    this.options = {};

    // Data / urls
    this.data = {
      // Playlist url
      ytapi: {
        playlist_info: 'https://www.googleapis.com/youtube/v3/playlists?part=snippet&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
        playlist: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
        pl_ID: '',
        videolist: 'https://www.googleapis.com/youtube/v3/videos?part=snippet,status&maxResults=50&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
      },
      temp_vl: [], // Temporary videolist
      firsttime: true,
      ismobile: (typeof window.orientation !== 'undefined'),
      ispopulated: false
    };

    // Initialize
    this.init(el, api_key, options);
  }

  // Prototype for the instance
  Rypp.prototype = {

    init: function(el, api_key, options) {

      // Api key
      this.api_key = api_key;

      // Default options
      this.options = {
        update_title_desc: false,
        autoplay: true,
        autonext: true,
        loop: true,
        mute: false,
        debug: false
      };

      // Merge initial options
      if (typeof options !== 'undefined') {
        $.extend(this.options, options);
      }

      // DOM elements
      this.DOM = {};
      this.DOM.$el = $(el);
      this.DOM.$playlc = this.DOM.$el.find('.RYPP-playlist');
      this.DOM.$items =  this.DOM.$el.find('.RYPP-items');
      this.DOM.$videoc = this.DOM.$el.find('.RYPP-video');
      this.DOM.$title  = this.DOM.$el.find('.RYPP-title');
      this.DOM.$desc   = this.DOM.$el.find('.RYPP-desc');

      // YT Player object
      this.DOM.$el[0].ytplayer = null;

      // Unique player ID
      this.data.player_uid = (Math.random().toString(16).substr(2,8));
      this.DOM.$el.attr('data-rypp',this.data.player_uid).find('.RYPP-video-player').attr('id','RYPP-vp-'+this.data.player_uid).attr('name','RYPP-vp-'+this.data.player_uid);
      if (this.options.debug) console.log('Unique ID: RYPP-vp-'+this.data.player_uid);

      // Link JS only once
      if (typeof window.YT === 'undefined') {
        var
          tag = document.createElement('script'),
          hID = document.getElementsByTagName('head')[0];
        // Add youtube API in HEAD
        // tag.src = "https://www.youtube.com/iframe_api";
        tag.src = 'https://www.youtube.com/iframe_api?version=3';
        hID.appendChild(tag);
      } else {
        this.addAPIPlayer();
      }

    },

    onYTIframeAPIReadyCallback: function() {
      this.addAPIPlayer();
    },

    updateTitleDesc: function() {
      var
        that = this,
        resources_id = this.DOM.$el.attr('data-playlist'),
        url  = this.data.ytapi.playlist_info.replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);

      $.ajaxSetup ({cache: false});
      $.ajax(url, {
        context: this,
        dataType: 'json',
        crossDomain: true,
        error: function(){
          // Not successful
        },
        success: function(data){
          // console.log(data);
          this.DOM.$title.html( data.items[0].snippet.title );
          this.DOM.$desc.html( data.items[0].snippet.description );
        }
      });
    },

    populatePlaylist: function() {

      if( this.options.update_title_desc ) {
        if (this.options.debug) console.log(this.data.player_uid+': Updating playlist title / desc');
        this.updateTitleDesc();
      }

      // Empty playlist
      if (this.options.debug) console.log(this.data.player_uid+': Populating playlist');
      this.DOM.$items.html('').append($('
'));

      // Now we read the video list from playlist data or from IDs...
      if (this.DOM.$el.attr('data-playlist')) {
        this.data.pl_ID = this.DOM.$el.attr('data-playlist');
        this.getVideosFrom(
          'playlist',
          this.data.pl_ID
        );
      } else if (this.DOM.$el.attr('data-ids')) {
        var vl = this.DOM.$el.attr('data-ids');
        // Clean spaces
        vl = ($.map(vl.split(','),$.trim)).join(',');
        this.getVideosFrom(
          'videolist',
          vl
        );
      }
    },

    addAPIPlayer: function() {
      var that = this;

      window.YTConfig = { 'host': 'https://www.youtube.com' };
      this.DOM.$el[0].ytplayer = new YT.Player('RYPP-vp-'+that.data.player_uid, {
        // height: '390',
        // width: '640',
        playerVars: {
          // controls: 0,
          // showinfo: 0 ,
          // autoplay: 0,
          // html5: 1,
          enablejsapi: 1,
          rel: 0,
          modestbranding: 1,
          wmode: 'transparent'
        },
        events: {
          'onReady': function(){
            if (that.options.debug)console.log(that.data.player_uid+': ytplayer ready');
            that.onPlayerReady();
          },
          'onStateChange': function(e){
            that.onPlayerStateChange(e);
          },
          'onError': function(e) {
            console.log(e);
          }
        }
      });
    },

    // Ready to play
    onPlayerReady: function() {
      if (this.options.debug) console.log(this.data.player_uid+': ytplayer ready callback');
      this.populatePlaylist();
      // this.startPlayList();
    },

    // When video finish
    onPlayerStateChange: function(e){
      var
        that = this;

      if (typeof e !== 'undefined') {

        // On video loaded?
        if(e.data === -1 && this.data.firsttime) {
          if(!this.options.autoplay && !this.data.ismobile) { // Is desktop
            this.DOM.$el[0].ytplayer.stopVideo();
            this.data.firsttime = false;
          }
          if(this.options.mute) {
            this.DOM.$el[0].ytplayer.mute();
          }
        }

        // If mobile and stored in buffer we STOP the video in mobile devices
        if(e.data === 3 && this.data.ismobile && this.data.firsttime) {
          setTimeout(function(){
            that.DOM.$el[0].ytplayer.stopVideo();
            that.data.firsttime = false;
          }, 500);
        }

        // Play next only if not mobile
        var next = null;
        if(e.data === 0 && !this.data.ismobile && this.options.autonext) {
          next = this.DOM.$items.find('li.selected').next();
          if (next.length === 0 && this.options.loop) {
            next = this.DOM.$items.find('li').first();
          }
          next.trigger('click');
        }

      }

    },

    // Get video from data-ids or playlist
    // It's impossible to know if a video in a playlist its available or currently deleted. So we do 2 request, first we get all the video IDs an then we ask for info about them.
    getVideosFrom: function(kind, resources_id, page_token) {
      var
        that = this,
        url  = this.data.ytapi[kind].replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);

      if (typeof page_token !== 'undefined') {
        url += '&pageToken=' + page_token;
      }

      $.ajaxSetup ({cache: false});
      $.ajax(url, {
        context: this,
        dataType: 'json',
        crossDomain: true,
        error: function(){
          // Not successful
        },
        success: function(data){

          // We queried for a playlist
          if (data.kind === 'youtube#playlistItemListResponse') {

            var video_set = [];

            // We get the video IDs and query gain, its the only way to be sure that all the videos are available, and not were deleted :(
            $.map(data.items, function(val,idx) {
              if (typeof val.snippet.resourceId.videoId !== 'undefined') {
                // Add video to temporary list
                video_set.push( val.snippet.resourceId.videoId );
                // return val.snippet.resourceId.videoId;
              }
            });
            that.data.temp_vl.push( video_set );

            // If there are several pages we ask for next
            if (typeof data.nextPageToken !== 'undefined' && data.nextPageToken !== '') {
              that.getVideosFrom(
                'playlist',
                that.data.pl_ID,
                data.nextPageToken
              );
            } else {
              // No more pages... we process the videos
              for (var j = 0, len_pl = that.data.temp_vl.length; j < len_pl; j++) {
                video_set = that.data.temp_vl.shift();
                that.getVideosFrom('videolist', video_set.join(','));
              }
            }

          } else if (data.kind === 'youtube#videoListResponse') {

            // Videos froma  Videolist
            for (var i = 0, len = data.items.length; i < len; i++) {
              var item = data.items[i];

              // Videos without thumbnail, deleted or rejected are not included in the player!
              if (
                $.inArray(item.status.uploadStatus, ['rejected', 'deleted', 'failed']) === -1 &&
                typeof item.snippet.thumbnails !== 'undefined'
              ) {
                var
                  vid = item.id,
                  tit = item.snippet.title,
                  aut = item.snippet.channelTitle,
                  thu = item.snippet.thumbnails.default.url;
                that.addVideo2Playlist(vid, tit, aut, thu);
              }
              if ( $.isEmptyObject( that.data.temp_vl ) ) {
                this.startPlayList();
              }
            }
          }
        }
      });
    },

    // All videos are supossed to be loaded
    // lets start the playlist
    startPlayList: function() {

      var
        D = this.DOM,
        vid = null,
        that = this;

      // Click on playlist elemnts
      D.$items.on('click', 'li', function(e) {
        e.preventDefault();
        D.$items.find('li').removeClass('selected');
        $(this).addClass('selected');
        vid = $(this).data('video-id');
        // Call YT API function
        that.DOM.$el[0].ytplayer.loadVideoById(vid);
        // If we are in mobile we must stop
        if (that.data.ismobile) {
          that.data.firsttime = true;
        }
      });

      // Select first if none
      if (D.$items.find('li.selected').length === 0) {
        if ( this.options.autoplay ) {
          D.$items.find('li').first().click();
        }
      }
    },

    // Add video block to playlist
    addVideo2Playlist: function(vid, tit, aut, thu) {
      var
        D  = this.DOM;
      $('

'+tit+'
'+aut+'

').appendTo(D.$items.find('ol'));
    },

  }; // prototypes

  return Rypp;

}(jQuery));

// YOUTUBE API CALLBACK
function onYouTubeIframeAPIReady() {
  // console.log( 'Youtube API script loaded. Start players.' );
  $('[data-rypp]').each(function(idx, el) {
    $(el)[0].rypp_data_obj.onYTIframeAPIReadyCallback();
  });
}

// JQuery hook
$.fn.rypp = function(api_key, options) {
  return this.each(function() {
    // Store object in DOM element
    this.rypp_data_obj = new RYPP(this, api_key, options);
  });
};
<commit_msg>Add playable_region option<commit_after>/*
  Youtube Player with Playlist (v2.22)
  https://github.com/carloscabo/responsive-youtube-player-with-playlist
  by Carlos Cabo (@putuko)
*/

var RYPP = (function($, undefined) {
  'use strict';

  function Rypp(el, api_key, options) {

    if (typeof api_key === 'undefined') {
      console.log("Youtube API V3 requires a valid API KEY.\nFollow the instructions at: https://developers.google.com/youtube/v3/getting-started");
      return false;
    }

    // DOM Elements container
    this.DOM = {};

    // Default settings container
    this.options = {};

    // Data / urls
    this.data = {
      // Playlist url
      ytapi: {
        playlist_info: 'https://www.googleapis.com/youtube/v3/playlists?part=snippet&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
        playlist: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
        pl_ID: '',
        videolist: 'https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,status&maxResults=50&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
      },
      temp_vl: [], // Temporary videolist
      firsttime: true,
      ismobile: (typeof window.orientation !== 'undefined'),
      ispopulated: false
    };

    // Initialize
    this.init(el, api_key, options);
  }

  // Prototype for the instance
  Rypp.prototype = {

    init: function(el, api_key, options) {

      // Api key
      this.api_key = api_key;

      // Default options
      this.options = {
        update_title_desc: false,
        autoplay: true,
        autonext: true,
        loop: true,
        mute: false,
        playable_region: false,
        debug: false
      };

      // Merge initial options
      if (typeof options !== 'undefined') {
        $.extend(this.options, options);
      }

      // DOM elements
      this.DOM = {};
      this.DOM.$el = $(el);
      this.DOM.$playlc = this.DOM.$el.find('.RYPP-playlist');
      this.DOM.$items =  this.DOM.$el.find('.RYPP-items');
      this.DOM.$videoc = this.DOM.$el.find('.RYPP-video');
      this.DOM.$title  = this.DOM.$el.find('.RYPP-title');
      this.DOM.$desc   = this.DOM.$el.find('.RYPP-desc');

      // YT Player object
      this.DOM.$el[0].ytplayer = null;

      // Unique player ID
      this.data.player_uid = (Math.random().toString(16).substr(2,8));
      this.DOM.$el.attr('data-rypp',this.data.player_uid).find('.RYPP-video-player').attr('id','RYPP-vp-'+this.data.player_uid).attr('name','RYPP-vp-'+this.data.player_uid);
      if (this.options.debug) console.log('Unique ID: RYPP-vp-'+this.data.player_uid);

      // Link JS only once
      if (typeof window.YT === 'undefined') {
        var
          tag = document.createElement('script'),
          hID = document.getElementsByTagName('head')[0];
        // Add youtube API in HEAD
        // tag.src = "https://www.youtube.com/iframe_api";
        tag.src = 'https://www.youtube.com/iframe_api?version=3';
        hID.appendChild(tag);
      } else {
        this.addAPIPlayer();
      }

    },

    onYTIframeAPIReadyCallback: function() {
      this.addAPIPlayer();
    },

    updateTitleDesc: function() {
      var
        that = this,
        resources_id = this.DOM.$el.attr('data-playlist'),
        url  = this.data.ytapi.playlist_info.replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);

      $.ajaxSetup ({cache: false});
      $.ajax(url, {
        context: this,
        dataType: 'json',
        crossDomain: true,
        error: function(){
          // Not successful
        },
        success: function(data){
          // console.log(data);
          this.DOM.$title.html( data.items[0].snippet.title );
          this.DOM.$desc.html( data.items[0].snippet.description );
        }
      });
    },

    populatePlaylist: function() {

      if( this.options.update_title_desc ) {
        if (this.options.debug) console.log(this.data.player_uid+': Updating playlist title / desc');
        this.updateTitleDesc();
      }

      // Empty playlist
      if (this.options.debug) console.log(this.data.player_uid+': Populating playlist');
      this.DOM.$items.html('').append($('
'));

      // Now we read the video list from playlist data or from IDs...
      if (this.DOM.$el.attr('data-playlist')) {
        this.data.pl_ID = this.DOM.$el.attr('data-playlist');
        this.getVideosFrom(
          'playlist',
          this.data.pl_ID
        );
      } else if (this.DOM.$el.attr('data-ids')) {
        var vl = this.DOM.$el.attr('data-ids');
        // Clean spaces
        vl = ($.map(vl.split(','),$.trim)).join(',');
        this.getVideosFrom(
          'videolist',
          vl
        );
      }
    },

    addAPIPlayer: function() {
      var that = this;

      window.YTConfig = { 'host': 'https://www.youtube.com' };
      this.DOM.$el[0].ytplayer = new YT.Player('RYPP-vp-'+that.data.player_uid, {
        // height: '390',
        // width: '640',
        playerVars: {
          // controls: 0,
          // showinfo: 0 ,
          // autoplay: 0,
          // html5: 1,
          enablejsapi: 1,
          rel: 0,
          modestbranding: 1,
          wmode: 'transparent'
        },
        events: {
          'onReady': function(){
            if (that.options.debug)console.log(that.data.player_uid+': ytplayer ready');
            that.onPlayerReady();
          },
          'onStateChange': function(e){
            that.onPlayerStateChange(e);
          },
          'onError': function(e) {
            console.log(e);
          }
        }
      });
    },

    // Ready to play
    onPlayerReady: function() {
      if (this.options.debug) console.log(this.data.player_uid+': ytplayer ready callback');
      this.populatePlaylist();
      // this.startPlayList();
    },

    // When video finish
    onPlayerStateChange: function(e){
      var
        that = this;

      if (typeof e !== 'undefined') {

        // On video loaded?
        if(e.data === -1 && this.data.firsttime) {
          if(!this.options.autoplay && !this.data.ismobile) { // Is desktop
            this.DOM.$el[0].ytplayer.stopVideo();
            this.data.firsttime = false;
          }
          if(this.options.mute) {
            this.DOM.$el[0].ytplayer.mute();
          }
        }

        // If mobile and stored in buffer we STOP the video in mobile devices
        if(e.data === 3 && this.data.ismobile && this.data.firsttime) {
          setTimeout(function(){
            that.DOM.$el[0].ytplayer.stopVideo();
            that.data.firsttime = false;
          }, 500);
        }

        // Play next only if not mobile
        var next = null;
        if(e.data === 0 && !this.data.ismobile && this.options.autonext) {
          next = this.DOM.$items.find('li.selected').next();
          if (next.length === 0 && this.options.loop) {
            next = this.DOM.$items.find('li').first();
          }
          next.trigger('click');
        }

      }

    },

    // Get video from data-ids or playlist
    // It's impossible to know if a video in a playlist its available or currently deleted. So we do 2 request, first we get all the video IDs an then we ask for info about them.
    getVideosFrom: function(kind, resources_id, page_token) {
      var
        that = this,
        url  = this.data.ytapi[kind].replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);

      if (typeof page_token !== 'undefined') {
        url += '&pageToken=' + page_token;
      }

      $.ajaxSetup ({cache: false});
      $.ajax(url, {
        context: this,
        dataType: 'json',
        crossDomain: true,
        error: function(){
          // Not successful
        },
        success: function(data){

          // We queried for a playlist
          if (data.kind === 'youtube#playlistItemListResponse') {

            var video_set = [];

            // We get the video IDs and query gain, its the only way to be sure that all the videos are available, and not were deleted :(
            $.map(data.items, function(val,idx) {
              if (typeof val.snippet.resourceId.videoId !== 'undefined') {
                // Add video to temporary list
                video_set.push( val.snippet.resourceId.videoId );
                // return val.snippet.resourceId.videoId;
              }
            });
            that.data.temp_vl.push( video_set );

            // If there are several pages we ask for next
            if (typeof data.nextPageToken !== 'undefined' && data.nextPageToken !== '') {
              that.getVideosFrom(
                'playlist',
                that.data.pl_ID,
                data.nextPageToken
              );
            } else {
              // No more pages... we process the videos
              for (var j = 0, len_pl = that.data.temp_vl.length; j < len_pl; j++) {
                video_set = that.data.temp_vl.shift();
                that.getVideosFrom('videolist', video_set.join(','));
              }
            }

          } else if (data.kind === 'youtube#videoListResponse') {

            // Videos from  Videolist
            for (var i = 0, len = data.items.length; i < len; i++) {
              var item = data.items[i];

              // Videos without thumbnail, deleted or rejected are not included in the player!
              if (
                $.inArray(item.status.uploadStatus, ['rejected', 'deleted', 'failed']) === -1 &&
                typeof item.snippet.thumbnails !== 'undefined'
              ) {
                // Videos disallowed by regionRestrictions are not included in the player
                if ( typeof this.options.playable_region === false ||
                  ( typeof item.contentDetails.regionRestriction !== 'undefined' &&
                    (
                      (
                        // The specified playable_region is allowed
                        typeof item.contentDetails.regionRestriction.allowed !== 'undefined' &&
                        $.inArray(this.options.playable_region, item.contentDetails.regionRestriction.allowed)
                      ) || (
                        // The specified playable_region is not blocked
                        typeof item.contentDetails.regionRestriction.blocked !== 'undefined' &&
                        $.inArray(this.options.playable_region, item.contentDetails.regionRestriction.blocked) === -1
                      )
                    )
                  )
                ) {
                    var
                      vid = item.id,
                      tit = item.snippet.title,
                      aut = item.snippet.channelTitle,
                      thu = item.snippet.thumbnails.default.url;
                    that.addVideo2Playlist(vid, tit, aut, thu);
                }
              }
              if ( $.isEmptyObject( that.data.temp_vl ) ) {
                this.startPlayList();
              }
            }
          }
        }
      });
    },

    // All videos are supossed to be loaded
    // lets start the playlist
    startPlayList: function() {

      var
        D = this.DOM,
        vid = null,
        that = this;

      // Click on playlist elemnts
      D.$items.on('click', 'li', function(e) {
        e.preventDefault();
        D.$items.find('li').removeClass('selected');
        $(this).addClass('selected');
        vid = $(this).data('video-id');
        // Call YT API function
        that.DOM.$el[0].ytplayer.loadVideoById(vid);
        // If we are in mobile we must stop
        if (that.data.ismobile) {
          that.data.firsttime = true;
        }
      });

      // Select first if none
      if (D.$items.find('li.selected').length === 0) {
        if ( this.options.autoplay ) {
          D.$items.find('li').first().click();
        }
      }
    },

    // Add video block to playlist
    addVideo2Playlist: function(vid, tit, aut, thu) {
      var
        D  = this.DOM;
      $('

'+tit+'
'+aut+'

').appendTo(D.$items.find('ol'));
    },

  }; // prototypes

  return Rypp;

}(jQuery));

// YOUTUBE API CALLBACK
function onYouTubeIframeAPIReady() {
  // console.log( 'Youtube API script loaded. Start players.' );
  $('[data-rypp]').each(function(idx, el) {
    $(el)[0].rypp_data_obj.onYTIframeAPIReadyCallback();
  });
}

// JQuery hook
$.fn.rypp = function(api_key, options) {
  return this.each(function() {
    // Store object in DOM element
    this.rypp_data_obj = new RYPP(this, api_key, options);
  });
};
<|endoftext|>


<commit_before>Util = {};

// Todo
// - Onload
// - Write to specified file in a lib
// - list files in fileBrowser
// - onclick display file
// - search files spec lib
// - list lib
// - choose notebook location

// O N L O A D   S T U F F
window,onload = function(){
	var files = Util.fs.getNotes("shakespeare");
	Util.txt.setFileBrowser(files);
}

// G E N E R A L   S T U F F
Util.gen = function(){

	function makeIterator(array){
	    var nextIndex = 0;

	    return {
	       next: function(){
	           return nextIndex < array.length ?
	               {value: array[nextIndex++], done: false} :
	               {done: true};
	       }
	    }
	}

	// Note mixed arrays might goof it up (eg 2="2"). Unless you dig that sorta thing
	function unique(array) {
	    var seen = {};
	    return array.filter(function(item) {
	        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
	    });
	}

	return{ makeIterator:makeIterator, unique:unique }
}();

// F I L E   S T U F F
Util.fs = function(){

	// Internal Variables

	var fs = require('fs');
	var path = require('path');

	var root = __dirname;
	var notebook = "notebook";

	// Internal Functions

 	function getDirectories(srcpath) {
	  return fs.readdirSync(srcpath).filter(function(file) {
	    return fs.statSync(path.join(srcpath, file)).isDirectory();
	  });
	}

 	function getFiles(srcpath) {
		var files = fs.readdirSync(srcpath);
		return files.filter(function(file) {
		    return !fs.statSync(path.join(srcpath, file)).isDirectory();
		  });
	}

 	function getFileContent(srcpath) {
		return fs.readFileSync(srcpath, {encoding: 'utf-8'});
	}

	// External Functions

	function getLibraries() {
		var notebookDir = path.join(root,notebook);
		return getDirectories(notebookDir);
	}

	function getNotes(library) {
		var libraryDir = path.join(root,notebook,library);
		return getFiles(libraryDir);
	}

	function getNoteContent(library, note) {
		var noteDir = path.join(root,notebook,library,note);
		return getFileContent(noteDir);
	}

	return{getLibraries:getLibraries, getNotes:getNotes, getNoteContent:getNoteContent}
}();

// T E X T   S T U F F
Util.txt = function(){

	// Internal Variables
	var regexIgnoreLine = /\n*#.*/g;
	// var regexIgnoreChar = /[ \" \, \. \- \! \? \* \[ \] \d ]/g;
	var regexIgnoreChar = /[^A-Za-z \s']/g;

	// Internal Functions

	// External Functions
	var clean = function(txt) {
		txt = txt.replace(regexIgnoreLine,"");
		txt = txt.replace(regexIgnoreChar,"");
		txt = txt.replace(/[\n\s\t]+/g," ");
		return txt;
	}

	// Takes an array of strings and removes duplicates
	// var unique = function(txtArray) {
	// 	var uniq = txtArray.reduce(function(a,b){
	// 	    if (a.indexOf(b) < 0 ) a.push(b);
	// 	    return a;
	//   	},[]);
	//   	return uniq;
	// }

	var debugOut = function(txt) {
		var debug = document.getElementById("debug");
		debug.textContent = txt;
	}

	var getInputText = function() {
		// var input = document.getElementById("inputTextbox");
		// return input.value;
		var editor = ace.edit('baseline-pane');
		return editor.getValue();
	}

	var setOutputText = function(txt) {
		// var output = document.getElementById("outputTextbox");
		// output.value = txt;
		var editor = ace.edit('baseline-pane');
		editor.setValue(txt);
	}

	var setInputText = function(txt) {
		var input = document.getElementById("inputTextbox");
		input.value = txt;
	}

	var setFileBrowser = function(files) {
		var fileBrowser = document.getElementById("fileBrowser");
		for (var i = 0; i < files.length; i++) {
			var note = files[i];
			var li = document.createElement("li");
			var strong = document.createElement("strong");
			strong.appendChild(document.createTextNode(note));
			li.appendChild(strong);
			fileBrowser.appendChild(li);
		};
	}

	return{ clean:clean, debugOut:debugOut, getInputText:getInputText, setOutputText:setOutputText, setInputText:setInputText, setFileBrowser:setFileBrowser }
}();

// T E S T
// var libs =  Util.fs.getLibraries();
// var lib = libs[3];
// var notes = Util.fs.getNotes(lib);
// var note = notes[0];
// console.log(Util.fs.getNoteContent(lib,note));
<commit_msg>cleaned Util<commit_after>Util = {};

// Todo
// - Onload
// - Write to specified file in a lib
// - list files in fileBrowser
// - onclick display file
// - search files spec lib
// - list lib
// - choose notebook location

// O N L O A D   S T U F F
window,onload = function(){
	var files = Util.fs.getNotes("shakespeare");
	Util.txt.setFileBrowser(files);
}

// G E N E R A L   S T U F F
Util.gen = function(){

	function makeIterator(array){
	    var nextIndex = 0;

	    return {
	       next: function(){
	           return nextIndex < array.length ?
	               {value: array[nextIndex++], done: false} :
	               {done: true};
	       }
	    }
	}

	// Note mixed arrays might goof it up (eg 2="2"). Unless you dig that sorta thing
	function unique(array) {
	    var seen = {};
	    return array.filter(function(item) {
	        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
	    });
	}

	return{ makeIterator:makeIterator, unique:unique }
}();

// F I L E   S T U F F
Util.fs = function(){

	// Internal Variables

	var fs = require('fs');
	var path = require('path');

	var root = __dirname;
	var notebook = "notebook";

	// Internal Functions

 	function getDirectories(srcpath) {
	  return fs.readdirSync(srcpath).filter(function(file) {
	    return fs.statSync(path.join(srcpath, file)).isDirectory();
	  });
	}

 	function getFiles(srcpath) {
		var files = fs.readdirSync(srcpath);
		return files.filter(function(file) {
		    return !fs.statSync(path.join(srcpath, file)).isDirectory();
		  });
	}

 	function getFileContent(srcpath) {
		return fs.readFileSync(srcpath, {encoding: 'utf-8'});
	}

	// External Functions

	function getLibraries() {
		var notebookDir = path.join(root,notebook);
		return getDirectories(notebookDir);
	}

	function getNotes(library) {
		var libraryDir = path.join(root,notebook,library);
		return getFiles(libraryDir);
	}

	function getNoteContent(library, note) {
		var noteDir = path.join(root,notebook,library,note);
		return getFileContent(noteDir);
	}

	return{getLibraries:getLibraries, getNotes:getNotes, getNoteContent:getNoteContent}
}();

// T E X T   S T U F F
Util.txt = function(){

	// Internal Variables
	var regexIgnoreLine = /\n*#.*/g;
	// var regexIgnoreChar = /[ \" \, \. \- \! \? \* \[ \] \d ]/g;
	var regexIgnoreChar = /[^A-Za-z \s']/g;

	// Internal Functions

	// External Functions
	function clean(txt) {
		txt = txt.replace(regexIgnoreLine,"");
		txt = txt.replace(regexIgnoreChar,"");
		txt = txt.replace(/[\n\s\t]+/g," ");
		return txt;
	}

	function debugOut(txt) {
		var debug = document.getElementById("debug");
		debug.textContent = txt;
	}

	function getInputText() {
		// var input = document.getElementById("inputTextbox");
		// return input.value;
		var editor = ace.edit('baseline-pane');
		return editor.getValue();
	}

	function setOutputText(txt) {
		// var output = document.getElementById("outputTextbox");
		// output.value = txt;
		var editor = ace.edit('baseline-pane');
		editor.setValue(txt);
	}

	function setInputText(txt) {
		var input = document.getElementById("inputTextbox");
		input.value = txt;
	}

	function setFileBrowser(files) {
		var fileBrowser = document.getElementById("fileBrowser");
		for (var i = 0; i < files.length; i++) {
			var note = files[i];
			var li = document.createElement("li");
			var strong = document.createElement("strong");
			strong.appendChild(document.createTextNode(note));
			li.appendChild(strong);
			fileBrowser.appendChild(li);
		};
	}

	return{ clean:clean, debugOut:debugOut, getInputText:getInputText, setOutputText:setOutputText, setInputText:setInputText, setFileBrowser:setFileBrowser }
}();

// T E S T
// var libs =  Util.fs.getLibraries();
// var lib = libs[3];
// var notes = Util.fs.getNotes(lib);
// var note = notes[0];
// console.log(Util.fs.getNoteContent(lib,note));
<|endoftext|>


<commit_before>define(['underscore','jquery','libwords','mybackbone','ocruidoc','events','wordconv'],
        function (_,$,libwords,mybackbone,mets,events,wordconv) {
    "use strict";

    var AltoModel = mybackbone.Model.extend({
        initialize: function (options) {
            this.set('pageNumber',options.pageNumber);
            this.currentUrl = options.doc.getAltoUrl(options.pageNumber);
            this.originalUrl = options.doc.getOriginalAltoUrl(options.pageNumber);
            options.doc.registerAlto(options.pageNumber,this);
            this.id = options.id;
            this.set('pageIndex',options.pageNumber-1);
            this.originalWords = [];
            this.savedWords = [];
            this.editorWords = [];
            this.changedSinceSave = false;
            this.changedSince0 = false;
        },
        refreshAfterSave: function (doc) {

            var self = this;

            if (!this.isDirty()) return;

            var p = this.get('pageNumber')
            this.currentUrl = doc.getAltoUrl(p);
            this.fetch()
                .done ( function () {
                    console.log('fetch done');
                    events.trigger('pageDirtyStateChanged');
                    events.trigger('altoRefreshed',self);
                } );

        },
        isDirty: function() {
            return this.changedSinceSave;
        },
        isDirty0: function() {
            return this.changedSince0;
        },
        getWordAt: function(x,y) {
            return libwords.getWordAt(this.editorWords,x,y);
        },
        updateStringsContent: function (strings) {

            var out = libwords.transform(
                    this.originalWords,
                    this.savedWords,
                    this.editorWords,
                    strings
            );
            this.editorWords = out.targetWords;
            this.changedSince0 = out.dirtySince0;
            this.changedSinceSave = out.dirtySinceSave;
            //console.log(out);
            events.trigger('pageDirtyStateChanged');

        },
        setNthWordLanguage: function(index,language) {
            this.editorWords[index].language = language;
            this.changedSinceSave = true;
            events.trigger("saveDocument");
            return this.editorWords[index];
        },
        setNthWordTag: function(index, tag) {
            this.editorWords[index].tag = tag;
            this.changedSinceSave = true;
            events.trigger("saveDocument");
            return this.editorWords[index];
        },

        getNthWord: function(index) {
            return this.editorWords[index];
        },
        getAsAltoXML: function() {

            return wordconv.words2alto(this.editorWords,this.originalXML);

        },
        getChangedSince0Sequence: function() {
            return libwords.getChangedSince0Sequence(this.editorWords);
        },
        getChangedSinceSaveSequence: function() {
            return libwords.getChangedSinceSaveSequence(this.editorWords);
        },
        getLanguageSequence: function() {
            return libwords.getLanguageSequence(this.editorWords);
        },
        getTagSequence: function() {
            return libwords.getTagSequence(this.editorWords);
        },
        getLayoutBoxes: function() {
            return this.layoutBoxes;
        },
        getString: function(lineBreaks) {
            var previousTextBlock = 0;
            var previousTextLine = 0;
            var words = libwords.getWordSequence(this.editorWords);
            var strings = _.map(words,function (w,i) {

                var rv;
                if (previousTextBlock != w.textBlock) {
                    rv = '\n\n' + w.content;
                } else if (previousTextLine != w.textLine) {
                    rv = (lineBreaks ? '\n' : ' ') + w.content;
                } else {
                    rv = (i != 0 ? ' ' : '') + w.content;
                }

                previousTextBlock = w.textBlock;
                previousTextLine = w.textLine;

                return rv;

            });

            return strings.join('');
        },
        fetch: function (options) {

            var self = this;
            var def = new $.Deferred();

            if ((options||{}).currentOnly) {

                return altoLoader('current');

            } else {

                var $def1 = altoLoader( 'current' );
                var $def2 = altoLoader( 'original' );

                return $.when( $def1, $def2 );

            }

            function altoLoader (version) {

                var url = (version == 'current') ?
                          self.currentUrl :
                          self.originalUrl;
                return $.get(url).done( function (data) {

                    var parsed = null;

                    try {
                        parsed = $.parseXML(data);
                    } catch (er) { }

                    if (version == 'current') {

                        self.currentXML = parsed;
                        self.savedWords = wordconv.alto2words(parsed);
                        self.editorWords = self.savedWords;
                        self.layoutBoxes = self.constructLayoutBoxes(
                            self.savedWords );

                    } else {

                        self.originalXML = parsed;
                        self.originalWords = wordconv.alto2words(parsed);

                    }

                    if (self.originalXML && self.currentXML) {

                        var strings = _.map(self.savedWords, getContent)
                        self.updateStringsContent(strings);
                        var page = $(data).find('Page');
                        var printSpace = $(data).find('PrintSpace');
                        var width = parseInt(page.attr("WIDTH"),10)
                                ||  parseInt(printSpace.attr("WIDTH"),10);
                        var height = parseInt(page.attr("HEIGHT"),10)
                                ||  parseInt(printSpace.attr("HEIGHT"),10);
                        events.trigger(
                            'setPageGeometry',
                            {width:width,height:height}
                            );

                    }

                });

            }

            function getContent(w) { return w.content; }

            function sorter (a,b) {
                var aN = parseInt(a.number,10);
                var bN = parseInt(b.number,10);
                return aN - bN;
            };

        },

        constructLayoutBoxes : function(words) {
            var layoutBoxes = Math.max.apply(null,
                _.map(words, function (w) { return w.textBlock; })
            );

            var boxes = [];
            for (var i = 0; i <= layoutBoxes; i++ ) {
                var myWords = _.filter(words,
                    function (w) {return w.textBlock == i;}
                );

                var layoutBox = libwords.getCombinedBoundingBox(myWords);
                layoutBox.index = i;
                layoutBox.fromIndex = Math.min.apply(null,
                    _.map(myWords, function(w) { return w.index; })
                );
                layoutBox.toIndex = Math.max.apply(null,
                    _.map(myWords, function(w) { return w.index; })
                );
                boxes.push(layoutBox);
            }
            return boxes;
        }

    });

    function get(options) {

        var promise = new $.Deferred();

        mets.getCurrent().then(
            function (doc) {
                var altoOptions = {
                    docId: options.docId,
                    pageNumber: options.pageNumber,
                    id: getAltoId(options),
                    doc: doc
                };
                var alto = altos[altoOptions.id];
                if (alto === undefined) {
                    try {
                        alto = new AltoModel(altoOptions);
                    } catch (err) {
                        promise.reject(err);
                        return;
                    }
                    altos[altoOptions.id] = alto;
                    alto.loading = alto.fetch();
                }
                alto.loading.then(
                    function () {promise.resolve(alto);},
                    function (err) {promise.reject(err);}
                );
            },
            function (arg) { promise.reject(arg); }
        );
        return promise;
    }

    var altos = {};

    events.on('documentSaved', function (doc) {

        for (var id in altos) {

            altos[id].refreshAfterSave(doc);

        }

    });

    function getAltoId(options) {
        return options.docId+'/'+options.pageNumber;
    }

    return {
        get : get
    };
});
<commit_msg>test tag with multiple words<commit_after>define(['underscore','jquery','libwords','mybackbone','ocruidoc','events','wordconv'],
        function (_,$,libwords,mybackbone,mets,events,wordconv) {
    "use strict";

    var AltoModel = mybackbone.Model.extend({
        initialize: function (options) {
            this.set('pageNumber',options.pageNumber);
            this.currentUrl = options.doc.getAltoUrl(options.pageNumber);
            this.originalUrl = options.doc.getOriginalAltoUrl(options.pageNumber);
            options.doc.registerAlto(options.pageNumber,this);
            this.id = options.id;
            this.set('pageIndex',options.pageNumber-1);
            this.originalWords = [];
            this.savedWords = [];
            this.editorWords = [];
            this.changedSinceSave = false;
            this.changedSince0 = false;
        },
        refreshAfterSave: function (doc) {

            var self = this;

            if (!this.isDirty()) return;

            var p = this.get('pageNumber')
            this.currentUrl = doc.getAltoUrl(p);
            this.fetch()
                .done ( function () {
                    console.log('fetch done');
                    events.trigger('pageDirtyStateChanged');
                    events.trigger('altoRefreshed',self);
                } );

        },
        isDirty: function() {
            return this.changedSinceSave;
        },
        isDirty0: function() {
            return this.changedSince0;
        },
        getWordAt: function(x,y) {
            return libwords.getWordAt(this.editorWords,x,y);
        },
        updateStringsContent: function (strings) {

            var out = libwords.transform(
                    this.originalWords,
                    this.savedWords,
                    this.editorWords,
                    strings
            );
            this.editorWords = out.targetWords;
            this.changedSince0 = out.dirtySince0;
            this.changedSinceSave = out.dirtySinceSave;
            //console.log(out);
            events.trigger('pageDirtyStateChanged');

        },
        setNthWordLanguage: function(index,language) {
            this.editorWords[index].language = language;
            return this.editorWords[index];
        },
        setNthWordTag: function(index, tag) {
            this.editorWords[index].tag = tag;
            return this.editorWords[index];
        },

        getNthWord: function(index) {
            return this.editorWords[index];
        },
        getAsAltoXML: function() {

            return wordconv.words2alto(this.editorWords,this.originalXML);

        },
        getChangedSince0Sequence: function() {
            return libwords.getChangedSince0Sequence(this.editorWords);
        },
        getChangedSinceSaveSequence: function() {
            return libwords.getChangedSinceSaveSequence(this.editorWords);
        },
        getLanguageSequence: function() {
            return libwords.getLanguageSequence(this.editorWords);
        },
        getTagSequence: function() {
            return libwords.getTagSequence(this.editorWords);
        },
        getLayoutBoxes: function() {
            return this.layoutBoxes;
        },
        getString: function(lineBreaks) {
            var previousTextBlock = 0;
            var previousTextLine = 0;
            var words = libwords.getWordSequence(this.editorWords);
            var strings = _.map(words,function (w,i) {

                var rv;
                if (previousTextBlock != w.textBlock) {
                    rv = '\n\n' + w.content;
                } else if (previousTextLine != w.textLine) {
                    rv = (lineBreaks ? '\n' : ' ') + w.content;
                } else {
                    rv = (i != 0 ? ' ' : '') + w.content;
                }

                previousTextBlock = w.textBlock;
                previousTextLine = w.textLine;

                return rv;

            });

            return strings.join('');
        },
        fetch: function (options) {

            var self = this;
            var def = new $.Deferred();

            if ((options||{}).currentOnly) {

                return altoLoader('current');

            } else {

                var $def1 = altoLoader( 'current' );
                var $def2 = altoLoader( 'original' );

                return $.when( $def1, $def2 );

            }

            function altoLoader (version) {

                var url = (version == 'current') ?
                          self.currentUrl :
                          self.originalUrl;
                return $.get(url).done( function (data) {

                    var parsed = null;

                    try {
                        parsed = $.parseXML(data);
                    } catch (er) { }

                    if (version == 'current') {

                        self.currentXML = parsed;
                        self.savedWords = wordconv.alto2words(parsed);
                        self.editorWords = self.savedWords;
                        self.layoutBoxes = self.constructLayoutBoxes(
                            self.savedWords );

                    } else {

                        self.originalXML = parsed;
                        self.originalWords = wordconv.alto2words(parsed);

                    }

                    if (self.originalXML && self.currentXML) {

                        var strings = _.map(self.savedWords, getContent)
                        self.updateStringsContent(strings);
                        var page = $(data).find('Page');
                        var printSpace = $(data).find('PrintSpace');
                        var width = parseInt(page.attr("WIDTH"),10)
                                ||  parseInt(printSpace.attr("WIDTH"),10);
                        var height = parseInt(page.attr("HEIGHT"),10)
                                ||  parseInt(printSpace.attr("HEIGHT"),10);
                        events.trigger(
                            'setPageGeometry',
                            {width:width,height:height}
                            );

                    }

                });

            }

            function getContent(w) { return w.content; }

            function sorter (a,b) {
                var aN = parseInt(a.number,10);
                var bN = parseInt(b.number,10);
                return aN - bN;
            };

        },

        constructLayoutBoxes : function(words) {
            var layoutBoxes = Math.max.apply(null,
                _.map(words, function (w) { return w.textBlock; })
            );

            var boxes = [];
            for (var i = 0; i <= layoutBoxes; i++ ) {
                var myWords = _.filter(words,
                    function (w) {return w.textBlock == i;}
                );

                var layoutBox = libwords.getCombinedBoundingBox(myWords);
                layoutBox.index = i;
                layoutBox.fromIndex = Math.min.apply(null,
                    _.map(myWords, function(w) { return w.index; })
                );
                layoutBox.toIndex = Math.max.apply(null,
                    _.map(myWords, function(w) { return w.index; })
                );
                boxes.push(layoutBox);
            }
            return boxes;
        }

    });

    function get(options) {

        var promise = new $.Deferred();

        mets.getCurrent().then(
            function (doc) {
                var altoOptions = {
                    docId: options.docId,
                    pageNumber: options.pageNumber,
                    id: getAltoId(options),
                    doc: doc
                };
                var alto = altos[altoOptions.id];
                if (alto === undefined) {
                    try {
                        alto = new AltoModel(altoOptions);
                    } catch (err) {
                        promise.reject(err);
                        return;
                    }
                    altos[altoOptions.id] = alto;
                    alto.loading = alto.fetch();
                }
                alto.loading.then(
                    function () {promise.resolve(alto);},
                    function (err) {promise.reject(err);}
                );
            },
            function (arg) { promise.reject(arg); }
        );
        return promise;
    }

    var altos = {};

    events.on('documentSaved', function (doc) {

        for (var id in altos) {

            altos[id].refreshAfterSave(doc);

        }

    });

    function getAltoId(options) {
        return options.docId+'/'+options.pageNumber;
    }

    return {
        get : get
    };
});
<|endoftext|>