<commit_before>
mop.modules.ListModule = new Class({

	/* TODO write unit tests for List*/

	Extends: mop.modules.Module,

	// listing properties and members, helps with maintenance and destruction.... standard practice from now on
	sortable: null,
	sortDirection: null,
	instanceName: null,
	addItemDialogue: null,
	items: null,
	controls: null,
	sortableList: null,
	scroller: null,
	submitDelay: null,
	oldSort: null,

	initialize: function( anElement, aMarshal, options ){

		this.parent( anElement, aMarshal, options );

		delete this.items;
		this.items = null;
		this.items = [];

		this.sortable = ( this.getValueFromClassName( "sortable" ) != "false" ) ? this.getValueFromClassName( "sortable" ) : false;
		this.sortDirection = this.getValueFromClassName( "sortDirection" );

		if( this.sortable ) this.makeSortable();
	},

	toString: function(){
		return "[ object, mop.modules.ListModule ]";
	},

	getInstanceName: function(){
		return this.instanceName;
	},

	build: function(){
		this.parent();
		this.initControls();
		this.addItemDialogue = null;
//		console.log( "build", this.toString() );
		this.initList();
	},

	initList: function(){
		delete this.items;
		this.items = null;
		this.items = [];
		this.listing = this.element.getElement( ".listing" );
		var children = this.listing.getChildren("li");
		children.each( function( element ){
			this.items.push( new mop.modules.ListItem( element, this, this.addItemDialogue ) );
		}, this );
	},

	toggleSortable: function(){
		if( this.sortable ){ this.killSortable(); }else{ this.makeSortable(); }
	},

	initControls: function(){
		// console.log( this.element.getElement( "#" + this.instanceName+"AddItemModal" ).retrieve("Class") );
		this.controls = this.element.getChildren( ".controls" );
		var addItemButton = this.controls.getElement( ".addItem" ).addEvent("click", this.addItem.bindWithEvent( this ) );//this.showModal.bindWithEvent( this, $( this.instanceName+"AddItemModal" ) ) );
		if( this.sortable ){
			var saveSort = this.controls.getElement( ".saveSort" ).addEvent("click", this.saveSort.bindWithEvent( this ) );
			saveSort = null;
		}
		addItemButton = null;
	},

	makeSortable: function(){
		if( this.sortable && !this.sortableList ){
				this.sortableList = new mop.ui.Sortable(  this.listing, this, {
				scrollElement: window,
				clone:  true,
				snap: 12,
				revert: true,
				velocity: .97,
				area: 24,
				constrain: true,
				onComplete: function( el ){
					if(!this.moved) return;
					this.moved = false;
					this.scroller.stop();
					this.marshal.onOrderChanged();
				},
				onStart: function(){
					this.moved = true;
					this.scroller.start();
				}
			});
		}else if( this.sortable ){
			this.sortableList.attach();
		}
		this.oldSort = this.serialize();
	},

	resumeSort: function(){
		if( this.sortable && this.sortableList ) this.sortableList.attach();
	},

	suspendSort: function(){
		if( this.sortable && this.sortableList ) this.sortableList.detach();
	},

	killSortable: function(){
		this.sortableList.detach();
		delete this.sortableList;
		this.sortableList = null;
	},

	onOrderChanged: function(){
		var newOrder = this.serialize();
		$clear( this.submitDelay );
		this.submitDelay = this.submitSortOrder.periodical( 3000, this, newOrder.join(",") );
		newOrder = null;
	},

	submitSortOrder: function( newOrder ){
		if( this.sortable && this.oldSort != newOrder ){
			$clear( this.submitDelay );
			this.submitDelay = null;
			this.JSONSend( "saveSortOrder", { sortorder: newOrder } );
			this.oldSort = newOrder;
		}
	},

	addItem: function( e ){
		if( e && e.preventDefault ){
			e.preventDefault();
		}else{
			e.returnValue = false;
		}

		if( this.addItemDialogue ) this.removeModal( this.addItemDialogue );
		this.addItemDialogue = new mop.ui.EnhancedAddItemDialogue( null, this );
		this.addItemDialogue.showLoading( e.target.get("text") );

		this.JSONSend( "addItem", null, {
			onComplete: function( json ){
				this.onItemAdded( json );
			}.bind( this )
		});
	},

	onItemAdded: function( json  ){
		var element = this.addItemDialogue.setContent( json.response, this.controls.getElement( ".addItem" ).get( "text" ) );
		var listItem = new mop.modules.ListItem( element, this, this.addItemDialogue, { scrollContext: 'modal' } );
		listItem.uiElements.each( function( uiInstance ){
			uiInstance.scrollContext = "modal";
		});
		listItem.filesToTop();
		this.items.push( listItem );
		this.addItemDialogue.show();
		listItem = null;
	},

	removeModal: function( aModal ){
		if( !this.addItemDialogue ) return;
		this.addItemDialogue = null;
	},

	insertItem: function( anElement ){
		var where = ( this.sortDirection == "DESC" )? "top" : "bottom";
		this.listing.grab( anElement, where );
		if( this.sortable && this.sortableList ) this.sortableList.addItems( anElement );

		// reset scrollContexts
		var listItemInstance = anElement.retrieve("Class");
		listItemInstance.scrollContext = 'window';
		listItemInstance.resetFileDepth();
		listItemInstance.uiElements.each( function( uiInstance ){
			uiInstance.scrollContext = "window";
		});
		anElement.tween( "opacity", 1 );
	 	anElement.getElement(".itemControls" ).getElement(".delete").removeClass("hidden");

		if( this.sortable != null ) this.onOrderChanged();
		listItemInstance = where = null;
	},

	serialize:function(){
		console.log( this.toString(), "serialize", this.listing, this.listing.getChildren() )
		var sortArray = [];

		//get all the items to serialize
		var children = this.listing.getChildren("li");
		children.each( function ( aListing ){
            var listItemId = aListing.get("id");
            var listItemIdSplit = listItemId.split( "_" );
            listItemId = listItemIdSplit[ listItemIdSplit.length - 1 ];
            sortArray.push( listItemId );
		});

		try{
			return sortArray;
		}finally{
			sortArray = null;
		}
	},

	onItemDeleted: function( anItem ){
		this.items.erase( anItem );
		anItem.destroy();
		delete anItem;
		anItem = null;
		mop.util.EventManager.broadcastEvent( "resize" );
		//again we should be removing from this.items
		//this is a potential memory leak, since adding and removing many times will leave
		//baggage around since it's not removed from this.items, now we have a class with all vars and methods deleted
	},

	destroy: function(){

		//We only want to killSortable if the list is currently sortable
		//It might now be, if an IPE is open and the user hits the trash can
		if(this.sortableList){
			this.killSortable();
		}

		$clear( this.submitDelay );

		this.removeModal();

		delete this.modal;
		delete this.addItemDialogue;
		delete this.controls;
		delete this.instanceName;
		delete this.items;
		delete this.listing;
		delete this.oldSort;
		delete this.scroller;
		delete this.sortable;
		delete this.sortDirection;
		delete this.submitDelay;

		this.addItemDialogue = null;
		this.controls = null;
		this.instanceName = null;
		this.items = null;
		this.listing = null;
		this.oldSort = null;
		this.scroller = null;
		this.sortable = null;
		this.sortDirection = null;
		this.submitDelay = null;

		mop.util.EventManager.broadcastEvent( 'resize' );

		this.parent();

	}

});

