<commit_before>function openWindow(url, windowName, width, height) {
  popup = window.open(url, windowName, 'width='+width+',height='+height+',toolbar=0,resizable=1,scrollbars=1,menubar=0,status=1');
  popup.focus();
}

function confirmRemove(url) {
  if (confirm("Are you sure?")) {
    window.location = url;
  }
}

function populateFilename(fromField, toField) {
  var indexOfSlash = fromField.value.lastIndexOf("/");
  if (indexOfSlash < 0) {
    indexOfSlash= fromField.value.lastIndexOf("\\");
  }
  if (indexOfSlash < 0) {
    indexOfSlash = 0;
  }

  toField.value = fromField.value.substring(indexOfSlash, fromField.value.length);
}

function checkAll(checkboxes) {
  if (!checkboxes.length) {
    checkboxes.checked = true;
  } else {
    for (i = 0; i < checkboxes.length; i++) {
      checkboxes[i].checked = true;
    }
  }
}

function uncheckAll(checkboxes) {
  if (!checkboxes.length) {
    checkboxes.checked = false;
  } else {
    for (i = 0; i < checkboxes.length; i++) {
      checkboxes[i].checked = false;
    }
  }
}

function toggleCheckAll(checkbox, checkboxes) {
  if (checkbox.checked) {
    checkAll(checkboxes);
  } else {
    uncheckAll(checkboxes);
  }
}

function toggleVisibility(elementId) {
    var element = document.getElementById(elementId);
    if(element.style.display == 'none') {
        element.style.display = 'block';
    } else {
        element.style.display = 'none';
    }
}

function setFocus(elementId) {
  var element = document.getElementById(elementId);
  element.focus();
}

function showComponent(elementId) {
  var element = document.getElementById(elementId);
  element.style.display = 'block';
}

function hideComponent(elementId) {
    var element = document.getElementById(elementId);
    element.style.display = 'none';
}

function showMenu(elementId) {
  var element = document.getElementById(elementId);
  element.style.display = 'inline';
}

function hideMenu(elementId) {
    var element = document.getElementById(elementId);
    element.style.display = 'none';
}

function switchStyle(elementId, style) {
    var element = document.getElementById(elementId);
    element.className = style;
}

function showCommentForm() {
  Effect.Appear('commentFormDiv', 'blind');
  var oFCKeditor = null;
  try {
    oFCKeditor = FCKeditorAPI.GetInstance('commentBody') ;
  } catch (error) {
    // do nothing - FCKeditor isn't available so we'll just use the regular commentBody textarea
  }
  if (oFCKeditor != null) {
    oFCKeditor.SwitchEditMode();
    oFCKeditor.SwitchEditMode();
  }
}

function previewComment() {
  var data = { author:null, email:null, website:null, title:null };
  dwr.util.getValues(data);
  var oFCKeditor = null;
  try {
    oFCKeditor = FCKeditorAPI.GetInstance('commentBody') ;
  } catch (error) {
    // do nothing - FCKeditor isn't available so we'll just use the regular commentBody textarea
  }
  if (oFCKeditor != null) {
    data.body = oFCKeditor.GetHTML();
  } else {
    data.body = dwr.util.getValue("commentBody");
  }
  Pebble.previewComment(dwr.util.getValue("blogId"), data, function(data) {
    dwr.util.setValue("previewComment.body", data.body, { escapeHtml:false });
    dwr.util.setValue("previewComment.title", dwr.util.getValue("title"));
    var author = '';
    if (dwr.util.getValue("website") != null && dwr.util.getValue("website") != '') {
      dwr.util.setValue("previewComment.author", "" + dwr.util.getValue("author") + "",  { escapeHtml:false });
    } else {
      dwr.util.setValue("previewComment.author", dwr.util.getValue("author"));
    }
    var avatar = dwr.util.getValue("avatar");
    if (avatar != null && avatar != "") {
      Element.insert("previewComment", {top: ""});
    }
  });
  Effect.Highlight('previewComment');
}

function updatePluginProperty(event) {
    var name = this.name;
    var value = this.value;
    var formElements = event.findElement("form").elements;
    // Find all elements in the form with the same name
    for (var i = 0; i < formElements.length; i++) {
        if (formElements[i].name == name) {
            formElements[i].value = value;
        }
    }
}

function initPluginProperties() {
    var formElements = document.forms["pluginsForm"].elements;
    for (var i = 0; i < formElements.length; i++) {
        if (formElements[i].name.indexOf("pluginProperty_") == 0) {
            Event.observe(formElements[i], "change", updatePluginProperty);
        }
    }
}

function initSingleSelect(element) {
  var select = document.forms["pluginsForm"].elements[element];
  var options = select.options;
  // Show the selected one
  for (var i = 0; i < options.length; i++) {
    var option = options[i];
    if (option.selected) {
      $("pluginsBox_" + element + "_" + option.value + "_pluginConfig").setStyle({display: "block"});
    }
  }
  // Attach callback
  Event.observe(select, "change", function(event) {
    for (var i = 0; i < options.length; i++) {
      var option = options[i];
      if (option.selected) {
        $("pluginsBox_" + element + "_" + option.value + "_pluginConfig").setStyle({display: "block"});
      } else {
        $("pluginsBox_" + element + "_" + option.value + "_pluginConfig").setStyle({display: "none"});
      }
    }
  })
}

// Update the form
function updateOpenIdCommentAuthor(author, website, email, avatar, logoutCallback) {
  var form = document.forms["commentForm"];
  form.elements["author"].value = author;
  form.elements["website"].value = website;
  form.elements["email"].value = email;
  form.elements["avatar"].value = avatar;
  // Hide everything that doesn't need to be seen
  $("commentAuthorDetails").setStyle({display : "none"});
  $("openIdCommentAuthorProviders").setStyle({display : "none"});
  // Show the user in place of the open id buttons
  Element.update("openIdCommentAuthorDetails", "" +
                                            author + "");
  Effect.Appear("openIdCommentAuthor");
  if (logoutCallback) {
    $("openIdCommentAuthor").openIdLogoutCallback = logoutCallback;
  }
}

function logoutOpenIdCommentAuthor() {
  // Clear the form
  var form = document.forms["commentForm"];
  form.elements["author"].value = "";
  form.elements["website"].value = "";
  form.elements["email"].value = "";
  form.elements["avatar"].value = "";
  // Hide the open id div
  $("openIdCommentAuthor").setStyle({display : "none"});
  // Show the providers div and author details
  Effect.Appear("openIdCommentAuthorProviders");
  Effect.Appear("commentAuthorDetails");
  // Call the callback to log the user out of the open id provider
  if ($("openIdCommentAuthor").openIdLogoutCallback) {
    $("openIdCommentAuthor").openIdLogoutCallback()
  }
}

/**
 * LOGIN
 */
function initLoginScreen() {
  var first = true;
  $$(".loginOption").each(function(option) {
    var loginOption = $(option);
    if (first) {
      loginOption.addClassName("loginOptionSelected");
      first = false;
    } else {
      $(loginOption.id + "Area").hide();
    }
    loginOption.observe("click", selectLoginOption);
  });
  $("loginUsingGoogle").observe("click", loginUsingGoogle);
}
function selectLoginOption(event) {
  var id = this.id;
  $$(".loginOption").each(function(option) {
    var loginOption = $(option);
    var area = $(loginOption.id + "Area");
    if (loginOption.id == id) {
      if (!loginOption.hasClassName("loginOptionSelected"))
      {
        loginOption.addClassName("loginOptionSelected");
        area.show()
      }
    } else {
      if (loginOption.hasClassName("loginOptionSelected")) {
        loginOption.removeClassName("loginOptionSelected");
        area.hide()
      }
    }
  });
}
function loginUsingGoogle(event) {
  // This is the URL for google openids
  $("openIdIdentifier").value = "https://www.google.com/accounts/o8/id";
  $("openIdLoginForm").submit();
}

function etPhoneHome(context) {
  setTimeout(function() {
    var url = "/ping";
    if (context) {
      url = context + url;
    }
    new Ajax.Request(url, {method: "get"});
    etPhoneHome(context);
  }, 300000);
}

/* Companion utils */
function openCompanion() {
  $("companionContainer").setStyle({display:"block"});
  $("companionContainerOpenLink").setStyle({display:"none"});
}
function closeCompanion() {
  $("companionContainer").setStyle({display:"none"});
  $("companionContainerOpenLink").style.display="";
}
function saveCompanion() {
  $("companionResult").innerHTML = "...";

  var form = document.forms["editBlogEntry"];
  if (!form) form = document.forms["editStaticPage"];
  var sToken = form.elements["pebbleSecurityToken"].value;

  new Ajax.Request('saveBlogCompanion.secureaction',
  {
    method:'post',
    parameters: {content: $("companionData").value, pebbleSecurityToken: sToken},
    onSuccess: function(transport){
      var response = transport.responseText;
      $("companionResult").innerHTML = response;
    },
    onFailure: function(){
      $("companionResult").innerHTML = "KO";
    }
  });

}
<commit_msg>Fixed stupid bug<commit_after>function openWindow(url, windowName, width, height) {
  popup = window.open(url, windowName, 'width='+width+',height='+height+',toolbar=0,resizable=1,scrollbars=1,menubar=0,status=1');
  popup.focus();
}

function confirmRemove(url) {
  if (confirm("Are you sure?")) {
    window.location = url;
  }
}

function populateFilename(fromField, toField) {
  var indexOfSlash = fromField.value.lastIndexOf("/");
  if (indexOfSlash < 0) {
    indexOfSlash= fromField.value.lastIndexOf("\\");
  }
  if (indexOfSlash < 0) {
    indexOfSlash = 0;
  }

  toField.value = fromField.value.substring(indexOfSlash, fromField.value.length);
}

