<commit_before>/* eslint-disable @typescript-eslint/explicit-function-return-type */
const seqCellColor = "rgb(241, 196, 15)";
const seqCellEmptyColor = "rgb(248, 249, 249)";

const seqCellPlayingColor = "rgb(201, 156, 0)";
const seqCellEmptyPlayingColor = "rgb(228, 229, 229)";

export default class StepSequencer {
    constructor(initParams) {
        this.parentElement = initParams.parent;
        this.stepModel = initParams.model;
        this.synthNotes = initParams.synthNotes;
        this.rowNames = initParams.rownames;

        this.rowCount = this.stepModel.length - 1;
        this.stepCount = this.stepModel[0].length - 1;
        this.currentStep = this.stepCount;

        const seqUI = this.createUI();
        this.mountIntoDOM(seqUI);

        this.stepsWithCells = this.getStepCells();
    }

    reset() {
        this.decolorizeColumn(this.currentStep);
        this.currentStep = -2; // must be lower than the 1st step when next() is called
    }

    next() {
        this.decolorizeColumn(this.currentStep);
        this.incrementCurrentStep();
        this.colorizeColumn(this.currentStep);
    }

    incrementCurrentStep() {
        this.currentStep++;
        if (this.currentStep > this.stepCount) {
            this.currentStep = 0;
        }
    }

    colorizeColumn(stepNumber) {
        if (stepNumber >= 0 && stepNumber <= this.stepCount) {
            const column = this.stepsWithCells[stepNumber];
            column.forEach((cell) => {
                if (cell.style.backgroundColor === seqCellColor) {
                    cell.style.backgroundColor = seqCellPlayingColor;
                } else {
                    cell.style.backgroundColor = seqCellEmptyPlayingColor;
                }
            });
        }
    }

    decolorizeColumn(stepNumber) {
        if (stepNumber >= 0 && stepNumber <= this.stepCount) {
            const column = this.stepsWithCells[stepNumber];
            column.forEach((cell) => {
                if (cell.style.backgroundColor === seqCellPlayingColor) {
                    cell.style.backgroundColor = seqCellColor;
                } else {
                    cell.style.backgroundColor = seqCellEmptyColor;
                }
            });
        }
    }

    getStepCells() {
        const rowCount = this.stepModel.length;
        const stepCount = this.stepModel[0].length;
        const steps = [];

        for (let i = 0; i < stepCount; i++) {
            steps.push([]);
            for (let j = 0; j < rowCount; j++) {
                const id = "seq-row_" + j + "_" + i;
                const cell = document.getElementById(id);
                steps[i].push(cell);
            }
        }
        return steps;
    }

    createUI() {
        const table = document.createElement("table");
        const rowCount = this.stepModel.length;

        table.id = "step-seq";
        table.className = "step-seq";
        table.appendChild(this.createHeaderRow(this.stepModel[0].length));

        for (let i = 0; i < rowCount; i++) {
            const row = this.createSeqRow(this.stepModel[i], i, this.rowNames[i]);
            table.appendChild(row);
        }
        const noteInputs = this.createNoteInputRow(this.stepModel[rowCount - 1]);
        table.appendChild(noteInputs);
        return table;
    }

    mountIntoDOM(seqUI) {
        const container = document.getElementById(this.parentElement);
        container.appendChild(seqUI);
    }

    createHeaderRow(stepCount) {
        const headerRow = document.createElement("tr");
        headerRow.id = "seq-row-header";
        this.populateHeaderRow(headerRow, stepCount);

        return headerRow;
    }

    populateHeaderRow(headerRow, rowCount) {
        for (let i = 0; i <= rowCount; i++) {
            const th = document.createElement("th");
            if (i !== 0) {
                th.className = "seq-header-cell";
                th.innerText = i;
            }
            headerRow.appendChild(th);
        }
    }

    createSeqRow(rowModel, rowNumber, rowName) {
        const seqRow = document.createElement("tr");
        seqRow.id = "seq-row_" + rowNumber;
        seqRow.className = "seq-row";

        this.addSeqRowHeader(seqRow, rowName);
        this.populateSeqRow(seqRow, rowModel);

        return seqRow;
    }

    addSeqRowHeader(seqRow, rowName) {
        const headerCell = document.createElement("th");
        headerCell.className = "seq-row-header";
        headerCell.innerText = rowName;
        seqRow.appendChild(headerCell);
    }

    populateSeqRow(seqRow, rowModel) {
        const rowId = seqRow.id;
        const stepCount = rowModel.length;

        for (let i = 0; i < stepCount; i++) {
            const td = document.createElement("td");
            td.id = rowId + "_" + i;
            td.className = "seq-step";
            td.onclick = this.changeStep.bind(this);

            if (rowModel[i] !== 0) {
                td.style.backgroundColor = seqCellColor;
            } else {
                td.style.backgroundColor = seqCellEmptyColor;
            }

            seqRow.appendChild(td);
        }
    }

    createNoteInputRow(rowModel) {
        const inputRow = document.createElement("tr");
        inputRow.id = "input-row";
        this.populateNoteInputRow(inputRow, rowModel);
        return inputRow;
    }

    populateNoteInputRow(rowElement, rowModel) {
        const stepCount = rowModel.length;

        for (let i = 0; i <= stepCount; i++) {
            const td = document.createElement("td");
            if (i !== 0) {
                const noteValue = this.synthNotes[i - 1];
                td.className = "note-input-cell";
                const input = document.createElement("input");
                input.id = "note-input_" + (i - 1);
                input.className = "note-input";
                input.type = "number";
                input.min = 0;
                input.max = 127;
                input.value = noteValue;
                input.onchange = this.changeNote.bind(this);
                td.appendChild(input);
            }
            rowElement.appendChild(td);
        }
    }

    changeNote(event) {
        const elementID = event.target.id;
        const stepNumber = parseInt(elementID.split("_")[1]);
        const noteNumber = event.target.valueAsNumber;

        this.onNoteChange(stepNumber, noteNumber);
    }

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    onNoteChange(stepNumber, noteNumber) {
        // can be overridden to inject code
        // that modifies the context
    }

    changeStep(event) {
        const seqCellId = event.target.id;
        const seqCell = document.getElementById(seqCellId);
        let activeStatus = false;

        if (seqCell.style.backgroundColor === seqCellColor) {
            seqCell.style.backgroundColor = seqCellEmptyColor;
        } else {
            seqCell.style.backgroundColor = seqCellColor;
            activeStatus = true;
        }

        const cellCoords = seqCellId.split("_");
        this.onStepChange(cellCoords[1], cellCoords[2], activeStatus);
    }

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    onStepChange(rowNumber, stepNumber, cellActive) {
        // can be overridden to inject code
        // that modifies the context
    }
}
<commit_msg>demo: fixed clicks to the active column of the step seq<commit_after>/* eslint-disable @typescript-eslint/explicit-function-return-type */
const seqCellColor = "rgb(241, 196, 15)";
const seqCellEmptyColor = "rgb(248, 249, 249)";

const seqCellPlayingColor = "rgb(201, 156, 0)";
const seqCellEmptyPlayingColor = "rgb(228, 229, 229)";

export default class StepSequencer {
    constructor(initParams) {
        this.parentElement = initParams.parent;
        this.stepModel = initParams.model;
        this.synthNotes = initParams.synthNotes;
        this.rowNames = initParams.rownames;

        this.rowCount = this.stepModel.length - 1;
        this.stepCount = this.stepModel[0].length - 1;
        this.currentStep = this.stepCount;

        const seqUI = this.createUI();
        this.mountIntoDOM(seqUI);

        this.stepsWithCells = this.getStepCells();
    }

    reset() {
        this.decolorizeColumn(this.currentStep);
        this.currentStep = -2; // must be lower than the 1st step when next() is called
    }

    next() {
        this.decolorizeColumn(this.currentStep);
        this.incrementCurrentStep();
        this.colorizeColumn(this.currentStep);
    }

    incrementCurrentStep() {
        this.currentStep++;
        if (this.currentStep > this.stepCount) {
            this.currentStep = 0;
        }
    }

    colorizeColumn(stepNumber) {
        if (stepNumber >= 0 && stepNumber <= this.stepCount) {
            const column = this.stepsWithCells[stepNumber];
            column.forEach((cell) => {
                if (cell.style.backgroundColor === seqCellColor) {
                    cell.style.backgroundColor = seqCellPlayingColor;
                } else {
                    cell.style.backgroundColor = seqCellEmptyPlayingColor;
                }
            });
        }
    }

    decolorizeColumn(stepNumber) {
        if (stepNumber >= 0 && stepNumber <= this.stepCount) {
            const column = this.stepsWithCells[stepNumber];
            column.forEach((cell) => {
                if (cell.style.backgroundColor === seqCellPlayingColor || cell.style.backgroundColor === seqCellColor) {
                    cell.style.backgroundColor = seqCellColor;
                } else {
                    cell.style.backgroundColor = seqCellEmptyColor;
                }
            });
        }
    }

    getStepCells() {
        const rowCount = this.stepModel.length;
        const stepCount = this.stepModel[0].length;
        const steps = [];

        for (let i = 0; i < stepCount; i++) {
            steps.push([]);
            for (let j = 0; j < rowCount; j++) {
                const id = "seq-row_" + j + "_" + i;
                const cell = document.getElementById(id);
                steps[i].push(cell);
            }
        }
        return steps;
    }

    createUI() {
        const table = document.createElement("table");
        const rowCount = this.stepModel.length;

        table.id = "step-seq";
        table.className = "step-seq";
        table.appendChild(this.createHeaderRow(this.stepModel[0].length));

        for (let i = 0; i < rowCount; i++) {
            const row = this.createSeqRow(this.stepModel[i], i, this.rowNames[i]);
            table.appendChild(row);
        }
        const noteInputs = this.createNoteInputRow(this.stepModel[rowCount - 1]);
        table.appendChild(noteInputs);
        return table;
    }

    mountIntoDOM(seqUI) {
        const container = document.getElementById(this.parentElement);
        container.appendChild(seqUI);
    }

    createHeaderRow(stepCount) {
        const headerRow = document.createElement("tr");
        headerRow.id = "seq-row-header";
        this.populateHeaderRow(headerRow, stepCount);

        return headerRow;
    }

    populateHeaderRow(headerRow, rowCount) {
        for (let i = 0; i <= rowCount; i++) {
            const th = document.createElement("th");
            if (i !== 0) {
                th.className = "seq-header-cell";
                th.innerText = i;
            }
            headerRow.appendChild(th);
        }
    }