mop.modules.ListItem = new Class({

	Extends: mop.modules.Module,

	Implements: [ Events, Options ],

	addItemDialogue: null,
	objectId: null,
	scrollContext: null,
	controls: null,
	fadeOut: null,

	//trash: false, // set to true when an item is destroyed

	initialize: function( anElement, aMarshal, addItemDialogue, options ){
		this.element = $( anElement);
		this.element.store( "Class", this );
		this.marshal = aMarshal;
		this.instanceName = this.element.get( "id" );
		this.addItemDialogue = addItemDialogue;
		this.objectId = this.element.get("id").split("_")[1];
		if( options && options.scrollContext ) this.scrollContext = options.scrollContext;
		this.build();
	},

	getObjectId: function(){ return this.objectId; },

	toString: function(){ return "[ object, mop.modules.ListItem ]"; },

	build: function(){
		this.parent();
		this.initControls();
	},

	initControls: function(){

		this.controls = this.element.getElement(".itemControls");
		if( this.controls.getElement(".delete") ) this.controls.getElement(".delete").addEvent( "click", this.deleteItem.bindWithEvent( this ) );

		// if( this.controls.getElement(".submit") )
		// 	this.controls.getElement(".submit").addEvent( "click", this.addItemDialogue.submit.bindWithEvent( this.addItemDialogue ) );
		//
		// if( this.controls.getElement(".cancel") )
		// 	this.controls.getElement(".cancel").addEvent( "click", this.addItemDialogue.cancel.bindWithEvent( this.addItemDialogue ) );

	},

	filesToTop: function(){
		this.uiElements.each( function( uiElementInstance, indexA ){
			if( uiElementInstance.type == "file" || uiElementInstance.type == "imageFile" ){
 				uiElementInstance.scrollContext = 'modal';
				uiElementInstance.reposition( 'modal' );
			}
		}, this );
	},

	resetFileDepth: function(){
		this.uiElements.each( function( anElement ){
			if( anElement.type == "file" || anElement.type == "imageFile" ){
				anElement.reposition( 'window' );
			}
		});
	},

	JSONSend: function( action, data, options ){
		var url = mop.getAppURL() + "ajax/" + this.getSubmissionController() +  "/" + action + "/" + this.getObjectId();
		mop.util.JSONSend( url, data, options );
	},

	getSubmissionController: function(){ return this.marshal.instanceName; },

	deleteItem: function( e ){
		if( e ){
			if( e.preventDefault ){
				e.preventDefault();
			}else{
				e.returnVal = false;
			}
			e.target.removeClass("delete");
			e.target.addClass("spinner");
		}
		this.JSONSend( "deleteItem" );
		if( this.marshal.sortable != null ) this.marshal.onOrderChanged();
		this.fadeOut = new Fx.Morph( this.element, { duration: 300, onComplete: this.marshal.onItemDeleted.bind( this.marshal, this ) } );
		this.fadeOut.start( { opacity: 0 } );
	},

	resumeSort: function(){
		if( this.marshal.sortable ) this.marshal.resumeSort();
	},

	suspendSort: function(){
		if( this.marshal.sortable ) this.marshal.suspendSort();
	},

	destroy: function(){

	 /*
		* this.trash is a hack to identify items that have already been deleted
		* but have not been removed from the this.marshal.items array
  	*/
		//This is now fixed by erasing the item in onItemDeleted
		/*
		if(this.trash == true){
			return;
		}
		*/

		//Destroy this.element if it still exists
		//This.element is the html element for the object
		//if(this.element != null){ this.element.destroy(); }
		//This is now fixed by erasing the item in onItemDeleted
		//also this apprears to be redundant now with mopUI.js

		this.element.destroy();

//		the item is not being removed from this.listing
//		which is causing some memory bloat and seems to be a problem in IE specifically

		console.log(this.element);
		this.parent();  //call the superclass's 'destroy()'

		this.addItemDialogue = null;
		this.controls = null;
		this.fadeOut = null;
		this.scrollContext = null;
		this.objectId = null;

		console.log(this.element);

		//this.trash = true;

	}

});
<commit_msg>modules : list : may fix a number of bugs : 236, 239, 243<commit_after>
mop.modules.ListModule = new Class({

	/* TODO write unit tests for List*/

	Extends: mop.modules.Module,

	// listing properties and members, helps with maintenance and destruction.... standard practice from now on
	sortable: null,
	sortDirection: null,
	instanceName: null,
	addItemDialogue: null,
	items: null,
	controls: null,
	sortableList: null,
	scroller: null,
	submitDelay: null,
	oldSort: null,

	initialize: function( anElement, aMarshal, options ){

		this.parent( anElement, aMarshal, options );

		delete this.items;
		this.items = null;
		this.items = [];

		this.sortable = ( this.getValueFromClassName( "sortable" ) != "false" ) ? this.getValueFromClassName( "sortable" ) : false;
		this.sortDirection = this.getValueFromClassName( "sortDirection" );

		if( this.sortable ) this.makeSortable();
	},

	toString: function(){
		return "[ object, mop.modules.ListModule ]";
	},

	getInstanceName: function(){
		return this.instanceName;
	},

	build: function(){
		this.parent();
		this.initControls();
		this.addItemDialogue = null;
//		console.log( "build", this.toString() );
		this.initList();
	},

	initList: function(){
		delete this.items;
		this.items = null;
		this.items = [];
		this.listing = this.element.getElement( ".listing" );
		var children = this.listing.getChildren("li");
		children.each( function( element ){
			this.items.push( new mop.modules.ListItem( element, this, this.addItemDialogue ) );
		}, this );
	},

	toggleSortable: function(){
		if( this.sortable ){ this.killSortable(); }else{ this.makeSortable(); }
	},

	initControls: function(){
		// console.log( this.element.getElement( "#" + this.instanceName+"AddItemModal" ).retrieve("Class") );
		this.controls = this.element.getChildren( ".controls" );
		var addItemButton = this.controls.getElement( ".addItem" ).addEvent("click", this.addItem.bindWithEvent( this ) );//this.showModal.bindWithEvent( this, $( this.instanceName+"AddItemModal" ) ) );
		if( this.sortable ){
			var saveSort = this.controls.getElement( ".saveSort" ).addEvent("click", this.saveSort.bindWithEvent( this ) );
			saveSort = null;
		}
		addItemButton = null;
	},

	makeSortable: function(){
		if( this.sortable && !this.sortableList ){
				this.sortableList = new mop.ui.Sortable(  this.listing, this, {
				scrollElement: window,
				clone:  true,
				snap: 12,
				revert: true,
				velocity: .97,
				area: 24,
				constrain: true,
				onComplete: function( el ){
					if(!this.moved) return;
					this.moved = false;
					this.scroller.stop();
					this.marshal.onOrderChanged();
				},
				onStart: function(){
					this.moved = true;
					this.scroller.start();
				}
			});
		}else if( this.sortable ){
			this.sortableList.attach();
		}
		this.oldSort = this.serialize();
	},

	resumeSort: function(){
		if( this.sortable && this.sortableList ) this.sortableList.attach();
	},

	suspendSort: function(){
		if( this.sortable && this.sortableList ) this.sortableList.detach();
	},

	killSortable: function(){
		this.sortableList.detach();
		delete this.sortableList;
		this.sortableList = null;
	},

	onOrderChanged: function(){
		var newOrder = this.serialize();
		$clear( this.submitDelay );
		this.submitDelay = this.submitSortOrder.periodical( 3000, this, newOrder.join(",") );
		newOrder = null;
	},

	submitSortOrder: function( newOrder ){
		if( this.sortable && this.oldSort != newOrder ){
			$clear( this.submitDelay );
			this.submitDelay = null;
			this.JSONSend( "saveSortOrder", { sortorder: newOrder } );
			this.oldSort = newOrder;
		}
	},

	addItem: function( e ){
		if( e && e.preventDefault ){
			e.preventDefault();
		}else{
			e.returnValue = false;
		}

		if( this.addItemDialogue ) this.removeModal( this.addItemDialogue );
		this.addItemDialogue = new mop.ui.EnhancedAddItemDialogue( null, this );
		this.addItemDialogue.showLoading( e.target.get("text") );

		this.JSONSend( "addItem", null, {
			onComplete: function( json ){
				this.onItemAdded( json );
			}.bind( this )
		});
	},

	onItemAdded: function( json  ){
		var element = this.addItemDialogue.setContent( json.response, this.controls.getElement( ".addItem" ).get( "text" ) );
		var listItem = new mop.modules.ListItem( element, this, this.addItemDialogue, { scrollContext: 'modal' } );
		listItem.uiElements.each( function( uiInstance ){
			uiInstance.scrollContext = "modal";
		});
		listItem.filesToTop();
		this.items.push( listItem );
		this.addItemDialogue.show();
		listItem = null;
	},

	removeModal: function( aModal ){
		if( !this.addItemDialogue ) return;
		this.addItemDialogue = null;
	},

	insertItem: function( anElement ){
		var where = ( this.sortDirection == "DESC" )? "top" : "bottom";
		this.listing.grab( anElement, where );
		if( this.sortable && this.sortableList ) this.sortableList.addItems( anElement );

		// reset scrollContexts
		var listItemInstance = anElement.retrieve("Class");
		listItemInstance.scrollContext = 'window';
		listItemInstance.resetFileDepth();
		listItemInstance.uiElements.each( function( uiInstance ){
			uiInstance.scrollContext = "window";
		});
		anElement.tween( "opacity", 1 );
	 	anElement.getElement(".itemControls" ).getElement(".delete").removeClass("hidden");

		if( this.sortable != null ) this.onOrderChanged();
		listItemInstance = where = null;
	},

	serialize:function(){
		console.log( this.toString(), "serialize", this.listing, this.listing.getChildren() )
		var sortArray = [];

		//get all the items to serialize
		var children = this.listing.getChildren("li");
		children.each( function ( aListing ){
            var listItemId = aListing.get("id");
            var listItemIdSplit = listItemId.split( "_" );
            listItemId = listItemIdSplit[ listItemIdSplit.length - 1 ];
            sortArray.push( listItemId );
		});

		try{
			return sortArray;
		}finally{
			sortArray = null;
		}
	},

	onItemDeleted: function( anItem ){
		this.items.erase( anItem );
		anItem.destroy();
		delete anItem;
		anItem = null;
		mop.util.EventManager.broadcastEvent( "resize" );
		//again we should be removing from this.items
		//this is a potential memory leak, since adding and removing many times will leave
		//baggage around since it's not removed from this.items, now we have a class with all vars and methods deleted
	},

	destroy: function(){

		//We only want to killSortable if the list is currently sortable
		//It might now be, if an IPE is open and the user hits the trash can
		if(this.sortableList){
			this.killSortable();
		}

		$clear( this.submitDelay );

		this.removeModal();

		delete this.modal;
		delete this.addItemDialogue;
		delete this.controls;
		delete this.instanceName;
		delete this.items;
		delete this.listing;
		delete this.oldSort;
		delete this.scroller;
		delete this.sortable;
		delete this.sortDirection;
		delete this.submitDelay;

		this.addItemDialogue = null;
		this.controls = null;
		this.instanceName = null;
		this.items = null;
		this.listing = null;
		this.oldSort = null;
		this.scroller = null;
		this.sortable = null;
		this.sortDirection = null;
		this.submitDelay = null;

		mop.util.EventManager.broadcastEvent( 'resize' );

		this.parent();

	}

});

mop.modules.ListItem = new Class({

	Extends: mop.modules.Module,

	Implements: [ Events, Options ],

	addItemDialogue: null,
	objectId: null,
	scrollContext: null,
	controls: null,
	fadeOut: null,

	//trash: false, // set to true when an item is destroyed

	initialize: function( anElement, aMarshal, addItemDialogue, options ){
		this.element = $( anElement);
		this.element.store( "Class", this );
		this.marshal = aMarshal;
		this.instanceName = this.element.get( "id" );
		this.addItemDialogue = addItemDialogue;
		this.objectId = this.element.get("id").split("_")[1];
		if( options && options.scrollContext ) this.scrollContext = options.scrollContext;
		this.build();
	},

	getObjectId: function(){ return this.objectId; },

	toString: function(){ return "[ object, mop.modules.ListItem ]"; },

	build: function(){
		this.parent();
		this.initControls();
	},

	initControls: function(){

		this.controls = this.element.getElement(".itemControls");
		if( this.controls.getElement(".delete") ) this.controls.getElement(".delete").addEvent( "click", this.deleteItem.bindWithEvent( this ) );

		// if( this.controls.getElement(".submit") )
		// 	this.controls.getElement(".submit").addEvent( "click", this.addItemDialogue.submit.bindWithEvent( this.addItemDialogue ) );
		//
		// if( this.controls.getElement(".cancel") )
		// 	this.controls.getElement(".cancel").addEvent( "click", this.addItemDialogue.cancel.bindWithEvent( this.addItemDialogue ) );

	},

	filesToTop: function(){
		this.uiElements.each( function( uiElementInstance, indexA ){
			if( uiElementInstance.type == "file" || uiElementInstance.type == "imageFile" ){
 				uiElementInstance.scrollContext = 'modal';
				uiElementInstance.reposition( 'modal' );
			}
		}, this );
	},

	resetFileDepth: function(){
		this.uiElements.each( function( anElement ){
			if( anElement.type == "file" || anElement.type == "imageFile" ){
				anElement.reposition( 'window' );
			}
		});
	},

	JSONSend: function( action, data, options ){
		var url = mop.util.getAppURL() + "ajax/" + this.getSubmissionController() +  "/" + action + "/" + this.getObjectId();
		mop.util.JSONSend( url, data, options );
	},

	getSubmissionController: function(){ return this.marshal.instanceName; },

	deleteItem: function( e ){
		if( e ){
			if( e.preventDefault ){
				e.preventDefault();
			}else{
				e.returnVal = false;
			}
			e.target.removeClass("delete");
			e.target.addClass("spinner");
		}
		this.JSONSend( "deleteItem" );
		if( this.marshal.sortable != null ) this.marshal.onOrderChanged();
		this.fadeOut = new Fx.Morph( this.element, { duration: 300, onComplete: this.marshal.onItemDeleted.bind( this.marshal, this ) } );
		this.fadeOut.start( { opacity: 0 } );
	},

	resumeSort: function(){
		if( this.marshal.sortable ) this.marshal.resumeSort();
	},

	suspendSort: function(){
		if( this.marshal.sortable ) this.marshal.suspendSort();
	},

	destroy: function(){

	 /*
		* this.trash is a hack to identify items that have already been deleted
		* but have not been removed from the this.marshal.items array
  	*/
		//This is now fixed by erasing the item in onItemDeleted
		/*
		if(this.trash == true){
			return;
		}
		*/

		//Destroy this.element if it still exists
		//This.element is the html element for the object
		//if(this.element != null){ this.element.destroy(); }
		//This is now fixed by erasing the item in onItemDeleted
		//also this apprears to be redundant now with mopUI.js

		this.element.destroy();

//		the item is not being removed from this.listing
//		which is causing some memory bloat and seems to be a problem in IE specifically

		console.log(this.element);
		this.parent();  //call the superclass's 'destroy()'

		this.addItemDialogue = null;
		this.controls = null;
		this.fadeOut = null;
		this.scrollContext = null;
		this.objectId = null;

		console.log(this.element);

		//this.trash = true;

	}

});
<|endoftext|>


