<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Enhances and consistently styles text inputs.
//>>label: Text Inputs & Textareas
//>>group: Forms
//>>css.structure: ../css/structure/jquery.mobile.forms.textinput.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../../jquery.mobile.core", "../../jquery.mobile.widget", "../../jquery.mobile.degradeInputs", "../../jquery.mobile.buttonMarkup", "../../jquery.mobile.zoom"  ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.textinput", $.mobile.widget, {
	options: {
		theme: null,
		mini: false,
		// This option defaults to true on iOS devices.
		preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
		initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type]), input[type='file']",
		clearBtn: false,
		clearSearchButtonText: null, //deprecating for 1.3...
		clearBtnText: "clear text",
		disabled: false
	},

	_create: function() {

		var self = this,
			input = this.element,
			o = this.options,
			theme = o.theme || $.mobile.getInheritedTheme( this.element, "c" ),
			themeclass  = " ui-body-" + theme,
			miniclass = o.mini ? " ui-mini" : "",
			isSearch = input.is( "[type='search'], :jqmData(type='search')" ),
			focusedEl,
			clearbtn,
			clearBtnText = o.clearSearchButtonText || o.clearBtnText,
			clearBtnBlacklist = input.is( "textarea, :jqmData(type='range')" ),
			inputNeedsClearBtn = !!o.clearBtn && !clearBtnBlacklist;

		function toggleClear() {
			setTimeout( function() {
				clearbtn.toggleClass( "ui-input-clear-hidden", !input.val() );
			}, 0 );
		}

		$( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );

		focusedEl = input.addClass("ui-input-text ui-body-"+ theme );

		// XXX: Temporary workaround for issue 785 (Apple bug 8910589).
		//      Turn off autocorrect and autocomplete on non-iOS 5 devices
		//      since the popup they use can't be dismissed by the user. Note
		//      that we test for the presence of the feature by looking for
		//      the autocorrect property on the input element. We currently
		//      have no test for iOS 5 or newer so we're temporarily using
		//      the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas
		if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) {
			// Set the attribute instead of the property just in case there
			// is code that attempts to make modifications via HTML.
			input[0].setAttribute( "autocorrect", "off" );
			input[0].setAttribute( "autocomplete", "off" );
		}

		//"search" and "text" input widgets
		if ( isSearch ) {
			focusedEl = input.wrap( "

" ).parent();
		} else if ( input.is( "input" ) ) {
			focusedEl = input.wrap( "

" ).parent();
		}

		if( inputNeedsClearBtn || isSearch ) {
			clearbtn = $( "" + clearBtnText + "" )
				.bind( "click", function( event ) {
					input
						.val( "" )
						.focus()
						.trigger( "change" );
					clearbtn.addClass( "ui-input-clear-hidden" );
					event.preventDefault();
				})
				.appendTo( focusedEl )
				.buttonMarkup({
					icon: "delete",
					iconpos: "notext",
					corners: true,
					shadow: true,
					mini: o.mini
				});

			toggleClear();

			input.bind( "paste cut keyup focus change blur", toggleClear );
		}
		else if ( input.is( "textarea" ) ) {
			input.addClass( "ui-corner-all ui-shadow-inset" + themeclass + miniclass );
		}

		input.focus(function() {
				// In many situations, iOS will zoom into the input upon tap, this prevents that from happening
				if ( o.preventFocusZoom ) {
					$.mobile.zoom.disable( true );
				}
				focusedEl.addClass( $.mobile.focusClass );
			})
			.blur(function() {
				focusedEl.removeClass( $.mobile.focusClass );
				if ( o.preventFocusZoom ) {
					$.mobile.zoom.enable( true );
				}
			})

		// Autogrow
		if ( input.is( "textarea" ) ) {
			var extraLineHeight = 15,
				keyupTimeoutBuffer = 100,
				keyupTimeout;

			this._keyup = function() {
				var scrollHeight = input[ 0 ].scrollHeight,
					clientHeight = input[ 0 ].clientHeight;

				if ( clientHeight < scrollHeight ) {
					input.height(scrollHeight + extraLineHeight);
				}
			};

			input.keyup(function() {
				clearTimeout( keyupTimeout );
				keyupTimeout = setTimeout( self._keyup, keyupTimeoutBuffer );
			});

			// binding to pagechange here ensures that for pages loaded via
			// ajax the height is recalculated without user input
			this._on( $( document ), { "pagechange": "_keyup" });

			// Issue 509: the browser is not providing scrollHeight properly until the styles load
			if ( $.trim( input.val() ) ) {
				// bind to the window load to make sure the height is calculated based on BOTH
				// the DOM and CSS
				this._on( $( window ), {"load": "_keyup"});
			}
		}
		if ( input.attr( "disabled" ) ) {
			this.disable();
		}
	},

	disable: function() {
		var $el,
				parentNeedsDisabled = this.element.attr( "disabled", true )	&& ( this.element.is( "[type='search'], :jqmData(type='search')" ) || ( this.element.is( "[type='text'],textarea" ) && !!this.options.clearBtn ) );
		if ( parentNeedsDisabled ) {
			$el = this.element.parent();
		} else {
			$el = this.element;
		}
		$el.addClass( "ui-disabled" );
		return this._setOption( "disabled", true );
	},

	enable: function() {
		var $el,
				parentNeedsDisabled = this.element.attr( "disabled", true )	&& ( this.element.is( "[type='search'], :jqmData(type='search')" ) || ( this.element.is( "[type='text'],textarea" ) && !!this.options.clearBtn ) );

		// TODO using more than one line of code is acceptable ;)
		if ( parentNeedsDisabled ) {
			$el = this.element.parent();
		} else {
			$el = this.element;
		}
		$el.removeClass( "ui-disabled" );
		return this._setOption( "disabled", false );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.textinput.prototype.enhanceWithin( e.target, true );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Prevent the slider number input from being wrapped in a div.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Enhances and consistently styles text inputs.
//>>label: Text Inputs & Textareas
//>>group: Forms
//>>css.structure: ../css/structure/jquery.mobile.forms.textinput.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../../jquery.mobile.core", "../../jquery.mobile.widget", "../../jquery.mobile.degradeInputs", "../../jquery.mobile.buttonMarkup", "../../jquery.mobile.zoom"  ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.textinput", $.mobile.widget, {
	options: {
		theme: null,
		mini: false,
		// This option defaults to true on iOS devices.
		preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
		initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type]), input[type='file']",
		clearBtn: false,
		clearSearchButtonText: null, //deprecating for 1.3...
		clearBtnText: "clear text",
		disabled: false
	},

	_create: function() {

		var self = this,
			input = this.element,
			o = this.options,
			theme = o.theme || $.mobile.getInheritedTheme( this.element, "c" ),
			themeclass  = " ui-body-" + theme,
			miniclass = o.mini ? " ui-mini" : "",
			isSearch = input.is( "[type='search'], :jqmData(type='search')" ),
			focusedEl,
			clearbtn,
			clearBtnText = o.clearSearchButtonText || o.clearBtnText,
			clearBtnBlacklist = input.is( "textarea, :jqmData(type='range')" ),
			inputNeedsClearBtn = !!o.clearBtn && !clearBtnBlacklist,
			inputNeedsWrap = input.is( "input" ) && !input.is( ":jqmData(type='range')" );

		function toggleClear() {
			setTimeout( function() {
				clearbtn.toggleClass( "ui-input-clear-hidden", !input.val() );
			}, 0 );
		}

		$( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );

		focusedEl = input.addClass("ui-input-text ui-body-"+ theme );

		// XXX: Temporary workaround for issue 785 (Apple bug 8910589).
		//      Turn off autocorrect and autocomplete on non-iOS 5 devices
		//      since the popup they use can't be dismissed by the user. Note
		//      that we test for the presence of the feature by looking for
		//      the autocorrect property on the input element. We currently
		//      have no test for iOS 5 or newer so we're temporarily using
		//      the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas
		if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) {
			// Set the attribute instead of the property just in case there
			// is code that attempts to make modifications via HTML.
			input[0].setAttribute( "autocorrect", "off" );
			input[0].setAttribute( "autocomplete", "off" );
		}

		//"search" and "text" input widgets
		if ( isSearch ) {
			focusedEl = input.wrap( "

" ).parent();
		} else if ( inputNeedsWrap ) {
			focusedEl = input.wrap( "

" ).parent();
		}

		if( inputNeedsClearBtn || isSearch ) {
			clearbtn = $( "" + clearBtnText + "" )
				.bind( "click", function( event ) {
					input
						.val( "" )
						.focus()
						.trigger( "change" );
					clearbtn.addClass( "ui-input-clear-hidden" );
					event.preventDefault();
				})
				.appendTo( focusedEl )
				.buttonMarkup({
					icon: "delete",
					iconpos: "notext",
					corners: true,
					shadow: true,
					mini: o.mini
				});

			toggleClear();

			input.bind( "paste cut keyup focus change blur", toggleClear );
		}
		else if ( !inputNeedsWrap && !isSearch ) {
			input.addClass( "ui-corner-all ui-shadow-inset" + themeclass + miniclass );
		}

		input.focus(function() {
				// In many situations, iOS will zoom into the input upon tap, this prevents that from happening
				if ( o.preventFocusZoom ) {
					$.mobile.zoom.disable( true );
				}
				focusedEl.addClass( $.mobile.focusClass );
			})
			.blur(function() {
				focusedEl.removeClass( $.mobile.focusClass );
				if ( o.preventFocusZoom ) {
					$.mobile.zoom.enable( true );
				}
			})

		// Autogrow
		if ( input.is( "textarea" ) ) {
			var extraLineHeight = 15,
				keyupTimeoutBuffer = 100,
				keyupTimeout;

			this._keyup = function() {
				var scrollHeight = input[ 0 ].scrollHeight,
					clientHeight = input[ 0 ].clientHeight;

				if ( clientHeight < scrollHeight ) {
					input.height(scrollHeight + extraLineHeight);
				}
			};

			input.keyup(function() {
				clearTimeout( keyupTimeout );
				keyupTimeout = setTimeout( self._keyup, keyupTimeoutBuffer );
			});

			// binding to pagechange here ensures that for pages loaded via
			// ajax the height is recalculated without user input
			this._on( $( document ), { "pagechange": "_keyup" });

			// Issue 509: the browser is not providing scrollHeight properly until the styles load
			if ( $.trim( input.val() ) ) {
				// bind to the window load to make sure the height is calculated based on BOTH
				// the DOM and CSS
				this._on( $( window ), {"load": "_keyup"});
			}
		}
		if ( input.attr( "disabled" ) ) {
			this.disable();
		}
	},

	disable: function() {
		var $el,
				parentNeedsDisabled = this.element.attr( "disabled", true )	&& ( this.element.is( "[type='search'], :jqmData(type='search')" ) || ( this.element.is( "[type='text'],textarea" ) && !!this.options.clearBtn ) );
		if ( parentNeedsDisabled ) {
			$el = this.element.parent();
		} else {
			$el = this.element;
		}
		$el.addClass( "ui-disabled" );
		return this._setOption( "disabled", true );
	},

	enable: function() {
		var $el,
				parentNeedsDisabled = this.element.attr( "disabled", true )	&& ( this.element.is( "[type='search'], :jqmData(type='search')" ) || ( this.element.is( "[type='text'],textarea" ) && !!this.options.clearBtn ) );

		// TODO using more than one line of code is acceptable ;)
		if ( parentNeedsDisabled ) {
			$el = this.element.parent();
		} else {
			$el = this.element;
		}
		$el.removeClass( "ui-disabled" );
		return this._setOption( "disabled", false );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.textinput.prototype.enhanceWithin( e.target, true );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>


<commit_before>/**
 * Our implementation of the CWRC-Writer
 * Delegator class.
 * @param config
 * @returns {___anonymous83_84}
 */
function islandoraBackendDelegate(config) {
	this.writer = config.writer;

	/**
	 * @param params
	 * @param callback
	 */
	this.lookupEntity = function(params, callback) {
		var type = params.type;
		var query = params.query;
		var lookupService = params.lookupService;
		if (lookupService == 'project') {
			$.ajax({
				url: cwrc_params['entities_search_callback'] + '/' + params.type + '?entities_query=' + query,
				dataType: 'json',
				success: function(data, status, xhr) {
					if ($.isPlainObject(data)) data = [data];
					if (data != null) {
						callback.call(this.writer, data);
					} else {
						callback.call(this.writer, []);
					}
				},
				error: function(xhr, status, error) {
					if (status == 'parsererror') {
						var lines = xhr.responseText.split(/\n/);
						if (lines[lines.length-1] == '') {
							lines.pop();
						}
						var string = lines.join(',');
						var data = $.parseJSON('['+string+']');
						callback.call(this.writer, data);
					} else {
						callback.call(this.writer, null);
					}
				}
			});
		} else if (lookupService == 'viaf') {
			$.ajax({
				url: 'http://viaf.org/viaf/AutoSuggest',
				data: {
					query: query
				},
				dataType: 'jsonp',
				success: function(data, status, xhr) {
					if (data != null && data.result != null) {
						callback.call(this.writer, data.result);
					} else {
						callback.call(this.writer, []);
					}
				},
				error: function() {
					callback.call(this.writer, null);
				}
			});
		}
	};

	this.validate = function(callback) {
		var docText = this.writer.fm.getDocumentContent(false);
		var schemaUrl = this.writer.schemas[this.writer.schemaId].url;
		var valid = 'pass';
		callback.call(this.writer, valid);
		//TODO: Implement true validator when/if cwrc makes this service available.
	};

	/**
	 * Loads a document based on the currentDocId
	 * TODO Move currentDocId system out of CWRCWriter
	 * @param docName
	 */
	this.loadDocument = function(callback) {
		$.ajax({
			url: Drupal.settings.basePath+'islandora/object/' + PID + '/datastream/CWRC/view',
			type: 'GET',
			async: false,
			dataType: 'xml',
			success: function(doc, status, xhr) {
				window.location.hash = '#' + PID;
				callback.call(this.writer, doc);
				// Need to wait on response to initilize.
				$(document.body).append(''+
				          '

'+
				          '
Edit Annotation
'+
				          '
Remove Annotation
'+
				          '

'
				        );
				        $('.comment_title').click(function(event) {
				          console.log("clicked");
				          //$(this).removeClass('over');
				        }).contextMenu('annoMenuContext', {
				          bindings: {
				            'editAnno': function(tag) {
				              console.log("editAnno");
				              var urn = $('#' + tag.id).parent('div').attr('urn');
				              var title = $('#' + tag.id).text().substring(2, 100);
				              var comment_text = $('#' + tag.id).next('.comment_text');
				              var anno_type = comment_text.find('.comment_type').text();
				              $('#' + tag.id).addClass('annotation-opened').next().show();
				              var annotation = comment_text.find('.comment_content').text();
				              var pm = $('#' + tag.id).find('.comment_showhide');
				              if (pm.text() == '+ ') {
				                pm.empty().append('- ');
				                var id = $('#' + tag.id).attr('id').substring(5, 100);
				                var canvas = $('#' + tag.id).attr('canvas');
				                paint_commentAnnoTargets('#' + tag.id, canvas, id);
				              }
				              startEditting(title, annotation, anno_type, urn);
				            },
				            'removeAnno': function(tag) {
				               var urn = $('#' + tag.id).parent('div').attr('urn');
				               var title = $('#' + tag.id).text().substring(2, 100);
				               if(urn) {
				                 if (confirm("Permananently Delete Annotation '" + title + "'")) {
				                   islandora_deleteAnno(urn);
				                 }
				              }
				            }
				          },
				          shadow: false,
				          menuStyle: {
				              backgroundColor: '#FFFFFF',
				              border: '1px solid #D4D0C8',
				              boxShadow: '1px 1px 2px #CCCCCC',
				              padding: '0px'
				          },
				          itemStyle: {
				            fontFamily: 'Tahoma,Verdana,Arial,Helvetica',
				            fontSize: '11px',
				            color: '#000',
				            lineHeight: '20px',
				            padding: '0px',
				            cursor: 'pointer',
				            textDecoration: 'none',
				            border: 'none'
				          },
				          itemHoverStyle: {
				            color: '#000',
				            backgroundColor: '#DBECF3',
				            border: 'none'
				          }
				        });
			},
			error: function(xhr, status, error) {
			  this.writer.dialogs.show('message', {
					title: 'Error',
					msg: 'An error ('+status+') occurred and '+PID+' was not loaded.',
					type: 'error'
				});
			  this.writer.currentDocId = null;
			}
		});
	};

	/**
	 * Performs the server call to save the document.
	 * @param callback Called with one boolean parameter: true for successful save, false otherwise
	 */
	this.saveDocument = function(callback) {
	  this.writer.mode == this.writer.XMLRDF;
		var docText = this.writer.fm.getDocumentContent(true);
		$.ajax({
			url : window.parent.Drupal.settings.basePath + 'islandora/cwrcwriter/save_data/' + PID,
			type: 'POST',
			async: false,
			dataType: 'text',
			data: {
				"text": docText
			},
			success: function(data, status, xhr) {
			  this.writer.editor.isNotDirty = 1; // force clean state
			  this.writer.dialogs.show('message', {
					title: 'Document Saved',
					msg: this.writer.currentDocId+' was saved successfully.'
				});
				window.location.hash = '#' + PID;
				if (callback) {
					callback.call(this.writer, true);
				}
			},
			error: function() {
			  this.writer.dialogs.show('message', {
					title: 'Error',
					msg: 'An error occurred and ' + PID + ' was not saved.',
					type: 'error'
				});
				if (callback) {
					callback.call(this.writer, false);
				}
			}
		});
	};

	this.getHelp = function(tagName) {
		return this.writer.u.getDocumentationForTag(tagName);
	};
}
<commit_msg>Updating writer delegate, pushing backup.<commit_after>/**
 * Our implementation of the CWRC-Writer
 * Delegator class.
 * @param config
 * @returns {___anonymous83_84}
 */
function islandoraBackendDelegate(config) {
	this.writer = config.writer;

	/**
	 * @param params
	 * @param callback
	 */
	this.lookupEntity = function(params, callback) {
		var type = params.type;
		var query = params.query;
		var lookupService = params.lookupService;

		if (lookupService == 'project') {
			$.ajax({
				url: cwrc_params['entities_search_callback']+ '/' + query,
				dataType: 'json',
				success: function(data, status, xhr) {
					if ($.isPlainObject(data)) data = [data];
					if (data != null) {
						callback.call(this.writer, data);
					} else {
						callback.call(this.writer, []);
					}
				},
				error: function(xhr, status, error) {
					if (status == 'parsererror') {
						var lines = xhr.responseText.split(/\n/);
						if (lines[lines.length-1] == '') {
							lines.pop();
						}
						var string = lines.join(',');
						var data = $.parseJSON('['+string+']');
						callback.call(this.writer, data);
					} else {
						callback.call(this.writer, null);
					}
				}
			});
		} else if (lookupService == 'viaf') {
			$.ajax({
				url: 'http://viaf.org/viaf/AutoSuggest',
				data: {
					query: query
				},
				dataType: 'jsonp',
				success: function(data, status, xhr) {
					if (data != null && data.result != null) {
						callback.call(this.writer, data.result);
					} else {
						callback.call(this.writer, []);
					}
				},
				error: function() {
					callback.call(this.writer, null);
				}
			});
		}
	};

	this.validate = function(callback) {
		var docText = this.writer.fm.getDocumentContent(false);
		var schemaUrl = this.writer.schemas[this.writer.schemaId].url;
		var valid = 'pass';
		callback.call(this.writer, valid);
		//TODO: Implement true validator when/if cwrc makes this service available.
	};

	/**
	 * Loads a document based on the currentDocId
	 * TODO Move currentDocId system out of CWRCWriter
	 * @param docName
	 */
	this.loadDocument = function(callback) {
		$.ajax({
			url: Drupal.settings.basePath+'islandora/object/' + PID + '/datastream/CWRC/view',
			type: 'GET',
			async: false,
			dataType: 'xml',
			success: function(doc, status, xhr) {
				window.location.hash = '#' + PID;
				callback.call(this.writer, doc);
				// Need to wait on response to initilize.
				$(document.body).append(''+
				          '

'+
				          '
Edit Annotation
'+
				          '
Remove Annotation
'+
				          '

'
				        );
				        $('.comment_title').click(function(event) {
				          console.log("clicked");
				          //$(this).removeClass('over');
				        }).contextMenu('annoMenuContext', {
				          bindings: {
				            'editAnno': function(tag) {
				              console.log("editAnno");
				              var urn = $('#' + tag.id).parent('div').attr('urn');
				              var title = $('#' + tag.id).text().substring(2, 100);
				              var comment_text = $('#' + tag.id).next('.comment_text');
				              var anno_type = comment_text.find('.comment_type').text();
				              $('#' + tag.id).addClass('annotation-opened').next().show();
				              var annotation = comment_text.find('.comment_content').text();
				              var pm = $('#' + tag.id).find('.comment_showhide');
				              if (pm.text() == '+ ') {
				                pm.empty().append('- ');
				                var id = $('#' + tag.id).attr('id').substring(5, 100);
				                var canvas = $('#' + tag.id).attr('canvas');
				                paint_commentAnnoTargets('#' + tag.id, canvas, id);
				              }
				              startEditting(title, annotation, anno_type, urn);
				            },
				            'removeAnno': function(tag) {
				               var urn = $('#' + tag.id).parent('div').attr('urn');
				               var title = $('#' + tag.id).text().substring(2, 100);
				               if(urn) {
				                 if (confirm("Permananently Delete Annotation '" + title + "'")) {
				                   islandora_deleteAnno(urn);
				                 }
				              }
				            }
				          },
				          shadow: false,
				          menuStyle: {
				              backgroundColor: '#FFFFFF',
				              border: '1px solid #D4D0C8',
				              boxShadow: '1px 1px 2px #CCCCCC',
				              padding: '0px'
				          },
				          itemStyle: {
				            fontFamily: 'Tahoma,Verdana,Arial,Helvetica',
				            fontSize: '11px',
				            color: '#000',
				            lineHeight: '20px',
				            padding: '0px',
				            cursor: 'pointer',
				            textDecoration: 'none',
				            border: 'none'
				          },
				          itemHoverStyle: {
				            color: '#000',
				            backgroundColor: '#DBECF3',
				            border: 'none'
				          }
				        });
			},
			error: function(xhr, status, error) {
			  this.writer.dialogs.show('message', {
					title: 'Error',
					msg: 'An error ('+status+') occurred and '+PID+' was not loaded.',
					type: 'error'
				});
			  this.writer.currentDocId = null;
			}
		});
	};
	this.attachContextMenu = function() {

	}
	/**
	 * Performs the server call to save the document.
	 * @param callback Called with one boolean parameter: true for successful save, false otherwise
	 */
	this.saveDocument = function(callback) {
	  this.writer.mode == this.writer.XMLRDF;
		var docText = this.writer.fm.getDocumentContent(true);
		$.ajax({
			url : window.parent.Drupal.settings.basePath + 'islandora/cwrcwriter/save_data/' + PID,
			type: 'POST',
			async: false,
			dataType: 'text',
			data: {
				"text": docText
			},
			success: function(data, status, xhr) {
			  this.writer.editor.isNotDirty = 1; // force clean state
			  this.writer.dialogs.show('message', {
					title: 'Document Saved',
					msg: this.writer.currentDocId+' was saved successfully.'
				});
				window.location.hash = '#' + PID;
				if (callback) {
					callback.call(this.writer, true);
				}
			},
			error: function() {
			  this.writer.dialogs.show('message', {
					title: 'Error',
					msg: 'An error occurred and ' + PID + ' was not saved.',
					type: 'error'
				});
				if (callback) {
					callback.call(this.writer, false);
				}
			}
		});
	};

	this.getHelp = function(tagName) {
		return this.writer.u.getDocumentationForTag(tagName);
	};
}
<|endoftext|>


<commit_before>/**
* @description Utillity directives for key and field events
**/
angular.module('umbraco.directives')

.directive('onKeyup', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onKeyup);
            };
            elm.on("keyup", f);
            scope.$on("$destroy", function(){ elm.off("keyup", f);} );
        }
    };
})

