<commit_before>var win1 = Ti.UI.currentWindow;

var utils = require('utils');
var atmos = win1.atmos;
var currentUserId = atmos.currentUserId();
var theme = require('theme');
var themeFGColorMain = theme.colorMain();
var themeFGColorSub = theme.colorSub();
var themeBGColor = theme.backgroundColor(win1.timeline_type);
var themeBGColorLight = theme.backgroundColorLight(win1.timeline_type);

var reloadButton = Ti.UI.createButton({
	systemButton: Titanium.UI.iPhone.SystemButton.REFRESH
});

reloadButton.addEventListener('click', function(e) {
	refreshTimeline();
});
win1.leftNavButton = reloadButton;

function showSendMessageWindow(title, timelineType, replyToMsgId, toUserIds) {
	var messageWindow = Ti.UI.createWindow({
		url: 'message_window.js',
		title: title,
		color: themeFGColorMain,
		backgroundColor: themeBGColor,
		backgroundColorLight: themeBGColorLight,
		layout: 'vertical',
		isPrivate: timelineType === 'private',
		replyToMsgId: replyToMsgId,
		toUserIds: toUserIds,
		atmos: atmos
	});
	Ti.UI.currentTab.open(messageWindow);
}

var messageButton = Ti.UI.createButton({
	systemButton: Titanium.UI.iPhone.SystemButton.ADD
});
messageButton.addEventListener('click', function(e) {
	showSendMessageWindow('new message', win1.timeline_type);
});
win1.rightNavButton = messageButton;

var tableView = Ti.UI.createTableView({
	data: []
});

var latestMessageCreatedAt = undefined;
var oldestMessageCreatedAt = undefined;

function judgeMessageStatus(createdAt) {
	if (latestMessageCreatedAt && createdAt <= latestMessageCreatedAt && oldestMessageCreatedAt && createdAt >= oldestMessageCreatedAt) {
		return 'exists';
	}
	else if (!latestMessageCreatedAt || createdAt > latestMessageCreatedAt) {
		return 'newer';
	}
	else {
		return 'older';
	}
}

function setCreatedAt(createdAt) {
	if (!latestMessageCreatedAt || createdAt > latestMessageCreatedAt) {
		latestMessageCreatedAt = createdAt;
	}
	if (!oldestMessageCreatedAt || createdAt < oldestMessageCreatedAt) {
		oldestMessageCreatedAt = createdAt;
	}
}

var timelineData = [];
var timelineMetaData = {};
function updateTimeline(timeline) {
	var heads = [];
	var tails = [];
	timeline.forEach(function(tlItem, i, a) {
		var createdAtUtc = new Date(tlItem['created_at']);
		var newMessageStatus = judgeMessageStatus(createdAtUtc);
		if (newMessageStatus != 'exists') {
			var row = Ti.UI.createTableViewRow({
				//height: 150,
				height: 'auto',
				layout: 'vertical',
				backgroundColor: themeBGColor
			});

			var imageView = Ti.UI.createImageView({
				image: atmos.getAvatorUrl(tlItem['created_by']),
				width: 48,
				height: 48,
				left: 5,
				top: 5
			});
			row.add(imageView);

			var nameLabel = Ti.UI.createLabel({
				width: 257,
	//			height: 12,
				height: 'auto',
				left: 58,
				top: -48,
				fontSize: 6,
				fontWeight: 'bold',
				color: themeFGColorSub
			});
			nameLabel.text = tlItem['created_by'];
			row.add(nameLabel);

			var commentLabel = Ti.UI.createLabel({
				width: 257,
	//			height: 100,
				height: 'auto',
				left: 58,
				top: 1,
				fontSize: 8,
				color: themeFGColorMain
			});
			commentLabel.text = tlItem.message;
			row.add(commentLabel);

			var dateLabel = Ti.UI.createLabel({
				width: 180,
	//			height: 12,
				height: 'auto',
				right: 0,
				top: 5,
				font: {fontSize: 1},
				color: themeFGColorSub
			});
			//var createdAtUtc = new Date(tlItem['created_at']);
			dateLabel.text = String.formatDate(createdAtUtc, 'medium') + ' ' + String.formatTime(createdAtUtc, 'medium');
			row.add(dateLabel);

			var replyButton = Ti.UI.createButton({
				width: 'auto',
				height: 'auto',
				left: 58,
				top: 2,
				color: themeFGColorSub,
				backgroundImage: 'reply_s.png'
			});
			var replyHandler = (function() {
				var sourceMsgId = tlItem['_id'];
				if (tlItem['to_user_id']) { // for private
					var toUserIds = tlItem['to_user_id'];
				}
				if (tlItem['addresses'] && tlItem['addresses']['users']) {
					var toUserIds = tlItem['addresses']['users'];
				}
				if (toUserIds) {
					var createdBy = tlItem['created_by'];
					var addressesUsers = [];
					toUserIds.forEach(function(userId, i, a) { if (userId !== currentUserId) { addressesUsers.push(userId); } });
					if (createdBy !== currentUserId && addressesUsers.indexOf(createdBy) === -1) {
						addressesUsers.push(createdBy);
					}
				}
				return function(e) {
					var orgMsg = timelineMetaData[sourceMsgId];
					showSendMessageWindow('reply message', win1.timeline_type, orgMsg['_id'], addressesUsers);
				};
			})();
			replyButton.addEventListener('click', replyHandler);
			row.add(replyButton);

			if (newMessageStatus === 'newer') {
				heads.push(row);
			}
			else {
				tails.push(row);
			}

			timelineMetaData[tlItem['_id']] = tlItem;
		}
	});
	timeline.forEach(function(tlItem, i, a) {
		setCreatedAt(new Date(tlItem['created_at']));
	});

	var nextData = heads.concat(timelineData);
	nextData = nextData.concat(tails);
	tableView.setData(nextData);

	timelineData = nextData;
}

// pull to refresh--
function formatDate(){
    var date = new Date;
    var datestr = (date.getMonth() + 1) +'/'+date.getDate()+'/'+date.getFullYear();
    if (date.getHours()>=12){
       datestr+=' '+(date.getHours()==12 ?
          date.getHours() : date.getHours()-12)+':'+
          date.getMinutes()+' PM';
    }
    else{
        datestr+=' '+date.getHours()+':'+date.getMinutes()+' AM';
    }
    return datestr;
}
var pulling = false;
var reloading = false;
var refreshHeaderTheme = theme.pullToRefreshTableHeader(formatDate());
var border = Ti.UI.createView(refreshHeaderTheme.border);
var tableHeader = Ti.UI.createView(refreshHeaderTheme.tableHeader);
tableHeader.add(border);
var arrow = Ti.UI.createView(refreshHeaderTheme.arrow);
var statusLabel = Ti.UI.createLabel(refreshHeaderTheme.statusLabel);
var lastUpdatedLabel = Ti.UI.createLabel(refreshHeaderTheme.lastUpdatedLabel);
var actInd = Titanium.UI.createActivityIndicator(refreshHeaderTheme.actInd);

tableHeader.add(arrow);
tableHeader.add(statusLabel);
tableHeader.add(lastUpdatedLabel);
tableHeader.add(actInd);
tableView.headerPullView = tableHeader;

win1.add(tableView);

tableView.beginReloading = function(){
    refreshTimeline();
};

function endReloading(success){
    tableView.setContentInsets({top:0},{animated:true});
    reloading = false;
    if(success){
        lastUpdatedLabel.text = "Last Updated: "+formatDate();
    }
    statusLabel.text = "Pull down to refresh...";
    actInd.hide();
    arrow.show();
};

tableView.addEventListener('scroll', function(e) {
    var offset = e.contentOffset.y;
    if (offset <= -65.0 && !pulling) {
        var t = Ti.UI.create2DMatrix();
        t = t.rotate(-180);
        pulling = true;
        arrow.animate({
            transform : t,
            duration : 180
        });
        statusLabel.text = "Release to refresh...";
    } else if (pulling && offset > -65.0 && offset < 0) {
        pulling = false;
        var t = Ti.UI.create2DMatrix();
        arrow.animate({
            transform : t,
            duration : 180
        });
        statusLabel.text = "Pull down to refresh...";
    }
});

tableView.addEventListener('dragEnd', function() {
    if (pulling && !reloading) {
        reloading = true;
        pulling = false;
        arrow.hide();
        actInd.show();
        statusLabel.text = "Reloading...";
        tableView.setContentInsets({
            top : 60
        }, {
            animated : true
        });

        tableView.scrollToTop(-60, true);
        arrow.transform = Ti.UI.create2DMatrix();
        tableView.beginReloading();
    }
});
// --pull to refresh

function refreshTimeline() {
	// var atmos = require('atmos');
	var resultApplier = function(e) {
		var resJSON = JSON.parse(e.source.responseText);
		updateTimeline(resJSON.results);
	};

	var options = {};
	if (latestMessageCreatedAt) {
		options['future_than'] = utils.toUtcDateTimeString(latestMessageCreatedAt);
	}
	if (win1.timeline_type === 'global') {
		atmos.getGlobalTimeline(options, resultApplier);
	}
	else if (win1.timeline_type === 'talk') {
		atmos.getTalkTimeline(options, resultApplier);
	}
	else if (win1.timeline_type === 'private') {
		atmos.getPrivateTimeline(options, resultApplier);
	}
    endReloading(true);
}

refreshTimeline();
<commit_msg>limit 20 messages per obtaining timeline, and added read more button.<commit_after>var win1 = Ti.UI.currentWindow;

var maxCount = 20;
var utils = require('utils');
var atmos = win1.atmos;
var currentUserId = atmos.currentUserId();
var theme = require('theme');
var themeFGColorMain = theme.colorMain();
var themeFGColorSub = theme.colorSub();
var themeBGColor = theme.backgroundColor(win1.timeline_type);
var themeBGColorLight = theme.backgroundColorLight(win1.timeline_type);

var reloadButton = Ti.UI.createButton({
	systemButton: Titanium.UI.iPhone.SystemButton.REFRESH
});

reloadButton.addEventListener('click', function(e) {
	refreshTimeline();
});
win1.leftNavButton = reloadButton;

function showSendMessageWindow(title, timelineType, replyToMsgId, toUserIds) {
	var messageWindow = Ti.UI.createWindow({
		url: 'message_window.js',
		title: title,
		color: themeFGColorMain,
		backgroundColor: themeBGColor,
		backgroundColorLight: themeBGColorLight,
		layout: 'vertical',
		isPrivate: timelineType === 'private',
		replyToMsgId: replyToMsgId,
		toUserIds: toUserIds,
		atmos: atmos
	});
	Ti.UI.currentTab.open(messageWindow);
}

var messageButton = Ti.UI.createButton({
	systemButton: Titanium.UI.iPhone.SystemButton.ADD
});
messageButton.addEventListener('click', function(e) {
	showSendMessageWindow('new message', win1.timeline_type);
});
win1.rightNavButton = messageButton;

var tableView = Ti.UI.createTableView({
	data: []
});

var tableFooter = Ti.UI.createView({
	height: '36',
	layout: 'vertical',
	backgroundColor: themeBGColor
});

var readMoreButton = Ti.UI.createButton({
	width: 320,
	height: 'auto',
	left: 0,
	top: 2,
	color: themeFGColorSub,
	backgroundColor: themeBGColorLight,
	title: "read more",
	textAlign: Titanium.UI.TEXT_ALIGNMENT_CENTER
});
readMoreButton.addEventListener('click', readMoreTimeline);
tableFooter.add(readMoreButton);
tableView.footerView = tableFooter;