<commit_before>/*!
    Copyright (C) 2016 Google Inc.
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
*/
(function (can, $) {
  can.Model.Cacheable('can.Model.Join', {
    join_keys: null,
    setup: function () {
      this._super.apply(this, arguments);
    },
    init: function () {
      if (this._super) {
        this._super.apply(this, arguments);
      }
      function reinit(ev, instance) {
        var refreshQueue;
        if (instance instanceof can.Model.Join) {
          instance.reinit();
          refreshQueue = new RefreshQueue();
          can.each(instance.constructor.join_keys, function (cls, key) {
            var obj;
            if (instance[key]) {
              if (instance[key].reify && instance[key].reify().refresh) {
                obj = instance[key].reify();
              } else {
                obj = cls.findInCacheById(instance[key].id);
              }
            }
            if (obj) {
              refreshQueue.enqueue(obj);
            }
          });
          refreshQueue.trigger();
        }
      }
      if (this === can.Model.Join) {
        this.bind('created', reinit);
        this.bind('destroyed', reinit);
      }
    }
  }, {
    init: function () {
      this._super.apply(this, arguments);
      can.each(this.constructor.join_keys, function (cls, key) {
        this.bind(key + '.stub_destroyed', function () {
          // Trigger `destroyed` on self, since it was destroyed on the server
          this.destroyed();
        }.bind(this));
      }.bind(this));
    },

    reinit: function () {
      this.init_join_objects();
    },

    init_join_object_with_type: function (attr) {
      var objectId;
      var objectType;
      if (this[attr] instanceof can.Model) {
        return;
      }

      objectId = this[attr + '_id'] || (this[attr] || {}).id;
      objectType = this[attr + '_type'] || (this[attr] || {}).type;

      if (objectId && objectType && typeof objectType === 'string') {
        this.attr(attr, CMS.Models.get_instance(
              objectType
            , objectId
            , this[attr]
            ) || this[attr]);
      } else if (objectId) {
        this.attr(attr, CMS.Models.get_instance(this[attr]));
      }
    },

    init_join_object: function (attr, modelName) {
      var objectId = this[attr + '_id'] || (this[attr] || {}).id;

      if (objectId) {
        this.attr(
            attr,
            CMS.Models.get_instance(
              modelName, objectId, this[attr]
            ).stub() || this[attr]
        );
      }
    },

    init_join_objects: function () {
      var that = this
        ;

      can.each(this.constructor.join_keys, function (model, attr) {
        if (model === can.Model.Cacheable) {
          that.init_join_object_with_type(attr);
        } else {
          that.init_join_object(attr, model.shortName);
        }
      });
    }
  });

  can.Model.Join('CMS.Models.Relationship', {
    root_object: 'relationship',
    root_collection: 'relationships',
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      source: 'CMS.Models.get_stub',
      destination: 'CMS.Models.get_stub'
    },
    join_keys: {
      source: can.Model.Cacheable,
      destination: can.Model.Cacheable
    },
    defaults: {
      source: null,
      destination: null
    },
    findAll: 'GET /api/relationships',
    create: 'POST /api/relationships',
    update: 'PUT /api/relationships/{id}',
    destroy: 'DELETE /api/relationships/{id}',
    createAssignee: function (options) {
      return new this({
        attrs: {
          AssigneeType: options.role
        },
        source: {
          href: options.source.href,
          type: options.source.type,
          id: options.source.id
        },
        context: options.context,
        destination: {
          href: options.destination.href,
          type: options.destination.type,
          id: options.destination.id
        }
      });
    },
    get_relationship: function (source, destination) {
      return _.first(_.filter(CMS.Models.Relationship.cache, function (model) {
        if (!model.source || !model.destination) {
          return false;
        }
        return model.source.type === source.type &&
                model.source.id === source.id &&
                model.destination.type === destination.type &&
                model.destination.id === destination.id ||
                model.source.type === destination.type &&
                model.source.id === destination.id &&
                model.destination.type === source.type &&
                model.destination.id === source.id;
      }));
    }
  }, {
    reinit: function () {
      this.attr('source', CMS.Models.get_instance(
        this.source_type ||
          (this.source &&
            (this.source.constructor &&
              this.source.constructor.shortName ||
              (!this.source.selfLink && this.source.type))),
          this.source_id || (this.source && this.source.id),
          this.source) || this.source);
      this.attr('destination', CMS.Models.get_instance(
        this.destination_type ||
          (this.destination &&
            (this.destination.constructor &&
              this.destination.constructor.shortName ||
              (!this.source.selfLink && this.destination.type))),
        this.destination_id || (this.destination && this.destination.id),
        this.destination) || this.destination);
    }
  });

  can.Model.Join('CMS.Models.UserRole', {
    root_object: 'user_role',
    root_collection: 'user_roles',
    findAll: 'GET /api/user_roles',
    update: 'PUT /api/user_roles/{id}',
    create: 'POST /api/user_roles',
    destroy: 'DELETE /api/user_roles/{id}',
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      person: 'CMS.Models.Person.stub',
      role: 'CMS.Models.Role.stub'
    },
    join_keys: {
      person: CMS.Models.Person,
      role: CMS.Models.Role
    }
  }, {
    save: function () {
      var role;
      if (!this.role && this.role_name) {
        role = _.find(CMS.Models.Role.cache, {name: this.role_name});
        if (role) {
          this.attr('role', role.stub());
          return this._super.apply(this, arguments);
        }
        return CMS.Models.Role.findAll({
          name__in: this.role_name
        }).then(function (roles) {
          if (roles.length < 1) {
            return new $.Deferred().reject('Role not found');
          }
          this.attr('role', roles[0].stub());
          return this._super.apply(this, arguments);
        }.bind(this));
      }
      return this._super.apply(this, arguments);
    }
  });

  can.Model.Join('CMS.Models.ObjectPerson', {
    root_object: 'object_person',
    root_collection: 'object_people',
    findAll: 'GET /api/object_people',
    create: 'POST /api/object_people',
    update: 'PUT /api/object_people/{id}',
    destroy: 'DELETE /api/object_people/{id}',
    join_keys: {
      personable: can.Model.Cacheable,
      person: CMS.Models.Person
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      person: 'CMS.Models.Person.stub',
      personable: 'CMS.Models.get_stub'
    }

  }, {});

  can.Model.Join('CMS.Models.ObjectOwner', {
    root_object: 'object_owner',
    root_collection: 'object_owners',
    findOne: 'GET /api/object_owners/{id}',
    findAll: 'GET /api/object_owners',
    create: 'POST /api/object_owners',
    update: 'PUT /api/object_owners/{id}',
    destroy: 'DELETE /api/object_owners/{id}',
    join_keys: {
      ownable: can.Model.Cacheable,
      person: CMS.Models.Person
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      person: 'CMS.Models.Person.stub',
      ownable: 'CMS.Models.get_stub'
    }
  }, {});

  can.Model.Join('CMS.Models.ObjectDocument', {
    root_object: 'object_document',
    root_collection: 'object_documents',
    findAll: 'GET /api/object_documents',
    create: 'POST /api/object_documents',
    destroy: 'DELETE /api/object_documents/{id}',
    join_keys: {
      documentable: can.Model.Cacheable,
      document: CMS.Models.Document
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      document: 'CMS.Models.Document.stub',
      documentable: 'CMS.Models.get_stub'
    }
  }, {});

  can.Model.Join('CMS.Models.MultitypeSearchJoin', {
    join_keys: {}
  }, {});

  can.Model.Join('CMS.Models.AuditObject', {
    root_object: 'audit_object',
    root_collection: 'audit_objects',
    findAll: 'GET /api/audit_objects',
    create: 'POST /api/audit_objects',
    destroy: 'DELETE /api/audit_objects/{id}',
    join_keys: {
      auditable: can.Model.Cacheable,
      audit: CMS.Models.Audit
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      audit: 'CMS.Models.Audit.stub',
      auditable: 'CMS.Models.get_stub'
    }
  }, {});
})(this.can, this.can.$);
<commit_msg>Fix error when super call within save function<commit_after>/*!
    Copyright (C) 2016 Google Inc.
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
*/
(function (can, $) {
  can.Model.Cacheable('can.Model.Join', {
    join_keys: null,
    setup: function () {
      this._super.apply(this, arguments);
    },
    init: function () {
      if (this._super) {
        this._super.apply(this, arguments);
      }
      function reinit(ev, instance) {
        var refreshQueue;
        if (instance instanceof can.Model.Join) {
          instance.reinit();
          refreshQueue = new RefreshQueue();
          can.each(instance.constructor.join_keys, function (cls, key) {
            var obj;
            if (instance[key]) {
              if (instance[key].reify && instance[key].reify().refresh) {
                obj = instance[key].reify();
              } else {
                obj = cls.findInCacheById(instance[key].id);
              }
            }
            if (obj) {
              refreshQueue.enqueue(obj);
            }
          });
          refreshQueue.trigger();
        }
      }
      if (this === can.Model.Join) {
        this.bind('created', reinit);
        this.bind('destroyed', reinit);
      }
    }
  }, {
    init: function () {
      this._super.apply(this, arguments);
      can.each(this.constructor.join_keys, function (cls, key) {
        this.bind(key + '.stub_destroyed', function () {
          // Trigger `destroyed` on self, since it was destroyed on the server
          this.destroyed();
        }.bind(this));
      }.bind(this));
    },

    reinit: function () {
      this.init_join_objects();
    },

    init_join_object_with_type: function (attr) {
      var objectId;
      var objectType;
      if (this[attr] instanceof can.Model) {
        return;
      }

      objectId = this[attr + '_id'] || (this[attr] || {}).id;
      objectType = this[attr + '_type'] || (this[attr] || {}).type;

      if (objectId && objectType && typeof objectType === 'string') {
        this.attr(attr, CMS.Models.get_instance(
              objectType
            , objectId
            , this[attr]
            ) || this[attr]);
      } else if (objectId) {
        this.attr(attr, CMS.Models.get_instance(this[attr]));
      }
    },

    init_join_object: function (attr, modelName) {
      var objectId = this[attr + '_id'] || (this[attr] || {}).id;

      if (objectId) {
        this.attr(
            attr,
            CMS.Models.get_instance(
              modelName, objectId, this[attr]
            ).stub() || this[attr]
        );
      }
    },

    init_join_objects: function () {
      var that = this
        ;

      can.each(this.constructor.join_keys, function (model, attr) {
        if (model === can.Model.Cacheable) {
          that.init_join_object_with_type(attr);
        } else {
          that.init_join_object(attr, model.shortName);
        }
      });
    }
  });

  can.Model.Join('CMS.Models.Relationship', {
    root_object: 'relationship',
    root_collection: 'relationships',
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      source: 'CMS.Models.get_stub',
      destination: 'CMS.Models.get_stub'
    },
    join_keys: {
      source: can.Model.Cacheable,
      destination: can.Model.Cacheable
    },
    defaults: {
      source: null,
      destination: null
    },
    findAll: 'GET /api/relationships',
    create: 'POST /api/relationships',
    update: 'PUT /api/relationships/{id}',
    destroy: 'DELETE /api/relationships/{id}',
    createAssignee: function (options) {
      return new this({
        attrs: {
          AssigneeType: options.role
        },
        source: {
          href: options.source.href,
          type: options.source.type,
          id: options.source.id
        },
        context: options.context,
        destination: {
          href: options.destination.href,
          type: options.destination.type,
          id: options.destination.id
        }
      });
    },
    get_relationship: function (source, destination) {
      return _.first(_.filter(CMS.Models.Relationship.cache, function (model) {
        if (!model.source || !model.destination) {
          return false;
        }
        return model.source.type === source.type &&
                model.source.id === source.id &&
                model.destination.type === destination.type &&
                model.destination.id === destination.id ||
                model.source.type === destination.type &&
                model.source.id === destination.id &&
                model.destination.type === source.type &&
                model.destination.id === source.id;
      }));
    }
  }, {
    reinit: function () {
      this.attr('source', CMS.Models.get_instance(
        this.source_type ||
          (this.source &&
            (this.source.constructor &&
              this.source.constructor.shortName ||
              (!this.source.selfLink && this.source.type))),
          this.source_id || (this.source && this.source.id),
          this.source) || this.source);
      this.attr('destination', CMS.Models.get_instance(
        this.destination_type ||
          (this.destination &&
            (this.destination.constructor &&
              this.destination.constructor.shortName ||
              (!this.source.selfLink && this.destination.type))),
        this.destination_id || (this.destination && this.destination.id),
        this.destination) || this.destination);
    }
  });

  can.Model.Join('CMS.Models.UserRole', {
    root_object: 'user_role',
    root_collection: 'user_roles',
    findAll: 'GET /api/user_roles',
    update: 'PUT /api/user_roles/{id}',
    create: 'POST /api/user_roles',
    destroy: 'DELETE /api/user_roles/{id}',
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      person: 'CMS.Models.Person.stub',
      role: 'CMS.Models.Role.stub'
    },
    join_keys: {
      person: CMS.Models.Person,
      role: CMS.Models.Role
    }
  }, {
    save: function () {
      var role;
      var _super = this._super;

      if (this.role && !this.role_name) {
        return _super.apply(this, arguments);
      }

      role = _.find(CMS.Models.Role.cache, {name: this.role_name});
      if (role) {
        this.attr('role', role.stub());
        return _super.apply(this, arguments);
      }
      return CMS.Models.Role.findAll({
        name__in: this.role_name
      }).then(function (role) {
        if (!role.length) {
          return new $.Deferred().reject('Role not found');
        }
        role = role[0];
        this.attr('role', role.stub());
        return _super.apply(this, arguments);
      }.bind(this));
    }
  });

  can.Model.Join('CMS.Models.ObjectPerson', {
    root_object: 'object_person',
    root_collection: 'object_people',
    findAll: 'GET /api/object_people',
    create: 'POST /api/object_people',
    update: 'PUT /api/object_people/{id}',
    destroy: 'DELETE /api/object_people/{id}',
    join_keys: {
      personable: can.Model.Cacheable,
      person: CMS.Models.Person
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      person: 'CMS.Models.Person.stub',
      personable: 'CMS.Models.get_stub'
    }

  }, {});

  can.Model.Join('CMS.Models.ObjectOwner', {
    root_object: 'object_owner',
    root_collection: 'object_owners',
    findOne: 'GET /api/object_owners/{id}',
    findAll: 'GET /api/object_owners',
    create: 'POST /api/object_owners',
    update: 'PUT /api/object_owners/{id}',
    destroy: 'DELETE /api/object_owners/{id}',
    join_keys: {
      ownable: can.Model.Cacheable,
      person: CMS.Models.Person
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      person: 'CMS.Models.Person.stub',
      ownable: 'CMS.Models.get_stub'
    }
  }, {});

  can.Model.Join('CMS.Models.ObjectDocument', {
    root_object: 'object_document',
    root_collection: 'object_documents',
    findAll: 'GET /api/object_documents',
    create: 'POST /api/object_documents',
    destroy: 'DELETE /api/object_documents/{id}',
    join_keys: {
      documentable: can.Model.Cacheable,
      document: CMS.Models.Document
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      document: 'CMS.Models.Document.stub',
      documentable: 'CMS.Models.get_stub'
    }
  }, {});

  can.Model.Join('CMS.Models.MultitypeSearchJoin', {
    join_keys: {}
  }, {});

  can.Model.Join('CMS.Models.AuditObject', {
    root_object: 'audit_object',
    root_collection: 'audit_objects',
    findAll: 'GET /api/audit_objects',
    create: 'POST /api/audit_objects',
    destroy: 'DELETE /api/audit_objects/{id}',
    join_keys: {
      auditable: can.Model.Cacheable,
      audit: CMS.Models.Audit
    },
    attributes: {
      context: 'CMS.Models.Context.stub',
      modified_by: 'CMS.Models.Person.stub',
      audit: 'CMS.Models.Audit.stub',
      auditable: 'CMS.Models.get_stub'
    }
  }, {});
})(this.can, this.can.$);
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  'use strict';

  grunt.loadNpmTasks('grunt-contrib');

  // project configuration
  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      src: 'src/**/*.js',
      dest: 'public/js/',
      specs: 'spec/**/*Spec.js',
      banner: '/* <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("m/d/yyyy") %>\n' +
        '* <%= pkg.homepage %>\n' +
        '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' +
        '* Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
    },
    test: {
      files: ['test/**/*.js']
    },
    watch: {
      files: ['Gruntfile.js', '<config:lint.files>'],
      //tasks: ['lint','test','concat', 'min'],
      test: {
        files: ['<%= meta.src %>', '<%= meta.specs %>'],
        tasks: 'test'
      }
    },
    concat: {
      dist: {
        src: [
          '<banner>',
          '<%= meta.dest %>/vendor/OpenLayers.js',
          '<%= meta.src %>'
          //'src/plugins.js',
          //'src/geoportal.js'
        ],
        dest: 'public/js/<%= pkg.name %>.js'
      }
    },
    min: {
      dist: {
        src: ['<banner>', '<%= meta.dest %><%= pkg.name %>.js'],
        dest: '<%= meta.dest %><%= pkg.name %>.min.js'
      }
    },
    uglify: {
      mangle: {toplevel: false},
      squeeze: {dead_code: false},
      codegen: {quote_keys: true},
      options: {
        sourceMap: 'public/js/source-map.js'
      }
    },
    lint: {
      files: ['<%= meta.src %>', '<%= meta.specs %>']
    },
    jshint: {
      all: [
        'Gruntfile.js',
        '<%= meta.src %>',
        '<%= meta.specs %>'
      ],
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        eqnull: true,
        browser: true
      },
      globals: {
        jQuery: true,
        jasmine : false,
        describe : false,
        beforeEach : false,
        expect : false,
        it : false,
        spyOn : false
      }
    }
    //jasmine: {
      //src: 'src/**/*.js',
      //options: {
        //specs: '<%= meta.specs %>'
      //}
    //}
    //'jasmine-server': {
      //browser: false
    //}
  });

  //grunt.loadNpmTasks('grunt-jasmine-runner');
  //grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // override qunit tests
  //grunt.registerTask('test', ['jshint', 'jasmine']);

  grunt.registerTask('default', 'lint concat min');
  //grunt.registerTask('default', 'jasmine concat min');
};
<commit_msg>code cleanup<commit_after>module.exports = function(grunt) {
  'use strict';

  grunt.loadNpmTasks('grunt-contrib');

  // project configuration
  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      src: 'src/**/*.js',
      dest: 'public/js/',
      specs: 'spec/**/*Spec.js',
      banner: '/* <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("m/d/yyyy") %>\n' +
        '* <%= pkg.homepage %>\n' +
        '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' +
        '* Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
    },
    test: {
      files: ['test/**/*.js']
    },
    watch: {
      files: ['Gruntfile.js', '<config:lint.files>'],
      test: {
        files: ['<%= meta.src %>', '<%= meta.specs %>'],
        tasks: 'test'
      }
    },
    concat: {
      dist: {
        src: [
          '<banner>',
          '<%= meta.dest %>/vendor/OpenLayers.js',
          '<%= meta.src %>'
        ],
        dest: 'public/js/<%= pkg.name %>.js'
      }
    },
    min: {
      dist: {
        src: ['<banner>', '<%= meta.dest %><%= pkg.name %>.js'],
        dest: '<%= meta.dest %><%= pkg.name %>.min.js'
      }
    },
    uglify: {
      mangle: {toplevel: false},
      squeeze: {dead_code: false},
      codegen: {quote_keys: true},
      options: {
        sourceMap: 'public/js/source-map.js'
      }
    },
    lint: {
      files: ['<%= meta.src %>', '<%= meta.specs %>']
    },
    jshint: {
      all: [
        'Gruntfile.js',
        '<%= meta.src %>',
        '<%= meta.specs %>'
      ],
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        eqnull: true,
        browser: true
      },
      globals: {
        jQuery: true,
        jasmine : false,
        describe : false,
        beforeEach : false,
        expect : false,
        it : false,
        spyOn : false
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', 'lint concat min');
};
<|endoftext|>