.directive('onKeydown', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onKeydown);
            };
            elm.on("keydown", f);
            scope.$on("$destroy", function(){ elm.off("keydown", f);} );
        }
    };
})

.directive('onBlur', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onBlur);
            };
            elm.on("blur", f);
            scope.$on("$destroy", function(){ elm.off("blur", f);} );
        }
    };
})

.directive('onFocus', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onFocus);
            };
            elm.on("focus", f);
            scope.$on("$destroy", function(){ elm.off("focus", f);} );
        }
    };
})

.directive('onDragEnter', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragEnter);
            };
            elm.on("dragenter", f);
            scope.$on("$destroy", function(){ elm.off("dragenter", f);} );
        }
    };
})

.directive('onDragLeave', function () {
    return function (scope, elm, attrs) {
        var f = function (event) {
            var rect = this.getBoundingClientRect();
            var getXY = function getCursorPosition(event) {
                var x, y;

                if (typeof event.clientX === 'undefined') {
                    // try touch screen
                    x = event.pageX + document.documentElement.scrollLeft;
                    y = event.pageY + document.documentElement.scrollTop;
                } else {
                    x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                    y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
                }

                return { x: x, y : y };
            };

            var e = getXY(event.originalEvent);

            // Check the mouseEvent coordinates are outside of the rectangle
            if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
                scope.$apply(attrs.onDragLeave);
            }
        };

        elm.on("dragleave", f);
        scope.$on("$destroy", function(){ elm.off("dragleave", f);} );
    };
})