    createSeqRow(rowModel, rowNumber, rowName) {
        const seqRow = document.createElement("tr");
        seqRow.id = "seq-row_" + rowNumber;
        seqRow.className = "seq-row";

        this.addSeqRowHeader(seqRow, rowName);
        this.populateSeqRow(seqRow, rowModel);

        return seqRow;
    }

    addSeqRowHeader(seqRow, rowName) {
        const headerCell = document.createElement("th");
        headerCell.className = "seq-row-header";
        headerCell.innerText = rowName;
        seqRow.appendChild(headerCell);
    }

    populateSeqRow(seqRow, rowModel) {
        const rowId = seqRow.id;
        const stepCount = rowModel.length;

        for (let i = 0; i < stepCount; i++) {
            const td = document.createElement("td");
            td.id = rowId + "_" + i;
            td.className = "seq-step";
            td.onclick = this.changeStep.bind(this);

            if (rowModel[i] !== 0) {
                td.style.backgroundColor = seqCellColor;
            } else {
                td.style.backgroundColor = seqCellEmptyColor;
            }

            seqRow.appendChild(td);
        }
    }

    createNoteInputRow(rowModel) {
        const inputRow = document.createElement("tr");
        inputRow.id = "input-row";
        this.populateNoteInputRow(inputRow, rowModel);
        return inputRow;
    }

    populateNoteInputRow(rowElement, rowModel) {
        const stepCount = rowModel.length;

        for (let i = 0; i <= stepCount; i++) {
            const td = document.createElement("td");
            if (i !== 0) {
                const noteValue = this.synthNotes[i - 1];
                td.className = "note-input-cell";
                const input = document.createElement("input");
                input.id = "note-input_" + (i - 1);
                input.className = "note-input";
                input.type = "number";
                input.min = 0;
                input.max = 127;
                input.value = noteValue;
                input.onchange = this.changeNote.bind(this);
                td.appendChild(input);
            }
            rowElement.appendChild(td);
        }
    }

    changeNote(event) {
        const elementID = event.target.id;
        const stepNumber = parseInt(elementID.split("_")[1]);
        const noteNumber = event.target.valueAsNumber;

        this.onNoteChange(stepNumber, noteNumber);
    }

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    onNoteChange(stepNumber, noteNumber) {
        // can be overridden to inject code
        // that modifies the context
    }

    changeStep(event) {
        const seqCellId = event.target.id;
        const seqCell = document.getElementById(seqCellId);
        let activeStatus = false;

        if (seqCell.style.backgroundColor === seqCellColor || seqCell.style.backgroundColor === seqCellPlayingColor) {
            seqCell.style.backgroundColor = seqCellEmptyColor;
        } else {
            seqCell.style.backgroundColor = seqCellColor;
            activeStatus = true;
        }

        const cellCoords = seqCellId.split("_");
        this.onStepChange(cellCoords[1], cellCoords[2], activeStatus);
    }

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    onStepChange(rowNumber, stepNumber, cellActive) {
        // can be overridden to inject code
        // that modifies the context
    }
}
<|endoftext|>


<commit_before>// You need to bring in jQuery first in order for this to work
//
// Call it like this:
// pkTagahead(<?php echo json_encode(url_for("taggableComplete/complete")) ?>);
//
// Or similar. Now all of your input elements with the input-tag class
// automatically gain the typeahead suggestion feature.
//
// If you're not using Symfony and sfDoctrineActAsTaggablePlugin,
// pass your own URL that returns a
 containing
s with the
// FULL TEXT of what the ENTIRE tag string will be if the user takes
// that suggestion, with the new tag you're suggesting an  link
// to #. Then use CSS to hide (visibility: none) the part of the
//
 that is not in the . Don't introduce any extra whitespace.

function pkTagahead(tagaheadUrl)
{
  $(function() {
    function getKey(event)
    {
      // Portable keycodes sigh
      return event.keyCode ? event.keyCode : event.which;
    }
    function setClick(target)
    {
      $(target).find('a').click(function(event)
      {
        // span contains ul contains li contains a
        var span = this.parentNode.parentNode.parentNode;
        var input = $(span).data("tag-peer");
        // Get text from the li
        var parent = this.parentNode;
        $(input).val($(parent).text());
        $(input).focus();
        return false;
      });
    }
    // Add suggestions span (you'll need to style that)
    $('input.tag-input').after("

");
    // Each tag field remembers its suggestions span...
    $('input.tag-input').each(function()
    {
      $(this).data("tag-peer", $(this).next()[0]);
    });
    // And vice versa
    $('div.tag-suggestions').each(function()
    {
      $(this).data("tag-peer", $(this).prev()[0]);
    });
    // Now we can really throw down
    $('input.tag-input').keyup(function(event)
    {
      var key = getKey(event);
      // Tab key
      if (key == 9)
      {
        var peer = $(this).data("tag-peer");
        var suggestions = $(peer).find("li");
        if (suggestions.length)
        {
          $(this).val($(suggestions[0]).text());
          $(this).focus();
        }
        // In any case don't insert the tab
        return false;
      }
      else
      {
        // Trigger ajax update of suggestions
      }
    });
    $('input.tag-input').keypress(function(event)
    {
      // Firefox 2.0 mac is stubborn and only allows cancel here
      // (we will still get the keyup and do the real work there)
      var key = getKey(event);
      if (key == 9)
      {
        // Don't insert tabs, ever
        return false;
      }
    });
    var lastValues = {};
    setInterval(function()
    {
      // AJAX query for suggestions only when changes have taken place
      $('input.tag-input').each(function()
      {
        var last = $(this).data('tag-last');
        var value = $(this).val();
        var peer = $(this).data('tag-peer');
        if (last !== value)
        {
          $(this).data('tag-last', value);
          $.post(
            tagaheadUrl,
            {
              current: $(this).val()
            },
            function(data, textStatus)
            {
              $(peer).html(data);
              setClick(peer);
            }
          );
        }
      });
    }, 200);
  });
}

function aInlineTaggableWidget(selector, options)
{
	var typeaheadUrl = options['typeahead-url'];
	var tagsLabel = options['tagsLabel'];
	var popularTags = options['popular-tags'];
	var existingTags = options['existing-tags'];
	var allTags = options['all-tags'];

	if (typeof(tagsLabel) == 'undefined')
	{
		tagsLabel = "Existing Tags";
	};

	function makePopularLink(attributes, title, text)
	{
		var new_tag = $('');
		var new_link = $('');
		new_tag.html(""+text+"");
		new_tag.attr({ title: title }).addClass('a-tag a-popular');
		new_tag.prepend(new_link);
		new_link.text(title);
		new_link.attr(attributes);
		return new_tag;
	}

	function makeRemoveLink(attributes, title, text)
	{
		title = $.trim(title);

		var new_tag = $('');
		var new_link = $('');
		var tagTitle = title;

		if (typeof(allTags) != 'undefined')
		{
			if (typeof(allTags[title]) != 'undefined')
			{
				title = title + ' - ' + allTags[title];
			}
			else
			{
				title = title + ' - 0';
			}
		}

		new_tag.html(""+title+"");
		new_tag.attr({ title: tagTitle }).addClass('a-tag');
		new_link.text('Remove Tag');
		new_link.attr(attributes);
		new_link.attr({ title: 'Remove' }).addClass('a-btn icon a-close-small no-label no-bg');
		new_link.prepend('');
		new_tag.append(new_link);
		return new_tag;
	}

	function trimExcessCommas(string)
	{
		string = string.replace(/(^,)|(, ?$)/g, '');
		string = string.replace(/(,,)|(, ,)/, ',');
		string = $.trim(string);

		return string;
	}

	$(selector).each(function()
	{
		// We don't want to display popular tags that we're already using
		var unusedPopulars = {};
		for (x in popularTags)
		{
			if (typeof(existingTags[x]) == 'undefined')
			{
				unusedPopulars[x] = popularTags[x];
			}
		}

		var popularsAttributes = {};
		var existingTagsAttributes = {};
		var existingDiv = $('
');
		var popularsDiv = $('
');

		// Establish the quick enhancement
		var tagInput = $(this);
		var typeAheadContainer = $('
');
		var typeAheadBox = $('<input />');
		typeAheadBox.attr('type', 'text');

		var addButton = $('');
		addButton.html('Add');
		addButton.attr({'href' : '#', 'class' : 'a-btn icon a-add add-tags-link', 'title' : 'Add these tags'});

		typeAheadContainer.addClass('a-inline-taggable-widget').append(typeAheadBox).append(addButton);

		tagInput.hide();
		tagInput.parent().append(typeAheadContainer);

		// Add a list of popular tags to be added
		function addTagsToForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val() + ', ' + tag;

			value = trimExcessCommas(value);
			tagInput.val(value);

			link.remove();

			var new_link = makeRemoveLink(existingTagsAttributes, tag, tag + ' x');
			new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent()); return false; });
			existingDiv.append(new_link);
		}

		// Add a list of tags that may be removed
		function removeTagsFromForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val();

			value = value.replace(tag, '');
			value = trimExcessCommas(value);
			tagInput.val(value);

			link.remove();

			// As we have just removed it from the list, we want the real deal populars.
			if (typeof(popularTags[tag]) != 'undefined')
			{
				var linkLabel = popularTags[tag];
				var new_link = makePopularLink(existingTagsAttributes, tag, linkLabel);
				new_link.children('a').bind('click', function() { addTagsToForm($(this).parent()); return false; });
				popularsDiv.append(new_link);
			}
		}

		// a maker function for tag containers
		function makeTagContainer(containerLabel, tagArray, linkAttributes, linkLabelType)
		{
			// Add a list of tags that may be removed
			var tagContainer = $('
');
			tagContainer.addClass('a-inline-taggable-widget-tag-container');
			var header = $('
');
			header.text(containerLabel);
			tagContainer.append(header);

			var attributes = {};
			for (x in tagArray)
			{
				var linkLabel = '';
				if (linkLabelType == 'add')
				{
					tagContainer.addClass('a-popular-tags');

					linkLabel = tagArray[x];
					var new_link = makePopularLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { addTagsToForm($(this).parent());  return false; });
				}
				else if (linkLabelType == 'remove')
				{
					tagContainer.addClass('a-existing-tags');

					linkLabel = 'x ' + x;
					var new_link = makeRemoveLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent());  return false; });
				}
				tagContainer.append(new_link);
			}
			return tagContainer;
		}

		// Add the new tags to the existing form input.
		// If the user doesn't click Save changes or add... tough?
		function commitTagsToForm()
		{
			var value = tagInput.val() + ',' + typeAheadBox.val();
			value = trimExcessCommas(value);
			tagInput.val(value);
			typeAheadBox.val('');

			existingTags = {};
			var lp = value.split(',');
			for (x in lp)
			{
				existingTags[lp[x]] = lp[x];
			}

			existingDiv.html(makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove').html());
			existingDiv.find('a').each(function() {
				$(this).bind('click', function() {
					removeTagsFromForm($(this).parent());
					return false;
				});
			});

			return false;
		}
		addButton.bind('click', function() { commitTagsToForm(); return false; });

		existingDiv = makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove');
		existingDiv.children('a').bind('click', function() { removeTagsFromForm($(this));  return false; });
		tagInput.parent().prepend(existingDiv);

		popularsDiv = makeTagContainer('Popular Tags', unusedPopulars, popularsAttributes, 'add');
		popularsDiv.children('a').bind('click', function() { addTagsToForm($(this));  return false; });
		tagInput.parent().append(popularsDiv);

		// TypeAhead
		typeAheadBox.autocomplete(typeaheadUrl, {	multiple: true });

		// Catch that enter key, baby!
		$(document).keyup(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		$(document).keypress(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		typeAheadBox.keyup(function(e)
			{
		 		if (e.keyCode == 13)
		 		{
		 			commitTagsToForm();
		 		}
		 	});
	});

}
<commit_msg>Apostrophe Ticket #657<commit_after>// You need to bring in jQuery first in order for this to work
//
// Call it like this:
// pkTagahead(<?php echo json_encode(url_for("taggableComplete/complete")) ?>);
//
// Or similar. Now all of your input elements with the input-tag class
// automatically gain the typeahead suggestion feature.
//
// If you're not using Symfony and sfDoctrineActAsTaggablePlugin,
// pass your own URL that returns a
 containing