<commit_before>/*
 * HTML5 Sortable jQuery Plugin
 * https://github.com/voidberg/html5sortable
 *
 * Original code copyright 2012 Ali Farhadi.
 * This version is mantained by Alexandru Badiu <andu@ctrlz.ro> & Lukas Oppermann <lukas@vea.re>
 *
 *
 * Released under the MIT license.
 */
'use strict';
/*
 * variables global to the plugin
 */
var dragging;
var draggingHeight;
var placeholders = $();
var sortables = [];
/*
 * remove event handlers from items
 * @param [jquery Collection] items
 * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event)
 */
var _removeItemEvents = function(items) {
  items.off('dragstart.h5s');
  items.off('dragend.h5s');
  items.off('selectstart.h5s');
  items.off('dragover.h5s');
  items.off('dragenter.h5s');
  items.off('drop.h5s');
};
/*
 * remove event handlers from sortable
 * @param [jquery Collection] sortable
 * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event)
 */
var _removeSortableEvents = function(sortable) {
  sortable.off('dragover.h5s');
  sortable.off('dragenter.h5s');
  sortable.off('drop.h5s');
};
/*
 * attache ghost to dataTransfer object
 * @param [event] original event
 * @param [object] ghost-object with item, x and y coordinates
 */
var _attachGhost = function(event, ghost) {
  // this needs to be set for HTML5 drag & drop to work
  event.dataTransfer.effectAllowed = 'move';
  event.dataTransfer.setData('text', '');

  // check if setDragImage method is available
  if (event.dataTransfer.setDragImage) {
    event.dataTransfer.setDragImage(ghost.item, ghost.x, ghost.y);
  }
};
/**
 * _addGhostPos clones the dragged item and adds it as a Ghost item
 * @param [object] event - the event fired when dragstart is triggered
 * @param [object] ghost - .item = node, draggedItem = jQuery collection
 */
var _addGhostPos = function(e, ghost) {
  if (!ghost.x) {
    ghost.x = parseInt(e.pageX - ghost.draggedItem.offset().left);
  }
  if (!ghost.y) {
    ghost.y = parseInt(e.pageY - ghost.draggedItem.offset().top);
  }
  return ghost;
};
/**
 * _makeGhost decides which way to make a ghost and passes it to attachGhost
 * @param [jQuery selection] $draggedItem - the item that the user drags
 */
var _makeGhost = function($draggedItem) {
  return {
    item: $draggedItem[0],
    draggedItem: $draggedItem
  };
};
/**
 * _getGhost constructs ghost and attaches it to dataTransfer
 * @param [event] event - the original drag event object
 * @param [jQuery selection] $draggedItem - the item that the user drags
 * @param [object] ghostOpt - the ghost options
 */
// TODO: could $draggedItem be replaced by event.target in all instances
var _getGhost = function(event, $draggedItem) {
  // add ghost item & draggedItem to ghost object
  var ghost = _makeGhost($draggedItem);
  // attach ghost position
  ghost = _addGhostPos(event, ghost);
  // attach ghost to dataTransfer
  _attachGhost(event, ghost);
};
/*
 * remove data from sortable
 * @param [jquery Collection] a single sortable
 */
var _removeSortableData = function(sortable) {
  sortable.removeData('opts');
  sortable.removeData('connectWith');
  sortable.removeData('items');
  sortable.removeAttr('aria-dropeffect');
};
/*
 * remove data from items
 * @param [jquery Collection] items
 */
var _removeItemData = function(items) {
  items.removeAttr('aria-grabbed');
  items.removeAttr('draggable');
  items.removeAttr('role');
};
/*
 * check if two lists are connected
 * @param [jquery Collection] items
 */
var _listsConnected = function(curList, destList) {
  if (curList[0] === destList[0]) {
    return true;
  }
  if (curList.data('connectWith') !== undefined) {
    return curList.data('connectWith') === destList.data('connectWith');
  }
  return false;
};
/*
 * destroy the sortable
 * @param [jquery Collection] a single sortable
 */
var _destroySortable = function(sortable) {
  var opts = sortable.data('opts') || {};
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  // remove event handlers & data from sortable
  _removeSortableEvents(sortable);
  _removeSortableData(sortable);
  // remove event handlers & data from items
  handles.off('mousedown.h5s');
  _removeItemEvents(items);
  _removeItemData(items);
};
/*
 * enable the sortable
 * @param [jquery Collection] a single sortable
 */
var _enableSortable = function(sortable) {
  var opts = sortable.data('opts');
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  sortable.attr('aria-dropeffect', 'move');
  handles.attr('draggable', 'true');
  // IE FIX for ghost
  // can be disabled as it has the side effect that other events
  // (e.g. click) will be ignored
  var spanEl = (document || window.document).createElement('span');
  if (typeof spanEl.dragDrop === 'function' && !opts.disableIEFix) {
    handles.on('mousedown.h5s', function() {
      if (items.index(this) !== -1) {
        this.dragDrop();
      } else {
        $(this).parents(opts.items)[0].dragDrop();
      }
    });
  }
};
/*
 * disable the sortable
 * @param [jquery Collection] a single sortable
 */
var _disableSortable = function(sortable) {
  var opts = sortable.data('opts');
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  sortable.attr('aria-dropeffect', 'none');
  handles.attr('draggable', false);
  handles.off('mousedown.h5s');
};
/*
 * reload the sortable
 * @param [jquery Collection] a single sortable
 * @description events need to be removed to not be double bound
 */