function checkAll(checkboxes) {
  if (!checkboxes.length) {
    checkboxes.checked = true;
  } else {
    for (i = 0; i < checkboxes.length; i++) {
      checkboxes[i].checked = true;
    }
  }
}

function uncheckAll(checkboxes) {
  if (!checkboxes.length) {
    checkboxes.checked = false;
  } else {
    for (i = 0; i < checkboxes.length; i++) {
      checkboxes[i].checked = false;
    }
  }
}

function toggleCheckAll(checkbox, checkboxes) {
  if (checkbox.checked) {
    checkAll(checkboxes);
  } else {
    uncheckAll(checkboxes);
  }
}

function toggleVisibility(elementId) {
    var element = document.getElementById(elementId);
    if(element.style.display == 'none') {
        element.style.display = 'block';
    } else {
        element.style.display = 'none';
    }
}

function setFocus(elementId) {
  var element = document.getElementById(elementId);
  element.focus();
}

function showComponent(elementId) {
  var element = document.getElementById(elementId);
  element.style.display = 'block';
}

function hideComponent(elementId) {
    var element = document.getElementById(elementId);
    element.style.display = 'none';
}

function showMenu(elementId) {
  var element = document.getElementById(elementId);
  element.style.display = 'inline';
}

function hideMenu(elementId) {
    var element = document.getElementById(elementId);
    element.style.display = 'none';
}

function switchStyle(elementId, style) {
    var element = document.getElementById(elementId);
    element.className = style;
}

function showCommentForm() {
  Effect.Appear('commentFormDiv', 'blind');
  var oFCKeditor = null;
  try {
    oFCKeditor = FCKeditorAPI.GetInstance('commentBody') ;
  } catch (error) {
    // do nothing - FCKeditor isn't available so we'll just use the regular commentBody textarea
  }
  if (oFCKeditor != null) {
    oFCKeditor.SwitchEditMode();
    oFCKeditor.SwitchEditMode();
  }
}

function previewComment() {
  var data = { author:null, email:null, website:null, title:null };
  dwr.util.getValues(data);
  var oFCKeditor = null;
  try {
    oFCKeditor = FCKeditorAPI.GetInstance('commentBody') ;
  } catch (error) {
    // do nothing - FCKeditor isn't available so we'll just use the regular commentBody textarea
  }
  if (oFCKeditor != null) {
    data.body = oFCKeditor.GetHTML();
  } else {
    data.body = dwr.util.getValue("commentBody");
  }
  Pebble.previewComment(dwr.util.getValue("blogId"), data, function(data) {
    dwr.util.setValue("previewComment.body", data.body, { escapeHtml:false });
    dwr.util.setValue("previewComment.title", dwr.util.getValue("title"));
    var author = '';
    if (dwr.util.getValue("website") != null && dwr.util.getValue("website") != '') {
      dwr.util.setValue("previewComment.author", "" + dwr.util.getValue("author") + "",  { escapeHtml:false });
    } else {
      dwr.util.setValue("previewComment.author", dwr.util.getValue("author"));
    }
    var avatar = dwr.util.getValue("avatar");
    if (avatar != null && avatar != "") {
      Element.insert("previewComment", {top: ""});
    }
  });
  Effect.Highlight('previewComment');
}

function updatePluginProperty(event) {
    var name = this.name;
    var value = this.value;
    var formElements = event.findElement("form").elements;
    // Find all elements in the form with the same name
    for (var i = 0; i < formElements.length; i++) {
        if (formElements[i].name == name) {
            formElements[i].value = value;
        }
    }
}

function initPluginProperties() {
    var formElements = document.forms["pluginsForm"].elements;
    for (var i = 0; i < formElements.length; i++) {
        if (formElements[i].name.indexOf("pluginProperty_") == 0) {
            Event.observe(formElements[i], "change", updatePluginProperty);
        }
    }
}

function initSingleSelect(element) {
  var select = document.forms["pluginsForm"].elements[element];
  var options = select.options;
  // Show the selected one
  for (var i = 0; i < options.length; i++) {
    var option = options[i];
    if (option.selected) {
      $("pluginsBox_" + element + "_" + option.value + "_pluginConfig").setStyle({display: "block"});
    }
  }
  // Attach callback
  Event.observe(select, "change", function(event) {
    for (var i = 0; i < options.length; i++) {
      var option = options[i];
      if (option.selected) {
        $("pluginsBox_" + element + "_" + option.value + "_pluginConfig").setStyle({display: "block"});
      } else {
        $("pluginsBox_" + element + "_" + option.value + "_pluginConfig").setStyle({display: "none"});
      }
    }
  })
}

// Update the form
function updateOpenIdCommentAuthor(author, website, email, avatar, logoutCallback) {
  var form = document.forms["commentForm"];
  form.elements["author"].value = author;
  form.elements["website"].value = website;
  form.elements["email"].value = email;
  form.elements["avatar"].value = avatar;
  // Hide everything that doesn't need to be seen
  $("commentAuthorDetails").setStyle({display : "none"});
  $("openIdCommentAuthorProviders").setStyle({display : "none"});
  // Show the user in place of the open id buttons
  Element.update("openIdCommentAuthorDetails", "" +
                                            author + "");
  Effect.Appear("openIdCommentAuthor");
  if (logoutCallback) {
    $("openIdCommentAuthor").openIdLogoutCallback = logoutCallback;
  }
}

function logoutOpenIdCommentAuthor() {
  // Clear the form
  var form = document.forms["commentForm"];
  form.elements["author"].value = "";
  form.elements["website"].value = "";
  form.elements["email"].value = "";
  form.elements["avatar"].value = "";
  // Hide the open id div
  $("openIdCommentAuthor").setStyle({display : "none"});
  // Show the providers div and author details
  Effect.Appear("openIdCommentAuthorProviders");
  Effect.Appear("commentAuthorDetails");
  // Call the callback to log the user out of the open id provider
  if ($("openIdCommentAuthor").openIdLogoutCallback) {
    $("openIdCommentAuthor").openIdLogoutCallback()
  }
}

/**
 * LOGIN
 */
function initLoginScreen() {
  var first = true;
  $$(".loginOption").each(function(option) {
    var loginOption = $(option);
    if (first) {
      loginOption.addClassName("loginOptionSelected");
      first = false;
    } else {
      $(loginOption.id + "Area").hide();
    }
    loginOption.observe("click", selectLoginOption);
  });
  $$(".loginUsingGoogle").observe("click", loginUsingGoogle);
}
function selectLoginOption(event) {
  var id = this.id;
  $$(".loginOption").each(function(option) {
    var loginOption = $(option);
    var area = $(loginOption.id + "Area");
    if (loginOption.id == id) {
      if (!loginOption.hasClassName("loginOptionSelected"))
      {
        loginOption.addClassName("loginOptionSelected");
        area.show()
      }
    } else {
      if (loginOption.hasClassName("loginOptionSelected")) {
        loginOption.removeClassName("loginOptionSelected");
        area.hide()
      }
    }
  });
}
function loginUsingGoogle(event) {
  // This is the URL for google openids
  $("openIdIdentifier").value = "https://www.google.com/accounts/o8/id";
  $("openIdLoginForm").submit();
}

function etPhoneHome(context) {
  setTimeout(function() {
    var url = "/ping";
    if (context) {
      url = context + url;
    }
    new Ajax.Request(url, {method: "get"});
    etPhoneHome(context);
  }, 300000);
}

/* Companion utils */
function openCompanion() {
  $("companionContainer").setStyle({display:"block"});
  $("companionContainerOpenLink").setStyle({display:"none"});
}
function closeCompanion() {
  $("companionContainer").setStyle({display:"none"});
  $("companionContainerOpenLink").style.display="";
}
function saveCompanion() {
  $("companionResult").innerHTML = "...";

  var form = document.forms["editBlogEntry"];
  if (!form) form = document.forms["editStaticPage"];
  var sToken = form.elements["pebbleSecurityToken"].value;

  new Ajax.Request('saveBlogCompanion.secureaction',
  {
    method:'post',
    parameters: {content: $("companionData").value, pebbleSecurityToken: sToken},
    onSuccess: function(transport){
      var response = transport.responseText;
      $("companionResult").innerHTML = response;
    },
    onFailure: function(){
      $("companionResult").innerHTML = "KO";
    }
  });

}
<|endoftext|>


<commit_before>import Emitter from './Emitter';
import {getCellID, getCellPos} from './cellID';
import parseExpression from './exprCompiler';
import {parseNumMaybe} from './exprCompiler/functions';

const defaultParams = {
    context: null,
    immutable: false,
    name: null,

    height: 6,
    width: 6,

    iterate: true,
    maxIterations: 1000,
    iterationEpsilon: 0.001,
};

const WINDOW_MOUSEUP = Symbol('window.onmouseup');

export default class WebSheet {
    constructor(params = {}) {
        Object.assign(this, defaultParams, params);

        this.data = [];
        this.calculated = [];

        this.calculationSemaphore = null;
        this.calculationSourceGraph = null;
        this.depUpdateQueue = null;
        this.dependencies = {}; // Map of cell ID to array of dependant cell IDs
        this.dependants = {}; // Map of cell ID to array of dependencies

        this.valueUpdates = new Emitter();
        this.calculatedUpdates = new Emitter();
        this.console = new Emitter();
    }

    addColumn(rerender = true) {
        this.width += 1;
        if (rerender) {
            this.forceRerender();
        }
    }
    addRow(rerender = true) {
        this.height += 1;
        this.data.push(new Array(this.width));
        this.calculated.push(new Array(this.width));
        if (rerender) {
            this.forceRerender();
        }
    }