var latestMessageCreatedAt = undefined;
var oldestMessageCreatedAt = undefined;

function judgeMessageStatus(createdAt) {
	if (latestMessageCreatedAt && createdAt <= latestMessageCreatedAt && oldestMessageCreatedAt && createdAt >= oldestMessageCreatedAt) {
		return 'exists';
	}
	else if (!latestMessageCreatedAt || createdAt > latestMessageCreatedAt) {
		return 'newer';
	}
	else {
		return 'older';
	}
}

function setCreatedAt(createdAt) {
	if (!latestMessageCreatedAt || createdAt > latestMessageCreatedAt) {
		latestMessageCreatedAt = createdAt;
	}
	if (!oldestMessageCreatedAt || createdAt < oldestMessageCreatedAt) {
		oldestMessageCreatedAt = createdAt;
	}
}

var timelineData = [];
var timelineMetaData = {};
function updateTimeline(timeline) {
	var heads = [];
	var tails = [];
	timeline.forEach(function(tlItem, i, a) {
		var createdAtUtc = new Date(tlItem['created_at']);
		var newMessageStatus = judgeMessageStatus(createdAtUtc);
		if (newMessageStatus != 'exists') {
			var row = Ti.UI.createTableViewRow({
				//height: 150,
				height: 'auto',
				layout: 'vertical',
				backgroundColor: themeBGColor
			});

			var imageView = Ti.UI.createImageView({
				image: atmos.getAvatorUrl(tlItem['created_by']),
				width: 48,
				height: 48,
				left: 5,
				top: 5
			});
			row.add(imageView);

			var nameLabel = Ti.UI.createLabel({
				width: 257,
	//			height: 12,
				height: 'auto',
				left: 58,
				top: -48,
				fontSize: 6,
				fontWeight: 'bold',
				color: themeFGColorSub
			});
			nameLabel.text = tlItem['created_by'];
			row.add(nameLabel);

			var commentLabel = Ti.UI.createLabel({
				width: 257,
	//			height: 100,
				height: 'auto',
				left: 58,
				top: 1,
				fontSize: 8,
				color: themeFGColorMain
			});
			commentLabel.text = tlItem.message;
			row.add(commentLabel);

			var dateLabel = Ti.UI.createLabel({
				width: 180,
	//			height: 12,
				height: 'auto',
				right: 0,
				top: 5,
				font: {fontSize: 1},
				color: themeFGColorSub
			});
			//var createdAtUtc = new Date(tlItem['created_at']);
			dateLabel.text = String.formatDate(createdAtUtc, 'medium') + ' ' + String.formatTime(createdAtUtc, 'medium');
			row.add(dateLabel);

			var replyButton = Ti.UI.createButton({
				width: 'auto',
				height: 'auto',
				left: 58,
				top: 2,
				color: themeFGColorSub,
				backgroundImage: 'reply_s.png'
			});
			var replyHandler = (function() {
				var sourceMsgId = tlItem['_id'];
				if (tlItem['to_user_id']) { // for private
					var toUserIds = tlItem['to_user_id'];
				}
				if (tlItem['addresses'] && tlItem['addresses']['users']) {
					var toUserIds = tlItem['addresses']['users'];
				}
				if (toUserIds) {
					var createdBy = tlItem['created_by'];
					var addressesUsers = [];
					toUserIds.forEach(function(userId, i, a) { if (userId !== currentUserId) { addressesUsers.push(userId); } });
					if (createdBy !== currentUserId && addressesUsers.indexOf(createdBy) === -1) {
						addressesUsers.push(createdBy);
					}
				}
				return function(e) {
					var orgMsg = timelineMetaData[sourceMsgId];
					showSendMessageWindow('reply message', win1.timeline_type, orgMsg['_id'], addressesUsers);
				};
			})();
			replyButton.addEventListener('click', replyHandler);
			row.add(replyButton);

			if (newMessageStatus === 'newer') {
				heads.push(row);
			}
			else {
				tails.push(row);
			}

			timelineMetaData[tlItem['_id']] = tlItem;
		}
	});
	timeline.forEach(function(tlItem, i, a) {
		setCreatedAt(new Date(tlItem['created_at']));
	});

	var nextData = heads.concat(timelineData);
	nextData = nextData.concat(tails);
	tableView.setData(nextData);

	timelineData = nextData;
}

// pull to refresh--
function formatDate(){
    var date = new Date;
    var datestr = (date.getMonth() + 1) +'/'+date.getDate()+'/'+date.getFullYear();
    if (date.getHours()>=12){
       datestr+=' '+(date.getHours()==12 ?
          date.getHours() : date.getHours()-12)+':'+
          date.getMinutes()+' PM';
    }
    else{
        datestr+=' '+date.getHours()+':'+date.getMinutes()+' AM';
    }
    return datestr;
}
var pulling = false;
var reloading = false;
var refreshHeaderTheme = theme.pullToRefreshTableHeader(formatDate());
var border = Ti.UI.createView(refreshHeaderTheme.border);
var tableHeader = Ti.UI.createView(refreshHeaderTheme.tableHeader);
tableHeader.add(border);
var arrow = Ti.UI.createView(refreshHeaderTheme.arrow);
var statusLabel = Ti.UI.createLabel(refreshHeaderTheme.statusLabel);
var lastUpdatedLabel = Ti.UI.createLabel(refreshHeaderTheme.lastUpdatedLabel);
var actInd = Titanium.UI.createActivityIndicator(refreshHeaderTheme.actInd);

tableHeader.add(arrow);
tableHeader.add(statusLabel);
tableHeader.add(lastUpdatedLabel);
tableHeader.add(actInd);
tableView.headerPullView = tableHeader;

win1.add(tableView);

tableView.beginReloading = function(){
    refreshTimeline();
};

function endReloading(success){
    tableView.setContentInsets({top:0},{animated:true});
    reloading = false;
    if(success){
        lastUpdatedLabel.text = "Last Updated: "+formatDate();
    }
    statusLabel.text = "Pull down to refresh...";
    actInd.hide();
    arrow.show();
};

tableView.addEventListener('scroll', function(e) {
    var offset = e.contentOffset.y;
    if (offset <= -65.0 && !pulling) {
        var t = Ti.UI.create2DMatrix();
        t = t.rotate(-180);
        pulling = true;
        arrow.animate({
            transform : t,
            duration : 180
        });
        statusLabel.text = "Release to refresh...";
    } else if (pulling && offset > -65.0 && offset < 0) {
        pulling = false;
        var t = Ti.UI.create2DMatrix();
        arrow.animate({
            transform : t,
            duration : 180
        });
        statusLabel.text = "Pull down to refresh...";
    }
});

tableView.addEventListener('dragEnd', function() {
    if (pulling && !reloading) {
        reloading = true;
        pulling = false;
        arrow.hide();
        actInd.show();
        statusLabel.text = "Reloading...";
        tableView.setContentInsets({
            top : 60
        }, {
            animated : true
        });

        tableView.scrollToTop(-60, true);
        arrow.transform = Ti.UI.create2DMatrix();
        tableView.beginReloading();
    }
});
// --pull to refresh

function refreshTimeline() {
	var resultApplier = function(e) {
		var resJSON = JSON.parse(e.source.responseText);
		updateTimeline(resJSON.results);
	};

	var options = {};
	options['count'] = maxCount;
	if (latestMessageCreatedAt) {
		options['future_than'] = utils.toUtcDateTimeString(latestMessageCreatedAt);
	}
	getTimelineRefresher(win1.timeline_type)(options, resultApplier);

    endReloading(true);
}

function readMoreTimeline() {
	var resultApplier = function(e) {
		var resJSON = JSON.parse(e.source.responseText);
		updateTimeline(resJSON.results);
	};

	var options = {};
	options['count'] = maxCount;
	if (oldestMessageCreatedAt) {
		options['past_than'] = utils.toUtcDateTimeString(oldestMessageCreatedAt);
	}
	getTimelineRefresher(win1.timeline_type)(options, resultApplier);
}

function getTimelineRefresher(timelineType) {
	if (timelineType === 'global') {
		return atmos.getGlobalTimeline;
	}
	else if (timelineType === 'talk') {
		return atmos.getTalkTimeline;
	}
	else if (timelineType === 'private') {
		return atmos.getPrivateTimeline;
	}
	else {
		return undefined;
	}
}

refreshTimeline();
<|endoftext|>


<commit_before>/**
 * Base drag class
 *
 * Does all the grunt work for manipulating elements via click-and-drag,
 * while leaving the actual element manipulation up to a subclass.
 */