var _reloadSortable = function(sortable) {
  var opts = sortable.data('opts');
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  // remove event handlers from items
  _removeItemEvents(items);
  handles.off('mousedown.h5s');
  // remove event handlers from sortable
  _removeSortableEvents(sortable);
};
/**
 * Get position of the element relatively to its sibling elements
 * @param {Element} element
 * @returns {number}
 */
var _index = function(element) {
  if (!element.parentElement) {
    return 0;
  }
  return [].indexOf.call(element.parentElement.children, element);
};
/**
 * Taken from jQuery source: https://github.com/jquery/jquery/blob/305f193aa57014dc7d8fa0739a3fefd47166cd44/src/css/hiddenVisibleSelectors.js#L11
 * @param {Element} element
 * @returns {boolean}
 */
var _visible = function(element) {
  return !!(
    element.offsetWidth ||
    element.offsetHeight ||
    element.getClientRects().length
  );
};
/**
 *
 * @param {Element|string} html
 * @returns {Element}
 * @private
 */
var _html2element = function(html) {
  if (typeof html !== 'string') {
    return html;
  }
  var div = document.createElement('div');
  div.innerHTML	= html;
  return div.firstChild;
};
/*
 * public sortable object
 * @param [object|string] options|method
 */
var sortable = function(selector, options) {

  var $sortables = $(selector);
  var method = String(options);

  options = $.extend({
    connectWith: false,
    placeholder: null,
    // dragImage can be null or a jQuery element
    dragImage: null,
    disableIEFix: false,
    placeholderClass: 'sortable-placeholder',
    draggingClass: 'sortable-dragging',
    hoverClass: false
  }, options);

  /* TODO: maxstatements should be 25, fix and remove line below */
  /*jshint maxstatements:false */
  return $sortables.each(function() {

    var $sortable = $(this);

    if (/enable|disable|destroy/.test(method)) {
      sortable[method]($sortable);
      return;
    }

    // get options & set options on sortable
    options = $sortable.data('opts') || options;
    $sortable.data('opts', options);
    // reset sortable
    _reloadSortable($sortable);
    // initialize
    var items = $sortable.children(options.items);
    var index;
    var startParent;
    var placeholder = options.placeholder;
    if (!placeholder) {
      placeholder = document.createElement(
        /^ul|ol$/i.test(this.tagName) ? 'li' : 'div'
      );
    }
    placeholder = _html2element(placeholder);
    placeholder.classList.add(options.placeholderClass);

    // setup sortable ids
    if (!$sortable.attr('data-sortable-id')) {
      var id = sortables.length;
      sortables[id] = $sortable;
      $sortable.attr('data-sortable-id', id);
      items.attr('data-item-sortable-id', id);
    }

    $sortable.data('items', options.items);
    placeholders = placeholders.add(placeholder);
    if (options.connectWith) {
      $sortable.data('connectWith', options.connectWith);
    }

    _enableSortable($sortable);
    items.attr('role', 'option');
    items.attr('aria-grabbed', 'false');

    // Mouse over class
    if (options.hoverClass) {
      var hoverClass = 'sortable-over';
      if (typeof options.hoverClass === 'string') {
        hoverClass = options.hoverClass;
      }

      items.hover(function() {
        this.classList.add(hoverClass);
      }, function() {
        this.classList.remove(hoverClass);
      });
    }

    // Handle drag events on draggable items
    items.on('dragstart.h5s', function(e) {
      e.stopImmediatePropagation();

      if (options.dragImage) {
        _attachGhost(e.originalEvent, {
          item: options.dragImage,
          x: 0,
          y: 0
        });
        console.log('WARNING: dragImage option is deprecated' +
        ' and will be removed in the future!');
      } else {
        // add transparent clone or other ghost to cursor
        _getGhost(e.originalEvent, $(this), options.dragImage);
      }
      // cache selsection & add attr for dragging
      this.classList.add(options.draggingClass);
      dragging = $(this);
      dragging.attr('aria-grabbed', 'true');
      // grab values
      index = dragging.index();
      draggingHeight = dragging.height();
      startParent = this.parentElement;
      // trigger sortstar update
      dragging.parent().triggerHandler('sortstart', {
        item: dragging,
        placeholder: placeholder,
        startparent: $(startParent)
      });
    });
    // Handle drag events on draggable items
    items.on('dragend.h5s', function() {
      var newParent;
      if (!dragging) {
        return;
      }
      // remove dragging attributes and show item
      dragging.removeClass(options.draggingClass);
      dragging.attr('aria-grabbed', 'false');
      dragging.show();

      placeholders.detach();
      newParent = $(this.parentElement);
      dragging.parent().triggerHandler('sortstop', {
        item: dragging,
        startparent: $(startParent)
      });
      if (index !== dragging.index() || startParent !== newParent.get(0)) {
        dragging.parent().triggerHandler('sortupdate', {
          item: dragging,
          index: newParent.children(newParent.data('items')).index(dragging),
          oldindex: items.index(dragging),
          elementIndex: dragging.index(),
          oldElementIndex: index,
          startparent: $(startParent),
          endparent: newParent
        });
      }
      dragging = null;
      draggingHeight = null;
    });
    // Handle drop event on sortable & placeholder
    // TODO: REMOVE placeholder?????
    $(this).add([placeholder]).on('drop.h5s', function(e) {
      var visiblePlaceholder;
      if (!_listsConnected($sortable, $(dragging).parent())) {
        return;
      }

      e.stopPropagation();
      visiblePlaceholder = placeholders.get().filter(_visible)[0];
      visiblePlaceholder.parentElement.insertBefore(
        dragging.get(0),
        visiblePlaceholder.nextElementSibling
      );
      dragging.trigger('dragend.h5s');
      return false;
    });

    // Handle dragover and dragenter events on draggable items
    items.add([this]).on('dragover.h5s dragenter.h5s', function(e) {
      if (!_listsConnected($sortable, $(dragging).parent())) {
        return;
      }

      e.preventDefault();
      e.originalEvent.dataTransfer.dropEffect = 'move';
      if (items.is(this)) {
        var thisHeight = parseInt(getComputedStyle(this).height);
        var placeholderIndex = _index(placeholder);
        var thisIndex = _index(this);
        var targetAfter;
        if (options.forcePlaceholderSize) {
          placeholder.style.height = draggingHeight + 'px';
        }

        // Check if `this` is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
        if (thisHeight > draggingHeight) {
          // Dead zone?
          var deadZone = thisHeight - draggingHeight;
          var offsetTop = $(this).offset().top;
          if (placeholderIndex < thisIndex &&
              e.originalEvent.pageY < offsetTop + deadZone) {
            return false;
          }
          if (placeholderIndex > thisIndex &&
              e.originalEvent.pageY > offsetTop + thisHeight - deadZone) {
            return false;
          }
        }

        dragging.hide();
        if (placeholderIndex < thisIndex) {
          targetAfter = this.nextElementSibling;
        } else {
          targetAfter = this;
        }
        this.parentNode.insertBefore(placeholder, targetAfter);
        placeholders.not(placeholder).detach();
      } else {
        if (!placeholders.is(this) && !$(this).children(options.items).length) {
          placeholders.detach();
          this.appendChild(placeholder);
        }
      }
      return false;
    });
  });
};

sortable.destroy = function(sortable) {
  _destroySortable(sortable);
};

sortable.enable = function(sortable) {
  _enableSortable(sortable);
};

sortable.disable = function(sortable) {
  _disableSortable(sortable);
};

$.fn.sortable = function(options) {
  return sortable(this, options);
};
/* start-testing */
sortable.__testing = {
  // add internal methods here for testing purposes
  _removeSortableEvents: _removeSortableEvents,
  _removeItemEvents: _removeItemEvents,
  _removeItemData: _removeItemData,
  _removeSortableData: _removeSortableData,
  _listsConnected: _listsConnected,
  _attachGhost: _attachGhost,
  _addGhostPos: _addGhostPos,
  _getGhost: _getGhost,
  _makeGhost: _makeGhost,
  _index: _index
};
module.exports = sortable;
/* end-testing */
<commit_msg>Simplify check, we don't actually need to know whether element is visible, but rather whether it is attached<commit_after>/*
 * HTML5 Sortable jQuery Plugin
 * https://github.com/voidberg/html5sortable
 *
 * Original code copyright 2012 Ali Farhadi.
 * This version is mantained by Alexandru Badiu <andu@ctrlz.ro> & Lukas Oppermann <lukas@vea.re>
 *
 *
 * Released under the MIT license.
 */
'use strict';
/*
 * variables global to the plugin
 */
var dragging;
var draggingHeight;
var placeholders = $();
var sortables = [];
/*
 * remove event handlers from items
 * @param [jquery Collection] items
 * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event)
 */
var _removeItemEvents = function(items) {
  items.off('dragstart.h5s');
  items.off('dragend.h5s');
  items.off('selectstart.h5s');
  items.off('dragover.h5s');
  items.off('dragenter.h5s');
  items.off('drop.h5s');
};
/*
 * remove event handlers from sortable
 * @param [jquery Collection] sortable
 * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event)
 */
var _removeSortableEvents = function(sortable) {
  sortable.off('dragover.h5s');
  sortable.off('dragenter.h5s');
  sortable.off('drop.h5s');
};
/*
 * attache ghost to dataTransfer object
 * @param [event] original event
 * @param [object] ghost-object with item, x and y coordinates
 */
var _attachGhost = function(event, ghost) {
  // this needs to be set for HTML5 drag & drop to work
  event.dataTransfer.effectAllowed = 'move';
  event.dataTransfer.setData('text', '');

  // check if setDragImage method is available
  if (event.dataTransfer.setDragImage) {
    event.dataTransfer.setDragImage(ghost.item, ghost.x, ghost.y);
  }
};
/**
 * _addGhostPos clones the dragged item and adds it as a Ghost item
 * @param [object] event - the event fired when dragstart is triggered
 * @param [object] ghost - .item = node, draggedItem = jQuery collection
 */
var _addGhostPos = function(e, ghost) {
  if (!ghost.x) {
    ghost.x = parseInt(e.pageX - ghost.draggedItem.offset().left);
  }
  if (!ghost.y) {
    ghost.y = parseInt(e.pageY - ghost.draggedItem.offset().top);
  }
  return ghost;
};
/**
 * _makeGhost decides which way to make a ghost and passes it to attachGhost
 * @param [jQuery selection] $draggedItem - the item that the user drags
 */
var _makeGhost = function($draggedItem) {
  return {
    item: $draggedItem[0],
    draggedItem: $draggedItem
  };
};
/**
 * _getGhost constructs ghost and attaches it to dataTransfer
 * @param [event] event - the original drag event object
 * @param [jQuery selection] $draggedItem - the item that the user drags
 * @param [object] ghostOpt - the ghost options
 */
// TODO: could $draggedItem be replaced by event.target in all instances
var _getGhost = function(event, $draggedItem) {
  // add ghost item & draggedItem to ghost object
  var ghost = _makeGhost($draggedItem);
  // attach ghost position
  ghost = _addGhostPos(event, ghost);
  // attach ghost to dataTransfer
  _attachGhost(event, ghost);
};
/*
 * remove data from sortable
 * @param [jquery Collection] a single sortable
 */
var _removeSortableData = function(sortable) {
  sortable.removeData('opts');
  sortable.removeData('connectWith');
  sortable.removeData('items');
  sortable.removeAttr('aria-dropeffect');
};
/*
 * remove data from items
 * @param [jquery Collection] items
 */
var _removeItemData = function(items) {
  items.removeAttr('aria-grabbed');
  items.removeAttr('draggable');
  items.removeAttr('role');
};
/*
 * check if two lists are connected
 * @param [jquery Collection] items
 */
var _listsConnected = function(curList, destList) {
  if (curList[0] === destList[0]) {
    return true;
  }
  if (curList.data('connectWith') !== undefined) {
    return curList.data('connectWith') === destList.data('connectWith');
  }
  return false;
};
/*
 * destroy the sortable
 * @param [jquery Collection] a single sortable
 */
var _destroySortable = function(sortable) {
  var opts = sortable.data('opts') || {};
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  // remove event handlers & data from sortable
  _removeSortableEvents(sortable);
  _removeSortableData(sortable);
  // remove event handlers & data from items
  handles.off('mousedown.h5s');
  _removeItemEvents(items);
  _removeItemData(items);
};
/*
 * enable the sortable
 * @param [jquery Collection] a single sortable
 */
