<commit_before>//
// new PaginatingTable( 'my_table', {
//   per_page: 10,     // How many rows per page?
//   current_page: 1,  // What page to start on when initialized
//   offset_el: false, // What dom element to stick the offset in
//   cutoff_el: false, // What dom element to stick the cutoff in
//   details: false    // Do we have hidden/collapsable rows?
// });
//
// The above were the defaults.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

var PaginatingTable = new Class({

  initialize: function( tbl, ids, options ) {
    this.options = $merge({
      per_page: 10,
      current_page: 1,
      offset_el: false,
      cutoff_el: false,
      details: false
    }, options);

    this.table = $(tbl);
    this.tbody = this.table.getElementsByTagName( 'tbody' )[0];

    if (this.options.offset_el)
      this.options.offset_el = $(this.options.offset_el);
    if (this.options.cutoff_el)
      this.options.cutoff_el = $(this.options.cutoff_el);

    this.paginators = [];
    if ($type(ids) == 'array'){
      $each(ids,function(id){
        this.paginators.push( $(id) );
      }.bind( this ));
    } else {
      this.paginators.push( $(ids) );
    }

    if (this.options.details) {
      this.options.per_page = this.options.per_page * 2
    }

    this.update_pages();
  },

  update_pages: function(){
    this.pages = Math.ceil( this.tbody.getElementsByTagName('tr').length / this.options.per_page );
    this.create_pagination();
    this.to_page( 1 );
  },

  to_page: function( page_num ) {
    page_num = parseInt( page_num );
    if (page_num > this.pages || page_num < 1) return;
    this.current_page = page_num;
    this.low_limit  = this.options.per_page * ( this.current_page - 1 );
    this.high_limit = this.options.per_page * this.current_page;
    var trs = this.tbody.getElementsByTagName('tr')
    if (trs.length < this.high_limit) this.high_limit = trs.length;
    for (var index=0; index < trs.length; index++) {
      if ( this.low_limit  <= index &&
           this.high_limit > index    ) {
        trs[index].style.display = '';
      } else {
        trs[index].style.display = 'none';
      }
    }
    this.paginators.each(function(paginator){
      var as = paginator.getElementsByTagName( 'a' );
      for (var index=0;index < as.length;index++){
        if (index == this.current_page) {
          as[index].addClass('currentPage');
        } else {
          as[index].removeClass('currentPage');
        }
      }
    }.bind( this ));
    if (this.options.offset_el)
      this.options.offset_el.set('text', Math.ceil( this.low_limit / ( this.options.details ? 2 : 1 ) + 1 ) );
    if (this.options.cutoff_el)
      this.options.cutoff_el.set('text', ( this.high_limit / ( this.options.details ? 2 : 1 ) ) );
  },

  to_next_page: function() {
    this.to_page( this.current_page + 1 );
  },

  to_prev_page: function() {
    this.to_page( this.current_page - 1 );
  },

  create_pagination: function() {
    this.paginators.each(function(paginator){
      paginator.empty();
      this.create_pagination_node( '«', function(evt){
        var evt = new Event( evt );
        this.to_prev_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
      for (var page=1; page <= this.pages; page++){
        this.create_pagination_node( page, function(evt){
          var evt = new Event( evt );
          this.to_page( evt.target.get( 'text' ) );
          evt.stop();
          return false;
        }).injectInside( paginator );
      }
      this.create_pagination_node( '»', function(evt){
        var evt = new Event( evt );
        this.to_next_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
    }.bind( this ));
  },

  create_pagination_node: function( text, evt ) {
    var span = new Element( 'span' ).set( 'html', text );
    if (text == '«'){
      var a = new Element( 'a', { 'href': '#', 'class': 'previous-page' }).addEvent( 'click', evt.bind( this ) );
    } else if (text == '»'){
      var a = new Element( 'a', { 'href': '#', 'class': 'next-page' }).addEvent( 'click', evt.bind( this ) );
    } else {
      var a = new Element( 'a', { 'href': '#'}).addEvent( 'click', evt.bind( this ) );
    }
    var li   = new Element( 'li' );
    span.injectInside( a.injectInside( li ) );
    return li;
  }

});
<commit_msg>Fix doc, mention handling arrays of paginators<commit_after>//
// new PaginatingTable( 'my_table', 'ul_for_paginating', {
//   per_page: 10,     // How many rows per page?
//   current_page: 1,  // What page to start on when initialized
//   offset_el: false, // What dom element to stick the offset in
//   cutoff_el: false, // What dom element to stick the cutoff in
//   details: false    // Do we have hidden/collapsable rows?
// });
//
// The above were the defaults.  You could also pass an array of paginators
// instead of just one.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

var PaginatingTable = new Class({

  initialize: function( tbl, ids, options ) {
    this.options = $merge({
      per_page: 10,
      current_page: 1,
      offset_el: false,
      cutoff_el: false,
      details: false
    }, options);

    this.table = $(tbl);
    this.tbody = this.table.getElementsByTagName( 'tbody' )[0];

    if (this.options.offset_el)
      this.options.offset_el = $(this.options.offset_el);
    if (this.options.cutoff_el)
      this.options.cutoff_el = $(this.options.cutoff_el);

    this.paginators = [];
    if ($type(ids) == 'array'){
      $each(ids,function(id){
        this.paginators.push( $(id) );
      }.bind( this ));
    } else {
      this.paginators.push( $(ids) );
    }

    if (this.options.details) {
      this.options.per_page = this.options.per_page * 2
    }

    this.update_pages();
  },

  update_pages: function(){
    this.pages = Math.ceil( this.tbody.getElementsByTagName('tr').length / this.options.per_page );
    this.create_pagination();
    this.to_page( 1 );
  },

  to_page: function( page_num ) {
    page_num = parseInt( page_num );
    if (page_num > this.pages || page_num < 1) return;
    this.current_page = page_num;
    this.low_limit  = this.options.per_page * ( this.current_page - 1 );
    this.high_limit = this.options.per_page * this.current_page;
    var trs = this.tbody.getElementsByTagName('tr')
    if (trs.length < this.high_limit) this.high_limit = trs.length;
    for (var index=0; index < trs.length; index++) {
      if ( this.low_limit  <= index &&
           this.high_limit > index    ) {
        trs[index].style.display = '';
      } else {
        trs[index].style.display = 'none';
      }
    }
    this.paginators.each(function(paginator){
      var as = paginator.getElementsByTagName( 'a' );
      for (var index=0;index < as.length;index++){
        if (index == this.current_page) {
          as[index].addClass('currentPage');
        } else {
          as[index].removeClass('currentPage');
        }
      }
    }.bind( this ));
    if (this.options.offset_el)
      this.options.offset_el.set('text', Math.ceil( this.low_limit / ( this.options.details ? 2 : 1 ) + 1 ) );
    if (this.options.cutoff_el)
      this.options.cutoff_el.set('text', ( this.high_limit / ( this.options.details ? 2 : 1 ) ) );
  },

  to_next_page: function() {
    this.to_page( this.current_page + 1 );
  },

  to_prev_page: function() {
    this.to_page( this.current_page - 1 );
  },

  create_pagination: function() {
    this.paginators.each(function(paginator){
      paginator.empty();
      this.create_pagination_node( '«', function(evt){
        var evt = new Event( evt );
        this.to_prev_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
      for (var page=1; page <= this.pages; page++){
        this.create_pagination_node( page, function(evt){
          var evt = new Event( evt );
          this.to_page( evt.target.get( 'text' ) );
          evt.stop();
          return false;
        }).injectInside( paginator );
      }
      this.create_pagination_node( '»', function(evt){
        var evt = new Event( evt );
        this.to_next_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
    }.bind( this ));
  },

  create_pagination_node: function( text, evt ) {
    var span = new Element( 'span' ).set( 'html', text );
    if (text == '«'){
      var a = new Element( 'a', { 'href': '#', 'class': 'previous-page' }).addEvent( 'click', evt.bind( this ) );
    } else if (text == '»'){
      var a = new Element( 'a', { 'href': '#', 'class': 'next-page' }).addEvent( 'click', evt.bind( this ) );
    } else {
      var a = new Element( 'a', { 'href': '#'}).addEvent( 'click', evt.bind( this ) );
    }
    var li   = new Element( 'li' );
    span.injectInside( a.injectInside( li ) );
    return li;
  }

});
<|endoftext|>


<commit_before>require('moonstone');

/**
* Contains the declaration for the {@link module:moonstone/Drawers~Drawers} kind.
* @module moonstone/Drawers
*/

var
	kind = require('enyo/kind'),
	dispatcher = require('enyo/dispatcher'),
	Animator = require('enyo/Animator'),
	Control = require('enyo/Control'),
	Drawer = require('enyo/Drawer'),
	dom = require('enyo/dom');

var
	options = require('../options'),
	Icon = require('../Icon'),
	Item = require('../Item'),
	MoonHistory = require('../History'),
	HistorySupport = MoonHistory.HistorySupport;

var
	MoonDrawer = require('./Drawer');

/**
* {@link module:moonstone/Drawers~Drawers} is a container kind designed to hold a set of {@link module:moonstone/Drawer~Drawer}
* objects and client content. The [drawers]{@link module:moonstone/Drawers~Drawers#drawers} property accepts
* an array of Drawer controls. The associated handles are positioned in their own small
* drawer, centered at the top of the "dresser" (the region containing the array of Drawer
* controls and the activator nub).
*
* When a handle is selected, it opens the corresponding Drawer object's main drawer or
* control drawer, depending on how the Drawer object is configured. The control's child
* components may be of any kind.
*
* ```
* {
*	kind: 'moon.Drawers',
*	drawers: [
*		{
*			name: 'musicDrawer',
*			kind: 'moon.Drawer',
*			handle: {kind: 'moon.DrawerHandle', content: 'Handle'},
*			components: [
*				{content: 'Drawer Content'}
*			],
*			controlDrawerComponents: [
*				{content: 'Controls'}
*			]
*		}
*	],
*	components: [
*		{content: 'Content Area'}
*	]
* }
* ```
*
* @class Drawers
* @extends module:enyo/Control~Control
* @ui
* @public
*/
module.exports = kind(
	/** @lends module:moonstone/Drawers~Drawers.prototype */ {

	/**
	* @private
	*/
	name: 'moon.Drawers',

	/**
	* @private
	*/
	kind: Control,

	/**
	* @private
	*/
	mixins : [HistorySupport],

	/**
	* @private
	*/
	classes: 'moon-drawers enyo-fit',

	/**
	* @private
	* @lends module:moonstone/Drawers~Drawers.prototype
	*/
	published: {

		/**
		* Populate with an array of {@link module:moonstone/Drawer~Drawer} components.
		*
		* @type {Object[]}
		* @default null
		* @public
		*/
		drawers: null,

		/**
		* When using a font-based icon, the name of the icon to be used.
		* The following icon names are valid:
		*
		* 'drawer'
		* 'arrowlargeup'
		* 'arrowlargedown'
		* 'arrowlargeleft'
		* 'arrowlargeright'
		* 'arrowsmallup'
		* 'arrowsmalldown'
		* 'arrowsmallleft'
		* 'arrowsmallright'
		* 'closex'
		* 'check'
		* 'search'
		*
		* @type {String}
		* @default ''
		* @public
		*/
		icon: '',

		/**
		* URL specifying path to icon image.
		*
		* @type {String|module:enyo/resolution#selectSrc~src}
		* @default ''
		* @public
		*/
		src: ''
	},

	/**
	* Default icon displayed on drawer handle when open
	*
	* @type {String}
	* @default 'arrowsmalldown'
	* @private
	*/
	iconClosed: 'arrowsmalldown',

	/**
	* Default icon displayed on drawer handle when closed
	*
	* @type {String}
	* @default 'arrowsmallup'
	* @private
	*/
	iconOpen: 'arrowsmallup',

	/**
	* Cached value of the top position of the client area. Used for non-accelerated animation.
	*
	* @type {Number}
	* @default 0
	* @private
	*/
	clientTop: 0,

	/**
	* @private
	*/
	handlers: {
		//* Handlers to update the activator when the state of the contained drawers changes
		onActivate: 'drawerActivated',
		onDeactivate: 'drawerDeactivated',
		onSpotlightDown: 'spotDown',
		onSpotlightUp: 'spotUp'
	},

	/**
	* @private
	*/
	components: [
		{name: 'activator', kind: Control, classes: 'moon-drawers-activator', spotlight: true, ontap: 'activatorTapped', components: [
			{name: 'activatorIcon', kind: Icon, classes: 'moon-drawers-activator-icon', small: false}
		]},
		{name: 'handleContainer', kind: Drawer, classes: 'moon-drawers-handle-container', resizeContainer: false, open: false, spotlightDisabled: true, components: [
			{name: 'handles', kind: Control, classes: 'moon-neutral moon-drawers-handles'}
		]},
		{name: 'drawers', kind: Control, classes: 'moon-drawers-drawer-container'},
		{name: 'client', kind: Control, classes: 'moon-drawers-client'}
	],

	/**
	* @private
	*/
	eventsToCapture: {
		ontap: 'captureTapSelect',
		onSpotlightFocus: 'captureSpotFocus',
		onSpotlightSelect: 'captureTapSelect'
	},

	/**
	* @private
	*/
	create: function () {
		Control.prototype.create.apply(this, arguments);
		this.drawers = this.$.drawers.createComponents(this.drawers, {kind: MoonDrawer, owner: this.owner});
		if (!options.accelerate) this.createComponent({name: 'animator', kind: Animator, onStep: 'animationStep'});
		this.setupHandles();
		this.updateActivator();
	},

	/**
	* @private
	*/
	rendered: function () {
		Control.prototype.rendered.apply(this, arguments);
		this.updateDrawerHeight();
	},

	/**
	* @private
	*/
	destroy: function () {
		var i,
			c$ = this.drawers;
		dispatcher.release(this.$.handleContainer);
		for (i = 0; i < c$.length; i++) {
			dispatcher.release(c$[i]);
		}
		Control.prototype.destroy.apply(this, arguments);
	},

	/**
	* @private
	*/
	srcChanged: function () {
		this.updateActivator();
	},

	/**
	* @private
	*/
	iconChanged: function () {
		this.updateActivator();
	},

	/**
	* @private
	*/
	setupHandles: function () {
		var i, len, handle,
			def = {kind: Item, owner: this},
			tap = this.bindSafely(this.handleTapped);

		for (i = 0, len = this.drawers.length; i < len; i++) {
			handle = this.$.handles.createComponent(this.drawers[i].handle || {}, def);
			handle.addClass('moon-drawers-handle');
			handle.tap = tap;
		}
	},

	/**
	* Updates the icon and styling of the activator for the state of the drawer
	*
	* @param {Boolean} open Drawer state
	* @private
	*/
	updateActivator: function (open) {
		var icon, src;

		if (open) {
			src = '';
			icon = this.iconOpen;
		} else {
			src = this.src;
			icon = (src && !icon) ? '' : (this.icon || this.iconClosed);
		}

		this.$.activator.addRemoveClass('open', open);
		this.$.activatorIcon.set('src', src);
		this.$.activatorIcon.set('icon', icon);
	},

	/**
	* Inform each drawer of the total available height
	*
	* @private
	*/
	updateDrawerHeight: function () {
		var dh = document.body.getBoundingClientRect().height,
			drawer, i;
		for (i = this.drawers.length - 1; i >= 0; --i) {
			drawer = this.drawers[i];
			if (drawer instanceof MoonDrawer) drawer.set('fullHeight', dh);
		}
	},

	/**
	* @private
	*/
	activatorTapped: function () {
		var handles;
		if (this.isDrawerOpen()) {
			this.closeDrawers();
		} else {
			handles = this.$.handles.getControls();
			if (handles.length == 1) {
				this.openDrawer(handles[0]);
				this.updateActivator(true);
			} else if (this.$.handleContainer.getOpen()) {
				this.closeHandleContainer();
			} else {
				this.openHandleContainer();
			}
		}
	},

	/**
	* @private
	*/
	openHandleContainer: function () {
		this.$.handleContainer.spotlightDisabled = false;
		this.$.handleContainer.setOpen(true);
		this.updateActivator(true);
		dispatcher.capture(this.$.handleContainer, this.eventsToCapture, this);
		if (this.allowBackKey) {
			this.pushBackHistory();
		}
	},

	/**
	* @private
	*/
	closeHandleContainer: function () {
		dispatcher.release(this.$.handleContainer);
		this.$.handleContainer.spotlightDisabled = true;
		this.$.handleContainer.setOpen(false);
		this.updateActivator(this.isDrawerOpen());
	},

	/**
	* @private
	*/
	handleTapped: function (sender, ev) {
		this.openDrawer(ev.originator);
		return true;
	},

	/**
	* @private
	*/
	openDrawer: function (handle) {
		var drawer,
			handles = this.$.handles.getControls();
		for (var index = 0; index < handles.length; ++index) {
			if (handle.isDescendantOf(handles[index])) {
				drawer = this.$.drawers.getControls()[index];
				drawer.show();
				drawer.toggleDrawer();
				this.closeHandleContainer();
				dispatcher.capture(drawer, this.eventsToCapture, this);
				return;
			}
		}
	},

	/**
	* @private
	*/
	isDrawerOpen: function () {
		var drawers = this.$.drawers.getControls();
		for (var index = 0; index < drawers.length; ++index) {
			if (drawers[index].get('open') || drawers[index].get('controlsOpen')) {
				return true;
			}
		}
		return false;
	},

	/**
	* @private
	*/
	closeDrawers: function () {
		var drawers = this.$.drawers.getControls();
		for (var index = 0; index < drawers.length; ++index) {
			var drawer = drawers[index];
			if (drawer.get('open') || drawer.get('controlsOpen')) {
				dispatcher.release(drawer);
				drawer.set('open', false);
				drawer.set('controlsOpen', false);
			}
		}
		this.$.client.spotlightDisabled = false;
		this.updateActivator(false);
	},

	/**
	* @private
	*/
	captureSpotFocus: function (sender, ev) {
		// Only close drawers on 5-way focus in the client (not pointer focus)
		if (ev.dir && ev.dispatchTarget.isDescendantOf(this.$.client)) {
			this.closeDrawers();
			this.closeHandleContainer();
		}
	},

	/**
	* @private
	*/
	captureTapSelect: function (sender, ev) {
		// Any tap or select in the client area closes the dresser/drawer
		if (ev.dispatchTarget.isDescendantOf(this.$.client)) {
			this.closeDrawers();
			this.closeHandleContainer();
		}
	},

	/**
	* Animates the position of the client area when a drawer is opened or closed
	*
	* @private
	*/
	animate: function (height) {
		if (options.accelerate) {
			dom.transformValue(this.$.client, 'translateY', height + 'px');
		} else {
			this.$.animator.play({
				startValue: this.clientTop,
				endValue: height
			});
		}
	},

	/**
	* When `!options.accelerate`, this handles {@link enyo/Animator#event:onStep} to update the
	* position of the client area
	*
	* @private
	*/
	animationStep: function (sender, event) {
		// cache the last top value to be reused by animate() as the startValue
		this.clientTop = sender.value;
		this.$.client.setBounds({top: this.clientTop + 'px'});
	},

	/**
	* @private
	*/
	drawerActivated: function (sender, ev) {
		var drawer = ev.originator instanceof MoonDrawer ? ev.originator : null;
		if (drawer) {
			this.updateActivator(true);
			// show/hide() is expensive. Use spotlightDisabled feature instead
			this.$.client.spotlightDisabled = drawer.open;
			this.animate(ev.height);
		}
	},

	/**
	* @private
	*/
	drawerDeactivated: function (sender, ev) {
		var drawer = ev.originator instanceof MoonDrawer ? ev.originator : null;
		if (drawer) {
			if (!drawer.open && !drawer.controlsOpen) this.updateActivator(false);
			// show/hide() is expensive. Use spotlightDisabled feature instead
			this.$.client.spotlightDisabled = drawer.open;
			this.animate(ev.height);
		}
	},

	/**
	* @private
	*/
	handleResize: function () {
		Control.prototype.handleResize.apply(this, arguments);
		this.updateDrawerHeight();
		this.updateActivator(false);
	},

	/**
	* @private
	*/
	backKeyHandler: function () {
		this.closeHandleContainer();
		return true;
	}
});

module.exports.Drawer = MoonDrawer;<commit_msg>ENYO-1957 Drawer: Handle is unable to display overlapping Images and Icons Enyo-DCO-1.1-Signed-off-by: Art Dahm art.dahm@lge.com<commit_after>require('moonstone');

/**
* Contains the declaration for the {@link module:moonstone/Drawers~Drawers} kind.
* @module moonstone/Drawers
*/

var
	kind = require('enyo/kind'),
	dispatcher = require('enyo/dispatcher'),
	Animator = require('enyo/Animator'),
	Control = require('enyo/Control'),
	Drawer = require('enyo/Drawer'),
	dom = require('enyo/dom');

var
	options = require('../options'),
	Icon = require('../Icon'),
	Item = require('../Item'),
	MoonHistory = require('../History'),
	HistorySupport = MoonHistory.HistorySupport;

var
	MoonDrawer = require('./Drawer');

/**
* {@link module:moonstone/Drawers~Drawers} is a container kind designed to hold a set of {@link module:moonstone/Drawer~Drawer}
* objects and client content. The [drawers]{@link module:moonstone/Drawers~Drawers#drawers} property accepts
* an array of Drawer controls. The associated handles are positioned in their own small
* drawer, centered at the top of the "dresser" (the region containing the array of Drawer
* controls and the activator nub).
*
* When a handle is selected, it opens the corresponding Drawer object's main drawer or
* control drawer, depending on how the Drawer object is configured. The control's child
* components may be of any kind.
*
* ```
* {
*	kind: 'moon.Drawers',
*	drawers: [
*		{
*			name: 'musicDrawer',
*			kind: 'moon.Drawer',
*			handle: {kind: 'moon.DrawerHandle', content: 'Handle'},
*			components: [
*				{content: 'Drawer Content'}
*			],
*			controlDrawerComponents: [
*				{content: 'Controls'}
*			]
*		}
*	],
*	components: [
*		{content: 'Content Area'}
*	]
* }
* ```
*
* @class Drawers
* @extends module:enyo/Control~Control
* @ui
* @public
*/
module.exports = kind(
	/** @lends module:moonstone/Drawers~Drawers.prototype */ {

	/**
	* @private
	*/
	name: 'moon.Drawers',

	/**
	* @private
	*/
	kind: Control,

	/**
	* @private
	*/
	mixins : [HistorySupport],

	/**
	* @private
	*/
	classes: 'moon-drawers enyo-fit',

	/**
	* @private
	* @lends module:moonstone/Drawers~Drawers.prototype
	*/
	published: {

		/**
		* Populate with an array of {@link module:moonstone/Drawer~Drawer} components.
		*
		* @type {Object[]}
		* @default null
		* @public
		*/
		drawers: null,

		/**
		* When using a font-based icon, the name of the icon to be used.
		* The following icon names are valid:
		*
		* 'drawer'
		* 'arrowlargeup'
		* 'arrowlargedown'
		* 'arrowlargeleft'
		* 'arrowlargeright'
		* 'arrowsmallup'
		* 'arrowsmalldown'
		* 'arrowsmallleft'
		* 'arrowsmallright'
		* 'closex'
		* 'check'
		* 'search'
		*
		* @type {String}
		* @default ''
		* @public
		*/
		icon: '',

		/**
		* URL specifying path to icon image.
		*
		* @type {String|module:enyo/resolution#selectSrc~src}
		* @default ''
		* @public
		*/
		src: ''
	},

	/**
	* Default icon displayed on drawer handle when open
	*
	* @type {String}
	* @default 'arrowsmalldown'
	* @private
	*/
	iconClosed: 'arrowsmalldown',

	/**
	* Default icon displayed on drawer handle when closed
	*
	* @type {String}
	* @default 'arrowsmallup'
	* @private
	*/
	iconOpen: 'arrowsmallup',

	/**
	* Cached value of the top position of the client area. Used for non-accelerated animation.
	*
	* @type {Number}
	* @default 0
	* @private
	*/
	clientTop: 0,

	/**
	* @private
	*/
	handlers: {
		//* Handlers to update the activator when the state of the contained drawers changes
		onActivate: 'drawerActivated',
		onDeactivate: 'drawerDeactivated',
		onSpotlightDown: 'spotDown',
		onSpotlightUp: 'spotUp'
	},

	/**
	* @private
	*/
	components: [
		{name: 'activator', kind: Control, classes: 'moon-drawers-activator', spotlight: true, ontap: 'activatorTapped', components: [
			{name: 'activatorIcon', kind: Icon, classes: 'moon-drawers-activator-icon', small: false}
		]},
		{name: 'handleContainer', kind: Drawer, classes: 'moon-drawers-handle-container', resizeContainer: false, open: false, spotlightDisabled: true, components: [
			{name: 'handles', kind: Control, classes: 'moon-neutral moon-drawers-handles'}
		]},
		{name: 'drawers', kind: Control, classes: 'moon-drawers-drawer-container'},
		{name: 'client', kind: Control, classes: 'moon-drawers-client'}
	],

	/**
	* @private
	*/
	eventsToCapture: {
		ontap: 'captureTapSelect',
		onSpotlightFocus: 'captureSpotFocus',
		onSpotlightSelect: 'captureTapSelect'
	},

	/**
	* @private
	*/
	create: function () {
		Control.prototype.create.apply(this, arguments);
		this.drawers = this.$.drawers.createComponents(this.drawers, {kind: MoonDrawer, owner: this.owner});
		if (!options.accelerate) this.createComponent({name: 'animator', kind: Animator, onStep: 'animationStep'});
		this.setupHandles();
		this.updateActivator();
	},

	/**
	* @private
	*/
	rendered: function () {
		Control.prototype.rendered.apply(this, arguments);
		this.updateDrawerHeight();
	},

	/**
	* @private
	*/
	destroy: function () {
		var i,
			c$ = this.drawers;
		dispatcher.release(this.$.handleContainer);
		for (i = 0; i < c$.length; i++) {
			dispatcher.release(c$[i]);
		}
		Control.prototype.destroy.apply(this, arguments);
	},

	/**
	* @private
	*/
	srcChanged: function () {
		this.updateActivator();
	},

	/**
	* @private
	*/
	iconChanged: function () {
		this.updateActivator();
	},

	/**
	* @private
	*/
	setupHandles: function () {
		var i, len, handle,
			def = {kind: Item, owner: this},
			tap = this.bindSafely(this.handleTapped);

		for (i = 0, len = this.drawers.length; i < len; i++) {
			handle = this.$.handles.createComponent(this.drawers[i].handle || {}, def);
			handle.addClass('moon-drawers-handle');
			handle.tap = tap;
		}
	},

	/**
	* Updates the icon and styling of the activator for the state of the drawer
	*
	* @param {Boolean} open Drawer state
	* @private
	*/
	updateActivator: function (open) {
		var icon, src;

		if (open) {
			src = '';
			icon = this.iconOpen;
		} else {
			src = this.src;
			icon = (src && !this.icon) ? '' : (this.icon || this.iconClosed);
		}

		this.$.activator.addRemoveClass('open', open);
		this.$.activatorIcon.set('src', src);
		this.$.activatorIcon.set('icon', icon);
	},

	/**
	* Inform each drawer of the total available height
	*
	* @private
	*/
	updateDrawerHeight: function () {
		var dh = document.body.getBoundingClientRect().height,
			drawer, i;
		for (i = this.drawers.length - 1; i >= 0; --i) {
			drawer = this.drawers[i];
			if (drawer instanceof MoonDrawer) drawer.set('fullHeight', dh);
		}
	},

	/**
	* @private
	*/
	activatorTapped: function () {
		var handles;
		if (this.isDrawerOpen()) {
			this.closeDrawers();
		} else {
			handles = this.$.handles.getControls();
			if (handles.length == 1) {
				this.openDrawer(handles[0]);
				this.updateActivator(true);
			} else if (this.$.handleContainer.getOpen()) {
				this.closeHandleContainer();
			} else {
				this.openHandleContainer();
			}
		}
	},

	/**
	* @private
	*/
	openHandleContainer: function () {
		this.$.handleContainer.spotlightDisabled = false;
		this.$.handleContainer.setOpen(true);
		this.updateActivator(true);
		dispatcher.capture(this.$.handleContainer, this.eventsToCapture, this);
		if (this.allowBackKey) {
			this.pushBackHistory();
		}
	},

	/**
	* @private
	*/
	closeHandleContainer: function () {
		dispatcher.release(this.$.handleContainer);
		this.$.handleContainer.spotlightDisabled = true;
		this.$.handleContainer.setOpen(false);
		this.updateActivator(this.isDrawerOpen());
	},

	/**
	* @private
	*/
	handleTapped: function (sender, ev) {
		this.openDrawer(ev.originator);
		return true;
	},

	/**
	* @private
	*/
	openDrawer: function (handle) {
		var drawer,
			handles = this.$.handles.getControls();
		for (var index = 0; index < handles.length; ++index) {
			if (handle.isDescendantOf(handles[index])) {
				drawer = this.$.drawers.getControls()[index];
				drawer.show();
				drawer.toggleDrawer();
				this.closeHandleContainer();
				dispatcher.capture(drawer, this.eventsToCapture, this);
				return;
			}
		}
	},

	/**
	* @private
	*/
	isDrawerOpen: function () {
		var drawers = this.$.drawers.getControls();
		for (var index = 0; index < drawers.length; ++index) {
			if (drawers[index].get('open') || drawers[index].get('controlsOpen')) {
				return true;
			}
		}
		return false;
	},

	/**
	* @private
	*/
	closeDrawers: function () {
		var drawers = this.$.drawers.getControls();
		for (var index = 0; index < drawers.length; ++index) {
			var drawer = drawers[index];
			if (drawer.get('open') || drawer.get('controlsOpen')) {
				dispatcher.release(drawer);
				drawer.set('open', false);
				drawer.set('controlsOpen', false);
			}
		}
		this.$.client.spotlightDisabled = false;
		this.updateActivator(false);
	},

	/**
	* @private
	*/
	captureSpotFocus: function (sender, ev) {
		// Only close drawers on 5-way focus in the client (not pointer focus)
		if (ev.dir && ev.dispatchTarget.isDescendantOf(this.$.client)) {
			this.closeDrawers();
			this.closeHandleContainer();
		}
	},

	/**
	* @private
	*/
	captureTapSelect: function (sender, ev) {
		// Any tap or select in the client area closes the dresser/drawer
		if (ev.dispatchTarget.isDescendantOf(this.$.client)) {
			this.closeDrawers();
			this.closeHandleContainer();
		}
	},

	/**
	* Animates the position of the client area when a drawer is opened or closed
	*
	* @private
	*/
	animate: function (height) {
		if (options.accelerate) {
			dom.transformValue(this.$.client, 'translateY', height + 'px');
		} else {
			this.$.animator.play({
				startValue: this.clientTop,
				endValue: height
			});
		}
	},

	/**
	* When `!options.accelerate`, this handles {@link enyo/Animator#event:onStep} to update the
	* position of the client area
	*
	* @private
	*/
	animationStep: function (sender, event) {
		// cache the last top value to be reused by animate() as the startValue
		this.clientTop = sender.value;
		this.$.client.setBounds({top: this.clientTop + 'px'});
	},

	/**
	* @private
	*/
	drawerActivated: function (sender, ev) {
		var drawer = ev.originator instanceof MoonDrawer ? ev.originator : null;
		if (drawer) {
			this.updateActivator(true);
			// show/hide() is expensive. Use spotlightDisabled feature instead
			this.$.client.spotlightDisabled = drawer.open;
			this.animate(ev.height);
		}
	},

	/**
	* @private
	*/
	drawerDeactivated: function (sender, ev) {
		var drawer = ev.originator instanceof MoonDrawer ? ev.originator : null;
		if (drawer) {
			if (!drawer.open && !drawer.controlsOpen) this.updateActivator(false);
			// show/hide() is expensive. Use spotlightDisabled feature instead
			this.$.client.spotlightDisabled = drawer.open;
			this.animate(ev.height);
		}
	},

	/**
	* @private
	*/
	handleResize: function () {
		Control.prototype.handleResize.apply(this, arguments);
		this.updateDrawerHeight();
		this.updateActivator(false);
	},

	/**
	* @private
	*/
	backKeyHandler: function () {
		this.closeHandleContainer();
		return true;
	}
});

module.exports.Drawer = MoonDrawer;<|endoftext|>


<commit_before>var _ = require('lodash');
var async = require('async');
var fs = require('graceful-fs');
var glob = require('glob');
var iconv = require('iconv-lite');
var mkdirp = require('mkdirp');
var mutil = require('miaow-util');
var path = require('path');
var Tapable = require('tapable');

var TaskContext = require('./TaskContext');

function Compilation() {
  Tapable.call(this);
  _.bindAll(this);

  this.modules = {};

  // 创建的模块
  this.emitModules = {};
}

Compilation.prototype = Object.create(Tapable.prototype);
Compilation.prototype.constructor = Compilation;

Compilation.prototype.getFiles = function(callback) {
  glob('**/*', {
    cwd: this.context,
    ignore: this.exclude.concat(['**/miaow.config.js']),
    nodir: true
  }, function(err, files) {
    callback(err, (files || []).map(function(file) {
      return mutil.relative('', file);
    }));
  });
};

// 创建模块
Compilation.prototype.createModules = function(files, callback) {
  async.map(files, this.createModule, callback);
};

Compilation.prototype.createModule = function(file, contents, callback) {
  if (_.isFunction(contents)) {
    callback = contents;
    contents = null;
  }

  this.factory.create(file, contents, function(err, module) {
    if (!err) {
      this.modules[module.src] = module;
    }

    callback(err, module);
  }.bind(this));
};

Compilation.prototype.buildModules = function(modules, callback) {
  this.applyPluginsAsyncSeries('build-modules', this.modules, function(err) {
    if (err) {
      return callback(err);
    }

    async.eachSeries(
      this.modules,
      this.buildModule,
      callback);
  }.bind(this));
};

Compilation.prototype.buildModule = function(module, callback) {
  var taskContext = new TaskContext(this, module);

  this.applyPluginsAsyncSeries('build-module', module, taskContext, function(err) {
    if (err) {
      return callback(err);
    }

    module.doBuild(taskContext).then(function() {
      callback(null, module);
    }, callback);
  });
};

Compilation.prototype.resolveFile = function(context, request, options, callback) {
  if (_.isFunction(options)) {
    callback = options;
    options = {};
  }

  this.resolver.resolve(context, request, options, callback);
};

Compilation.prototype.resolveModule = function(context, request, options, callback) {
  if (_.isFunction(options)) {
    callback = options;
    options = {};
  }

  this.resolver.resolve(context, request, options, function(err, file) {
    if (err) {
      return callback(err);
    }

    var src = mutil.relative(this.context, file);

    var module = this.modules[src];

    if (module) {
      this.buildModule(module, callback);
    } else {
      async.waterfall([
        this.createModule.bind(this, src),
        this.buildModule
      ], callback);
    }
  }.bind(this));
};

Compilation.prototype.emitFile = function(dest, contents, charset, callback) {
  if (!/utf[\-]?8/i.test(charset)) {
    contents = iconv.encode(contents.toString(), charset);
  }

  var abspath = path.resolve(this.output, dest);

  async.series([
    _.partial(mkdirp, path.dirname(abspath)),
    fs.writeFile.bind(fs, abspath, contents)
  ], callback);
};

Compilation.prototype.emitModule = function(src, contents, callback) {
  src = mutil.relative('', src);

  var module = this.modules[src];

  if (module) {
    this.buildModule(module, callback);
  } else {
    async.waterfall([
      this.createModule.bind(this, src, contents),
      function(module, callback) {
        this.emitModules[src] = module;
        callback(null, module);
      }.bind(this),
      this.buildModule
    ], callback);
  }
};

// 编译
Compilation.prototype.seal = function(callback) {
  async.waterfall([
    this.getFiles,
    this.createModules,
    this.buildModules
  ], callback);
};

module.exports = Compilation;
<commit_msg>新增 module 路径模式<commit_after>var _ = require('lodash');
var async = require('async');
var fs = require('graceful-fs');
var glob = require('glob');
var iconv = require('iconv-lite');
var mkdirp = require('mkdirp');
var mutil = require('miaow-util');
var path = require('path');
var Tapable = require('tapable');

var TaskContext = require('./TaskContext');

function Compilation() {
  Tapable.call(this);
  _.bindAll(this);

  this.modules = {};

  // 创建的模块
  this.emitModules = {};
}

Compilation.prototype = Object.create(Tapable.prototype);
Compilation.prototype.constructor = Compilation;

Compilation.prototype.getFiles = function(callback) {
  glob('**/*', {
    cwd: this.context,
    ignore: this.exclude.concat(['**/miaow.config.js']),
    nodir: true
  }, function(err, files) {
    callback(err, (files || []).map(function(file) {
      return mutil.relative('', file);
    }));
  });
};

// 创建模块
Compilation.prototype.createModules = function(files, callback) {
  async.map(files, this.createModule, callback);
};

Compilation.prototype.createModule = function(file, contents, callback) {
  if (_.isFunction(contents)) {
    callback = contents;
    contents = null;
  }

  this.factory.create(file, contents, function(err, module) {
    if (!err) {
      this.modules[module.src] = module;
    }

    callback(err, module);
  }.bind(this));
};

Compilation.prototype.buildModules = function(modules, callback) {
  this.applyPluginsAsyncSeries('build-modules', this.modules, function(err) {
    if (err) {
      return callback(err);
    }

    async.eachSeries(
      this.modules,
      this.buildModule,
      callback);
  }.bind(this));
};

Compilation.prototype.buildModule = function(module, callback) {
  var taskContext = new TaskContext(this, module);

  this.applyPluginsAsyncSeries('build-module', module, taskContext, function(err) {
    if (err) {
      return callback(err);
    }

    module.doBuild(taskContext).then(function() {
      callback(null, module);
    }, callback);
  });
};

Compilation.prototype.resolveFile = function(context, request, options, callback) {
  if (_.isFunction(options)) {
    callback = options;
    options = {};
  }

  this.resolver.resolve(context, request, options, callback);
};

Compilation.prototype.resolveModule = function(context, request, options, callback) {
  if (_.isFunction(options)) {
    callback = options;
    options = {};
  }

  // module://src 格式的路径解析
  var moduleSchemaRegexp = /^module:\/\//;
  if (moduleSchemaRegexp.test(request)) {
    var module = this.modules[request.replace(moduleSchemaRegexp, '')];
    return callback(module ? null : new Error(request + '未被查找到!'), module);
  }

  this.resolver.resolve(context, request, options, function(err, file) {
    if (err) {
      return callback(err);
    }

    var src = mutil.relative(this.context, file);

    var module = this.modules[src];

    if (module) {
      this.buildModule(module, callback);
    } else {
      async.waterfall([
        this.createModule.bind(this, src),
        this.buildModule
      ], callback);
    }
  }.bind(this));
};

Compilation.prototype.emitFile = function(dest, contents, charset, callback) {
  if (!/utf[\-]?8/i.test(charset)) {
    contents = iconv.encode(contents.toString(), charset);
  }

  var abspath = path.resolve(this.output, dest);

  async.series([
    _.partial(mkdirp, path.dirname(abspath)),
    fs.writeFile.bind(fs, abspath, contents)
  ], callback);
};

Compilation.prototype.emitModule = function(src, contents, callback) {
  src = mutil.relative('', src);

  var module = this.modules[src];

  if (module) {
    this.buildModule(module, callback);
  } else {
    async.waterfall([
      this.createModule.bind(this, src, contents),
      function(module, callback) {
        this.emitModules[src] = module;
        callback(null, module);
      }.bind(this),
      this.buildModule
    ], callback);
  }
};

// 编译
Compilation.prototype.seal = function(callback) {
  async.waterfall([
    this.getFiles,
    this.createModules,
    this.buildModules
  ], callback);
};

module.exports = Compilation;
<|endoftext|>


<commit_before>var base58 = require('./Base58').base58;
var coinUtil = require('../util');
var Key = require('./Key');
var Point = require('./Point');
var SecureRandom = require('./SecureRandom');
var bignum = require('bignum');
var networks = require('../networks');

var secp256k1_n = new bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16);
var secp256k1_Gx = new bignum('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16);

/*
random new HierarchicalKey: new HierarchicalKey();
from extended public or private key: new HierarchicalKey(str);
new blank HierarchicalKey: new HierarchicalKey(null);
*/
var HierarchicalKey = function(bytes) {
  if (typeof bytes == 'undefined' || bytes == 'mainnet' || bytes == 'livenet') {
    bytes = 'livenet';
    this.version = networks['livenet'].hkeyPrivateVersion;
  } else if (bytes == 'testnet') {
    this.version = networks['testnet'].hkeyPrivateVersion;
  }
  if (bytes == 'livenet' || bytes == 'testnet') {
    this.depth = 0x00;
    this.parentFingerprint = new Buffer([0, 0, 0, 0]);
    this.childIndex = new Buffer([0, 0, 0, 0]);
    this.chainCode = SecureRandom.getRandomBuffer(32);
    this.eckey = Key.generateSync();
    this.hasPrivateKey = true;
    this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public);
    this.buildExtendedPublicKey();
    this.buildExtendedPrivateKey();
    return;
  }

  // decode base58
  if (typeof bytes === 'string') {
    var decoded = base58.decode(bytes);
    if (decoded.length != 82)
      throw new Error('Not enough data, expected 82 and received ' + decoded.length);
    var checksum = decoded.slice(78, 82);
    bytes = decoded.slice(0, 78);

    var hash = coinUtil.sha256(coinUtil.sha256(bytes));

    if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3]) {
      throw new Error('Invalid checksum');
    }
  }

  if (bytes !== undefined && bytes !== null)
    this.initFromBytes(bytes);
}

HierarchicalKey.seed = function(bytes, network) {
  if (!network)
    network = 'livenet';

  if (!Buffer.isBuffer(bytes))
    bytes = new Buffer(bytes, 'hex'); //if not buffer, assume hex
  if (bytes.length < 128 / 8)
    return false; //need more entropy
  if (bytes.length > 512 / 8)
    return false;
  var hash = coinUtil.sha512hmac(bytes, new Buffer('Bitcoin seed'));

  var hkey = new HierarchicalKey(null);
  hkey.depth = 0x00;
  hkey.parentFingerprint = new Buffer([0, 0, 0, 0]);
  hkey.childIndex = new Buffer([0, 0, 0, 0]);
  hkey.chainCode = hash.slice(32, 64);
  hkey.version = networks[network].hkeyPrivateVersion;
  hkey.eckey = new Key();
  hkey.eckey.private = hash.slice(0, 32);
  hkey.eckey.regenerateSync();
  hkey.hasPrivateKey = true;
  hkey.pubKeyHash = coinUtil.sha256ripe160(hkey.eckey.public);

  hkey.buildExtendedPublicKey();
  hkey.buildExtendedPrivateKey();

  return hkey;
};

HierarchicalKey.prototype.initFromBytes = function(bytes) {
  // Both pub and private extended keys are 78 bytes
  if (bytes.length != 78) throw new Error('not enough data');

  this.version = u32(bytes.slice(0, 4));
  this.depth = u8(bytes.slice(4, 5));
  this.parentFingerprint = bytes.slice(5, 9);
  this.childIndex = u32(bytes.slice(9, 13));
  this.chainCode = bytes.slice(13, 45);

  var keyBytes = bytes.slice(45, 78);

  var isPrivate =
    (this.version == networks['livenet'].hkeyPrivateVersion ||
      this.version == networks['testnet'].hkeyPrivateVersion);

  var isPublic =
    (this.version == networks['livenet'].hkeyPublicVersion ||
      this.version == networks['testnet'].hkeyPublicVersion);

  if (isPrivate && keyBytes[0] == 0) {
    this.eckey = new Key();
    this.eckey.private = keyBytes.slice(1, 33);
    this.eckey.compressed = true;
    this.eckey.regenerateSync();
    this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public);
    this.hasPrivateKey = true;
  } else if (isPublic && (keyBytes[0] == 0x02 || keyBytes[0] == 0x03)) {
    this.eckey = new Key();
    this.eckey.public = keyBytes;
    this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public);
    this.hasPrivateKey = false;
  } else {
    throw new Error('Invalid key');
  }

  this.buildExtendedPublicKey();
  this.buildExtendedPrivateKey();
}

HierarchicalKey.prototype.buildExtendedPublicKey = function() {
  this.extendedPublicKey = new Buffer([]);

  var v = null;
  switch (this.version) {
    case networks['livenet'].hkeyPublicVersion:
    case networks['livenet'].hkeyPrivateVersion:
      v = networks['livenet'].hkeyPublicVersion;
      break;
    case networks['testnet'].hkeyPublicVersion:
    case networks['testnet'].hkeyPrivateVersion:
      v = networks['testnet'].hkeyPublicVersion;
      break;
    default:
      throw new Error('Unknown version');
  }

  // Version
  this.extendedPublicKey = Buffer.concat([
    new Buffer([v >> 24]),
    new Buffer([(v >> 16) & 0xff]),
    new Buffer([(v >> 8) & 0xff]),
    new Buffer([v & 0xff]),
    new Buffer([this.depth]),
    this.parentFingerprint,
    new Buffer([this.childIndex >>> 24]),
    new Buffer([(this.childIndex >>> 16) & 0xff]),
    new Buffer([(this.childIndex >>> 8) & 0xff]),
    new Buffer([this.childIndex & 0xff]),
    this.chainCode,
    this.eckey.public
  ]);
}

HierarchicalKey.prototype.extendedPublicKeyString = function(format) {
  if (format === undefined || format === 'base58') {
    var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPublicKey));
    var checksum = hash.slice(0, 4);
    var data = Buffer.concat([this.extendedPublicKey, checksum]);
    return base58.encode(data);
  } else if (format === 'hex') {
    return this.extendedPublicKey.toString('hex');;
  } else {
    throw new Error('bad format');
  }
}

HierarchicalKey.prototype.buildExtendedPrivateKey = function() {
  if (!this.hasPrivateKey) return;
  this.extendedPrivateKey = new Buffer([]);

  var v = this.version;

  this.extendedPrivateKey = Buffer.concat([
    new Buffer([v >> 24]),
    new Buffer([(v >> 16) & 0xff]),
    new Buffer([(v >> 8) & 0xff]),
    new Buffer([v & 0xff]),
    new Buffer([this.depth]),
    this.parentFingerprint,
    new Buffer([this.childIndex >>> 24]),
    new Buffer([(this.childIndex >>> 16) & 0xff]),
    new Buffer([(this.childIndex >>> 8) & 0xff]),
    new Buffer([this.childIndex & 0xff]),
    this.chainCode,
    new Buffer([0]),
    this.eckey.private
  ]);
}

HierarchicalKey.prototype.extendedPrivateKeyString = function(format) {
  if (format === undefined || format === 'base58') {
    var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPrivateKey));
    var checksum = hash.slice(0, 4);
    var data = Buffer.concat([this.extendedPrivateKey, checksum]);
    return base58.encode(data);
  } else if (format === 'hex') {
    return this.extendedPrivateKey.toString('hex');
  } else {
    throw new Error('bad format');
  }
}