s with the
// FULL TEXT of what the ENTIRE tag string will be if the user takes
// that suggestion, with the new tag you're suggesting an  link
// to #. Then use CSS to hide (visibility: none) the part of the
//
 that is not in the . Don't introduce any extra whitespace.

function pkTagahead(tagaheadUrl)
{
  $(function() {
    function getKey(event)
    {
      // Portable keycodes sigh
      return event.keyCode ? event.keyCode : event.which;
    }
    function setClick(target)
    {
      $(target).find('a').click(function(event)
      {
        // span contains ul contains li contains a
        var span = this.parentNode.parentNode.parentNode;
        var input = $(span).data("tag-peer");
        // Get text from the li
        var parent = this.parentNode;
        $(input).val($(parent).text());
        $(input).focus();
        return false;
      });
    }
    // Add suggestions span (you'll need to style that)
    $('input.tag-input').after("

");
    // Each tag field remembers its suggestions span...
    $('input.tag-input').each(function()
    {
      $(this).data("tag-peer", $(this).next()[0]);
    });
    // And vice versa
    $('div.tag-suggestions').each(function()
    {
      $(this).data("tag-peer", $(this).prev()[0]);
    });
    // Now we can really throw down
    $('input.tag-input').keyup(function(event)
    {
      var key = getKey(event);
      // Tab key
      if (key == 9)
      {
        var peer = $(this).data("tag-peer");
        var suggestions = $(peer).find("li");
        if (suggestions.length)
        {
          $(this).val($(suggestions[0]).text());
          $(this).focus();
        }
        // In any case don't insert the tab
        return false;
      }
      else
      {
        // Trigger ajax update of suggestions
      }
    });
    $('input.tag-input').keypress(function(event)
    {
      // Firefox 2.0 mac is stubborn and only allows cancel here
      // (we will still get the keyup and do the real work there)
      var key = getKey(event);
      if (key == 9)
      {
        // Don't insert tabs, ever
        return false;
      }
    });
    var lastValues = {};
    setInterval(function()
    {
      // AJAX query for suggestions only when changes have taken place
      $('input.tag-input').each(function()
      {
        var last = $(this).data('tag-last');
        var value = $(this).val();
        var peer = $(this).data('tag-peer');
        if (last !== value)
        {
          $(this).data('tag-last', value);
          $.post(
            tagaheadUrl,
            {
              current: $(this).val()
            },
            function(data, textStatus)
            {
              $(peer).html(data);
              setClick(peer);
            }
          );
        }
      });
    }, 200);
  });
}

function aInlineTaggableWidget(selector, options)
{
	var typeaheadUrl = options['typeahead-url'];
	var tagsLabel = options['tagsLabel'];
	var popularTags = options['popular-tags'];
	var existingTags = options['existing-tags'];
	var allTags = options['all-tags'];
	var commitSelector = options['commit-selector'];

	if (typeof(tagsLabel) == 'undefined')
	{
		tagsLabel = "Existing Tags";
	};

	function makePopularLink(attributes, title, text)
	{
		var new_tag = $('');
		var new_link = $('');
		new_tag.html(""+text+"");
		new_tag.attr({ title: title }).addClass('a-tag a-popular');
		new_tag.prepend(new_link);
		new_link.text(title);
		new_link.attr(attributes);
		return new_tag;
	}

	function makeRemoveLink(attributes, title, text)
	{
		title = $.trim(title);

		var new_tag = $('');
		var new_link = $('');
		var tagTitle = title;

		if (typeof(allTags) != 'undefined')
		{
			if (typeof(allTags[title]) != 'undefined')
			{
				title = title + ' - ' + allTags[title];
			}
			else
			{
				title = title + ' - 0';
			}
		}

		new_tag.html(""+title+"");
		new_tag.attr({ title: tagTitle }).addClass('a-tag');
		new_link.text('Remove Tag');
		new_link.attr(attributes);
		new_link.attr({ title: 'Remove' }).addClass('a-btn icon a-close-small no-label no-bg');
		new_link.prepend('');
		new_tag.append(new_link);
		return new_tag;
	}

	function trimExcessCommas(string)
	{
		string = string.replace(/(^,)|(, ?$)/g, '');
		string = string.replace(/(,,)|(, ,)/, ',');
		string = $.trim(string);

		return string;
	}

	$(selector).each(function()
	{
		// We don't want to display popular tags that we're already using
		var unusedPopulars = {};
		for (x in popularTags)
		{
			if (typeof(existingTags[x]) == 'undefined')
			{
				unusedPopulars[x] = popularTags[x];
			}
		}

		var popularsAttributes = {};
		var existingTagsAttributes = {};
		var existingDiv = $('
');
		var popularsDiv = $('
');

		// Establish the quick enhancement
		var tagInput = $(this);
		var typeAheadContainer = $('
');
		var typeAheadBox = $('<input />');
		var typeAheadBoxId = 'inline-tag-ahead-box-' + Math.floor(Math.random() * 2000);
		typeAheadBox.attr('type', 'text');
		typeAheadBox.attr('id', typeAheadBoxId);
		typeAheadBox.autocomplete(typeaheadUrl, {	multiple: true });

		var addButton = $('');
		addButton.html('Add');
		addButton.attr({'href' : '#', 'class' : 'a-btn icon a-add add-tags-link', 'title' : 'Add these tags'});

		typeAheadContainer.addClass('a-inline-taggable-widget').append(typeAheadBox).append(addButton);

		tagInput.hide();
		tagInput.parent().append(typeAheadContainer);

		// Add a list of popular tags to be added
		function addTagsToForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val() + ', ' + tag;

			value = trimExcessCommas(value);
			tagInput.val(value);

			link.remove();

			var new_link = makeRemoveLink(existingTagsAttributes, tag, tag + ' x');
			new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent()); return false; });
			existingDiv.append(new_link);
		}

		// Add a list of tags that may be removed
		function removeTagsFromForm(link)
		{
			var tag = link.attr('title');
			var value = tagInput.val();

			value = value.replace(tag, '');
			value = trimExcessCommas(value);
			tagInput.val(value);

			link.remove();

			// As we have just removed it from the list, we want the real deal populars.
			if (typeof(popularTags[tag]) != 'undefined')
			{
				var linkLabel = popularTags[tag];
				var new_link = makePopularLink(existingTagsAttributes, tag, linkLabel);
				new_link.children('a').bind('click', function() { addTagsToForm($(this).parent()); return false; });
				popularsDiv.append(new_link);
			}
		}

		// a maker function for tag containers
		function makeTagContainer(containerLabel, tagArray, linkAttributes, linkLabelType)
		{
			// Add a list of tags that may be removed
			var tagContainer = $('
');
			tagContainer.addClass('a-inline-taggable-widget-tag-container');
			var header = $('
');
			header.text(containerLabel);
			tagContainer.append(header);

			var attributes = {};
			for (x in tagArray)
			{
				var linkLabel = '';
				if (linkLabelType == 'add')
				{
					tagContainer.addClass('a-popular-tags');

					linkLabel = tagArray[x];
					var new_link = makePopularLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { addTagsToForm($(this).parent());  return false; });
				}
				else if (linkLabelType == 'remove')
				{
					tagContainer.addClass('a-existing-tags');

					linkLabel = 'x ' + x;
					var new_link = makeRemoveLink(linkAttributes, x, linkLabel);
					new_link.children('a').bind('click', function() { removeTagsFromForm($(this).parent());  return false; });
				}
				tagContainer.append(new_link);
			}
			return tagContainer;
		}

		// Add the new tags to the existing form input.
		// If the user doesn't click Save changes or add... tough?
		function commitTagsToForm()
		{
			var value = tagInput.val() + ',' + typeAheadBox.val();
			value = trimExcessCommas(value);
			tagInput.val(value);
			typeAheadBox.val('');

			existingTags = {};
			var lp = value.split(',');
			for (x in lp)
			{
				existingTags[lp[x]] = lp[x];
			}

			existingDiv.html(makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove').html());
			existingDiv.find('a').each(function() {
				$(this).bind('click', function() {
					removeTagsFromForm($(this).parent());
					return false;
				});
			});

			return false;
		}
		addButton.bind('click', function() { commitTagsToForm(); return false; });
		if (commitSelector != 'undefined')
		{
			$(commitSelector).bind('click', function() {
				commitTagsToForm();
				return true;
			});
		}

		existingDiv = makeTagContainer(tagsLabel, existingTags, existingTagsAttributes, 'remove');
		existingDiv.children('a').bind('click', function() { removeTagsFromForm($(this));  return false; });
		tagInput.parent().prepend(existingDiv);

		popularsDiv = makeTagContainer('Popular Tags', unusedPopulars, popularsAttributes, 'add');
		popularsDiv.children('a').bind('click', function() { addTagsToForm($(this));  return false; });
		tagInput.parent().append(popularsDiv);

		// Catch that enter key, baby!
		$(document).keyup(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		$(document).keypress(function(e)
			{
				if (e.keyCode == 13)
				{
					e.preventDefault();
				}
			});

		typeAheadBox.keyup(function(e)
			{
		 		if (e.keyCode == 13)
		 		{
		 			commitTagsToForm();
		 		}
		 	});
	});

}
<|endoftext|>


<commit_before>'use strict'

/**
 * Module dependencies
 */

var format = require('util').format
var utils = require('lazy-cache')(require)

/**
 * Temporarily re-assign `require` to trick browserify and
 * webpack into reconizing lazy dependencies.
 *
 * This tiny bit of ugliness has the huge dual advantage of
 * only loading modules that are actually called at some
 * point in the lifecycle of the application, whilst also
 * allowing browserify and webpack to find modules that
 * are depended on but never actually called.
 */

var fn = require
require = utils // eslint-disable-line no-undef, no-native-reassign

/**
 * Lazily required module dependencies
 */

require('async')
require('async-base-iterator', 'base')
require('extend-shallow', 'extend')

/**
 * Restore `require`
 */

require = fn // eslint-disable-line no-undef, no-native-reassign

/**
 * > Factory used to create, validate and normalize `series` and `parallel` methods.
 *
 * @name   factory
 * @param  {AsyncControl} `app`
 * @param  {String} `flow`
 * @return {Function}
 * @private
 */
utils.factory = function factory (app, flow) {
  /**
   * > Iterate over `value` in parallel or series flow.
   * The `async.map` or `async.mapSeries` method is used.
   *
   * @param  {Object|Array|Function} `value`
   * @param  {Object=} `options`
   * @param  {Function=} `done`
   * @return {Function}
   * @private
   */
  return function seriesOrParallel (value, options, done) {
    var argz = utils.validateArgs(flow, value, options, done)
    utils.normalize.call(this, app, argz.value, argz.options)

    if (typeof argz.done === 'function') {
      utils.async[flow](argz.value, app.iterator, utils.doneCallback(app, argz.done))
      return
    }

    return function thunk (cb) {
      if (typeof cb !== 'function') {
        var msg = format('AsyncControl.%s `done` to be function.', flow)
        throw new TypeError(msg)
      }
      utils.async[flow](argz.value, app.iterator, utils.doneCallback(app, cb))
    }
  }
}

/**
 * > Final (done) callback. Also calls the `after` hook.
 *
 * @param  {Object}   app
 * @param  {Function} done
 * @return {Function} callback
 * @private
 */
utils.doneCallback = function doneCallback (app, done) {
  return function callback () {
    app.options.after && app.options.after.apply(app, arguments)
    done.apply(app, arguments)
  }
}

/**
 * > Set and normalize defaults, input value, iterator and opitons.
 * Also calls the `before` hook.
 *
 * @param  {Object} `app`
 * @param  {Object|Array|Function} `value`
 * @param  {Object} `options`
 * @return {Object}
 * @private
 */
utils.normalize = function normalize (app, value, options) {
  app.define('_input', value)
  app.options = options ? utils.extend(app.options, options) : app.options
  app.options.context = app.options.context || this
  app.options.before && app.options.before.call(app.options.context, app, value)

  var makeIterator = utils.base.makeIterator.bind(utils.base)
  var iterator = app.options.iterator || app.iterator
  iterator = typeof iterator !== 'function' ? makeIterator : iterator
  iterator = iterator(app.options)
  app.define('iterator', iterator)

  return app
}

/**
 * > Validates incoming arguments.
 *
 * @param  {Object|Array|Function} `value`
 * @param  {Object=} `options`
 * @param  {Function=} `done`
 * @return {Object}
 * @private
 */
utils.validateArgs = function validateArgs (flow, value, options, done) {
  if (typeof value === 'function') {
    value = [value]
  }
  if (typeof options === 'function') {
    done = options
    options = null
  }
  if (typeof value !== 'object' && typeof value !== 'function') {
    var msg = format('AsyncControl.%s `value` to be array, object or function.', flow)
    throw new TypeError(msg)
  }

  return {
    value: value,
    options: options,
    done: done
  }
}

/**
 * > Expose `utils` modules.
 *
 * @type {Object}
 * @private
 */
module.exports = utils
<commit_msg>emit before/after events when app is emitter<commit_after>'use strict'

/**
 * Module dependencies
 */

var format = require('util').format
var utils = require('lazy-cache')(require)

/**
 * Temporarily re-assign `require` to trick browserify and
 * webpack into reconizing lazy dependencies.
 *
 * This tiny bit of ugliness has the huge dual advantage of
 * only loading modules that are actually called at some
 * point in the lifecycle of the application, whilst also
 * allowing browserify and webpack to find modules that
 * are depended on but never actually called.
 */

var fn = require
require = utils // eslint-disable-line no-undef, no-native-reassign

/**
 * Lazily required module dependencies
 */

require('async')
require('async-base-iterator', 'base')
require('extend-shallow', 'extend')

/**
 * Restore `require`
 */

require = fn // eslint-disable-line no-undef, no-native-reassign

/**
 * > Factory used to create, validate and normalize `series` and `parallel` methods.
 *
 * @name   factory
 * @param  {AsyncControl} `app`
 * @param  {String} `flow`
 * @return {Function}
 * @private
 */
utils.factory = function factory (app, flow) {
  /**
   * > Iterate over `value` in parallel or series flow.
   * The `async.map` or `async.mapSeries` method is used.
   *
   * @param  {Object|Array|Function} `value`
   * @param  {Object=} `options`
   * @param  {Function=} `done`
   * @return {Function}
   * @private
   */
  return function seriesOrParallel (value, options, done) {
    var argz = utils.validateArgs(flow, value, options, done)
    utils.normalize.call(this, app, argz.value, argz.options)

    if (typeof argz.done === 'function') {
      utils.async[flow](argz.value, app.iterator, utils.doneCallback(app, argz.done))
      return
    }

    return function thunk (cb) {
      if (typeof cb !== 'function') {
        var msg = format('AsyncControl.%s `done` to be function.', flow)
        throw new TypeError(msg)
      }
      utils.async[flow](argz.value, app.iterator, utils.doneCallback(app, cb))
    }
  }
}

/**
 * > Final (done) callback. Also calls the `after` hook.
 *
 * @param  {Object}   app
 * @param  {Function} done
 * @return {Function} callback
 * @private
 */
utils.doneCallback = function doneCallback (app, done) {
  return function callback () {
    if (typeof app.options.after === 'function') {
      app.options.after.apply(app.options.context, arguments)
    }
    if (typeof app.emit === 'function') {
      var args = [].slice.call(arguments)
      app.emit.apply(app.options.context, ['after'].concat(args))
    }
    done.apply(app, arguments)
  }
}

/**
 * > Set and normalize defaults, input value, iterator and opitons.
 * Also calls the `before` hook.
 *
 * @param  {Object} `app`
 * @param  {Object|Array|Function} `value`
 * @param  {Object} `options`
 * @return {Object}
 * @private
 */
utils.normalize = function normalize (app, value, options) {
  app.define('_input', value)
  app.options = options ? utils.extend(app.options, options) : app.options
  app.options.context = app.options.context || this

  var opts = app.options

  if (typeof opts.before === 'function') {
    opts.before.call(opts.context, app, value)
  }
  if (typeof app.emit === 'function') {
    app.emit.call(opts.context, 'before', app, value)
  }

  var makeIterator = utils.base.makeIterator.bind(utils.base)
  var iterator = app.options.iterator || app.iterator
  iterator = typeof iterator !== 'function' ? makeIterator : iterator
  iterator = iterator(app.options)
  app.define('iterator', iterator)

  return app
}

/**
 * > Validates incoming arguments.
 *
 * @param  {Object|Array|Function} `value`
 * @param  {Object=} `options`
 * @param  {Function=} `done`
 * @return {Object}
 * @private
 */
utils.validateArgs = function validateArgs (flow, value, options, done) {
  if (typeof value === 'function') {
    value = [value]
  }
  if (typeof options === 'function') {
    done = options
    options = null
  }
  if (typeof value !== 'object' && typeof value !== 'function') {
    var msg = format('AsyncControl.%s `value` to be array, object or function.', flow)
    throw new TypeError(msg)
  }

  return {
    value: value,
    options: options,
    done: done
  }
}

/**
 * > Expose `utils` modules.
 *
 * @type {Object}
 * @private
 */
module.exports = utils
<|endoftext|>


<commit_before>import Ember from 'ember';
const { keys, create } = Object; // jshint ignore:line
const {computed, observer, $, A, run, on, typeOf, debug, defineProperty, get, set, inject, isEmpty} = Ember;  // jshint ignore:line
const snake = thingy => {
  return thingy ? Ember.String.underscore(thingy) : thingy;
};
import layout from '../templates/components/ui-slider';
const numericApiSurface = ['min','max','step','precision','ticksSnapBounds'];
const booleanApiSurface = ['range','tooltipSplit','reversed','enabled','naturalArrowKeys','focus'];
const stringApiSurface = ['selection','tooltip','tooltipSeparator','tooltipPosition','selection','handle','scale','orientation'];
const arrayApiSurface = ['ticks','ticksPositions','ticksLabels'];
const functionalApiSurface = ['formatter'];
const apiSurface = [...numericApiSurface,...booleanApiSurface,...stringApiSurface,...arrayApiSurface, ...functionalApiSurface];
const assign = function() {
  let target = {};

  for (let i = 0; i < arguments.length; i++) {
    let source = arguments[i];

    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        target[key] = source[key];
      }
    }
  }

  return target;
};
const MINALIMAL_VALUE = 'min_value_exceeded';
const MAXIMAL_VALUE = 'max_value_exceeded';

export default Ember.Component.extend({
  layout: layout,
  classNames: ['ui-slider'],
  classNameBindings: ['isSliding:sliding','_mood','_section','range:range:singular'],
  // API Surface (defaults)
  min: 1,
  max: 10,
  step: 1,
  precision: 0,
  orientation: 'horizontal',
  range: false,
  selection: 'before', // values are 'before', 'after', or 'none' and indicate placement
  tooltip: 'show' , // show, hide, or always
  tooltipSeparator: ':', // used in ranges
  tooltipPosition: 'top',
  tooltipSplit: false, // if false only one tooltip for ranges, if true then tooltips for both
  handle: 'round', // values are round, square, triangle, or custom
  reversed: false,
  enabled: Ember.computed("disabled", {
    get() {
      return !this.get("disabled");
    },
    set(key, value) {
      return value;
    }
  }),
  naturalArrowKeys: false,
  scale: 'linear',
  focus: false,
  ticks:[],
  ticksPositions:[],
  ticksLabels:[],
  ticksSnapBounds:0,
  // VALUE
  keepInRange: true,
  immediateResponse: false,
  _immediateResponse: on('init',observer('immediateResponse', function() {
    const immediateResponse = this.get('immediateResponse');
    let self = this;
    if(immediateResponse) {
      Ember.run.schedule('afterRender', () => {
        this._slider.on('slide', function(evt) {
          Ember.run.debounce(() => {
            self.set('value', evt.value);
          },30);
        });
      });
    } else {
      if(this._slider) {
        this._slider.off('slide');
      }
    }
  })),
  sections: null,
  _oldSection: null,
  _section: computed('value','sections', function() {
    const {_oldSection} = this.getProperties('_oldSection');
    const newSection = this.sectionCalculator();

    if(newSection && newSection !== _oldSection) {
      this.sendAction('action','section-change',{
        context: this,
        section: newSection,
        oldSection: _oldSection
      });
      this.set('_oldSection', newSection);
    }

    return newSection ? `section-${newSection}` : null;
  }),
  sectionCalculator() {
    let {sections,min,max,value} = this.getProperties('sections','min','max','value');
    if(!sections || new A(['null','undefined']).includes(value)) {
      return null;
    }
    let section = 1;
    if(typeOf(sections) === 'array') {
      sections.map((item,index) => {
        if(item > min && item < max && value > item) {
          section = index+2;
        }
      });
    } else {
      const width = max - min + 1;
      const sectionWidth = width / Number(sections);
      section = Math.floor((value-min)/sectionWidth) + 1;
    }

    return section;
  },
  _value: observer('value','min','max','step', function() {
    this._valueObserver();
  }),
  mood: null,
  _mood: computed('mood', function() {
    const mood = this.get('mood');
    return mood ? `mood-${mood}` : null;
  }),
  _valueObserver() {
    run.next(()=> {
      let {value,min,max,range} = this.getProperties('value','min','max','range');
      const controlValue = this._slider.slider('getValue');

      if(JSON.stringify(value) !== JSON.stringify(controlValue)) {
        // regardless of whether range or not process as an array
        value = typeOf(value) === 'array' ? value : [value];
        value = value.map(v => {
          v = (v < min) ? this.handleMinimalValue() : v;
          v = (v > max) ? this.handleMaximalValue() : v;

          return v;
        });
        // now convert back to scalar if appropriate
        value = range ? value : value[0];
        this.setValue(value);

        this.sendAction('action', 'value-sync', {
          context: this,
          value: value,
          message: `A new value -- ${value} -- was received by container and pushed into slider UI`
        });
      }
    });
  },

  handleMinimalValue() {
    const {min,value,keepInRange} = this.getProperties('min','value','keepInRange');
    this.sendAction('error', MINALIMAL_VALUE, {
      message: `The minimum value [${min}] was exceeded: ${value}`,
      context: this
    });
    if(keepInRange) {
      run.next(()=>{
        this.set('value',min);
        this.sendAction('action', 'range-correction', {
          context: this,
          message: `The value was less than the minimum so resetting value to minimum [${min}]`,
          value: min,
          oldValue: value
        });
      });
    }

    return min;
  },
  handleMaximalValue() {
    const {max,value,keepInRange} = this.getProperties('max','value','keepInRange');
    this.sendAction('error', MAXIMAL_VALUE, {
      message: `The maximum value [${max}] was exceeded: ${value}`,
      context: this
    });
    if(keepInRange) {
      run.next(()=>{
        this.set('value',max);
        this.sendAction('action', 'range-correction', {
          context: this,
          message: `The value was less than the minimum so resetting value to minimum [${max}]`,
          value: max,
          oldValue: value
        });
      });
    }

    return max;
  },

  // Functions
  disabled: false,
  _disabled: observer('disabled', function() {
    const disabled = this.get('disabled');
    run.next(()=>{
      if(disabled) {
        this._slider.slider('disable');
        this.sendAction('action', 'slide-disabled', {
          context: this,
          value: this.get('value')
        });
      } else {
        this._slider.slider('enable');
        this.sendAction('action', 'slide-enabled', {
          context: this,
          value: this.get('value')
        });
      }
    });
  }),
  // Configuration Changes
  _configObserver: observer(...apiSurface, function() {
    this.updateConfig();
  }),
  updateConfig() {
    const changedConfig = apiSurface.filter(item => {
      return this[item] !== this._benchmark[item];
    });
    changedConfig.map(item => {
      this._slider.slider('setAttribute', snake(item), get(this,item));
      this.sendAction('action', 'set-attribute', {context:this, property: item, value: get(this,item)});
    });
    this._benchmarkConfig();
    this._slider.slider('refresh');
    this.setValue(this.get('value'));
  },
  _benchmarkConfig() {
    this._benchmark = this.getProperties(apiSurface);
  },
  getConfiguration() {
    let options = {};
    numericApiSurface.map(item=>{
      options[snake(item)] = Number(this.get(item));
      return item;
    });
    booleanApiSurface.map(item=>{
      options[snake(item)] = Boolean(this.get(item));
      return item;
    });
    arrayApiSurface.map(item=> {
      let data = this.get(item);
      if(typeOf(data) === 'string') {
        data = data.split(',');
        data = data.map(d=> {
          return isNaN(Number(d)) ? d : Number(d);
        });
      }
      if(data) {
        options[snake(item)] = data;
      }
      return item;
    });
    stringApiSurface.map(item=>{
      options[snake(item)] = this.get(item);
      return item;
    });
    functionalApiSurface.map(item => {
      options[snake(item)] = this.get(item);
    });

    return options;
  },
  initializeJqueryComponent() {
    const elementId = this.get('elementId');
    let options = this.getConfiguration();
    let value = this.get('value');
    if(typeOf(value) === 'string') {
      value = isNaN(Number(value)) ? options.min : Number(value);
    }

    options = assign(options, {value: value});
    this._slider = this.$(`#slider-value-${elementId}`).slider(options);
  },
  addEventListeners() {
    var self = this;
    self._slider.on('slideStart', function(evt) {
      self.set('isSliding', true);
      evt.preventDefault();
      run.next(()=> {
        self.sendAction('action','slideStart',{context: self, value: evt.value, evt: evt});
      });
    });
    self._slider.on('slideStop', function(evt) {
      self.set('isSliding', false);
      evt.preventDefault();
      self.sendAction('action', 'slideStop', {context: self, value: evt.value, evt: evt});
      self.sendAction('changed', evt.value, {context: self, evt: evt, oldValue: self.get('value')});
      self.set('value', evt.value);
    });
  },
  destroyJqueryComponent() {
    this._slider.slider('destroy');
  },
  setDefaultValue() {
    let {defaultValue,value} = this.getProperties('defaultValue', 'value');
    if(new A(['null','undefined']).includes(typeOf(value))) {
      defaultValue = typeOf(defaultValue) === 'string' && defaultValue.split(',').length > 1 ? defaultValue.split(',') : defaultValue;
      this.set('value', defaultValue);
    }
  },
  ensureValueSynced() {
    const {value} = this.getProperties('value');
    if(!value) {
      this.set('value', this.getValue());
    }
  },
  getValue() {
    return this._slider.slider('getValue');
  },
  setValue(value) {
    this._slider.slider('setValue', value);
  },

  // LIFECYCLE HOOKS
  init() {
    this._super(...arguments);
    if(!this.get('elementId')) {
      this.set('elementId', 'ember-' + Math.random().toString(36).substr(2, 9));
    }

    run.schedule('afterRender', () => {
      this.initializeJqueryComponent();
      this.addEventListeners();
      this.setDefaultValue();
      this.ensureValueSynced(); // if no default value and value set then we need to get value from the control
      this._benchmarkConfig();
    });
  },
  willDestroyElement() {
    this._super(...arguments);
    this.destroyJqueryComponent();
  }
});
<commit_msg>add ticksTooltip to booleanApiSurface and default to false<commit_after>import Ember from 'ember';
const { keys, create } = Object; // jshint ignore:line
const {computed, observer, $, A, run, on, typeOf, debug, defineProperty, get, set, inject, isEmpty} = Ember;  // jshint ignore:line
const snake = thingy => {
  return thingy ? Ember.String.underscore(thingy) : thingy;
};
import layout from '../templates/components/ui-slider';
const numericApiSurface = ['min','max','step','precision','ticksSnapBounds'];
const booleanApiSurface = ['range','tooltipSplit','ticksTooltip','reversed','enabled','naturalArrowKeys','focus'];
const stringApiSurface = ['selection','tooltip','tooltipSeparator','tooltipPosition','selection','handle','scale','orientation'];
const arrayApiSurface = ['ticks','ticksPositions','ticksLabels'];
const functionalApiSurface = ['formatter'];
const apiSurface = [...numericApiSurface,...booleanApiSurface,...stringApiSurface,...arrayApiSurface, ...functionalApiSurface];
const assign = function() {
  let target = {};

  for (let i = 0; i < arguments.length; i++) {
    let source = arguments[i];

    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        target[key] = source[key];
      }
    }
  }

  return target;
};
const MINALIMAL_VALUE = 'min_value_exceeded';
const MAXIMAL_VALUE = 'max_value_exceeded';