Garnish.BaseDrag = Garnish.Base.extend({

	// Properties
	// =========================================================================

	$items: null,

	dragging: false,

	mousedownX: null,
	mousedownY: null,
	mouseX: null,
	mouseY: null,
	mouseDistX: null,
	mouseDistY: null,

	$targetItem: null,
	targetItemMouseOffsetX: null,
	targetItemMouseOffsetY: null,

	scrollProperty: null,
	scrollDir: null,
	scrollProxy: null,
	scrollFrame: null,

	_: null,

	// Public methods
	// =========================================================================

	/**
	 * Constructor
	 *
	 * @param mixed  items    Elements that should be draggable right away. (Can be skipped.)
	 * @param object settings Any settings that should override the defaults.
	 */
	init: function(items, settings)
	{
		// Param mapping
		if (!settings && $.isPlainObject(items))
		{
			// (settings)
			settings = items;
			items = null;
		}

		this.settings = $.extend({}, Garnish.BaseDrag.defaults, settings);

		this.$items = $();
		this._ = {};

		if (items)
		{
			this.addItems(items);
		}
	},

	/**
	 * Start Dragging
	 */
	startDragging: function()
	{
		this.dragging = true;
		this.onDragStart();
	},

	/**
	 * Drag
	 */
	drag: function(didMouseMove)
	{
		if (didMouseMove)
		{
			// Is the mouse up against one of the window edges?
			this.drag._scrollProperty = null;

			if (this.settings.axis != Garnish.X_AXIS)
			{
				// Scrolling up?
				this.drag._winScrollTop = Garnish.$win.scrollTop();

				if (this.mouseY < this.drag._winScrollTop + Garnish.BaseDrag.windowScrollTargetSize)
				{
					this.drag._scrollProperty = 'scrollTop';
					this.drag._scrollDir = -1;
				}
				else
				{
					// Scrolling down?
					this.drag._winHeight = Garnish.$win.height();

					if (this.mouseY > this.drag._winScrollTop + this.drag._winHeight - Garnish.BaseDrag.windowScrollTargetSize)
					{
						this.drag._scrollProperty = 'scrollTop';
						this.drag._scrollDir = 1;
					}
				}
			}

			if (!this.drag._scrollProperty && this.settings.axis != Garnish.Y_AXIS)
			{
				// Scrolling left?
				this.drag._winScrollLeft = Garnish.$win.scrollLeft();

				if (this.mouseX < this.drag._winScrollLeft + Garnish.BaseDrag.windowScrollTargetSize)
				{
					this.drag._scrollProperty = 'scrollLeft';
					this.drag._scrollDir = -1;
				}
				else
				{
					// Scrolling right?
					this.drag._winWidth = Garnish.$win.width();

					if (this.mouseX > this.drag._winScrollLeft + this.drag._winWidth - Garnish.BaseDrag.windowScrollTargetSize)
					{
						this.drag._scrollProperty = 'scrollLeft';
						this.drag._scrollDir = 1;
					}
				}
			}

			if (this.drag._scrollProperty)
			{
				// Are we starting to scroll now?
				if (!this.scrollProperty)
				{
					if (!this.scrollProxy)
					{
						this.scrollProxy = $.proxy(this, '_scrollWindow');
					}

					this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);
				}

				this.scrollProperty = this.drag._scrollProperty;
				this.scrollDir = this.drag._scrollDir;
			}
			else
			{
				this._cancelWindowScroll();
			}
		}

		this.onDrag();
	},

	/**
	 * Stop Dragging
	 */
	stopDragging: function()
	{
		this.dragging = false;
		this.onDragStop();

		// Clear the scroll animation
		this._cancelWindowScroll();
	},

	/**
	 * Add Items
	 *
	 * @param mixed items Elements that should be draggable.
	 */
	addItems: function(items)
	{
		items = $.makeArray(items);

		for (var i = 0; i < items.length; i++)
		{
			var item = items[i];

			// Make sure this element doesn't belong to another dragger
			if ($.data(item, 'drag'))
			{
				Garnish.log('Element was added to more than one dragger');
				$.data(item, 'drag').removeItems(item);
			}

			// Add the item
			$.data(item, 'drag', this);

			// Get the handle
			if (this.settings.handle)
			{
				if (typeof this.settings.handle == 'object')
				{
					var $handle = $(this.settings.handle);
				}
				else if (typeof this.settings.handle == 'string')
				{
					var $handle = $(item).find(this.settings.handle);
				}
				else if (typeof this.settings.handle == 'function')
				{
					var $handle = $(this.settings.handle(item));
				}
			}
			else
			{
				var $handle = $(item);
			}

			$.data(item, 'drag-handle', $handle);
			$handle.data('drag-item', item);
			this.addListener($handle, 'mousedown', '_onMouseDown');
		}

		this.$items = $().add(this.$items.add(items));
	},

	/**
	 * Remove Items
	 *
	 * @param mixed items Elements that should no longer be draggable.
	 */
	removeItems: function(items)
	{
		items = $.makeArray(items);

		for (var i = 0; i < items.length; i++)
		{
			var item = items[i];

			// Make sure we actually know about this item
			var index = $.inArray(item, this.$items);
			if (index != -1)
			{
				var $handle = $.data(item, 'drag-handle');
				$handle.data('drag-item', null);
				$.data(item, 'drag', null);
				$.data(item, 'drag-handle', null);
				this.removeAllListeners($handle);
				this.$items.splice(index, 1);
			}
		}
	},

	/**
	 * Remove All Items
	 */
	removeAllItems: function()
	{
		for (var i = 0; i < this.$items.length; i++)
		{
			var item = this.$items[i],
				$handle = $.data(item, 'drag-handle');

			$.data(item, 'drag', null);

			if ($handle)
			{
				$.data(item, 'drag-handle', null);
				$handle.data('drag-item', null);
				this.removeAllListeners($handle);
			}
		}

		this.$items = $();
	},

	// Events
	// -------------------------------------------------------------------------

	/**
	 * On Drag Start
	 */
	onDragStart: function()
	{
		Garnish.requestAnimationFrame($.proxy(function()
		{
			this.trigger('dragStart');
			this.settings.onDragStart();
		}, this));
	},

	/**
	 * On Drag
	 */
	onDrag: function()
	{
		Garnish.requestAnimationFrame($.proxy(function()
		{
			this.trigger('drag');
			this.settings.onDrag();
		}, this));
	},

	/**
	 * On Drag Stop
	 */
	onDragStop: function()
	{
		Garnish.requestAnimationFrame($.proxy(function()
		{
			this.trigger('dragStop');
			this.settings.onDragStop();
		}, this));
	},

	// Private methods
	// =========================================================================

	/**
	 * On Mouse Down
	 */
	_onMouseDown: function(ev)
	{
		// Ignore right clicks
		if (ev.which != Garnish.PRIMARY_CLICK)
		{
			return;
		}

		// Ignore if we already have a target
		if (this.$targetItem)
		{
			return;
		}

		// Make sure the target isn't a button (unless the button is the handle)
		if (ev.currentTarget != ev.target && this.settings.ignoreHandleSelector)
		{
			var $target = $(ev.target);

			if (
				$target.is(this.settings.ignoreHandleSelector) ||
				$target.closest(this.settings.ignoreHandleSelector).length
			)
			{
				return;
			}
		}

		ev.preventDefault();

		// Capture the target
		this.$targetItem = $($.data(ev.currentTarget, 'drag-item'));

		// Capture the current mouse position
		this.mousedownX = this.mouseX = ev.pageX;
		this.mousedownY = this.mouseY = ev.pageY;

		// Capture the difference between the mouse position and the target item's offset
		var offset = this.$targetItem.offset();
		this.targetItemMouseOffsetX = offset.left - ev.pageX;
		this.targetItemMouseOffsetY = offset.top - ev.pageY;

		// Listen for mousemove, mouseup
		this.addListener(Garnish.$doc, 'mousemove', '_onMouseMove');
		this.addListener(Garnish.$doc, 'mouseup', '_onMouseUp');
	},

	/**
	 * On Mouse Move
	 */
	_onMouseMove: function(ev)
	{
		ev.preventDefault();

		if (this.settings.axis != Garnish.Y_AXIS)
		{
			this.mouseX = ev.pageX;
		}

		if (this.settings.axis != Garnish.X_AXIS)
		{
			this.mouseY = ev.pageY;
		}

		this.mouseDistX = this.mouseX - this.mousedownX;
		this.mouseDistY = this.mouseY - this.mousedownY;

		if (!this.dragging)
		{
			// Has the mouse moved far enough to initiate dragging yet?
			this._onMouseMove._mouseDist = Garnish.getDist(this.mousedownX, this.mousedownY, this.mouseX, this.mouseY);

			if (this._onMouseMove._mouseDist >= Garnish.BaseDrag.minMouseDist)
			{
				this.startDragging();
			}
		}

		if (this.dragging)
		{
			this.drag(true);
		}
	},

	/**
	 * On Moues Up
	 */
	_onMouseUp: function(ev)
	{
		// Unbind the document events
		this.removeAllListeners(Garnish.$doc);

		if (this.dragging)
		{
			this.stopDragging();
		}

		this.$targetItem = null;
	},

	/**
	 * Scroll Window
	 */
	_scrollWindow: function()
	{
		this._.scrollPos = Garnish.$win[this.scrollProperty]();
		Garnish.$win[this.scrollProperty](this._.scrollPos + this.scrollDir * 3);

		this.mouseY -= this._.scrollPos - Garnish.$win[this.scrollProperty]()

		this.drag();
	},

	/**
	 * Cancel Window Scroll
	 */
	_cancelWindowScroll: function()
	{
		if (this.scrollFrame)
		{
			Garnish.cancelAnimationFrame(this.scrollFrame);
			this.scrollFrame = null;
		}

		this.scrollProperty = null;
		this.scrollDir = null;
	}
},

// Static Properties
// =============================================================================

{
	minMouseDist: 1,
	windowScrollTargetSize: 20,

	defaults: {
		handle: null,
		axis: null,
		ignoreHandleSelector: 'input, textarea, button, select, .btn',

		onDragStart: $.noop,
		onDrag:      $.noop,
		onDragStop:  $.noop
	}
});
<commit_msg>Store the real mouse position, and use that to determine if dragging has started<commit_after>/**
 * Base drag class
 *
 * Does all the grunt work for manipulating elements via click-and-drag,
 * while leaving the actual element manipulation up to a subclass.
 */