HierarchicalKey.prototype.derive = function(path) {
  var e = path.split('/');

  // Special cases:
  if (path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'')
    return this;

  var hkey = this;
  for (var i in e) {
    var c = e[i];

    if (i == 0) {
      if (c != 'm') throw new Error('invalid path');
      continue;
    }

    var usePrivate = (c.length > 1) && (c[c.length - 1] == '\'');
    var childIndex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff;

    if (usePrivate)
      childIndex += 0x80000000;

    hkey = hkey.deriveChild(childIndex);
  }

  return hkey;
}

HierarchicalKey.prototype.deriveChild = function(i) {
  var ib = [];
  ib.push((i >> 24) & 0xff);
  ib.push((i >> 16) & 0xff);
  ib.push((i >> 8) & 0xff);
  ib.push(i & 0xff);
  ib = new Buffer(ib);

  var usePrivate = (i & 0x80000000) != 0;

  var isPrivate =
    (this.version == networks['livenet'].hkeyPrivateVersion ||
      this.version == networks['testnet'].hkeyPrivateVersion);

  if (usePrivate && (!this.hasPrivateKey || !isPrivate))
    throw new Error('Cannot do private key derivation without private key');

  var ret = null;
  if (this.hasPrivateKey) {
    var data = null;

    if (usePrivate) {
      data = Buffer.concat([new Buffer([0]), this.eckey.private, ib]);
    } else {
      data = Buffer.concat([this.eckey.public, ib]);
    }

    var hash = coinUtil.sha512hmac(data, this.chainCode);
    var il = bignum.fromBuffer(hash.slice(0, 32), {
      size: 32
    });
    var ir = hash.slice(32, 64);

    // ki = IL + kpar (mod n).
    var priv = bignum.fromBuffer(this.eckey.private, {
      size: 32
    });
    var k = il.add(priv).mod(secp256k1_n);

    ret = new HierarchicalKey(null);
    ret.chainCode = ir;

    ret.eckey = new Key();
    ret.eckey.private = k.toBuffer({
      size: 32
    });
    ret.eckey.regenerateSync();
    ret.hasPrivateKey = true;

  } else {
    var data = Buffer.concat([this.eckey.public, ib]);
    var hash = coinUtil.sha512hmac(data, this.chainCode);
    var il = hash.slice(0, 32);
    var ir = hash.slice(32, 64);

    // Ki = (IL + kpar)*G = IL*G + Kpar
    var ilGkey = new Key();
    ilGkey.private = il;
    ilGkey.regenerateSync();
    ilGkey.compressed = false;
    var ilG = Point.fromUncompressedPubKey(ilGkey.public);
    var oldkey = new Key();
    oldkey.public = this.eckey.public;
    oldkey.compressed = false;
    var Kpar = Point.fromUncompressedPubKey(oldkey.public);
    var newpub = Point.add(ilG, Kpar).toUncompressedPubKey();

    ret = new HierarchicalKey(null);
    ret.chainCode = new Buffer(ir);

    var eckey = new Key();
    eckey.public = newpub;
    eckey.compressed = true;
    ret.eckey = eckey;
    ret.hasPrivateKey = false;
  }

  ret.childIndex = i;
  ret.parentFingerprint = this.pubKeyHash.slice(0, 4);
  ret.version = this.version;
  ret.depth = this.depth + 1;

  ret.eckey.compressed = true;
  ret.pubKeyHash = coinUtil.sha256ripe160(ret.eckey.public);

  ret.buildExtendedPublicKey();
  ret.buildExtendedPrivateKey();

  return ret;
}