    calculateValueAtPosition(row, col, expression) {
        if (!expression) return;
        const cellID = getCellID(row, col);
        let value;

        // Do some cycle detection.
        if (this.calculationSemaphore) {
            if (cellID in this.calculationSemaphore) {
                if (this.calculationSemaphore[cellID] > this.maxIterations) {
                    this.console.fire('warn', 'Circular reference hit max iteration limit');
                    return;
                }

                this.calculationSemaphore[cellID]++;

            } else {
                this.calculationSemaphore[cellID] = 1;
            }
        }

        // Parse the expression
        const parsed = parseExpression(expression);

        // Evaluate the expression to find a value
        try {
            value = parsed.run(this);
        } catch (e) {
            value = new Error('#ERROR!');
        }

        // Set the calculated value in the calculated cache
        this.calculated[row] = this.calculated[row] || [];

        const origCalculatedValue = this.calculated[row][col];
        const wasUpdated = (
            origCalculatedValue !== value ||
            Math.abs(origCalculatedValue - value) > this.iterationEpsilon
        );

        if (!wasUpdated) {
            return;
        }

        this.calculated[row][col] = value;

        // Set the dependants
        const dependants = [];
        if (parsed) {
            // Bind intra-sheet dependencies
            parsed.findCellDependencies(dep => {
                if (dependants.indexOf(dep) !== -1) return;
                dependants.push(dep);
                if (!(dep in this.dependencies)) {
                    this.dependencies[dep] = [cellID];
                    return;
                }

                const deps = this.dependencies[dep];
                if (deps && deps.indexOf(cellID) === -1) {
                    deps.push(cellID);
                }
            });

            // Bind inter-sheet dependencies if a sheet context exists
            if (this.context) {
                this.context.clearDependencies(this, cellID);
                let sheetDeps = [];
                parsed.findSheetDependencies((sheet, dep) => {
                    if (!this.context.sheets[sheet.toUpperCase()]) return;
                    var depName = `${sheet}!${dep}`;
                    if (sheetDeps.indexOf(depName) !== -1) return;
                    sheetDeps.push(depName);

                    this.context.setDependency(this, cellID, sheet, dep, () => {
                        this.calculateValueAtPosition(row, col, expression);
                    });

                });
            }

        }
        this.dependants[cellID] = dependants;

        this.updateDependencies(cellID);
        this.calculatedUpdates.fire(cellID, value);

        return this.formatValue(cellID, value);
    }

    forceRerender() {
        this.console.fire('log', 'Rerender ignored in headless websheet');
    }

    clearCell(row, col) {
        const cellID = getCellID(row, col);
        if (row in this.data) delete this.data[row][col];
        if (row in this.calculated) delete this.calculated[row][col];
        this.clearDependants(cellID);
        this.dependants[cellID] = [];
    }

    clearDependants(id) {
        const deps = this.dependants[id];
        if (!deps) return;

        for (let i = 0; i < deps.length; i++) {
            let remDeps = this.dependencies[deps[i]];
            if (!remDeps) continue;
            let idx = remDeps.indexOf(id);
            if (idx !== -1) remDeps.splice(idx, 1);
        }

        if (!this.context) return;
        this.context.clearDependencies(this, id);
    }

    formatValue(cellID, value) {
        switch (typeof value) {
            case 'string':
                break; // pass

            case 'number':
                if (value === Infinity || value === -1 * Infinity) {
                    return '#DIV/0!';
                }
                if (isNaN(value)) {
                    return '#VALUE!';
                }
                value = value.toString();
                break;

            case 'boolean':
                value = value ? 'TRUE' : 'FALSE';
                break;

            default:
                if (value instanceof Date) {
                    value = value.toLocaleString();
                    break;
                }
                if (value instanceof Error) {
                    return value.message;
                }
                return '#VALUE!';
        }

        return value;
    }

    getCalculatedValueAtID(id) {
        const {row, col} = getCellPos(id);
        return this.getCalculatedValueAtPos(row, col);
    }

    getCalculatedValueAtPos(row, col) {
        if (row in this.calculated) {
            let data = this.calculated[row][col];
            if (data !== null && typeof data !== 'undefined') {
                return parseNumMaybe(data);
            }
        }
        if (row in this.data) {
            let data = this.data[row][col];
            if (data !== null && typeof data !== 'undefined') {
                return parseNumMaybe(data);
            }
        }

        return 0;
    }

    getSheet(name) {
        if (!this.context) {
            throw new Error('No context to extract sheet from');
        }
        name = name.toUpperCase();
        if (!(name in this.context.sheets)) {
            throw new Error('Undefined sheet requested');
        }
        return this.context.sheets[name];
    }

    getValueAtPos(row, col) {
        return (this.data[row] || [])[col] || null;
    }

    insertColumnBefore(idx) {
        this.width += 1;
        for (let i = 0; i < this.height; i++) {
            if (this.data[i]) {
                this.data[i].splice(idx, 0, null);
            }
            if (this.calculated[i]) {
                this.calculated[i].splice(idx, 0, null);
            }
        }
        this.forceRerender();
    }
    insertRowBefore(idx) {
        this.height += 1;
        this.data.splice(idx, 0, new Array(this.width));
        this.calculated.splice(idx, 0, new Array(this.width));
        this.forceRerender();
    }

    loadData(data) {
        while (this.height < data.length) this.addRow(false);
        while (this.width < data[0].length) this.addColumn(false);

        for (let i = 0; i < data.length; i++) {
            this.data[i] = this.data[i] || [];
            for (let j = 0; j < data[i].length; j++) {
                this.setValueAtPosition(i, j, data[i][j], true);
            }
        }
        this.forceRerender();
    }

    popColumn() {
        if (this.width < 2) throw new Error('Cannot make spreadsheet that small');
        this.width -= 1;
        this.columnWidths.pop();
        for (let i = 0; i < this.height; i++) {
            if (this.data[i] && this.data[i].length > this.width) this.data[i].pop();
            if (this.calculated[i] && this.calculated[i].length > this.width) this.calculated[i].pop();
        }
        this.forceRerender();
    }
    popRow() {
        if (this.height < 2) throw new Error('Cannot make spreadsheet that small');
        this.height -= 1;
        this.data.pop();
        this.calculated.pop();
        this.forceRerender();
    }

    removeColumn(idx) {
        if (this.width < 2) throw new Error('Cannot make spreadsheet that small');
        if (idx < 0 || idx >= this.width) throw new Error('Removing cells that do not exist');

        this.width -= 1;
        this.columnWidths.splice(idx, 1);
        for (let i = 0; i < this.height; i++) {
            if (this.data[i]) this.data[i].splice(idx, 1);
            if (this.calculated[i]) this.calculated[i].splice(idx, 1);
        }
        this.forceRerender();
    }
    removeRow(i) {
        if (this.height < 2) throw new Error('Cannot make spreadsheet that small');
        if (i < 0 || i >= this.width) throw new Error('Removing cells that do not exist');

        this.height -= 1;
        this.data.splice(i, 1);
        this.calculated.splice(i, 1);
        this.forceRerender();
    }

    setValueAtPosition(row, col, value, force = false) {
        const cellID = getCellID(row, col);

        this.data[row] = this.data[row] || [];
        if (this.data[row][col] === value && !force) {
            return false;
        }

        this.data[row][col] = value;
        if (this.calculated[row]) {
            delete this.calculated[row][col];
        }

        this.clearDependants(cellID);

        this.valueUpdates.fire(cellID, value);

        if (value[0] === '=') {
            this.calculateValueAtPosition(row, col, value.substr(1));
        } else {
            this.updateDependencies(cellID);
        }

        return true;
    }

    updateDependencies(cellID) {
        const deps = this.dependencies[cellID];
        if (!deps) {
            return;
        }

        if (this.depUpdateQueue) {
            // Iterate each dependency
            for (let dep of deps) {
                // Have we seen this dependency before?
                if (this.calculationSourceGraph) {
                    if (dep in this.calculationSourceGraph) {
                        // If we've seen it referenced from this source before and
                        // iteration is banned, report it.
                        if (!this.iterate &&
                            this.calculationSourceGraph[dep].indexOf(cellID) !== -1) {
                            this.console.fire('error', `Cyclic reference banned at ${cellID} -> ${dep}`);
                            continue;
                        }
                        // If we haven't seen it, mark that we've seen it
                        // referenced from this cell.
                        this.calculationSourceGraph[dep].push(cellID);
                    } else {
                        // If we haven't seen it, create the entry.
                        this.calculationSourceGraph[dep] = [cellID];
                    }
                }

                // If we've already queueued the recalculation of the
                // dependency, don't queue it a second time.
                if (this.depUpdateQueue.indexOf(dep) !== -1) {
                    continue;
                }
                // Otherwise queue the dependency for recalculation.
                this.depUpdateQueue.push(dep);
            }
            return;
        }

        if (!this.iterate) {
            this.calculationSourceGraph = {};
        }
        this.calculationSemaphore = {[cellID]: 1};
        this.depUpdateQueue = [...deps];

        while (this.depUpdateQueue.length) {
            const dep = this.depUpdateQueue.shift();
            const {row, col} = getCellPos(dep);
            this.calculateValueAtPosition(row, col, this.data[row][col].substr(1));
        }

        this.calculationSourceGraph = null;
        this.calculationSemaphore = null;
        this.depUpdateQueue = null;
    }
};
<commit_msg>Remove columnWidths references<commit_after>import Emitter from './Emitter';
import {getCellID, getCellPos} from './cellID';
import parseExpression from './exprCompiler';
import {parseNumMaybe} from './exprCompiler/functions';

const defaultParams = {
    context: null,
    immutable: false,
    name: null,

    height: 6,
    width: 6,

    iterate: true,
    maxIterations: 1000,
    iterationEpsilon: 0.001,
};

const WINDOW_MOUSEUP = Symbol('window.onmouseup');