Garnish.BaseDrag = Garnish.Base.extend({

	// Properties
	// =========================================================================

	$items: null,

	dragging: false,

	mousedownX: null,
	mousedownY: null,
	realMouseX: null,
	realMouseY: null,
	mouseX: null,
	mouseY: null,
	mouseDistX: null,
	mouseDistY: null,

	$targetItem: null,
	targetItemMouseOffsetX: null,
	targetItemMouseOffsetY: null,

	scrollProperty: null,
	scrollDir: null,
	scrollProxy: null,
	scrollFrame: null,

	_: null,

	// Public methods
	// =========================================================================

	/**
	 * Constructor
	 *
	 * @param mixed  items    Elements that should be draggable right away. (Can be skipped.)
	 * @param object settings Any settings that should override the defaults.
	 */
	init: function(items, settings)
	{
		// Param mapping
		if (!settings && $.isPlainObject(items))
		{
			// (settings)
			settings = items;
			items = null;
		}

		this.settings = $.extend({}, Garnish.BaseDrag.defaults, settings);

		this.$items = $();
		this._ = {};

		if (items)
		{
			this.addItems(items);
		}
	},

	/**
	 * Start Dragging
	 */
	startDragging: function()
	{
		this.dragging = true;
		this.onDragStart();
	},

	/**
	 * Drag
	 */
	drag: function(didMouseMove)
	{
		if (didMouseMove)
		{
			// Is the mouse up against one of the window edges?
			this.drag._scrollProperty = null;

			if (this.settings.axis != Garnish.X_AXIS)
			{
				// Scrolling up?
				this.drag._winScrollTop = Garnish.$win.scrollTop();

				if (this.mouseY < this.drag._winScrollTop + Garnish.BaseDrag.windowScrollTargetSize)
				{
					this.drag._scrollProperty = 'scrollTop';
					this.drag._scrollDir = -1;
				}
				else
				{
					// Scrolling down?
					this.drag._winHeight = Garnish.$win.height();

					if (this.mouseY > this.drag._winScrollTop + this.drag._winHeight - Garnish.BaseDrag.windowScrollTargetSize)
					{
						this.drag._scrollProperty = 'scrollTop';
						this.drag._scrollDir = 1;
					}
				}
			}

			if (!this.drag._scrollProperty && this.settings.axis != Garnish.Y_AXIS)
			{
				// Scrolling left?
				this.drag._winScrollLeft = Garnish.$win.scrollLeft();

				if (this.mouseX < this.drag._winScrollLeft + Garnish.BaseDrag.windowScrollTargetSize)
				{
					this.drag._scrollProperty = 'scrollLeft';
					this.drag._scrollDir = -1;
				}
				else
				{
					// Scrolling right?
					this.drag._winWidth = Garnish.$win.width();

					if (this.mouseX > this.drag._winScrollLeft + this.drag._winWidth - Garnish.BaseDrag.windowScrollTargetSize)
					{
						this.drag._scrollProperty = 'scrollLeft';
						this.drag._scrollDir = 1;
					}
				}
			}

			if (this.drag._scrollProperty)
			{
				// Are we starting to scroll now?
				if (!this.scrollProperty)
				{
					if (!this.scrollProxy)
					{
						this.scrollProxy = $.proxy(this, '_scrollWindow');
					}

					this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);
				}

				this.scrollProperty = this.drag._scrollProperty;
				this.scrollDir = this.drag._scrollDir;
			}
			else
			{
				this._cancelWindowScroll();
			}
		}

		this.onDrag();
	},

	/**
	 * Stop Dragging
	 */
	stopDragging: function()
	{
		this.dragging = false;
		this.onDragStop();

		// Clear the scroll animation
		this._cancelWindowScroll();
	},

	/**
	 * Add Items
	 *
	 * @param mixed items Elements that should be draggable.
	 */
	addItems: function(items)
	{
		items = $.makeArray(items);

		for (var i = 0; i < items.length; i++)
		{
			var item = items[i];

			// Make sure this element doesn't belong to another dragger
			if ($.data(item, 'drag'))
			{
				Garnish.log('Element was added to more than one dragger');
				$.data(item, 'drag').removeItems(item);
			}

			// Add the item
			$.data(item, 'drag', this);

			// Get the handle
			if (this.settings.handle)
			{
				if (typeof this.settings.handle == 'object')
				{
					var $handle = $(this.settings.handle);
				}
				else if (typeof this.settings.handle == 'string')
				{
					var $handle = $(item).find(this.settings.handle);
				}
				else if (typeof this.settings.handle == 'function')
				{
					var $handle = $(this.settings.handle(item));
				}
			}
			else
			{
				var $handle = $(item);
			}

			$.data(item, 'drag-handle', $handle);
			$handle.data('drag-item', item);
			this.addListener($handle, 'mousedown', '_onMouseDown');
		}

		this.$items = $().add(this.$items.add(items));
	},

	/**
	 * Remove Items
	 *
	 * @param mixed items Elements that should no longer be draggable.
	 */
	removeItems: function(items)
	{
		items = $.makeArray(items);

		for (var i = 0; i < items.length; i++)
		{
			var item = items[i];

			// Make sure we actually know about this item
			var index = $.inArray(item, this.$items);
			if (index != -1)
			{
				var $handle = $.data(item, 'drag-handle');
				$handle.data('drag-item', null);
				$.data(item, 'drag', null);
				$.data(item, 'drag-handle', null);
				this.removeAllListeners($handle);
				this.$items.splice(index, 1);
			}
		}
	},

	/**
	 * Remove All Items
	 */
	removeAllItems: function()
	{
		for (var i = 0; i < this.$items.length; i++)
		{
			var item = this.$items[i],
				$handle = $.data(item, 'drag-handle');

			$.data(item, 'drag', null);

			if ($handle)
			{
				$.data(item, 'drag-handle', null);
				$handle.data('drag-item', null);
				this.removeAllListeners($handle);
			}
		}

		this.$items = $();
	},

	// Events
	// -------------------------------------------------------------------------

	/**
	 * On Drag Start
	 */
	onDragStart: function()
	{
		Garnish.requestAnimationFrame($.proxy(function()
		{
			this.trigger('dragStart');
			this.settings.onDragStart();
		}, this));
	},

	/**
	 * On Drag
	 */
	onDrag: function()
	{
		Garnish.requestAnimationFrame($.proxy(function()
		{
			this.trigger('drag');
			this.settings.onDrag();
		}, this));
	},

	/**
	 * On Drag Stop
	 */
	onDragStop: function()
	{
		Garnish.requestAnimationFrame($.proxy(function()
		{
			this.trigger('dragStop');
			this.settings.onDragStop();
		}, this));
	},

	// Private methods
	// =========================================================================

	/**
	 * On Mouse Down
	 */
	_onMouseDown: function(ev)
	{
		// Ignore right clicks
		if (ev.which != Garnish.PRIMARY_CLICK)
		{
			return;
		}

		// Ignore if we already have a target
		if (this.$targetItem)
		{
			return;
		}

		// Make sure the target isn't a button (unless the button is the handle)
		if (ev.currentTarget != ev.target && this.settings.ignoreHandleSelector)
		{
			var $target = $(ev.target);

			if (
				$target.is(this.settings.ignoreHandleSelector) ||
				$target.closest(this.settings.ignoreHandleSelector).length
			)
			{
				return;
			}
		}

		ev.preventDefault();

		// Capture the target
		this.$targetItem = $($.data(ev.currentTarget, 'drag-item'));

		// Capture the current mouse position
		this.mousedownX = this.mouseX = ev.pageX;
		this.mousedownY = this.mouseY = ev.pageY;

		// Capture the difference between the mouse position and the target item's offset
		var offset = this.$targetItem.offset();
		this.targetItemMouseOffsetX = offset.left - ev.pageX;
		this.targetItemMouseOffsetY = offset.top - ev.pageY;

		// Listen for mousemove, mouseup
		this.addListener(Garnish.$doc, 'mousemove', '_onMouseMove');
		this.addListener(Garnish.$doc, 'mouseup', '_onMouseUp');
	},

	/**
	 * On Mouse Move
	 */
	_onMouseMove: function(ev)
	{
		ev.preventDefault();

		this.realMouseX = ev.pageX;
		this.realMouseY = ev.pageY;

		if (this.settings.axis != Garnish.Y_AXIS)
		{
			this.mouseX = ev.pageX;
		}

		if (this.settings.axis != Garnish.X_AXIS)
		{
			this.mouseY = ev.pageY;
		}

		this.mouseDistX = this.mouseX - this.mousedownX;
		this.mouseDistY = this.mouseY - this.mousedownY;

		if (!this.dragging)
		{
			// Has the mouse moved far enough to initiate dragging yet?
			this._onMouseMove._mouseDist = Garnish.getDist(this.mousedownX, this.mousedownY, this.realMouseX, this.realMouseY);

			if (this._onMouseMove._mouseDist >= Garnish.BaseDrag.minMouseDist)
			{
				this.startDragging();
			}
		}

		if (this.dragging)
		{
			this.drag(true);
		}
	},

	/**
	 * On Moues Up
	 */
	_onMouseUp: function(ev)
	{
		// Unbind the document events
		this.removeAllListeners(Garnish.$doc);

		if (this.dragging)
		{
			this.stopDragging();
		}

		this.$targetItem = null;
	},

	/**
	 * Scroll Window
	 */
	_scrollWindow: function()
	{
		this._.scrollPos = Garnish.$win[this.scrollProperty]();
		Garnish.$win[this.scrollProperty](this._.scrollPos + this.scrollDir * 3);

		this.mouseY -= this._.scrollPos - Garnish.$win[this.scrollProperty]()

		this.drag();
	},

	/**
	 * Cancel Window Scroll
	 */
	_cancelWindowScroll: function()
	{
		if (this.scrollFrame)
		{
			Garnish.cancelAnimationFrame(this.scrollFrame);
			this.scrollFrame = null;
		}

		this.scrollProperty = null;
		this.scrollDir = null;
	}
},

// Static Properties
// =============================================================================

{
	minMouseDist: 1,
	windowScrollTargetSize: 20,

	defaults: {
		handle: null,
		axis: null,
		ignoreHandleSelector: 'input, textarea, button, select, .btn',

		onDragStart: $.noop,
		onDrag:      $.noop,
		onDragStop:  $.noop
	}
});
<|endoftext|>


<commit_before>Vps.Auto.Filter.Text = function(config)
{
    Vps.Auto.Filter.Text.superclass.constructor.call(this, config);

    this.textField = new Ext.form.TriggerField({
        width:config.width,
        triggerClass:'x-form-clear-trigger',
        onTriggerClick: this.clear.createDelegate(this)
    });
    this.paramName = config.paramName;
    this.textField.on('render', function() {
        // TODO:
        // event darf nicht "keypress" sein, da sonst zB backspace und del tasten
        // nicht funktionieren. Was jetzt noch das Problem ist: Was ist wenn man
        // per rechter Maustaste etwas einfügt? Man müsste sich merken was drin
        // steht und bei allen events prüfen ob was daherkommt...
        this.textField.getEl().on('keyup', function() {
            this.fireEvent('filter', this, this.getParams());
        }, this, {buffer: 500});
    }, this);
    this.toolbarItems.add(this.textField);
};

Ext.extend(Vps.Auto.Filter.Text, Vps.Auto.Filter.Abstract, {
	clear: function()
	{
        if (this.textField.getValue()) {
            this.textField.setValue('');
            this.fireEvent('filter', this, this.getParams());
        }
	},

    reset: function() {
        this.textField.reset();
    },
    getParams: function() {
        var params = {};
        params[this.paramName] = this.textField.getValue();
        return params;
    },
    setValue: function(v) {
        this.textField.setValue(v);
        this.fireEvent('filter', this, this.getParams());
    }
});
<commit_msg>min length fuer text filter moeglich<commit_after>Vps.Auto.Filter.Text = function(config)
{
    Vps.Auto.Filter.Text.superclass.constructor.call(this, config);

    this.textField = new Ext.form.TriggerField({
        width:config.width,
        triggerClass:'x-form-clear-trigger',
        onTriggerClick: this.clear.createDelegate(this)
    });
    this.paramName = config.paramName;
    if (config.minLength) this.minLength = config.minLength;
    this.textField.on('render', function() {
        // TODO:
        // event darf nicht "keypress" sein, da sonst zB backspace und del tasten
        // nicht funktionieren. Was jetzt noch das Problem ist: Was ist wenn man
        // per rechter Maustaste etwas einfügt? Man müsste sich merken was drin
        // steht und bei allen events prüfen ob was daherkommt...
        this.textField.getEl().on('keyup', function() {
            if (!this.minLength) {
                this.fireEvent('filter', this, this.getParams());
            } else if (this.textField.getValue().length == 0 || this.textField.getValue().length >= this.minLength) {
                this.fireEvent('filter', this, this.getParams());
            }
        }, this, {buffer: 500});
    }, this);
    this.toolbarItems.add(this.textField);
};