function uint(f, size) {
  if (f.length < size)
    throw new Error('not enough data');
  var n = 0;
  for (var i = 0; i < size; i++) {
    n *= 256;
    n += f[i];
  }
  return n;
}

function u8(f) {
  return uint(f, 1);
}

function u16(f) {
  return uint(f, 2);
}

function u32(f) {
  return uint(f, 4);
}

function u64(f) {
  return uint(f, 8);
}

module.exports = HierarchicalKey;
<commit_msg>Updating HeirarchicalKey.seed to use a reddcoin salt for compatibility with Reddcoin Electrum<commit_after>var base58 = require('./Base58').base58;
var coinUtil = require('../util');
var Key = require('./Key');
var Point = require('./Point');
var SecureRandom = require('./SecureRandom');
var bignum = require('bignum');
var networks = require('../networks');

var secp256k1_n = new bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16);
var secp256k1_Gx = new bignum('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16);

/*
random new HierarchicalKey: new HierarchicalKey();
from extended public or private key: new HierarchicalKey(str);
new blank HierarchicalKey: new HierarchicalKey(null);
*/
var HierarchicalKey = function(bytes) {
  if (typeof bytes == 'undefined' || bytes == 'mainnet' || bytes == 'livenet') {
    bytes = 'livenet';
    this.version = networks['livenet'].hkeyPrivateVersion;
  } else if (bytes == 'testnet') {
    this.version = networks['testnet'].hkeyPrivateVersion;
  }
  if (bytes == 'livenet' || bytes == 'testnet') {
    this.depth = 0x00;
    this.parentFingerprint = new Buffer([0, 0, 0, 0]);
    this.childIndex = new Buffer([0, 0, 0, 0]);
    this.chainCode = SecureRandom.getRandomBuffer(32);
    this.eckey = Key.generateSync();
    this.hasPrivateKey = true;
    this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public);
    this.buildExtendedPublicKey();
    this.buildExtendedPrivateKey();
    return;
  }

  // decode base58
  if (typeof bytes === 'string') {
    var decoded = base58.decode(bytes);
    if (decoded.length != 82)
      throw new Error('Not enough data, expected 82 and received ' + decoded.length);
    var checksum = decoded.slice(78, 82);
    bytes = decoded.slice(0, 78);

    var hash = coinUtil.sha256(coinUtil.sha256(bytes));

    if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3]) {
      throw new Error('Invalid checksum');
    }
  }

  if (bytes !== undefined && bytes !== null)
    this.initFromBytes(bytes);
}