export default class WebSheet {
    constructor(params = {}) {
        Object.assign(this, defaultParams, params);

        this.data = [];
        this.calculated = [];

        this.calculationSemaphore = null;
        this.calculationSourceGraph = null;
        this.depUpdateQueue = null;
        this.dependencies = {}; // Map of cell ID to array of dependant cell IDs
        this.dependants = {}; // Map of cell ID to array of dependencies

        this.valueUpdates = new Emitter();
        this.calculatedUpdates = new Emitter();
        this.console = new Emitter();
    }

    addColumn(rerender = true) {
        this.width += 1;
        if (rerender) {
            this.forceRerender();
        }
    }
    addRow(rerender = true) {
        this.height += 1;
        this.data.push(new Array(this.width));
        this.calculated.push(new Array(this.width));
        if (rerender) {
            this.forceRerender();
        }
    }

    calculateValueAtPosition(row, col, expression) {
        if (!expression) return;
        const cellID = getCellID(row, col);
        let value;

        // Do some cycle detection.
        if (this.calculationSemaphore) {
            if (cellID in this.calculationSemaphore) {
                if (this.calculationSemaphore[cellID] > this.maxIterations) {
                    this.console.fire('warn', 'Circular reference hit max iteration limit');
                    return;
                }

                this.calculationSemaphore[cellID]++;

            } else {
                this.calculationSemaphore[cellID] = 1;
            }
        }

        // Parse the expression
        const parsed = parseExpression(expression);

        // Evaluate the expression to find a value
        try {
            value = parsed.run(this);
        } catch (e) {
            value = new Error('#ERROR!');
        }

        // Set the calculated value in the calculated cache
        this.calculated[row] = this.calculated[row] || [];

        const origCalculatedValue = this.calculated[row][col];
        const wasUpdated = (
            origCalculatedValue !== value ||
            Math.abs(origCalculatedValue - value) > this.iterationEpsilon
        );

        if (!wasUpdated) {
            return;
        }

        this.calculated[row][col] = value;

        // Set the dependants
        const dependants = [];
        if (parsed) {
            // Bind intra-sheet dependencies
            parsed.findCellDependencies(dep => {
                if (dependants.indexOf(dep) !== -1) return;
                dependants.push(dep);
                if (!(dep in this.dependencies)) {
                    this.dependencies[dep] = [cellID];
                    return;
                }

                const deps = this.dependencies[dep];
                if (deps && deps.indexOf(cellID) === -1) {
                    deps.push(cellID);
                }
            });

            // Bind inter-sheet dependencies if a sheet context exists
            if (this.context) {
                this.context.clearDependencies(this, cellID);
                let sheetDeps = [];
                parsed.findSheetDependencies((sheet, dep) => {
                    if (!this.context.sheets[sheet.toUpperCase()]) return;
                    var depName = `${sheet}!${dep}`;
                    if (sheetDeps.indexOf(depName) !== -1) return;
                    sheetDeps.push(depName);

                    this.context.setDependency(this, cellID, sheet, dep, () => {
                        this.calculateValueAtPosition(row, col, expression);
                    });

                });
            }

        }
        this.dependants[cellID] = dependants;

        this.updateDependencies(cellID);
        this.calculatedUpdates.fire(cellID, value);

        return this.formatValue(cellID, value);
    }

    forceRerender() {
        this.console.fire('log', 'Rerender ignored in headless websheet');
    }

    clearCell(row, col) {
        const cellID = getCellID(row, col);
        if (row in this.data) delete this.data[row][col];
        if (row in this.calculated) delete this.calculated[row][col];
        this.clearDependants(cellID);
        this.dependants[cellID] = [];
    }

    clearDependants(id) {
        const deps = this.dependants[id];
        if (!deps) return;

        for (let i = 0; i < deps.length; i++) {
            let remDeps = this.dependencies[deps[i]];
            if (!remDeps) continue;
            let idx = remDeps.indexOf(id);
            if (idx !== -1) remDeps.splice(idx, 1);
        }

        if (!this.context) return;
        this.context.clearDependencies(this, id);
    }

    formatValue(cellID, value) {
        switch (typeof value) {
            case 'string':
                break; // pass

            case 'number':
                if (value === Infinity || value === -1 * Infinity) {
                    return '#DIV/0!';
                }
                if (isNaN(value)) {
                    return '#VALUE!';
                }
                value = value.toString();
                break;

            case 'boolean':
                value = value ? 'TRUE' : 'FALSE';
                break;

            default:
                if (value instanceof Date) {
                    value = value.toLocaleString();
                    break;
                }
                if (value instanceof Error) {
                    return value.message;
                }
                return '#VALUE!';
        }

        return value;
    }

    getCalculatedValueAtID(id) {
        const {row, col} = getCellPos(id);
        return this.getCalculatedValueAtPos(row, col);
    }

    getCalculatedValueAtPos(row, col) {
        if (row in this.calculated) {
            let data = this.calculated[row][col];
            if (data !== null && typeof data !== 'undefined') {
                return parseNumMaybe(data);
            }
        }
        if (row in this.data) {
            let data = this.data[row][col];
            if (data !== null && typeof data !== 'undefined') {
                return parseNumMaybe(data);
            }
        }

        return 0;
    }

    getSheet(name) {
        if (!this.context) {
            throw new Error('No context to extract sheet from');
        }
        name = name.toUpperCase();
        if (!(name in this.context.sheets)) {
            throw new Error('Undefined sheet requested');
        }
        return this.context.sheets[name];
    }

    getValueAtPos(row, col) {
        return (this.data[row] || [])[col] || null;
    }

    insertColumnBefore(idx) {
        this.width += 1;
        for (let i = 0; i < this.height; i++) {
            if (this.data[i]) {
                this.data[i].splice(idx, 0, null);
            }
            if (this.calculated[i]) {
                this.calculated[i].splice(idx, 0, null);
            }
        }
        this.forceRerender();
    }
    insertRowBefore(idx) {
        this.height += 1;
        this.data.splice(idx, 0, new Array(this.width));
        this.calculated.splice(idx, 0, new Array(this.width));
        this.forceRerender();
    }

    loadData(data) {
        while (this.height < data.length) this.addRow(false);
        while (this.width < data[0].length) this.addColumn(false);

        for (let i = 0; i < data.length; i++) {
            this.data[i] = this.data[i] || [];
            for (let j = 0; j < data[i].length; j++) {
                this.setValueAtPosition(i, j, data[i][j], true);
            }
        }
        this.forceRerender();
    }

    popColumn() {
        if (this.width < 2) throw new Error('Cannot make spreadsheet that small');
        this.width -= 1;
        for (let i = 0; i < this.height; i++) {
            if (this.data[i] && this.data[i].length > this.width) this.data[i].pop();
            if (this.calculated[i] && this.calculated[i].length > this.width) this.calculated[i].pop();
        }
        this.forceRerender();
    }
    popRow() {
        if (this.height < 2) throw new Error('Cannot make spreadsheet that small');
        this.height -= 1;
        this.data.pop();
        this.calculated.pop();
        this.forceRerender();
    }

    removeColumn(idx) {
        if (this.width < 2) throw new Error('Cannot make spreadsheet that small');
        if (idx < 0 || idx >= this.width) throw new Error('Removing cells that do not exist');

        this.width -= 1;
        for (let i = 0; i < this.height; i++) {
            if (this.data[i]) this.data[i].splice(idx, 1);
            if (this.calculated[i]) this.calculated[i].splice(idx, 1);
        }
        this.forceRerender();
    }
    removeRow(i) {
        if (this.height < 2) throw new Error('Cannot make spreadsheet that small');
        if (i < 0 || i >= this.width) throw new Error('Removing cells that do not exist');

        this.height -= 1;
        this.data.splice(i, 1);
        this.calculated.splice(i, 1);
        this.forceRerender();
    }

    setValueAtPosition(row, col, value, force = false) {
        const cellID = getCellID(row, col);

        this.data[row] = this.data[row] || [];
        if (this.data[row][col] === value && !force) {
            return false;
        }

        this.data[row][col] = value;
        if (this.calculated[row]) {
            delete this.calculated[row][col];
        }

        this.clearDependants(cellID);

        this.valueUpdates.fire(cellID, value);

        if (value[0] === '=') {
            this.calculateValueAtPosition(row, col, value.substr(1));
        } else {
            this.updateDependencies(cellID);
        }

        return true;
    }

    updateDependencies(cellID) {
        const deps = this.dependencies[cellID];
        if (!deps) {
            return;
        }

        if (this.depUpdateQueue) {
            // Iterate each dependency
            for (let dep of deps) {
                // Have we seen this dependency before?
                if (this.calculationSourceGraph) {
                    if (dep in this.calculationSourceGraph) {
                        // If we've seen it referenced from this source before and
                        // iteration is banned, report it.
                        if (!this.iterate &&
                            this.calculationSourceGraph[dep].indexOf(cellID) !== -1) {
                            this.console.fire('error', `Cyclic reference banned at ${cellID} -> ${dep}`);
                            continue;
                        }
                        // If we haven't seen it, mark that we've seen it
                        // referenced from this cell.
                        this.calculationSourceGraph[dep].push(cellID);
                    } else {
                        // If we haven't seen it, create the entry.
                        this.calculationSourceGraph[dep] = [cellID];
                    }
                }

                // If we've already queueued the recalculation of the
                // dependency, don't queue it a second time.
                if (this.depUpdateQueue.indexOf(dep) !== -1) {
                    continue;
                }
                // Otherwise queue the dependency for recalculation.
                this.depUpdateQueue.push(dep);
            }
            return;
        }

        if (!this.iterate) {
            this.calculationSourceGraph = {};
        }
        this.calculationSemaphore = {[cellID]: 1};
        this.depUpdateQueue = [...deps];

        while (this.depUpdateQueue.length) {
            const dep = this.depUpdateQueue.shift();
            const {row, col} = getCellPos(dep);
            this.calculateValueAtPosition(row, col, this.data[row][col].substr(1));
        }

        this.calculationSourceGraph = null;
        this.calculationSemaphore = null;
        this.depUpdateQueue = null;
    }
};
<|endoftext|>