Ext.extend(Vps.Auto.Filter.Text, Vps.Auto.Filter.Abstract, {
	clear: function()
	{
        if (this.textField.getValue()) {
            this.textField.setValue('');
            this.fireEvent('filter', this, this.getParams());
        }
	},

    reset: function() {
        this.textField.reset();
    },
    getParams: function() {
        var params = {};
        params[this.paramName] = this.textField.getValue();
        return params;
    },
    setValue: function(v) {
        this.textField.setValue(v);
        this.fireEvent('filter', this, this.getParams());
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    testBasic: {
        test: function(component) {
            // Add content to rubberbandingBecauseMissingRefresh to trigger
            // rubber banding
            var rubberbandingBecauseMissingRefresh = component
                    .find("rubberbandingBecauseMissingRefresh");
            var child = document.createElement('div');
            child.innerHTML = 'Some silly value';
            rubberbandingBecauseMissingRefresh.find('scrollContent').getElement().appendChild(child);

            var errors = $A.componentService.getDef('markup://ui:scroller').getHelper().validateScrollers();
            $A.test.assertEquals(2, errors.length);

            $A.test.assertTrue(errors[0].indexOf('Scroller instance was not created') > -1);
            $A.test.assertTrue(errors[1].indexOf('Rubberbanding detected: actual content height does not match cached height') > -1);
        }
    },

    testDynamicImages : {
        test: [function(component) {
            // Update an image tag in the scrolled content to insure that this
            // does not cause a problem
            var imageToChange = component.find("dynamicImage").getElement();

            var imageLoaded;
            $A.util.on(imageToChange, "load", function() {
                // Give the scroller image update detection code time to run since there is a 400ms callback timeout
                setTimeout(function() {
                    imageLoaded = true;
                }, 1000);
            });

            $A.test.addWaitFor(true, function(){
                return imageLoaded;
            });

            imageToChange.src = "/auraFW/resources/img/msg_icons/warning32.png";
        },

        function(component) {
            var errors = $A.componentService.getDef('markup://ui:scroller').getHelper().validateScrollers();
            $A.test.assertEquals(1, errors.length);
            $A.test.assertTrue(errors[0].indexOf('Scroller instance was not created') > -1);
        }]
    },

    testPullToRefreshDiv: {
        test: function(component) {
            // Make sure the "pull to refresh" div exists at the top of the scroll contents
            var pullDownDiv = $A.test.getElementByClass("pullToRefresh");
            $A.test.assertNotNull(pullDownDiv, "There should be a 'pullToRefresh' div");
            var scroller = component.find("pullToRefresh");
            $A.test.assertTrue(scroller._scroller.options.topOffset > 0, "Scroller should have a top offset");
        }
    }
})
<commit_msg>Add more debugging to test failures. @rev esalman@later @bug W-1410432@<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    testBasic: {
        test: function(component) {
            // Add content to rubberbandingBecauseMissingRefresh to trigger
            // rubber banding
            var rubberbandingBecauseMissingRefresh = component
                    .find("rubberbandingBecauseMissingRefresh");
            var child = document.createElement('div');
            child.innerHTML = 'Some silly value';
            rubberbandingBecauseMissingRefresh.find('scrollContent').getElement().appendChild(child);

            var errors = $A.componentService.getDef('markup://ui:scroller').getHelper().validateScrollers();
            $A.test.assertEquals(2, errors.length, this.getErrorMsgs(errors));

            $A.test.assertTrue(errors[0].indexOf('Scroller instance was not created') > -1);
            $A.test.assertTrue(errors[1].indexOf('Rubberbanding detected: actual content height does not match cached height') > -1);
        }
    },

    testDynamicImages : {
        test: [function(component) {
            // Update an image tag in the scrolled content to insure that this
            // does not cause a problem
            var imageToChange = component.find("dynamicImage").getElement();

            var imageLoaded;
            $A.util.on(imageToChange, "load", function() {
                // Give the scroller image update detection code time to run since there is a 400ms callback timeout
                setTimeout(function() {
                    imageLoaded = true;
                }, 1000);
            });

            $A.test.addWaitFor(true, function(){
                return imageLoaded;
            });

            imageToChange.src = "/auraFW/resources/img/msg_icons/warning32.png";
        },

        function(component) {
            var errors = $A.componentService.getDef('markup://ui:scroller').getHelper().validateScrollers();
            $A.test.assertEquals(1, errors.length, this.getErrorMsgs(errors));
            $A.test.assertTrue(errors[0].indexOf('Scroller instance was not created') > -1);
        }]
    },

    testPullToRefreshDiv: {
        test: function(component) {
            // Make sure the "pull to refresh" div exists at the top of the scroll contents
            var pullDownDiv = $A.test.getElementByClass("pullToRefresh");
            $A.test.assertNotNull(pullDownDiv, "There should be a 'pullToRefresh' div");
            var scroller = component.find("pullToRefresh");
            $A.test.assertTrue(scroller._scroller.options.topOffset > 0, "Scroller should have a top offset");
        }
    },

    getErrorMsgs : function(errorsArray) {
    	var errMsgs = "";
        if (errorsArray) {
        	for (var i=0; i<errorsArray.length; i++) {
        		errMsgs+="ERROR["+i+"]"+errorsArray[i]+"\n";
        	}
        }
        return errMsgs;
    }
})
<|endoftext|>


<commit_before>/* global $ */
/* global CollapsibleLists */
import {ObjectViewer} from "../utils/object-viewer";
import $ from 'jquery';
import {resizable} from 'jquery-ui';

@customElement('pastebin')
export class ExpressionDataExplorer{
  editorTooltipSelector = "#editorTooltip";
  editorTooltipId = "editorTooltip";
  editorTooltipContentId = "editorTooltipContent";
  treeViewId = "treeViewContent";
  viewportSelector = "#codeContent .ace_scroller";
  viewportPadding = -6;
  editorTooltipShowDelay = 750;
  editorTooltipHideDelay = 750;
  content = "";

  constructor(eventAggregator, aceUtils, aureliaEditor, traceViewModel){
    this.eventAggregator = eventAggregator;
    this.aceUtils = aceUtils;
    this.aureliaEditor = aureliaEditor;
    this.traceViewModel = traceViewModel;
  }

  attached(){
    let self = this;
    let eventAggregator = this.eventAggregator;
    let aceUtils = this.aceUtils;
    let editor = this.aureliaEditor.editor;
    this.expressionMarkerManager = aceUtils.makeAceMarkerManager(editor);
    this.errorMarkerManager = aceUtils.makeAceMarkerManager(editor);
    this.logMarkerManager = aceUtils.makeAceMarkerManager(editor);
    this.expressionMarkerManager.markerRenderer = aceUtils.getAvailableMarkers().expressionMarker;
    this.errorMarkerManager.markerRenderer = aceUtils.getAvailableMarkers().errorMarker;
    this.logMarkerManager.markerRenderer = aceUtils.getAvailableMarkers().logMarker;

    let $editor = $(editor.renderer.getContainerElement());
    $editor.mouseleave(function aceEditorMouseleave(){
      eventAggregator.publish("expressionHovered");
    });

    let $editorTooltip = $(this.editorTooltipSelector);

    if(!$editorTooltip.length){
      $editorTooltip = $(`<div id='${this.editorTooltipId}' />`);
      $editorTooltip.attr({
        "data-toggle": "popover",
        "data-placement": "auto",
        "data-content": "No value found."
      });
      $editorTooltip.popover({
        viewport: {selector: this.viewportSelector, padding: this.viewportPadding},
        html: true,
        trigger: 'manual',
        template: '

'
      });
    }

    $editorTooltip.appendTo('body');
    $editorTooltip.on('inserted.bs.popover', function(){
      let $popoverContentTreeViewContent = $("#" + self.editorTooltipContentId);
      $popoverContentTreeViewContent.html("");
      $popoverContentTreeViewContent.append(self.title);
      $popoverContentTreeViewContent.append(self.content);
      self.title = "";
      self.content = "";
      CollapsibleLists.apply();
      $('[data-toggle="tooltip"]').tooltip();
    });

    $editorTooltip.on('shown.bs.popover', function () {
      let $popoverContentTreeViewContainer = $("#" + $(this).attr("aria-describedby"));
      $popoverContentTreeViewContainer.resizable({
        handles: "n, e, s, w"
      });

    });

    this.$editorTooltip = $editorTooltip;
    aceUtils.subscribeToExpressionHoverEvents(editor, eventAggregator, this);
    this.attachTooltipUpdate();
    this.subscribe();
  }

  decoratePopoverContentElement($popoverContentElement){
    if(!this.elementDecorator){
      return;
    }

    if(this.this.isShowToolTipEvent){
      this.elementDecorator.$decorate();
    }else{
      if(this.elementDecorator.$undecorate){
        this.elementDecorator.$undecorate();
      }
    }
  }

  attachTooltipUpdate(){
    let self = this;
    let $editorTooltip =   this.$editorTooltip;
    let aceUtils = this.aceUtils;

    this.update$Tooltip = function update$Tooltip(position, match, dimensions) {
      if(!$editorTooltip){
        return;
      }

		    if(position){
		        $editorTooltip.css({
		            position: "absolute",
		            marginLeft: 0,
		            marginTop: 0,
		            top: `${position.pageY}px`,
              left: `${position.pageX}px`,
              width: `${dimensions.width}`,
              height: `${dimensions.height}`
              ,
              "z-index": -1000

		        });
		    }

      if(match && !self.isBranchNavigatorVisible){
        self.currentObjectViewer = new ObjectViewer(match.value, self.treeViewId);
        let popoverData = self.currentObjectViewer.generatePopoverTreeViewContent();
        let popoverTitle = `<strong>${match.id !== null ? match.id : ""} :</strong> <i>${self.currentObjectViewer.classType}</i>`;
        // $editorTooltip.attr("data-content", `<div class="custom-popover-title">${popoverTitle}</div>${popoverData.content}`);
        $editorTooltip.attr("data-content", "");
        self.title = `<div class="custom-popover-title">${popoverTitle}</div>`;
        self.content = popoverData.content;
        $editorTooltip.popover("show");
        aceUtils.updateAceMarkers(self.expressionMarkerManager, [match]);
      }else{
        self.$hideTooltip();
      }
      // let $popoverContentElement = $("#"+self.editorTooltipContentId);
      let $popoverContentTreeViewContainer = $("#" + $(self.editorTooltipId).attr("aria-describedby"));
      $popoverContentTreeViewContainer.mouseenter(
        function editorTooltipMouseenter(){
          clearTimeout(self.onExpressionHoveredTimeout);
          clearTimeout(self.editorTooltiptimeout);
        }
      ).mouseleave(
        function editorTooltipMouseleave(){
          self.editorTooltiptimeout = setTimeout(function editorTooltiptimeout(){
            self.$hideTooltip();
          }, self.editorTooltipHideDelay);
        }
      );
      self.decoratePopoverContentElement($popoverContentTreeViewContainer);
    };
  }

  handleIndexInTimeline(indexInTimeline){
    if( indexInTimeline === null){
      return;
    }

    if(!this.traceViewModel.traceHelper){
      return;
    }

    let timeline  = this.traceViewModel.traceHelper.getTimeline();
    if(!timeline){
      return;
    }

    let match =  timeline[indexInTimeline];
    if(match){
      this.traceViewModel.branchModel.getNavigationStackBlockCountsByIndexInTimeline(indexInTimeline);
      this.eventAggregator.publish("expressionHovered", match);
    }
  }

  $showTooltip(match){
    match.id = "console.log";
    this.eventAggregator.publish("expressionHovered", match);
  }

  $hideTooltip(){
    let $popoverContentElement = $("#"+this.editorTooltipContentId);
    if(this.$editorTooltip && $popoverContentElement.length  && !$popoverContentElement.is(":hover")){
      this.content = "";
      this.$editorTooltip.popover("hide");
      this.aceUtils.updateAceMarkers(this.expressionMarkerManager, []);
      clearTimeout(this.onExpressionHoveredTimeout);
      clearTimeout(this.editorTooltiptimeout);
    }
  }

  $showError(data){
    this.aceUtils.updateAceMarkers(this.errorMarkerManager, [data]);
  }

  $hideError(causeRange){
    this.aceUtils.updateAceMarkers(this.errorMarkerManager, []);
  }

  subscribe(){
    let eventAggregator = this.eventAggregator;

    eventAggregator.subscribe(
      "branchNavigatorChange", branchNavigatorData => {
        this.isBranchNavigatorVisible = branchNavigatorData.isVisible;
        if(this.isBranchNavigatorVisible){
          this.$hideTooltip();
        }
      });

    eventAggregator.subscribe(
      "jsEditorCursorMoved", info => {
        this.selectedLine = info.cursor ||1;
        this.$hideTooltip();
      });

    eventAggregator.subscribe(
      "jsEditorPreChange", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "jsEditorChangeError", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "activeEditorChange", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "jsGutterChangeScrollTop", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "expressionDataExplorerHideTooltip", data =>{
        this.isShowToolTipEvent = false;
        this.elementDecorator = data.elementDecorator;

        switch(data.type){
          case "right-gutter":
            this.onExpressionHovered();
            break;
          case "player":
            this.$hideTooltip(data);
            break;
          case "error":
            this.$hideError(data);
            break;
          default:
            this.onExpressionHovered();
        }

        this.elementDecorator = null;
      }
    );

    eventAggregator.subscribe(
      "expressionDataExplorerShowTooltip", data =>{
        this.isShowToolTipEvent = true;
        this.elementDecorator = data.elementDecorator;
        switch(data.type){
          case "right-gutter":
            this.handleIndexInTimeline(data.indexInTimeline);
            break;
          case "player":
            this.handleIndexInTimeline(data.indexInTimeline);
            break;
          case "error":
            this.$showError(data);
            break;
          default:
            this.$showTooltip(data);
        }
      }
    );
  }