HierarchicalKey.seed = function(bytes, network) {
  if (!network)
    network = 'livenet';

  if (!Buffer.isBuffer(bytes))
    bytes = new Buffer(bytes, 'hex'); //if not buffer, assume hex
  if (bytes.length < 128 / 8)
    return false; //need more entropy
  if (bytes.length > 512 / 8)
    return false;
  var hash = coinUtil.sha512hmac(bytes, new Buffer('Reddcoin seed'));

  var hkey = new HierarchicalKey(null);
  hkey.depth = 0x00;
  hkey.parentFingerprint = new Buffer([0, 0, 0, 0]);
  hkey.childIndex = new Buffer([0, 0, 0, 0]);
  hkey.chainCode = hash.slice(32, 64);
  hkey.version = networks[network].hkeyPrivateVersion;
  hkey.eckey = new Key();
  hkey.eckey.private = hash.slice(0, 32);
  hkey.eckey.regenerateSync();
  hkey.hasPrivateKey = true;
  hkey.pubKeyHash = coinUtil.sha256ripe160(hkey.eckey.public);

  hkey.buildExtendedPublicKey();
  hkey.buildExtendedPrivateKey();

  return hkey;
};

HierarchicalKey.prototype.initFromBytes = function(bytes) {
  // Both pub and private extended keys are 78 bytes
  if (bytes.length != 78) throw new Error('not enough data');

  this.version = u32(bytes.slice(0, 4));
  this.depth = u8(bytes.slice(4, 5));
  this.parentFingerprint = bytes.slice(5, 9);
  this.childIndex = u32(bytes.slice(9, 13));
  this.chainCode = bytes.slice(13, 45);

  var keyBytes = bytes.slice(45, 78);

  var isPrivate =
    (this.version == networks['livenet'].hkeyPrivateVersion ||
      this.version == networks['testnet'].hkeyPrivateVersion);

  var isPublic =
    (this.version == networks['livenet'].hkeyPublicVersion ||
      this.version == networks['testnet'].hkeyPublicVersion);

  if (isPrivate && keyBytes[0] == 0) {
    this.eckey = new Key();
    this.eckey.private = keyBytes.slice(1, 33);
    this.eckey.compressed = true;
    this.eckey.regenerateSync();
    this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public);
    this.hasPrivateKey = true;
  } else if (isPublic && (keyBytes[0] == 0x02 || keyBytes[0] == 0x03)) {
    this.eckey = new Key();
    this.eckey.public = keyBytes;
    this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public);
    this.hasPrivateKey = false;
  } else {
    throw new Error('Invalid key');
  }

  this.buildExtendedPublicKey();
  this.buildExtendedPrivateKey();
}