<commit_before>'use strict';

(function (angular, buildfire, window) {
    angular
        .module('loyaltyPluginWidget', ['ngRoute', 'ngAnimate'])
        .config(['$routeProvider', '$httpProvider', '$compileProvider', function ($routeProvider, $httpProvider, $compileProvider) {

      /**
       * To make href urls safe on mobile
       */
      $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension|cdvfile|file):/);

            var interceptor = ['$q', function ($q) {
                var counter = 0;
                return {
                    request: function (config) {
                        console.log('Showing spinner-----------------------------------------------------------------------');
                        buildfire.spinner.show();
                        counter++;
                        return config;
                    },
                    response: function (response) {
                        counter--;
                        if (counter === 0) {
                            console.log('Hiding spinner-----------------------------Success------------------------------------------');
                            buildfire.spinner.hide();
                        }
                        return response;
                    },
                    responseError: function (rejection) {
                        counter--;
                        if (counter === 0) {
                            console.log('Hiding spinner-----------------------Rejection------------------------------------------------');
                            buildfire.spinner.hide();
                        }

                        return $q.reject(rejection);
                    }
                };
            }];

            $httpProvider.interceptors.push(interceptor);

        }])
        .directive("viewSwitcher", ["ViewStack", "$rootScope", '$compile',
            function (ViewStack, $rootScope, $compile) {
                return {
                    restrict: 'AE',
                    link: function (scope, elem, attrs) {
                        var views = 0,
                            currentView = null;
                        manageDisplay();
                        $rootScope.$on('VIEW_CHANGED', function (e, type, view, noAnimation) {
                            if (type === 'PUSH') {
                                console.log("VIEW_CHANGED>>>>>>>>");
                                currentView = ViewStack.getPreviousView();

                var _el = $("").attr("href", "javascript:void(0)"),
                  oldTemplate = $('#' + currentView.template);

                oldTemplate.append(_el);

                oldTemplate.find("input[type=number], input[type=password], input[type=text]").each(function () {
                  $(this).blur().attr("disabled", "disabled");
                });

                $(document.activeElement).blur();
                _el.focus();

                var newScope = $rootScope.$new();
                var _newView = '

';
                var parTpl = $compile(_newView)(newScope);

                $(elem).append(parTpl);
                views++;

              } else if (type === 'POP') {

                var _elToRemove = $(elem).find('#' + view.template),
                  _child = _elToRemove.children("div").eq(0);

                _child.addClass("ng-leave ng-leave-active");
                _child.one("webkitTransitionEnd transitionend oTransitionEnd", function (e) {
                  _elToRemove.remove();
                  views--;
                });

                currentView = ViewStack.getCurrentView();
                $('#' + currentView.template).find("input[type=number], input[type=password], input[type=text]").each(function () {
                  $(this).removeAttr("disabled");
                });

              } else if (type === 'POPALL') {
                angular.forEach(view, function (value, key) {
                  var _elToRemove = $(elem).find('#' + value.template),
                    _child = _elToRemove.children("div").eq(0);

                  if (!noAnimation) {
                    _child.addClass("ng-leave ng-leave-active");
                    _child.one("webkitTransitionEnd transitionend oTransitionEnd", function (e) {
                      _elToRemove.remove();
                      views--;
                    });
                  } else {
                    _elToRemove.remove();
                    views--;
                  }
                });
              }
              manageDisplay();
            });

            function manageDisplay() {
              if (views) {
                $(elem).removeClass("ng-hide");
              } else {
                $(elem).addClass("ng-hide");
              }
            }

          }
        };
      }])
    .filter('cropImage', [function () {
      return function (url, width, height, noDefault) {
        if (noDefault) {
          if (!url)
            return '';
        }
        return buildfire.imageLib.cropImage(url, {
          width: width,
          height: height
        });
      };
    }])
    .directive('backImg', ["$filter", "$rootScope", function ($filter, $rootScope) {
      return function (scope, element, attrs) {
        attrs.$observe('backImg', function (value) {
          var img = '';
          if (value) {
            img = $filter("cropImage")(value, $rootScope.deviceWidth, $rootScope.deviceHeight, true);
            element.attr("style", 'background:url(' + img + ') !important');
            element.css({
              'background-size': 'cover'
            });
          }
          else {
            img = "";
            element.attr("style", 'background-color:white');
            element.css({
              'background-size': 'cover'
            });
          }
        });
      };
    }])
    .directive("buildFireCarousel", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel:LOADED");
        }
      };
    }])
    .directive("buildFireCarousel2", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel2:LOADED");
        }
      };
    }])
    .directive("buildFireCarousel3", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel3:LOADED");
        }
      };
    }])
    .directive("buildFireCarousel4", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel4:LOADED");
        }
      };
    }])
    .directive('getFocus', ["$timeout", function ($timeout) {
      return {
        link: function (scope, element, attrs) {
          $(element).parents(".slide").eq(0).on("webkitTransitionEnd transitionend oTransitionEnd", function () {
            $timeout(function () {
              $(element).focus();
            }, 300);
            //open keyboard manually
            if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
              window.cordova.plugins.Keyboard.show();
            }

            $(element).on('blur', function () {
              //open keyboard manually
              if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
                window.cordova.plugins.Keyboard.hide();
              }
            });
          });

          scope.$on("$destroy", function () {
            $(element).parents(".slide").eq(0).off("webkitTransitionEnd transitionend oTransitionEnd", "**");
          });
        }
      }
    }])
    .directive("loadImage", [function () {
      return {
        restrict: 'A',
        link: function (scope, element, attrs) {
          element.attr("src","assets/images/" + attrs.loadImage + ".png");

          var elem = $("");
          elem[0].onload = function () {
            element.attr("src", attrs.finalSrc);
            elem.remove();
          };
          elem.attr("src", attrs.finalSrc);
        }
      };
    }])
    .filter('getImageUrl', function () {
      return function (url, width, height, type) {
        if (type == 'resize')
          return buildfire.imageLib.resizeImage(url, {
            width: width,
            height: height
          });
        else
          return buildfire.imageLib.cropImage(url, {
            width: width,
            height: height
          });
      }
    })
    .run(['Location', '$location', '$rootScope', 'RewardCache', 'ViewStack', 'Context',
      function (Location, $location, $rootScope, RewardCache, ViewStack, Context) {
        buildfire.messaging.onReceivedMessage = function (msg) {
          switch (msg.type) {
            case 'AddNewItem':
              RewardCache.setReward(msg.data);
              ViewStack.popAllViews(true);
              ViewStack.push({
                template: 'Item_Details',
                totalPoints: $rootScope.loyaltyPoints
              });
              $rootScope.$broadcast("REWARD_ADDED", msg.data);
              $rootScope.$apply();
              break;

            case 'OpenItem':
              RewardCache.setReward(msg.data);
              ViewStack.popAllViews(true);
              ViewStack.push({
                template: 'Item_Details',
                totalPoints: $rootScope.loyaltyPoints
              });
              $rootScope.$apply();
              break;

            case 'UpdateItem':
              RewardCache.setReward(msg.data);
              $rootScope.$broadcast("REWARD_UPDATED", msg.data);
              $rootScope.$apply();
              break;

            case 'RemoveItem':
              $rootScope.$broadcast("REWARD_DELETED", msg.index);
              $rootScope.$apply();
              break;

            case 'ListSorted':
              $rootScope.$broadcast("REWARDS_SORTED");
              $rootScope.$apply();
              break;

            case 'UpdateApplication':
              $rootScope.$broadcast("APPLICATION_UPDATED", msg.data);
              $rootScope.$apply();
              break;

            case 'ReturnHome':
              $rootScope.$broadcast("GOTO_HOME");
              $rootScope.$apply();
              break;

            case 'AppCreated':
              $rootScope.$broadcast("REFRESH_APP");
              $rootScope.$apply();
              break;
          }
        };

        buildfire.navigation.onBackButtonClick = function () {
          if (ViewStack.hasViews()) {
            if (ViewStack.getCurrentView().template == 'Item_Details') {
              buildfire.messaging.sendMessageToControl({
                type: 'BackToHome'
              });
            }
            ViewStack.pop();
          } else {
            buildfire.navigation.navigateHome();
          }
        };

      }])
})(window.angular, window.buildfire, window);<commit_msg>Made changes required for issue: #1752<commit_after>'use strict';