.directive('onDragOver', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragOver);
            };
            elm.on("dragover", f);
            scope.$on("$destroy", function(){ elm.off("dragover", f);} );
        }
    };
})

.directive('onDragStart', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragStart);
            };
            elm.on("dragstart", f);
            scope.$on("$destroy", function(){ elm.off("dragstart", f);} );
        }
    };
})

.directive('onDragEnd', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragEnd);
            };
            elm.on("dragend", f);
            scope.$on("$destroy", function(){ elm.off("dragend", f);} );
        }
    };
})

.directive('onDrop', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDrop);
            };
            elm.on("drop", f);
            scope.$on("$destroy", function(){ elm.off("drop", f);} );
        }
    };
})

.directive('onOutsideClick', function ($timeout) {
    return function (scope, element, attrs) {

        var eventBindings = [];

        function oneTimeClick(event) {
                var el = event.target.nodeName;

                //ignore link and button clicks
                var els = ["INPUT","A","BUTTON"];
                if(els.indexOf(el) >= 0){return;}

                // ignore children of links and buttons
                // ignore clicks on new overlay
                var parents = $(event.target).parents("a,button,.umb-overlay");
                if(parents.length > 0){
                    return;
                }

                // ignore clicks on dialog from old dialog service
                var oldDialog = $(event.target).parents("#old-dialog-service");
                if (oldDialog.length === 1) {
                    return;
                }

                // ignore clicks in tinyMCE dropdown(floatpanel)
                var floatpanel = $(event.target).closest(".mce-floatpanel");
                if (floatpanel.length === 1) {
                    return;
                }

                //ignore clicks inside this element
                if( $(element).has( $(event.target) ).length > 0 ){
                    return;
                }

                scope.$apply(attrs.onOutsideClick);
        }

        $timeout(function(){

            if ("bindClickOn" in attrs) {

                eventBindings.push(scope.$watch(function() {
                    return attrs.bindClickOn;
                }, function(newValue) {
                    if (newValue === "true") {
                        $(document).on("click", oneTimeClick);
                    } else {
                        $(document).off("click", oneTimeClick);
                    }
                }));

            } else {
                $(document).on("click", oneTimeClick);
            }

            scope.$on("$destroy", function() {
                $(document).off("click", oneTimeClick);

                // unbind watchers
                for (var e in eventBindings) {
                    eventBindings[e]();
                }

            });
        }); // Temp removal of 1 sec timeout to prevent bug where overlay does not open. We need to find a better solution.

    };
})