HierarchicalKey.prototype.buildExtendedPublicKey = function() {
  this.extendedPublicKey = new Buffer([]);

  var v = null;
  switch (this.version) {
    case networks['livenet'].hkeyPublicVersion:
    case networks['livenet'].hkeyPrivateVersion:
      v = networks['livenet'].hkeyPublicVersion;
      break;
    case networks['testnet'].hkeyPublicVersion:
    case networks['testnet'].hkeyPrivateVersion:
      v = networks['testnet'].hkeyPublicVersion;
      break;
    default:
      throw new Error('Unknown version');
  }

  // Version
  this.extendedPublicKey = Buffer.concat([
    new Buffer([v >> 24]),
    new Buffer([(v >> 16) & 0xff]),
    new Buffer([(v >> 8) & 0xff]),
    new Buffer([v & 0xff]),
    new Buffer([this.depth]),
    this.parentFingerprint,
    new Buffer([this.childIndex >>> 24]),
    new Buffer([(this.childIndex >>> 16) & 0xff]),
    new Buffer([(this.childIndex >>> 8) & 0xff]),
    new Buffer([this.childIndex & 0xff]),
    this.chainCode,
    this.eckey.public
  ]);
}

HierarchicalKey.prototype.extendedPublicKeyString = function(format) {
  if (format === undefined || format === 'base58') {
    var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPublicKey));
    var checksum = hash.slice(0, 4);
    var data = Buffer.concat([this.extendedPublicKey, checksum]);
    return base58.encode(data);
  } else if (format === 'hex') {
    return this.extendedPublicKey.toString('hex');;
  } else {
    throw new Error('bad format');
  }
}