(function (angular, buildfire, window) {
    angular
        .module('loyaltyPluginWidget', ['ngRoute', 'ngAnimate'])
        .config(['$routeProvider', '$httpProvider', '$compileProvider', function ($routeProvider, $httpProvider, $compileProvider) {

      /**
       * To make href urls safe on mobile
       */
      $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension|cdvfile|file):/);

            var interceptor = ['$q', function ($q) {
                var counter = 0;
                return {
                    request: function (config) {
                        console.log('Showing spinner-----------------------------------------------------------------------');
                        buildfire.spinner.show();
                        counter++;
                        return config;
                    },
                    response: function (response) {
                        counter--;
                        if (counter === 0) {
                            console.log('Hiding spinner-----------------------------Success------------------------------------------');
                            buildfire.spinner.hide();
                        }
                        return response;
                    },
                    responseError: function (rejection) {
                        counter--;
                        if (counter === 0) {
                            console.log('Hiding spinner-----------------------Rejection------------------------------------------------');
                            buildfire.spinner.hide();
                        }

                        return $q.reject(rejection);
                    }
                };
            }];

            $httpProvider.interceptors.push(interceptor);

        }])
        .directive("viewSwitcher", ["ViewStack", "$rootScope", '$compile',
            function (ViewStack, $rootScope, $compile) {
                return {
                    restrict: 'AE',
                    link: function (scope, elem, attrs) {
                        var views = 0,
                            currentView = null;
                        manageDisplay();
                        $rootScope.$on('VIEW_CHANGED', function (e, type, view, noAnimation) {
                            if (type === 'PUSH') {
                                console.log("VIEW_CHANGED>>>>>>>>");
                                currentView = ViewStack.getPreviousView();

                var _el = $("").attr("href", "javascript:void(0)"),
                  oldTemplate = $('#' + currentView.template);

                oldTemplate.append(_el);

                oldTemplate.find("input[type=number], input[type=password], input[type=text]").each(function () {
                  $(this).blur().attr("disabled", "disabled");
                });

                $(document.activeElement).blur();
                _el.focus();

                var newScope = $rootScope.$new();
                var _newView = '

';
                var parTpl = $compile(_newView)(newScope);

                $(elem).append(parTpl);
                views++;

              } else if (type === 'POP') {

                var _elToRemove = $(elem).find('#' + view.template),
                  _child = _elToRemove.children("div").eq(0);

                _child.addClass("ng-leave ng-leave-active");
                _child.one("webkitTransitionEnd transitionend oTransitionEnd", function (e) {
                  _elToRemove.remove();
                  views--;
                });

                currentView = ViewStack.getCurrentView();
                $('#' + currentView.template).find("input[type=number], input[type=password], input[type=text]").each(function () {
                  $(this).removeAttr("disabled");
                });

              } else if (type === 'POPALL') {
                angular.forEach(view, function (value, key) {
                  var _elToRemove = $(elem).find('#' + value.template),
                    _child = _elToRemove.children("div").eq(0);

                  if (!noAnimation) {
                    _child.addClass("ng-leave ng-leave-active");
                    _child.one("webkitTransitionEnd transitionend oTransitionEnd", function (e) {
                      _elToRemove.remove();
                      views--;
                    });
                  } else {
                    _elToRemove.remove();
                    views--;
                  }
                });
              }
              manageDisplay();
            });

            function manageDisplay() {
              if (views) {
                $(elem).removeClass("ng-hide");
              } else {
                $(elem).addClass("ng-hide");
              }
            }

          }
        };
      }])
    .filter('cropImage', [function () {
      return function (url, width, height, noDefault) {
        if (noDefault) {
          if (!url)
            return '';
        }
        return buildfire.imageLib.cropImage(url, {
          width: width,
          height: height
        });
      };
    }])
    .directive('backImg', ["$filter", "$rootScope", function ($filter, $rootScope) {
      return function (scope, element, attrs) {
        attrs.$observe('backImg', function (value) {
          var img = '';
          if (value) {
            img = $filter("cropImage")(value, $rootScope.deviceWidth, $rootScope.deviceHeight, true);
            element.attr("style", 'background:url(' + img + ') !important');
            element.css({
              'background-size': 'cover'
            });
          }
          else {
            img = "";
            element.attr("style", 'background-color:white');
            element.css({
              'background-size': 'cover'
            });
          }
        });
      };
    }])
    .directive("buildFireCarousel", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel:LOADED");
        }
      };
    }])
    .directive("buildFireCarousel2", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel2:LOADED");
        }
      };
    }])
    .directive("buildFireCarousel3", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel3:LOADED");
        }
      };
    }])
    .directive("buildFireCarousel4", ["$rootScope", function ($rootScope) {
      return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
          $rootScope.$broadcast("Carousel4:LOADED");
        }
      };
    }])
    .directive('getFocus', ["$timeout", function ($timeout) {
      return {
        link: function (scope, element, attrs) {
          $(element).parents(".slide").eq(0).on("webkitTransitionEnd transitionend oTransitionEnd", function () {
            $timeout(function () {
              $(element).focus();
            }, 300);
            //open keyboard manually
            if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
              window.cordova.plugins.Keyboard.show();
            }

            $(element).on('blur', function () {
              //open keyboard manually
              if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
                window.cordova.plugins.Keyboard.hide();
              }
            });
          });

          scope.$on("$destroy", function () {
            $(element).parents(".slide").eq(0).off("webkitTransitionEnd transitionend oTransitionEnd", "**");
          });
        }
      }
    }])
    .directive("loadImage", [function () {
      return {
        restrict: 'A',
        link: function (scope, element, attrs) {
          element.attr("src","assets/images/" + attrs.loadImage + ".png");

          var elem = $("");
          elem[0].onload = function () {
            element.attr("src", attrs.finalSrc);
            elem.remove();
          };
          elem.attr("src", attrs.finalSrc);
        }
      };
    }])
    .filter('getImageUrl', function () {
      return function (url, width, height, type) {
        if (type == 'resize')
          return buildfire.imageLib.resizeImage(url, {
            width: width,
            height: height
          });
        else
          return buildfire.imageLib.cropImage(url, {
            width: width,
            height: height
          });
      }
    })
    .run(['Location', '$location', '$rootScope', 'RewardCache', 'ViewStack', 'Context',
      function (Location, $location, $rootScope, RewardCache, ViewStack, Context) {
        buildfire.messaging.onReceivedMessage = function (msg) {
          switch (msg.type) {
            case 'AddNewItem':
              RewardCache.setReward(msg.data);
              ViewStack.popAllViews(true);
              ViewStack.push({
                template: 'Item_Details',
                totalPoints: $rootScope.loyaltyPoints
              });
              $rootScope.$broadcast("REWARD_ADDED", msg.data);
              $rootScope.$apply();
              break;

            case 'OpenItem':
              RewardCache.setReward(msg.data);
              ViewStack.popAllViews(true);
              ViewStack.push({
                template: 'Item_Details',
                totalPoints: $rootScope.loyaltyPoints
              });
              $rootScope.$apply();
              break;

            case 'UpdateItem':
              RewardCache.setReward(msg.data);
              $rootScope.$broadcast("REWARD_UPDATED", msg.data);
              $rootScope.$apply();
              break;

            case 'RemoveItem':
              $rootScope.$broadcast("REWARD_DELETED", msg.index);
              $rootScope.$apply();
              break;

            case 'ListSorted':
              $rootScope.$broadcast("REWARDS_SORTED");
              $rootScope.$apply();
              break;

            case 'UpdateApplication':
              $rootScope.$broadcast("APPLICATION_UPDATED", msg.data);
              $rootScope.$apply();
              break;

            case 'ReturnHome':
              $rootScope.$broadcast("GOTO_HOME");
              $rootScope.$apply();
              break;

            case 'AppCreated':
              $rootScope.$broadcast("REFRESH_APP");
              $rootScope.$apply();
              break;
          }
        };

        buildfire.navigation.onBackButtonClick = function () {
          if (ViewStack.hasViews()) {
            if (ViewStack.getCurrentView().template == 'Item_Details') {
              buildfire.messaging.sendMessageToControl({
                type: 'BackToHome'
              });
            }
            ViewStack.pop();
          } else {
              buildfire.navigation._goBackOne();
          }
        };

      }])
})(window.angular, window.buildfire, window);<|endoftext|>