  onExpressionHovered(match, pixelPosition, dimensions) {
    let isEditorTooltipContentVisible = $("#"+this.editorTooltipContentId).is(":visible");

    if(isEditorTooltipContentVisible && this.currentMatch === match){
      return;
    }
    this.currentMatch = match;

    let self = this;
    if(match && match.range){
      clearTimeout(this.onExpressionHoveredTimeout);
      this.onExpressionHoveredTimeout = setTimeout( function onExpressionHoveredTimeout(){
        self.update$Tooltip(pixelPosition, match, dimensions);
      }, this.editorTooltipShowDelay);
    }else{
      clearTimeout(this.onExpressionHoveredTimeout);
      this.onExpressionHoveredTimeout = setTimeout( function onExpressionHoveredTimeout(){
        self.update$Tooltip();
      }, this.editorTooltipHideDelay);
    }
  }
}
<commit_msg>pull from rc01<commit_after>/* global $ */
/* global CollapsibleLists */
import {ObjectViewer} from "../utils/object-viewer";
import $ from 'jquery';
import {resizable} from 'jquery-ui';

@customElement('pastebin')
export class ExpressionDataExplorer{
  editorTooltipSelector = "#editorTooltip";
  editorTooltipId = "editorTooltip";
  editorTooltipContentId = "editorTooltipContent";
  treeViewId = "treeViewContent";
  viewportSelector = "#codeContent .ace_scroller";
  viewportPadding = -6;
  editorTooltipShowDelay = 750;
  editorTooltipHideDelay = 750;
  content = "";

  constructor(eventAggregator, aceUtils, aureliaEditor, traceViewModel){
    this.eventAggregator = eventAggregator;
    this.aceUtils = aceUtils;
    this.aureliaEditor = aureliaEditor;
    this.traceViewModel = traceViewModel;
  }

  attached(){
    let self = this;
    let eventAggregator = this.eventAggregator;
    let aceUtils = this.aceUtils;
    let editor = this.aureliaEditor.editor;
    this.expressionMarkerManager = aceUtils.makeAceMarkerManager(editor);
    this.errorMarkerManager = aceUtils.makeAceMarkerManager(editor);
    this.logMarkerManager = aceUtils.makeAceMarkerManager(editor);
    this.expressionMarkerManager.markerRenderer = aceUtils.getAvailableMarkers().expressionMarker;
    this.errorMarkerManager.markerRenderer = aceUtils.getAvailableMarkers().errorMarker;
    this.logMarkerManager.markerRenderer = aceUtils.getAvailableMarkers().logMarker;

    let $editor = $(editor.renderer.getContainerElement());
    $editor.mouseleave(function aceEditorMouseleave(){
      eventAggregator.publish("expressionHovered");
    });

    let $editorTooltip = $(this.editorTooltipSelector);

    if(!$editorTooltip.length){
      $editorTooltip = $(`<div id='${this.editorTooltipId}' />`);
      $editorTooltip.attr({
        "data-toggle": "popover",
        "data-placement": "auto",
        "data-content": "No value found."
      });
      $editorTooltip.popover({
        viewport: {selector: this.viewportSelector, padding: this.viewportPadding},
        html: true,
        trigger: 'manual',
        template: '

'
      });
    }

    $editorTooltip.appendTo('body');
    $editorTooltip.on('inserted.bs.popover', function(){
      let $popoverContentTreeViewContent = $("#" + self.editorTooltipContentId);
      $popoverContentTreeViewContent.html("");
      $popoverContentTreeViewContent.append(self.title);
      $popoverContentTreeViewContent.append(self.content);
      self.title = "";
      self.content = "";
      CollapsibleLists.apply();
      $('[data-toggle="tooltip"]').tooltip();
    });

    $editorTooltip.on('shown.bs.popover', function () {
      let $popoverContentTreeViewContainer = $("#" + $(this).attr("aria-describedby"));
      $popoverContentTreeViewContainer.resizable({
        handles: "n, e, s, w"
      });

    });

    this.$editorTooltip = $editorTooltip;
    aceUtils.subscribeToExpressionHoverEvents(editor, eventAggregator, this);
    this.attachTooltipUpdate();
    this.subscribe();
  }

  decoratePopoverContentElement($popoverContentElement){
    if(!this.elementDecorator){
      return;
    }

    if(this.this.isShowToolTipEvent){
      this.elementDecorator.$decorate();
    }else{
      if(this.elementDecorator.$undecorate){
        this.elementDecorator.$undecorate();
      }
    }
  }

  attachTooltipUpdate(){
    let self = this;
    let $editorTooltip =   this.$editorTooltip;
    let aceUtils = this.aceUtils;

    this.update$Tooltip = function update$Tooltip(position, match, dimensions) {
      if(!$editorTooltip){
        return;
      }

      if (position) {
        $editorTooltip.css({
          position: "absolute",
          marginLeft: 0,
          marginTop: 0,
          top: `${position.pageY}px`,
          left: `${position.pageX}px`,
          width: `${dimensions.width}`,
          height: `${dimensions.height}`
          ,
          "z-index": -1000

        });
      }

      if(match && !self.isBranchNavigatorVisible){
        self.currentObjectViewer = new ObjectViewer(match.value, self.treeViewId);
        let popoverData = self.currentObjectViewer.generatePopoverTreeViewContent();
        let popoverTitle = `<strong>${match.id !== null ? match.id : ""} :</strong> <i>${self.currentObjectViewer.classType}</i>`;
        // $editorTooltip.attr("data-content", `<div class="custom-popover-title">${popoverTitle}</div>${popoverData.content}`);
        $editorTooltip.attr("data-content", "");
        self.title = `<div class="custom-popover-title">${popoverTitle}</div>`;
        self.content = popoverData.content;
        $editorTooltip.popover("show");
        aceUtils.updateAceMarkers(self.expressionMarkerManager, [match]);
      }else{
        self.$hideTooltip();
      }
      // let $popoverContentElement = $("#"+self.editorTooltipContentId);
      let $popoverContentTreeViewContainer = $("#" + $(self.editorTooltipId).attr("aria-describedby"));
      $popoverContentTreeViewContainer.mouseenter(
        function editorTooltipMouseenter(){
          clearTimeout(self.onExpressionHoveredTimeout);
          clearTimeout(self.editorTooltiptimeout);
        }
      ).mouseleave(
        function editorTooltipMouseleave(){
          self.editorTooltiptimeout = setTimeout(function editorTooltiptimeout(){
            self.$hideTooltip();
          }, self.editorTooltipHideDelay);
        }
      );
      self.decoratePopoverContentElement($popoverContentTreeViewContainer);
    };
  }

  handleIndexInTimeline(indexInTimeline){
    if( indexInTimeline === null){
      return;
    }

    if(!this.traceViewModel.traceHelper){
      return;
    }

    let timeline  = this.traceViewModel.traceHelper.getTimeline();
    if(!timeline){
      return;
    }

    let match =  timeline[indexInTimeline];
    if(match){
      this.traceViewModel.branchModel.getNavigationStackBlockCountsByIndexInTimeline(indexInTimeline);
      this.eventAggregator.publish("expressionHovered", match);
    }
  }

  $showTooltip(match){
    match.id = "console.log";
    this.eventAggregator.publish("expressionHovered", match);
  }

  $hideTooltip(){
    let $popoverContentElement = $("#"+this.editorTooltipContentId);
    if(this.$editorTooltip && $popoverContentElement.length  && !$popoverContentElement.is(":hover")){
      this.content = "";
      this.$editorTooltip.popover("hide");
      this.aceUtils.updateAceMarkers(this.expressionMarkerManager, []);
      clearTimeout(this.onExpressionHoveredTimeout);
      clearTimeout(this.editorTooltiptimeout);
    }
  }

  $showError(data){
    this.aceUtils.updateAceMarkers(this.errorMarkerManager, [data]);
  }

  $hideError(causeRange){
    this.aceUtils.updateAceMarkers(this.errorMarkerManager, []);
  }

  subscribe(){
    let eventAggregator = this.eventAggregator;

    eventAggregator.subscribe(
      "branchNavigatorChange", branchNavigatorData => {
        this.isBranchNavigatorVisible = branchNavigatorData.isVisible;
        if(this.isBranchNavigatorVisible){
          this.$hideTooltip();
        }
      });

    eventAggregator.subscribe(
      "jsEditorCursorMoved", info => {
        this.selectedLine = info.cursor ||1;
        this.$hideTooltip();
      });

    eventAggregator.subscribe(
      "jsEditorPreChange", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "jsEditorChangeError", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "activeEditorChange", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "jsGutterChangeScrollTop", payload =>{
        this.$hideTooltip();
      }
    );

    eventAggregator.subscribe(
      "expressionDataExplorerHideTooltip", data =>{
        this.isShowToolTipEvent = false;
        this.elementDecorator = data.elementDecorator;

        switch(data.type){
          case "right-gutter":
            this.onExpressionHovered();
            break;
          case "player":
            this.$hideTooltip(data);
            break;
          case "error":
            this.$hideError(data);
            break;
          default:
            this.onExpressionHovered();
        }

        this.elementDecorator = null;
      }
    );

    eventAggregator.subscribe(
      "expressionDataExplorerShowTooltip", data =>{
        this.isShowToolTipEvent = true;
        this.elementDecorator = data.elementDecorator;
        switch(data.type){
          case "right-gutter":
            this.handleIndexInTimeline(data.indexInTimeline);
            break;
          case "player":
            this.handleIndexInTimeline(data.indexInTimeline);
            break;
          case "error":
            this.$showError(data);
            break;
          default:
            this.$showTooltip(data);
        }
      }
    );
  }

  onExpressionHovered(match, pixelPosition, dimensions) {
    let isEditorTooltipContentVisible = $("#"+this.editorTooltipContentId).is(":visible");

    if(isEditorTooltipContentVisible && this.currentMatch === match){
      return;
    }
    this.currentMatch = match;

    let self = this;
    if(match && match.range){
      clearTimeout(this.onExpressionHoveredTimeout);
      this.onExpressionHoveredTimeout = setTimeout( function onExpressionHoveredTimeout(){
        self.update$Tooltip(pixelPosition, match, dimensions);
      }, this.editorTooltipShowDelay);
    }else{
      clearTimeout(this.onExpressionHoveredTimeout);
      this.onExpressionHoveredTimeout = setTimeout( function onExpressionHoveredTimeout(){
        self.update$Tooltip();
      }, this.editorTooltipHideDelay);
    }
  }
}
<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')
const http = require('http')
const https = require('https')
const path = require('path')
const tcp = require('net')
const tls = require('tls')

const httpHandler = require('./http-handler')
const tcpHandler = require('./tcp-handler')

const config = {
  httpPort: +(process.env.HTTP_PORT || 8082),
  httpsPort: +(process.env.HTTPS_PORT || 8443),
  tcpBodyPort: +(process.env.TCP_BODY_PORT || 9000),
  tlsBodyPort: +(process.env.TLS_BODY_PORT || 9001),
  tcpDelayPort: +(process.env.TCP_BODY_PORT || 9002),
  tlsDelayPort: +(process.env.TLS_BODY_PORT || 9003)

}

const tlsOptions = {
  key: fs.readFileSync(path.join(__dirname, 'tls', 'key.pem')),
  cert: fs.readFileSync(path.join(__dirname, 'tls', 'cert.pem'))
}