var _enableSortable = function(sortable) {
  var opts = sortable.data('opts');
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  sortable.attr('aria-dropeffect', 'move');
  handles.attr('draggable', 'true');
  // IE FIX for ghost
  // can be disabled as it has the side effect that other events
  // (e.g. click) will be ignored
  var spanEl = (document || window.document).createElement('span');
  if (typeof spanEl.dragDrop === 'function' && !opts.disableIEFix) {
    handles.on('mousedown.h5s', function() {
      if (items.index(this) !== -1) {
        this.dragDrop();
      } else {
        $(this).parents(opts.items)[0].dragDrop();
      }
    });
  }
};
/*
 * disable the sortable
 * @param [jquery Collection] a single sortable
 */
var _disableSortable = function(sortable) {
  var opts = sortable.data('opts');
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  sortable.attr('aria-dropeffect', 'none');
  handles.attr('draggable', false);
  handles.off('mousedown.h5s');
};
/*
 * reload the sortable
 * @param [jquery Collection] a single sortable
 * @description events need to be removed to not be double bound
 */
var _reloadSortable = function(sortable) {
  var opts = sortable.data('opts');
  var items = sortable.children(opts.items);
  var handles = opts.handle ? items.find(opts.handle) : items;
  // remove event handlers from items
  _removeItemEvents(items);
  handles.off('mousedown.h5s');
  // remove event handlers from sortable
  _removeSortableEvents(sortable);
};
/**
 * Get position of the element relatively to its sibling elements
 * @param {Element} element
 * @returns {number}
 */
var _index = function(element) {
  if (!element.parentElement) {
    return 0;
  }
  return [].indexOf.call(element.parentElement.children, element);
};
/**
 * Whether element is in DOM
 * @param {Element} element
 * @returns {boolean}
 */
var _attached = function(element) {
  return !!element.parentNode;
};
/**
 *
 * @param {Element|string} html
 * @returns {Element}
 * @private
 */
var _html2element = function(html) {
  if (typeof html !== 'string') {
    return html;
  }
  var div = document.createElement('div');
  div.innerHTML	= html;
  return div.firstChild;
};
/*
 * public sortable object
 * @param [object|string] options|method
 */
var sortable = function(selector, options) {

  var $sortables = $(selector);
  var method = String(options);

  options = $.extend({
    connectWith: false,
    placeholder: null,
    // dragImage can be null or a jQuery element
    dragImage: null,
    disableIEFix: false,
    placeholderClass: 'sortable-placeholder',
    draggingClass: 'sortable-dragging',
    hoverClass: false
  }, options);

  /* TODO: maxstatements should be 25, fix and remove line below */
  /*jshint maxstatements:false */
  return $sortables.each(function() {

    var $sortable = $(this);

    if (/enable|disable|destroy/.test(method)) {
      sortable[method]($sortable);
      return;
    }

    // get options & set options on sortable
    options = $sortable.data('opts') || options;
    $sortable.data('opts', options);
    // reset sortable
    _reloadSortable($sortable);
    // initialize
    var items = $sortable.children(options.items);
    var index;
    var startParent;
    var placeholder = options.placeholder;
    if (!placeholder) {
      placeholder = document.createElement(
        /^ul|ol$/i.test(this.tagName) ? 'li' : 'div'
      );
    }
    placeholder = _html2element(placeholder);
    placeholder.classList.add(options.placeholderClass);

    // setup sortable ids
    if (!$sortable.attr('data-sortable-id')) {
      var id = sortables.length;
      sortables[id] = $sortable;
      $sortable.attr('data-sortable-id', id);
      items.attr('data-item-sortable-id', id);
    }

    $sortable.data('items', options.items);
    placeholders = placeholders.add(placeholder);
    if (options.connectWith) {
      $sortable.data('connectWith', options.connectWith);
    }

    _enableSortable($sortable);
    items.attr('role', 'option');
    items.attr('aria-grabbed', 'false');

    // Mouse over class
    if (options.hoverClass) {
      var hoverClass = 'sortable-over';
      if (typeof options.hoverClass === 'string') {
        hoverClass = options.hoverClass;
      }

      items.hover(function() {
        this.classList.add(hoverClass);
      }, function() {
        this.classList.remove(hoverClass);
      });
    }

    // Handle drag events on draggable items
    items.on('dragstart.h5s', function(e) {
      e.stopImmediatePropagation();

      if (options.dragImage) {
        _attachGhost(e.originalEvent, {
          item: options.dragImage,
          x: 0,
          y: 0
        });
        console.log('WARNING: dragImage option is deprecated' +
        ' and will be removed in the future!');
      } else {
        // add transparent clone or other ghost to cursor
        _getGhost(e.originalEvent, $(this), options.dragImage);
      }
      // cache selsection & add attr for dragging
      this.classList.add(options.draggingClass);
      dragging = $(this);
      dragging.attr('aria-grabbed', 'true');
      // grab values
      index = dragging.index();
      draggingHeight = dragging.height();
      startParent = this.parentElement;
      // trigger sortstar update
      dragging.parent().triggerHandler('sortstart', {
        item: dragging,
        placeholder: placeholder,
        startparent: $(startParent)
      });
    });
    // Handle drag events on draggable items
    items.on('dragend.h5s', function() {
      var newParent;
      if (!dragging) {
        return;
      }
      // remove dragging attributes and show item
      dragging.removeClass(options.draggingClass);
      dragging.attr('aria-grabbed', 'false');
      dragging.show();

      placeholders.detach();
      newParent = $(this.parentElement);
      dragging.parent().triggerHandler('sortstop', {
        item: dragging,
        startparent: $(startParent)
      });
      if (index !== dragging.index() || startParent !== newParent.get(0)) {
        dragging.parent().triggerHandler('sortupdate', {
          item: dragging,
          index: newParent.children(newParent.data('items')).index(dragging),
          oldindex: items.index(dragging),
          elementIndex: dragging.index(),
          oldElementIndex: index,
          startparent: $(startParent),
          endparent: newParent
        });
      }
      dragging = null;
      draggingHeight = null;
    });
    // Handle drop event on sortable & placeholder
    // TODO: REMOVE placeholder?????
    $(this).add([placeholder]).on('drop.h5s', function(e) {
      var visiblePlaceholder;
      if (!_listsConnected($sortable, $(dragging).parent())) {
        return;
      }

      e.stopPropagation();
      visiblePlaceholder = placeholders.get().filter(_attached)[0];
      visiblePlaceholder.parentElement.insertBefore(
        dragging.get(0),
        visiblePlaceholder.nextElementSibling
      );
      dragging.trigger('dragend.h5s');
      return false;
    });

    // Handle dragover and dragenter events on draggable items
    items.add([this]).on('dragover.h5s dragenter.h5s', function(e) {
      if (!_listsConnected($sortable, $(dragging).parent())) {
        return;
      }

      e.preventDefault();
      e.originalEvent.dataTransfer.dropEffect = 'move';
      if (items.is(this)) {
        var thisHeight = parseInt(getComputedStyle(this).height);
        var placeholderIndex = _index(placeholder);
        var thisIndex = _index(this);
        var targetAfter;
        if (options.forcePlaceholderSize) {
          placeholder.style.height = draggingHeight + 'px';
        }

        // Check if `this` is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
        if (thisHeight > draggingHeight) {
          // Dead zone?
          var deadZone = thisHeight - draggingHeight;
          var offsetTop = $(this).offset().top;
          if (placeholderIndex < thisIndex &&
              e.originalEvent.pageY < offsetTop + deadZone) {
            return false;
          }
          if (placeholderIndex > thisIndex &&
              e.originalEvent.pageY > offsetTop + thisHeight - deadZone) {
            return false;
          }
        }

        dragging.hide();
        if (placeholderIndex < thisIndex) {
          targetAfter = this.nextElementSibling;
        } else {
          targetAfter = this;
        }
        this.parentNode.insertBefore(placeholder, targetAfter);
        placeholders.not(placeholder).detach();
      } else {
        if (!placeholders.is(this) && !$(this).children(options.items).length) {
          placeholders.detach();
          this.appendChild(placeholder);
        }
      }
      return false;
    });
  });
};

sortable.destroy = function(sortable) {
  _destroySortable(sortable);
};

sortable.enable = function(sortable) {
  _enableSortable(sortable);
};

sortable.disable = function(sortable) {
  _disableSortable(sortable);
};

$.fn.sortable = function(options) {
  return sortable(this, options);
};
/* start-testing */
sortable.__testing = {
  // add internal methods here for testing purposes
  _removeSortableEvents: _removeSortableEvents,
  _removeItemEvents: _removeItemEvents,
  _removeItemData: _removeItemData,
  _removeSortableData: _removeSortableData,
  _listsConnected: _listsConnected,
  _attachGhost: _attachGhost,
  _addGhostPos: _addGhostPos,
  _getGhost: _getGhost,
  _makeGhost: _makeGhost,
  _index: _index
};
module.exports = sortable;
/* end-testing */
<|endoftext|>


<commit_before>

// USAGE:
// 		require('ergo-utils').inject_macros()

// console.error(__TODO__)

// Why so cumbersome? Because we're injecting code into the GLOBAL scope, which frankly said, is never great thing.
// Note that the policy usage is that this should ONLY be used for debugging.
var l = require('./log').module('ergo-utils');
var _ = require('./not_');

module.exports = function() { // TODO add ability to define a macro: eg require(...)(['__BUG__', '__LINE__(__FILE__): Bug detected here'])

	// based on: http://stackoverflow.com/a/11386493/125525

	Object.defineProperty(global, '__stack__', {
	  get: function(){
	    var orig = Error.prepareStackTrace;
	    Error.prepareStackTrace = function(_, stack){ return stack; };
	    var err = new Error;
	    Error.captureStackTrace(err, arguments.callee);
	    var stack = err.stack;
	    Error.prepareStackTrace = orig;
	    return stack;
	  }
	});
	const stack_offset = 1;
	function __fnLine(offset) {
		var s = __stack__;
		offset = offset || stack_offset;
		if (offset>=s.length)
			offset = s.length-1;
		return s[offset].getLineNumber();
	}
	function __fnFilename(offset) {
		var s = __stack__;
		offset = offset || stack_offset;
		if (offset>=s.length)
			offset = s.length-1;
		return s[offset].getFileName().split('/').slice(-1)[0];
	}

	Object.defineProperty(global, '__line__', {
	  get: function(){
	    return __fnLine();
	  }
	});
	Object.defineProperty(global, '__file__', {
	  get: function(){
	    return __fnFilename();
	  }
	});

	Object.defineProperty(global, '__TODO__', {
	  get: function(){
	    return "TODO at " + __fnFilename(stack_offset+1) + "("+__fnLine(stack_offset+1)+")";
	  }
	});

	// log using the global logger (not specific to this module)
	require('./log').logw('ENABLED macros in ' + __fnFilename(stack_offset+1) + "("+__fnLine(stack_offset+1)+ "). Their use should be disabled in Production systems");
}
<commit_msg>minor fixes<commit_after>

// USAGE:
// 		require('ergo-utils').inject_macros()

// console.error(__TODO__)

// Why so cumbersome? Because we're injecting code into the GLOBAL scope, which frankly said, is never great thing.
// Note that the policy usage is that this should ONLY be used for debugging.