export default Ember.Component.extend({
  layout: layout,
  classNames: ['ui-slider'],
  classNameBindings: ['isSliding:sliding','_mood','_section','range:range:singular'],
  // API Surface (defaults)
  min: 1,
  max: 10,
  step: 1,
  precision: 0,
  orientation: 'horizontal',
  range: false,
  selection: 'before', // values are 'before', 'after', or 'none' and indicate placement
  tooltip: 'show' , // show, hide, or always
  tooltipSeparator: ':', // used in ranges
  tooltipPosition: 'top',
  tooltipSplit: false, // if false only one tooltip for ranges, if true then tooltips for both
  ticksTooltip: false,
  handle: 'round', // values are round, square, triangle, or custom
  reversed: false,
  enabled: Ember.computed("disabled", {
    get() {
      return !this.get("disabled");
    },
    set(key, value) {
      return value;
    }
  }),
  naturalArrowKeys: false,
  scale: 'linear',
  focus: false,
  ticks:[],
  ticksPositions:[],
  ticksLabels:[],
  ticksSnapBounds:0,
  // VALUE
  keepInRange: true,
  immediateResponse: false,
  _immediateResponse: on('init',observer('immediateResponse', function() {
    const immediateResponse = this.get('immediateResponse');
    let self = this;
    if(immediateResponse) {
      Ember.run.schedule('afterRender', () => {
        this._slider.on('slide', function(evt) {
          Ember.run.debounce(() => {
            self.set('value', evt.value);
          },30);
        });
      });
    } else {
      if(this._slider) {
        this._slider.off('slide');
      }
    }
  })),
  sections: null,
  _oldSection: null,
  _section: computed('value','sections', function() {
    const {_oldSection} = this.getProperties('_oldSection');
    const newSection = this.sectionCalculator();

    if(newSection && newSection !== _oldSection) {
      this.sendAction('action','section-change',{
        context: this,
        section: newSection,
        oldSection: _oldSection
      });
      this.set('_oldSection', newSection);
    }

    return newSection ? `section-${newSection}` : null;
  }),
  sectionCalculator() {
    let {sections,min,max,value} = this.getProperties('sections','min','max','value');
    if(!sections || new A(['null','undefined']).includes(value)) {
      return null;
    }
    let section = 1;
    if(typeOf(sections) === 'array') {
      sections.map((item,index) => {
        if(item > min && item < max && value > item) {
          section = index+2;
        }
      });
    } else {
      const width = max - min + 1;
      const sectionWidth = width / Number(sections);
      section = Math.floor((value-min)/sectionWidth) + 1;
    }

    return section;
  },
  _value: observer('value','min','max','step', function() {
    this._valueObserver();
  }),
  mood: null,
  _mood: computed('mood', function() {
    const mood = this.get('mood');
    return mood ? `mood-${mood}` : null;
  }),
  _valueObserver() {
    run.next(()=> {
      let {value,min,max,range} = this.getProperties('value','min','max','range');
      const controlValue = this._slider.slider('getValue');

      if(JSON.stringify(value) !== JSON.stringify(controlValue)) {
        // regardless of whether range or not process as an array
        value = typeOf(value) === 'array' ? value : [value];
        value = value.map(v => {
          v = (v < min) ? this.handleMinimalValue() : v;
          v = (v > max) ? this.handleMaximalValue() : v;

          return v;
        });
        // now convert back to scalar if appropriate
        value = range ? value : value[0];
        this.setValue(value);

        this.sendAction('action', 'value-sync', {
          context: this,
          value: value,
          message: `A new value -- ${value} -- was received by container and pushed into slider UI`
        });
      }
    });
  },

  handleMinimalValue() {
    const {min,value,keepInRange} = this.getProperties('min','value','keepInRange');
    this.sendAction('error', MINALIMAL_VALUE, {
      message: `The minimum value [${min}] was exceeded: ${value}`,
      context: this
    });
    if(keepInRange) {
      run.next(()=>{
        this.set('value',min);
        this.sendAction('action', 'range-correction', {
          context: this,
          message: `The value was less than the minimum so resetting value to minimum [${min}]`,
          value: min,
          oldValue: value
        });
      });
    }

    return min;
  },
  handleMaximalValue() {
    const {max,value,keepInRange} = this.getProperties('max','value','keepInRange');
    this.sendAction('error', MAXIMAL_VALUE, {
      message: `The maximum value [${max}] was exceeded: ${value}`,
      context: this
    });
    if(keepInRange) {
      run.next(()=>{
        this.set('value',max);
        this.sendAction('action', 'range-correction', {
          context: this,
          message: `The value was less than the minimum so resetting value to minimum [${max}]`,
          value: max,
          oldValue: value
        });
      });
    }

    return max;
  },

  // Functions
  disabled: false,
  _disabled: observer('disabled', function() {
    const disabled = this.get('disabled');
    run.next(()=>{
      if(disabled) {
        this._slider.slider('disable');
        this.sendAction('action', 'slide-disabled', {
          context: this,
          value: this.get('value')
        });
      } else {
        this._slider.slider('enable');
        this.sendAction('action', 'slide-enabled', {
          context: this,
          value: this.get('value')
        });
      }
    });
  }),
  // Configuration Changes
  _configObserver: observer(...apiSurface, function() {
    this.updateConfig();
  }),
  updateConfig() {
    const changedConfig = apiSurface.filter(item => {
      return this[item] !== this._benchmark[item];
    });
    changedConfig.map(item => {
      this._slider.slider('setAttribute', snake(item), get(this,item));
      this.sendAction('action', 'set-attribute', {context:this, property: item, value: get(this,item)});
    });
    this._benchmarkConfig();
    this._slider.slider('refresh');
    this.setValue(this.get('value'));
  },
  _benchmarkConfig() {
    this._benchmark = this.getProperties(apiSurface);
  },
  getConfiguration() {
    let options = {};
    numericApiSurface.map(item=>{
      options[snake(item)] = Number(this.get(item));
      return item;
    });
    booleanApiSurface.map(item=>{
      options[snake(item)] = Boolean(this.get(item));
      return item;
    });
    arrayApiSurface.map(item=> {
      let data = this.get(item);
      if(typeOf(data) === 'string') {
        data = data.split(',');
        data = data.map(d=> {
          return isNaN(Number(d)) ? d : Number(d);
        });
      }
      if(data) {
        options[snake(item)] = data;
      }
      return item;
    });
    stringApiSurface.map(item=>{
      options[snake(item)] = this.get(item);
      return item;
    });
    functionalApiSurface.map(item => {
      options[snake(item)] = this.get(item);
    });

    return options;
  },
  initializeJqueryComponent() {
    const elementId = this.get('elementId');
    let options = this.getConfiguration();
    let value = this.get('value');
    if(typeOf(value) === 'string') {
      value = isNaN(Number(value)) ? options.min : Number(value);
    }

    options = assign(options, {value: value});
    this._slider = this.$(`#slider-value-${elementId}`).slider(options);
  },
  addEventListeners() {
    var self = this;
    self._slider.on('slideStart', function(evt) {
      self.set('isSliding', true);
      evt.preventDefault();
      run.next(()=> {
        self.sendAction('action','slideStart',{context: self, value: evt.value, evt: evt});
      });
    });
    self._slider.on('slideStop', function(evt) {
      self.set('isSliding', false);
      evt.preventDefault();
      self.sendAction('action', 'slideStop', {context: self, value: evt.value, evt: evt});
      self.sendAction('changed', evt.value, {context: self, evt: evt, oldValue: self.get('value')});
      self.set('value', evt.value);
    });
  },
  destroyJqueryComponent() {
    this._slider.slider('destroy');
  },
  setDefaultValue() {
    let {defaultValue,value} = this.getProperties('defaultValue', 'value');
    if(new A(['null','undefined']).includes(typeOf(value))) {
      defaultValue = typeOf(defaultValue) === 'string' && defaultValue.split(',').length > 1 ? defaultValue.split(',') : defaultValue;
      this.set('value', defaultValue);
    }
  },
  ensureValueSynced() {
    const {value} = this.getProperties('value');
    if(!value) {
      this.set('value', this.getValue());
    }
  },
  getValue() {
    return this._slider.slider('getValue');
  },
  setValue(value) {
    this._slider.slider('setValue', value);
  },

  // LIFECYCLE HOOKS
  init() {
    this._super(...arguments);
    if(!this.get('elementId')) {
      this.set('elementId', 'ember-' + Math.random().toString(36).substr(2, 9));
    }

    run.schedule('afterRender', () => {
      this.initializeJqueryComponent();
      this.addEventListeners();
      this.setDefaultValue();
      this.ensureValueSynced(); // if no default value and value set then we need to get value from the control
      this._benchmarkConfig();
    });
  },
  willDestroyElement() {
    this._super(...arguments);
    this.destroyJqueryComponent();
  }
});
<|endoftext|>