const httpServer = http.createServer(httpHandler.handleRequest)
httpServer.listen(config.httpPort, () => {
  console.log(`HTTP server started on ${config.httpPort}`)
})

const httpsServer = https.createServer(tlsOptions, httpHandler.handleRequest)
httpsServer.listen(config.httpsPort, () => {
  console.log(`HTTPS server started on ${config.httpsPort}`)
})

const tcpBodyServer = tcp.createServer(tcpHandler.handleBodyRequest)
tcpBodyServer.listen(config.tcpBodyPort, () => {
  console.log(`TCP body server started on ${config.tcpBodyPort}`)
})

const tlsBodyServer = tls.createServer(tlsOptions, tcpHandler.handleBodyRequest)
tlsBodyServer.listen(config.tlsBodyPort, () => {
  console.log(`TLS body server started on ${config.tlsBodyPort}`)
})
const tcpDelayServer = tcp.createServer(tcpHandler.handleDelayRequest)
tcpDelayServer.listen(config.tcpDelayPort, () => {
  console.log(`Tcp delay server started on ${config.tcpDelayPort}`)
})

const tlsDelayServer = tls.createServer(tlsOptions, tcpHandler.handleDelayRequest)
tlsDelayServer.listen(config.tlsDelayPort, () => {
  console.log(`TLS delay server started on ${config.tlsDelayPort}`)
})
<commit_msg>Fix formatting<commit_after>'use strict'

const fs = require('fs')
const http = require('http')
const https = require('https')
const path = require('path')
const tcp = require('net')
const tls = require('tls')

const httpHandler = require('./http-handler')
const tcpHandler = require('./tcp-handler')

const config = {
  httpPort: +(process.env.HTTP_PORT || 8082),
  httpsPort: +(process.env.HTTPS_PORT || 8443),
  tcpBodyPort: +(process.env.TCP_BODY_PORT || 9000),
  tlsBodyPort: +(process.env.TLS_BODY_PORT || 9001),
  tcpDelayPort: +(process.env.TCP_BODY_PORT || 9002),
  tlsDelayPort: +(process.env.TLS_BODY_PORT || 9003)

}

const tlsOptions = {
  key: fs.readFileSync(path.join(__dirname, 'tls', 'key.pem')),
  cert: fs.readFileSync(path.join(__dirname, 'tls', 'cert.pem'))
}

const httpServer = http.createServer(httpHandler.handleRequest)
httpServer.listen(config.httpPort, () => {
  console.log(`HTTP server started on ${config.httpPort}`)
})

const httpsServer = https.createServer(tlsOptions, httpHandler.handleRequest)
httpsServer.listen(config.httpsPort, () => {
  console.log(`HTTPS server started on ${config.httpsPort}`)
})

const tcpBodyServer = tcp.createServer(tcpHandler.handleBodyRequest)
tcpBodyServer.listen(config.tcpBodyPort, () => {
  console.log(`TCP body server started on ${config.tcpBodyPort}`)
})

const tlsBodyServer = tls.createServer(tlsOptions, tcpHandler.handleBodyRequest)
tlsBodyServer.listen(config.tlsBodyPort, () => {
  console.log(`TLS body server started on ${config.tlsBodyPort}`)
})

const tcpDelayServer = tcp.createServer(tcpHandler.handleDelayRequest)
tcpDelayServer.listen(config.tcpDelayPort, () => {
  console.log(`TCP delay server started on ${config.tcpDelayPort}`)
})

const tlsDelayServer = tls.createServer(tlsOptions, tcpHandler.handleDelayRequest)
tlsDelayServer.listen(config.tlsDelayPort, () => {
  console.log(`TLS delay server started on ${config.tlsDelayPort}`)
})
<|endoftext|>


<commit_before>function ContentLoader(){
  var constructor = function(){
    setInterval(function(){checkValidation(navigator.connection.type);},30000);
    loadShopInfo();
  }

  function checkValidation(connection){
    if((connection != "none" && connection != "unknown")){
      console.log("refreshato");
      window.location.href = 'index.html';
    }
  }
  function loadShopInfo(){
    $.get('/shop/contacts.html', function(data){
      if($(data).length > 0){
        $(data).appendTo($('#mainLogo'))
      }
    });
  }
  constructor();
}
(function () {
  var c_loader = new ContentLoader();
}());<commit_msg>fix su url di file<commit_after>function ContentLoader(){
  var constructor = function(){
    setInterval(function(){checkValidation(navigator.connection.type);},30000);
    loadShopInfo();
  }

  function checkValidation(connection){
    if((connection != "none" && connection != "unknown")){
      console.log("refreshato");
      window.location.href = 'index.html';
    }
  }
  function loadShopInfo(){
    $.get('local/shop/contacts.html', function(data){
      if($(data).length > 0){
        $(data).appendTo($('#mainLogo'))
      }
    });
  }
  constructor();
}
(function () {
  var c_loader = new ContentLoader();
}());<|endoftext|>


<commit_before>let output = '';
const musicSources = ['Spotify', 'iTunes']
for(source in musicSources){
    if ( Application(musicSources[source]).running() ){
        const track = Application(musicSources[source]).currentTrack;
        const artist = track.artist();
        const title = track.name();
        output = (`♫ ${title} - ${artist}`).substr(0, 50);
        break
    }
}
<commit_msg>[scripts] remove music icons - minimal?<commit_after>let output = '';
const musicSources = ['Spotify', 'iTunes']
for(source in musicSources){
    if ( Application(musicSources[source]).running() ){
        const track = Application(musicSources[source]).currentTrack;
        const artist = track.artist();
        const title = track.name();
        output = (`${title} - ${artist}`).substr(0, 50);
        break
    }
}
<|endoftext|>


<commit_before>/* eslint-disable jsx-a11y/mouse-events-have-key-events */
import React, {
  useCallback,
  useEffect,
  useContext,
  useMemo,
  useRef,
  useState,
} from "react";
import PropTypes from "prop-types";

import StyledMenuItemWrapper from "../../menu-item/menu-item.style";
import OptionHelper from "../../../../utils/helpers/options-helper";
import { StyledSubmenu, StyledSubmenuWrapper } from "./submenu.style";
import Link from "../../../link";
import Events from "../../../../utils/helpers/events";
import { MenuContext } from "../../menu.component";
import MenuItem from "../../menu-item";
import { characterNavigation } from "../keyboard-navigation";
import ScrollableBlock from "../../scrollable-block";
import SubmenuContext from "./submenu.context";