module.exports = function() { // TODO add ability to define a macro: eg require(...)(['__BUG__', '__LINE__(__FILE__): Bug detected here'])

	// based on: http://stackoverflow.com/a/11386493/125525

	Object.defineProperty(global, '__stack__', {
	  get: function(){
	    var orig = Error.prepareStackTrace;
	    Error.prepareStackTrace = function(_, stack){ return stack; };
	    var err = new Error;
	    Error.captureStackTrace(err, arguments.callee);
	    var stack = err.stack;
	    Error.prepareStackTrace = orig;
	    return stack;
	  }
	});
	const stack_offset = 1;
	function __fnLine(offset) {
		var s = __stack__;
		offset = offset || stack_offset;
		if (offset>=s.length)
			offset = s.length-1;
		return s[offset].getLineNumber();
	}
	function __fnFilename(offset) {
		var s = __stack__;
		offset = offset || stack_offset;
		if (offset>=s.length)
			offset = s.length-1;
		return s[offset].getFileName().split('/').slice(-1)[0];
	}

	Object.defineProperty(global, '__line__', {
	  get: function(){
	    return __fnLine();
	  }
	});
	Object.defineProperty(global, '__file__', {
	  get: function(){
	    return __fnFilename();
	  }
	});

	Object.defineProperty(global, '__TODO__', {
	  get: function(){
	    return "TODO at " + __fnFilename(stack_offset+1) + "("+__fnLine(stack_offset+1)+")";
	  }
	});

	// log using the global logger (not specific to this module)
	require('./log').vlogw('ENABLED macros in ' + __fnFilename(stack_offset+1) + "("+__fnLine(stack_offset+1)+ "). Their use should be disabled in Production systems");
}
<|endoftext|>