.directive('onRightClick',function(){

    document.oncontextmenu = function (e) {
       if(e.target.hasAttribute('on-right-click')) {
           e.preventDefault();
           e.stopPropagation();
           return false;
       }
    };

    return function(scope,el,attrs){
        el.on('contextmenu',function(e){
            e.preventDefault();
            e.stopPropagation();
            scope.$apply(attrs.onRightClick);
            return false;
        });
    };
})

.directive('onDelayedMouseleave', function ($timeout, $parse) {
        return {

            restrict: 'A',

            link: function (scope, element, attrs, ctrl) {
                var active = false;
                var fn = $parse(attrs.onDelayedMouseleave);

                var leave_f = function(event) {
                    var callback = function() {
                        fn(scope, {$event:event});
                    };

                    active = false;
                    $timeout(function(){
                        if(active === false){
                            scope.$apply(callback);
                        }
                    }, 650);
                };

                var enter_f = function(event, args){
                    active = true;
                };

                element.on("mouseleave", leave_f);
                element.on("mouseenter", enter_f);

                //unsub events
                scope.$on("$destroy", function(){
                    element.off("mouseleave", leave_f);
                    element.off("mouseenter", enter_f);
                });
            }
        };
    });
<commit_msg>allow outside click to run when you click links and buttons<commit_after>/**
* @description Utillity directives for key and field events
**/
angular.module('umbraco.directives')

.directive('onKeyup', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onKeyup);
            };
            elm.on("keyup", f);
            scope.$on("$destroy", function(){ elm.off("keyup", f);} );
        }
    };
})

.directive('onKeydown', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onKeydown);
            };
            elm.on("keydown", f);
            scope.$on("$destroy", function(){ elm.off("keydown", f);} );
        }
    };
})

.directive('onBlur', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onBlur);
            };
            elm.on("blur", f);
            scope.$on("$destroy", function(){ elm.off("blur", f);} );
        }
    };
})

.directive('onFocus', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onFocus);
            };
            elm.on("focus", f);
            scope.$on("$destroy", function(){ elm.off("focus", f);} );
        }
    };
})

.directive('onDragEnter', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragEnter);
            };
            elm.on("dragenter", f);
            scope.$on("$destroy", function(){ elm.off("dragenter", f);} );
        }
    };
})

.directive('onDragLeave', function () {
    return function (scope, elm, attrs) {
        var f = function (event) {
            var rect = this.getBoundingClientRect();
            var getXY = function getCursorPosition(event) {
                var x, y;

                if (typeof event.clientX === 'undefined') {
                    // try touch screen
                    x = event.pageX + document.documentElement.scrollLeft;
                    y = event.pageY + document.documentElement.scrollTop;
                } else {
                    x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                    y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
                }

                return { x: x, y : y };
            };

            var e = getXY(event.originalEvent);

            // Check the mouseEvent coordinates are outside of the rectangle
            if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
                scope.$apply(attrs.onDragLeave);
            }
        };

        elm.on("dragleave", f);
        scope.$on("$destroy", function(){ elm.off("dragleave", f);} );
    };
})

.directive('onDragOver', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragOver);
            };
            elm.on("dragover", f);
            scope.$on("$destroy", function(){ elm.off("dragover", f);} );
        }
    };
})

.directive('onDragStart', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragStart);
            };
            elm.on("dragstart", f);
            scope.$on("$destroy", function(){ elm.off("dragstart", f);} );
        }
    };
})

.directive('onDragEnd', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDragEnd);
            };
            elm.on("dragend", f);
            scope.$on("$destroy", function(){ elm.off("dragend", f);} );
        }
    };
})

.directive('onDrop', function () {
    return {
        link: function (scope, elm, attrs) {
            var f = function () {
                scope.$apply(attrs.onDrop);
            };
            elm.on("drop", f);
            scope.$on("$destroy", function(){ elm.off("drop", f);} );
        }
    };
})