const Submenu = React.forwardRef(
  (
    {
      children,
      className,
      title,
      icon,
      submenuDirection = "right",
      onKeyDown,
      variant = "default",
      showDropdownArrow = true,
      clickToOpen,
      href,
      maxWidth,
      ...rest
    },
    ref
  ) => {
    const menuContext = useContext(MenuContext);
    const [submenuOpen, setSubmenuOpen] = useState(false);
    const [submenuFocusIndex, setSubmenuFocusIndex] = useState(undefined);
    const [characterString, setCharacterString] = useState("");
    const submenuRef = useRef();

    const formattedChildren = React.Children.map(children, (child) => {
      if (child.type === ScrollableBlock) {
        return [...child.props.children];
      }

      return child;
    });

    const numberOfChildren = useMemo(
      () => React.Children.count(formattedChildren),
      [formattedChildren]
    );

    const characterTimer = useRef();

    const startCharacterTimeout = useCallback(() => {
      characterTimer.current = setTimeout(() => {
        setCharacterString("");
      }, 1500);
    }, []);

    const restartCharacterTimeout = useCallback(() => {
      clearTimeout(characterTimer.current);
      startCharacterTimeout();
    }, [startCharacterTimeout]);

    const closeSubmenu = useCallback(() => {
      setSubmenuOpen(false);
      setSubmenuFocusIndex(undefined);
      setCharacterString("");
    }, []);

    const handleKeyDown = useCallback(
      (event, index = submenuFocusIndex) => {
        if (!submenuOpen) {
          if (
            Events.isEnterKey(event) ||
            Events.isSpaceKey(event) ||
            Events.isDownKey(event) ||
            Events.isUpKey(event)
          ) {
            event.preventDefault();
            setSubmenuOpen(true);
            if (!href) {
              setSubmenuFocusIndex(0);
            }
          }

          if (!event.defaultPrevented) {
            menuContext.handleKeyDown(event);
          }
        }

        if (submenuOpen) {
          let nextIndex = index;

          if (Events.isTabKey(event) && !Events.isShiftKey(event)) {
            if (index === numberOfChildren - 1) {
              closeSubmenu();
              return;
            }
            nextIndex = index + 1;
          }

          if (Events.isTabKey(event) && Events.isShiftKey(event)) {
            if (index === 0) {
              closeSubmenu();
              return;
            }
            nextIndex = index - 1;
          }

          if (Events.isDownKey(event)) {
            event.preventDefault();
            if (index < numberOfChildren - 1) {
              nextIndex = index + 1;
            }
          }

          if (Events.isUpKey(event)) {
            event.preventDefault();
            if (index > 0) {
              nextIndex = index - 1;
            }
          }

          if (Events.isEscKey(event)) {
            onKeyDown(event);
            closeSubmenu();
            return;
          }

          if (Events.isHomeKey(event)) {
            event.preventDefault();
            nextIndex = 0;
          }

          if (Events.isEndKey(event)) {
            event.preventDefault();
            nextIndex = numberOfChildren - 1;
          }

          if (Events.isAlphabetKey(event) || Events.isNumberKey(event)) {
            event.stopPropagation();

            if (characterTimer.current) {
              restartCharacterTimeout();
            } else {
              startCharacterTimeout();
            }

            setCharacterString(`${characterString}${event.key.toLowerCase()}`);
          } else {
            setCharacterString("");
          }

          if (href && index === undefined) {
            if (
              Events.isEnterKey(event) ||
              (Events.isTabKey(event) && Events.isShiftKey(event))
            ) {
              closeSubmenu();
              return;
            }

            if (
              Events.isSpaceKey(event) ||
              Events.isDownKey(event) ||
              Events.isUpKey(event) ||
              Events.isTabKey(event)
            ) {
              nextIndex = 0;
            }
          }

          // Defensive check in case an unhandled key event from a child component
          // has bubbled up
          if (!nextIndex && nextIndex !== 0) return;

          // Check that next index contains a MenuItem
          // If not, call handleKeyDown again
          const nextChild = React.Children.toArray(formattedChildren)[
            nextIndex
          ];
          if (nextChild && nextChild.type === MenuItem) {
            setSubmenuFocusIndex(nextIndex);
          } else {
            handleKeyDown(event, nextIndex);
          }
        }
      },
      [
        characterString,
        characterTimer,
        startCharacterTimeout,
        restartCharacterTimeout,
        formattedChildren,
        closeSubmenu,
        href,
        menuContext,
        numberOfChildren,
        onKeyDown,
        submenuFocusIndex,
        setSubmenuFocusIndex,
        submenuOpen,
      ]
    );

    const onClickOutside = useCallback(
      (event) => {
        if (!Events.composedPath(event).includes(submenuRef.current)) {
          document.removeEventListener("click", onClickOutside);
          closeSubmenu();
        }
      },
      [closeSubmenu]
    );

    useEffect(() => {
      if (characterString !== "") {
        const nextIndex = characterNavigation(
          characterString,
          React.Children.toArray(formattedChildren),
          submenuFocusIndex
        );

        setSubmenuFocusIndex(nextIndex);
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [characterString]);

    useEffect(() => {
      if (submenuOpen) {
        document.addEventListener("click", onClickOutside);
      }

      return function cleanup() {
        document.removeEventListener("click", onClickOutside);
      };
    }, [onClickOutside, submenuOpen]);

    return (
      <StyledSubmenuWrapper
        data-component="submenu-wrapper"
        role="menuitem"
        onMouseOver={!clickToOpen ? () => setSubmenuOpen(true) : undefined}
        onMouseLeave={() => closeSubmenu()}
        onClick={clickToOpen ? () => setSubmenuOpen(true) : undefined}
        ref={submenuRef}
        isSubmenuOpen={submenuOpen}
      >
        <StyledMenuItemWrapper
          {...rest}
          data-component="menu-item"
          className={className}
          menuType={menuContext.menuType}
          ref={ref}
          icon={icon}
          tabIndex={-1}
          variant={variant}
          isOpen={submenuOpen}
          as={Link}
          hasSubmenu
          showDropdownArrow={showDropdownArrow}
          onKeyDown={handleKeyDown}
          clickToOpen={clickToOpen}
          href={href}
          maxWidth={maxWidth}
        >
          {title}
        </StyledMenuItemWrapper>

        {submenuOpen && (
          <StyledSubmenu
            submenuDirection={submenuDirection}
            variant={variant}
            menuType={menuContext.menuType}
          >
            {React.Children.map(children, (child, index) => (
              <SubmenuContext.Provider
                value={{
                  isFocused: submenuFocusIndex === index,
                  focusIndex: submenuFocusIndex,
                  handleKeyDown,
                  blockIndex: React.Children.toArray(children).findIndex(
                    (item) => item.type === ScrollableBlock
                  ),
                }}
              >
                {child}
              </SubmenuContext.Provider>
            ))}
          </StyledSubmenu>
        )}
      </StyledSubmenuWrapper>
    );
  }
);

Submenu.propTypes = {
  /** Children elements */
  children: PropTypes.node.isRequired,
  /** Custom className */
  className: PropTypes.string,
  /** Adds an icon to the menu item. */
  icon: PropTypes.oneOf(OptionHelper.icons),
  /** Defines which direction the submenu will hang eg. left/right */
  submenuDirection: PropTypes.string,
  /** A title for the menu item that has a submenu. */
  title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  /** onKeyDown handler */
  onKeyDown: PropTypes.func,
  /** set the colour variant for a menuType */
  variant: PropTypes.oneOf(["default", "alternate"]),
  /** Flag to display the dropdown arrow when an item has a submenu */
  showDropdownArrow: PropTypes.bool,
  /** When set the submenu opens by click instead of hover */
  clickToOpen: PropTypes.bool,
  /** The href to use for the menu item. */
  href: PropTypes.string,
  /** Maximum width in px */
  maxWidth: PropTypes.number,
};

export default Submenu;
<commit_msg>refactor(submenu): pr comments<commit_after>/* eslint-disable jsx-a11y/mouse-events-have-key-events */
import React, {
  useCallback,
  useEffect,
  useContext,
  useMemo,
  useRef,
  useState,
} from "react";
import PropTypes from "prop-types";

import StyledMenuItemWrapper from "../../menu-item/menu-item.style";
import OptionHelper from "../../../../utils/helpers/options-helper";
import { StyledSubmenu, StyledSubmenuWrapper } from "./submenu.style";
import Link from "../../../link";
import Events from "../../../../utils/helpers/events";
import { MenuContext } from "../../menu.component";
import MenuItem from "../../menu-item";
import { characterNavigation } from "../keyboard-navigation";
import ScrollableBlock from "../../scrollable-block";
import SubmenuContext from "./submenu.context";

const Submenu = React.forwardRef(
  (
    {
      children,
      className,
      title,
      icon,
      submenuDirection = "right",
      onKeyDown,
      variant = "default",
      showDropdownArrow = true,
      clickToOpen,
      href,
      maxWidth,
      ...rest
    },
    ref
  ) => {
    const menuContext = useContext(MenuContext);
    const [submenuOpen, setSubmenuOpen] = useState(false);
    const [submenuFocusIndex, setSubmenuFocusIndex] = useState(undefined);
    const [characterString, setCharacterString] = useState("");
    const submenuRef = useRef();

    const formattedChildren = React.Children.map(children, (child) => {
      if (child.type === ScrollableBlock) {
        return [...child.props.children];
      }

      return child;
    });

    const numberOfChildren = useMemo(
      () => React.Children.count(formattedChildren),
      [formattedChildren]
    );

    const characterTimer = useRef();

    const startCharacterTimeout = useCallback(() => {
      characterTimer.current = setTimeout(() => {
        setCharacterString("");
      }, 1500);
    }, []);

    const restartCharacterTimeout = useCallback(() => {
      clearTimeout(characterTimer.current);
      startCharacterTimeout();
    }, [startCharacterTimeout]);

    const closeSubmenu = useCallback(() => {
      setSubmenuOpen(false);
      setSubmenuFocusIndex(undefined);
      setCharacterString("");
    }, []);

    const handleKeyDown = useCallback(
      (event, index = submenuFocusIndex) => {
        if (!submenuOpen) {
          if (
            Events.isEnterKey(event) ||
            Events.isSpaceKey(event) ||
            Events.isDownKey(event) ||
            Events.isUpKey(event)
          ) {
            event.preventDefault();
            setSubmenuOpen(true);
            if (!href) {
              setSubmenuFocusIndex(0);
            }
          }

          if (!event.defaultPrevented) {
            menuContext.handleKeyDown(event);
          }
        }

        if (submenuOpen) {
          let nextIndex = index;

          if (Events.isTabKey(event) && !Events.isShiftKey(event)) {
            if (index === numberOfChildren - 1) {
              closeSubmenu();
              return;
            }
            nextIndex = index + 1;
          }

          if (Events.isTabKey(event) && Events.isShiftKey(event)) {
            if (index === 0) {
              closeSubmenu();
              return;
            }
            nextIndex = index - 1;
          }

          if (Events.isDownKey(event)) {
            event.preventDefault();
            if (index < numberOfChildren - 1) {
              nextIndex = index + 1;
            }
          }

          if (Events.isUpKey(event)) {
            event.preventDefault();
            if (index > 0) {
              nextIndex = index - 1;
            }
          }

          if (Events.isEscKey(event)) {
            onKeyDown(event);
            closeSubmenu();
            return;
          }

          if (Events.isHomeKey(event)) {
            event.preventDefault();
            nextIndex = 0;
          }

          if (Events.isEndKey(event)) {
            event.preventDefault();
            nextIndex = numberOfChildren - 1;
          }

          if (Events.isAlphabetKey(event) || Events.isNumberKey(event)) {
            event.stopPropagation();

            if (characterTimer.current) {
              restartCharacterTimeout();
            } else {
              startCharacterTimeout();
            }

            setCharacterString(`${characterString}${event.key.toLowerCase()}`);
          } else {
            setCharacterString("");
          }

          if (href && index === undefined) {
            if (
              Events.isEnterKey(event) ||
              (Events.isTabKey(event) && Events.isShiftKey(event))
            ) {
              closeSubmenu();
              return;
            }

            if (
              Events.isSpaceKey(event) ||
              Events.isDownKey(event) ||
              Events.isUpKey(event) ||
              Events.isTabKey(event)
            ) {
              nextIndex = 0;
            }
          }

          // Defensive check in case an unhandled key event from a child component
          // has bubbled up
          if (!nextIndex && nextIndex !== 0) return;

          // Check that next index contains a MenuItem
          // If not, call handleKeyDown again
          const nextChild = React.Children.toArray(formattedChildren)[
            nextIndex
          ];
          if (nextChild && nextChild.type === MenuItem) {
            setSubmenuFocusIndex(nextIndex);
          } else {
            handleKeyDown(event, nextIndex);
          }
        }
      },
      [
        characterString,
        characterTimer,
        startCharacterTimeout,
        restartCharacterTimeout,
        formattedChildren,
        closeSubmenu,
        href,
        menuContext,
        numberOfChildren,
        onKeyDown,
        submenuFocusIndex,
        setSubmenuFocusIndex,
        submenuOpen,
      ]
    );

    const onClickOutside = useCallback(
      (event) => {
        if (!Events.composedPath(event).includes(submenuRef.current)) {
          document.removeEventListener("click", onClickOutside);
          closeSubmenu();
        }
      },
      [closeSubmenu]
    );

    useEffect(() => {
      if (characterString !== "") {
        const nextIndex = characterNavigation(
          characterString,
          React.Children.toArray(formattedChildren),
          submenuFocusIndex
        );

        setSubmenuFocusIndex(nextIndex);
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [characterString]);

    useEffect(() => {
      if (submenuOpen) {
        document.addEventListener("click", onClickOutside);
      }

      return function cleanup() {
        document.removeEventListener("click", onClickOutside);
      };
    }, [onClickOutside, submenuOpen]);

    return (
      <StyledSubmenuWrapper
        data-component="submenu-wrapper"
        role="menuitem"
        onMouseOver={!clickToOpen ? () => setSubmenuOpen(true) : undefined}
        onMouseLeave={() => closeSubmenu()}
        onClick={clickToOpen ? () => setSubmenuOpen(true) : undefined}
        ref={submenuRef}
        isSubmenuOpen={submenuOpen}
      >
        <StyledMenuItemWrapper
          {...rest}
          data-component="menu-item"
          className={className}
          menuType={menuContext.menuType}
          ref={ref}
          icon={icon}
          tabIndex={-1}
          variant={variant}
          isOpen={submenuOpen}
          as={Link}
          hasSubmenu
          showDropdownArrow={showDropdownArrow}
          onKeyDown={handleKeyDown}
          clickToOpen={clickToOpen}
          href={href}
          maxWidth={maxWidth}
        >
          {title}
        </StyledMenuItemWrapper>

        {submenuOpen && (
          <StyledSubmenu
            submenuDirection={submenuDirection}
            variant={variant}
            menuType={menuContext.menuType}
          >
            {React.Children.map(children, (child, index) => (
              <SubmenuContext.Provider
                value={{
                  isFocused: submenuFocusIndex === index,
                  focusIndex: submenuFocusIndex,
                  handleKeyDown,
                  blockIndex: React.Children.toArray(children).findIndex(
                    (item) => item.type === ScrollableBlock
                  ),
                }}
              >
                {child}
              </SubmenuContext.Provider>
            ))}
          </StyledSubmenu>
        )}
      </StyledSubmenuWrapper>
    );
  }
);

Submenu.propTypes = {
  /** Children elements */
  children: PropTypes.node.isRequired,
  /** Custom className */
  className: PropTypes.string,
  /** Adds an icon to the menu item. */
  icon: PropTypes.oneOf(OptionHelper.icons),
  /** Defines which direction the submenu will hang eg. left/right */
  submenuDirection: PropTypes.string,
  /** A title for the menu item that has a submenu. */
  title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  /** onKeyDown handler */
  onKeyDown: PropTypes.func,
  /** set the colour variant for a menuType */
  variant: PropTypes.oneOf(["default", "alternate"]),
  /** Flag to display the dropdown arrow when an item has a submenu */
  showDropdownArrow: PropTypes.bool,
  /** When set the submenu opens by click instead of hover */
  clickToOpen: PropTypes.bool,
  /** The href to use for the menu item. */
  href: PropTypes.string,
  /** Maximum width. Any valid CSS string */
  maxWidth: PropTypes.string,
};

export default Submenu;
<|endoftext|>