<commit_before>/*@flow*/
/*::
const define = (x:any, y:any) => {};
const require = define;
*/
define([
    '/api/config',
    '/bower_components/nthen/index.js'
], function (Config, nThen) { /*::});module.exports = (function() {
    const Config = (undefined:any);
    const nThen = (undefined:any);
    */

    var module = { exports: {} };
    var key = Config.requireConf.urlArgs;
    var localStorage = {};
    if (!window.cryptpadCache) {
        try {
            localStorage = window.localStorage || {};
            if (localStorage['LESS_CACHE'] !== key) {
                Object.keys(localStorage).forEach(function (k) {
                    if (k.indexOf('LESS_CACHE|') !== 0) { return; }
                    delete localStorage[k];
                });
                localStorage['LESS_CACHE'] = key;
            }
        } catch (e) {
            console.error(e);
            localStorage = {};
        }
    }

    var cacheGet = function (k, cb) {
        if (window.cryptpadCache) { return void window.cryptpadCache.get(k, cb); }
        setTimeout(function () { cb(localStorage['LESS_CACHE|' + key + '|' + k]); });
    };
    var cachePut = function (k, v, cb) {
        if (window.cryptpadCache) { return void window.cryptpadCache.put(k, v, cb); }
        setTimeout(function () {
            localStorage['LESS_CACHE|' + key + '|' + k] = v;
            if (cb) { cb(); }
        });
    };

    var fixURL = function (url, parent) {
        // data: blob: etc
        if (/^[a-zA-Z0-9]*:/.test(url)) { return url; }
        var ua = url.split('#');
        var mark = (ua[0].indexOf('?') !== -1) ? '&' : '?';
        ua[0] = ua[0] + mark + key;
        if (ua[0].indexOf(':') === -1 && ua[0].indexOf('/') && parent) {
            ua[0] = parent.replace(/\/[^\/]*$/, '/') + ua[0];
        }
        ua[0] = ua[0].replace(/^\/\.\.\//, '/');
        var out = ua.join('#');
        //console.log(url + "  -->  " + out);
        return out;
    };

    var inject = function (cssText /*:string*/, url) {
        var curStyle = document.createElement('style');
        curStyle.setAttribute('data-original-src', url);
        curStyle.type = 'text/css';
        curStyle.appendChild(document.createTextNode(cssText));
        if (!document.head) { throw new Error(); }
        document.head.appendChild(curStyle);
    };

    var fixAllURLs = function (source /*:string*/, parent) {
        var urlRegEx = /@import\s*("([^"]*)"|'([^']*)')|url\s*\(\s*(\s*"([^"]*)"|'([^']*)'|[^\)]*\s*)\s*\)/ig;
        var result, url;

        while (!!(result = urlRegEx.exec(source))) {
            url = result[3] || result[2] || result[5] || result[6] || result[4];
            var newUrl = fixURL(url, parent);
            var quoteLen = result[5] || result[6] ? 1 : 0;
            source = source.substr(0, urlRegEx.lastIndex - url.length - quoteLen - 1)
               + newUrl + source.substr(urlRegEx.lastIndex - quoteLen - 1);
            urlRegEx.lastIndex = urlRegEx.lastIndex + (newUrl.length - url.length);
        }

        return source;
    };

    var loadCSS = function (url, cb) {
        var xhr = new window.XMLHttpRequest();
        xhr.open("GET", fixURL(url), true);
        xhr.responseType = 'text';
        xhr.onload = function () {
            if (/^4/.test('' + this.status)) { return cb("error loading " + url); }
            cb(undefined, xhr.response);
        };
        xhr.send(null);
    };

    var COLORTHEME = '/customize/src/less2/include/colortheme.less';
    var COLORTHEME_DARK = '/customize/src/less2/include/colortheme-dark.less';
    var getColorthemeURL = function () {
        if (window.CryptPad_theme === 'dark') { return COLORTHEME_DARK; }
        return COLORTHEME;
    };

    var lessEngine;
    var tempCache = { key: Math.random() };
    var getLessEngine = function (cb) {
        if (lessEngine) {
            cb(lessEngine);
        } else {
            require(['/common/less.min.js'], function (Less) {
                if (lessEngine) { return void cb(lessEngine); }
                lessEngine = Less;
                Less.functions.functionRegistry.add('LessLoader_currentFile', function () {
                    return new Less.tree.UnicodeDescriptor('"' +
                        fixURL(this.currentFileInfo.filename) + '"');
                });
                var doXHR = lessEngine.FileManager.prototype.doXHR;
                lessEngine.FileManager.prototype.doXHR = function (url, type, callback, errback) {
                    console.error(url, COLORTHEME); // XXX
                    var col = false;
                    if (url === COLORTHEME) {
                        col = true;
                        url = getColorthemeURL();
                        console.warn(url);
                    }
                    url = fixURL(url);
                    var cached = tempCache[url];
                    if (cached && cached.res) {
                        var res = cached.res;
                        return void setTimeout(function () { callback(res[0], res[1]); });
                    }
                    if (cached) { return void cached.queue.push(callback); }
                    cached = tempCache[url] = { queue: [ callback ], res: undefined };
                    return doXHR(url, type, function (text, lastModified) {
                        if (col) {
                            console.warn(text, lastModified);
                            // XXX COLOR: append custom theme here
                        }
                        cached.res = [ text, lastModified ];
                        var queue = cached.queue;
                        cached.queue = [];
                        queue.forEach(function (f) {
                            setTimeout(function () { f(text, lastModified); });
                        });
                    }, errback);
                };
                cb(lessEngine);
            });
        }
    };

    var loadLess = function (url, cb) {
        getLessEngine(function (less) {
            less.render('@import (multiple) "' + url + '";', {}, function(err, css) {
                if (err) { return void cb(err); }
                cb(undefined, css.css);
            }, window.less);
        });
    };

    var loadSubmodulesAndInject = function (css, url, cb, stack) {
        inject(css, url);
        nThen(function (w) {
            css.replace(/\-\-LessLoader_require\:\s*"([^"]*)"\s*;/g, function (all, u) {
                u = u.replace(/\?.*$/, '');
                module.exports.load(u, w(), stack);
                return '';
            });
        }).nThen(function () { cb(); });
    };

    var idx = 0;
    module.exports.load = function (url /*:string*/, cb /*:()=>void*/, stack /*:?Array<string>*/) {
        var btime = stack ? null : +new Date();
        stack = stack || [];
        if (stack.indexOf(url) > -1) { return void cb(); }
        var timeout = setTimeout(function () { console.log('failed', url); }, 10000);
        var done = function () {
            clearTimeout(timeout);
            if (btime) {
                console.info("Compiling [" + url + "] took " + (+new Date() - btime) + "ms");
            }
            cb();
        };
        stack.push(url);
        if (window.CryptPad_updateLoadingProgress) {
            window.CryptPad_updateLoadingProgress({
                type: 'less',
                progress: 4*idx++
            });
        }
        cacheGet(url, function (css) {
            if (css) { return void loadSubmodulesAndInject(css, url, done, stack); }
            console.debug('CACHE MISS ' + url);
            ((/\.less([\?\#].*)?$/.test(url)) ? loadLess : loadCSS)(url, function (err, css) {
                if (!css) {
                    if (window.CryptPad_loadingError) {
                        window.CryptPad_loadingError('LESS: ' + (err && err.message));
                    }
                    return void console.error(err);
                }
                var output = fixAllURLs(css, url);
                cachePut(url, output);
                loadSubmodulesAndInject(output, url, done, stack);
            });
        });
    };

    return module.exports;
})/*::()*/;
<commit_msg>Add custom colortheme<commit_after>/*@flow*/
/*::
const define = (x:any, y:any) => {};
const require = define;
*/
define([
    '/api/config',
    '/bower_components/nthen/index.js'
], function (Config, nThen) { /*::});module.exports = (function() {
    const Config = (undefined:any);
    const nThen = (undefined:any);
    */

    var module = { exports: {} };
    var key = Config.requireConf.urlArgs;
    var localStorage = {};
    if (!window.cryptpadCache) {
        try {
            localStorage = window.localStorage || {};
            if (localStorage['LESS_CACHE'] !== key) {
                Object.keys(localStorage).forEach(function (k) {
                    if (k.indexOf('LESS_CACHE|') !== 0) { return; }
                    delete localStorage[k];
                });
                localStorage['LESS_CACHE'] = key;
            }
        } catch (e) {
            console.error(e);
            localStorage = {};
        }
    }

    var cacheGet = function (k, cb) {
        if (window.cryptpadCache) { return void window.cryptpadCache.get(k, cb); }
        setTimeout(function () { cb(localStorage['LESS_CACHE|' + key + '|' + k]); });
    };
    var cachePut = function (k, v, cb) {
        if (window.cryptpadCache) { return void window.cryptpadCache.put(k, v, cb); }
        setTimeout(function () {
            localStorage['LESS_CACHE|' + key + '|' + k] = v;
            if (cb) { cb(); }
        });
    };

    var fixURL = function (url, parent) {
        // data: blob: etc
        if (/^[a-zA-Z0-9]*:/.test(url)) { return url; }
        var ua = url.split('#');
        var mark = (ua[0].indexOf('?') !== -1) ? '&' : '?';
        ua[0] = ua[0] + mark + key;
        if (ua[0].indexOf(':') === -1 && ua[0].indexOf('/') && parent) {
            ua[0] = parent.replace(/\/[^\/]*$/, '/') + ua[0];
        }
        ua[0] = ua[0].replace(/^\/\.\.\//, '/');
        var out = ua.join('#');
        //console.log(url + "  -->  " + out);
        return out;
    };

    var inject = function (cssText /*:string*/, url) {
        var curStyle = document.createElement('style');
        curStyle.setAttribute('data-original-src', url);
        curStyle.type = 'text/css';
        curStyle.appendChild(document.createTextNode(cssText));
        if (!document.head) { throw new Error(); }
        document.head.appendChild(curStyle);
    };

    var fixAllURLs = function (source /*:string*/, parent) {
        var urlRegEx = /@import\s*("([^"]*)"|'([^']*)')|url\s*\(\s*(\s*"([^"]*)"|'([^']*)'|[^\)]*\s*)\s*\)/ig;
        var result, url;

        while (!!(result = urlRegEx.exec(source))) {
            url = result[3] || result[2] || result[5] || result[6] || result[4];
            var newUrl = fixURL(url, parent);
            var quoteLen = result[5] || result[6] ? 1 : 0;
            source = source.substr(0, urlRegEx.lastIndex - url.length - quoteLen - 1)
               + newUrl + source.substr(urlRegEx.lastIndex - quoteLen - 1);
            urlRegEx.lastIndex = urlRegEx.lastIndex + (newUrl.length - url.length);
        }

        return source;
    };

    var loadCSS = function (url, cb) {
        var xhr = new window.XMLHttpRequest();
        xhr.open("GET", fixURL(url), true);
        xhr.responseType = 'text';
        xhr.onload = function () {
            if (/^4/.test('' + this.status)) { return cb("error loading " + url); }
            cb(undefined, xhr.response);
        };
        xhr.send(null);
    };

    var COLORTHEME = '/customize/src/less2/include/colortheme.less';
    var COLORTHEME_DARK = '/customize/src/less2/include/colortheme-dark.less';
    var getColortheme = function () {
        return window.CryptPad_theme;
    };
    var getColorthemeURL = function () {
        if (window.CryptPad_theme === 'dark') { return COLORTHEME_DARK; }
        return COLORTHEME;
    };

    var lessEngine;
    var tempCache = { key: Math.random() };
    var getLessEngine = function (cb) {
        if (lessEngine) {
            cb(lessEngine);
        } else {
            require(['/common/less.min.js'], function (Less) {
                if (lessEngine) { return void cb(lessEngine); }
                lessEngine = Less;
                Less.functions.functionRegistry.add('LessLoader_currentFile', function () {
                    return new Less.tree.UnicodeDescriptor('"' +
                        fixURL(this.currentFileInfo.filename) + '"');
                });
                var doXHR = lessEngine.FileManager.prototype.doXHR;
                lessEngine.FileManager.prototype.doXHR = function (url, type, callback, errback) {
                    console.error(url, COLORTHEME); // XXX
                    var col = false;
                    if (url === COLORTHEME) {
                        col = true;
                        url = getColorthemeURL();
                        console.warn(url);
                    }
                    url = fixURL(url);
                    var cached = tempCache[url];
                    if (cached && cached.res) {
                        var res = cached.res;
                        return void setTimeout(function () { callback(res[0], res[1]); });
                    }
                    if (cached) { return void cached.queue.push(callback); }
                    cached = tempCache[url] = { queue: [ callback ], res: undefined };
                    return doXHR(url, type, function (text, lastModified) {
                        if (col) {
                            console.warn(text, lastModified);
                            if (getColortheme() === "custom") {
                                // XXX COLOR: append custom theme here
                                var custom = [
                                    '@cryptpad_text_col: #FF0000;'
                                ].join('\n');
                                text += '\n'+custom;
                            }
                        }
                        cached.res = [ text, lastModified ];
                        var queue = cached.queue;
                        cached.queue = [];
                        queue.forEach(function (f) {
                            setTimeout(function () { f(text, lastModified); });
                        });
                    }, errback);
                };
                cb(lessEngine);
            });
        }
    };

    var loadLess = function (url, cb) {
        getLessEngine(function (less) {
            less.render('@import (multiple) "' + url + '";', {}, function(err, css) {
                if (err) { return void cb(err); }
                cb(undefined, css.css);
            }, window.less);
        });
    };

    var loadSubmodulesAndInject = function (css, url, cb, stack) {
        inject(css, url);
        nThen(function (w) {
            css.replace(/\-\-LessLoader_require\:\s*"([^"]*)"\s*;/g, function (all, u) {
                u = u.replace(/\?.*$/, '');
                module.exports.load(u, w(), stack);
                return '';
            });
        }).nThen(function () { cb(); });
    };

    var idx = 0;
    module.exports.load = function (url /*:string*/, cb /*:()=>void*/, stack /*:?Array<string>*/) {
        var btime = stack ? null : +new Date();
        stack = stack || [];
        if (stack.indexOf(url) > -1) { return void cb(); }
        var timeout = setTimeout(function () { console.log('failed', url); }, 10000);
        var done = function () {
            clearTimeout(timeout);
            if (btime) {
                console.info("Compiling [" + url + "] took " + (+new Date() - btime) + "ms");
            }
            cb();
        };
        stack.push(url);
        if (window.CryptPad_updateLoadingProgress) {
            window.CryptPad_updateLoadingProgress({
                type: 'less',
                progress: 4*idx++
            });
        }
        cacheGet(url, function (css) {
            if (css) { return void loadSubmodulesAndInject(css, url, done, stack); }
            console.debug('CACHE MISS ' + url);
            ((/\.less([\?\#].*)?$/.test(url)) ? loadLess : loadCSS)(url, function (err, css) {
                if (!css) {
                    if (window.CryptPad_loadingError) {
                        window.CryptPad_loadingError('LESS: ' + (err && err.message));
                    }
                    return void console.error(err);
                }
                var output = fixAllURLs(css, url);
                cachePut(url, output);
                loadSubmodulesAndInject(output, url, done, stack);
            });
        });
    };

    return module.exports;
})/*::()*/;
<|endoftext|>