HierarchicalKey.prototype.buildExtendedPrivateKey = function() {
  if (!this.hasPrivateKey) return;
  this.extendedPrivateKey = new Buffer([]);

  var v = this.version;

  this.extendedPrivateKey = Buffer.concat([
    new Buffer([v >> 24]),
    new Buffer([(v >> 16) & 0xff]),
    new Buffer([(v >> 8) & 0xff]),
    new Buffer([v & 0xff]),
    new Buffer([this.depth]),
    this.parentFingerprint,
    new Buffer([this.childIndex >>> 24]),
    new Buffer([(this.childIndex >>> 16) & 0xff]),
    new Buffer([(this.childIndex >>> 8) & 0xff]),
    new Buffer([this.childIndex & 0xff]),
    this.chainCode,
    new Buffer([0]),
    this.eckey.private
  ]);
}

HierarchicalKey.prototype.extendedPrivateKeyString = function(format) {
  if (format === undefined || format === 'base58') {
    var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPrivateKey));
    var checksum = hash.slice(0, 4);
    var data = Buffer.concat([this.extendedPrivateKey, checksum]);
    return base58.encode(data);
  } else if (format === 'hex') {
    return this.extendedPrivateKey.toString('hex');
  } else {
    throw new Error('bad format');
  }
}

HierarchicalKey.prototype.derive = function(path) {
  var e = path.split('/');

  // Special cases:
  if (path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'')
    return this;

  var hkey = this;
  for (var i in e) {
    var c = e[i];

    if (i == 0) {
      if (c != 'm') throw new Error('invalid path');
      continue;
    }

    var usePrivate = (c.length > 1) && (c[c.length - 1] == '\'');
    var childIndex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff;

    if (usePrivate)
      childIndex += 0x80000000;

    hkey = hkey.deriveChild(childIndex);
  }

  return hkey;
}

HierarchicalKey.prototype.deriveChild = function(i) {
  var ib = [];
  ib.push((i >> 24) & 0xff);
  ib.push((i >> 16) & 0xff);
  ib.push((i >> 8) & 0xff);
  ib.push(i & 0xff);
  ib = new Buffer(ib);

  var usePrivate = (i & 0x80000000) != 0;

  var isPrivate =
    (this.version == networks['livenet'].hkeyPrivateVersion ||
      this.version == networks['testnet'].hkeyPrivateVersion);

  if (usePrivate && (!this.hasPrivateKey || !isPrivate))
    throw new Error('Cannot do private key derivation without private key');

  var ret = null;
  if (this.hasPrivateKey) {
    var data = null;

    if (usePrivate) {
      data = Buffer.concat([new Buffer([0]), this.eckey.private, ib]);
    } else {
      data = Buffer.concat([this.eckey.public, ib]);
    }

    var hash = coinUtil.sha512hmac(data, this.chainCode);
    var il = bignum.fromBuffer(hash.slice(0, 32), {
      size: 32
    });
    var ir = hash.slice(32, 64);

    // ki = IL + kpar (mod n).
    var priv = bignum.fromBuffer(this.eckey.private, {
      size: 32
    });
    var k = il.add(priv).mod(secp256k1_n);

    ret = new HierarchicalKey(null);
    ret.chainCode = ir;

    ret.eckey = new Key();
    ret.eckey.private = k.toBuffer({
      size: 32
    });
    ret.eckey.regenerateSync();
    ret.hasPrivateKey = true;

  } else {
    var data = Buffer.concat([this.eckey.public, ib]);
    var hash = coinUtil.sha512hmac(data, this.chainCode);
    var il = hash.slice(0, 32);
    var ir = hash.slice(32, 64);

    // Ki = (IL + kpar)*G = IL*G + Kpar
    var ilGkey = new Key();
    ilGkey.private = il;
    ilGkey.regenerateSync();
    ilGkey.compressed = false;
    var ilG = Point.fromUncompressedPubKey(ilGkey.public);
    var oldkey = new Key();
    oldkey.public = this.eckey.public;
    oldkey.compressed = false;
    var Kpar = Point.fromUncompressedPubKey(oldkey.public);
    var newpub = Point.add(ilG, Kpar).toUncompressedPubKey();

    ret = new HierarchicalKey(null);
    ret.chainCode = new Buffer(ir);

    var eckey = new Key();
    eckey.public = newpub;
    eckey.compressed = true;
    ret.eckey = eckey;
    ret.hasPrivateKey = false;
  }

  ret.childIndex = i;
  ret.parentFingerprint = this.pubKeyHash.slice(0, 4);
  ret.version = this.version;
  ret.depth = this.depth + 1;

  ret.eckey.compressed = true;
  ret.pubKeyHash = coinUtil.sha256ripe160(ret.eckey.public);

  ret.buildExtendedPublicKey();
  ret.buildExtendedPrivateKey();

  return ret;
}

function uint(f, size) {
  if (f.length < size)
    throw new Error('not enough data');
  var n = 0;
  for (var i = 0; i < size; i++) {
    n *= 256;
    n += f[i];
  }
  return n;
}

function u8(f) {
  return uint(f, 1);
}

function u16(f) {
  return uint(f, 2);
}

function u32(f) {
  return uint(f, 4);
}

function u64(f) {
  return uint(f, 8);
}

module.exports = HierarchicalKey;
<|endoftext|>


<commit_before>(function (api){
	var
		  noop = function (){}

		, XHR = function (options){
			this.uid = api.uid();
			this.xhr = {
				  abort: noop
				, getResponseHeader: noop
				, getAllResponseHeaders: noop
			};
			this.options = options;
		}
	;

	XHR.prototype = {
		status: 0,
		statusText: '',

		getResponseHeader: function (name){
			return this.xhr.getResponseHeader(name);
		},

		getAllResponseHeaders: function (){
			return this.xhr.getAllResponseHeaders() || {};
		},

		end: function (status, statusText){
			var _this = this, options = _this.options;

			_this.abort	= noop;
			_this.status = status;

			if( statusText ){
				_this.statusText = statusText;
			}

			options.complete(status == 200 ? false : _this.statusText || 'unknown', _this);

			if( _this.xhr && _this.xhr.node ){
				setTimeout(function (){
					try {
						_this.xhr.node.parentNode.removeChild(_this.xhr.node);
					} catch (er){}
					_this.xhr.node = null;
					delete window[_this.uid];
				}, 1);
			}
		},

		abort: function (){
			this.end(0, 'abort');

			if( this.xhr ){
				this.xhr.abort();
			}
		},

		send: function (FormData){
			var _this = this, options = this.options;

			FormData.toData(function (data){
				// Start uploading
				options.upload(options, _this);
				_this._send.call(_this, options, data);
			});
		},

		_send: function (options, data){
			var _this = this, xhr, uid = _this.uid;

			api.log('XHR._send:', data);

			if( data.nodeName ){
				options.upload(options, _this);

				xhr = document.createElement('div');
				xhr.innerHTML = '<form target="'+ uid +'" action="'+ options.url +'" method="POST" enctype="multipart/form-data" style="position: absolute; top: -1000px; overflow: hidden; width: 1px; height: 1px;">'
							+ ''
							+ '<input value="'+ uid +'" name="callback" type="hidden"/>'
							+ '</form>'
				;

				_this.xhr.abort = function (){
					var transport = xhr.getElementsByName('iframe')[0];
					if( transport ){
						try {
							if( transport.stop ) transport.stop();
							else if( transport.contentWindow.stop ) transport.contentWindow.stop();
							else transport.contentWindow.document.execCommand('Stop');
						}
						catch (er) {}
					}
				};

				// append form-data
				var form = xhr.getElementsByTagName('form')[0];
				form.appendChild(data);

				// append to DOM
				document.body.appendChild(xhr);

				// keep a reference to node-transport
				this.xhr.node = xhr;

				// jsonp-callack
				window[uid] = function (status, statusText, response){
					_this.readyState	= 4;
					_this.responseText	= response;
					_this.end(status, statusText);
				};

				// send
				_this.readyState = 2; // loaded
				form.submit();
				form = null;
			}
			else {
				xhr = _this.xhr = api.getXHR();

				xhr.open('POST', options.url, true);
				xhr.withCredential = "true";

				api.each(options.headers, function (val, key){
					xhr.setRequestHeader(key, val);
				});

				if( xhr.upload ){
					// https://github.com/blueimp/jQuery-File-Upload/wiki/Fixing-Safari-hanging-on-very-high-speed-connections-%281Gbps%29
					api.event.on(xhr.upload, 'progress', api.throttle(function (/**Event*/evt){
						options.progress(evt, options, _this);
					}, 100));
				}

				xhr.onreadystatechange = function (){
					_this.status     = xhr.status;
					_this.statusText = xhr.statusText;
					_this.readyState = xhr.readyState;

					if( xhr.readyState == 4 ){
						for( var k in { '': 1, XML: 1, Text: 1, Body: 1 } ){
							_this['response'+k]  = xhr['response'+k];
						}
						xhr.onreadystatechange = null;
						_this.end(xhr.status);
					}
				};

				if( api.isArray(data) ){
					// multipart
					xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=_'+api.expando);
					data = data.join('') +'--_'+ api.expando +'--';

					/** @namespace  xhr.sendAsBinary  https://developer.mozilla.org/ru/XMLHttpRequest#Sending_binary_content */
					if( xhr.sendAsBinary ){
						xhr.sendAsBinary(data);
					}
					else {
						var bytes = Array.prototype.map.call(data, function(c){ return c.charCodeAt(0) & 0xff; });
						xhr.send(new Uint8Array(bytes).buffer);

					}
				}
				else {
					xhr.send(data);
				}
			}
		}
	};

	// @export
	api.XHR = XHR;
})(FileAPI);
<commit_msg>+ X-Requested-With header<commit_after>(function (api){
	var
		  noop = function (){}

		, XHR = function (options){
			this.uid = api.uid();
			this.xhr = {
				  abort: noop
				, getResponseHeader: noop
				, getAllResponseHeaders: noop
			};
			this.options = options;
		}
	;

	XHR.prototype = {
		status: 0,
		statusText: '',

		getResponseHeader: function (name){
			return this.xhr.getResponseHeader(name);
		},

		getAllResponseHeaders: function (){
			return this.xhr.getAllResponseHeaders() || {};
		},

		end: function (status, statusText){
			var _this = this, options = _this.options;

			_this.abort	= noop;
			_this.status = status;

			if( statusText ){
				_this.statusText = statusText;
			}

			options.complete(status == 200 ? false : _this.statusText || 'unknown', _this);

			if( _this.xhr && _this.xhr.node ){
				setTimeout(function (){
					try {
						_this.xhr.node.parentNode.removeChild(_this.xhr.node);
					} catch (er){}
					_this.xhr.node = null;
					delete window[_this.uid];
				}, 1);
			}
		},

		abort: function (){
			this.end(0, 'abort');

			if( this.xhr ){
				this.xhr.abort();
			}
		},

		send: function (FormData){
			var _this = this, options = this.options;

			FormData.toData(function (data){
				// Start uploading
				options.upload(options, _this);
				_this._send.call(_this, options, data);
			});
		},

		_send: function (options, data){
			var _this = this, xhr, uid = _this.uid;

			api.log('XHR._send:', data);

			if( data.nodeName ){
				options.upload(options, _this);

				xhr = document.createElement('div');
				xhr.innerHTML = '<form target="'+ uid +'" action="'+ options.url +'" method="POST" enctype="multipart/form-data" style="position: absolute; top: -1000px; overflow: hidden; width: 1px; height: 1px;">'
							+ ''
							+ '<input value="'+ uid +'" name="callback" type="hidden"/>'
							+ '</form>'
				;

				_this.xhr.abort = function (){
					var transport = xhr.getElementsByName('iframe')[0];
					if( transport ){
						try {
							if( transport.stop ) transport.stop();
							else if( transport.contentWindow.stop ) transport.contentWindow.stop();
							else transport.contentWindow.document.execCommand('Stop');
						}
						catch (er) {}
					}
				};

				// append form-data
				var form = xhr.getElementsByTagName('form')[0];
				form.appendChild(data);

				// append to DOM
				document.body.appendChild(xhr);

				// keep a reference to node-transport
				this.xhr.node = xhr;

				// jsonp-callack
				window[uid] = function (status, statusText, response){
					_this.readyState	= 4;
					_this.responseText	= response;
					_this.end(status, statusText);
				};

				// send
				_this.readyState = 2; // loaded
				form.submit();
				form = null;
			}
			else {
				xhr = _this.xhr = api.getXHR();

				xhr.open('POST', options.url, true);
				xhr.withCredential = "true";

				if( !options.headers || !options.headers['X-Requested-With'] ){
					xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
				}

				api.each(options.headers, function (val, key){
					xhr.setRequestHeader(key, val);
				});

				if( xhr.upload ){
					// https://github.com/blueimp/jQuery-File-Upload/wiki/Fixing-Safari-hanging-on-very-high-speed-connections-%281Gbps%29
					api.event.on(xhr.upload, 'progress', api.throttle(function (/**Event*/evt){
						options.progress(evt, options, _this);
					}, 100));
				}

				xhr.onreadystatechange = function (){
					_this.status     = xhr.status;
					_this.statusText = xhr.statusText;
					_this.readyState = xhr.readyState;

					if( xhr.readyState == 4 ){
						for( var k in { '': 1, XML: 1, Text: 1, Body: 1 } ){
							_this['response'+k]  = xhr['response'+k];
						}
						xhr.onreadystatechange = null;
						_this.end(xhr.status);
					}
				};

				if( api.isArray(data) ){
					// multipart
					xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=_'+api.expando);
					data = data.join('') +'--_'+ api.expando +'--';

					/** @namespace  xhr.sendAsBinary  https://developer.mozilla.org/ru/XMLHttpRequest#Sending_binary_content */
					if( xhr.sendAsBinary ){
						xhr.sendAsBinary(data);
					}
					else {
						var bytes = Array.prototype.map.call(data, function(c){ return c.charCodeAt(0) & 0xff; });
						xhr.send(new Uint8Array(bytes).buffer);

					}
				}
				else {
					xhr.send(data);
				}
			}
		}
	};

	// @export
	api.XHR = XHR;
})(FileAPI);
<|endoftext|>