.directive('onOutsideClick', function ($timeout) {
    return function (scope, element, attrs) {

        var eventBindings = [];

        function oneTimeClick(event) {
                var el = event.target.nodeName;

                // ignore clicks on new overlay
                var parents = $(event.target).parents(".umb-overlay");
                if(parents.length > 0){
                    return;
                }

                // ignore clicks on dialog from old dialog service
                var oldDialog = $(event.target).parents("#old-dialog-service");
                if (oldDialog.length === 1) {
                    return;
                }

                // ignore clicks in tinyMCE dropdown(floatpanel)
                var floatpanel = $(event.target).closest(".mce-floatpanel");
                if (floatpanel.length === 1) {
                    return;
                }

                //ignore clicks inside this element
                if( $(element).has( $(event.target) ).length > 0 ){
                    return;
                }

                scope.$apply(attrs.onOutsideClick);
        }

        $timeout(function(){

            if ("bindClickOn" in attrs) {

                eventBindings.push(scope.$watch(function() {
                    return attrs.bindClickOn;
                }, function(newValue) {
                    if (newValue === "true") {
                        $(document).on("click", oneTimeClick);
                    } else {
                        $(document).off("click", oneTimeClick);
                    }
                }));

            } else {
                $(document).on("click", oneTimeClick);
            }

            scope.$on("$destroy", function() {
                $(document).off("click", oneTimeClick);

                // unbind watchers
                for (var e in eventBindings) {
                    eventBindings[e]();
                }

            });
        }); // Temp removal of 1 sec timeout to prevent bug where overlay does not open. We need to find a better solution.

    };
})

.directive('onRightClick',function(){

    document.oncontextmenu = function (e) {
       if(e.target.hasAttribute('on-right-click')) {
           e.preventDefault();
           e.stopPropagation();
           return false;
       }
    };

    return function(scope,el,attrs){
        el.on('contextmenu',function(e){
            e.preventDefault();
            e.stopPropagation();
            scope.$apply(attrs.onRightClick);
            return false;
        });
    };
})

.directive('onDelayedMouseleave', function ($timeout, $parse) {
        return {

            restrict: 'A',

            link: function (scope, element, attrs, ctrl) {
                var active = false;
                var fn = $parse(attrs.onDelayedMouseleave);

                var leave_f = function(event) {
                    var callback = function() {
                        fn(scope, {$event:event});
                    };

                    active = false;
                    $timeout(function(){
                        if(active === false){
                            scope.$apply(callback);
                        }
                    }, 650);
                };

                var enter_f = function(event, args){
                    active = true;
                };

                element.on("mouseleave", leave_f);
                element.on("mouseenter", enter_f);

                //unsub events
                scope.$on("$destroy", function(){
                    element.off("mouseleave", leave_f);
                    element.off("mouseenter", enter_f);
                });
            }
        };
    });
<|endoftext|>


<commit_before>/**
@ngdoc directive
@name umbraco.directives.directive:umbPagination
@restrict E
@scope

@description
Use this directive to generate a pagination.

Markup example

        <umb-pagination
            page-number="vm.pagination.pageNumber"
            total-pages="vm.pagination.totalPages"
            on-next="vm.nextPage"
            on-prev="vm.prevPage"
            on-go-to-page="vm.goToPage">
        </umb-pagination>

Controller example

    (function () {
        "use strict";

        function Controller() {

            var vm = this;

            vm.pagination = {
                pageNumber: 1,
                totalPages: 10
            }

            vm.nextPage = nextPage;
            vm.prevPage = prevPage;
            vm.goToPage = goToPage;

            function nextPage(pageNumber) {
                // do magic here
                console.log(pageNumber);
                alert("nextpage");
            }

            function prevPage(pageNumber) {
                // do magic here
                console.log(pageNumber);
                alert("prevpage");
            }

            function goToPage(pageNumber) {
                // do magic here
                console.log(pageNumber);
                alert("go to");
            }

        }

        angular.module("umbraco").controller("My.Controller", Controller);
    })();

@param {number} pageNumber (binding): Current page number.
@param {number} totalPages (binding): The total number of pages.
@param {callback} onNext (binding): Callback method to go to the next page.

The callback returns:

pageNumber: The page number

@param {callback=} onPrev (binding): Callback method to go to the previous page.

The callback returns:

pageNumber: The page number

@param {callback=} onGoToPage (binding): Callback method to go to a specific page.

The callback returns:

pageNumber: The page number

**/

(function() {
   'use strict';

   function PaginationDirective(localizationService) {

      function link(scope, el, attr, ctrl) {

         function activate() {

            scope.pagination = [];

            var i = 0;

            if (scope.totalPages <= 10) {
                for (i = 0; i < scope.totalPages; i++) {
                    scope.pagination.push({
                        val: (i + 1),
                        isActive: scope.pageNumber === (i + 1)
                    });
                }
            }
            else {
                //if there is more than 10 pages, we need to do some fancy bits

                //get the max index to start
                var maxIndex = scope.totalPages - 10;
                //set the start, but it can't be below zero
                var start = Math.max(scope.pageNumber - 5, 0);
                //ensure that it's not too far either
                start = Math.min(maxIndex, start);

                for (i = start; i < (10 + start) ; i++) {
                    scope.pagination.push({
                        val: (i + 1),
                        isActive: scope.pageNumber === (i + 1)
                    });
                }

                //now, if the start is greater than 0 then '1' will not be displayed, so do the elipses thing
                if (start > 0) {
                    scope.pagination.unshift({ name: localizationService.localize("general_first"), val: 1, isActive: false }, {val: "...",isActive: false});
                }

                //same for the end
                if (start < maxIndex) {
                    scope.pagination.push({ val: "...", isActive: false }, { name: localizationService.localize("general_last"), val: scope.totalPages, isActive: false });
                }
            }

         }

         scope.next = function () {
             if (scope.pageNumber < scope.totalPages) {
                 scope.pageNumber++;
                 if (scope.onNext) {
                     scope.onNext(scope.pageNumber);
                 }
                 if (scope.onChange) {
                     scope.onChange({ "pageNumber": scope.pageNumber });
                 }
             }
         };

         scope.prev = function (pageNumber) {
             if (scope.pageNumber > 1) {
                 scope.pageNumber--;
                 if (scope.onPrev) {
                     scope.onPrev(scope.pageNumber);
                 }
                 if (scope.onChange) {
                     scope.onChange({ "pageNumber": scope.pageNumber });
                 }
             }
         };

         scope.goToPage = function (pageNumber) {
             scope.pageNumber = pageNumber + 1;
             if (scope.onGoToPage) {
                 scope.onGoToPage(scope.pageNumber);
             }
             if (scope.onChange) {
                 if (scope.onChange) {
                     scope.onChange({ "pageNumber": scope.pageNumber });
                 }
             }
         };

         var unbindPageNumberWatcher = scope.$watch('pageNumber', function(newValue, oldValue){
            activate();
         });

         scope.$on('$destroy', function(){
           unbindPageNumberWatcher();
         });

         activate();

      }

      var directive = {
         restrict: 'E',
         replace: true,
         templateUrl: 'views/components/umb-pagination.html',
         scope: {
            pageNumber: "=",
            totalPages: "=",
            onNext: "=",
            onPrev: "=",
            onGoToPage: "=",
            onChange: "&"
         },
         link: link
      };

      return directive;

   }

   angular.module('umbraco.directives').directive('umbPagination', PaginationDirective);

})();
<commit_msg>add watchCollection to include totalpages<commit_after>/**
@ngdoc directive
@name umbraco.directives.directive:umbPagination
@restrict E
@scope

@description
Use this directive to generate a pagination.

Markup example

        <umb-pagination
            page-number="vm.pagination.pageNumber"
            total-pages="vm.pagination.totalPages"
            on-next="vm.nextPage"
            on-prev="vm.prevPage"
            on-go-to-page="vm.goToPage">
        </umb-pagination>

Controller example

    (function () {
        "use strict";

        function Controller() {

            var vm = this;

            vm.pagination = {
                pageNumber: 1,
                totalPages: 10
            }

            vm.nextPage = nextPage;
            vm.prevPage = prevPage;
            vm.goToPage = goToPage;

            function nextPage(pageNumber) {
                // do magic here
                console.log(pageNumber);
                alert("nextpage");
            }

            function prevPage(pageNumber) {
                // do magic here
                console.log(pageNumber);
                alert("prevpage");
            }

            function goToPage(pageNumber) {
                // do magic here
                console.log(pageNumber);
                alert("go to");
            }

        }

        angular.module("umbraco").controller("My.Controller", Controller);
    })();

@param {number} pageNumber (binding): Current page number.
@param {number} totalPages (binding): The total number of pages.
@param {callback} onNext (binding): Callback method to go to the next page.

The callback returns:

pageNumber: The page number

@param {callback=} onPrev (binding): Callback method to go to the previous page.

The callback returns:

pageNumber: The page number

@param {callback=} onGoToPage (binding): Callback method to go to a specific page.

The callback returns:

pageNumber: The page number

**/