<commit_before>'use strict'
describe('getting the list of notebooks', function() {
  var subject

  before('set up stubs', function() {
    var Task = require('data.task')

    var getConfig = td.replace('./getConfig')

    getConfig.getConfig = Task.of({ quiverpath: 'foo' })

    var fileUtils = td.replace('./utils/fileUtils')
    td.when(fileUtils.readFile('foo/meta.json')).thenReturn(
      Task.of(
        JSON.stringify({
          children: [{ uuid: 'foodircontents' }, { uuid: 'bardircontents' }]
        })
      )
    )

    subject = require('./getNotebooks')
  })

  context('first run', function() {
    it('should be ok', function(done) {
      subject.getNotebooks.fork(console.error, t => {
        expect(t).to.eql(['foo/foodircontents', 'foo/bardircontents'])
        done()
      })
    })
  })
})
<commit_msg>getNoteBooks test rewritten<commit_after>const { task } = require('folktale/concurrency/task')
jest.mock('./getConfig')
var getConfig = require('./getConfig')
jest.mock('./utils/fileUtils')
var fileUtils = require('./utils/fileUtils')

console.log('mocked normally')
test('getting the list of notebooks', done => {
  const getConfigTask = task(resolver =>
    resolver.resolve({ quiverpath: 'foo' })
  )
  getConfig.mockReturnValue(getConfigTask)

  const readFileTask = task(resolver =>
    resolver.resolve(
      JSON.stringify({
        children: [{ uuid: 'foodircontents' }, { uuid: 'bardircontents' }]
      })
    )
  )
  fileUtils.readFile.mockReturnValue(readFileTask)

  // ***********************

  var subject = require('./getNotebooks')
  subject.run().listen({
    onResolved: t => {
      expect(t).to.eql(['foo/foodircontents', 'foo/bardircontents'])
      done()
    }
  })
})
<|endoftext|>


<commit_before>/* eslint-env mocha */
const InsertionSort = require('../../../src').Algorithms.Sorting.InsertionSort;
const assert = require('assert');

describe('Insertion Sort', () => {
  it('should have no data when empty initialization', () => {
    const inst = new InsertionSort();
    assert.equal(inst.size, 0);
    assert.deepEqual(inst.unsortedList, []);
    assert.deepEqual(inst.sortedList, []);
  });

  it('should sort the array', () => {
    const inst = new InsertionSort([2, 1, 3, 4]);
    assert.equal(inst.size, 4);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4]);
    assert.deepEqual(inst.sortedList, [1, 2, 3, 4]);
    assert.equal(inst.toString(), '1, 2, 3, 4');
  });

  it('should sort the array in ascending order with few equal vals', () => {
    const inst = new InsertionSort([2, 1, 3, 4, 2], (a, b) => a < b);
    assert.equal(inst.size, 5);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4, 2]);
    assert.deepEqual(inst.sortedList, [1, 2, 2, 3, 4]);
    assert.equal(inst.toString(), '1, 2, 2, 3, 4');
  });

  it('should sort 2 element array', () => {
    const inst = new InsertionSort([2, 1]);
    assert.equal(inst.size, 2);

    assert.deepEqual(inst.unsortedList, [2, 1]);
    assert.deepEqual(inst.sortedList, [1, 2]);
    assert.equal(inst.toString(), '1, 2');
  });

  it('should sort 1 element array', () => {
    const inst = new InsertionSort([1]);
    assert.equal(inst.size, 1);

    assert.deepEqual(inst.unsortedList, [1]);
    assert.deepEqual(inst.sortedList, [1]);
    assert.equal(inst.toString(), '1');
  });

  it('should sort the array in decending order', () => {
    const inst = new InsertionSort([2, 1, 3, 4], (a, b) => a > b);
    assert.equal(inst.size, 4);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4]);
    assert.deepEqual(inst.sortedList, [4, 3, 2, 1]);
    assert.equal(inst.toString(), '4, 3, 2, 1');
  });

});
<commit_msg>Test Insertion Sort: Sort in descending order with equal values<commit_after>/* eslint-env mocha */
const InsertionSort = require('../../../src').Algorithms.Sorting.InsertionSort;
const assert = require('assert');

describe('Insertion Sort', () => {
  it('should have no data when empty initialization', () => {
    const inst = new InsertionSort();
    assert.equal(inst.size, 0);
    assert.deepEqual(inst.unsortedList, []);
    assert.deepEqual(inst.sortedList, []);
  });

  it('should sort the array', () => {
    const inst = new InsertionSort([2, 1, 3, 4]);
    assert.equal(inst.size, 4);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4]);
    assert.deepEqual(inst.sortedList, [1, 2, 3, 4]);
    assert.equal(inst.toString(), '1, 2, 3, 4');
  });

  it('should sort the array in ascending order with few equal vals', () => {
    const inst = new InsertionSort([2, 1, 3, 4, 2], (a, b) => a < b);
    assert.equal(inst.size, 5);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4, 2]);
    assert.deepEqual(inst.sortedList, [1, 2, 2, 3, 4]);
    assert.equal(inst.toString(), '1, 2, 2, 3, 4');
  });

  it('should sort 2 element array', () => {
    const inst = new InsertionSort([2, 1]);
    assert.equal(inst.size, 2);

    assert.deepEqual(inst.unsortedList, [2, 1]);
    assert.deepEqual(inst.sortedList, [1, 2]);
    assert.equal(inst.toString(), '1, 2');
  });

  it('should sort 1 element array', () => {
    const inst = new InsertionSort([1]);
    assert.equal(inst.size, 1);

    assert.deepEqual(inst.unsortedList, [1]);
    assert.deepEqual(inst.sortedList, [1]);
    assert.equal(inst.toString(), '1');
  });

  it('should sort the array in decending order', () => {
    const inst = new InsertionSort([2, 1, 3, 4], (a, b) => a > b);
    assert.equal(inst.size, 4);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4]);
    assert.deepEqual(inst.sortedList, [4, 3, 2, 1]);
    assert.equal(inst.toString(), '4, 3, 2, 1');
  });

  it('should sort the array in decending order with few equal vals', () => {
    const inst = new InsertionSort([2, 1, 3, 4, 2], (a, b) => a > b);
    assert.equal(inst.size, 5);

    assert.deepEqual(inst.unsortedList, [2, 1, 3, 4, 2]);
    assert.deepEqual(inst.sortedList, [4, 3, 2, 2, 1]);
    assert.equal(inst.toString(), '4, 3, 2, 2, 1');
  });
});
<|endoftext|>