<commit_before>/************************************
 * Copyright (c) 2014 AnsibleWorks, Inc.
 *
 *
 *  Teams.js
 *
 *  Controller functions for the Team model.
 *
 */
/**
 * @ngdoc function
 * @name controllers.function:Teams
 * @description This controller's for teams
*/
'use strict';

function TeamsList($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, TeamList, GenerateList, LoadBreadCrumbs,
    Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, SelectionInit, Wait,
    Stream) {

    ClearScope();

    var list = TeamList,
        defaultUrl = GetBasePath('teams'),
        generator = GenerateList,
        paths = $location.path().replace(/^\//, '').split('/'),
        mode = (paths[0] === 'teams') ? 'edit' : 'select',
        url;

    generator.inject(list, { mode: mode, scope: $scope });
    $scope.selected = [];

    url = GetBasePath('base') + $location.path() + '/';
    SelectionInit({
        scope: $scope,
        list: list,
        url: url,
        returnToCaller: 1
    });

    if ($scope.removePostRefresh) {
        $scope.removePostRefresh();
    }
    $scope.removePostRefresh = $scope.$on('PostRefresh', function () {
        // After a refresh, populate the organization name on each row
        var i;
        if ($scope.teams) {
            for (i = 0; i < $scope.teams.length; i++) {
                $scope.teams[i].organization_name = $scope.teams[i].summary_fields.organization.name;
            }
        }
    });

    SearchInit({
        scope: $scope,
        set: 'teams',
        list: list,
        url: defaultUrl
    });
    PaginateInit({
        scope: $scope,
        list: list,
        url: defaultUrl
    });
    $scope.search(list.iterator);

    LoadBreadCrumbs();

    $scope.showActivity = function () {
        Stream({ scope: $scope });
    };

    $scope.addTeam = function () {
        $location.path($location.path() + '/add');
    };

    $scope.editTeam = function (id) {
        $location.path($location.path() + '/' + id);
    };

    $scope.deleteTeam = function (id, name) {

        var action = function () {
            Wait('start');
            var url = defaultUrl + id + '/';
            Rest.setUrl(url);
            Rest.destroy()
                .success(function () {
                    Wait('stop');
                    $('#prompt-modal').modal('hide');
                    $scope.search(list.iterator);
                })
                .error(function (data, status) {
                    Wait('stop');
                    $('#prompt-modal').modal('hide');
                    ProcessErrors($scope, data, status, null, {
                        hdr: 'Error!',
                        msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
                    });
                });
        };

        Prompt({
            hdr: 'Delete',
            body: '
Delete team ' + name + '?
',
            action: action
        });
    };
}

TeamsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'TeamList', 'GenerateList',
    'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
    'SetTeamListeners', 'GetBasePath', 'SelectionInit', 'Wait', 'Stream'
];

function TeamsAdd($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm,
    Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GenerateList,
    OrganizationList, SearchInit, PaginateInit, GetBasePath, LookUpInit, Wait) {
    ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
    //$scope.

    // Inject dynamic view
    var defaultUrl = GetBasePath('teams'),
        form = TeamForm,
        generator = GenerateForm,
        scope = generator.inject(form, { mode: 'add', related: false });

    $rootScope.flashMessage = null;
    generator.reset();
    LoadBreadCrumbs();

    LookUpInit({
        scope: $scope,
        form: form,
        current_item: null,
        list: OrganizationList,
        field: 'organization',
        input_type: 'radio'
    });

    // Save
    $scope.formSave = function () {
        var fld, data;
        generator.clearApiErrors();
        Wait('start');
        Rest.setUrl(defaultUrl);
        data = {};
        for (fld in form.fields) {
            data[fld] = scope[fld];
        }
        Rest.post(data)
            .success(function (data) {
                Wait('stop');
                $rootScope.flashMessage = "New team successfully created!";
                $location.path('/teams/' + data.id);
            })
            .error(function (data, status) {
                Wait('stop');
                ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to add new team. Post returned status: ' +
                    status });
            });
    };

    // Reset
    $scope.formReset = function () {
        // Defaults
        generator.reset();
    };
}

TeamsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm', 'GenerateForm',
    'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
    'OrganizationList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'LookUpInit', 'Wait'
];

function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm, Rest, Alert, ProcessErrors,
    LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, GetBasePath, CheckAccess,
    OrganizationList, Wait, Stream) {

    ClearScope();

    var defaultUrl = GetBasePath('teams'),
        generator = GenerateForm,
        form = TeamForm,
        base = $location.path().replace(/^\//, '').split('/')[0],
        master = {},
        id = $routeParams.team_id,
        relatedSets = {};

    generator.inject(form, { mode: 'edit', related: true, scope: $scope });
    generator.reset();

    $scope.PermissionAddAllowed = false;

    // Retrieve each related set and any lookups
    if ($scope.teamLoadedRemove) {
        $scope.teamLoadedRemove();
    }
    $scope.teamLoadedRemove = $scope.$on('teamLoaded', function () {
        CheckAccess({ scope: $scope });
        Rest.setUrl($scope.organization_url);
        Rest.get()
            .success(function (data) {
                $scope.organization_name = data.name;
                master.organization_name = data.name;
                Wait('stop');
            })
            .error(function (data, status) {
                ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve organization: ' +
                    $scope.orgnization_url + '. GET status: ' + status });
            });
        for (var set in relatedSets) {
            $scope.search(relatedSets[set].iterator);
        }
    });

    // Retrieve detail record and prepopulate the form
    Wait('start');
    Rest.setUrl(defaultUrl + ':id/');
    Rest.get({
        params: {
            id: id
        }
    })
        .success(function (data) {
            var fld, related, set;
            LoadBreadCrumbs({ path: '/teams/' + id, title: data.name });
            for (fld in form.fields) {
                if (data[fld]) {
                    $scope[fld] = data[fld];
                    master[fld] = $scope[fld];
                }
            }
            related = data.related;
            for (set in form.related) {
                if (related[set]) {
                    relatedSets[set] = {
                        url: related[set],
                        iterator: form.related[set].iterator
                    };
                }
            }
            // Initialize related search functions. Doing it here to make sure relatedSets object is populated.
            RelatedSearchInit({
                scope: $scope,
                form: form,
                relatedSets: relatedSets
            });
            RelatedPaginateInit({
                scope: $scope,
                relatedSets: relatedSets
            });

            LookUpInit({
                scope: $scope,
                form: form,
                current_item: data.organization,
                list: OrganizationList,
                field: 'organization',
                input_type: 'radio'
            });

            $scope.organization_url = data.related.organization;
            $scope.$emit('teamLoaded');
        })
        .error(function (data, status) {
            ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to retrieve team: ' + $routeParams.team_id +
                '. GET status: ' + status });
        });

    $scope.showActivity = function () {
        Stream({ scope: $scope });
    };

    // Save changes to the parent
    $scope.formSave = function () {
        var data = {}, fld;
        generator.clearApiErrors();
        Wait('start');
        $rootScope.flashMessage = null;
        Rest.setUrl(defaultUrl + $routeParams.team_id + '/');
        for (fld in form.fields) {
            data[fld] = $scope[fld];
        }
        Rest.put(data)
            .success(function () {
                Wait('stop');
                var base = $location.path().replace(/^\//, '').split('/')[0];
                if (base === 'teams') {
                    ReturnToCaller();
                }
                else {
                    ReturnToCaller(1);
                }
            })
            .error(function (data, status) {
                Wait('stop');
                ProcessErrors($scope, data, status, form, { hdr: 'Error!',
                    msg: 'Failed to update team: ' + $routeParams.team_id + '. PUT status: ' + status });
            });
    };

    // Cancel
    $scope.formReset = function () {
        $rootScope.flashMessage = null;
        generator.reset();
        for (var fld in master) {
            $scope[fld] = master[fld];
        }
    };

    // Related set: Add button
    $scope.add = function (set) {
        $rootScope.flashMessage = null;
        if (set === 'permissions') {
            if ($scope.PermissionAddAllowed) {
                $location.path('/' + base + '/' + $routeParams.team_id + '/' + set + '/add');
            } else {
                Alert('Access Denied', 'You do not have access to this function. Please contact your system administrator.');
            }
        } else {
            $location.path('/' + base + '/' + $routeParams.team_id + '/' + set);
        }
    };

    // Related set: Edit button
    $scope.edit = function (set, id) {
        $rootScope.flashMessage = null;
        if (set === 'permissions') {
            $location.path('/' + base + '/' + $routeParams.team_id + '/' + set + '/' + id);
        } else {
            $location.path('/' + set + '/' + id);
        }
    };

    // Related set: Delete button
    $scope['delete'] = function (set, itm_id, name, title) {
        $rootScope.flashMessage = null;

        var action = function () {
            var url;
            if (set === 'permissions') {
                if ($scope.PermissionAddAllowed) {
                    url = GetBasePath('base') + 'permissions/' + itm_id + '/';
                    Rest.setUrl(url);
                    Rest.destroy()
                        .success(function () {
                            $('#prompt-modal').modal('hide');
                            $scope.search(form.related[set].iterator);
                        })
                        .error(function (data, status) {
                            $('#prompt-modal').modal('hide');
                            ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
                                ' failed. DELETE returned status: ' + status });
                        });
                } else {
                    Alert('Access Denied', 'You do not have access to this function. Please contact your system administrator.');
                }
            } else {
                url = defaultUrl + $routeParams.team_id + '/' + set + '/';
                Rest.setUrl(url);
                Rest.post({ id: itm_id, disassociate: 1 })
                    .success(function () {
                        $('#prompt-modal').modal('hide');
                        $scope.search(form.related[set].iterator);
                    })
                    .error(function (data, status) {
                        $('#prompt-modal').modal('hide');
                        ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
                            ' failed. POST returned status: ' + status });
                    });
            }
        };

        Prompt({
            hdr: 'Delete',
            body: 'Are you sure you want to remove ' + name + ' from ' + $scope.name + ' ' + title + '?',
            action: action
        });
    };
}

TeamsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm',
    'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit',
    'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream'
];<commit_msg>Fixed teams list crashing when team has no organization<commit_after>/************************************
 * Copyright (c) 2014 AnsibleWorks, Inc.
 *
 *
 *  Teams.js
 *
 *  Controller functions for the Team model.
 *
 */
/**
 * @ngdoc function
 * @name controllers.function:Teams
 * @description This controller's for teams
*/
'use strict';

function TeamsList($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, TeamList, GenerateList, LoadBreadCrumbs,
    Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, SelectionInit, Wait,
    Stream) {

    ClearScope();

    var list = TeamList,
        defaultUrl = GetBasePath('teams'),
        generator = GenerateList,
        paths = $location.path().replace(/^\//, '').split('/'),
        mode = (paths[0] === 'teams') ? 'edit' : 'select',
        url;

    generator.inject(list, { mode: mode, scope: $scope });
    $scope.selected = [];

    url = GetBasePath('base') + $location.path() + '/';
    SelectionInit({
        scope: $scope,
        list: list,
        url: url,
        returnToCaller: 1
    });

    if ($scope.removePostRefresh) {
        $scope.removePostRefresh();
    }
    $scope.removePostRefresh = $scope.$on('PostRefresh', function () {
        // After a refresh, populate the organization name on each row
        var i;
        if ($scope.teams) {
            for (i = 0; i < $scope.teams.length; i++) {
                if ($scope.teams[i].summary_fields.organization) {
                    $scope.teams[i].organization_name = $scope.teams[i].summary_fields.organization.name;
                }
            }
        }
    });

    SearchInit({
        scope: $scope,
        set: 'teams',
        list: list,
        url: defaultUrl
    });
    PaginateInit({
        scope: $scope,
        list: list,
        url: defaultUrl
    });
    $scope.search(list.iterator);

    LoadBreadCrumbs();

    $scope.showActivity = function () {
        Stream({ scope: $scope });
    };

    $scope.addTeam = function () {
        $location.path($location.path() + '/add');
    };

    $scope.editTeam = function (id) {
        $location.path($location.path() + '/' + id);
    };

    $scope.deleteTeam = function (id, name) {

        var action = function () {
            Wait('start');
            var url = defaultUrl + id + '/';
            Rest.setUrl(url);
            Rest.destroy()
                .success(function () {
                    Wait('stop');
                    $('#prompt-modal').modal('hide');
                    $scope.search(list.iterator);
                })
                .error(function (data, status) {
                    Wait('stop');
                    $('#prompt-modal').modal('hide');
                    ProcessErrors($scope, data, status, null, {
                        hdr: 'Error!',
                        msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
                    });
                });
        };

        Prompt({
            hdr: 'Delete',
            body: '
Delete team ' + name + '?
',
            action: action
        });
    };
}

TeamsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'TeamList', 'GenerateList',
    'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
    'SetTeamListeners', 'GetBasePath', 'SelectionInit', 'Wait', 'Stream'
];

function TeamsAdd($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm,
    Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GenerateList,
    OrganizationList, SearchInit, PaginateInit, GetBasePath, LookUpInit, Wait) {
    ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
    //$scope.

    // Inject dynamic view
    var defaultUrl = GetBasePath('teams'),
        form = TeamForm,
        generator = GenerateForm,
        scope = generator.inject(form, { mode: 'add', related: false });

    $rootScope.flashMessage = null;
    generator.reset();
    LoadBreadCrumbs();

    LookUpInit({
        scope: $scope,
        form: form,
        current_item: null,
        list: OrganizationList,
        field: 'organization',
        input_type: 'radio'
    });

    // Save
    $scope.formSave = function () {
        var fld, data;
        generator.clearApiErrors();
        Wait('start');
        Rest.setUrl(defaultUrl);
        data = {};
        for (fld in form.fields) {
            data[fld] = scope[fld];
        }
        Rest.post(data)
            .success(function (data) {
                Wait('stop');
                $rootScope.flashMessage = "New team successfully created!";
                $location.path('/teams/' + data.id);
            })
            .error(function (data, status) {
                Wait('stop');
                ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to add new team. Post returned status: ' +
                    status });
            });
    };

    // Reset
    $scope.formReset = function () {
        // Defaults
        generator.reset();
    };
}

TeamsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm', 'GenerateForm',
    'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
    'OrganizationList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'LookUpInit', 'Wait'
];

function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm, Rest, Alert, ProcessErrors,
    LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, GetBasePath, CheckAccess,
    OrganizationList, Wait, Stream) {

    ClearScope();

    var defaultUrl = GetBasePath('teams'),
        generator = GenerateForm,
        form = TeamForm,
        base = $location.path().replace(/^\//, '').split('/')[0],
        master = {},
        id = $routeParams.team_id,
        relatedSets = {};

    generator.inject(form, { mode: 'edit', related: true, scope: $scope });
    generator.reset();

    $scope.PermissionAddAllowed = false;

    // Retrieve each related set and any lookups
    if ($scope.teamLoadedRemove) {
        $scope.teamLoadedRemove();
    }
    $scope.teamLoadedRemove = $scope.$on('teamLoaded', function () {
        CheckAccess({ scope: $scope });
        Rest.setUrl($scope.organization_url);
        Rest.get()
            .success(function (data) {
                $scope.organization_name = data.name;
                master.organization_name = data.name;
                Wait('stop');
            })
            .error(function (data, status) {
                ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve organization: ' +
                    $scope.orgnization_url + '. GET status: ' + status });
            });
        for (var set in relatedSets) {
            $scope.search(relatedSets[set].iterator);
        }
    });

    // Retrieve detail record and prepopulate the form
    Wait('start');
    Rest.setUrl(defaultUrl + ':id/');
    Rest.get({
        params: {
            id: id
        }
    })
        .success(function (data) {
            var fld, related, set;
            LoadBreadCrumbs({ path: '/teams/' + id, title: data.name });
            for (fld in form.fields) {
                if (data[fld]) {
                    $scope[fld] = data[fld];
                    master[fld] = $scope[fld];
                }
            }
            related = data.related;
            for (set in form.related) {
                if (related[set]) {
                    relatedSets[set] = {
                        url: related[set],
                        iterator: form.related[set].iterator
                    };
                }
            }
            // Initialize related search functions. Doing it here to make sure relatedSets object is populated.
            RelatedSearchInit({
                scope: $scope,
                form: form,
                relatedSets: relatedSets
            });
            RelatedPaginateInit({
                scope: $scope,
                relatedSets: relatedSets
            });

            LookUpInit({
                scope: $scope,
                form: form,
                current_item: data.organization,
                list: OrganizationList,
                field: 'organization',
                input_type: 'radio'
            });

            $scope.organization_url = data.related.organization;
            $scope.$emit('teamLoaded');
        })
        .error(function (data, status) {
            ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to retrieve team: ' + $routeParams.team_id +
                '. GET status: ' + status });
        });

    $scope.showActivity = function () {
        Stream({ scope: $scope });
    };

    // Save changes to the parent
    $scope.formSave = function () {
        var data = {}, fld;
        generator.clearApiErrors();
        Wait('start');
        $rootScope.flashMessage = null;
        Rest.setUrl(defaultUrl + $routeParams.team_id + '/');
        for (fld in form.fields) {
            data[fld] = $scope[fld];
        }
        Rest.put(data)
            .success(function () {
                Wait('stop');
                var base = $location.path().replace(/^\//, '').split('/')[0];
                if (base === 'teams') {
                    ReturnToCaller();
                }
                else {
                    ReturnToCaller(1);
                }
            })
            .error(function (data, status) {
                Wait('stop');
                ProcessErrors($scope, data, status, form, { hdr: 'Error!',
                    msg: 'Failed to update team: ' + $routeParams.team_id + '. PUT status: ' + status });
            });
    };

    // Cancel
    $scope.formReset = function () {
        $rootScope.flashMessage = null;
        generator.reset();
        for (var fld in master) {
            $scope[fld] = master[fld];
        }
    };

    // Related set: Add button
    $scope.add = function (set) {
        $rootScope.flashMessage = null;
        if (set === 'permissions') {
            if ($scope.PermissionAddAllowed) {
                $location.path('/' + base + '/' + $routeParams.team_id + '/' + set + '/add');
            } else {
                Alert('Access Denied', 'You do not have access to this function. Please contact your system administrator.');
            }
        } else {
            $location.path('/' + base + '/' + $routeParams.team_id + '/' + set);
        }
    };

    // Related set: Edit button
    $scope.edit = function (set, id) {
        $rootScope.flashMessage = null;
        if (set === 'permissions') {
            $location.path('/' + base + '/' + $routeParams.team_id + '/' + set + '/' + id);
        } else {
            $location.path('/' + set + '/' + id);
        }
    };

    // Related set: Delete button
    $scope['delete'] = function (set, itm_id, name, title) {
        $rootScope.flashMessage = null;

        var action = function () {
            var url;
            if (set === 'permissions') {
                if ($scope.PermissionAddAllowed) {
                    url = GetBasePath('base') + 'permissions/' + itm_id + '/';
                    Rest.setUrl(url);
                    Rest.destroy()
                        .success(function () {
                            $('#prompt-modal').modal('hide');
                            $scope.search(form.related[set].iterator);
                        })
                        .error(function (data, status) {
                            $('#prompt-modal').modal('hide');
                            ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
                                ' failed. DELETE returned status: ' + status });
                        });
                } else {
                    Alert('Access Denied', 'You do not have access to this function. Please contact your system administrator.');
                }
            } else {
                url = defaultUrl + $routeParams.team_id + '/' + set + '/';
                Rest.setUrl(url);
                Rest.post({ id: itm_id, disassociate: 1 })
                    .success(function () {
                        $('#prompt-modal').modal('hide');
                        $scope.search(form.related[set].iterator);
                    })
                    .error(function (data, status) {
                        $('#prompt-modal').modal('hide');
                        ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
                            ' failed. POST returned status: ' + status });
                    });
            }
        };

        Prompt({
            hdr: 'Delete',
            body: 'Are you sure you want to remove ' + name + ' from ' + $scope.name + ' ' + title + '?',
            action: action
        });
    };
}

TeamsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm',
    'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit',
    'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream'
];<|endoftext|>