(function() {
   'use strict';

   function PaginationDirective(localizationService) {

      function link(scope, el, attr, ctrl) {

         function activate() {

            scope.pagination = [];

            var i = 0;

            if (scope.totalPages <= 10) {
                for (i = 0; i < scope.totalPages; i++) {
                    scope.pagination.push({
                        val: (i + 1),
                        isActive: scope.pageNumber === (i + 1)
                    });
                }
            }
            else {
                //if there is more than 10 pages, we need to do some fancy bits

                //get the max index to start
                var maxIndex = scope.totalPages - 10;
                //set the start, but it can't be below zero
                var start = Math.max(scope.pageNumber - 5, 0);
                //ensure that it's not too far either
                start = Math.min(maxIndex, start);

                for (i = start; i < (10 + start) ; i++) {
                    scope.pagination.push({
                        val: (i + 1),
                        isActive: scope.pageNumber === (i + 1)
                    });
                }

                //now, if the start is greater than 0 then '1' will not be displayed, so do the elipses thing
                if (start > 0) {
                    scope.pagination.unshift({ name: localizationService.localize("general_first"), val: 1, isActive: false }, {val: "...",isActive: false});
                }

                //same for the end
                if (start < maxIndex) {
                    scope.pagination.push({ val: "...", isActive: false }, { name: localizationService.localize("general_last"), val: scope.totalPages, isActive: false });
                }
            }

         }

         scope.next = function () {
             if (scope.pageNumber < scope.totalPages) {
                 scope.pageNumber++;
                 if (scope.onNext) {
                     scope.onNext(scope.pageNumber);
                 }
                 if (scope.onChange) {
                     scope.onChange({ "pageNumber": scope.pageNumber });
                 }
             }
         };

         scope.prev = function (pageNumber) {
             if (scope.pageNumber > 1) {
                 scope.pageNumber--;
                 if (scope.onPrev) {
                     scope.onPrev(scope.pageNumber);
                 }
                 if (scope.onChange) {
                     scope.onChange({ "pageNumber": scope.pageNumber });
                 }
             }
         };

         scope.goToPage = function (pageNumber) {
             scope.pageNumber = pageNumber + 1;
             if (scope.onGoToPage) {
                 scope.onGoToPage(scope.pageNumber);
             }
             if (scope.onChange) {
                 if (scope.onChange) {
                     scope.onChange({ "pageNumber": scope.pageNumber });
                 }
             }
         };

         var unbindPageNumberWatcher =  scope.$watchCollection('[pageNumber, totalPages]', function (newValues, oldValues) {
            activate();
         });

         scope.$on('$destroy', function(){
           unbindPageNumberWatcher();
         });

         activate();

      }

      var directive = {
         restrict: 'E',
         replace: true,
         templateUrl: 'views/components/umb-pagination.html',
         scope: {
            pageNumber: "=",
            totalPages: "=",
            onNext: "=",
            onPrev: "=",
            onGoToPage: "=",
            onChange: "&"
         },
         link: link
      };

      return directive;

   }

   angular.module('umbraco.directives').directive('umbPagination', PaginationDirective);

})();
<|endoftext|>


<commit_before>'use strict';

const should = require('chai').should(); // eslint-disable-line