<commit_before>var cssParse = Npm.require('css-parse');
var cssStringify = Npm.require('css-stringify');
var url = Npm.require('url');
var path = Npm.require('path');

CssTools = {
  parseCss: cssParse,
  stringifyCss: cssStringify,
  minifyCss: function (cssText) {
    return CssTools.minifyCssAst(cssParse(cssText));
  },
  minifyCssAst: function (cssAst) {
    return MinifyAst(cssAst);
  },
  mergeCssAsts: function (cssAsts, warnCb) {
    var rulesPredicate = function (rules) {
      if (! _.isArray(rules))
        rules = [rules];
      return function (node) {
        return _.contains(rules, node.type);
      }
    };

    // Simple concatenation of CSS files would break @import rules
    // located in the beginning of a file. Before concatenation, pull them to
    // the beginning of a new syntax tree so they always precede other rules.
    var newAst = {
      type: 'stylesheet',
      stylesheet: { rules: [] }
    };

    _.each(cssAsts, function (ast) {
      // Pick only the imports from the beginning of file ignoring @charset
      // rules as every file is assumed to be in UTF-8.
      var charsetRules = _.filter(ast.stylesheet.rules,
                                  rulesPredicate("charset"));

      if (_.any(charsetRules, function (rule) {
        // According to MDN, only 'UTF-8' and "UTF-8" are the correct encoding
        // directives representing UTF-8.
        return ! /^(['"])UTF-8\1$/.test(rule.charset);
      })) {
        warnCb(ast.filename, "@charset rules in this file will be ignored as UTF-8 is the only encoding supported");
      }

      ast.stylesheet.rules = _.reject(ast.stylesheet.rules,
                                      rulesPredicate("charset"));
      var importCount = 0;
      for (var i = 0; i < ast.stylesheet.rules.length; i++)
        if (! rulesPredicate(["import", "comment"])(ast.stylesheet.rules[i])) {
          importCount = i;
          break;
        }

      CssTools.rewriteCssUrls(ast);

      var imports = ast.stylesheet.rules.splice(0, importCount);
      newAst.stylesheet.rules = newAst.stylesheet.rules.concat(imports);

      // if there are imports left in the middle of file, warn user as it might
      // be a potential bug (imports are valid only in the beginning of file).
      if (_.any(ast.stylesheet.rules, rulesPredicate("import"))) {
        // XXX make this an error?
        warnCb(ast.filename, "there are some @import rules those are not taking effect as they are required to be in the beginning of the file");
      }

    });

    // Now we can put the rest of CSS rules into new AST
    _.each(cssAsts, function (ast) {
      newAst.stylesheet.rules =
        newAst.stylesheet.rules.concat(ast.stylesheet.rules);
    });

    return newAst;
  },

  // We are looking for all relative urls defined with the `url()` functional
  // notation and rewriting them to the equivalent absolute url using the
  // `position.source` path provided by css-parse
  // For performance reasons this function acts by side effect by modifying the
  // given AST without doing a deep copy.
  rewriteCssUrls: function (ast) {
    var mergedCssPath = "/";
    rewriteRules(ast.stylesheet.rules, mergedCssPath);
  }
};

if (typeof Profile !== 'undefined') {
  _.each(['parseCss', 'stringifyCss', 'minifyCss',
          'minifyCssAst', 'mergeCssAsts', 'rewriteCssUrls'],
         function (funcName) {
           CssTools[funcName] = Profile('CssTools.'+funcName,
                                        CssTools[funcName]);
         });
}

var rewriteRules = function (rules, mergedCssPath) {
  _.each(rules, function(rule, ruleIndex) {

    // Recurse if there are sub-rules. An example:
    //     @media (...) {
    //         .rule { url(...); }
    //     }
    if (_.has(rule, 'rules')) {
      rewriteRules(rule.rules, mergedCssPath);
    }

    var basePath = pathJoin("/", pathDirname(rule.position.source));

    // Set the correct basePath based on how the linked asset will be served.
    // XXX This is wrong. We are coupling the information about how files will
    // be served by the web server to the information how they were stored
    // originally on the filesystem in the project structure. Ideally, there
    // should be some module that tells us precisely how each asset will be
    // served but for now we are just assuming that everything that comes from
    // a folder starting with "/packages/" is served on the same path as
    // it was on the filesystem and everything else is served on root "/".
    if (! basePath.match(/^\/?packages\//i))
        basePath = "/";

    _.each(rule.declarations, function(declaration, declarationIndex) {
      var parts, resource, absolutePath, relativeToMergedCss, quote, oldCssUrl, newCssUrl;
      var value = declaration.value;

      // Match css values containing some functional calls to `url(URI)` where
      // URI is optionally quoted.
      // Note that a css value can contains other elements, for instance:
      //   background: top center url("background.png") black;
      // or even multiple url(), for instance for multiple backgrounds.
      var cssUrlRegex = /url\s*\(\s*(['"]?)(.+?)\1\s*\)/gi;
      while (parts = cssUrlRegex.exec(value)) {
        oldCssUrl = parts[0];
        quote = parts[1];
        resource = url.parse(parts[2]);

        // We don't rewrite URLs starting with a protocol definition such as
        // http, https, or data, or those with network-path references
        // i.e. //img.domain.com/cat.gif
        if (resource.protocol !== null || resource.href.startsWith('//') || resource.href.startsWith('#')) {
          continue;
        }

        // Rewrite relative paths (that refers to the internal application tree)
        // to absolute paths (addressable from the public build).
        if (isRelative(resource.path)) {
          absolutePath = pathJoin(basePath, resource.path);
        } else {
          absolutePath = resource.path;
        }

        if(resource.hash){
          absolutePath += resource.hash;
        }

        // We used to finish the rewriting process at the absolute path step
        // above. But it didn't work in case the Meteor application was deployed
        // under a sub-path (eg `ROOT_URL=http://localhost:3000/myapp meteor`)
        // in which case the resources linked in the merged CSS file would miss
        // the `myapp/` prefix. Since this path prefix is only known at launch
        // time (rather than build time) we can't use absolute paths to link
        // resources in the generated CSS.
        //
        // Instead we transform absolute paths to make them relative to the
        // merged CSS, leaving to the browser the responsibility to calculate
        // the final resource links (by adding the application deployment
        // prefix, here `myapp/`, if applicable).
        relativeToMergedCss = pathRelative(mergedCssPath, absolutePath);
        newCssUrl = "url(" + quote + relativeToMergedCss + quote + ")";
        value = value.replace(oldCssUrl, newCssUrl);
      }

      declaration.value = value;
    });
  });
};

var isRelative = function(path) {
  return path && path.charAt(0) !== '/';
};

// These are duplicates of functions in tools/files.js, because we don't have
// a good way of exporting them into packages.
// XXX deduplicate files.js into a package at some point so that we can use it
// in core
var toOSPath = function (p) {
  if (process.platform === 'win32')
    return p.replace(/\//g, '\\');
  return p;
}

var toStandardPath = function (p) {
  if (process.platform === 'win32')
    return p.replace(/\\/g, '/');
  return p;
};

var pathJoin = function (a, b) {
  return toStandardPath(path.join(
    toOSPath(a),
    toOSPath(b)));
};

var pathDirname = function (p) {
  return toStandardPath(path.dirname(toOSPath(p)));
};

var pathRelative = function(p1, p2) {
  return toStandardPath(path.relative(toOSPath(p1), toOSPath(p2)));
};
<commit_msg>Add spaces before and after parenthesis<commit_after>var cssParse = Npm.require('css-parse');
var cssStringify = Npm.require('css-stringify');
var url = Npm.require('url');
var path = Npm.require('path');

CssTools = {
  parseCss: cssParse,
  stringifyCss: cssStringify,
  minifyCss: function (cssText) {
    return CssTools.minifyCssAst(cssParse(cssText));
  },
  minifyCssAst: function (cssAst) {
    return MinifyAst(cssAst);
  },
  mergeCssAsts: function (cssAsts, warnCb) {
    var rulesPredicate = function (rules) {
      if (! _.isArray(rules))
        rules = [rules];
      return function (node) {
        return _.contains(rules, node.type);
      }
    };

    // Simple concatenation of CSS files would break @import rules
    // located in the beginning of a file. Before concatenation, pull them to
    // the beginning of a new syntax tree so they always precede other rules.
    var newAst = {
      type: 'stylesheet',
      stylesheet: { rules: [] }
    };

    _.each(cssAsts, function (ast) {
      // Pick only the imports from the beginning of file ignoring @charset
      // rules as every file is assumed to be in UTF-8.
      var charsetRules = _.filter(ast.stylesheet.rules,
                                  rulesPredicate("charset"));

      if (_.any(charsetRules, function (rule) {
        // According to MDN, only 'UTF-8' and "UTF-8" are the correct encoding
        // directives representing UTF-8.
        return ! /^(['"])UTF-8\1$/.test(rule.charset);
      })) {
        warnCb(ast.filename, "@charset rules in this file will be ignored as UTF-8 is the only encoding supported");
      }

      ast.stylesheet.rules = _.reject(ast.stylesheet.rules,
                                      rulesPredicate("charset"));
      var importCount = 0;
      for (var i = 0; i < ast.stylesheet.rules.length; i++)
        if (! rulesPredicate(["import", "comment"])(ast.stylesheet.rules[i])) {
          importCount = i;
          break;
        }

      CssTools.rewriteCssUrls(ast);

      var imports = ast.stylesheet.rules.splice(0, importCount);
      newAst.stylesheet.rules = newAst.stylesheet.rules.concat(imports);

      // if there are imports left in the middle of file, warn user as it might
      // be a potential bug (imports are valid only in the beginning of file).
      if (_.any(ast.stylesheet.rules, rulesPredicate("import"))) {
        // XXX make this an error?
        warnCb(ast.filename, "there are some @import rules those are not taking effect as they are required to be in the beginning of the file");
      }

    });

    // Now we can put the rest of CSS rules into new AST
    _.each(cssAsts, function (ast) {
      newAst.stylesheet.rules =
        newAst.stylesheet.rules.concat(ast.stylesheet.rules);
    });

    return newAst;
  },

  // We are looking for all relative urls defined with the `url()` functional
  // notation and rewriting them to the equivalent absolute url using the
  // `position.source` path provided by css-parse
  // For performance reasons this function acts by side effect by modifying the
  // given AST without doing a deep copy.
  rewriteCssUrls: function (ast) {
    var mergedCssPath = "/";
    rewriteRules(ast.stylesheet.rules, mergedCssPath);
  }
};

if (typeof Profile !== 'undefined') {
  _.each(['parseCss', 'stringifyCss', 'minifyCss',
          'minifyCssAst', 'mergeCssAsts', 'rewriteCssUrls'],
         function (funcName) {
           CssTools[funcName] = Profile('CssTools.'+funcName,
                                        CssTools[funcName]);
         });
}

var rewriteRules = function (rules, mergedCssPath) {
  _.each(rules, function(rule, ruleIndex) {

    // Recurse if there are sub-rules. An example:
    //     @media (...) {
    //         .rule { url(...); }
    //     }
    if (_.has(rule, 'rules')) {
      rewriteRules(rule.rules, mergedCssPath);
    }

    var basePath = pathJoin("/", pathDirname(rule.position.source));

    // Set the correct basePath based on how the linked asset will be served.
    // XXX This is wrong. We are coupling the information about how files will
    // be served by the web server to the information how they were stored
    // originally on the filesystem in the project structure. Ideally, there
    // should be some module that tells us precisely how each asset will be
    // served but for now we are just assuming that everything that comes from
    // a folder starting with "/packages/" is served on the same path as
    // it was on the filesystem and everything else is served on root "/".
    if (! basePath.match(/^\/?packages\//i))
        basePath = "/";

    _.each(rule.declarations, function(declaration, declarationIndex) {
      var parts, resource, absolutePath, relativeToMergedCss, quote, oldCssUrl, newCssUrl;
      var value = declaration.value;

      // Match css values containing some functional calls to `url(URI)` where
      // URI is optionally quoted.
      // Note that a css value can contains other elements, for instance:
      //   background: top center url("background.png") black;
      // or even multiple url(), for instance for multiple backgrounds.
      var cssUrlRegex = /url\s*\(\s*(['"]?)(.+?)\1\s*\)/gi;
      while (parts = cssUrlRegex.exec(value)) {
        oldCssUrl = parts[0];
        quote = parts[1];
        resource = url.parse(parts[2]);

        // We don't rewrite URLs starting with a protocol definition such as
        // http, https, or data, or those with network-path references
        // i.e. //img.domain.com/cat.gif
        if (resource.protocol !== null || resource.href.startsWith('//') || resource.href.startsWith('#')) {
          continue;
        }

        // Rewrite relative paths (that refers to the internal application tree)
        // to absolute paths (addressable from the public build).
        if (isRelative(resource.path)) {
          absolutePath = pathJoin(basePath, resource.path);
        } else {
          absolutePath = resource.path;
        }

        if (resource.hash) {
          absolutePath += resource.hash;
        }

        // We used to finish the rewriting process at the absolute path step
        // above. But it didn't work in case the Meteor application was deployed
        // under a sub-path (eg `ROOT_URL=http://localhost:3000/myapp meteor`)
        // in which case the resources linked in the merged CSS file would miss
        // the `myapp/` prefix. Since this path prefix is only known at launch
        // time (rather than build time) we can't use absolute paths to link
        // resources in the generated CSS.
        //
        // Instead we transform absolute paths to make them relative to the
        // merged CSS, leaving to the browser the responsibility to calculate
        // the final resource links (by adding the application deployment
        // prefix, here `myapp/`, if applicable).
        relativeToMergedCss = pathRelative(mergedCssPath, absolutePath);
        newCssUrl = "url(" + quote + relativeToMergedCss + quote + ")";
        value = value.replace(oldCssUrl, newCssUrl);
      }

      declaration.value = value;
    });
  });
};

var isRelative = function(path) {
  return path && path.charAt(0) !== '/';
};

// These are duplicates of functions in tools/files.js, because we don't have
// a good way of exporting them into packages.
// XXX deduplicate files.js into a package at some point so that we can use it
// in core
var toOSPath = function (p) {
  if (process.platform === 'win32')
    return p.replace(/\//g, '\\');
  return p;
}

var toStandardPath = function (p) {
  if (process.platform === 'win32')
    return p.replace(/\\/g, '/');
  return p;
};

var pathJoin = function (a, b) {
  return toStandardPath(path.join(
    toOSPath(a),
    toOSPath(b)));
};

var pathDirname = function (p) {
  return toStandardPath(path.dirname(toOSPath(p)));
};

var pathRelative = function(p1, p2) {
  return toStandardPath(path.relative(toOSPath(p1), toOSPath(p2)));
};
<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('15.12.0');
		this.setClientTag('node:19-12-03');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('15.12.0');
		this.setClientTag('node:19-12-04');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * The ButtonListener is a scenery Input Listener that translates input events
 * (down, up, enter, exit) into states in a button model.  Duck typing is used
 * for the buttonModel, it can be anything with "down" and "over" properties,
 * such as a PushButtonModel or a StickyToggleButtonModel.
 *
 * One assumption of this ButtonListener is that only one pointer can interact
 * with the button at a time, and the other pointers are effectively "locked
 * out" while another pointer is using the button.
 *
 * @author John Blanco
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var DownUpListener = require( 'SCENERY/input/DownUpListener' );
  var inherit = require( 'PHET_CORE/inherit' );

  /**
   * @param { down:Property<Boolean> over:Property<Boolean> } buttonModel
   * @constructor
   */
  function ButtonListener( buttonModel ) {
    this.buttonModel = buttonModel;
    var buttonListener = this;

    // Track the pointer that is currently interacting with this button, ignore others.
    this.overPointer = null;
    this.downPointer = null;

    DownUpListener.call( this, {
        down: function( event, trail ) {
          if ( buttonListener.downPointer === null ) {
            buttonListener.downPointer = event.pointer;
          }
          if ( event.pointer === buttonListener.downPointer ) {
            buttonModel.down = true;
          }
        },

        up: function( event, trail ) {
          if ( event.pointer === buttonListener.downPointer ) {
            buttonListener.downPointer = null;
            buttonModel.down = false;
          }
        }
      }
    );
  }

  return inherit( DownUpListener, ButtonListener, {
    enter: function( event, trail ) {
      if ( this.overPointer === null ) {
        this.overPointer = event.pointer;
        this.buttonModel.over = true;
      }
    },

    exit: function( event, trail ) {
      if ( event.pointer === this.overPointer ) {
        this.overPointer = null;
        this.buttonModel.over = false;
      }
    } } );
} );<commit_msg>note that down and over are boolean properties, add duck-typing to jsdoc for the buttonModel param<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * The ButtonListener is a scenery Input Listener that translates input events
 * (down, up, enter, exit) into states in a button model.  Duck typing is used
 * for the buttonModel, it can be anything with "down" and "over" boolean properties,
 * such as a PushButtonModel or a StickyToggleButtonModel.
 *
 * One assumption of this ButtonListener is that only one pointer can interact
 * with the button at a time, and the other pointers are effectively "locked
 * out" while another pointer is using the button.
 *
 * @author John Blanco
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var DownUpListener = require( 'SCENERY/input/DownUpListener' );
  var inherit = require( 'PHET_CORE/inherit' );

  /**
   * @param { down:Property<Boolean> over:Property<Boolean> } buttonModel
   * @constructor
   */
  function ButtonListener( buttonModel ) {
    this.buttonModel = buttonModel;
    var buttonListener = this;

    // Track the pointer that is currently interacting with this button, ignore others.
    this.overPointer = null;
    this.downPointer = null;

    DownUpListener.call( this, {
        down: function( event, trail ) {
          if ( buttonListener.downPointer === null ) {
            buttonListener.downPointer = event.pointer;
          }
          if ( event.pointer === buttonListener.downPointer ) {
            buttonModel.down = true;
          }
        },

        up: function( event, trail ) {
          if ( event.pointer === buttonListener.downPointer ) {
            buttonListener.downPointer = null;
            buttonModel.down = false;
          }
        }
      }
    );
  }

  return inherit( DownUpListener, ButtonListener, {
    enter: function( event, trail ) {
      if ( this.overPointer === null ) {
        this.overPointer = event.pointer;
        this.buttonModel.over = true;
      }
    },

    exit: function( event, trail ) {
      if ( event.pointer === this.overPointer ) {
        this.overPointer = null;
        this.buttonModel.over = false;
      }
    } } );
} );<|endoftext|>


<commit_before>/*
 * Pasta.js
 *
 * Actor-based MVC framework
 *
 * 2013 Minori Yamashita <ympbyc@gmail.com>
 */

var Pasta = (function () {
  var __ = Fw || require('./Fw');

  //Hide informations that are not necessary for appRule actor, but for execution
  var mainloopGenerator = function (config, api, signal) {
    return function (state, ev, ev_val) {
      var kont = function (patch) { api.modifyState(patch); };
      kont(config[ev](state, ev_val, signal)); //no longer passes `send`
    };
  };

  var UIHandler = function (appModel, UIAPI, updateRule, parentUI, initState) {
    var self = {};       //interface to the external world
    var appState = initState || {};   //mutable application state
    var mainloop = mainloopGenerator(appModel, self, signal);

    //`signal` function is given to UI actors on construction time, UI actors send messages to appRule actors
    // through this function.
    //`signal` have to be defined here because it accesses the closed mutable value `appState`
    function signal (ev_name, fn) {
      return function (e) {
        var val = fn ? fn(e) : e;
        mainloop(appState, ev_name, val);
      };
    };

    //Send messages to View actor.
    //Each message has a pattern `.changedVal (hash_of_UI_actors, copy_of_patched_appState, old_value)`
    function autoUpdate (patch) {
      var tempState = __.merge(appState, patch);
      __.hashFold(patch, null, function (change, key) {
        if (updateRule[key] !== undefined) updateRule[key](UIAPI, tempState, appState[key]);
      });
    }

    //DEPRECATED
    //initialize each view actors
    //app.js should send this
    self.start = function () {
      if (console) console.log("WARNING: Using a deprecated feature: start");
      __.hashFold(UIAPI, null, function (mdl, key) {
        if (UIAPI[key].initialize) UIAPI[key].initialize(parentUI, signal);
      });
      signal('start')();
    };

    //call `autoUpdate`. When done, merge the patch to the current appState
    self.modifyState = function (patch) {
      autoUpdate(patch);       //apply changes to UIs
      __._merge(appState, patch); //destructively update appState
    };

    //since 2013/4/10
    //expose signal
    self.signal = signal;

    return self;
  };

  //Pasta() is UIHandler

  UIHandler.__ = __;
  return UIHandler;

}());

if (typeof module !== "undefined") module.exports = Pasta;
else this.Pasta = Pasta;
<commit_msg>async<commit_after>/*
 * Pasta.js
 *
 * Actor-based MVC framework
 *
 * 2013 Minori Yamashita <ympbyc@gmail.com>
 */

var Pasta = (function () {
  var __ = Fw || require('./Fw');

  //Hide informations that are not necessary for appRule actor, but for execution
  var mainloopGenerator = function (config, api, signal) {
    return function (state, ev, ev_val) {
      var kont = function (patch) { api.modifyState(patch); };
      kont(config[ev](state, ev_val, signal)); //no longer passes `send`
    };
  };

  var UIHandler = function (appModel, UIAPI, updateRule, parentUI, initState) {
    var self = {};       //interface to the external world
    var appState = initState || {};   //mutable application state
    var mainloop = mainloopGenerator(appModel, self, signal);

    //`signal` function is given to UI actors on construction time, UI actors send messages to appRule actors
    // through this function.
    //`signal` have to be defined here because it accesses the closed mutable value `appState`
    function signal (ev_name, fn) {
      return function (e) {
        var val = fn ? fn(e) : e;
        setTimeout(function () {
            mainloop(appState, ev_name, val);
        }, 0);
      };
    };

    //Send messages to View actor.
    //Each message has a pattern `.changedVal (hash_of_UI_actors, copy_of_patched_appState, old_value)`
    function autoUpdate (patch) {
      var tempState = __.merge(appState, patch);
      __.hashFold(patch, null, function (change, key) {
        if (updateRule[key] !== undefined) updateRule[key](UIAPI, tempState, appState[key]);
      });
    }

    //DEPRECATED
    //initialize each view actors
    //app.js should send this
    self.start = function () {
      if (console) console.log("WARNING: Using a deprecated feature: start");
      __.hashFold(UIAPI, null, function (mdl, key) {
        if (UIAPI[key].initialize) UIAPI[key].initialize(parentUI, signal);
      });
      signal('start')();
    };

    //call `autoUpdate`. When done, merge the patch to the current appState
    self.modifyState = function (patch) {
      autoUpdate(patch);       //apply changes to UIs
      __._merge(appState, patch); //destructively update appState
    };

    //since 2013/4/10
    //expose signal
    self.signal = signal;

    return self;
  };

  //Pasta() is UIHandler

  UIHandler.__ = __;
  return UIHandler;

}());

if (typeof module !== "undefined") module.exports = Pasta;
else this.Pasta = Pasta;
<|endoftext|>


<commit_before>module.exports = {
  overrides: [
    {
      files: [
        '**/*.test.js',
        '**/*.test.jsx',
        '**/*.test.ts',
        '**/*.test.tsx',
        '**/__tests__/**/*.test.js',
        '**/__tests__/**/*.test.jsx',
        '**/__tests__/**/*.test.ts',
        '**/__tests__/**/*.test.tsx',
        '**/__tests__/**/*.js',
        '**/__tests__/**/*.jsx',
        '**/__tests__/**/*.ts',
        '**/__tests__/**/*.tsx',
      ],
      globals: {
        React: true,
        mount: true,
        shallow: true,
        render: true,
      },
    },
  ],
};
<commit_msg>Added support for spec files to eslint-config-jest-enzyme to match Jest.<commit_after>module.exports = {
  overrides: [
    {
      files: [
        '**/*.test.js',
        '**/*.test.jsx',
        '**/*.test.ts',
        '**/*.test.tsx',
        '**/*.spec.js',
        '**/*.spec.jsx',
        '**/*.spec.ts',
        '**/*.spec.tsx',
        '**/__tests__/**/*.test.js',
        '**/__tests__/**/*.test.jsx',
        '**/__tests__/**/*.test.ts',
        '**/__tests__/**/*.test.tsx',
        '**/__tests__/**/*.spec.js',
        '**/__tests__/**/*.spec.jsx',
        '**/__tests__/**/*.spec.ts',
        '**/__tests__/**/*.spec.tsx',
        '**/__tests__/**/*.js',
        '**/__tests__/**/*.jsx',
        '**/__tests__/**/*.ts',
        '**/__tests__/**/*.tsx',
      ],
      globals: {
        React: true,
        mount: true,
        shallow: true,
        render: true,
      },
    },
  ],
};
<|endoftext|>