<commit_before>(function( $, window ) {
	if(location.hash !== ""){
		throw "Hash must be empty for tests to work properly";
	}

	var $doc, $instance, commonSetup, commonTeardown;

	commonSetup = function() {
		$instance = $( "#dialog" );

		if( $instance.data("instance") ) {
			$instance.data( "instance" ).destroy();
		}

		$instance.dialog();
	};

	commonTeardown = function() {
		$instance.unbind( "dialog-closed" );
		$instance.unbind( "dialog-opened" );

		$instance.data( "instance" ).destroy();
	};

	// we have to give the browser the time to trigger a hashchange
	// so there's no mixup
	function closeInstance(){
		$instance.trigger( "dialog-close" );
		setTimeout(function(){
			start()
		}, 400);
	}

	module( "opening", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	var openTest = function( open ) {
		$instance.one( "dialog-opened", function(){
			ok( $instance.is(".dialog-open") );
			closeInstance();
		});

		ok( !$instance.is(".dialog-open") );

		open();
	};

	asyncTest( "with the link", function() {
		var $link = $( $instance.find("a").attr( "href" ) );

		openTest(function() {
			$link.trigger( "click" );
		});
	});

	asyncTest( "with a trigger", function() {
		openTest(function() {
			$instance.trigger( "dialog-open" );
		});
	});

	asyncTest( "with trigger sets the hash to #dialog", function() {
		$instance.one( "dialog-opened", function(){
			equal( location.hash, "#dialog-dialog" );
			closeInstance();
		});

		ok( !$instance.is(".dialog-open") );
		$instance.trigger( "dialog-open" );
	});

	module( "background", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	test( "is added to the body", function() {
		equal($( "body" ).find( ".dialog-background" ).length ,1 );
	});

	module( "closing", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	var closeTest = function( close ) {
		expect( 3 );

		$instance.one( "dialog-opened", function(){
			ok( $instance.is(".dialog-open") );
			$instance.trigger( "dialog-close" );
		});

		$instance.one( "dialog-closed", function(){
			ok( !$instance.is(".dialog-open") );
			start();
		});

		ok( !$instance.is(".dialog-open") );
		$instance.trigger( "dialog-open" );
	};

	asyncTest( "using trigger makes the dialog invisible", function() {
		window.foo = true;
		closeTest(function() {
			$instance.trigger( "dialog-close" );
		});
	});

	asyncTest( "using the back button makes the dialog invisible", function() {
		closeTest(function() {
			window.history.back();
		});
	});

	asyncTest( "using the escape key makes the dialog invisible", function() {
		var keyupEvent = {
			type: "keyup",
			timestamp: (new Date()).getTime()
		};

		keyupEvent.which = 27;

		closeTest(function() {
			$( document ).trigger( keyupEvent );
		});
	});

	asyncTest( "closing an open dialog clears the hash", function() {
		$(window).one("hashchange", function(){
			equal(location.hash, "#dialog-dialog");

			$(window).one("hashchange", function(){
				equal(location.hash, "");
				start();
			});

			$instance.trigger("dialog-close");
		});

		$instance.trigger("dialog-open");
	});

	asyncTest( "closing an open dialog doesn't clear other hash", function() {
		$(window).one("hashchange", function(){
			equal(location.hash, "#dialog-dialog");

			$(window).one("hashchange", function(){
				// the hash should not have changed ...
				equal(location.hash, "#foo");

				// ... but the dialog should be closed
				ok( !$instance.is(".dialog-open") );
				start();
			});

			location.hash = "foo"
			$instance.trigger("dialog-close");
		});

		$instance.trigger("dialog-open");
	});

})( window.jQuery || window.shoestring, this );
<commit_msg>wrong event<commit_after>(function( $, window ) {
	if(location.hash !== ""){
		throw "Hash must be empty for tests to work properly";
	}

	var $doc, $instance, commonSetup, commonTeardown;

	commonSetup = function() {
		$instance = $( "#dialog" );

		if( $instance.data("instance") ) {
			$instance.data( "instance" ).destroy();
		}

		$instance.dialog();
	};

	commonTeardown = function() {
		$instance.unbind( "dialog-closed" );
		$instance.unbind( "dialog-opened" );

		$instance.data( "instance" ).destroy();
	};

	// we have to give the browser the time to trigger a hashchange
	// so there's no mixup
	function closeInstance(){
		$instance.trigger( "dialog-close" );
		setTimeout(function(){
			start()
		}, 400);
	}

	module( "opening", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	var openTest = function( open ) {
		$instance.one( "dialog-opened", function(){
			ok( $instance.is(".dialog-open") );
			closeInstance();
		});

		ok( !$instance.is(".dialog-open") );

		open();
	};

	asyncTest( "with the link", function() {
		var $link = $( $instance.find("a").attr( "href" ) );

		openTest(function() {
			$link.trigger( "click" );
		});
	});

	asyncTest( "with a trigger", function() {
		openTest(function() {
			$instance.trigger( "dialog-open" );
		});
	});

	asyncTest( "with trigger sets the hash to #dialog", function() {
		$instance.one( "dialog-opened", function(){
			equal( location.hash, "#dialog-dialog" );
			closeInstance();
		});

		ok( !$instance.is(".dialog-open") );
		$instance.trigger( "dialog-open" );
	});

	module( "background", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	test( "is added to the body", function() {
		equal($( "body" ).find( ".dialog-background" ).length ,1 );
	});

	module( "closing", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	var closeTest = function( close ) {
		expect( 3 );

		$instance.one( "dialog-opened", function(){
			ok( $instance.is(".dialog-open") );
			$instance.trigger( "dialog-close" );
		});

		$instance.one( "dialog-closed", function(){
			ok( !$instance.is(".dialog-open") );
			start();
		});

		ok( !$instance.is(".dialog-open") );
		$instance.trigger( "dialog-open" );
	};

	asyncTest( "using trigger makes the dialog invisible", function() {
		window.foo = true;
		closeTest(function() {
			$instance.trigger( "dialog-close" );
		});
	});

	asyncTest( "using the back button makes the dialog invisible", function() {
		closeTest(function() {
			window.history.back();
		});
	});

	asyncTest( "using the escape key makes the dialog invisible", function() {
		var keyupEvent = {
			type: "keyup",
			timestamp: (new Date()).getTime()
		};

		keyupEvent.which = 27;

		closeTest(function() {
			$( document ).trigger( keyupEvent );
		});
	});

	asyncTest( "closing an open dialog clears the hash", function() {
		$(window).one("hashchange", function(){
			equal(location.hash, "#dialog-dialog");

			$(window).one("hashchange", function(){
				equal(location.hash, "");
				start();
			});

			$instance.trigger("dialog-close");
		});

		$instance.trigger("dialog-open");
	});

	asyncTest( "closing an open dialog doesn't clear other hash", function() {
		$(window).one("hashchange", function(){
			equal(location.hash, "#dialog-dialog");

			$instance.one("dialog-closed", function(){
				// the hash should not have changed ...
				equal(location.hash, "#foo");

				// ... but the dialog should be closed
				ok( !$instance.is(".dialog-open") );
				start();
			});

			location.hash = "foo"
			$instance.trigger("dialog-close");
		});

		$instance.trigger("dialog-open");
	});

})( window.jQuery || window.shoestring, this );
<|endoftext|>


<commit_before>var allEmbeds = new Array();
var currentEmbedIndex = 0;
function slidesLiveEmbedBox(){
	//Public properties
	var thisInstance = this;
	this.xmlhttp = 5;
	this.presentationID = 38889556;
	this.width = 960;
	this.height = 100;
	this.videoSlideRatio = -1; //-1-100 -1 is balanced
	this.forceLightbox = true;
	this.zoomingOn = true;
	this.startSlide = 1;
	this.bgColor = "#1E1E1E";

	//Private vars
	this.playerContainer = document.createElement('div'),
	this.hasVideo = true,
	this.hasSlides = true,
	this.mediaType = "",
	this.mediaID = "",
	this.isPaird = false,
	this.playerURL = "http://slideslive.com/bundles/player/Player_5_THC.swf",
	//this.playerURL = "http://localhost/SlidesLive/web/bundles/player/Player_5_THC.swf",
	this.presentationJsonApiUrl = "http://slideslive.com/embedjsonapi/",

	this.embedPresentation = function(presentationID, width, videoSlideRatio, forceLightbox, zoomingOn, startSlide) {
		console.log("Embeding presentation"+presentationID);
		if(typeof(presentationID)!=='undefined') thisInstance.presentationID = presentationID;
		if(typeof(width)!=='undefined') thisInstance.width = width;
		if(typeof(videoSlideRatio)!=='undefined') thisInstance.videoSlideRatio = videoSlideRatio;
		if(typeof(forceLightbox)!=='undefined') thisInstance.forceLightbox = forceLightbox;
		if(typeof(zoomingOn)!=='undefined') thisInstance.zoomingOn = zoomingOn;
		if(typeof(startSlide)!=='undefined') thisInstance.startSlide = startSlide;

		thisInstance.createPlayerContainer();
	},

	this.createPlayerContainer = function() {
		console.log("creating container");
		thisInstance.playerContainer.style.width = thisInstance.width+'px';
		thisInstance.playerContainer.style.height = thisInstance.height+'px';
		thisInstance.playerContainer.style.color = "white";
		thisInstance.playerContainer.setAttribute("id", thisInstance.presentationID);
		thisInstance.getPresentationData();

		//Find script tag that called creation
		var scripts = document.getElementsByTagName("script");
		var embedScript = document.getElementById('sle81767');

		//Try to find exact one
		for (var i=0; i<scripts.length; ++i ) {
		  if ( scripts[i].innerHTML.indexOf("embedPresentation("+thisInstance.presentationID) != -1 ) {
			embedScript = scripts[i];
		  }
		}

		embedScript.parentNode.insertBefore(thisInstance.playerContainer, embedScript);
	},

	this.resizePlayerContainer = function(newHeight) {
		if(thisInstance.hasSlides && !thisInstance.hasVideo) newHeight = (thisInstance.width * 3) / 4;
		thisInstance.height = newHeight;
		console.log(thisInstance.height);
		thisInstance.playerContainer.style.height = thisInstance.height+"px";
	},

	this.createPlayerHtml = function(){
		var flashVarString = "hasVideo="+thisInstance.hasVideo+
							"&hasSlides="+thisInstance.hasSlides+
							"&presentationID="+thisInstance.presentationID+
							"&mediaType="+thisInstance.mediaType+
							"&mediaID="+thisInstance.mediaID+
							"&widthScale="+thisInstance.width+
							"&isEmbed=true"+
							"&isPaid=true"+thisInstance.isPaid+
							"&videoSlideRatio="+thisInstance.videoSlideRatio+
							"&zoomingOn="+thisInstance.zoomingOn+
							"&startSlide="+thisInstance.startSlide;

		if(thisInstance.bgColor == "transparent"){
			var colorParameter = "<param name=\"wmode\" value=\"transparent\">";
			var colorEmbed = "wmode=\"transparent\"";
		} else {
			var colorParameter = "<param name=\"bgcolor\" value=\""+thisInstance.bgColor+"\">";
			var colorEmbed = "bgcolor=\""+thisInstance.bgColor+"\"";
		}

		var playerString = "<object type=\"application/x-shockwave-flash\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"100%\" height=\"100%\">"+
							"<param name=\"movie\" value=\""+thisInstance.playerURL+"\"></param>"+
							"<param name=\"allowFullScreen\" value=\"true\"></param>"+
							"<param name=\"allowscriptaccess\" value=\"always\"></param>"+
							"<param name=\"flashvars\" value=\""+flashVarString+"\"></param>"+
							colorParameter+
    						"<embed src=\""+thisInstance.playerURL+"\" "+colorEmbed+" flashvars=\""+flashVarString+"\" type=\"application/x-shockwave-flash\" width=\"100%\" height=\"100%\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\"  allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>"+
							"</object>";
		return playerString;
	}

	this.getPresentationData = function(){
		if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
			thisInstance.xmlhttp=new XMLHttpRequest();
		} else {// code for IE6, IE5
			thisInstance.xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
		}

		thisInstance.xmlhttp.open("GET",thisInstance.presentationJsonApiUrl+thisInstance.presentationID,true);
		thisInstance.xmlhttp.onreadystatechange=thisInstance.serverResponseProcess;
		thisInstance.xmlhttp.send();
	}

	this.serverResponseProcess = function(){
		if (thisInstance.xmlhttp.readyState==4 && thisInstance.xmlhttp.status==200)
		{
			var json = thisInstance.xmlhttp.responseText;
			var presentations = JSON.parse(json);
			var presentation = presentations[0];
			console.log(json);
			thisInstance.hasVideo = presentation.hasVideo;
			thisInstance.hasSlides = presentation.hasSlides;
			thisInstance.mediaType = presentation.mediaType;
			thisInstance.mediaID = presentation.mediaID;
			thisInstance.isPaid = presentation.isPaid;
		}
		thisInstance.playerContainer.innerHTML = thisInstance.createPlayerHtml();
	}
};

function createSlidesLiveBox(){
	var tmpSL = new slidesLiveEmbedBox();
	allEmbeds[currentEmbedIndex] = tmpSL;
	currentEmbedIndex++;
	return tmpSL;
}

function resizeEmbedBridge(newHeight, presentationID) {
	for (var i = 0; i < allEmbeds.length; i++) {
		if(allEmbeds[i].presentationID == presentationID) allEmbeds[i].resizePlayerContainer(newHeight);
	}
}
<commit_msg>Embed lightbox update<commit_after>var allEmbeds = new Array();
var currentEmbedIndex = 0;
function slidesLiveEmbedBox(){
	//Public properties
	var thisInstance = this;
	this.xmlhttp = 5;
	this.presentationID = 38889556;
	this.width = 960;
	this.height = 100;
	this.videoSlideRatio = -1; //-1-100 -1 is balanced
	this.forceLightbox = true;
	this.zoomingOn = true;
	this.startSlide = 1;
	this.bgColor = "#1E1E1E";

	//Private vars
	this.playerContainer = document.createElement('div'),
	this.lightboxShadow = document.createElement('div'),
	this.lightboxClose = document.createElement('div'),
	this.hasVideo = true,
	this.hasSlides = true,
	this.mediaType = "",
	this.mediaID = "",
	this.isPaid = false,
	this.playerURL = "http://slideslive.com/bundles/player/Player_5_THC.swf",
	//this.playerURL = "http://localhost/SlidesLive/web/bundles/player/Player_5_THC.swf",
	this.presentationJsonApiUrl = "http://slideslive.com/embedjsonapi/",

	this.embedPresentation = function(presentationID, width, videoSlideRatio, forceLightbox, zoomingOn, startSlide) {
		thisInstance.printLog("Embeding presentation"+presentationID);
		if(typeof(presentationID)!=='undefined') thisInstance.presentationID = presentationID;
		if(typeof(width)!=='undefined') thisInstance.width = width;
		if(typeof(videoSlideRatio)!=='undefined') thisInstance.videoSlideRatio = videoSlideRatio;
		if(typeof(forceLightbox)!=='undefined') thisInstance.forceLightbox = forceLightbox;
		if(typeof(zoomingOn)!=='undefined') thisInstance.zoomingOn = zoomingOn;
		if(typeof(startSlide)!=='undefined') thisInstance.startSlide = startSlide;

		thisInstance.createPlayerContainer();
	},

	this.createPlayerContainer = function() {
		thisInstance.printLog("creating container");
		thisInstance.playerContainer.style.width = thisInstance.width+'px';
		thisInstance.playerContainer.style.height = thisInstance.height+'px';
		thisInstance.playerContainer.style.color = "white";
		thisInstance.playerContainer.setAttribute("id", thisInstance.presentationID);
		thisInstance.getPresentationData();

		//Find script tag that called creation
		var scripts = document.getElementsByTagName("script");
		var embedScript = document.getElementById('sle81767');

		//Try to find exact one
		for (var i=0; i<scripts.length; ++i ) {
		  if ( scripts[i].innerHTML.indexOf("embedPresentation("+thisInstance.presentationID) != -1 ) {
			embedScript = scripts[i];
		  }
		}

		embedScript.parentNode.insertBefore(thisInstance.playerContainer, embedScript);
	},

	this.resizePlayerContainer = function(newHeight) {
		if(thisInstance.hasSlides && !thisInstance.hasVideo) newHeight = (thisInstance.width * 3) / 4;
		thisInstance.height = newHeight;
		thisInstance.printLog(thisInstance.height);
		thisInstance.playerContainer.style.height = thisInstance.height+"px";
	},

	this.createPlayerHtml = function(scaledWidth, lightboxCode){
		if(typeof(scaledWidth)=='undefined') scaledWidth = thisInstance.width;

		var flashVarString = "hasVideo="+thisInstance.hasVideo+
							"&hasSlides="+thisInstance.hasSlides+
							"&presentationID="+thisInstance.presentationID+
							"&mediaType="+thisInstance.mediaType+
							"&mediaID="+thisInstance.mediaID+
							"&widthScale="+scaledWidth+
							"&isEmbed=true"+
							"&isPaid="+thisInstance.isPaid+
							"&videoSlideRatio="+thisInstance.videoSlideRatio+
							"&zoomingOn="+thisInstance.zoomingOn+
							"&startSlide="+thisInstance.startSlide;

		if(thisInstance.bgColor == "transparent" || lightboxCode){
			var colorParameter = "<param name=\"wmode\" value=\"transparent\">";
			var colorEmbed = "wmode=\"transparent\"";
		} else {
			var colorParameter = "<param name=\"bgcolor\" value=\""+thisInstance.bgColor+"\">";
			var colorEmbed = "bgcolor=\""+thisInstance.bgColor+"\"";
		}

		var playerString = "<object type=\"application/x-shockwave-flash\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"100%\" height=\"100%\">"+
							"<param name=\"movie\" value=\""+thisInstance.playerURL+"\"></param>"+
							"<param name=\"allowFullScreen\" value=\"true\"></param>"+
							"<param name=\"allowscriptaccess\" value=\"always\"></param>"+
							"<param name=\"flashvars\" value=\""+flashVarString+"\"></param>"+
							colorParameter+
    						"<embed src=\""+thisInstance.playerURL+"\" "+colorEmbed+" flashvars=\""+flashVarString+"\" type=\"application/x-shockwave-flash\" width=\"100%\" height=\"100%\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\"  allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>"+
							"</object>";
		return playerString;
	}

	this.getPresentationData = function(){
		if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
			thisInstance.xmlhttp=new XMLHttpRequest();
		} else {// code for IE6, IE5
			thisInstance.xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
		}

		thisInstance.xmlhttp.open("GET",thisInstance.presentationJsonApiUrl+thisInstance.presentationID,true);
		thisInstance.xmlhttp.onreadystatechange=thisInstance.serverResponseProcess;
		thisInstance.xmlhttp.send();
	}

	this.serverResponseProcess = function(){
		if (thisInstance.xmlhttp.readyState==4 && thisInstance.xmlhttp.status==200)
		{
			var json = thisInstance.xmlhttp.responseText;
			var presentations = JSON.parse(json);
			var presentation = presentations[0];
			thisInstance.printLog(json);
			thisInstance.hasVideo = presentation.hasVideo;
			thisInstance.hasSlides = presentation.hasSlides;
			thisInstance.mediaType = presentation.mediaType;
			thisInstance.mediaID = presentation.mediaID;
			thisInstance.isPaid = presentation.isPaid;
		}
		thisInstance.playerContainer.innerHTML = thisInstance.createPlayerHtml();
	}

	this.hideLightBox = function() {
		thisInstance.lightboxShadow.style.display = "none";

		//Find script tag that called creation
		var scripts = document.getElementsByTagName("script");
		var embedScript = document.getElementById('sle81767');

		thisInstance.playerContainer.style.width = thisInstance.width+'px';
		thisInstance.playerContainer.style.marginLeft = "0px";
		thisInstance.playerContainer.style.marginRight = "0px";
		thisInstance.playerContainer.innerHTML = thisInstance.createPlayerHtml();

		//Try to find exact one
		for (var i=0; i<scripts.length; ++i ) {
		  if ( scripts[i].innerHTML.indexOf("embedPresentation("+thisInstance.presentationID) != -1 ) {
			embedScript = scripts[i];
		  }
		}

		embedScript.parentNode.insertBefore(thisInstance.playerContainer, embedScript);
	}

	this.displayLightBox = function() {
		if(thisInstance.width >= 650 || !thisInstance.forceLightbox) return false;

		document.onkeypress=function(e){
			var e=window.event || e
			if(e.keyCode == 27) thisInstance.hideLightBox();
		}

		lbPlayerWidth = (0.8 * window.innerWidth)
		thisInstance.lightboxShadow.style.width = "100%";
		thisInstance.lightboxShadow.style.height = "100%";
		thisInstance.lightboxShadow.style.backgroundColor = "#000";
		thisInstance.lightboxShadow.style.backgroundColor = "rgba(0, 0, 0, 0.8)";

		thisInstance.lightboxShadow.style.display = "block";
		thisInstance.lightboxShadow.style.position = "fixed";
		thisInstance.lightboxShadow.style.zIndex = "9999";
		thisInstance.lightboxShadow.style.left = "0px";
		thisInstance.lightboxShadow.style.top = "0px";

		thisInstance.lightboxClose.addEventListener("click",thisInstance.hideLightBox,true);
		thisInstance.lightboxClose.style.width = "50px";
		thisInstance.lightboxClose.style.height = "50px";
		thisInstance.lightboxClose.style.backgroundColor = "#CC6633";
		thisInstance.lightboxClose.style.display = "block";
		thisInstance.lightboxClose.style.position = "fixed";
		thisInstance.lightboxClose.style.zIndex = "9999";
		thisInstance.lightboxClose.style.right = "0px";
		thisInstance.lightboxClose.style.top = "0px";

		thisInstance.playerContainer.style.width = lbPlayerWidth+'px';
		thisInstance.playerContainer.style.height = "500px";
		thisInstance.playerContainer.style.marginLeft = "auto";
		thisInstance.playerContainer.style.marginRight = "auto";

		document.body.appendChild(thisInstance.lightboxShadow);
		thisInstance.lightboxShadow.appendChild(thisInstance.playerContainer);
		thisInstance.lightboxShadow.appendChild(thisInstance.lightboxClose);

		thisInstance.playerContainer.innerHTML = thisInstance.createPlayerHtml(lbPlayerWidth,true);
		//document.body.insertBefore(thisInstance.lightboxShadow, document.body.firstChild);
	}

	this.printLog = function(message){
		console.log(message);
	}
};

function createSlidesLiveBox(){
	var tmpSL = new slidesLiveEmbedBox();
	allEmbeds[currentEmbedIndex] = tmpSL;
	currentEmbedIndex++;
	return tmpSL;
}

function resizeEmbedBridge(newHeight, presentationID) {
	for (var i = 0; i < allEmbeds.length; i++) {
		if(allEmbeds[i].presentationID == presentationID) allEmbeds[i].resizePlayerContainer(newHeight);
	}
}
<|endoftext|>