describe('util', () => {
  const util = require('../../lib/util');

  it('getProp()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.getProp(obj, 'a.b').should.eql(obj.a.b);
    util.getProp(obj, 'c').should.eql(obj.c);
    util.getProp(obj, 'd.e.f').should.eql(obj.d.e.f);
  });

  it('getProp() - obj must be an object', () => {
    try {
      util.getProp();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('getProp() - key is required', () => {
    try {
      util.getProp({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('setProp()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.setProp(obj, 'a.b', 10);
    obj.a.b.should.eql(10);

    util.setProp(obj, 'c', 20);
    obj.c.should.eql(20);

    util.setProp(obj, 'd.e.f', 'haha');
    obj.d.e.f.should.eql('haha');
  });

  it('setProp() - obj must be an object', () => {
    try {
      util.setProp();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('setProp() - key is required', () => {
    try {
      util.setProp({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('delProp()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.delProp(obj, 'a.b');
    should.not.exist(obj.a.b);

    util.delProp(obj, 'c');
    should.not.exist(obj.c);

    util.delProp(obj, 'd.e.f');
    should.not.exist(obj.d.e.f);
  });

  it('delProp() - obj must be an object', () => {
    try {
      util.delProp();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('delProp() - key is required', () => {
    try {
      util.delProp({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('setGetter()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.setGetter(obj, 'a.b', () => 100);

    obj.a.b.should.eql(100);

    util.setGetter(obj, 'c', () => 200);

    obj.c.should.eql(200);

    util.setGetter(obj, 'd.e.f', () => 'haha');

    obj.d.e.f.should.eql('haha');

    util.setGetter(obj, 'a.c.h', () => 'ach');

    obj.a.c.h.should.eql('ach');
  });

  it('setGetter() - obj must be an object', () => {
    try {
      util.setGetter();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('setGetter() - key is required', () => {
    try {
      util.setGetter({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('setGetter() - fn must be a function', () => {
    try {
      util.setGetter({}, 'test');
    } catch (err) {
      err.should.have.property('message', 'fn must be a function!');
    }
  });

  it('arr2obj()', () => {
    util.arr2obj(['a', 'b'], 1).should.eql({a: 1, b: 1});
  });

  it('arr2obj() - arr must be an array', () => {
    try {
      util.arr2obj();
    } catch (err) {
      err.should.have.property('message', 'arr must be an array!');
    }
  });

  it('reverse()', () => {
    const arr = [1, '2', 'w'];

    util.reverse(arr).should.eql(['w', '2', 1]);
  });

  it('reverse() - arr must be an array', () => {
    try {
      util.reverse();
    } catch (err) {
      err.should.have.property('message', 'arr must be an array!');
    }
  });

  it('parseArgs() - arr must be an array', () => {
    try {
      util.parseArgs();
    } catch (err) {
      err.should.have.property('message', 'arr must be an array!');
    }
  });

  it('parseArgs()', () => {
    util.parseArgs('name').should.eql({name: 1});
    util.parseArgs('name', -1).should.eql({name: -1});
    util.parseArgs('name -date').should.eql({name: 1, date: -1});
    util.parseArgs('name -date +priority').should.eql({name: 1, date: -1, priority: 1});
  });
});
<commit_msg>add test<commit_after>'use strict';

const should = require('chai').should(); // eslint-disable-line

describe('util', () => {
  const util = require('../../lib/util');

  it('shuffle()', () => {
    const src = Array(100).fill(0).map((_, i) => i);
    const result = util.shuffle(src);

    result.should.not.eql(src);
    result.should.to.have.members(src);
    result.length.should.eql(src.length);

    src.should.eql(Array(100).fill(0).map((_, i) => i));
  });

  it('getProp()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.getProp(obj, 'a.b').should.eql(obj.a.b);
    util.getProp(obj, 'c').should.eql(obj.c);
    util.getProp(obj, 'd.e.f').should.eql(obj.d.e.f);
  });

  it('getProp() - obj must be an object', () => {
    try {
      util.getProp();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('getProp() - key is required', () => {
    try {
      util.getProp({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('setProp()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.setProp(obj, 'a.b', 10);
    obj.a.b.should.eql(10);

    util.setProp(obj, 'c', 20);
    obj.c.should.eql(20);

    util.setProp(obj, 'd.e.f', 'haha');
    obj.d.e.f.should.eql('haha');
  });

  it('setProp() - obj must be an object', () => {
    try {
      util.setProp();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('setProp() - key is required', () => {
    try {
      util.setProp({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('delProp()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.delProp(obj, 'a.b');
    should.not.exist(obj.a.b);

    util.delProp(obj, 'c');
    should.not.exist(obj.c);

    util.delProp(obj, 'd.e.f');
    should.not.exist(obj.d.e.f);
  });

  it('delProp() - obj must be an object', () => {
    try {
      util.delProp();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('delProp() - key is required', () => {
    try {
      util.delProp({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('setGetter()', () => {
    const obj = {
      a: {
        b: 1
      },
      c: 2,
      d: {
        e: {
          f: 'foo'
        }
      }
    };

    util.setGetter(obj, 'a.b', () => 100);

    obj.a.b.should.eql(100);

    util.setGetter(obj, 'c', () => 200);

    obj.c.should.eql(200);

    util.setGetter(obj, 'd.e.f', () => 'haha');

    obj.d.e.f.should.eql('haha');

    util.setGetter(obj, 'a.c.h', () => 'ach');

    obj.a.c.h.should.eql('ach');
  });

  it('setGetter() - obj must be an object', () => {
    try {
      util.setGetter();
    } catch (err) {
      err.should.have.property('message', 'obj must be an object!');
    }
  });

  it('setGetter() - key is required', () => {
    try {
      util.setGetter({});
    } catch (err) {
      err.should.have.property('message', 'key is required!');
    }
  });

  it('setGetter() - fn must be a function', () => {
    try {
      util.setGetter({}, 'test');
    } catch (err) {
      err.should.have.property('message', 'fn must be a function!');
    }
  });

  it('arr2obj()', () => {
    util.arr2obj(['a', 'b'], 1).should.eql({a: 1, b: 1});
  });

  it('arr2obj() - arr must be an array', () => {
    try {
      util.arr2obj();
    } catch (err) {
      err.should.have.property('message', 'arr must be an array!');
    }
  });

  it('reverse()', () => {
    const arr = [1, '2', 'w'];

    util.reverse(arr).should.eql(['w', '2', 1]);
  });

  it('reverse() - arr must be an array', () => {
    try {
      util.reverse();
    } catch (err) {
      err.should.have.property('message', 'arr must be an array!');
    }
  });

  it('parseArgs() - arr must be an array', () => {
    try {
      util.parseArgs();
    } catch (err) {
      err.should.have.property('message', 'arr must be an array!');
    }
  });

  it('parseArgs()', () => {
    util.parseArgs('name').should.eql({name: 1});
    util.parseArgs('name', -1).should.eql({name: -1});
    util.parseArgs('name -date').should.eql({name: 1, date: -1});
    util.parseArgs('name -date +priority').should.eql({name: 1, date: -1, priority: 1});
  });
});
<|endoftext|>


<commit_before>var GRAVITY = 980;
var SINK_SPEED = 10;

/** Player Structure */
function Player(){
  // Location of player
  this.nx = 0;
  this.ny = 0;
  this.w = 48;
  this.h = 24;
  this.speed = 5;
  this.mesh;

  // Physics
  this.jumpt = 0;
  this.yo = 0;
  this.air_t = 0;
  this.jumpTime = .45;
	this.minAirtForInAir = .02;

  // States
  this.alive = true;
  this.jumping = false;
  this.inAir = false;
  this.pass_x = true;
  this.pass_y = true;
  this.in_water = false;
}

/** Initialize player values */
Player.prototype.init = function(level){
  // Make mesh and add it to scene
  var cube = new THREE.Geometry();
  var material = new THREE.MeshPhongMaterial({color: 0xff1818,shininess: 20, metal: true });

  // Make vertices
  cube.vertices.push(new THREE.Vector3(0,0,12));
  cube.vertices.push(new THREE.Vector3(0,0,-12));
  cube.vertices.push(new THREE.Vector3(0,24,12));
  cube.vertices.push(new THREE.Vector3(0,24,-12));
  cube.vertices.push(new THREE.Vector3(48,12,0));

  // Make faces
  cube.faces.push(new THREE.Face3(0,1,4));
  cube.faces.push(new THREE.Face3(1,3,4));
  cube.faces.push(new THREE.Face3(0,4,2));
  cube.faces.push(new THREE.Face3(3,2,4));
  cube.faces.push(new THREE.Face3(0,2,1));
  cube.faces.push(new THREE.Face3(2,3,1));

  this.mesh = new THREE.Mesh(cube, material);
  this.mesh.position.x = level.screen_width/2;
  this.mesh.position.y = level.water_level;
  this.mesh.castShadow = true;
  this.mesh.receiveShadow = true;
  level.scene.add(this.mesh);
}

/** Update player state */
Player.prototype.update = function(level){
  if (this.alive){
    /** Update Location */
    // Grab location
    this.nx = this.mesh.position.x;
    this.ny = this.mesh.position.y;

    // If player is sitting on or above the water
    if (this.ny <= level.water_level- (this.h/2) ){
      this.in_water = false;

      // Update controls
      if (keyboard[KEY_D])
        this.nx += this.speed;
      if (keyboard[KEY_A])
        this.nx -= this.speed;
      if (keyboard[KEY_W]){
        // See if player can jump
        if (!this.jumping && !this.inAir){
          // Set up physics
          this.jumpt = this.jumpTime;
          this.airt = 0;
          this.yo = this.ny;

          // Set states
          this.jumping = true;
          this.inAir = true;
        }
      }

      // Gravity
      if (!this.jumping){
        this.air_t += time_step;
        this.ny = this.yo + (.5 * GRAVITY * (this.air_t * this.air_t));
      }
      // If jumping
      else {
        // This equation must be used to get a smooth jump curve
				this.ny = this.yo 							// Starting loc
						- (.5 * GRAVITY * (this.jumpTime * this.jumpTime)) // Add max jump
						+ (.5 * GRAVITY * (this.jumpt * this.jumpt));		// Minus curve value
				this.jumpt -= time_step;

        if (this.jumpt < 0){
          this.stopJump();
        }
      }
    }
    // If player is below the water
    else if (this.ny > level.water_level- (this.h/2) ){
      this.in_water = true;

      // Update controls
      if (keyboard[KEY_D])
        this.nx += this.speed;
      if (keyboard[KEY_A])
        this.nx -= this.speed;
      if (keyboard[KEY_S])
        this.ny += this.speed;
      if (keyboard[KEY_W])
        this.ny -= this.speed;

      // Water gravity
      this.ny += SINK_SPEED * time_step;
    }

    /** Check collision */
    this.checkCollision(level);

    /** Collision Response */
    this.collisionResponse();
  }
}

/** Check player collision with other obstacles */
Player.prototype.checkCollision = function(level){
  // Reset our checks
  this.pass_x = true;
  this.pass_y = true;

  // Level collision
  if (this.ny + this.h > level.level_bottom()){
    //this.mesh.position.y = level.level_bottom() - this.h;
    this.pass_y = false;
  }
  /*else if (this.ny < level.level_top()){
    //this.mesh.position.y = level.level_top();
    this.pass_y = false;
  }*/

  // Check if the player was above water and lands in it
  if (this.in_water == false && this.ny > level.water_level - (this.h/2)){
    this.hitGround();
  }

  // Block collision checks
  for (var i = 0; i < level.blocks.length; i++){
    // Make sure block is alive and not null
    if (level.blocks[i].active && level.blocks[i].collides){
      // x axis collision check
      if (this.checkBlockX(level.blocks[i])){
        this.pass_x = false;
      }

      // y axis collision check
      if (this.checkBlockY(level.blocks[i])){
        // Might need this
        // this.mesh.position.y = level.blocks[i].y - this.h;

        this.hitGround();
        this.pass_y = false;
      }
    }
  }
}

/** Collision Response code */
Player.prototype.collisionResponse = function(){
  // If locations passed, fix them
  if (this.pass_x)
    this.mesh.position.x = this.nx;

  if (this.pass_y)
    this.mesh.position.y = this.ny;

  // Stop jump if hits wall
  if (!this.pass_y && this.jumping)
    this.stopJump();

  // Air check
  if (this.air_t > this.minAirtForInAir)
    this.inAir = true;

  // Do death checks
  if (this.mesh.position.x + this.w < level.level_left()){
    this.alive = false;
    level.gameover = true;
  }
}

/** Stop player if they are jumping*/
Player.prototype.stopJump = function(){
  this.jumping = false;
  this.air_t = 0;
  this.yo = this.mesh.position.y;
}

/** Call when the player hits the ground **/
Player.prototype.hitGround = function(){
  this.air_t = 0;
  this.yo = this.mesh.position.y;
  this.inAir = false;
  this.jumping = false;
}

/** Check block collision on x axis **/
Player.prototype.checkBlockX = function(block){
  return !((block.y + block.height) < this.mesh.position.y ||
    block.y > (this.mesh.position.y + this.h) ||
    (block.x + block.width) < this.nx ||
    block.x > (this.nx + this.w));
}

/** Check block collision on y axis **/
Player.prototype.checkBlockY = function(block){
  return !((block.y + block.height) < this.ny ||
    block.y > (this.ny + this.h) ||
    (block.x + block.width) < this.mesh.position.x ||
    block.x > (this.mesh.position.x + this.w));
}

/** Check collision on both axis's */
Player.prototype.checkBlockBoth = function(block){
  return !((block.y + block.height) < this.ny ||
    block.y > (this.ny + this.h) ||
    (block.x + block.width) < this.nx ||
    block.x > (this.nx + this.w));
}<commit_msg>Updated collision response code Fixes #30<commit_after>var GRAVITY = 980;
var SINK_SPEED = 10;

/** Player Structure */
function Player(){
  // Location of player
  this.nx = 0;
  this.ny = 0;
  this.w = 48;
  this.h = 24;
  this.speed = 5;
  this.mesh;

  // Physics
  this.jumpt = 0;
  this.yo = 0;
  this.air_t = 0;
  this.jumpTime = .45;
	this.minAirtForInAir = .02;

  // States
  this.alive = true;
  this.jumping = false;
  this.inAir = false;
  this.pass_x = true;
  this.pass_y = true;
  this.in_water = false;
  this.allow_roof_climbing = true;
}

/** Initialize player values */
Player.prototype.init = function(level){
  // Make mesh and add it to scene
  var cube = new THREE.Geometry();
  var material = new THREE.MeshPhongMaterial({color: 0xff1818,shininess: 20, metal: true });

  // Make vertices
  cube.vertices.push(new THREE.Vector3(0,0,12));
  cube.vertices.push(new THREE.Vector3(0,0,-12));
  cube.vertices.push(new THREE.Vector3(0,24,12));
  cube.vertices.push(new THREE.Vector3(0,24,-12));
  cube.vertices.push(new THREE.Vector3(48,12,0));

  // Make faces
  cube.faces.push(new THREE.Face3(0,1,4));
  cube.faces.push(new THREE.Face3(1,3,4));
  cube.faces.push(new THREE.Face3(0,4,2));
  cube.faces.push(new THREE.Face3(3,2,4));
  cube.faces.push(new THREE.Face3(0,2,1));
  cube.faces.push(new THREE.Face3(2,3,1));

  this.mesh = new THREE.Mesh(cube, material);
  this.mesh.position.x = level.screen_width/2;
  this.mesh.position.y = level.water_level;
  this.mesh.castShadow = true;
  this.mesh.receiveShadow = true;
  level.scene.add(this.mesh);
}

/** Update player state */
Player.prototype.update = function(level){
  if (this.alive){
    /** Update Location */
    // Grab location
    this.nx = this.mesh.position.x;
    this.ny = this.mesh.position.y;

    // If player is sitting on or above the water
    if (this.ny <= level.water_level- (this.h/2) ){
      this.in_water = false;

      // Update controls
      if (keyboard[KEY_D])
        this.nx += this.speed;
      if (keyboard[KEY_A])
        this.nx -= this.speed;
      if (keyboard[KEY_W]){
        // See if player can jump
        if (!this.jumping && !this.inAir){
          // Set up physics
          this.jumpt = this.jumpTime;
          this.airt = 0;
          this.yo = this.ny;

          // Set states
          this.jumping = true;
          this.inAir = true;
        }
      }

      // Gravity
      if (!this.jumping){
        this.air_t += time_step;
        this.ny = this.yo + (.5 * GRAVITY * (this.air_t * this.air_t));
      }
      // If jumping
      else {
        // This equation must be used to get a smooth jump curve
				this.ny = this.yo 							// Starting loc
						- (.5 * GRAVITY * (this.jumpTime * this.jumpTime)) // Add max jump
						+ (.5 * GRAVITY * (this.jumpt * this.jumpt));		// Minus curve value
				this.jumpt -= time_step;

        if (this.jumpt < 0){
          this.stopJump();
        }
      }
    }
    // If player is below the water
    else if (this.ny > level.water_level- (this.h/2) ){
      this.in_water = true;

      // Update controls
      if (keyboard[KEY_D])
        this.nx += this.speed;
      if (keyboard[KEY_A])
        this.nx -= this.speed;
      if (keyboard[KEY_S])
        this.ny += this.speed;
      if (keyboard[KEY_W])
        this.ny -= this.speed;

      // Water gravity
      this.ny += SINK_SPEED * time_step;
    }

    /** Check collision */
    this.checkCollision(level);

    /** Collision Response */
    this.collisionResponse();
  }
}

/** Check player collision with other obstacles */
Player.prototype.checkCollision = function(level){
  // Reset our checks
  this.pass_x = true;
  this.pass_y = true;

  // Level collision
  if (this.ny + this.h > level.level_bottom()){
    this.mesh.position.y = level.level_bottom() - this.h;
    this.pass_y = false;
  }
  /*else if (this.ny < level.level_top()){
    //this.mesh.position.y = level.level_top();
    this.pass_y = false;
  }*/

  // Check if the player was above water and lands in it
  if (this.in_water == false && this.ny > level.water_level - (this.h/2)){
    this.hitGround();
  }

  // Block collision checks
  for (var i = 0; i < level.blocks.length; i++){
    // Make sure block is alive and not null
    if (level.blocks[i].active && level.blocks[i].collides){
      // x axis collision check
      if (this.checkBlockX(level.blocks[i]) && this.pass_x){
        // Small collision response
        if (level.blocks[i].x < this.nx)
          this.mesh.position.x = level.blocks[i].x + level.blocks[i].width + .5;
        else if (level.blocks[i].x > this.nx)
          this.mesh.position.x = level.blocks[i].x - this.w - .5;
        // Set collision flag
        this.pass_x = false;
      }

      // y axis collision check
      if (this.checkBlockY(level.blocks[i]) && this.pass_y){
        // Small collision response
        if (level.blocks[i].y < this.ny){
          this.hitCeiling();
          this.mesh.position.y = level.blocks[i].y + level.blocks[i].height + .5;
        }
        else if (level.blocks[i].y > this.ny){
          this.hitGround();
          this.mesh.position.y = level.blocks[i].y - this.h - .5;
        }

        // Set collision flag
        this.pass_y = false;
      }
    }
  }
}

/** Collision Response code */
Player.prototype.collisionResponse = function(){
  // If locations passed, fix them
  if (this.pass_x)
    this.mesh.position.x = this.nx;

  if (this.pass_y)
    this.mesh.position.y = this.ny;

  // Air check
  if (this.air_t > this.minAirtForInAir)
    this.inAir = true;

  // Do death checks
  if (this.mesh.position.x + this.w < level.level_left()){
    this.alive = false;
    level.gameover = true;
  }
}

/** Stop player if they are jumping*/
Player.prototype.stopJump = function(){
  this.jumping = false;
  this.air_t = 0;
  this.yo = this.mesh.position.y;
}

/** Call when the player hits the ground **/
Player.prototype.hitGround = function(){
  this.air_t = 0;
  this.yo = this.mesh.position.y;
  this.inAir = false;
  this.jumping = false;
}

/** Call when the player hits the ceiling **/
Player.prototype.hitCeiling = function(){
  this.air_t = 0;
  this.yo = this.mesh.position.y;
  // If inAir is set false here, player will be able to roof climb.
  // if it is true, they will not.
  this.inAir = !this.allow_roof_climbing;
  this.jumping = false;
}

/** Check block collision on x axis **/
Player.prototype.checkBlockX = function(block){
  return !((block.y + block.height) < this.mesh.position.y ||
    block.y > (this.mesh.position.y + this.h) ||
    (block.x + block.width) < this.nx ||
    block.x > (this.nx + this.w));
}

/** Check block collision on y axis **/
Player.prototype.checkBlockY = function(block){
  return !((block.y + block.height) < this.ny ||
    block.y > (this.ny + this.h) ||
    (block.x + block.width) < this.mesh.position.x ||
    block.x > (this.mesh.position.x + this.w));
}

/** Check collision on both axis's */
Player.prototype.checkBlockBoth = function(block){
  return !((block.y + block.height) < this.ny ||
    block.y > (this.ny + this.h) ||
    (block.x + block.width) < this.nx ||
    block.x > (this.nx + this.w));
}<|endoftext|>